1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 /*
24  * This file is based on WME Lite.
25  * http://dead-code.org/redir.php?target=wmelite
26  * Copyright (c) 2011 Jan Nedoma
27  */
28 
29 #include "engines/wintermute/dcgf.h"
30 #include "engines/wintermute/base/base_file_manager.h"
31 #include "engines/wintermute/base/base_game.h"
32 #include "engines/wintermute/base/base_engine.h"
33 #include "engines/wintermute/base/base_persistence_manager.h"
34 #include "engines/wintermute/platform_osystem.h"
35 #include "engines/wintermute/math/vector2.h"
36 #include "engines/wintermute/base/gfx/base_image.h"
37 #include "engines/wintermute/base/save_thumb_helper.h"
38 #include "engines/wintermute/base/sound/base_sound.h"
39 #include "engines/wintermute/wintermute.h"
40 #include "graphics/scaler.h"
41 #include "image/bmp.h"
42 #include "common/memstream.h"
43 #include "common/str.h"
44 #include "common/system.h"
45 #include "common/savefile.h"
46 
47 #ifdef ENABLE_WME3D
48 #include "math/angle.h"
49 #include "math/matrix4.h"
50 #include "math/vector3d.h"
51 #endif
52 
53 namespace Wintermute {
54 
55 // The original WME-Lite savegames had the following:
56 //#define SAVE_MAGIC      0x45564153
57 //#define SAVE_MAGIC_2    0x32564153
58 // In case anyone tries to load original savegames, or for that matter
59 // in case we ever want to attempt to support original savegames, we
60 // avoid those numbers, and use this instead:
61 #define SAVE_MAGIC_3    0x12564154
62 
63 //////////////////////////////////////////////////////////////////////////
BasePersistenceManager(const Common::String & savePrefix,bool deleteSingleton)64 BasePersistenceManager::BasePersistenceManager(const Common::String &savePrefix, bool deleteSingleton) {
65 	_saving = false;
66 	_offset = 0;
67 	_saveStream = nullptr;
68 	_loadStream = nullptr;
69 	_deleteSingleton = deleteSingleton;
70 	if (BaseEngine::instance().getGameRef()) {
71 		_gameRef = BaseEngine::instance().getGameRef();
72 	} else {
73 		_gameRef = nullptr;
74 	}
75 
76 	_richBuffer = nullptr;
77 	_richBufferSize = 0;
78 
79 	_scummVMThumbnailData = nullptr;
80 	_scummVMThumbSize = 0;
81 
82 	_savedDescription = nullptr;
83 //	_savedTimestamp = 0;
84 	_savedVerMajor = _savedVerMinor = _savedVerBuild = 0;
85 	_savedExtMajor = _savedExtMinor = 0;
86 
87 	_savedTimestamp.tm_sec = 0;
88 	_savedTimestamp.tm_min = 0;
89 	_savedTimestamp.tm_hour = 0;
90 	_savedTimestamp.tm_mday = 0;
91 	_savedTimestamp.tm_mon = 0;
92 	_savedTimestamp.tm_year = 0;
93 	_savedTimestamp.tm_wday = 0;
94 
95 	_savedPlayTime = 0;
96 
97 	_thumbnailDataSize = 0;
98 	_thumbnailData = nullptr;
99 	if (savePrefix != "") {
100 		_savePrefix = savePrefix;
101 	} else if (_gameRef) {
102 		_savePrefix = _gameRef->getGameTargetName();
103 	} else {
104 		_savePrefix = "wmesav";
105 	}
106 }
107 
108 
109 //////////////////////////////////////////////////////////////////////////
~BasePersistenceManager()110 BasePersistenceManager::~BasePersistenceManager() {
111 	cleanup();
112 	if (_deleteSingleton && BaseEngine::instance().getGameRef() == nullptr)
113 		BaseEngine::destroy();
114 }
115 
116 
117 //////////////////////////////////////////////////////////////////////////
cleanup()118 void BasePersistenceManager::cleanup() {
119 	_offset = 0;
120 
121 	delete[] _richBuffer;
122 	_richBuffer = nullptr;
123 	_richBufferSize = 0;
124 
125 	delete[] _savedDescription;
126 	_savedDescription = nullptr; // ref to buffer
127 //	_savedTimestamp = 0;
128 	_savedVerMajor = _savedVerMinor = _savedVerBuild = 0;
129 	_savedExtMajor = _savedExtMinor = 0;
130 
131 	_thumbnailDataSize = 0;
132 	if (_thumbnailData) {
133 		delete[] _thumbnailData;
134 		_thumbnailData = nullptr;
135 	}
136 
137 	_scummVMThumbSize = 0;
138 	if (_scummVMThumbnailData) {
139 		delete[] _scummVMThumbnailData;
140 		_scummVMThumbnailData = nullptr;
141 	}
142 
143 	delete _loadStream;
144 	delete _saveStream;
145 	_loadStream = nullptr;
146 	_saveStream = nullptr;
147 }
148 
getFilenameForSlot(int slot) const149 Common::String BasePersistenceManager::getFilenameForSlot(int slot) const {
150 	// 3 Digits, to allow for one save-slot for autosave + slot 1 - 100 (which will be numbered 0-99 filename-wise)
151 	return Common::String::format("%s.%03d", _savePrefix.c_str(), slot);
152 }
153 
getSaveStateDesc(int slot,SaveStateDescriptor & desc)154 void BasePersistenceManager::getSaveStateDesc(int slot, SaveStateDescriptor &desc) {
155 	Common::String filename = getFilenameForSlot(slot);
156 	debugC(kWintermuteDebugSaveGame, "Trying to list savegame %s in slot %d", filename.c_str(), slot);
157 	if (DID_FAIL(readHeader(filename))) {
158 		debugC(kWintermuteDebugSaveGame, "getSavedDesc(%d) - Failed for %s", slot, filename.c_str());
159 		return;
160 	}
161 	desc.setSaveSlot(slot);
162 	desc.setDescription(_savedDescription);
163 	desc.setDeletableFlag(true);
164 	desc.setWriteProtectedFlag(false);
165 
166 	int thumbSize = 0;
167 	byte *thumbData = nullptr;
168 	if (_scummVMThumbSize > 0) {
169 		thumbSize = _scummVMThumbSize;
170 		thumbData = _scummVMThumbnailData;
171 	} else if (_thumbnailDataSize > 0) {
172 		thumbSize = _thumbnailDataSize;
173 		thumbData = _thumbnailData;
174 	}
175 
176 	if (thumbSize > 0) {
177 		Common::MemoryReadStream thumbStream(thumbData, thumbSize, DisposeAfterUse::NO);
178 		Image::BitmapDecoder bmpDecoder;
179 		if (bmpDecoder.loadStream(thumbStream)) {
180 			const Graphics::Surface *bmpSurface = bmpDecoder.getSurface();
181 			Graphics::Surface *scaled = bmpSurface->scale(kThumbnailWidth, kThumbnailHeight2);
182 			Graphics::Surface *thumb = scaled->convertTo(g_system->getOverlayFormat());
183 			desc.setThumbnail(thumb);
184 			scaled->free();
185 			delete scaled;
186 		}
187 	}
188 
189 	desc.setSaveDate(_savedTimestamp.tm_year + 1900, _savedTimestamp.tm_mon + 1, _savedTimestamp.tm_mday);
190 	desc.setSaveTime(_savedTimestamp.tm_hour, _savedTimestamp.tm_min);
191 	desc.setPlayTime(0);
192 }
193 
deleteSaveSlot(int slot)194 void BasePersistenceManager::deleteSaveSlot(int slot) {
195 	Common::String filename = getFilenameForSlot(slot);
196 	g_system->getSavefileManager()->removeSavefile(filename);
197 }
198 
getMaxUsedSlot()199 uint32 BasePersistenceManager::getMaxUsedSlot() {
200 	Common::String saveMask = Common::String::format("%s.???", _savePrefix.c_str());
201 	Common::StringArray saves = g_system->getSavefileManager()->listSavefiles(saveMask);
202 	Common::StringArray::iterator it = saves.begin();
203 	int ret = -1;
204 	for (; it != saves.end(); ++it) {
205 		int num = -1;
206 		sscanf(it->c_str(), ".%d", &num);
207 		ret = MAX(ret, num);
208 	}
209 	return ret;
210 }
211 
getSaveExists(int slot)212 bool BasePersistenceManager::getSaveExists(int slot) {
213 	Common::String filename = getFilenameForSlot(slot);
214 	if (DID_FAIL(readHeader(filename))) {
215 		return false;
216 	}
217 	return true;
218 }
219 
220 //////////////////////////////////////////////////////////////////////////
initSave(const Common::String & desc)221 bool BasePersistenceManager::initSave(const Common::String &desc) {
222 	if (desc == "") {
223 		return STATUS_FAILED;
224 	}
225 
226 	cleanup();
227 	_saving = true;
228 
229 	_saveStream = new Common::MemoryWriteStreamDynamic(DisposeAfterUse::YES);
230 
231 	if (_saveStream) {
232 		// get thumbnails
233 		if (!_gameRef->_cachedThumbnail) {
234 			_gameRef->_cachedThumbnail = new SaveThumbHelper(_gameRef);
235 			if (DID_FAIL(_gameRef->_cachedThumbnail->storeThumbnail(true))) {
236 				delete _gameRef->_cachedThumbnail;
237 				_gameRef->_cachedThumbnail = nullptr;
238 			}
239 		}
240 
241 		uint32 magic = DCGF_MAGIC;
242 		putDWORD(magic);
243 
244 		magic = SAVE_MAGIC_3;
245 		putDWORD(magic);
246 
247 		byte verMajor, verMinor, extMajor, extMinor;
248 		_gameRef->getVersion(&verMajor, &verMinor, &extMajor, &extMinor);
249 		_saveStream->writeByte(verMajor);
250 		_saveStream->writeByte(verMinor);
251 		_saveStream->writeByte(extMajor);
252 		_saveStream->writeByte(extMinor);
253 
254 		// new in ver 2
255 		putDWORD((uint32)DCGF_VER_BUILD);
256 		putString(_gameRef->getName());
257 
258 		// thumbnail data size
259 		bool thumbnailOK = false;
260 
261 		if (_gameRef->_cachedThumbnail) {
262 			if (_gameRef->_cachedThumbnail->_thumbnail) {
263 				Common::MemoryWriteStreamDynamic thumbStream(DisposeAfterUse::YES);
264 				if (_gameRef->_cachedThumbnail->_thumbnail->writeBMPToStream(&thumbStream)) {
265 					_saveStream->writeUint32LE(thumbStream.size());
266 					_saveStream->write(thumbStream.getData(), thumbStream.size());
267 				} else {
268 					_saveStream->writeUint32LE(0);
269 				}
270 
271 				thumbnailOK = true;
272 			}
273 		}
274 		if (!thumbnailOK) {
275 			putDWORD(0);
276 		}
277 		thumbnailOK = false;
278 		// Again for the ScummVM-thumb:
279 		if (_gameRef->_cachedThumbnail) {
280 			if (_gameRef->_cachedThumbnail->_scummVMThumb) {
281 				Common::MemoryWriteStreamDynamic scummVMthumbStream(DisposeAfterUse::YES);
282 				if (_gameRef->_cachedThumbnail->_scummVMThumb->writeBMPToStream(&scummVMthumbStream)) {
283 					_saveStream->writeUint32LE(scummVMthumbStream.size());
284 					_saveStream->write(scummVMthumbStream.getData(), scummVMthumbStream.size());
285 				} else {
286 					_saveStream->writeUint32LE(0);
287 				}
288 
289 				thumbnailOK = true;
290 			}
291 		}
292 		if (!thumbnailOK) {
293 			putDWORD(0);
294 		}
295 
296 
297 		// in any case, destroy the cached thumbnail once used
298 		delete _gameRef->_cachedThumbnail;
299 		_gameRef->_cachedThumbnail = nullptr;
300 
301 		uint32 dataOffset = _offset +
302 		                    sizeof(uint32) + // data offset
303 		                    sizeof(uint32) + strlen(desc.c_str()) + 1 + // description
304 		                    sizeof(uint32); // timestamp
305 
306 		putDWORD(dataOffset);
307 		putString(desc.c_str());
308 
309 		g_system->getTimeAndDate(_savedTimestamp);
310 		putTimeDate(_savedTimestamp);
311 		_savedPlayTime = g_system->getMillis();
312 		_saveStream->writeUint32LE(_savedPlayTime);
313 	}
314 	return STATUS_OK;
315 }
316 
readHeader(const Common::String & filename)317 bool BasePersistenceManager::readHeader(const Common::String &filename) {
318 	cleanup();
319 
320 	_saving = false;
321 
322 	_loadStream = g_system->getSavefileManager()->openForLoading(filename);
323 
324 	if (_loadStream) {
325 		uint32 magic;
326 		magic = getDWORD();
327 
328 		if (magic != DCGF_MAGIC) {
329 			cleanup();
330 			return STATUS_FAILED;
331 		}
332 
333 		magic = getDWORD();
334 
335 		if (magic == SAVE_MAGIC_3) {
336 			_savedVerMajor = _loadStream->readByte();
337 			_savedVerMinor = _loadStream->readByte();
338 			_savedExtMajor = _loadStream->readByte();
339 			_savedExtMinor = _loadStream->readByte();
340 
341 			_savedVerBuild = (byte)getDWORD();
342 			_savedName = getStringObj();
343 
344 			// load thumbnail
345 			_thumbnailDataSize = getDWORD();
346 			if (_thumbnailDataSize > 0) {
347 				_thumbnailData = new byte[_thumbnailDataSize];
348 				if (_thumbnailData) {
349 					getBytes(_thumbnailData, _thumbnailDataSize);
350 				} else {
351 					_thumbnailDataSize = 0;
352 				}
353 			}
354 
355 			_scummVMThumbSize = getDWORD();
356 			_scummVMThumbnailData = new byte[_scummVMThumbSize];
357 			if (_scummVMThumbnailData) {
358 				getBytes(_scummVMThumbnailData, _scummVMThumbSize);
359 			} else {
360 				_scummVMThumbSize = 0;
361 			}
362 
363 			uint32 dataOffset = getDWORD();
364 
365 			_savedDescription = getString();
366 			_savedTimestamp = getTimeDate();
367 			_savedPlayTime = _loadStream->readUint32LE();
368 
369 			_offset = dataOffset;
370 
371 			return STATUS_OK;
372 		}
373 	}
374 
375 	cleanup();
376 	return STATUS_FAILED;
377 }
378 
379 //////////////////////////////////////////////////////////////////////////
initLoad(const Common::String & filename)380 bool BasePersistenceManager::initLoad(const Common::String &filename) {
381 	if (DID_FAIL(readHeader(filename))) {
382 		cleanup();
383 		return STATUS_FAILED;
384 	}
385 	_saving = false;
386 
387 	if (_savedName == "" || scumm_stricmp(_savedName.c_str(), _gameRef->getName()) != 0) {
388 		debugC(kWintermuteDebugSaveGame, "ERROR: Saved game name doesn't match current game");
389 		cleanup();
390 		return STATUS_FAILED;
391 	}
392 
393 	// if save is newer version than we are, fail
394 	if (_savedVerMajor >  DCGF_VER_MAJOR ||
395 	        (_savedVerMajor == DCGF_VER_MAJOR && _savedVerMinor >  DCGF_VER_MINOR) ||
396 	        (_savedVerMajor == DCGF_VER_MAJOR && _savedVerMinor == DCGF_VER_MINOR && _savedVerBuild > DCGF_VER_BUILD)
397 	   ) {
398 
399 		debugC(kWintermuteDebugSaveGame, "ERROR: Saved game version is newer than current game");
400 		debugC(kWintermuteDebugSaveGame, "ERROR: Expected %d.%d.%d got %d.%d.%d", DCGF_VER_MAJOR, DCGF_VER_MINOR, DCGF_VER_BUILD, _savedVerMajor, _savedVerMinor, _savedVerBuild);
401 		cleanup();
402 		return STATUS_FAILED;
403 	}
404 
405 	// if save is older than the minimal version we support
406 	if (_savedVerMajor <  SAVEGAME_VER_MAJOR ||
407 	        (_savedVerMajor == SAVEGAME_VER_MAJOR && _savedVerMinor <  SAVEGAME_VER_MINOR) ||
408 	        (_savedVerMajor == SAVEGAME_VER_MAJOR && _savedVerMinor == SAVEGAME_VER_MINOR && _savedVerBuild < SAVEGAME_VER_BUILD)
409 	   ) {
410 		debugC(kWintermuteDebugSaveGame, "ERROR: Saved game is too old and cannot be used by this version of game engine");
411 		debugC(kWintermuteDebugSaveGame, "ERROR: Expected %d.%d.%d got %d.%d.%d", DCGF_VER_MAJOR, DCGF_VER_MINOR, DCGF_VER_BUILD, _savedVerMajor, _savedVerMinor, _savedVerBuild);
412 		cleanup();
413 		return STATUS_FAILED;
414 
415 	}
416 
417 	return STATUS_OK;
418 }
419 
420 
421 //////////////////////////////////////////////////////////////////////////
saveFile(const Common::String & filename)422 bool BasePersistenceManager::saveFile(const Common::String &filename) {
423 	byte *prefixBuffer = _richBuffer;
424 	uint32 prefixSize = _richBufferSize;
425 	byte *buffer = ((Common::MemoryWriteStreamDynamic *)_saveStream)->getData();
426 	uint32 bufferSize = ((Common::MemoryWriteStreamDynamic *)_saveStream)->size();
427 
428 	Common::SaveFileManager *saveMan = ((WintermuteEngine *)g_engine)->getSaveFileMan();
429 	Common::OutSaveFile *file = saveMan->openForSaving(filename);
430 	file->write(prefixBuffer, prefixSize);
431 	file->write(buffer, bufferSize);
432 	bool retVal = !file->err();
433 	file->finalize();
434 	delete file;
435 	return retVal;
436 }
437 
438 
439 //////////////////////////////////////////////////////////////////////////
putBytes(byte * buffer,uint32 size)440 bool BasePersistenceManager::putBytes(byte *buffer, uint32 size) {
441 	_saveStream->write(buffer, size);
442 	if (_saveStream->err()) {
443 		return STATUS_FAILED;
444 	}
445 	return STATUS_OK;
446 }
447 
448 //////////////////////////////////////////////////////////////////////////
getBytes(byte * buffer,uint32 size)449 bool BasePersistenceManager::getBytes(byte *buffer, uint32 size) {
450 	_loadStream->read(buffer, size);
451 	if (_loadStream->err()) {
452 		return STATUS_FAILED;
453 	}
454 	return STATUS_OK;
455 }
456 
457 //////////////////////////////////////////////////////////////////////////
putDWORD(uint32 val)458 void BasePersistenceManager::putDWORD(uint32 val) {
459 	_saveStream->writeUint32LE(val);
460 }
461 
462 
463 //////////////////////////////////////////////////////////////////////////
getDWORD()464 uint32 BasePersistenceManager::getDWORD() {
465 	uint32 ret = _loadStream->readUint32LE();
466 	return ret;
467 }
468 
469 
470 //////////////////////////////////////////////////////////////////////////
putString(const char * val)471 void BasePersistenceManager::putString(const char *val) {
472 	if (!val) {
473 		_saveStream->writeUint32LE(0);
474 		return;
475 	}
476 
477 	uint32 len = strlen(val);
478 
479 	_saveStream->writeUint32LE(len + 1);
480 	_saveStream->write(val, len);
481 }
482 
getStringObj()483 Common::String BasePersistenceManager::getStringObj() {
484 	return getString();
485 }
486 
487 //////////////////////////////////////////////////////////////////////////
getString()488 char *BasePersistenceManager::getString() {
489 	uint32 len = _loadStream->readUint32LE();
490 
491 	if (checkVersion(1,2,2)) {
492 		// Version 1.2.2 and above: len == strlen() + 1, NULL has len == 0
493 
494 		if (len == 0)
495 			return nullptr;
496 
497 		char *ret = new char[len];
498 		_loadStream->read(ret, len - 1);
499 		ret[len - 1] = '\0';
500 
501 		return ret;
502 
503 	} else {
504 
505 		// Version 1.2.1 and older: NULL strings are represented as "(null)"
506 		char *ret = new char[len + 1];
507 		_loadStream->read(ret, len);
508 		ret[len] = '\0';
509 
510 		if (!strcmp(ret, "(null)")) {
511 			delete[] ret;
512 			return nullptr;
513 		}
514 
515 		return ret;
516 	}
517 
518 }
519 
putTimeDate(const TimeDate & t)520 bool BasePersistenceManager::putTimeDate(const TimeDate &t) {
521 	_saveStream->writeSint32LE(t.tm_sec);
522 	_saveStream->writeSint32LE(t.tm_min);
523 	_saveStream->writeSint32LE(t.tm_hour);
524 	_saveStream->writeSint32LE(t.tm_mday);
525 	_saveStream->writeSint32LE(t.tm_mon);
526 	_saveStream->writeSint32LE(t.tm_year);
527 	_saveStream->writeSint32LE(t.tm_wday);
528 
529 	if (_saveStream->err()) {
530 		return STATUS_FAILED;
531 	}
532 	return STATUS_OK;
533 }
534 
getTimeDate()535 TimeDate BasePersistenceManager::getTimeDate() {
536 	TimeDate t;
537 	t.tm_sec = _loadStream->readSint32LE();
538 	t.tm_min = _loadStream->readSint32LE();
539 	t.tm_hour = _loadStream->readSint32LE();
540 	t.tm_mday = _loadStream->readSint32LE();
541 	t.tm_mon = _loadStream->readSint32LE();
542 	t.tm_year = _loadStream->readSint32LE();
543 	t.tm_wday = _loadStream->readSint32LE();
544 	return t;
545 }
546 
putFloat(float val)547 void BasePersistenceManager::putFloat(float val) {
548 	int exponent = 0;
549 	float significand = frexp(val, &exponent);
550 	Common::String str = Common::String::format("FS%f", significand);
551 	putString(str.c_str());
552 	_saveStream->writeSint32LE(exponent);
553 }
554 
getFloat()555 float BasePersistenceManager::getFloat() {
556 	char *str = getString();
557 	float value = 0.0f;
558 	float significand = 0.0f;
559 	int32 exponent = _loadStream->readSint32LE();
560 	int ret = sscanf(str, "FS%f", &significand);
561 	value = ldexp(significand, exponent);
562 	if (ret != 1) {
563 		warning("%s not parsed as float", str);
564 	}
565 	delete[] str;
566 	return value;
567 }
568 
putDouble(double val)569 void BasePersistenceManager::putDouble(double val) {
570 	int exponent = 0;
571 	double significand = frexp(val, &exponent);
572 	Common::String str = Common::String::format("DS%f", significand);
573 	putString(str.c_str());
574 	_saveStream->writeSint32LE(exponent);
575 }
576 
getDouble()577 double BasePersistenceManager::getDouble() {
578 	char *str = getString();
579 	double value = 0.0f;
580 	float significand = 0.0f;
581 	int32 exponent = _loadStream->readSint32LE();
582 	int ret = sscanf(str, "DS%f", &significand);
583 	value = ldexp(significand, exponent);
584 	if (ret != 1) {
585 		warning("%s not parsed as double", str);
586 	}
587 	delete[] str;
588 	return value;
589 }
590 
591 //////////////////////////////////////////////////////////////////////////
592 // bool
transferBool(const char * name,bool * val)593 bool BasePersistenceManager::transferBool(const char *name, bool *val) {
594 	if (_saving) {
595 		_saveStream->writeByte(*val);
596 		if (_saveStream->err()) {
597 			return STATUS_FAILED;
598 		}
599 		return STATUS_OK;
600 	} else {
601 		*val = _loadStream->readByte();
602 		if (_loadStream->err()) {
603 			return STATUS_FAILED;
604 		}
605 		return STATUS_OK;
606 	}
607 }
608 
609 
610 //////////////////////////////////////////////////////////////////////////
611 // int
transferSint32(const char * name,int32 * val)612 bool BasePersistenceManager::transferSint32(const char *name, int32 *val) {
613 	if (_saving) {
614 		_saveStream->writeSint32LE(*val);
615 		if (_saveStream->err()) {
616 			return STATUS_FAILED;
617 		}
618 		return STATUS_OK;
619 	} else {
620 		*val = _loadStream->readSint32LE();
621 		if (_loadStream->err()) {
622 			return STATUS_FAILED;
623 		}
624 		return STATUS_OK;
625 	}
626 }
627 
628 
629 //////////////////////////////////////////////////////////////////////////
630 // DWORD
transferUint32(const char * name,uint32 * val)631 bool BasePersistenceManager::transferUint32(const char *name, uint32 *val) {
632 	if (_saving) {
633 		_saveStream->writeUint32LE(*val);
634 		if (_saveStream->err()) {
635 			return STATUS_FAILED;
636 		}
637 		return STATUS_OK;
638 	} else {
639 		*val = _loadStream->readUint32LE();
640 		if (_loadStream->err()) {
641 			return STATUS_FAILED;
642 		}
643 		return STATUS_OK;
644 	}
645 }
646 
647 
648 //////////////////////////////////////////////////////////////////////////
649 // float
transferFloat(const char * name,float * val)650 bool BasePersistenceManager::transferFloat(const char *name, float *val) {
651 	if (_saving) {
652 		putFloat(*val);
653 		if (_saveStream->err()) {
654 			return STATUS_FAILED;
655 		}
656 		return STATUS_OK;
657 	} else {
658 		*val = getFloat();
659 		if (_loadStream->err()) {
660 			return STATUS_FAILED;
661 		}
662 		return STATUS_OK;
663 	}
664 }
665 
666 
667 //////////////////////////////////////////////////////////////////////////
668 // double
transferDouble(const char * name,double * val)669 bool BasePersistenceManager::transferDouble(const char *name, double *val) {
670 	if (_saving) {
671 		putDouble(*val);
672 		if (_saveStream->err()) {
673 			return STATUS_FAILED;
674 		}
675 		return STATUS_OK;
676 	} else {
677 		*val = getDouble();
678 		if (_loadStream->err()) {
679 			return STATUS_FAILED;
680 		}
681 		return STATUS_OK;
682 	}
683 }
684 
685 
686 //////////////////////////////////////////////////////////////////////////
687 // char*
transferCharPtr(const char * name,char ** val)688 bool BasePersistenceManager::transferCharPtr(const char *name, char **val) {
689 	if (_saving) {
690 		putString(*val);
691 		return STATUS_OK;
692 	} else {
693 		char *str = getString();
694 		if (_loadStream->err()) {
695 			delete[] str;
696 			return STATUS_FAILED;
697 		}
698 		*val = str;
699 		return STATUS_OK;
700 	}
701 }
702 
703 //////////////////////////////////////////////////////////////////////////
704 // const char*
transferConstChar(const char * name,const char ** val)705 bool BasePersistenceManager::transferConstChar(const char *name, const char **val) {
706 	if (_saving) {
707 		putString(*val);
708 		return STATUS_OK;
709 	} else {
710 		char *str = getString();
711 		if (_loadStream->err()) {
712 			delete[] str;
713 			return STATUS_FAILED;
714 		}
715 		*val = str;
716 		return STATUS_OK;
717 	}
718 }
719 
720 //////////////////////////////////////////////////////////////////////////
721 // Common::String
transferString(const char * name,Common::String * val)722 bool BasePersistenceManager::transferString(const char *name, Common::String *val) {
723 	if (_saving) {
724 		putString(val->c_str());
725 		return STATUS_OK;
726 	} else {
727 		char *str = getString();
728 		if (_loadStream->err()) {
729 			delete[] str;
730 			return STATUS_FAILED;
731 		}
732 		if (str) {
733 			*val = str;
734 			delete[] str;
735 		} else {
736 			*val = "";
737 		}
738 		return STATUS_OK;
739 	}
740 }
741 
742 //////////////////////////////////////////////////////////////////////////
743 // BYTE
transferByte(const char * name,byte * val)744 bool BasePersistenceManager::transferByte(const char *name, byte *val) {
745 	if (_saving) {
746 		_saveStream->writeByte(*val);
747 		if (_saveStream->err()) {
748 			return STATUS_FAILED;
749 		}
750 		return STATUS_OK;
751 	} else {
752 		*val = _loadStream->readByte();
753 		if (_loadStream->err()) {
754 			return STATUS_FAILED;
755 		}
756 		return STATUS_OK;
757 	}
758 }
759 
760 
761 //////////////////////////////////////////////////////////////////////////
762 // RECT
transferRect32(const char * name,Rect32 * val)763 bool BasePersistenceManager::transferRect32(const char *name, Rect32 *val) {
764 	if (_saving) {
765 		_saveStream->writeSint32LE(val->left);
766 		_saveStream->writeSint32LE(val->top);
767 		_saveStream->writeSint32LE(val->right);
768 		_saveStream->writeSint32LE(val->bottom);
769 		if (_saveStream->err()) {
770 			return STATUS_FAILED;
771 		}
772 		return STATUS_OK;
773 	} else {
774 		val->left = _loadStream->readSint32LE();
775 		val->top = _loadStream->readSint32LE();
776 		val->right = _loadStream->readSint32LE();
777 		val->bottom = _loadStream->readSint32LE();
778 		if (_loadStream->err()) {
779 			return STATUS_FAILED;
780 		}
781 		return STATUS_OK;
782 	}
783 }
784 
785 
786 //////////////////////////////////////////////////////////////////////////
787 // POINT
transferPoint32(const char * name,Point32 * val)788 bool BasePersistenceManager::transferPoint32(const char *name, Point32 *val) {
789 	if (_saving) {
790 		_saveStream->writeSint32LE(val->x);
791 		_saveStream->writeSint32LE(val->y);
792 		if (_saveStream->err()) {
793 			return STATUS_FAILED;
794 		}
795 		return STATUS_OK;
796 	} else {
797 		val->x = _loadStream->readSint32LE();
798 		val->y = _loadStream->readSint32LE();
799 		if (_loadStream->err()) {
800 			return STATUS_FAILED;
801 		}
802 		return STATUS_OK;
803 	}
804 }
805 
806 
807 //////////////////////////////////////////////////////////////////////////
808 // Vector2
transferVector2(const char * name,Vector2 * val)809 bool BasePersistenceManager::transferVector2(const char *name, Vector2 *val) {
810 	if (_saving) {
811 		putFloat(val->x);
812 		putFloat(val->y);
813 		if (_saveStream->err()) {
814 			return STATUS_FAILED;
815 		}
816 		return STATUS_OK;
817 	} else {
818 		val->x = getFloat();
819 		val->y = getFloat();
820 		if (_loadStream->err()) {
821 			return STATUS_FAILED;
822 		}
823 		return STATUS_OK;
824 	}
825 }
826 
827 #ifdef ENABLE_WME3D
828 //////////////////////////////////////////////////////////////////////////
829 // Vector3
transferVector3d(const char * name,Math::Vector3d * val)830 bool BasePersistenceManager::transferVector3d(const char *name, Math::Vector3d *val) {
831 	if (_saving) {
832 		putFloat(val->x());
833 		putFloat(val->y());
834 		putFloat(val->z());
835 
836 		if (_saveStream->err()) {
837 			return STATUS_FAILED;
838 		}
839 
840 		return STATUS_OK;
841 	} else {
842 		val->x() = getFloat();
843 		val->y() = getFloat();
844 		val->z() = getFloat();
845 
846 		if (_loadStream->err()) {
847 			return STATUS_FAILED;
848 		}
849 
850 		return STATUS_OK;
851 	}
852 }
853 
854 //////////////////////////////////////////////////////////////////////////
855 // Matrix4
transferMatrix4(const char * name,Math::Matrix4 * val)856 bool BasePersistenceManager::transferMatrix4(const char *name, Math::Matrix4 *val) {
857 	if (_saving) {
858 		for (int r = 0; r < 4; ++r) {
859 			for (int c = 0; c < 4; ++c) {
860 				putFloat((*val)(r, c));
861 			}
862 		}
863 
864 		if (_saveStream->err()) {
865 			return STATUS_FAILED;
866 		}
867 
868 		return STATUS_OK;
869 	} else {
870 		for (int r = 0; r < 4; ++r) {
871 			for (int c = 0; c < 4; ++c) {
872 				(*val)(r, c) = getFloat();
873 			}
874 		}
875 
876 		if (_loadStream->err()) {
877 			return STATUS_FAILED;
878 		}
879 
880 		return STATUS_OK;
881 	}
882 }
883 
transferAngle(const char * name,Math::Angle * val)884 bool BasePersistenceManager::transferAngle(const char *name, Math::Angle *val) {
885 	if (_saving) {
886 		putFloat(val->getDegrees());
887 
888 		if (_saveStream->err()) {
889 			return STATUS_FAILED;
890 		}
891 	} else {
892 		*val = getFloat();
893 
894 		if (_loadStream->err()) {
895 			return STATUS_FAILED;
896 		}
897 	}
898 
899 	return STATUS_OK;
900 }
901 #endif
902 
903 
904 //////////////////////////////////////////////////////////////////////////
905 // generic pointer
906 
transferPtr(const char * name,void * val)907 bool BasePersistenceManager::transferPtr(const char *name, void *val) {
908 	int classID = -1, instanceID = -1;
909 
910 	if (_saving) {
911 		SystemClassRegistry::getInstance()->getPointerID(*(void **)val, &classID, &instanceID);
912 		if (*(void **)val != nullptr && (classID == -1 || instanceID == -1)) {
913 			debugC(kWintermuteDebugSaveGame, "Warning: invalid instance '%s'", name);
914 		}
915 
916 		_saveStream->writeUint32LE(classID);
917 		_saveStream->writeUint32LE(instanceID);
918 	} else {
919 		classID = _loadStream->readUint32LE();
920 		instanceID = _loadStream->readUint32LE();
921 
922 		*(void **)val = SystemClassRegistry::getInstance()->idToPointer(classID, instanceID);
923 	}
924 
925 	return STATUS_OK;
926 }
927 
928 //////////////////////////////////////////////////////////////////////////
checkVersion(byte verMajor,byte verMinor,byte verBuild)929 bool BasePersistenceManager::checkVersion(byte verMajor, byte verMinor, byte verBuild) {
930 	if (_saving) {
931 		return true;
932 	}
933 
934 	// it's ok if we are same or newer than the saved game
935 	if (verMajor >  _savedVerMajor ||
936 	        (verMajor == _savedVerMajor && verMinor >  _savedVerMinor) ||
937 	        (verMajor == _savedVerMajor && verMinor == _savedVerMinor && verBuild > _savedVerBuild)
938 	   ) {
939 		return false;
940 	}
941 
942 	return true;
943 }
944 
945 } // End of namespace Wintermute
946