1 /** 2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 #ifndef LIBPANDAFILE_FILE_WRITER_H_ 16 #define LIBPANDAFILE_FILE_WRITER_H_ 17 18 #include "os/file.h" 19 #include "utils/span.h" 20 #include "utils/type_helpers.h" 21 #include "utils/leb128.h" 22 #include "securec.h" 23 24 #include <cstdint> 25 #include <cerrno> 26 27 #include <limits> 28 #include <vector> 29 30 namespace ark::panda_file { 31 32 class Writer { 33 public: 34 virtual bool WriteByte(uint8_t byte) = 0; 35 36 virtual bool WriteBytes(const std::vector<uint8_t> &bytes) = 0; 37 38 virtual size_t GetOffset() const = 0; 39 CountChecksum(bool )40 virtual void CountChecksum(bool /* counting */) {} 41 WriteChecksum(size_t )42 virtual bool WriteChecksum(size_t /* offset */) 43 { 44 return false; 45 } 46 Align(size_t alignment)47 bool Align(size_t alignment) 48 { 49 size_t offset = GetOffset(); 50 size_t n = RoundUp(offset, alignment) - offset; 51 while (n-- > 0) { 52 if (!WriteByte(0)) { 53 return false; 54 } 55 } 56 return true; 57 } 58 59 template <class T> Write(T data)60 bool Write(T data) 61 { 62 static constexpr size_t BYTE_MASK = 0xff; 63 [[maybe_unused]] static constexpr size_t BYTE_WIDTH = std::numeric_limits<uint8_t>::digits; 64 65 for (size_t i = 0; i < sizeof(T); i++) { 66 if (!WriteByte(data & BYTE_MASK)) { 67 return false; 68 } 69 70 if constexpr (sizeof(T) > sizeof(uint8_t)) { 71 data >>= BYTE_WIDTH; 72 } 73 } 74 return true; 75 } 76 77 template <class T> WriteUleb128(T v)78 bool WriteUleb128(T v) 79 { 80 size_t n = leb128::UnsignedEncodingSize(v); 81 std::vector<uint8_t> out(n); 82 leb128::EncodeUnsigned(v, out.data()); 83 return WriteBytes(out); 84 } 85 86 template <class T> WriteSleb128(T v)87 bool WriteSleb128(T v) 88 { 89 size_t n = leb128::SignedEncodingSize(v); 90 std::vector<uint8_t> out(n); 91 leb128::EncodeSigned(v, out.data()); 92 return WriteBytes(out); 93 } 94 95 // default methods 96 Writer() = default; 97 virtual ~Writer() = default; 98 99 NO_COPY_SEMANTIC(Writer); 100 NO_MOVE_SEMANTIC(Writer); 101 }; 102 103 class MemoryWriter : public Writer { 104 public: 105 bool WriteByte(uint8_t byte) override 106 { 107 data_.push_back(byte); 108 return true; 109 } 110 111 bool WriteBytes(const std::vector<uint8_t> &bytes) override 112 { 113 data_.insert(data_.end(), bytes.cbegin(), bytes.cend()); 114 return true; 115 } 116 GetData()117 const std::vector<uint8_t> &GetData() 118 { 119 return data_; 120 } 121 122 size_t GetOffset() const override 123 { 124 return data_.size(); 125 } 126 127 private: 128 std::vector<uint8_t> data_; 129 }; 130 131 class MemoryBufferWriter : public Writer { 132 public: MemoryBufferWriter(uint8_t *buffer, size_t size)133 explicit MemoryBufferWriter(uint8_t *buffer, size_t size) : sp_(buffer, size) {} 134 135 ~MemoryBufferWriter() override = default; 136 137 NO_COPY_SEMANTIC(MemoryBufferWriter); 138 NO_MOVE_SEMANTIC(MemoryBufferWriter); 139 140 bool WriteByte(uint8_t byte) override 141 { 142 sp_[offset_++] = byte; 143 return true; 144 } 145 146 bool WriteBytes(const std::vector<uint8_t> &bytes) override 147 { 148 if (bytes.empty()) { 149 return true; 150 } 151 152 auto subSp = sp_.SubSpan(offset_, bytes.size()); 153 if (memcpy_s(subSp.data(), subSp.size(), bytes.data(), bytes.size()) != 0) { 154 return false; 155 } 156 offset_ += bytes.size(); 157 return true; 158 } 159 160 size_t GetOffset() const override 161 { 162 return offset_; 163 } 164 165 private: 166 Span<uint8_t> sp_; 167 size_t offset_ {0}; 168 }; 169 170 class FileWriter : public Writer { 171 public: 172 explicit FileWriter(const std::string &fileName); 173 174 ~FileWriter() override; 175 176 NO_COPY_SEMANTIC(FileWriter); 177 NO_MOVE_SEMANTIC(FileWriter); 178 179 void CountChecksum(bool counting) override 180 { 181 countChecksum_ = counting; 182 } 183 184 bool WriteChecksum(size_t offset) override 185 { 186 if (fseek(file_, static_cast<int64_t>(offset), SEEK_SET) != 0) { 187 LOG(FATAL, RUNTIME) << "Unable to write checksum by offset: " << static_cast<int64_t>(offset); 188 UNREACHABLE(); 189 } 190 auto res = Write<uint32_t>(checksum_); 191 if (fseek(file_, static_cast<int64_t>(offset), SEEK_END) != 0) { 192 LOG(FATAL, RUNTIME) << "Unable to write checksum by offset: " << static_cast<int64_t>(offset); 193 UNREACHABLE(); 194 } 195 return res; 196 } 197 198 bool WriteByte(uint8_t data) override; 199 200 bool WriteBytes(const std::vector<uint8_t> &bytes) override; 201 202 size_t GetOffset() const override 203 { 204 return offset_; 205 } 206 GetChecksum() const207 uint32_t GetChecksum() const 208 { 209 return checksum_; 210 } 211 operator bool() const212 explicit operator bool() const 213 { 214 return file_ != nullptr; 215 } 216 217 private: 218 FILE *file_; 219 size_t offset_ {0}; 220 uint32_t checksum_; 221 bool countChecksum_ {false}; 222 }; 223 224 } // namespace ark::panda_file 225 226 #endif // LIBPANDAFILE_FILE_WRITER_H_ 227