• 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 #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