• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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