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
21using std::ios;
22using std::ios_base;
23
24// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
25Serializer::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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
68Serializer::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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
84void Serializer::rewind()
85{
86 myStream->clear();
87 myStream->seekg(ios_base::beg);
88 myStream->seekp(ios_base::beg);
89}
90
91// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
92size_t Serializer::size() const
93{
94 return myStream->tellp();
95}
96
97// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
98uInt8 Serializer::getByte() const
99{
100 char buf;
101 myStream->read(&buf, 1);
102
103 return buf;
104}
105
106// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
107void Serializer::getByteArray(uInt8* array, size_t size) const
108{
109 myStream->read(reinterpret_cast<char*>(array), size);
110}
111
112// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
113uInt16 Serializer::getShort() const
114{
115 uInt16 val = 0;
116 myStream->read(reinterpret_cast<char*>(&val), sizeof(uInt16));
117
118 return val;
119}
120
121// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
122void Serializer::getShortArray(uInt16* array, size_t size) const
123{
124 myStream->read(reinterpret_cast<char*>(array), sizeof(uInt16)*size);
125}
126
127// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
128uInt32 Serializer::getInt() const
129{
130 uInt32 val = 0;
131 myStream->read(reinterpret_cast<char*>(&val), sizeof(uInt32));
132
133 return val;
134}
135
136// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
137void Serializer::getIntArray(uInt32* array, size_t size) const
138{
139 myStream->read(reinterpret_cast<char*>(array), sizeof(uInt32)*size);
140}
141
142// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
143uInt64 Serializer::getLong() const
144{
145 uInt64 val = 0;
146 myStream->read(reinterpret_cast<char*>(&val), sizeof(uInt64));
147
148 return val;
149}
150
151// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
152double 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
161string 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
172bool Serializer::getBool() const
173{
174 return getByte() == TruePattern;
175}
176
177// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
178void Serializer::putByte(uInt8 value)
179{
180 myStream->write(reinterpret_cast<char*>(&value), 1);
181}
182
183// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
184void Serializer::putByteArray(const uInt8* array, size_t size)
185{
186 myStream->write(reinterpret_cast<const char*>(array), size);
187}
188
189// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
190void Serializer::putShort(uInt16 value)
191{
192 myStream->write(reinterpret_cast<char*>(&value), sizeof(uInt16));
193}
194
195// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
196void Serializer::putShortArray(const uInt16* array, size_t size)
197{
198 myStream->write(reinterpret_cast<const char*>(array), sizeof(uInt16)*size);
199}
200
201// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
202void Serializer::putInt(uInt32 value)
203{
204 myStream->write(reinterpret_cast<char*>(&value), sizeof(uInt32));
205}
206
207// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
208void Serializer::putIntArray(const uInt32* array, size_t size)
209{
210 myStream->write(reinterpret_cast<const char*>(array), sizeof(uInt32)*size);
211}
212
213// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
214void Serializer::putLong(uInt64 value)
215{
216 myStream->write(reinterpret_cast<char*>(&value), sizeof(uInt64));
217}
218
219// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
220void Serializer::putDouble(double value)
221{
222 myStream->write(reinterpret_cast<char*>(&value), sizeof(double));
223}
224
225// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
226void Serializer::putString(const string& str)
227{
228 uInt32 len = uInt32(str.length());
229 putInt(len);
230 myStream->write(str.data(), len);
231}
232
233// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
234void Serializer::putBool(bool b)
235{
236 putByte(b ? TruePattern: FalsePattern);
237}
238