1 /*
2 ** farchive.cpp
3 ** Implements an archiver for DObject serialization.
4 **
5 **---------------------------------------------------------------------------
6 ** Copyright 1998-2009 Randy Heit
7 ** All rights reserved.
8 **
9 ** Redistribution and use in source and binary forms, with or without
10 ** modification, are permitted provided that the following conditions
11 ** are met:
12 **
13 ** 1. Redistributions of source code must retain the above copyright
14 **    notice, this list of conditions and the following disclaimer.
15 ** 2. Redistributions in binary form must reproduce the above copyright
16 **    notice, this list of conditions and the following disclaimer in the
17 **    documentation and/or other materials provided with the distribution.
18 ** 3. The name of the author may not be used to endorse or promote products
19 **    derived from this software without specific prior written permission.
20 **
21 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 **---------------------------------------------------------------------------
32 **
33 ** The structure of the archive file generated is influenced heavily by the
34 ** description of the MFC archive format published somewhere in the MSDN
35 ** library.
36 **
37 ** Two major shortcomings of the format I use are that there is no version
38 ** control and no support for storing the non-default portions of objects.
39 ** The latter would allow for easier extension of objects in future
40 ** releases even without a versioning system.
41 */
42 
43 #include <stddef.h>
44 #include <string.h>
45 #include <zlib.h>
46 #include <stdlib.h>
47 
48 #include "doomtype.h"
49 #include "farchive.h"
50 #include "m_swap.h"
51 #include "m_crc32.h"
52 #include "cmdlib.h"
53 #include "i_system.h"
54 #include "c_cvars.h"
55 #include "c_dispatch.h"
56 #include "d_player.h"
57 #include "m_misc.h"
58 #include "dobject.h"
59 
60 // These are special tokens found in the data stream of an archive.
61 // Whenever a new object is encountered, it gets created using new and
62 // is then asked to serialize itself before processing of the previous
63 // object continues. This can result in some very deep recursion if
64 // you aren't careful about how you organize your data.
65 
66 #define NEW_OBJ				((BYTE)1)	// Data for a new object follows
67 #define NEW_CLS_OBJ			((BYTE)2)	// Data for a new class and object follows
68 #define OLD_OBJ				((BYTE)3)	// Reference to an old object follows
69 #define NULL_OBJ			((BYTE)4)	// Load as NULL
70 #define M1_OBJ				((BYTE)44)	// Load as (DObject*)-1
71 
72 #define NEW_PLYR_OBJ		((BYTE)5)	// Data for a new player follows
73 #define NEW_PLYR_CLS_OBJ	((BYTE)6)	// Data for a new class and player follows
74 
75 #define NEW_NAME			((BYTE)27)	// A new name follows
76 #define OLD_NAME			((BYTE)28)	// Reference to an old name follows
77 #define NIL_NAME			((BYTE)33)	// Load as NULL
78 
79 #define NEW_SPRITE			((BYTE)11)	// A new sprite name follows
80 #define OLD_SPRITE			((BYTE)12)	// Reference to an old sprite name follows
81 
82 #ifdef __BIG_ENDIAN__
SWAP_WORD(WORD x)83 static inline WORD SWAP_WORD(WORD x) { return x; }
SWAP_DWORD(DWORD x)84 static inline DWORD SWAP_DWORD(DWORD x) { return x; }
SWAP_QWORD(QWORD x)85 static inline QWORD SWAP_QWORD(QWORD x) { return x; }
SWAP_FLOAT(float x)86 static inline void SWAP_FLOAT(float x) { }
SWAP_DOUBLE(double & dst,double src)87 static inline void SWAP_DOUBLE(double &dst, double src) { dst = src; }
88 #else
89 #ifdef _MSC_VER
SWAP_WORD(WORD x)90 static inline WORD  SWAP_WORD(WORD x)		{ return _byteswap_ushort(x); }
SWAP_DWORD(DWORD x)91 static inline DWORD SWAP_DWORD(DWORD x)		{ return _byteswap_ulong(x); }
SWAP_QWORD(QWORD x)92 static inline QWORD SWAP_QWORD(QWORD x)		{ return _byteswap_uint64(x); }
SWAP_DOUBLE(double & dst,double & src)93 static inline void SWAP_DOUBLE(double &dst, double &src)
94 {
95 	union twiddle { QWORD q; double d; } tdst, tsrc;
96 	tsrc.d = src;
97 	tdst.q = _byteswap_uint64(tsrc.q);
98 	dst = tdst.d;
99 }
100 #else
SWAP_WORD(WORD x)101 static inline WORD  SWAP_WORD(WORD x)		{ return (((x)<<8) | ((x)>>8)); }
SWAP_DWORD(DWORD x)102 static inline DWORD SWAP_DWORD(DWORD x)		{ return x = (((x)>>24) | (((x)>>8)&0xff00) | (((x)<<8)&0xff0000) | ((x)<<24)); }
SWAP_QWORD(QWORD x)103 static inline QWORD SWAP_QWORD(QWORD x)
104 {
105 	union { QWORD q; DWORD d[2]; } t, u;
106 	t.q = x;
107 	u.d[0] = SWAP_DWORD(t.d[1]);
108 	u.d[1] = SWAP_DWORD(t.d[0]);
109 	return u.q;
110 }
SWAP_DOUBLE(double & dst,double & src)111 static inline void SWAP_DOUBLE(double &dst, double &src)
112 {
113 	union twiddle { double f; DWORD d[2]; } tdst, tsrc;
114 	DWORD t;
115 
116 	tsrc.f = src;
117 	t = tsrc.d[0];
118 	tdst.d[0] = SWAP_DWORD(tsrc.d[1]);
119 	tdst.d[1] = SWAP_DWORD(t);
120 	dst = tdst.f;
121 }
122 #endif
SWAP_FLOAT(float & x)123 static inline void SWAP_FLOAT(float &x)
124 {
125 	union twiddle { DWORD i; float f; } t;
126 	t.f = x;
127 	t.i = SWAP_DWORD(t.i);
128 	x = t.f;
129 }
130 #endif
131 
132 // Output buffer size for compression; need some extra space.
133 // I assume the description in zlib.h is accurate.
134 #define OUT_LEN(a)		((a) + (a) / 1000 + 12)
135 
BeEmpty()136 void FCompressedFile::BeEmpty ()
137 {
138 	m_Pos = 0;
139 	m_BufferSize = 0;
140 	m_MaxBufferSize = 0;
141 	m_Buffer = NULL;
142 	m_File = NULL;
143 	m_NoCompress = false;
144 	m_Mode = ENotOpen;
145 }
146 
147 static const char LZOSig[4] = { 'F', 'L', 'Z', 'O' };
148 static const char ZSig[4] = { 'F', 'L', 'Z', 'L' };
149 
FCompressedFile()150 FCompressedFile::FCompressedFile ()
151 {
152 	BeEmpty ();
153 }
154 
FCompressedFile(const char * name,EOpenMode mode,bool dontCompress)155 FCompressedFile::FCompressedFile (const char *name, EOpenMode mode, bool dontCompress)
156 {
157 	BeEmpty ();
158 	Open (name, mode);
159 	m_NoCompress = dontCompress;
160 }
161 
FCompressedFile(FILE * file,EOpenMode mode,bool dontCompress,bool postopen)162 FCompressedFile::FCompressedFile (FILE *file, EOpenMode mode, bool dontCompress, bool postopen)
163 {
164 	BeEmpty ();
165 	m_Mode = mode;
166 	m_File = file;
167 	m_NoCompress = dontCompress;
168 	if (postopen)
169 	{
170 		PostOpen ();
171 	}
172 }
173 
~FCompressedFile()174 FCompressedFile::~FCompressedFile ()
175 {
176 	Close ();
177 }
178 
Open(const char * name,EOpenMode mode)179 bool FCompressedFile::Open (const char *name, EOpenMode mode)
180 {
181 	Close ();
182 	if (name == NULL)
183 		return false;
184 	m_Mode = mode;
185 	m_File = fopen (name, mode == EReading ? "rb" : "wb");
186 	PostOpen ();
187 	return !!m_File;
188 }
189 
PostOpen()190 void FCompressedFile::PostOpen ()
191 {
192 	if (m_File && m_Mode == EReading)
193 	{
194 		char sig[4];
195 		fread (sig, 4, 1, m_File);
196 		if (sig[0] != ZSig[0] || sig[1] != ZSig[1] || sig[2] != ZSig[2] || sig[3] != ZSig[3])
197 		{
198 			fclose (m_File);
199 			m_File = NULL;
200 			if (sig[0] == LZOSig[0] && sig[1] == LZOSig[1] && sig[2] == LZOSig[2] && sig[3] == LZOSig[3])
201 			{
202 				Printf ("Compressed files from older ZDooms are not supported.\n");
203 			}
204 			return;
205 		}
206 		else
207 		{
208 			DWORD sizes[2];
209 			fread (sizes, sizeof(DWORD), 2, m_File);
210 			sizes[0] = SWAP_DWORD (sizes[0]);
211 			sizes[1] = SWAP_DWORD (sizes[1]);
212 			unsigned int len = sizes[0] == 0 ? sizes[1] : sizes[0];
213 			m_Buffer = (BYTE *)M_Malloc (len+8);
214 			fread (m_Buffer+8, len, 1, m_File);
215 			sizes[0] = SWAP_DWORD (sizes[0]);
216 			sizes[1] = SWAP_DWORD (sizes[1]);
217 			((DWORD *)m_Buffer)[0] = sizes[0];
218 			((DWORD *)m_Buffer)[1] = sizes[1];
219 			Explode ();
220 		}
221 	}
222 }
223 
Close()224 void FCompressedFile::Close ()
225 {
226 	if (m_File)
227 	{
228 		if (m_Mode == EWriting)
229 		{
230 			Implode ();
231 			fwrite (ZSig, 4, 1, m_File);
232 			fwrite (m_Buffer, m_BufferSize + 8, 1, m_File);
233 		}
234 		fclose (m_File);
235 		m_File = NULL;
236 	}
237 	if (m_Buffer)
238 	{
239 		M_Free (m_Buffer);
240 		m_Buffer = NULL;
241 	}
242 	BeEmpty ();
243 }
244 
Flush()245 void FCompressedFile::Flush ()
246 {
247 }
248 
Mode() const249 FFile::EOpenMode FCompressedFile::Mode () const
250 {
251 	return m_Mode;
252 }
253 
IsOpen() const254 bool FCompressedFile::IsOpen () const
255 {
256 	return !!m_File;
257 }
258 
Write(const void * mem,unsigned int len)259 FFile &FCompressedFile::Write (const void *mem, unsigned int len)
260 {
261 	if (m_Mode == EWriting)
262 	{
263 		if (m_Pos + len > m_MaxBufferSize)
264 		{
265 			do
266 			{
267 				m_MaxBufferSize = m_MaxBufferSize ? m_MaxBufferSize * 2 : 16384;
268 			}
269 			while (m_Pos + len > m_MaxBufferSize);
270 			m_Buffer = (BYTE *)M_Realloc (m_Buffer, m_MaxBufferSize);
271 		}
272 		if (len == 1)
273 			m_Buffer[m_Pos] = *(BYTE *)mem;
274 		else
275 			memcpy (m_Buffer + m_Pos, mem, len);
276 		m_Pos += len;
277 		if (m_Pos > m_BufferSize)
278 			m_BufferSize = m_Pos;
279 	}
280 	else
281 	{
282 		I_Error ("Tried to write to reading cfile");
283 	}
284 	return *this;
285 }
286 
Read(void * mem,unsigned int len)287 FFile &FCompressedFile::Read (void *mem, unsigned int len)
288 {
289 	if (m_Mode == EReading)
290 	{
291 		if (m_Pos + len > m_BufferSize)
292 		{
293 			I_Error ("Attempt to read past end of cfile");
294 		}
295 		if (len == 1)
296 			*(BYTE *)mem = m_Buffer[m_Pos];
297 		else
298 			memcpy (mem, m_Buffer + m_Pos, len);
299 		m_Pos += len;
300 	}
301 	else
302 	{
303 		I_Error ("Tried to read from writing cfile");
304 	}
305 	return *this;
306 }
307 
Tell() const308 unsigned int FCompressedFile::Tell () const
309 {
310 	return m_Pos;
311 }
312 
Seek(int pos,ESeekPos ofs)313 FFile &FCompressedFile::Seek (int pos, ESeekPos ofs)
314 {
315 	if (ofs == ESeekRelative)
316 		pos += m_Pos;
317 	else if (ofs == ESeekEnd)
318 		pos = m_BufferSize - pos;
319 
320 	if (pos < 0)
321 		m_Pos = 0;
322 	else if ((unsigned)pos > m_BufferSize)
323 		m_Pos = m_BufferSize;
324 	else
325 		m_Pos = pos;
326 
327 	return *this;
328 }
329 
330 CVAR (Bool, nofilecompression, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
331 
Implode()332 void FCompressedFile::Implode ()
333 {
334 	uLong outlen;
335 	uLong len = m_BufferSize;
336 	Byte *compressed = NULL;
337 	BYTE *oldbuf = m_Buffer;
338 	int r;
339 
340 	if (!nofilecompression && !m_NoCompress)
341 	{
342 		outlen = OUT_LEN(len);
343 		do
344 		{
345 			compressed = new Bytef[outlen];
346 			r = compress (compressed, &outlen, m_Buffer, len);
347 			if (r == Z_BUF_ERROR)
348 			{
349 				delete[] compressed;
350 				outlen += 1024;
351 			}
352 		} while (r == Z_BUF_ERROR);
353 
354 		// If the data could not be compressed, store it as-is.
355 		if (r != Z_OK || outlen >= len)
356 		{
357 			DPrintf ("cfile could not be compressed\n");
358 			outlen = 0;
359 		}
360 		else
361 		{
362 			DPrintf ("cfile shrank from %lu to %lu bytes\n", len, outlen);
363 		}
364 	}
365 	else
366 	{
367 		outlen = 0;
368 	}
369 
370 	m_MaxBufferSize = m_BufferSize = ((outlen == 0) ? len : outlen);
371 	m_Buffer = (BYTE *)M_Malloc (m_BufferSize + 8);
372 	m_Pos = 0;
373 
374 	DWORD *lens = (DWORD *)(m_Buffer);
375 	lens[0] = BigLong((unsigned int)outlen);
376 	lens[1] = BigLong((unsigned int)len);
377 
378 	if (outlen == 0)
379 		memcpy (m_Buffer + 8, oldbuf, len);
380 	else
381 		memcpy (m_Buffer + 8, compressed, outlen);
382 	if (compressed)
383 		delete[] compressed;
384 	M_Free (oldbuf);
385 }
386 
Explode()387 void FCompressedFile::Explode ()
388 {
389 	uLong expandsize, cprlen;
390 	unsigned char *expand;
391 
392 	if (m_Buffer)
393 	{
394 		unsigned int *ints = (unsigned int *)(m_Buffer);
395 		cprlen = BigLong(ints[0]);
396 		expandsize = BigLong(ints[1]);
397 
398 		expand = (unsigned char *)M_Malloc (expandsize);
399 		if (cprlen)
400 		{
401 			int r;
402 			uLong newlen;
403 
404 			newlen = expandsize;
405 			r = uncompress (expand, &newlen, m_Buffer + 8, cprlen);
406 			if (r != Z_OK || newlen != expandsize)
407 			{
408 				M_Free (expand);
409 				I_Error ("Could not decompress buffer: %s", M_ZLibError(r).GetChars());
410 			}
411 		}
412 		else
413 		{
414 			memcpy (expand, m_Buffer + 8, expandsize);
415 		}
416 		if (FreeOnExplode ())
417 			M_Free (m_Buffer);
418 		m_Buffer = expand;
419 		m_BufferSize = expandsize;
420 	}
421 }
422 
FCompressedMemFile()423 FCompressedMemFile::FCompressedMemFile ()
424 {
425 	m_SourceFromMem = false;
426 	m_ImplodedBuffer = NULL;
427 }
428 
429 /*
430 FCompressedMemFile::FCompressedMemFile (const char *name, EOpenMode mode)
431 	: FCompressedFile (name, mode)
432 {
433 	m_SourceFromMem = false;
434 	m_ImplodedBuffer = NULL;
435 }
436 */
437 
~FCompressedMemFile()438 FCompressedMemFile::~FCompressedMemFile ()
439 {
440 	if (m_ImplodedBuffer != NULL)
441 	{
442 		M_Free (m_ImplodedBuffer);
443 	}
444 }
445 
Open(const char * name,EOpenMode mode)446 bool FCompressedMemFile::Open (const char *name, EOpenMode mode)
447 {
448 	if (mode == EWriting)
449 	{
450 		if (name)
451 		{
452 			I_Error ("FCompressedMemFile cannot write to disk");
453 		}
454 		else
455 		{
456 			return Open ();
457 		}
458 	}
459 	else
460 	{
461 		bool res = FCompressedFile::Open (name, EReading);
462 		if (res)
463 		{
464 			fclose (m_File);
465 			m_File = NULL;
466 		}
467 		return res;
468 	}
469 	return false;
470 }
471 
Open(void * memblock)472 bool FCompressedMemFile::Open (void *memblock)
473 {
474 	Close ();
475 	m_Mode = EReading;
476 	m_Buffer = (BYTE *)memblock;
477 	m_SourceFromMem = true;
478 	Explode ();
479 	m_SourceFromMem = false;
480 	return !!m_Buffer;
481 }
482 
Open()483 bool FCompressedMemFile::Open ()
484 {
485 	Close ();
486 	m_Mode = EWriting;
487 	m_BufferSize = 0;
488 	m_MaxBufferSize = 16384;
489 	m_Buffer = (unsigned char *)M_Malloc (16384);
490 	m_Pos = 0;
491 	return true;
492 }
493 
Reopen()494 bool FCompressedMemFile::Reopen ()
495 {
496 	if (m_Buffer == NULL && m_ImplodedBuffer)
497 	{
498 		m_Mode = EReading;
499 		m_Buffer = m_ImplodedBuffer;
500 		m_SourceFromMem = true;
501 		try
502 		{
503 			Explode ();
504 		}
505 		catch(...)
506 		{
507 			// If we just leave things as they are, m_Buffer and m_ImplodedBuffer
508 			// both point to the same memory block and both will try to free it.
509 			m_Buffer = NULL;
510 			m_SourceFromMem = false;
511 			throw;
512 		}
513 		m_SourceFromMem = false;
514 		return true;
515 	}
516 	return false;
517 }
518 
Close()519 void FCompressedMemFile::Close ()
520 {
521 	if (m_Mode == EWriting)
522 	{
523 		Implode ();
524 		m_ImplodedBuffer = m_Buffer;
525 		m_Buffer = NULL;
526 	}
527 }
528 
Serialize(FArchive & arc)529 void FCompressedMemFile::Serialize (FArchive &arc)
530 {
531 	if (arc.IsStoring ())
532 	{
533 		if (m_ImplodedBuffer == NULL)
534 		{
535 			I_Error ("FCompressedMemFile must be compressed before storing");
536 		}
537 		arc.Write (ZSig, 4);
538 
539 		DWORD sizes[2];
540 		sizes[0] = SWAP_DWORD (((DWORD *)m_ImplodedBuffer)[0]);
541 		sizes[1] = SWAP_DWORD (((DWORD *)m_ImplodedBuffer)[1]);
542 		arc.Write (m_ImplodedBuffer, (sizes[0] ? sizes[0] : sizes[1])+8);
543 	}
544 	else
545 	{
546 		Close ();
547 		m_Mode = EReading;
548 
549 		char sig[4];
550 		DWORD sizes[2] = { 0, 0 };
551 
552 		arc.Read (sig, 4);
553 
554 		if (sig[0] != ZSig[0] || sig[1] != ZSig[1] || sig[2] != ZSig[2] || sig[3] != ZSig[3])
555 			I_Error ("Expected to extract a compressed file");
556 
557 		arc << sizes[0] << sizes[1];
558 		DWORD len = sizes[0] == 0 ? sizes[1] : sizes[0];
559 
560 		m_Buffer = (BYTE *)M_Malloc (len+8);
561 		((DWORD *)m_Buffer)[0] = SWAP_DWORD(sizes[0]);
562 		((DWORD *)m_Buffer)[1] = SWAP_DWORD(sizes[1]);
563 		arc.Read (m_Buffer+8, len);
564 		m_ImplodedBuffer = m_Buffer;
565 		m_Buffer = NULL;
566 		m_Mode = EWriting;
567 	}
568 }
569 
IsOpen() const570 bool FCompressedMemFile::IsOpen () const
571 {
572 	return !!m_Buffer;
573 }
574 
GetSizes(unsigned int & compressed,unsigned int & uncompressed) const575 void FCompressedMemFile::GetSizes(unsigned int &compressed, unsigned int &uncompressed) const
576 {
577 	if (m_ImplodedBuffer != NULL)
578 	{
579 		compressed = BigLong(*(unsigned int *)m_ImplodedBuffer);
580 		uncompressed = BigLong(*(unsigned int *)(m_ImplodedBuffer + 4));
581 	}
582 	else
583 	{
584 		compressed = 0;
585 		uncompressed = m_BufferSize;
586 	}
587 }
588 
FPNGChunkFile(FILE * file,DWORD id)589 FPNGChunkFile::FPNGChunkFile (FILE *file, DWORD id)
590 	: FCompressedFile (file, EWriting, true, false), m_ChunkID (id)
591 {
592 }
593 
FPNGChunkFile(FILE * file,DWORD id,size_t chunklen)594 FPNGChunkFile::FPNGChunkFile (FILE *file, DWORD id, size_t chunklen)
595 	: FCompressedFile (file, EReading, true, false), m_ChunkID (id)
596 {
597 	m_Buffer = (BYTE *)M_Malloc (chunklen);
598 	m_BufferSize = (unsigned int)chunklen;
599 	fread (m_Buffer, chunklen, 1, m_File);
600 	// Skip the CRC for now. Maybe later it will be used.
601 	fseek (m_File, 4, SEEK_CUR);
602 }
603 
604 // Unlike FCompressedFile::Close, m_File is left open
Close()605 void FPNGChunkFile::Close ()
606 {
607 	DWORD data[2];
608 	DWORD crc;
609 
610 	if (m_File)
611 	{
612 		if (m_Mode == EWriting)
613 		{
614 			crc = CalcCRC32 ((BYTE *)&m_ChunkID, 4);
615 			crc = AddCRC32 (crc, (BYTE *)m_Buffer, m_BufferSize);
616 
617 			data[0] = BigLong(m_BufferSize);
618 			data[1] = m_ChunkID;
619 			fwrite (data, 8, 1, m_File);
620 			fwrite (m_Buffer, m_BufferSize, 1, m_File);
621 			crc = SWAP_DWORD (crc);
622 			fwrite (&crc, 4, 1, m_File);
623 		}
624 		m_File = NULL;
625 	}
626 	FCompressedFile::Close ();
627 }
628 
FPNGChunkArchive(FILE * file,DWORD id)629 FPNGChunkArchive::FPNGChunkArchive (FILE *file, DWORD id)
630 	: FArchive (), Chunk (file, id)
631 {
632 	AttachToFile (Chunk);
633 }
634 
FPNGChunkArchive(FILE * file,DWORD id,size_t len)635 FPNGChunkArchive::FPNGChunkArchive (FILE *file, DWORD id, size_t len)
636 	: FArchive (), Chunk (file, id, len)
637 {
638 	AttachToFile (Chunk);
639 }
640 
~FPNGChunkArchive()641 FPNGChunkArchive::~FPNGChunkArchive ()
642 {
643 	// Close before FArchive's destructor, because Chunk will be
644 	// destroyed before the FArchive is destroyed.
645 	Close ();
646 }
647 
648 //============================================
649 //
650 // FArchive
651 //
652 //============================================
653 
FArchive()654 FArchive::FArchive ()
655 {
656 }
657 
FArchive(FFile & file)658 FArchive::FArchive (FFile &file)
659 {
660 	AttachToFile (file);
661 }
662 
AttachToFile(FFile & file)663 void FArchive::AttachToFile (FFile &file)
664 {
665 	unsigned int i;
666 
667 	m_HubTravel = false;
668 	m_File = &file;
669 	m_MaxObjectCount = m_ObjectCount = 0;
670 	m_ObjectMap = NULL;
671 	if (file.Mode() == FFile::EReading)
672 	{
673 		m_Loading = true;
674 		m_Storing = false;
675 	}
676 	else
677 	{
678 		m_Loading = false;
679 		m_Storing = true;
680 	}
681 	m_Persistent = file.IsPersistent();
682 	m_TypeMap = NULL;
683 	m_TypeMap = new TypeMap[PClass::m_Types.Size()];
684 	for (i = 0; i < PClass::m_Types.Size(); i++)
685 	{
686 		m_TypeMap[i].toArchive = TypeMap::NO_INDEX;
687 		m_TypeMap[i].toCurrent = NULL;
688 	}
689 	m_ClassCount = 0;
690 	for (i = 0; i < EObjectHashSize; i++)
691 	{
692 		m_ObjectHash[i] = ~0;
693 		m_NameHash[i] = NameMap::NO_INDEX;
694 	}
695 	m_NumSprites = 0;
696 	m_SpriteMap = new int[sprites.Size()];
697 	for (size_t s = 0; s < sprites.Size(); ++s)
698 	{
699 		m_SpriteMap[s] = -1;
700 	}
701 }
702 
~FArchive()703 FArchive::~FArchive ()
704 {
705 	Close ();
706 	if (m_TypeMap)
707 		delete[] m_TypeMap;
708 	if (m_ObjectMap)
709 		M_Free (m_ObjectMap);
710 	if (m_SpriteMap)
711 		delete[] m_SpriteMap;
712 }
713 
Write(const void * mem,unsigned int len)714 void FArchive::Write (const void *mem, unsigned int len)
715 {
716 	m_File->Write (mem, len);
717 }
718 
Read(void * mem,unsigned int len)719 void FArchive::Read (void *mem, unsigned int len)
720 {
721 	m_File->Read (mem, len);
722 }
723 
Close()724 void FArchive::Close ()
725 {
726 	if (m_File)
727 	{
728 		m_File->Close ();
729 		m_File = NULL;
730 		DPrintf ("Processed %u objects\n", m_ObjectCount);
731 	}
732 }
733 
WriteCount(DWORD count)734 void FArchive::WriteCount (DWORD count)
735 {
736 	BYTE out;
737 
738 	do
739 	{
740 		out = count & 0x7f;
741 		if (count >= 0x80)
742 			out |= 0x80;
743 		Write (&out, sizeof(BYTE));
744 		count >>= 7;
745 	} while (count);
746 
747 }
748 
ReadCount()749 DWORD FArchive::ReadCount ()
750 {
751 	BYTE in;
752 	DWORD count = 0;
753 	int ofs = 0;
754 
755 	do
756 	{
757 		Read (&in, sizeof(BYTE));
758 		count |= (in & 0x7f) << ofs;
759 		ofs += 7;
760 	} while (in & 0x80);
761 
762 	return count;
763 }
764 
WriteName(const char * name)765 void FArchive::WriteName (const char *name)
766 {
767 	BYTE id;
768 
769 	if (name == NULL)
770 	{
771 		id = NIL_NAME;
772 		Write (&id, 1);
773 	}
774 	else
775 	{
776 		DWORD index = FindName (name);
777 		if (index != NameMap::NO_INDEX)
778 		{
779 			id = OLD_NAME;
780 			Write (&id, 1);
781 			WriteCount (index);
782 		}
783 		else
784 		{
785 			AddName (name);
786 			id = NEW_NAME;
787 			Write (&id, 1);
788 			WriteString (name);
789 		}
790 	}
791 }
792 
ReadName()793 const char *FArchive::ReadName ()
794 {
795 	BYTE id;
796 
797 	operator<< (id);
798 	if (id == NIL_NAME)
799 	{
800 		return NULL;
801 	}
802 	else if (id == OLD_NAME)
803 	{
804 		DWORD index = ReadCount ();
805 		if (index >= m_Names.Size())
806 		{
807 			I_Error ("Name %u has not been read yet\n", index);
808 		}
809 		return &m_NameStorage[m_Names[index].StringStart];
810 	}
811 	else if (id == NEW_NAME)
812 	{
813 		DWORD index;
814 		DWORD size = ReadCount ();
815 		char *str;
816 
817 		index = (DWORD)m_NameStorage.Reserve (size);
818 		str = &m_NameStorage[index];
819 		Read (str, size-1);
820 		str[size-1] = 0;
821 		AddName (index);
822 		return str;
823 	}
824 	else
825 	{
826 		I_Error ("Expected a name but got something else\n");
827 		return NULL;
828 	}
829 }
830 
WriteString(const char * str)831 void FArchive::WriteString (const char *str)
832 {
833 	if (str == NULL)
834 	{
835 		WriteCount (0);
836 	}
837 	else
838 	{
839 		DWORD size = (DWORD)(strlen (str) + 1);
840 		WriteCount (size);
841 		Write (str, size - 1);
842 	}
843 }
844 
operator <<(char * & str)845 FArchive &FArchive::operator<< (char *&str)
846 {
847 	if (m_Storing)
848 	{
849 		WriteString (str);
850 	}
851 	else
852 	{
853 		DWORD size = ReadCount ();
854 		char *str2;
855 
856 		if (size == 0)
857 		{
858 			str2 = NULL;
859 		}
860 		else
861 		{
862 			str2 = new char[size];
863 			size--;
864 			Read (str2, size);
865 			str2[size] = 0;
866 			ReplaceString ((char **)&str, str2);
867 		}
868 		if (str)
869 		{
870 			delete[] str;
871 		}
872 		str = str2;
873 	}
874 	return *this;
875 }
876 
operator <<(FString & str)877 FArchive &FArchive::operator<< (FString &str)
878 {
879 	if (m_Storing)
880 	{
881 		WriteString (str.GetChars());
882 	}
883 	else
884 	{
885 		DWORD size = ReadCount();
886 
887 		if (size == 0)
888 		{
889 			str = "";
890 		}
891 		else
892 		{
893 			char *str2 = (char *)alloca(size*sizeof(char));
894 			size--;
895 			Read (str2, size);
896 			str2[size] = 0;
897 			str = str2;
898 		}
899 	}
900 	return *this;
901 }
902 
operator <<(BYTE & c)903 FArchive &FArchive::operator<< (BYTE &c)
904 {
905 	if (m_Storing)
906 		Write (&c, sizeof(BYTE));
907 	else
908 		Read (&c, sizeof(BYTE));
909 	return *this;
910 }
911 
operator <<(WORD & w)912 FArchive &FArchive::operator<< (WORD &w)
913 {
914 	if (m_Storing)
915 	{
916 		WORD temp = SWAP_WORD(w);
917 		Write (&temp, sizeof(WORD));
918 	}
919 	else
920 	{
921 		Read (&w, sizeof(WORD));
922 		w = SWAP_WORD(w);
923 	}
924 	return *this;
925 }
926 
operator <<(DWORD & w)927 FArchive &FArchive::operator<< (DWORD &w)
928 {
929 	if (m_Storing)
930 	{
931 		DWORD temp = SWAP_DWORD(w);
932 		Write (&temp, sizeof(DWORD));
933 	}
934 	else
935 	{
936 		Read (&w, sizeof(DWORD));
937 		w = SWAP_DWORD(w);
938 	}
939 	return *this;
940 }
941 
operator <<(QWORD & w)942 FArchive &FArchive::operator<< (QWORD &w)
943 {
944 	if (m_Storing)
945 	{
946 		QWORD temp = SWAP_QWORD(w);
947 		Write (&temp, sizeof(QWORD));
948 	}
949 	else
950 	{
951 		Read (&w, sizeof(QWORD));
952 		w = SWAP_QWORD(w);
953 	}
954 	return *this;
955 }
956 
operator <<(float & w)957 FArchive &FArchive::operator<< (float &w)
958 {
959 	if (m_Storing)
960 	{
961 		float temp = w;
962 		SWAP_FLOAT(temp);
963 		Write (&temp, sizeof(float));
964 	}
965 	else
966 	{
967 		Read (&w, sizeof(float));
968 		SWAP_FLOAT(w);
969 	}
970 	return *this;
971 }
972 
operator <<(double & w)973 FArchive &FArchive::operator<< (double &w)
974 {
975 	if (m_Storing)
976 	{
977 		double temp;
978 		SWAP_DOUBLE(temp,w);
979 		Write (&temp, sizeof(double));
980 	}
981 	else
982 	{
983 		Read (&w, sizeof(double));
984 		SWAP_DOUBLE(w,w);
985 	}
986 	return *this;
987 }
988 
operator <<(FName & n)989 FArchive &FArchive::operator<< (FName &n)
990 { // In an archive, a "name" is a string that might be stored multiple times,
991   // so it is only stored once. It is still treated as a normal string. In the
992   // rest of the game, a name is a unique identifier for a number.
993 	if (m_Storing)
994 	{
995 		WriteName (n.GetChars());
996 	}
997 	else
998 	{
999 		n = FName(ReadName());
1000 	}
1001 	return *this;
1002 }
1003 
SerializePointer(void * ptrbase,BYTE ** ptr,DWORD elemSize)1004 FArchive &FArchive::SerializePointer (void *ptrbase, BYTE **ptr, DWORD elemSize)
1005 {
1006 	DWORD w;
1007 
1008 	if (m_Storing)
1009 	{
1010 		if (*(void **)ptr)
1011 		{
1012 			w = DWORD(((size_t)*ptr - (size_t)ptrbase) / elemSize);
1013 		}
1014 		else
1015 		{
1016 			w = ~0u;
1017 		}
1018 		WriteCount (w);
1019 	}
1020 	else
1021 	{
1022 		w = ReadCount ();
1023 		if (w != ~0u)
1024 		{
1025 			*(void **)ptr = (BYTE *)ptrbase + w * elemSize;
1026 		}
1027 		else
1028 		{
1029 			*(void **)ptr = NULL;
1030 		}
1031 	}
1032 	return *this;
1033 }
1034 
SerializeObject(DObject * & object,PClass * type)1035 FArchive &FArchive::SerializeObject (DObject *&object, PClass *type)
1036 {
1037 	if (IsStoring ())
1038 	{
1039 		return WriteObject (object);
1040 	}
1041 	else
1042 	{
1043 		return ReadObject (object, type);
1044 	}
1045 }
1046 
WriteObject(DObject * obj)1047 FArchive &FArchive::WriteObject (DObject *obj)
1048 {
1049 	player_t *player;
1050 	BYTE id[2];
1051 
1052 	if (obj == NULL)
1053 	{
1054 		id[0] = NULL_OBJ;
1055 		Write (id, 1);
1056 	}
1057 	else if (obj == (DObject*)~0)
1058 	{
1059 		id[0] = M1_OBJ;
1060 		Write (id, 1);
1061 	}
1062 	else if (obj->ObjectFlags & OF_EuthanizeMe)
1063 	{
1064 		// Objects that want to die are not saved to the archive, but
1065 		// we leave the pointers to them alone.
1066 		id[0] = NULL_OBJ;
1067 		Write (id, 1);
1068 	}
1069 	else
1070 	{
1071 		const PClass *type = RUNTIME_TYPE(obj);
1072 
1073 		if (type == RUNTIME_CLASS(DObject))
1074 		{
1075 			//I_Error ("Tried to save an instance of DObject.\n"
1076 			//		 "This should not happen.\n");
1077 			id[0] = NULL_OBJ;
1078 			Write (id, 1);
1079 		}
1080 		else if (m_TypeMap[type->ClassIndex].toArchive == TypeMap::NO_INDEX)
1081 		{
1082 			// No instances of this class have been written out yet.
1083 			// Write out the class, then write out the object. If this
1084 			// is an actor controlled by a player, make note of that
1085 			// so that it can be overridden when moving around in a hub.
1086 			if (obj->IsKindOf (RUNTIME_CLASS (AActor)) &&
1087 				(player = static_cast<AActor *>(obj)->player) &&
1088 				player->mo == obj)
1089 			{
1090 				id[0] = NEW_PLYR_CLS_OBJ;
1091 				id[1] = (BYTE)(player - players);
1092 				Write (id, 2);
1093 			}
1094 			else
1095 			{
1096 				id[0] = NEW_CLS_OBJ;
1097 				Write (id, 1);
1098 			}
1099 			WriteClass (type);
1100 //			Printf ("Make class %s (%u)\n", type->Name, m_File->Tell());
1101 			MapObject (obj);
1102 			obj->SerializeUserVars (*this);
1103 			obj->Serialize (*this);
1104 			obj->CheckIfSerialized ();
1105 		}
1106 		else
1107 		{
1108 			// An instance of this class has already been saved. If
1109 			// this object has already been written, save a reference
1110 			// to the saved object. Otherwise, save a reference to the
1111 			// class, then save the object. Again, if this is a player-
1112 			// controlled actor, remember that.
1113 			DWORD index = FindObjectIndex (obj);
1114 
1115 			if (index == TypeMap::NO_INDEX)
1116 			{
1117 
1118 				if (obj->IsKindOf (RUNTIME_CLASS (AActor)) &&
1119 					(player = static_cast<AActor *>(obj)->player) &&
1120 					player->mo == obj)
1121 				{
1122 					id[0] = NEW_PLYR_OBJ;
1123 					id[1] = (BYTE)(player - players);
1124 					Write (id, 2);
1125 				}
1126 				else
1127 				{
1128 					id[0] = NEW_OBJ;
1129 					Write (id, 1);
1130 				}
1131 				WriteCount (m_TypeMap[type->ClassIndex].toArchive);
1132 //				Printf ("Reuse class %s (%u)\n", type->Name, m_File->Tell());
1133 				MapObject (obj);
1134 				obj->SerializeUserVars (*this);
1135 				obj->Serialize (*this);
1136 				obj->CheckIfSerialized ();
1137 			}
1138 			else
1139 			{
1140 				id[0] = OLD_OBJ;
1141 				Write (id, 1);
1142 				WriteCount (index);
1143 			}
1144 		}
1145 	}
1146 	return *this;
1147 }
1148 
ReadObject(DObject * & obj,PClass * wanttype)1149 FArchive &FArchive::ReadObject (DObject* &obj, PClass *wanttype)
1150 {
1151 	BYTE objHead;
1152 	const PClass *type;
1153 	BYTE playerNum;
1154 	DWORD index;
1155 
1156 	operator<< (objHead);
1157 
1158 	switch (objHead)
1159 	{
1160 	case NULL_OBJ:
1161 		obj = NULL;
1162 		break;
1163 
1164 	case M1_OBJ:
1165 		obj = (DObject *)~0;
1166 		break;
1167 
1168 	case OLD_OBJ:
1169 		index = ReadCount ();
1170 		if (index >= m_ObjectCount)
1171 		{
1172 			I_Error ("Object reference too high (%u; max is %u)\n", index, m_ObjectCount);
1173 		}
1174 		obj = (DObject *)m_ObjectMap[index].object;
1175 		break;
1176 
1177 	case NEW_PLYR_CLS_OBJ:
1178 		operator<< (playerNum);
1179 		if (m_HubTravel)
1180 		{
1181 			// If travelling inside a hub, use the existing player actor
1182 			type = ReadClass (wanttype);
1183 //			Printf ("New player class: %s (%u)\n", type->Name, m_File->Tell());
1184 			obj = players[playerNum].mo;
1185 
1186 			// But also create a new one so that we can get past the one
1187 			// stored in the archive.
1188 			AActor *tempobj = static_cast<AActor *>(type->CreateNew ());
1189 			MapObject (obj != NULL ? obj : tempobj);
1190 			tempobj->SerializeUserVars (*this);
1191 			tempobj->Serialize (*this);
1192 			tempobj->CheckIfSerialized ();
1193 			// If this player is not present anymore, keep the new body
1194 			// around just so that the load will succeed.
1195 			if (obj != NULL)
1196 			{
1197 				// When the temporary player's inventory items were loaded,
1198 				// they became owned by the real player. Undo that now.
1199 				for (AInventory *item = tempobj->Inventory; item != NULL; item = item->Inventory)
1200 				{
1201 					item->Owner = tempobj;
1202 				}
1203 				tempobj->Destroy ();
1204 			}
1205 			else
1206 			{
1207 				obj = tempobj;
1208 				players[playerNum].mo = static_cast<APlayerPawn *>(obj);
1209 			}
1210 			break;
1211 		}
1212 		/* fallthrough when not travelling to a previous level */
1213 	case NEW_CLS_OBJ:
1214 		type = ReadClass (wanttype);
1215 //		Printf ("New class: %s (%u)\n", type->Name, m_File->Tell());
1216 		obj = type->CreateNew ();
1217 		MapObject (obj);
1218 		obj->SerializeUserVars (*this);
1219 		obj->Serialize (*this);
1220 		obj->CheckIfSerialized ();
1221 		break;
1222 
1223 	case NEW_PLYR_OBJ:
1224 		operator<< (playerNum);
1225 		if (m_HubTravel)
1226 		{
1227 			type = ReadStoredClass (wanttype);
1228 //			Printf ("Use player class: %s (%u)\n", type->Name, m_File->Tell());
1229 			obj = players[playerNum].mo;
1230 
1231 			AActor *tempobj = static_cast<AActor *>(type->CreateNew ());
1232 			MapObject (obj != NULL ? obj : tempobj);
1233 			tempobj->SerializeUserVars (*this);
1234 			tempobj->Serialize (*this);
1235 			tempobj->CheckIfSerialized ();
1236 			if (obj != NULL)
1237 			{
1238 				for (AInventory *item = tempobj->Inventory;
1239 					item != NULL; item = item->Inventory)
1240 				{
1241 					item->Owner = tempobj;
1242 				}
1243 				tempobj->Destroy ();
1244 			}
1245 			else
1246 			{
1247 				obj = tempobj;
1248 				players[playerNum].mo = static_cast<APlayerPawn *>(obj);
1249 			}
1250 			break;
1251 		}
1252 		/* fallthrough when not travelling to a previous level */
1253 	case NEW_OBJ:
1254 		type = ReadStoredClass (wanttype);
1255 //		Printf ("Use class: %s (%u)\n", type->Name, m_File->Tell());
1256 		obj = type->CreateNew ();
1257 		MapObject (obj);
1258 		obj->SerializeUserVars (*this);
1259 		obj->Serialize (*this);
1260 		obj->CheckIfSerialized ();
1261 		break;
1262 
1263 	default:
1264 		I_Error ("Unknown object code (%d) in archive\n", objHead);
1265 	}
1266 	return *this;
1267 }
1268 
WriteSprite(int spritenum)1269 void FArchive::WriteSprite (int spritenum)
1270 {
1271 	BYTE id;
1272 
1273 	if ((unsigned)spritenum >= (unsigned)sprites.Size())
1274 	{
1275 		spritenum = 0;
1276 	}
1277 
1278 	if (m_SpriteMap[spritenum] < 0)
1279 	{
1280 		m_SpriteMap[spritenum] = (int)(m_NumSprites++);
1281 		id = NEW_SPRITE;
1282 		Write (&id, 1);
1283 		Write (sprites[spritenum].name, 4);
1284 
1285 		// Write the current sprite number as a hint, because
1286 		// these will only change between different versions.
1287 		WriteCount (spritenum);
1288 	}
1289 	else
1290 	{
1291 		id = OLD_SPRITE;
1292 		Write (&id, 1);
1293 		WriteCount (m_SpriteMap[spritenum]);
1294 	}
1295 }
1296 
ReadSprite()1297 int FArchive::ReadSprite ()
1298 {
1299 	BYTE id;
1300 
1301 	Read (&id, 1);
1302 	if (id == OLD_SPRITE)
1303 	{
1304 		DWORD index = ReadCount ();
1305 		if (index >= m_NumSprites)
1306 		{
1307 			I_Error ("Sprite %u has not been read yet\n", index);
1308 		}
1309 		return m_SpriteMap[index];
1310 	}
1311 	else if (id == NEW_SPRITE)
1312 	{
1313 		DWORD name;
1314 		DWORD hint;
1315 
1316 		Read (&name, 4);
1317 		hint = ReadCount ();
1318 
1319 		if (hint >= NumStdSprites || sprites[hint].dwName != name)
1320 		{
1321 			for (hint = NumStdSprites; hint-- != 0; )
1322 			{
1323 				if (sprites[hint].dwName == name)
1324 				{
1325 					break;
1326 				}
1327 			}
1328 			if (hint >= sprites.Size())
1329 			{ // Don't know this sprite, so just use the first one
1330 				hint = 0;
1331 			}
1332 		}
1333 		m_SpriteMap[m_NumSprites++] = hint;
1334 		return hint;
1335 	}
1336 	else
1337 	{
1338 		I_Error ("Expected a sprite but got something else\n");
1339 		return 0;
1340 	}
1341 }
1342 
AddName(const char * name)1343 DWORD FArchive::AddName (const char *name)
1344 {
1345 	DWORD index;
1346 	unsigned int hash = MakeKey (name) % EObjectHashSize;
1347 
1348 	index = FindName (name, hash);
1349 	if (index == NameMap::NO_INDEX)
1350 	{
1351 		DWORD namelen = (DWORD)(strlen (name) + 1);
1352 		DWORD strpos = (DWORD)m_NameStorage.Reserve (namelen);
1353 		NameMap mapper = { strpos, (DWORD)m_NameHash[hash] };
1354 
1355 		memcpy (&m_NameStorage[strpos], name, namelen);
1356 		m_NameHash[hash] = index = (DWORD)m_Names.Push (mapper);
1357 	}
1358 	return index;
1359 }
1360 
AddName(unsigned int start)1361 DWORD FArchive::AddName (unsigned int start)
1362 {
1363 	DWORD hash = MakeKey (&m_NameStorage[start]) % EObjectHashSize;
1364 	NameMap mapper = { (DWORD)start, (DWORD)m_NameHash[hash] };
1365 	return (DWORD)(m_NameHash[hash] = m_Names.Push (mapper));
1366 }
1367 
FindName(const char * name) const1368 DWORD FArchive::FindName (const char *name) const
1369 {
1370 	return FindName (name, MakeKey (name) % EObjectHashSize);
1371 }
1372 
FindName(const char * name,unsigned int bucket) const1373 DWORD FArchive::FindName (const char *name, unsigned int bucket) const
1374 {
1375 	unsigned int map = m_NameHash[bucket];
1376 
1377 	while (map != NameMap::NO_INDEX)
1378 	{
1379 		const NameMap *mapping = &m_Names[map];
1380 		if (strcmp (name, &m_NameStorage[mapping->StringStart]) == 0)
1381 		{
1382 			return (DWORD)map;
1383 		}
1384 		map = mapping->HashNext;
1385 	}
1386 	return (DWORD)map;
1387 }
1388 
WriteClass(const PClass * info)1389 DWORD FArchive::WriteClass (const PClass *info)
1390 {
1391 	if (m_ClassCount >= PClass::m_Types.Size())
1392 	{
1393 		I_Error ("Too many unique classes have been written.\nOnly %u were registered\n",
1394 			PClass::m_Types.Size());
1395 	}
1396 	if (m_TypeMap[info->ClassIndex].toArchive != TypeMap::NO_INDEX)
1397 	{
1398 		I_Error ("Attempt to write '%s' twice.\n", info->TypeName.GetChars());
1399 	}
1400 	m_TypeMap[info->ClassIndex].toArchive = m_ClassCount;
1401 	m_TypeMap[m_ClassCount].toCurrent = info;
1402 	WriteString (info->TypeName.GetChars());
1403 	return m_ClassCount++;
1404 }
1405 
ReadClass()1406 const PClass *FArchive::ReadClass ()
1407 {
1408 	struct String {
1409 		String() { val = NULL; }
1410 		~String() { if (val) delete[] val; }
1411 		char *val;
1412 	} typeName;
1413 
1414 	if (m_ClassCount >= PClass::m_Types.Size())
1415 	{
1416 		I_Error ("Too many unique classes have been read.\nOnly %u were registered\n",
1417 			PClass::m_Types.Size());
1418 	}
1419 	operator<< (typeName.val);
1420 	FName zaname(typeName.val, true);
1421 	if (zaname != NAME_None)
1422 	{
1423 		for (unsigned int i = PClass::m_Types.Size(); i-- > 0; )
1424 		{
1425 			if (PClass::m_Types[i]->TypeName == zaname)
1426 			{
1427 				m_TypeMap[i].toArchive = m_ClassCount;
1428 				m_TypeMap[m_ClassCount].toCurrent = PClass::m_Types[i];
1429 				m_ClassCount++;
1430 				return PClass::m_Types[i];
1431 			}
1432 		}
1433 	}
1434 	I_Error ("Unknown class '%s'\n", typeName.val);
1435 	return NULL;
1436 }
1437 
ReadClass(const PClass * wanttype)1438 const PClass *FArchive::ReadClass (const PClass *wanttype)
1439 {
1440 	const PClass *type = ReadClass ();
1441 	if (!type->IsDescendantOf (wanttype))
1442 	{
1443 		I_Error ("Expected to extract an object of type '%s'.\n"
1444 				 "Found one of type '%s' instead.\n",
1445 			wanttype->TypeName.GetChars(), type->TypeName.GetChars());
1446 	}
1447 	return type;
1448 }
1449 
ReadStoredClass(const PClass * wanttype)1450 const PClass *FArchive::ReadStoredClass (const PClass *wanttype)
1451 {
1452 	DWORD index = ReadCount ();
1453 	if (index >= m_ClassCount)
1454 	{
1455 		I_Error ("Class reference too high (%u; max is %u)\n", index, m_ClassCount);
1456 	}
1457 	const PClass *type = m_TypeMap[index].toCurrent;
1458 	if (!type->IsDescendantOf (wanttype))
1459 	{
1460 		I_Error ("Expected to extract an object of type '%s'.\n"
1461 				 "Found one of type '%s' instead.\n",
1462 			wanttype->TypeName.GetChars(), type->TypeName.GetChars());
1463 	}
1464 	return type;
1465 }
1466 
MapObject(const DObject * obj)1467 DWORD FArchive::MapObject (const DObject *obj)
1468 {
1469 	DWORD i;
1470 
1471 	if (m_ObjectCount >= m_MaxObjectCount)
1472 	{
1473 		m_MaxObjectCount = m_MaxObjectCount ? m_MaxObjectCount * 2 : 1024;
1474 		m_ObjectMap = (ObjectMap *)M_Realloc (m_ObjectMap, sizeof(ObjectMap)*m_MaxObjectCount);
1475 		for (i = m_ObjectCount; i < m_MaxObjectCount; i++)
1476 		{
1477 			m_ObjectMap[i].hashNext = ~0;
1478 			m_ObjectMap[i].object = NULL;
1479 		}
1480 	}
1481 
1482 	DWORD index = m_ObjectCount++;
1483 	DWORD hash = HashObject (obj);
1484 
1485 	m_ObjectMap[index].object = obj;
1486 	m_ObjectMap[index].hashNext = m_ObjectHash[hash];
1487 	m_ObjectHash[hash] = index;
1488 
1489 	return index;
1490 }
1491 
HashObject(const DObject * obj) const1492 DWORD FArchive::HashObject (const DObject *obj) const
1493 {
1494 	return (DWORD)((size_t)obj % EObjectHashSize);
1495 }
1496 
FindObjectIndex(const DObject * obj) const1497 DWORD FArchive::FindObjectIndex (const DObject *obj) const
1498 {
1499 	DWORD index = m_ObjectHash[HashObject (obj)];
1500 	while (index != TypeMap::NO_INDEX && m_ObjectMap[index].object != obj)
1501 	{
1502 		index = m_ObjectMap[index].hashNext;
1503 	}
1504 	return index;
1505 }
1506 
UserWriteClass(const PClass * type)1507 void FArchive::UserWriteClass (const PClass *type)
1508 {
1509 	BYTE id;
1510 
1511 	if (type == NULL)
1512 	{
1513 		id = 2;
1514 		Write (&id, 1);
1515 	}
1516 	else
1517 	{
1518 		if (m_TypeMap[type->ClassIndex].toArchive == TypeMap::NO_INDEX)
1519 		{
1520 			id = 1;
1521 			Write (&id, 1);
1522 			WriteClass (type);
1523 		}
1524 		else
1525 		{
1526 			id = 0;
1527 			Write (&id, 1);
1528 			WriteCount (m_TypeMap[type->ClassIndex].toArchive);
1529 		}
1530 	}
1531 }
1532 
UserReadClass(const PClass * & type)1533 void FArchive::UserReadClass (const PClass *&type)
1534 {
1535 	BYTE newclass;
1536 
1537 	Read (&newclass, 1);
1538 	switch (newclass)
1539 	{
1540 	case 0:
1541 		type = ReadStoredClass (RUNTIME_CLASS(DObject));
1542 		break;
1543 	case 1:
1544 		type = ReadClass ();
1545 		break;
1546 	case 2:
1547 		type = NULL;
1548 		break;
1549 	default:
1550 		I_Error ("Unknown class type %d in archive.\n", newclass);
1551 		break;
1552 	}
1553 }
1554 
operator <<(FArchive & arc,const PClass * & info)1555 FArchive &operator<< (FArchive &arc, const PClass * &info)
1556 {
1557 	if (arc.IsStoring ())
1558 	{
1559 		arc.UserWriteClass (info);
1560 	}
1561 	else
1562 	{
1563 		arc.UserReadClass (info);
1564 	}
1565 	return arc;
1566 }
1567 
operator <<(FArchive & arc,sector_t * & sec)1568 FArchive &operator<< (FArchive &arc, sector_t *&sec)
1569 {
1570 	return arc.SerializePointer (sectors, (BYTE **)&sec, sizeof(*sectors));
1571 }
1572 
operator <<(FArchive & arc,const sector_t * & sec)1573 FArchive &operator<< (FArchive &arc, const sector_t *&sec)
1574 {
1575 	return arc.SerializePointer (sectors, (BYTE **)&sec, sizeof(*sectors));
1576 }
1577 
operator <<(FArchive & arc,line_t * & line)1578 FArchive &operator<< (FArchive &arc, line_t *&line)
1579 {
1580 	return arc.SerializePointer (lines, (BYTE **)&line, sizeof(*lines));
1581 }
1582 
operator <<(FArchive & arc,vertex_t * & vert)1583 FArchive &operator<< (FArchive &arc, vertex_t *&vert)
1584 {
1585 	return arc.SerializePointer (vertexes, (BYTE **)&vert, sizeof(*vertexes));
1586 }
1587 
operator <<(FArchive & arc,side_t * & side)1588 FArchive &operator<< (FArchive &arc, side_t *&side)
1589 {
1590 	return arc.SerializePointer (sides, (BYTE **)&side, sizeof(*sides));
1591 }
1592