1//////////////////////////////////////////////////////////////////////
2// This file is part of Remere's Map Editor
3//////////////////////////////////////////////////////////////////////
4// Remere's Map Editor is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Remere's Map Editor is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16//////////////////////////////////////////////////////////////////////
17
18#ifndef RME_FILEHANDLE_H_
19#define RME_FILEHANDLE_H_
20
21#include "definitions.h"
22
23#include <stdexcept>
24#include <string>
25#include <stack>
26#include <stdio.h>
27
28#ifndef FORCEINLINE
29 #ifdef _MSV_VER
30 #define FORCEINLINE __forceinline
31 #else
32 #define FORCEINLINE inline
33 #endif
34#endif
35
36enum FileHandleError {
37 FILE_NO_ERROR,
38 FILE_COULD_NOT_OPEN,
39 FILE_INVALID_IDENTIFIER,
40 FILE_STRING_TOO_LONG,
41 FILE_READ_ERROR,
42 FILE_WRITE_ERROR,
43 FILE_SYNTAX_ERROR,
44 FILE_PREMATURE_END,
45};
46
47enum NodeType {
48 NODE_START = 0xfe,
49 NODE_END = 0xff,
50 ESCAPE_CHAR = 0xfd,
51};
52
53class FileHandle : boost::noncopyable {
54public:
55 FileHandle() :
56 error_code(FILE_NO_ERROR), file(nullptr) { }
57 virtual ~FileHandle() {
58 close();
59 }
60
61 virtual void close();
62 virtual bool isOpen() {
63 return file != nullptr;
64 }
65 virtual bool isOk() {
66 return isOpen() && error_code == FILE_NO_ERROR && ferror(file) == 0;
67 }
68 std::string getErrorMessage();
69
70public:
71 FileHandleError error_code;
72 FILE* file;
73};
74
75class FileReadHandle : public FileHandle {
76public:
77 explicit FileReadHandle(const std::string& name);
78 virtual ~FileReadHandle();
79
80 FORCEINLINE bool getU8(uint8_t& u8) {
81 return getType(u8);
82 }
83 FORCEINLINE bool getByte(uint8_t& u8) {
84 return getType(u8);
85 }
86 FORCEINLINE bool getSByte(int8_t& i8) {
87 return getType(i8);
88 }
89 FORCEINLINE bool getU16(uint16_t& u16) {
90 return getType(u16);
91 }
92 FORCEINLINE bool getU32(uint32_t& u32) {
93 return getType(u32);
94 }
95 FORCEINLINE bool get32(int32_t& i32) {
96 return getType(i32);
97 }
98 bool getRAW(uint8_t* ptr, size_t sz);
99 bool getRAW(std::string& str, size_t sz);
100 bool getString(std::string& str);
101 bool getLongString(std::string& str);
102
103 virtual void close();
104 bool seek(size_t offset);
105 bool seekRelative(size_t offset);
106 FORCEINLINE void skip(size_t offset) {
107 seekRelative(offset);
108 }
109 size_t size() {
110 return file_size;
111 }
112 size_t tell() {
113 if (file) {
114 return ftell(file);
115 }
116 return 0;
117 }
118
119protected:
120 size_t file_size;
121
122 template <class T>
123 bool getType(T& ref) {
124 fread(&ref, sizeof(ref), 1, file);
125 return ferror(file) == 0;
126 }
127};
128
129class NodeFileReadHandle;
130class DiskNodeFileReadHandle;
131class MemoryNodeFileReadHandle;
132
133class BinaryNode {
134public:
135 BinaryNode(NodeFileReadHandle* file, BinaryNode* parent);
136 ~BinaryNode();
137
138 FORCEINLINE bool getU8(uint8_t& u8) {
139 return getType(u8);
140 }
141 FORCEINLINE bool getByte(uint8_t& u8) {
142 return getType(u8);
143 }
144 FORCEINLINE bool getU16(uint16_t& u16) {
145 return getType(u16);
146 }
147 FORCEINLINE bool getU32(uint32_t& u32) {
148 return getType(u32);
149 }
150 FORCEINLINE bool getU64(uint64_t& u64) {
151 return getType(u64);
152 }
153 FORCEINLINE bool skip(size_t sz) {
154 if (read_offset + sz > data.size()) {
155 read_offset = data.size();
156 return false;
157 }
158 read_offset += sz;
159 return true;
160 }
161 bool getRAW(uint8_t* ptr, size_t sz);
162 bool getRAW(std::string& str, size_t sz);
163 bool getString(std::string& str);
164 bool getLongString(std::string& str);
165
166 BinaryNode* getChild();
167 // Returns this on success, nullptr on failure
168 BinaryNode* advance();
169
170protected:
171 template <class T>
172 bool getType(T& ref) {
173 if (read_offset + sizeof(ref) > data.size()) {
174 read_offset = data.size();
175 return false;
176 }
177 ref = *(T*)(data.data() + read_offset);
178
179 read_offset += sizeof(ref);
180 return true;
181 }
182
183 void load();
184 std::string data;
185 size_t read_offset;
186 NodeFileReadHandle* file;
187 BinaryNode* parent;
188 BinaryNode* child;
189
190 friend class DiskNodeFileReadHandle;
191 friend class MemoryNodeFileReadHandle;
192};
193
194class NodeFileReadHandle : public FileHandle {
195public:
196 NodeFileReadHandle();
197 virtual ~NodeFileReadHandle();
198
199 virtual BinaryNode* getRootNode() = 0;
200
201 virtual size_t size() = 0;
202 virtual size_t tell() = 0;
203
204protected:
205 BinaryNode* getNode(BinaryNode* parent);
206 void freeNode(BinaryNode* node);
207 // Returns false when end-of-file is reached
208 virtual bool renewCache() = 0;
209
210 bool last_was_start;
211 uint8_t* cache;
212 size_t cache_size;
213 size_t cache_length;
214 size_t local_read_index;
215
216 BinaryNode* root_node;
217
218 std::stack<void*> unused;
219
220 friend class BinaryNode;
221};
222
223class DiskNodeFileReadHandle : public NodeFileReadHandle {
224public:
225 DiskNodeFileReadHandle(const std::string& name, const std::vector<std::string>& acceptable_identifiers);
226 virtual ~DiskNodeFileReadHandle();
227
228 virtual void close();
229 virtual BinaryNode* getRootNode();
230
231 virtual size_t size() {
232 return file_size;
233 }
234 virtual size_t tell() {
235 if (file) {
236 return ftell(file);
237 }
238 return 0;
239 }
240
241protected:
242 virtual bool renewCache();
243
244 size_t file_size;
245};
246
247class MemoryNodeFileReadHandle : public NodeFileReadHandle {
248public:
249 // Does NOT claim ownership of the memory it is given.
250 MemoryNodeFileReadHandle(const uint8_t* data, size_t size);
251 virtual ~MemoryNodeFileReadHandle();
252
253 void assign(const uint8_t* data, size_t size);
254
255 virtual void close();
256 virtual BinaryNode* getRootNode();
257
258 virtual size_t size() {
259 return cache_size;
260 }
261 virtual size_t tell() {
262 return local_read_index;
263 }
264 virtual bool isOk() {
265 return true;
266 }
267
268protected:
269 virtual bool renewCache();
270
271 uint8_t* index;
272};
273
274class FileWriteHandle : public FileHandle {
275public:
276 explicit FileWriteHandle(const std::string& name);
277 virtual ~FileWriteHandle();
278
279 FORCEINLINE bool addU8(uint8_t u8) {
280 return addType(u8);
281 }
282 FORCEINLINE bool addByte(uint8_t u8) {
283 return addType(u8);
284 }
285 FORCEINLINE bool addU16(uint16_t u16) {
286 return addType(u16);
287 }
288 FORCEINLINE bool addU32(uint32_t u32) {
289 return addType(u32);
290 }
291 FORCEINLINE bool addU64(uint64_t u64) {
292 return addType(u64);
293 }
294 bool addString(const std::string& str);
295 bool addString(const char* str);
296 bool addLongString(const std::string& str);
297 bool addRAW(const std::string& str);
298 bool addRAW(const uint8_t* ptr, size_t sz);
299 bool addRAW(const char* c) {
300 return addRAW(reinterpret_cast<const uint8_t*>(c), strlen(c));
301 }
302
303protected:
304 template <class T>
305 bool addType(T ref) {
306 fwrite(&ref, sizeof(ref), 1, file);
307 return ferror(file) == 0;
308 }
309};
310
311class NodeFileWriteHandle : public FileHandle {
312public:
313 NodeFileWriteHandle();
314 virtual ~NodeFileWriteHandle();
315
316 bool addNode(uint8_t nodetype);
317 bool endNode();
318
319 bool addU8(uint8_t u8);
320 bool addByte(uint8_t u8);
321 bool addU16(uint16_t u16);
322 bool addU32(uint32_t u32);
323 bool addU64(uint64_t u64);
324 bool addString(const std::string& str);
325 bool addLongString(const std::string& str);
326 bool addRAW(std::string& str);
327 bool addRAW(const uint8_t* ptr, size_t sz);
328 bool addRAW(const char* c) {
329 return addRAW(reinterpret_cast<const uint8_t*>(c), strlen(c));
330 }
331
332protected:
333 virtual void renewCache() = 0;
334
335 static uint8_t NODE_START;
336 static uint8_t NODE_END;
337 static uint8_t ESCAPE_CHAR;
338
339 uint8_t* cache;
340 size_t cache_size;
341 size_t local_write_index;
342
343 FORCEINLINE void writeBytes(const uint8_t* ptr, size_t sz) {
344 if (sz) {
345 do {
346 if (*ptr == NODE_START || *ptr == NODE_END || *ptr == ESCAPE_CHAR) {
347 cache[local_write_index++] = ESCAPE_CHAR;
348 if (local_write_index >= cache_size) {
349 renewCache();
350 }
351 }
352 cache[local_write_index++] = *ptr;
353 if (local_write_index >= cache_size) {
354 renewCache();
355 }
356 ++ptr;
357 --sz;
358 } while (sz != 0);
359 }
360 }
361};
362
363class DiskNodeFileWriteHandle : public NodeFileWriteHandle {
364public:
365 DiskNodeFileWriteHandle(const std::string& name, const std::string& identifier);
366 virtual ~DiskNodeFileWriteHandle();
367
368 virtual void close();
369
370protected:
371 virtual void renewCache();
372};
373
374class MemoryNodeFileWriteHandle : public NodeFileWriteHandle {
375public:
376 MemoryNodeFileWriteHandle();
377 virtual ~MemoryNodeFileWriteHandle();
378
379 void reset();
380 virtual void close();
381
382 uint8_t* getMemory();
383 size_t getSize();
384
385protected:
386 virtual void renewCache();
387};
388
389#endif
390