1 /**
2  * Copyright (c) 2021-2024 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     bool WriteByte(uint8_t byte) override
106     {
107         data_.push_back(byte);
108         return true;
109     }
110 
111     bool WriteBytes(const std::vector<uint8_t> &bytes) override
112     {
113         data_.insert(data_.end(), bytes.cbegin(), bytes.cend());
114         return true;
115     }
116 
GetData()117     const std::vector<uint8_t> &GetData()
118     {
119         return data_;
120     }
121 
122     size_t GetOffset() const override
123     {
124         return data_.size();
125     }
126 
127 private:
128     std::vector<uint8_t> data_;
129 };
130 
131 class MemoryBufferWriter : public Writer {
132 public:
MemoryBufferWriter(uint8_t *buffer, size_t size)133     explicit MemoryBufferWriter(uint8_t *buffer, size_t size) : sp_(buffer, size) {}
134 
135     ~MemoryBufferWriter() override = default;
136 
137     NO_COPY_SEMANTIC(MemoryBufferWriter);
138     NO_MOVE_SEMANTIC(MemoryBufferWriter);
139 
140     bool WriteByte(uint8_t byte) override
141     {
142         sp_[offset_++] = byte;
143         return true;
144     }
145 
146     bool WriteBytes(const std::vector<uint8_t> &bytes) override
147     {
148         if (bytes.empty()) {
149             return true;
150         }
151 
152         auto subSp = sp_.SubSpan(offset_, bytes.size());
153         if (memcpy_s(subSp.data(), subSp.size(), bytes.data(), bytes.size()) != 0) {
154             return false;
155         }
156         offset_ += bytes.size();
157         return true;
158     }
159 
160     size_t GetOffset() const override
161     {
162         return offset_;
163     }
164 
165 private:
166     Span<uint8_t> sp_;
167     size_t offset_ {0};
168 };
169 
170 class FileWriter : public Writer {
171 public:
172     explicit FileWriter(const std::string &fileName);
173 
174     ~FileWriter() override;
175 
176     NO_COPY_SEMANTIC(FileWriter);
177     NO_MOVE_SEMANTIC(FileWriter);
178 
179     void CountChecksum(bool counting) override
180     {
181         countChecksum_ = counting;
182     }
183 
184     bool WriteChecksum(size_t offset) override
185     {
186         if (fseek(file_, static_cast<int64_t>(offset), SEEK_SET) != 0) {
187             LOG(FATAL, RUNTIME) << "Unable to write checksum by offset: " << static_cast<int64_t>(offset);
188             UNREACHABLE();
189         }
190         auto res = Write<uint32_t>(checksum_);
191         if (fseek(file_, static_cast<int64_t>(offset), SEEK_END) != 0) {
192             LOG(FATAL, RUNTIME) << "Unable to write checksum by offset: " << static_cast<int64_t>(offset);
193             UNREACHABLE();
194         }
195         return res;
196     }
197 
198     bool WriteByte(uint8_t data) override;
199 
200     bool WriteBytes(const std::vector<uint8_t> &bytes) override;
201 
202     size_t GetOffset() const override
203     {
204         return offset_;
205     }
206 
GetChecksum() const207     uint32_t GetChecksum() const
208     {
209         return checksum_;
210     }
211 
operator bool() const212     explicit operator bool() const
213     {
214         return file_ != nullptr;
215     }
216 
217 private:
218     FILE *file_;
219     size_t offset_ {0};
220     uint32_t checksum_;
221     bool countChecksum_ {false};
222 };
223 
224 }  // namespace ark::panda_file
225 
226 #endif  // LIBPANDAFILE_FILE_WRITER_H_
227