diff options
-rw-r--r-- | src/saveload/saveload.cpp | 335 |
1 files changed, 183 insertions, 152 deletions
diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 8780234da..c953f5a4a 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -52,9 +52,15 @@ char _savegame_format[8]; ///< how to compress savegames typedef void WriterProc(size_t len); typedef size_t ReaderProc(); +/** What are we currently doing? */ +enum SaveLoadAction { + SLA_LOAD, ///< loading + SLA_SAVE, ///< saving +}; + /** The saveload struct, containing reader-writer functions, bufffer, version, etc. */ -static struct { - bool save; ///< are we doing a save or a load atm. True when saving +struct SaveLoadParams { + SaveLoadAction action; ///< are we doing a save or a load atm. byte need_length; ///< ??? byte block_mode; ///< ??? bool error; ///< did an error occur or not @@ -82,7 +88,9 @@ static struct { void (*excpt_uninit)(); ///< the function to execute on any encountered error StringID error_str; ///< the translateable error message to show char *extra_msg; ///< the error message -} _sl; +}; + +static SaveLoadParams _sl; enum NeedLengthValues {NL_NONE = 0, NL_WANTLENGTH = 1, NL_CALCLENGTH = 2}; @@ -388,7 +396,7 @@ int SlIterateArray() */ void SlSetLength(size_t length) { - assert(_sl.save); + assert(_sl.action == SLA_SAVE); switch (_sl.need_length) { case NL_WANTLENGTH: @@ -427,12 +435,16 @@ void SlSetLength(size_t length) */ static void SlCopyBytes(void *ptr, size_t length) { - byte *p = (byte*)ptr; + byte *p = (byte *)ptr; - if (_sl.save) { - for (; length != 0; length--) {SlWriteByteInternal(*p++);} - } else { - for (; length != 0; length--) {*p++ = SlReadByteInternal();} + switch (_sl.action) { + case SLA_LOAD: + for (; length != 0; length--) { *p++ = SlReadByteInternal(); } + break; + case SLA_SAVE: + for (; length != 0; length--) { SlWriteByteInternal(*p++); } + break; + default: NOT_REACHED(); } } @@ -506,43 +518,46 @@ void WriteValue(void *ptr, VarType conv, int64 val) */ static void SlSaveLoadConv(void *ptr, VarType conv) { - int64 x = 0; - - if (_sl.save) { // SAVE values - /* Read a value from the struct. These ARE endian safe. */ - x = ReadValue(ptr, conv); - - /* Write the value to the file and check if its value is in the desired range */ - switch (GetVarFileType(conv)) { - case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break; - case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break; - case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break; - case SLE_FILE_STRINGID: - case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break; - case SLE_FILE_I32: - case SLE_FILE_U32: SlWriteUint32((uint32)x);break; - case SLE_FILE_I64: - case SLE_FILE_U64: SlWriteUint64(x);break; - default: NOT_REACHED(); - } - } else { // LOAD values - - /* Read a value from the file */ - switch (GetVarFileType(conv)) { - case SLE_FILE_I8: x = (int8 )SlReadByte(); break; - case SLE_FILE_U8: x = (byte )SlReadByte(); break; - case SLE_FILE_I16: x = (int16 )SlReadUint16(); break; - case SLE_FILE_U16: x = (uint16)SlReadUint16(); break; - case SLE_FILE_I32: x = (int32 )SlReadUint32(); break; - case SLE_FILE_U32: x = (uint32)SlReadUint32(); break; - case SLE_FILE_I64: x = (int64 )SlReadUint64(); break; - case SLE_FILE_U64: x = (uint64)SlReadUint64(); break; - case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break; - default: NOT_REACHED(); + switch (_sl.action) { + case SLA_SAVE: { + int64 x = ReadValue(ptr, conv); + + /* Write the value to the file and check if its value is in the desired range */ + switch (GetVarFileType(conv)) { + case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break; + case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break; + case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break; + case SLE_FILE_STRINGID: + case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break; + case SLE_FILE_I32: + case SLE_FILE_U32: SlWriteUint32((uint32)x);break; + case SLE_FILE_I64: + case SLE_FILE_U64: SlWriteUint64(x);break; + default: NOT_REACHED(); + } + break; } + case SLA_LOAD: { + int64 x; + /* Read a value from the file */ + switch (GetVarFileType(conv)) { + case SLE_FILE_I8: x = (int8 )SlReadByte(); break; + case SLE_FILE_U8: x = (byte )SlReadByte(); break; + case SLE_FILE_I16: x = (int16 )SlReadUint16(); break; + case SLE_FILE_U16: x = (uint16)SlReadUint16(); break; + case SLE_FILE_I32: x = (int32 )SlReadUint32(); break; + case SLE_FILE_U32: x = (uint32)SlReadUint32(); break; + case SLE_FILE_I64: x = (int64 )SlReadUint64(); break; + case SLE_FILE_U64: x = (uint64)SlReadUint64(); break; + case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break; + default: NOT_REACHED(); + } - /* Write The value to the struct. These ARE endian safe. */ - WriteValue(ptr, conv, x); + /* Write The value to the struct. These ARE endian safe. */ + WriteValue(ptr, conv, x); + break; + } + default: NOT_REACHED(); } } @@ -596,55 +611,60 @@ static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType con * @param conv must be SLE_FILE_STRING */ static void SlString(void *ptr, size_t length, VarType conv) { - size_t len; + switch (_sl.action) { + case SLA_SAVE: { + size_t len; + switch (GetVarMemType(conv)) { + default: NOT_REACHED(); + case SLE_VAR_STRB: + case SLE_VAR_STRBQ: + len = SlCalcNetStringLen((char *)ptr, length); + break; + case SLE_VAR_STR: + case SLE_VAR_STRQ: + ptr = *(char **)ptr; + len = SlCalcNetStringLen((char *)ptr, SIZE_MAX); + break; + } - if (_sl.save) { // SAVE string - switch (GetVarMemType(conv)) { - default: NOT_REACHED(); - case SLE_VAR_STRB: - case SLE_VAR_STRBQ: - len = SlCalcNetStringLen((char*)ptr, length); - break; - case SLE_VAR_STR: - case SLE_VAR_STRQ: - ptr = *(char**)ptr; - len = SlCalcNetStringLen((char*)ptr, SIZE_MAX); - break; + SlWriteArrayLength(len); + SlCopyBytes(ptr, len); + break; } + case SLA_LOAD: { + size_t len = SlReadArrayLength(); + + switch (GetVarMemType(conv)) { + default: NOT_REACHED(); + case SLE_VAR_STRB: + case SLE_VAR_STRBQ: + if (len >= length) { + DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating"); + SlCopyBytes(ptr, length); + SlSkipBytes(len - length); + len = length - 1; + } else { + SlCopyBytes(ptr, len); + } + break; + case SLE_VAR_STR: + case SLE_VAR_STRQ: // Malloc'd string, free previous incarnation, and allocate + free(*(char **)ptr); + if (len == 0) { + *(char **)ptr = NULL; + } else { + *(char **)ptr = MallocT<char>(len + 1); // terminating '\0' + ptr = *(char **)ptr; + SlCopyBytes(ptr, len); + } + break; + } - SlWriteArrayLength(len); - SlCopyBytes(ptr, len); - } else { // LOAD string - len = SlReadArrayLength(); - - switch (GetVarMemType(conv)) { - default: NOT_REACHED(); - case SLE_VAR_STRB: - case SLE_VAR_STRBQ: - if (len >= length) { - DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating"); - SlCopyBytes(ptr, length); - SlSkipBytes(len - length); - len = length - 1; - } else { - SlCopyBytes(ptr, len); - } - break; - case SLE_VAR_STR: - case SLE_VAR_STRQ: // Malloc'd string, free previous incarnation, and allocate - free(*(char**)ptr); - if (len == 0) { - *(char**)ptr = NULL; - } else { - *(char**)ptr = MallocT<char>(len + 1); // terminating '\0' - ptr = *(char**)ptr; - SlCopyBytes(ptr, len); - } - break; + ((char *)ptr)[len] = '\0'; // properly terminate the string + str_validate((char *)ptr, (char *)ptr + len); + break; } - - ((char*)ptr)[len] = '\0'; // properly terminate the string - str_validate((char*)ptr, (char*)ptr + len); + default: NOT_REACHED(); } } @@ -675,7 +695,7 @@ void SlArray(void *array, size_t length, VarType conv) /* NOTICE - handle some buggy stuff, in really old versions everything was saved * as a byte-type. So detect this, and adjust array size accordingly */ - if (!_sl.save && _sl_version == 0) { + if (_sl.action != SLA_SAVE && _sl_version == 0) { /* all arrays except difficulty settings */ if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID || conv == SLE_INT32 || conv == SLE_UINT32) { @@ -742,22 +762,28 @@ void SlList(void *list, SLRefType conv) std::list<void *> *l = (std::list<void *> *) list; - if (_sl.save) { - SlWriteUint32((uint32)l->size()); + switch (_sl.action) { + case SLA_SAVE: { + SlWriteUint32((uint32)l->size()); - std::list<void *>::iterator iter; - for (iter = l->begin(); iter != l->end(); ++iter) { - void *ptr = *iter; - SlWriteUint32(ReferenceToInt(ptr, conv)); + std::list<void *>::iterator iter; + for (iter = l->begin(); iter != l->end(); ++iter) { + void *ptr = *iter; + SlWriteUint32(ReferenceToInt(ptr, conv)); + } + break; } - } else { - uint length = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(); + case SLA_LOAD: { + uint length = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(); - /* Load each reference and push to the end of the list */ - for (uint i = 0; i < length; i++) { - void *ptr = IntToReference(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(), conv); - l->push_back(ptr); + /* Load each reference and push to the end of the list */ + for (uint i = 0; i < length; i++) { + void *ptr = IntToReference(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(), conv); + l->push_back(ptr); + } + break; } + default: NOT_REACHED(); } } @@ -776,7 +802,7 @@ static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld) * bytestream itself as well, so there is no need to skip it somewhere else */ static inline bool SlSkipVariableOnLoad(const SaveLoad *sld) { - if ((sld->conv & SLF_NETWORK_NO) && !_sl.save && _networking && !_network_server) { + if ((sld->conv & SLF_NETWORK_NO) && _sl.action != SLA_SAVE && _networking && !_network_server) { SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length); return true; } @@ -803,7 +829,7 @@ size_t SlCalcObjLength(const void *object, const SaveLoad *sld) size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld) { - assert(_sl.save); + assert(_sl.action == SLA_SAVE); switch (sld->cmd) { case SL_VAR: @@ -815,12 +841,12 @@ size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld) if (!SlIsObjectValidInSavegame(sld)) break; switch (sld->cmd) { - case SL_VAR: return SlCalcConvFileLen(sld->conv); - case SL_REF: return SlCalcRefLen(); - case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv); - case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv); - case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld)); - default: NOT_REACHED(); + case SL_VAR: return SlCalcConvFileLen(sld->conv); + case SL_REF: return SlCalcRefLen(); + case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv); + case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv); + case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld)); + default: NOT_REACHED(); } break; case SL_WRITEBYTE: return 1; // a byte is logically of size 1 @@ -835,49 +861,54 @@ bool SlObjectMember(void *ptr, const SaveLoad *sld) { VarType conv = GB(sld->conv, 0, 8); switch (sld->cmd) { - case SL_VAR: - case SL_REF: - case SL_ARR: - case SL_STR: - case SL_LST: - /* CONDITIONAL saveload types depend on the savegame version */ - if (!SlIsObjectValidInSavegame(sld)) return false; - if (SlSkipVariableOnLoad(sld)) return false; - - switch (sld->cmd) { - case SL_VAR: SlSaveLoadConv(ptr, conv); break; - case SL_REF: // Reference variable, translate - if (_sl.save) { - SlWriteUint32(ReferenceToInt(*(void**)ptr, (SLRefType)conv)); - } else { - *(void**)ptr = IntToReference(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(), (SLRefType)conv); + case SL_VAR: + case SL_REF: + case SL_ARR: + case SL_STR: + case SL_LST: + /* CONDITIONAL saveload types depend on the savegame version */ + if (!SlIsObjectValidInSavegame(sld)) return false; + if (SlSkipVariableOnLoad(sld)) return false; + + switch (sld->cmd) { + case SL_VAR: SlSaveLoadConv(ptr, conv); break; + case SL_REF: // Reference variable, translate + switch (_sl.action) { + case SLA_SAVE: + SlWriteUint32(ReferenceToInt(*(void **)ptr, (SLRefType)conv)); + break; + case SLA_LOAD: + *(void **)ptr = IntToReference(CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32(), (SLRefType)conv); + break; + default: NOT_REACHED(); + } + break; + case SL_ARR: SlArray(ptr, sld->length, conv); break; + case SL_STR: SlString(ptr, sld->length, conv); break; + case SL_LST: SlList(ptr, (SLRefType)conv); break; + default: NOT_REACHED(); } break; - case SL_ARR: SlArray(ptr, sld->length, conv); break; - case SL_STR: SlString(ptr, sld->length, conv); break; - case SL_LST: SlList(ptr, (SLRefType)conv); break; - default: NOT_REACHED(); - } - break; - /* SL_WRITEBYTE translates a value of a variable to another one upon - * saving or loading. - * XXX - variable renaming abuse - * game_value: the value of the variable ingame is abused by sld->version_from - * file_value: the value of the variable in the savegame is abused by sld->version_to */ - case SL_WRITEBYTE: - if (_sl.save) { - SlWriteByte(sld->version_to); - } else { - *(byte*)ptr = sld->version_from; - } - break; + /* SL_WRITEBYTE translates a value of a variable to another one upon + * saving or loading. + * XXX - variable renaming abuse + * game_value: the value of the variable ingame is abused by sld->version_from + * file_value: the value of the variable in the savegame is abused by sld->version_to */ + case SL_WRITEBYTE: + switch (_sl.action) { + case SLA_SAVE: SlWriteByte(sld->version_to); break; + case SLA_LOAD: *(byte *)ptr = sld->version_from; break; + default: NOT_REACHED(); + } + break; - /* SL_VEH_INCLUDE loads common code for vehicles */ - case SL_VEH_INCLUDE: - SlObject(ptr, GetVehicleDescription(VEH_END)); - break; - default: NOT_REACHED(); + /* SL_VEH_INCLUDE loads common code for vehicles */ + case SL_VEH_INCLUDE: + SlObject(ptr, GetVehicleDescription(VEH_END)); + break; + + default: NOT_REACHED(); } return true; } @@ -919,7 +950,7 @@ void SlAutolength(AutolengthProc *proc, void *arg) { size_t offs; - assert(_sl.save); + assert(_sl.action == SL_SAVE); /* Tell it to calculate the length */ _sl.need_length = NL_CALCLENGTH; @@ -1579,7 +1610,7 @@ const char *GetSaveLoadErrorString() SetDParamStr(1, _sl.extra_msg); static char err_str[512]; - GetString(err_str, _sl.save ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str)); + GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str)); return err_str; } @@ -1718,7 +1749,7 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb) _sl.bufe = _sl.bufp = NULL; _sl.offs_base = 0; - _sl.save = (mode != 0); + _sl.action = (mode != 0) ? SLA_SAVE : SLA_LOAD; _sl.chs = _chunk_handlers; /* General tactic is to first save the game to memory, then use an available writer |