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