1 /** 2 * Copyright (c) 2021-2025 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 PANDA_PUBLIC_API MemoryWriter(); 106 CountChecksum(bool counting)107 void CountChecksum(bool counting) override 108 { 109 countChecksum_ = counting; 110 } 111 WriteChecksum(size_t offset)112 bool WriteChecksum(size_t offset) override 113 { 114 auto span = Span(data_.data(), data_.size()); 115 auto sub = span.SubSpan(offset); 116 return (memcpy_s(sub.data(), sizeof(checksum_), &checksum_, sizeof(checksum_)) == 0); 117 } 118 WriteByte(uint8_t byte)119 bool WriteByte(uint8_t byte) override 120 { 121 return WriteBytes({byte}); 122 } 123 124 bool WriteBytes(const std::vector<uint8_t> &bytes) override; 125 GetData()126 const std::vector<uint8_t> &GetData() 127 { 128 return data_; 129 } 130 GetOffset()131 size_t GetOffset() const override 132 { 133 return data_.size(); 134 } 135 136 private: 137 std::vector<uint8_t> data_; 138 uint32_t checksum_; 139 bool countChecksum_ {false}; 140 }; 141 142 class MemoryBufferWriter : public Writer { 143 public: 144 PANDA_PUBLIC_API explicit MemoryBufferWriter(uint8_t *buffer, size_t size); 145 146 ~MemoryBufferWriter() override = default; 147 148 NO_COPY_SEMANTIC(MemoryBufferWriter); 149 NO_MOVE_SEMANTIC(MemoryBufferWriter); 150 CountChecksum(bool counting)151 void CountChecksum(bool counting) override 152 { 153 countChecksum_ = counting; 154 } 155 WriteChecksum(size_t offset)156 bool WriteChecksum(size_t offset) override 157 { 158 auto sub = sp_.SubSpan(offset); 159 return (memcpy_s(sub.data(), sizeof(checksum_), &checksum_, sizeof(checksum_)) != 0); 160 } 161 WriteByte(uint8_t byte)162 bool WriteByte(uint8_t byte) override 163 { 164 return WriteBytes({byte}); 165 } 166 167 bool WriteBytes(const std::vector<uint8_t> &bytes) override; 168 GetOffset()169 size_t GetOffset() const override 170 { 171 return offset_; 172 } 173 174 private: 175 Span<uint8_t> sp_; 176 size_t offset_ {0}; 177 uint32_t checksum_; 178 bool countChecksum_ {false}; 179 }; 180 181 class FileWriter : public Writer { 182 public: 183 PANDA_PUBLIC_API explicit FileWriter(const std::string &fileName); 184 185 PANDA_PUBLIC_API ~FileWriter() override; 186 187 NO_COPY_SEMANTIC(FileWriter); 188 NO_MOVE_SEMANTIC(FileWriter); 189 CountChecksum(bool counting)190 void CountChecksum(bool counting) override 191 { 192 countChecksum_ = counting; 193 } 194 WriteChecksum(size_t offset)195 bool WriteChecksum(size_t offset) override 196 { 197 if (fseek(file_, static_cast<int64_t>(offset), SEEK_SET) != 0) { 198 LOG(FATAL, RUNTIME) << "Unable to write checksum by offset: " << static_cast<int64_t>(offset); 199 UNREACHABLE(); 200 } 201 auto res = Write<uint32_t>(checksum_); 202 if (fseek(file_, static_cast<int64_t>(offset), SEEK_END) != 0) { 203 LOG(FATAL, RUNTIME) << "Unable to write checksum by offset: " << static_cast<int64_t>(offset); 204 UNREACHABLE(); 205 } 206 return res; 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 offset_; 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 228 private: 229 FILE *file_; 230 size_t offset_ {0}; 231 uint32_t checksum_; 232 bool countChecksum_ {false}; 233 }; 234 235 } // namespace ark::panda_file 236 237 #endif // LIBPANDAFILE_FILE_WRITER_H_ 238