libnedit
Lightweight C++ library for Nintendo DS(i) formats
Loading...
Searching...
No Matches
fs_BinaryFile.hpp
1
2#pragma once
3#include <ntr/fs/fs_Base.hpp>
4#include <ntr/util/util_Compression.hpp>
5#include <ntr/util/util_Memory.hpp>
6
7namespace ntr::fs {
8
9 class BinaryFile {
10 private:
11 std::shared_ptr<FileHandle> file_handle;
12 bool ok;
13 OpenMode mode;
14 FileCompression comp;
15 util::LzVersion comp_lz_ver;
16 u8 *dec_file_data;
17 size_t dec_file_offset;
18 size_t dec_file_size;
19 size_t dec_file_buf_size;
20
21 Result LoadDecompressedData();
22 Result SaveCompressedData();
23 Result ReadDecompressedData(void *read_buf, const size_t read_size, size_t &out_read_size);
24 Result WriteDecompressedData(const void *write_buf, const size_t write_size);
25 Result ReallocateDecompressedData(const size_t new_size);
26
27 public:
28 BinaryFile() : file_handle(), ok(false), mode(OpenMode::Read), comp(FileCompression::None), comp_lz_ver(util::LzVersion::LZ10), dec_file_data(nullptr), dec_file_offset(0), dec_file_size(0) {}
29 BinaryFile(const BinaryFile&) = delete;
30
31 ~BinaryFile() {
32 this->Close();
33 }
34
35 Result Open(std::shared_ptr<FileHandle> file_handle, const std::string &path, const OpenMode mode, const FileCompression comp = FileCompression::None);
36 Result Close();
37
38 inline bool IsValid() {
39 return this->ok && static_cast<bool>(this->file_handle);
40 }
41
42 inline bool IsCompressed() {
43 return this->comp != FileCompression::None;
44 }
45
46 inline constexpr bool CanRead() {
47 return CanReadWithMode(this->mode);
48 }
49
50 inline constexpr bool CanWrite() {
51 return CanWriteWithMode(this->mode);
52 }
53
54 inline Result GetSize(size_t &out_size) {
55 if(!this->IsValid()) {
56 NTR_R_FAIL(ResultInvalidFile);
57 }
58
59 if(this->IsCompressed()) {
60 out_size = this->dec_file_size;
61 NTR_R_SUCCEED();
62 }
63 else {
64 return this->file_handle->GetSize(out_size);
65 }
66 }
67
68 Result CopyFrom(BinaryFile &other_bf, const size_t size);
69
70 Result SetAbsoluteOffset(const size_t offset);
71
72 inline Result GetAbsoluteOffset(size_t &out_offset) {
73 if(!this->IsValid()) {
74 NTR_R_FAIL(ResultInvalidFile);
75 }
76
77 if(this->IsCompressed()) {
78 out_offset = this->dec_file_offset;
79 NTR_R_SUCCEED();
80 }
81 else {
82 return this->file_handle->GetOffset(out_offset);
83 }
84 }
85
86 inline Result SetAtEnd() {
87 if(!this->IsValid()) {
88 NTR_R_FAIL(ResultInvalidFile);
89 }
90
91 if(this->IsCompressed()) {
92 this->dec_file_offset = this->dec_file_size;
93 NTR_R_SUCCEED();
94 }
95 else {
96 size_t f_size;
97 NTR_R_TRY(this->GetSize(f_size));
98 return this->file_handle->SetOffset(f_size, Position::Begin);
99 }
100 }
101
102 inline Result MoveOffset(const size_t size) {
103 if(!this->IsValid()) {
104 NTR_R_FAIL(ResultInvalidFile);
105 }
106
107 if(this->IsCompressed()) {
108 if((this->dec_file_offset + size) > this->dec_file_buf_size) {
109 NTR_R_TRY(this->ReallocateDecompressedData(this->dec_file_offset + size));
110 }
111 this->dec_file_offset += size;
112 if(this->dec_file_offset > this->dec_file_size) {
113 this->dec_file_size = this->dec_file_offset;
114 }
115 NTR_R_SUCCEED();
116 }
117 else {
118 return this->file_handle->SetOffset(size, Position::Current);
119 }
120 }
121
122 Result ReadData(void *read_buf, const size_t read_size, size_t &out_read_size);
123
124 inline Result ReadDataExact(void *read_buf, const size_t read_size) {
125 size_t actual_read_size;
126 NTR_R_TRY(this->ReadData(read_buf, read_size, actual_read_size));
127
128 if(actual_read_size == read_size) {
129 NTR_R_SUCCEED();
130 }
131 else {
132 NTR_R_FAIL(ResultUnexpectedReadSize);
133 }
134 }
135
136 template<typename T>
137 inline Result Read(T &out_t) {
138 return this->ReadDataExact(std::addressof(out_t), sizeof(out_t));
139 }
140
141 template<typename T>
142 inline Result ReadLEB128(T &out_t) {
143 out_t = {};
144 while(true) {
145 u8 v;
146 NTR_R_TRY(this->Read(v));
147
148 out_t = (out_t << 7) | (v & 0x7f);
149 if(!(v & 0x80)) {
150 break;
151 }
152 }
153
154 NTR_R_SUCCEED();
155 }
156
157 template<typename C>
158 inline Result ReadNullTerminatedString(std::basic_string<C> &out_str, const size_t tmp_buf_size = 0x200) {
159 // Note: this approach is significantly faster than the classic read-char-by-char approach, specially when reading hundreds of strings ;)
160 out_str.clear();
161 size_t old_offset;
162 NTR_R_TRY(this->GetAbsoluteOffset(old_offset));
163 size_t f_size;
164 NTR_R_TRY(this->GetSize(f_size));
165 const auto available_size = f_size - old_offset;
166 if(available_size == 0) {
167 NTR_R_FAIL(ResultEndOfData);
168 }
169 const auto r_size = std::min(tmp_buf_size, available_size);
170 auto buf = util::NewArray<C>(r_size);
171 ScopeGuard on_exit_cleanup([&]() {
172 delete[] buf;
173 });
174
175 size_t read_size;
176 NTR_R_TRY(this->ReadData(buf, r_size, read_size));
177
178 for(size_t i = 0; i < read_size; i++) {
179 if(buf[i] == static_cast<C>(0)) {
180 NTR_R_TRY(this->SetAbsoluteOffset(old_offset + i + 1));
181 out_str = std::basic_string<C>(buf, i);
182 NTR_R_SUCCEED();
183 }
184 }
185
186 NTR_R_TRY(this->SetAbsoluteOffset(old_offset));
187 return ReadNullTerminatedString(out_str, tmp_buf_size * 2);
188 }
189
190 Result WriteData(const void *write_buf, const size_t write_size);
191
192 template<typename C>
193 inline Result WriteString(const std::basic_string<C> &str) {
194 return this->WriteData(str.c_str(), str.length() * sizeof(C));
195 }
196
197 inline Result WriteCString(const char *str) {
198 const auto str_len = std::strlen(str);
199 return this->WriteData(str, str_len);
200 }
201
202 template<typename T>
203 inline Result Write(const T t) {
204 return this->WriteData(std::addressof(t), sizeof(t));
205 }
206
207 inline Result WriteEnsureAlignment(const size_t align, size_t &out_pad_size) {
208 size_t cur_offset;
209 NTR_R_TRY(this->GetAbsoluteOffset(cur_offset));
210 out_pad_size = util::AlignUp(cur_offset, align) - cur_offset;
211
212 for(size_t i = 0; i < out_pad_size; i++) {
213 NTR_R_TRY(this->Write<u8>(0));
214 }
215 NTR_R_SUCCEED();
216 }
217
218 template<typename T>
219 inline Result WriteVector(const std::vector<T> &vec) {
220 return this->WriteData(vec.data(), vec.size() * sizeof(T));
221 }
222
223 template<typename C>
224 inline Result WriteNullTerminatedString(const std::basic_string<C> &str) {
225 NTR_R_TRY(this->WriteString(str));
226 NTR_R_TRY(this->Write(static_cast<C>(0)));
227
228 NTR_R_SUCCEED();
229 }
230 };
231
232}
Definition ntr_Include.hpp:35
Definition fs_BinaryFile.hpp:9
Definition ntr_Include.hpp:75