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