Line data Source code
1 : /* Copyright (C) 2021 Wildfire Games.
2 : * This file is part of 0 A.D.
3 : *
4 : * 0 A.D. 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 2 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : /*
19 : * endian-safe binary file IO helpers.
20 : */
21 :
22 : // the file format has passing similarity to IFF. note however that
23 : // "chunks" aren't identified by FOURCCs; only the file header is
24 : // so marked.
25 : // all > 8-bit integers are stored in little-endian format
26 : // (hence the _le suffix). however, the caller is responsible for
27 : // swapping their raw data before passing it to PackRaw. a convenience
28 : // routine is provided for the common case of storing size_t.
29 :
30 : #ifndef INCLUDED_FILEPACKER
31 : #define INCLUDED_FILEPACKER
32 :
33 : #include "lib/file/vfs/vfs_path.h"
34 : #include "ps/CStrForward.h"
35 : #include "ps/Errors.h"
36 : #include "ps/Filesystem.h" // WriteBuffer
37 :
38 0 : ERROR_GROUP(File);
39 0 : ERROR_TYPE(File, OpenFailed);
40 0 : ERROR_TYPE(File, WriteFailed);
41 0 : ERROR_TYPE(File, InvalidType);
42 0 : ERROR_TYPE(File, InvalidVersion);
43 0 : ERROR_TYPE(File, ReadFailed);
44 0 : ERROR_TYPE(File, UnexpectedEOF);
45 :
46 :
47 : /**
48 : * helper class for writing binary files. this is basically a
49 : * resizable buffer that allows adding raw data and strings;
50 : * upon calling Write(), everything is written out to disk.
51 : **/
52 : class CFilePacker
53 : {
54 : public:
55 : /**
56 : * adds version and signature (i.e. the header) to the buffer.
57 : * this means Write() can write the entire buffer to file in one go,
58 : * which is simpler and more efficient than writing in pieces.
59 : **/
60 : CFilePacker(u32 version, const char magic[4]);
61 :
62 : ~CFilePacker();
63 :
64 : /**
65 : * write out to file all packed data added so far.
66 : * it's safe to call this multiple times, but typically would
67 : * only be done once.
68 : **/
69 : void Write(const VfsPath& filename);
70 :
71 : /**
72 : * pack given number of bytes onto the end of the data stream
73 : **/
74 : void PackRaw(const void* rawData, size_t rawDataSize);
75 :
76 : /**
77 : * convenience: convert a number (almost always a size type) to
78 : * little-endian u32 and pack that.
79 : **/
80 : void PackSize(size_t value);
81 :
82 : /**
83 : * pack a string onto the end of the data stream
84 : * (encoded as a 32-bit length followed by the characters)
85 : **/
86 : void PackString(const CStr8& str);
87 :
88 : private:
89 : /**
90 : * the output data stream built during pack operations.
91 : * contains the header, so we can write this out in one go.
92 : **/
93 : WriteBuffer m_writeBuffer;
94 : };
95 :
96 :
97 : /**
98 : * helper class for reading binary files
99 : **/
100 : class CFileUnpacker
101 : {
102 : public:
103 : CFileUnpacker();
104 : ~CFileUnpacker();
105 :
106 : /**
107 : * open and read in given file, check magic bits against those given;
108 : * throw variety of exceptions if open failed / version incorrect, etc.
109 : **/
110 : void Read(const VfsPath& filename, const char magic[4]);
111 :
112 : /**
113 : * @return version number that was stored in the file's header.
114 : **/
115 30 : u32 GetVersion() const
116 : {
117 30 : return m_version;
118 : }
119 :
120 : /**
121 : * unpack given number of bytes from the input into the given array.
122 : * throws PSERROR_File_UnexpectedEOF if the end of the data stream is
123 : * reached before the given number of bytes have been read.
124 : **/
125 : void UnpackRaw(void* rawData, size_t rawDataSize);
126 :
127 : /**
128 : * use UnpackRaw to retrieve 32-bits; returns their value as size_t
129 : * after converting from little endian to native byte order.
130 : **/
131 : size_t UnpackSize();
132 :
133 : /**
134 : * unpack a string from the raw data stream.
135 : * @param result is assigned a newly constructed CStr8 holding the
136 : * string read from the input stream.
137 : **/
138 : void UnpackString(CStr8& result);
139 :
140 : private:
141 : // the data read from file and used during unpack operations
142 : std::shared_ptr<u8> m_buf;
143 : size_t m_bufSize;
144 :
145 : size_t m_unpackPos; /// current unpack position in stream
146 : u32 m_version; /// version that was stored in the file header
147 : };
148 :
149 : #endif
|