1 /** 2 * Copyright (c) 2021-2022 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 16 #ifndef LIBPANDAFILE_FILE_WRITER_H 17 #define LIBPANDAFILE_FILE_WRITER_H 18 19 #include "os/file.h" 20 #include "utils/span.h" 21 #include "utils/type_helpers.h" 22 #include "utils/leb128.h" 23 #include "securec.h" 24 25 #include <cstdint> 26 #include <cerrno> 27 28 #include <limits> 29 #include <vector> 30 31 namespace panda::panda_file { 32 33 class Writer { 34 public: 35 virtual bool WriteByte(uint8_t byte) = 0; 36 37 virtual bool WriteBytes(const std::vector<uint8_t> &bytes) = 0; 38 39 virtual size_t GetOffset() const = 0; 40 CountChecksum(bool)41 virtual void CountChecksum(bool /* counting */) {} 42 RewriteChecksum(size_t)43 virtual bool RewriteChecksum(size_t /* offset */) 44 { 45 return false; 46 } 47 Align(size_t alignment)48 bool Align(size_t alignment) 49 { 50 size_t offset = GetOffset(); 51 size_t n = RoundUp(offset, alignment) - offset; 52 while (n-- > 0) { 53 if (!WriteByte(0)) { 54 return false; 55 } 56 } 57 return true; 58 } 59 60 template <class T> Write(T data)61 bool Write(T data) 62 { 63 static constexpr size_t BYTE_MASK = 0xff; 64 static constexpr size_t BYTE_WIDTH = std::numeric_limits<uint8_t>::digits; 65 66 for (size_t i = 0; i < sizeof(T); i++) { 67 if (!WriteByte(data & BYTE_MASK)) { 68 return false; 69 } 70 71 if (sizeof(T) > sizeof(uint8_t)) { 72 data >>= BYTE_WIDTH; 73 } 74 } 75 return true; 76 } 77 78 template <class T> WriteUleb128(T v)79 bool WriteUleb128(T v) 80 { 81 size_t n = leb128::UnsignedEncodingSize(v); 82 std::vector<uint8_t> out(n); 83 leb128::EncodeUnsigned(v, out.data()); 84 return WriteBytes(out); 85 } 86 87 template <class T> WriteSleb128(T v)88 bool WriteSleb128(T v) 89 { 90 size_t n = leb128::SignedEncodingSize(v); 91 std::vector<uint8_t> out(n); 92 leb128::EncodeSigned(v, out.data()); 93 return WriteBytes(out); 94 } 95 ReserveBufferCapacity(size_t size)96 virtual void ReserveBufferCapacity([[maybe_unused]] size_t size) {} 97 FinishWrite()98 virtual bool FinishWrite() 99 { 100 return true; 101 } 102 103 // default methods 104 Writer() = default; 105 virtual ~Writer() = default; 106 107 NO_COPY_SEMANTIC(Writer); 108 NO_MOVE_SEMANTIC(Writer); 109 }; 110 111 class MemoryWriter : public Writer { 112 public: WriteByte(uint8_t byte)113 bool WriteByte(uint8_t byte) override 114 { 115 data_.push_back(byte); 116 return true; 117 } 118 WriteBytes(const std::vector<uint8_t> & bytes)119 bool WriteBytes(const std::vector<uint8_t> &bytes) override 120 { 121 data_.insert(data_.end(), bytes.cbegin(), bytes.cend()); 122 return true; 123 } 124 GetData()125 const std::vector<uint8_t> &GetData() 126 { 127 return data_; 128 } 129 GetOffset()130 size_t GetOffset() const override 131 { 132 return data_.size(); 133 } 134 135 private: 136 std::vector<uint8_t> data_; 137 }; 138 139 class MemoryBufferWriter : public Writer { 140 public: MemoryBufferWriter(uint8_t * buffer,size_t size)141 explicit MemoryBufferWriter(uint8_t *buffer, size_t size) : sp_(buffer, size) {} 142 143 ~MemoryBufferWriter() override = default; 144 145 NO_COPY_SEMANTIC(MemoryBufferWriter); 146 NO_MOVE_SEMANTIC(MemoryBufferWriter); 147 WriteByte(uint8_t byte)148 bool WriteByte(uint8_t byte) override 149 { 150 sp_[offset_++] = byte; 151 return true; 152 } 153 WriteBytes(const std::vector<uint8_t> & bytes)154 bool WriteBytes(const std::vector<uint8_t> &bytes) override 155 { 156 if (bytes.empty()) { 157 return true; 158 } 159 160 auto sub_sp = sp_.SubSpan(offset_, bytes.size()); 161 if (memcpy_s(sub_sp.data(), sub_sp.size(), bytes.data(), bytes.size()) != 0) { 162 return false; 163 } 164 offset_ += bytes.size(); 165 return true; 166 } 167 GetOffset()168 size_t GetOffset() const override 169 { 170 return offset_; 171 } 172 173 private: 174 Span<uint8_t> sp_; 175 size_t offset_ {0}; 176 }; 177 178 class FileWriter : public Writer { 179 public: 180 explicit FileWriter(const std::string &file_name); 181 182 ~FileWriter() override; 183 184 NO_COPY_SEMANTIC(FileWriter); 185 NO_MOVE_SEMANTIC(FileWriter); 186 CountChecksum(bool counting)187 void CountChecksum(bool counting) override 188 { 189 count_checksum_ = counting; 190 } 191 RewriteChecksum(size_t offset)192 bool RewriteChecksum(size_t offset) override 193 { 194 static constexpr size_t MASK = 0xff; 195 static constexpr size_t WIDTH = std::numeric_limits<uint8_t>::digits; 196 197 size_t length = sizeof(uint32_t); 198 if (offset + length > buffer_.size()) { 199 return false; 200 } 201 uint32_t temp = checksum_; 202 for (size_t i = 0; i < length; i++) { 203 buffer_[offset + i] = temp & MASK; 204 temp >>= WIDTH; 205 } 206 return true; 207 } 208 209 bool WriteByte(uint8_t data) override; 210 211 bool WriteBytes(const std::vector<uint8_t> &bytes) override; 212 GetOffset()213 size_t GetOffset() const override 214 { 215 return buffer_.size(); 216 } 217 GetChecksum()218 uint32_t GetChecksum() const 219 { 220 return checksum_; 221 } 222 223 explicit operator bool() const 224 { 225 return file_ != nullptr; 226 } 227 ReserveBufferCapacity(size_t size)228 void ReserveBufferCapacity(size_t size) override 229 { 230 buffer_.reserve(size); 231 } 232 GetBuffer()233 const std::vector<uint8_t> &GetBuffer() const 234 { 235 return buffer_; 236 } 237 238 bool FinishWrite() override; 239 240 private: 241 FILE *file_; 242 uint32_t checksum_; 243 bool count_checksum_ {false}; 244 std::vector<uint8_t> buffer_; 245 }; 246 247 } // namespace panda::panda_file 248 249 #endif // LIBPANDAFILE_FILE_WRITER_H 250