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