1 | //============================================================================ |
2 | // |
3 | // SSSS tt lll lll |
4 | // SS SS tt ll ll |
5 | // SS tttttt eeee ll ll aaaa |
6 | // SSSS tt ee ee ll ll aa |
7 | // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" |
8 | // SS SS tt ee ll ll aa aa |
9 | // SSSS ttt eeeee llll llll aaaaa |
10 | // |
11 | // Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony |
12 | // and the Stella Team |
13 | // |
14 | // See the file "License.txt" for information on usage and redistribution of |
15 | // this file, and for a DISCLAIMER OF ALL WARRANTIES. |
16 | //============================================================================ |
17 | |
18 | #include "FSNode.hxx" |
19 | #include "Serializer.hxx" |
20 | |
21 | using std::ios; |
22 | using std::ios_base; |
23 | |
24 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
25 | Serializer::Serializer(const string& filename, Mode m) |
26 | : myStream(nullptr) |
27 | { |
28 | if(m == Mode::ReadOnly) |
29 | { |
30 | FilesystemNode node(filename); |
31 | if(node.isFile() && node.isReadable()) |
32 | { |
33 | unique_ptr<fstream> str = make_unique<fstream>(filename, ios::in | ios::binary); |
34 | if(str && str->is_open()) |
35 | { |
36 | myStream = std::move(str); |
37 | myStream->exceptions( ios_base::failbit | ios_base::badbit | ios_base::eofbit ); |
38 | rewind(); |
39 | } |
40 | } |
41 | } |
42 | else |
43 | { |
44 | // When using fstreams, we need to manually create the file first |
45 | // if we want to use it in read/write mode, since it won't be created |
46 | // if it doesn't already exist |
47 | // However, if it *does* exist, we don't want to overwrite it |
48 | // So we open in write and append mode - the write creates the file |
49 | // when necessary, and the append doesn't delete any data if it |
50 | // already exists |
51 | fstream temp(filename, ios::out | ios::app); |
52 | temp.close(); |
53 | |
54 | ios_base::openmode stream_mode = ios::in | ios::out | ios::binary; |
55 | if(m == Mode::ReadWriteTrunc) |
56 | stream_mode |= ios::trunc; |
57 | unique_ptr<fstream> str = make_unique<fstream>(filename, stream_mode); |
58 | if(str && str->is_open()) |
59 | { |
60 | myStream = std::move(str); |
61 | myStream->exceptions( ios_base::failbit | ios_base::badbit | ios_base::eofbit ); |
62 | rewind(); |
63 | } |
64 | } |
65 | } |
66 | |
67 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
68 | Serializer::Serializer() |
69 | : myStream(nullptr) |
70 | { |
71 | myStream = make_unique<stringstream>(ios::in | ios::out | ios::binary); |
72 | |
73 | // For some reason, Windows and possibly macOS needs to store something in |
74 | // the stream before it is used for the first time |
75 | if(myStream) |
76 | { |
77 | myStream->exceptions( ios_base::failbit | ios_base::badbit | ios_base::eofbit ); |
78 | putBool(true); |
79 | rewind(); |
80 | } |
81 | } |
82 | |
83 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
84 | void Serializer::rewind() |
85 | { |
86 | myStream->clear(); |
87 | myStream->seekg(ios_base::beg); |
88 | myStream->seekp(ios_base::beg); |
89 | } |
90 | |
91 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
92 | size_t Serializer::size() const |
93 | { |
94 | return myStream->tellp(); |
95 | } |
96 | |
97 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
98 | uInt8 Serializer::getByte() const |
99 | { |
100 | char buf; |
101 | myStream->read(&buf, 1); |
102 | |
103 | return buf; |
104 | } |
105 | |
106 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
107 | void Serializer::getByteArray(uInt8* array, size_t size) const |
108 | { |
109 | myStream->read(reinterpret_cast<char*>(array), size); |
110 | } |
111 | |
112 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
113 | uInt16 Serializer::getShort() const |
114 | { |
115 | uInt16 val = 0; |
116 | myStream->read(reinterpret_cast<char*>(&val), sizeof(uInt16)); |
117 | |
118 | return val; |
119 | } |
120 | |
121 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
122 | void Serializer::getShortArray(uInt16* array, size_t size) const |
123 | { |
124 | myStream->read(reinterpret_cast<char*>(array), sizeof(uInt16)*size); |
125 | } |
126 | |
127 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
128 | uInt32 Serializer::getInt() const |
129 | { |
130 | uInt32 val = 0; |
131 | myStream->read(reinterpret_cast<char*>(&val), sizeof(uInt32)); |
132 | |
133 | return val; |
134 | } |
135 | |
136 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
137 | void Serializer::getIntArray(uInt32* array, size_t size) const |
138 | { |
139 | myStream->read(reinterpret_cast<char*>(array), sizeof(uInt32)*size); |
140 | } |
141 | |
142 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
143 | uInt64 Serializer::getLong() const |
144 | { |
145 | uInt64 val = 0; |
146 | myStream->read(reinterpret_cast<char*>(&val), sizeof(uInt64)); |
147 | |
148 | return val; |
149 | } |
150 | |
151 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
152 | double Serializer::getDouble() const |
153 | { |
154 | double val = 0.0; |
155 | myStream->read(reinterpret_cast<char*>(&val), sizeof(double)); |
156 | |
157 | return val; |
158 | } |
159 | |
160 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
161 | string Serializer::getString() const |
162 | { |
163 | int len = getInt(); |
164 | string str; |
165 | str.resize(len); |
166 | myStream->read(&str[0], len); |
167 | |
168 | return str; |
169 | } |
170 | |
171 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
172 | bool Serializer::getBool() const |
173 | { |
174 | return getByte() == TruePattern; |
175 | } |
176 | |
177 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
178 | void Serializer::putByte(uInt8 value) |
179 | { |
180 | myStream->write(reinterpret_cast<char*>(&value), 1); |
181 | } |
182 | |
183 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
184 | void Serializer::putByteArray(const uInt8* array, size_t size) |
185 | { |
186 | myStream->write(reinterpret_cast<const char*>(array), size); |
187 | } |
188 | |
189 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
190 | void Serializer::putShort(uInt16 value) |
191 | { |
192 | myStream->write(reinterpret_cast<char*>(&value), sizeof(uInt16)); |
193 | } |
194 | |
195 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
196 | void Serializer::putShortArray(const uInt16* array, size_t size) |
197 | { |
198 | myStream->write(reinterpret_cast<const char*>(array), sizeof(uInt16)*size); |
199 | } |
200 | |
201 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
202 | void Serializer::putInt(uInt32 value) |
203 | { |
204 | myStream->write(reinterpret_cast<char*>(&value), sizeof(uInt32)); |
205 | } |
206 | |
207 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
208 | void Serializer::putIntArray(const uInt32* array, size_t size) |
209 | { |
210 | myStream->write(reinterpret_cast<const char*>(array), sizeof(uInt32)*size); |
211 | } |
212 | |
213 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
214 | void Serializer::putLong(uInt64 value) |
215 | { |
216 | myStream->write(reinterpret_cast<char*>(&value), sizeof(uInt64)); |
217 | } |
218 | |
219 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
220 | void Serializer::putDouble(double value) |
221 | { |
222 | myStream->write(reinterpret_cast<char*>(&value), sizeof(double)); |
223 | } |
224 | |
225 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
226 | void Serializer::putString(const string& str) |
227 | { |
228 | uInt32 len = uInt32(str.length()); |
229 | putInt(len); |
230 | myStream->write(str.data(), len); |
231 | } |
232 | |
233 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
234 | void Serializer::putBool(bool b) |
235 | { |
236 | putByte(b ? TruePattern: FalsePattern); |
237 | } |
238 | |