src/demo.cpp

changeset 18
6bf57b4f42cd
parent 17
b41d74bacdea
child 20
a5457405cc9b
equal deleted inserted replaced
17:b41d74bacdea 18:6bf57b4f42cd
19 #include <QFile> 19 #include <QFile>
20 #include <QDataStream> 20 #include <QDataStream>
21 #include <QMessageBox> 21 #include <QMessageBox>
22 #include <QProcess> 22 #include <QProcess>
23 #include "demo.h" 23 #include "demo.h"
24 #include "bytestream.h"
25 #include "misc.h" 24 #include "misc.h"
26 #include "ui_demoprompt.h" 25 #include "ui_demoprompt.h"
27 #include "prompts.h" 26 #include "prompts.h"
28 27
29 static const uint32 g_demoSignature = makeByteID ('Z', 'C', 'L', 'D'); 28 static const uint32 g_demoSignature = makeByteID ('Z', 'C', 'L', 'D');
99 return ""; 98 return "";
100 } 99 }
101 100
102 // ============================================================================= 101 // =============================================================================
103 // ----------------------------------------------------------------------------- 102 // -----------------------------------------------------------------------------
104 #ifdef _WIN32 103 QDataStream& operator>> (QDataStream& stream, str& out) {
105 # define FILE_FLAGS "rb" 104 uint8 c;
106 #else 105 out = "";
107 # define FILE_FLAGS "r" 106
108 #endif // _WIN32 107 for (stream >> c; c != '\0'; stream >> c)
109 108 out += c;
109
110 return stream;
111 }
112
113 // =============================================================================
114 // -----------------------------------------------------------------------------
110 int launchDemo (str path) { 115 int launchDemo (str path) {
111 FILE* fp = fopen (path.toStdString().c_str(), FILE_FLAGS); 116 QFile f (path);
112 117
113 if (!fp) { 118 if (!f.open (QIODevice::ReadOnly)) {
114 error (fmt (tr ("Couldn't open '%1' for reading: %2"), path, strerror (errno))); 119 error (fmt (tr ("Couldn't open '%1' for reading: %2"), path, strerror (errno)));
115 return 1; 120 return 1;
116 } 121 }
117 122
118 fseek (fp, 0, SEEK_END); 123 QDataStream stream (&f);
119 const size_t fsize = ftell (fp); 124 stream.setByteOrder (QDataStream::LittleEndian);
120 rewind (fp);
121
122 char* buf = new char[fsize];
123
124 const size_t bytesRead = fread (buf, 1, fsize, fp);
125 if (bytesRead != fsize) {
126 error (fmt (tr ("I/O error: %1 / %2 bytes read"), bytesRead, fsize));
127 delete[] buf;
128 return 2;
129 }
130
131 Bytestream s (buf, fsize);
132 delete[] buf;
133 125
134 uint8 offset; 126 uint8 offset;
135 uint32 length; 127 uint32 length;
128 uint16 zanversionID, numWads;
129 uint32 longSink;
130 str zanversion;
131 list<str> wads;
132 uint8 buildID;
133 bool ready = false;
136 134
137 struct { 135 struct {
138 str netname, skin, className; 136 str netname, skin, className;
139 uint8 gender, handicap, unlagged, respawnOnFire, ticsPerUpdate, connectionType; 137 uint8 gender, handicap, unlagged, respawnOnFire, ticsPerUpdate, connectionType;
140 uint32 color, aimdist, railcolor; 138 uint32 color, aimdist, railcolor;
142 140
143 // Check signature 141 // Check signature
144 { 142 {
145 uint32 sig; 143 uint32 sig;
146 144
147 if (!s.readLong (sig) || sig != g_demoSignature) { 145 stream >> sig;
146 if (sig != g_demoSignature) {
148 error (fmt (tr ("'%1' is not a Zandronum demo file!"), path)); 147 error (fmt (tr ("'%1' is not a Zandronum demo file!"), path));
149 return 3; 148 return 3;
150 } 149 }
151 } 150 }
152 151
153 // Zandronum stores CLD_DEMOLENGTH after the signature. This is also the 152 // Zandronum stores CLD_DEMOLENGTH after the signature. This is also the
154 // first demo enumerator, so we can determine the offset (which is variable!) 153 // first demo enumerator, so we can determine the offset (which is variable!)
155 // from this byte 154 // from this byte
156 s.readByte (offset); 155 stream >> offset
157 s.readLong (length); 156 >> length;
158
159 uint16 zanversionID, numWads;
160 uint32 longSink;
161 str zanversion;
162 list<str> wads;
163 bool ready = false;
164 uint8 buildID;
165 157
166 // Read the demo header and get data 158 // Read the demo header and get data
167 for (;;) { 159 for (;;) {
168 uint8 header; 160 uint8 header;
169 161 stream >> header;
170 if (!s.readByte (header)) 162 print ("header: %1\n", (int) header);
171 break;
172 163
173 if (header == DemoBodyStart + offset) { 164 if (header == DemoBodyStart + offset) {
174 ready = true; 165 ready = true;
175 break; 166 break;
176 } elif (header == DemoVersion + offset) { 167 } elif (header == DemoVersion + offset) {
177 s.readShort (zanversionID); 168 print ("Read demo version\n");
178 s.readString (zanversion); 169 stream >> zanversionID
170 >> zanversion;
171
172 print ("version ID: %1, version: %2\n", zanversionID, zanversion);
179 173
180 if (zanversion.left (4) != "1.1-" && zanversion.left (6) != "1.1.1-") 174 if (zanversion.left (4) != "1.1-" && zanversion.left (6) != "1.1.1-")
181 s.readByte (buildID); 175 stream >> buildID;
182 else 176 else {
177 // Assume a release build if not supplied. The demo only got the
178 // "ZCLD" signature in the 1.1 release build, 1.1.1 had no
179 // development binaries and the build ID will be included in 1.1.2.
183 buildID = 1; 180 buildID = 1;
184 181 }
185 s.readLong (longSink); // rng seed - we don't need it 182
183 stream >> longSink; // rng seed - we don't need it
186 } elif (header == DemoUserInfo + offset) { 184 } elif (header == DemoUserInfo + offset) {
187 s.readString (userinfo.netname); 185 print ("Read userinfo\n");
188 s.readByte (userinfo.gender); 186 stream >> userinfo.netname
189 s.readLong (userinfo.color); 187 >> userinfo.gender
190 s.readLong (userinfo.aimdist); 188 >> userinfo.color
191 s.readString (userinfo.skin); 189 >> userinfo.aimdist
192 s.readLong (userinfo.railcolor); 190 >> userinfo.skin
193 s.readByte (userinfo.handicap); 191 >> userinfo.railcolor
194 s.readByte (userinfo.unlagged); 192 >> userinfo.handicap
195 s.readByte (userinfo.respawnOnFire); 193 >> userinfo.unlagged
196 s.readByte (userinfo.ticsPerUpdate); 194 >> userinfo.respawnOnFire
197 s.readByte (userinfo.connectionType); 195 >> userinfo.ticsPerUpdate
198 s.readString (userinfo.className); 196 >> userinfo.connectionType
197 >> userinfo.className;
199 } elif (header == DemoWads + offset) { 198 } elif (header == DemoWads + offset) {
200 str sink; 199 str sink;
201 s.readShort (numWads); 200 stream >> numWads;
202 201
203 for (uint8 i = 0; i < numWads; ++i) { 202 for (uint8 i = 0; i < numWads; ++i) {
204 str wad; 203 str wad;
205 s.readString (wad); 204 stream >> wad;
206 wads << wad; 205 wads << wad;
207 } 206 }
208 207
209 // The demo has two checksum strings. We're not interested 208 // The demo has two checksum strings. We're not interested
210 // in them though. 209 // in them though. Down the sink they go...
211 for (int i = 0; i < 2; ++i) 210 for (int i = 0; i < 2; ++i)
212 s.readString (sink); 211 stream >> sink;
213 } else { 212 } else {
214 error (fmt (tr ("Unknown header %1!\n"), (int) header)); 213 error (fmt (tr ("Unknown header %1!\n"), (int) header));
215 return 3; 214 return 3;
216 } 215 }
217 } 216 }

mercurial