|
@@ -1292,13 +1292,13 @@ static void WriteLZO(size_t size)
|
|
|
lzo1x_1_compress(_sl.buf, (lzo_uint)size, out + sizeof(uint32) * 2, &outlen, wrkmem);
|
|
|
((uint32*)out)[1] = TO_BE32((uint32)outlen);
|
|
|
((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32)));
|
|
|
if (fwrite(out, outlen + sizeof(uint32) * 2, 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
|
|
|
}
|
|
|
|
|
|
static bool InitLZO()
|
|
|
static bool InitLZO(byte compression)
|
|
|
{
|
|
|
_sl.bufsize = LZO_SIZE;
|
|
|
_sl.buf = _sl.buf_ori = MallocT<byte>(LZO_SIZE);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -1319,13 +1319,13 @@ static size_t ReadNoComp()
|
|
|
|
|
|
static void WriteNoComp(size_t size)
|
|
|
{
|
|
|
if (fwrite(_sl.buf, 1, size, _sl.fh) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
|
|
|
}
|
|
|
|
|
|
static bool InitNoComp()
|
|
|
static bool InitNoComp(byte compression)
|
|
|
{
|
|
|
_sl.bufsize = LZO_SIZE;
|
|
|
_sl.buf = _sl.buf_ori = MallocT<byte>(LZO_SIZE);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -1383,13 +1383,13 @@ static bool InitMem()
|
|
|
|
|
|
#if defined(WITH_ZLIB)
|
|
|
#include <zlib.h>
|
|
|
|
|
|
static z_stream _z;
|
|
|
|
|
|
static bool InitReadZlib()
|
|
|
static bool InitReadZlib(byte compression)
|
|
|
{
|
|
|
memset(&_z, 0, sizeof(_z));
|
|
|
if (inflateInit(&_z) != Z_OK) return false;
|
|
|
|
|
|
_sl.bufsize = 4096;
|
|
|
_sl.buf = _sl.buf_ori = MallocT<byte>(4096 + 4096); // also contains fread buffer
|
|
@@ -1423,16 +1423,16 @@ static size_t ReadZlib()
|
|
|
static void UninitReadZlib()
|
|
|
{
|
|
|
inflateEnd(&_z);
|
|
|
free(_sl.buf_ori);
|
|
|
}
|
|
|
|
|
|
static bool InitWriteZlib()
|
|
|
static bool InitWriteZlib(byte compression)
|
|
|
{
|
|
|
memset(&_z, 0, sizeof(_z));
|
|
|
if (deflateInit(&_z, 6) != Z_OK) return false;
|
|
|
if (deflateInit(&_z, compression) != Z_OK) return false;
|
|
|
|
|
|
_sl.bufsize = 4096;
|
|
|
_sl.buf = _sl.buf_ori = MallocT<byte>(4096);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -1583,60 +1583,90 @@ static void *IntToReference(size_t index
|
|
|
default: NOT_REACHED();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/** The format for a reader/writer type of a savegame */
|
|
|
struct SaveLoadFormat {
|
|
|
const char *name; ///< name of the compressor/decompressor (debug-only)
|
|
|
uint32 tag; ///< the 4-letter tag by which it is identified in the savegame
|
|
|
const char *name; ///< name of the compressor/decompressor (debug-only)
|
|
|
uint32 tag; ///< the 4-letter tag by which it is identified in the savegame
|
|
|
|
|
|
bool (*init_read)(byte compression); ///< function executed upon initalization of the loader
|
|
|
ReaderProc *reader; ///< function that loads the data from the file
|
|
|
void (*uninit_read)(); ///< function executed when reading is finished
|
|
|
|
|
|
bool (*init_read)(); ///< function executed upon initalization of the loader
|
|
|
ReaderProc *reader; ///< function that loads the data from the file
|
|
|
void (*uninit_read)(); ///< function executed when reading is finished
|
|
|
bool (*init_write)(byte compression); ///< function executed upon intialization of the saver
|
|
|
WriterProc *writer; ///< function that saves the data to the file
|
|
|
void (*uninit_write)(); ///< function executed when writing is done
|
|
|
|
|
|
bool (*init_write)(); ///< function executed upon intialization of the saver
|
|
|
WriterProc *writer; ///< function that saves the data to the file
|
|
|
void (*uninit_write)(); ///< function executed when writing is done
|
|
|
byte min_compression; ///< the minimum compression level of this format
|
|
|
byte default_compression; ///< the default compression level of this format
|
|
|
byte max_compression; ///< the maximum compression level of this format
|
|
|
};
|
|
|
|
|
|
static const SaveLoadFormat _saveload_formats[] = {
|
|
|
#if defined(WITH_LZO)
|
|
|
{"lzo", TO_BE32X('OTTD'), InitLZO, ReadLZO, UninitLZO, InitLZO, WriteLZO, UninitLZO},
|
|
|
{"lzo", TO_BE32X('OTTD'), InitLZO, ReadLZO, UninitLZO, InitLZO, WriteLZO, UninitLZO, 0, 0, 0},
|
|
|
#else
|
|
|
{"lzo", TO_BE32X('OTTD'), NULL, NULL, NULL, NULL, NULL, NULL},
|
|
|
{"lzo", TO_BE32X('OTTD'), NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0},
|
|
|
#endif
|
|
|
{"none", TO_BE32X('OTTN'), InitNoComp, ReadNoComp, UninitNoComp, InitNoComp, WriteNoComp, UninitNoComp},
|
|
|
{"none", TO_BE32X('OTTN'), InitNoComp, ReadNoComp, UninitNoComp, InitNoComp, WriteNoComp, UninitNoComp, 0, 0, 0},
|
|
|
#if defined(WITH_ZLIB)
|
|
|
{"zlib", TO_BE32X('OTTZ'), InitReadZlib, ReadZlib, UninitReadZlib, InitWriteZlib, WriteZlib, UninitWriteZlib},
|
|
|
{"zlib", TO_BE32X('OTTZ'), InitReadZlib, ReadZlib, UninitReadZlib, InitWriteZlib, WriteZlib, UninitWriteZlib, 0, 6, 9},
|
|
|
#else
|
|
|
{"zlib", TO_BE32X('OTTZ'), NULL, NULL, NULL, NULL, NULL, NULL},
|
|
|
{"zlib", TO_BE32X('OTTZ'), NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0},
|
|
|
#endif
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Return the savegameformat of the game. Whether it was created with ZLIB compression
|
|
|
* uncompressed, or another type
|
|
|
* @param s Name of the savegame format. If NULL it picks the first available one
|
|
|
* @param compression_level Output for telling what compression level we want.
|
|
|
* @return Pointer to SaveLoadFormat struct giving all characteristics of this type of savegame
|
|
|
*/
|
|
|
static const SaveLoadFormat *GetSavegameFormat(const char *s)
|
|
|
static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level)
|
|
|
{
|
|
|
const SaveLoadFormat *def = lastof(_saveload_formats);
|
|
|
|
|
|
/* find default savegame format, the highest one with which files can be written */
|
|
|
while (!def->init_write) def--;
|
|
|
|
|
|
if (!StrEmpty(s)) {
|
|
|
/* Get the ":..." of the compression level out of the way */
|
|
|
char *complevel = strrchr(s, ':');
|
|
|
if (complevel != NULL) *complevel = '\0';
|
|
|
|
|
|
for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
|
|
|
if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
|
|
|
*compression_level = slf->default_compression;
|
|
|
if (complevel != NULL) {
|
|
|
/* There is a compression level in the string.
|
|
|
* First restore the : we removed to do proper name matching,
|
|
|
* then move the the begin of the actual version. */
|
|
|
*complevel = ':';
|
|
|
complevel++;
|
|
|
|
|
|
/* Get the version and determine whether all went fine. */
|
|
|
char *end;
|
|
|
long level = strtol(complevel, &end, 10);
|
|
|
if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) {
|
|
|
ShowInfoF("Compression level '%s' is not valid.", complevel);
|
|
|
} else {
|
|
|
*compression_level = level;
|
|
|
}
|
|
|
}
|
|
|
return slf;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
ShowInfoF("Savegame format '%s' is not available. Reverting to '%s'.", s, def->name);
|
|
|
|
|
|
/* Restore the string by adding the : back */
|
|
|
if (complevel != NULL) *complevel = ':';
|
|
|
}
|
|
|
*compression_level = def->default_compression;
|
|
|
return def;
|
|
|
}
|
|
|
|
|
|
/* actual loader/saver function */
|
|
|
void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings);
|
|
|
extern bool AfterLoadGame();
|
|
@@ -1704,19 +1734,20 @@ static void SaveFileError()
|
|
|
* and appropiate compressor and start writing to file.
|
|
|
*/
|
|
|
static SaveOrLoadResult SaveFileToDisk(bool threaded)
|
|
|
{
|
|
|
_sl.excpt_uninit = NULL;
|
|
|
try {
|
|
|
const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format);
|
|
|
byte compression;
|
|
|
const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
|
|
|
|
|
|
/* We have written our stuff to memory, now write it to file! */
|
|
|
uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
|
|
|
if (fwrite(hdr, sizeof(hdr), 1, _sl.fh) != 1) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
|
|
|
|
|
|
if (!fmt->init_write()) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
|
|
|
if (!fmt->init_write(compression)) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
|
|
|
|
|
|
{
|
|
|
uint i;
|
|
|
|
|
|
if (_ts.count != _sl.offs_base) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unexpected size of chunk");
|
|
|
for (i = 0; i != _memory_savegame.Length() - 1; i++) {
|
|
@@ -1898,13 +1929,13 @@ SaveOrLoadResult SaveOrLoad(const char *
|
|
|
if (fmt->init_read == NULL) {
|
|
|
char err_str[64];
|
|
|
snprintf(err_str, lengthof(err_str), "Loader for '%s' is not available.", fmt->name);
|
|
|
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
|
|
|
}
|
|
|
|
|
|
if (!fmt->init_read()) {
|
|
|
if (!fmt->init_read(0)) {
|
|
|
char err_str[64];
|
|
|
snprintf(err_str, lengthof(err_str), "Initializing loader '%s' failed", fmt->name);
|
|
|
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
|
|
|
}
|
|
|
|
|
|
_engine_mngr.ResetToDefaultMapping();
|