libeditwl
Lightweight C++ library for Nintendo DS(i) formats
Loading...
Searching...
No Matches
fs_File.hpp
1
2#pragma once
3#include <twl/twl_Include.hpp>
4#include <twl/util/util_Compression.hpp>
5#include <twl/util/util_Align.hpp>
6#include <cstdio>
7#include <cstring>
8
9namespace twl::fs {
10
11 enum class FileMode : u8 {
12 Invalid,
13 Read,
14 Write
15 };
16
17 inline constexpr bool CanReadWithMode(const FileMode mode) {
18 return mode == FileMode::Read;
19 }
20
21 inline constexpr bool CanWriteWithMode(const FileMode mode) {
22 return mode == FileMode::Write;
23 }
24
25 enum class Whence : u8 {
26 Begin,
27 Current
28 };
29
30 enum class FileCompression : u8 {
31 Invalid,
32 Auto,
33 None,
34 LZ77
35 };
36
38 public:
39 virtual Result ReadBuffer(void *read_buf, const size_t read_size) = 0;
40 virtual Result WriteBuffer(const void *write_buf, const size_t write_size) = 0;
41 virtual Result SetOffset(const ssize_t offset, const Whence whence) = 0;
42 virtual Result GetOffset(size_t &out_offset) = 0;
43 virtual Result GetSize(size_t &out_size) = 0;
44
45 inline Result SetAbsoluteOffset(const size_t offset) {
46 TWL_R_TRY(this->SetOffset(offset, Whence::Begin));
47 TWL_R_SUCCEED();
48 }
49
50 inline Result MoveOffset(const ssize_t offset) {
51 TWL_R_TRY(this->SetOffset(offset, Whence::Current));
52 TWL_R_SUCCEED();
53 }
54
55 template<typename T>
56 inline Result Read(T &out_t) {
57 TWL_R_TRY(this->ReadBuffer(std::addressof(out_t), sizeof(T)));
58 TWL_R_SUCCEED();
59 }
60
61 template<typename T>
62 inline Result Write(const T &t) {
63 TWL_R_TRY(this->WriteBuffer(std::addressof(t), sizeof(T)));
64 TWL_R_SUCCEED();
65 }
66
67 template<typename T>
68 inline Result ReadLEB128(T &out_t) {
69 out_t = {};
70 while(true) {
71 u8 v;
72 TWL_R_TRY(this->Read(v));
73
74 out_t = (out_t << 7) | (v & 0x7F);
75 if(!(v & 0x80)) {
76 break;
77 }
78 }
79
80 TWL_R_SUCCEED();
81 }
82
83 template<typename C>
84 inline Result ReadTerminatedString(std::basic_string<C> &out_str, const C terminator, const size_t tmp_buf_size = 0x200) {
85 // Note: this approach is significantly faster than the classic read-char-by-char approach, specially when reading hundreds of strings ;)
86 out_str.clear();
87
88 size_t old_offset;
89 TWL_R_TRY(this->GetOffset(old_offset));
90 size_t f_size;
91 TWL_R_TRY(this->GetSize(f_size));
92 const auto available_size = f_size - old_offset;
93 if(available_size == 0) {
94 TWL_R_FAIL(ResultEndOfData);
95 }
96 const auto r_size = std::min(tmp_buf_size, available_size);
97 auto buf = new C[r_size]();
98 ScopeGuard on_exit_cleanup([&]() {
99 delete[] buf;
100 });
101
102 TWL_R_TRY(this->ReadBuffer(buf, r_size));
103
104 for(size_t i = 0; i < r_size; i++) {
105 if(buf[i] == terminator) {
106 TWL_R_TRY(this->SetAbsoluteOffset(old_offset + i + 1));
107 out_str = std::basic_string<C>(buf, i);
108 TWL_R_SUCCEED();
109 }
110 }
111
112 TWL_R_TRY(this->SetAbsoluteOffset(old_offset));
113 return ReadNullTerminatedString(out_str, tmp_buf_size * 2);
114 }
115
116 template<typename C>
117 inline Result ReadNullTerminatedString(std::basic_string<C> &out_str, const size_t tmp_buf_size = 0x200) {
118 return this->ReadTerminatedString(out_str, static_cast<C>(0), tmp_buf_size);
119 }
120
121 template<typename C>
122 inline Result WriteString(const std::basic_string<C> &str) {
123 return this->WriteBuffer(str.c_str(), str.length() * sizeof(C));
124 }
125
126 inline Result WriteCString(const char *str) {
127 const auto str_len = std::strlen(str);
128 return this->WriteBuffer(str, str_len);
129 }
130
131 inline Result WriteEnsureAlignmentPadding(const size_t align, size_t &out_pad_size) {
132 if(align == 0) {
133 TWL_R_SUCCEED();
134 }
135
136 size_t cur_offset;
137 TWL_R_TRY(this->GetOffset(cur_offset));
138 out_pad_size = util::AlignUp(cur_offset, align) - cur_offset;
139
140 auto zero_buf = new u8[out_pad_size]();
141 ScopeGuard cleanup([&]() {
142 delete[] zero_buf;
143 });
144
145 TWL_R_TRY(this->WriteBuffer(zero_buf, out_pad_size));
146
147 TWL_R_SUCCEED();
148 }
149
150 inline Result WriteEnsureAlignment(const size_t align) {
151 size_t dummy_size;
152 TWL_R_TRY(this->WriteEnsureAlignmentPadding(align, dummy_size));
153 TWL_R_SUCCEED();
154 }
155
156 template<typename T>
157 inline Result WriteVector(const std::vector<T> &vec) {
158 return this->WriteBuffer(vec.data(), vec.size() * sizeof(T));
159 }
160
161 template<typename C>
162 inline Result WriteNullTerminatedString(const std::basic_string<C> &str) {
163 TWL_R_TRY(this->WriteString(str));
164 TWL_R_TRY(this->Write(static_cast<C>(0)));
165
166 TWL_R_SUCCEED();
167 }
168 };
169
170 class BufferReaderWriter : public AbstractReaderWriter {
171 private:
172 void *buf;
173 size_t buf_size;
174 size_t offset;
175
176 public:
177 constexpr BufferReaderWriter() : buf(nullptr), buf_size(0), offset(0) {}
178
179 inline BufferReaderWriter(const size_t buf_size) : buf(nullptr), buf_size(0), offset(0) {
180 this->CreateAllocate(buf_size);
181 }
182
183 inline BufferReaderWriter(void *buf, const size_t buf_size, const bool transfer_ownership = true) : buf(nullptr), buf_size(0), offset(0) {
184 this->CreateFrom(buf, buf_size, transfer_ownership);
185 }
186
187 BufferReaderWriter(const BufferReaderWriter&) = delete;
188 BufferReaderWriter(BufferReaderWriter&&) = default;
189
190 void CreateAllocate(const size_t buf_size);
191 void CreateFrom(void *buf, const size_t buf_size, const bool transfer_ownership = true);
192
193 inline void Dispose() {
194 if(this->buf != nullptr) {
195 auto del_buf = reinterpret_cast<u8*>(this->buf);
196 delete[] del_buf;
197 this->buf = nullptr;
198 }
199
200 this->buf_size = 0;
201 this->offset = 0;
202 }
203
204 inline bool IsValid() {
205 return (this->buf != nullptr) && (this->buf_size > 0);
206 }
207
208 inline void *GetBuffer() {
209 return this->buf;
210 }
211
212 inline size_t GetBufferSize() {
213 return this->buf_size;
214 }
215
216 Result SetOffset(const ssize_t offset, const Whence whence) override;
217
218 inline size_t GetBufferOffset() {
219 return this->offset;
220 }
221
222 inline Result GetOffset(size_t &out_offset) override {
223 out_offset = this->GetBufferOffset();
224 TWL_R_SUCCEED();
225 }
226
227 inline Result GetSize(size_t &out_size) override {
228 out_size = this->GetBufferSize();
229 TWL_R_SUCCEED();
230 }
231
232 Result ReadBuffer(void *read_buf, const size_t read_size) override;
233 Result WriteBuffer(const void *write_buf, const size_t write_size) override;
234 };
235
236 class File : public AbstractReaderWriter {
237 protected:
238 FileMode mode;
239
240 private:
241 bool opened;
242 FileCompression comp;
243 util::LzVersion lz_ver;
244 BufferReaderWriter decomp_rw;
245
246 Result DecompressRead();
247 Result CompressWrite();
248
249 Result Open(const FileMode mode, const FileCompression comp);
250
251 public:
252 constexpr File() : mode(FileMode::Invalid), opened(false), comp(FileCompression::Invalid), lz_ver(util::LzVersion::Invalid), decomp_rw() {}
253
254 File(const File&) = delete;
255 File(File&&) = default;
256
257 inline bool IsOpened() {
258 return this->opened;
259 }
260
261 inline constexpr bool IsCompressed() {
262 return (this->comp != FileCompression::Invalid) && (this->comp != FileCompression::None);
263 }
264
265 virtual Result OpenImpl(const FileMode mode) = 0;
266 virtual Result GetSizeImpl(size_t &out_size) = 0;
267 virtual Result SetOffsetImpl(const size_t offset, const Whence whence) = 0;
268 virtual Result GetOffsetImpl(size_t &out_offset) = 0;
269 virtual Result ReadBufferImpl(void *read_buf, const size_t read_size) = 0;
270 virtual Result WriteBufferImpl(const void *write_buf, const size_t write_size) = 0;
271 virtual Result CloseImpl() = 0;
272
273 inline Result OpenRead(const FileCompression comp = FileCompression::Auto) {
274 TWL_R_TRY(this->Open(fs::FileMode::Read, comp));
275 TWL_R_SUCCEED();
276 }
277
278 inline Result OpenWrite(const FileCompression comp = FileCompression::None) {
279 TWL_R_TRY(this->Open(fs::FileMode::Write, comp));
280 TWL_R_SUCCEED();
281 }
282
283 inline Result GetSize(size_t &out_size) override {
284 if(this->IsCompressed()) {
285 out_size = this->decomp_rw.GetBufferSize();
286 }
287 else {
288 TWL_R_TRY(this->GetSizeImpl(out_size));
289 }
290
291 TWL_R_SUCCEED();
292 }
293
294 Result SetOffset(const ssize_t offset, const Whence whence) override;
295 Result GetOffset(size_t &out_offset) override;
296 Result ReadBuffer(void *read_buf, const size_t read_size) override;
297 Result WriteBuffer(const void *write_buf, const size_t write_size) override;
298
299 Result Close();
300 };
301
302 class StdioFile : public File {
303 private:
304 std::string path;
305 FILE *file;
306
307 public:
308 inline StdioFile(const std::string &path) : File(), path(path), file(nullptr) {}
309
310 StdioFile(const StdioFile&) = delete;
311 StdioFile(StdioFile&&) = default;
312
313 Result OpenImpl(const FileMode mode) override;
314 Result GetSizeImpl(size_t &out_size) override;
315 Result SetOffsetImpl(const size_t offset, const Whence whence) override;
316 Result GetOffsetImpl(size_t &out_offset) override;
317 Result ReadBufferImpl(void *read_buf, const size_t read_size) override;
318 Result WriteBufferImpl(const void *write_buf, const size_t write_size) override;
319 Result CloseImpl() override;
320
321 inline std::string &GetPath() {
322 return this->path;
323 }
324 };
325
326 class BufferFile : public File {
327 private:
329
330 public:
331 constexpr BufferFile() : File(), rw() {}
332 inline BufferFile(size_t buf_size) : File(), rw(buf_size) {}
333 inline BufferFile(void *buf, size_t buf_size, const bool transfer_ownership = true) : File(), rw(buf, buf_size, transfer_ownership) {}
334
335 BufferFile(const BufferFile&) = delete;
336 BufferFile(BufferFile&&) = default;
337
338 inline void CreateAllocate(size_t buf_size) {
339 this->Close();
340 this->rw.CreateAllocate(buf_size);
341 }
342
343 inline void CreateFrom(void *buf, size_t buf_size, const bool transfer_ownership = true) {
344 this->Close();
345 this->rw.CreateFrom(buf, buf_size, transfer_ownership);
346 }
347
348 inline void Dispose() {
349 this->Close();
350 this->rw.Dispose();
351 }
352
353 inline bool IsValid() {
354 return this->rw.IsValid();
355 }
356
357 inline void *GetBuffer() {
358 return this->rw.GetBuffer();
359 }
360
361 inline size_t GetBufferSize() {
362 return this->rw.GetBufferSize();
363 }
364
365 Result OpenImpl(const FileMode mode) override;
366
367 inline Result GetSizeImpl(size_t &out_size) override {
368 out_size = this->rw.GetBufferSize();
369 TWL_R_SUCCEED();
370 }
371
372 Result SetOffsetImpl(const size_t offset, const Whence whence) override;
373
374 inline Result GetOffsetImpl(size_t &out_offset) override {
375 out_offset = this->rw.GetBufferOffset();
376 TWL_R_SUCCEED();
377 }
378
379 Result ReadBufferImpl(void *read_buf, const size_t read_size) override;
380 Result WriteBufferImpl(const void *write_buf, const size_t write_size) override;
381 Result CloseImpl() override;
382 };
383
384}
Definition twl_Include.hpp:22
Definition fs_File.hpp:37
Definition fs_File.hpp:170
Definition twl_Include.hpp:62