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 #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 panda::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 RewriteChecksum(size_t)42 virtual bool RewriteChecksum(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 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 (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 ReserveBufferCapacity(size_t size)95 virtual void ReserveBufferCapacity([[maybe_unused]] size_t size) {} 96 FinishWrite()97 virtual bool FinishWrite() 98 { 99 return true; 100 } 101 102 // default methods 103 Writer() = default; 104 virtual ~Writer() = default; 105 106 NO_COPY_SEMANTIC(Writer); 107 NO_MOVE_SEMANTIC(Writer); 108 }; 109 110 class MemoryWriter : public Writer { 111 public: WriteByte(uint8_t byte)112 bool WriteByte(uint8_t byte) override 113 { 114 data_.push_back(byte); 115 return true; 116 } 117 WriteBytes(const std::vector<uint8_t> & bytes)118 bool WriteBytes(const std::vector<uint8_t> &bytes) override 119 { 120 data_.insert(data_.end(), bytes.cbegin(), bytes.cend()); 121 return true; 122 } 123 GetData()124 const std::vector<uint8_t> &GetData() 125 { 126 return data_; 127 } 128 GetOffset()129 size_t GetOffset() const override 130 { 131 return data_.size(); 132 } 133 134 private: 135 std::vector<uint8_t> data_; 136 }; 137 138 class MemoryBufferWriter : public Writer { 139 public: MemoryBufferWriter(uint8_t * buffer,size_t size)140 explicit MemoryBufferWriter(uint8_t *buffer, size_t size) : sp_(buffer, size) {} 141 142 ~MemoryBufferWriter() override = default; 143 144 NO_COPY_SEMANTIC(MemoryBufferWriter); 145 NO_MOVE_SEMANTIC(MemoryBufferWriter); 146 WriteByte(uint8_t byte)147 bool WriteByte(uint8_t byte) override 148 { 149 sp_[offset_++] = byte; 150 return true; 151 } 152 WriteBytes(const std::vector<uint8_t> & bytes)153 bool WriteBytes(const std::vector<uint8_t> &bytes) override 154 { 155 if (bytes.empty()) { 156 return true; 157 } 158 159 auto sub_sp = sp_.SubSpan(offset_, bytes.size()); 160 if (memcpy_s(sub_sp.data(), sub_sp.size(), bytes.data(), bytes.size()) != 0) { 161 return false; 162 } 163 offset_ += bytes.size(); 164 return true; 165 } 166 GetOffset()167 size_t GetOffset() const override 168 { 169 return offset_; 170 } 171 172 private: 173 Span<uint8_t> sp_; 174 size_t offset_ {0}; 175 }; 176 177 class FileWriter : public Writer { 178 public: 179 explicit FileWriter(const std::string &file_name); 180 181 ~FileWriter() override; 182 183 NO_COPY_SEMANTIC(FileWriter); 184 NO_MOVE_SEMANTIC(FileWriter); 185 CountChecksum(bool counting)186 void CountChecksum(bool counting) override 187 { 188 count_checksum_ = counting; 189 } 190 RewriteChecksum(size_t offset)191 bool RewriteChecksum(size_t offset) override 192 { 193 static constexpr size_t MASK = 0xff; 194 static constexpr size_t WIDTH = std::numeric_limits<uint8_t>::digits; 195 196 size_t length = sizeof(uint32_t); 197 if (offset + length > buffer_.size()) { 198 return false; 199 } 200 uint32_t temp = checksum_; 201 for (size_t i = 0; i < length; i++) { 202 buffer_[offset + i] = temp & MASK; 203 temp >>= WIDTH; 204 } 205 return true; 206 } 207 208 bool WriteByte(uint8_t data) override; 209 210 bool WriteBytes(const std::vector<uint8_t> &bytes) override; 211 GetOffset()212 size_t GetOffset() const override 213 { 214 return buffer_.size(); 215 } 216 GetChecksum()217 uint32_t GetChecksum() const 218 { 219 return checksum_; 220 } 221 222 explicit operator bool() const 223 { 224 return file_ != nullptr; 225 } 226 ReserveBufferCapacity(size_t size)227 void ReserveBufferCapacity(size_t size) override 228 { 229 buffer_.reserve(size); 230 } 231 GetBuffer()232 const std::vector<uint8_t> &GetBuffer() const 233 { 234 return buffer_; 235 } 236 237 bool FinishWrite() override; 238 239 private: 240 FILE *file_; 241 uint32_t checksum_; 242 bool count_checksum_ {false}; 243 std::vector<uint8_t> buffer_; 244 }; 245 246 } // namespace panda::panda_file 247 248 #endif // LIBPANDAFILE_FILE_WRITER_H_ 249