diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -1043,51 +1043,34 @@ static void SlStdString(void *ptr, VarTy } /** - * Return the size in bytes of a certain type of atomic array - * @param length The length of the array counted in elements - * @param conv VarType type of the variable that is used in calculating the size + * Internal function to save/Load a list of SL_VARs. + * SlCopy() and SlArray() are very similar, with the exception of the header. + * This function represents the common part. + * @param object The object being manipulated. + * @param length The length of the object in elements + * @param conv VarType type of the items. */ -static inline size_t SlCalcArrayLen(size_t length, VarType conv) +static void SlCopyInternal(void *object, size_t length, VarType conv) { - return SlCalcConvFileLen(conv) * length; -} - -/** - * Save/Load an array. - * @param array The array being manipulated - * @param length The length of the array in elements - * @param conv VarType type of the atomic array (int, byte, uint64, etc.) - */ -void SlArray(void *array, size_t length, VarType conv) -{ - if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return; - - /* Automatically calculate the length? */ - if (_sl.need_length != NL_NONE) { - SlSetLength(SlCalcArrayLen(length, conv)); - /* Determine length only? */ - if (_sl.need_length == NL_CALCLENGTH) return; - } - if (GetVarMemType(conv) == SLE_VAR_NULL) { assert(_sl.action != SLA_SAVE); // Use SL_NULL if you want to write null-bytes - SlSkipBytes(SlCalcArrayLen(length, conv)); + SlSkipBytes(length * SlCalcConvFileLen(conv)); return; } /* NOTICE - handle some buggy stuff, in really old versions everything was saved - * as a byte-type. So detect this, and adjust array size accordingly */ + * as a byte-type. So detect this, and adjust object size accordingly */ if (_sl.action != SLA_SAVE && _sl_version == 0) { - /* all arrays except difficulty settings */ + /* all objects except difficulty settings */ if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID || conv == SLE_INT32 || conv == SLE_UINT32) { - SlCopyBytes(array, length * SlCalcConvFileLen(conv)); + SlCopyBytes(object, length * SlCalcConvFileLen(conv)); return; } /* used for conversion of Money 32bit->64bit */ if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) { for (uint i = 0; i < length; i++) { - ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32()); + ((int64*)object)[i] = (int32)BSWAP32(SlReadUint32()); } return; } @@ -1096,9 +1079,9 @@ void SlArray(void *array, size_t length, /* If the size of elements is 1 byte both in file and memory, no special * conversion is needed, use specialized copy-copy function to speed up things */ if (conv == SLE_INT8 || conv == SLE_UINT8) { - SlCopyBytes(array, length); + SlCopyBytes(object, length); } else { - byte *a = (byte*)array; + byte *a = (byte*)object; byte mem_size = SlCalcConvMemLen(conv); for (; length != 0; length --) { @@ -1108,6 +1091,71 @@ void SlArray(void *array, size_t length, } } +/** + * Copy a list of SL_VARs to/from a savegame. + * These entries are copied as-is, and you as caller have to make sure things + * like length-fields are calculated correctly. + * @param object The object being manipulated. + * @param length The length of the object in elements + * @param conv VarType type of the items. + */ +void SlCopy(void *object, size_t length, VarType conv) +{ + if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return; + + /* Automatically calculate the length? */ + if (_sl.need_length != NL_NONE) { + SlSetLength(length * SlCalcConvFileLen(conv)); + /* Determine length only? */ + if (_sl.need_length == NL_CALCLENGTH) return; + } + + SlCopyInternal(object, length, conv); +} + +/** + * Return the size in bytes of a certain type of atomic array + * @param length The length of the array counted in elements + * @param conv VarType type of the variable that is used in calculating the size + */ +static inline size_t SlCalcArrayLen(size_t length, VarType conv) +{ + return SlCalcConvFileLen(conv) * length + SlGetArrayLength(length); +} + +/** + * Save/Load the length of the array followed by the array of SL_VAR elements. + * @param array The array being manipulated + * @param length The length of the array in elements + * @param conv VarType type of the atomic array (int, byte, uint64, etc.) + */ +static void SlArray(void *array, size_t length, VarType conv) +{ + switch (_sl.action) { + case SLA_SAVE: + SlWriteArrayLength(length); + SlCopyInternal(array, length, conv); + return; + + case SLA_LOAD_CHECK: + case SLA_LOAD: { + if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH)) { + size_t sv_length = SlReadArrayLength(); + if (sv_length != length) SlErrorCorrupt("Fixed-length array is of wrong length"); + } + + SlCopyInternal(array, length, conv); + return; + } + + case SLA_PTRS: + case SLA_NULL: + return; + + default: + NOT_REACHED(); + } +} /** * Pointers cannot be saved to a savegame, so this functions gets