summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/saveload/saveload.cpp165
1 files changed, 78 insertions, 87 deletions
diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp
index 2fedb1b9b..22844f4dc 100644
--- a/src/saveload/saveload.cpp
+++ b/src/saveload/saveload.cpp
@@ -227,7 +227,6 @@ byte _sl_minor_version; ///< the minor savegame version, DO NOT USE!
char _savegame_format[8]; ///< how to compress savegames
bool _do_autosave; ///< are we doing an autosave at the moment?
-typedef void DumperProc(size_t len);
typedef void WriterProc(byte *buf, size_t len);
typedef size_t ReaderProc();
@@ -246,6 +245,63 @@ enum NeedLength {
NL_CALCLENGTH = 2, ///< need to calculate the length
};
+/** Save in chunks of 128 KiB. */
+static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
+
+/** Container for dumping the savegame (quickly) to memory. */
+struct MemoryDumper {
+ AutoFreeSmallVector<byte *, 16> blocks; ///< Buffer with blocks of allocated memory.
+ byte *buf; ///< Buffer we're going to write to.
+ byte *bufe; ///< End of the buffer we write to.
+
+ /** Initialise our variables. */
+ MemoryDumper() : buf(NULL), bufe(NULL)
+ {
+ }
+
+ /**
+ * Write a single byte into the dumper.
+ * @param b The byte to write.
+ */
+ FORCEINLINE void WriteByte(byte b)
+ {
+ /* Are we at the end of this chunk? */
+ if (this->buf == this->bufe) {
+ this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
+ *this->blocks.Append() = this->buf;
+ this->bufe = this->buf + MEMORY_CHUNK_SIZE;
+ }
+
+ *this->buf++ = b;
+ }
+
+ /**
+ * Flush this dumper into a writer.
+ * @param writer The writer we want to use.
+ */
+ void Flush(WriterProc writer)
+ {
+ uint i = 0;
+ size_t t = this->GetSize();
+
+ while (t > 0) {
+ size_t to_write = min(MEMORY_CHUNK_SIZE, t);
+
+ writer(this->blocks[i++], to_write);
+ t -= to_write;
+ }
+ }
+
+ /**
+ * Get the size of the memory dump made so far.
+ * @return The size.
+ */
+ size_t GetSize()
+ {
+ return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
+ }
+};
+
/** The saveload struct, containing reader-writer functions, buffer, version, etc. */
struct SaveLoadParams {
SaveLoadAction action; ///< are we doing a save or a load atm.
@@ -258,7 +314,7 @@ struct SaveLoadParams {
size_t offs_base; ///< the offset in number of bytes since we started writing data (eg uncompressed savegame size)
- DumperProc *dump_bytes; ///< savegame dumper function
+ MemoryDumper *dumper; ///< Memory dumper to write the savegame to.
ReaderProc *read_bytes; ///< savegame loader function
/* When saving/loading savegames, they are always saved to a temporary memory-place
@@ -460,26 +516,6 @@ static inline size_t SlGetOffs()
}
/**
- * Flush the output buffer by writing to disk with the given reader.
- * If the buffer pointer has not yet been set up, set it up now. Usually
- * only called when the buffer is full, or there is no more data to be processed
- */
-static void SlWriteFill()
-{
- /* flush the buffer to disk (the writer) */
- if (_sl.bufp != NULL) {
- uint len = _sl.bufp - _sl.buf;
- _sl.offs_base += len;
- if (len) _sl.dump_bytes(len);
- }
-
- /* All the data from the buffer has been written away, rewind to the beginning
- * to start reading in more data */
- _sl.bufp = _sl.buf;
- _sl.bufe = _sl.buf + _sl.bufsize;
-}
-
-/**
* Read in a single byte from file. If the temporary buffer is full,
* flush it to its final destination
* @return return the read byte from file
@@ -494,19 +530,14 @@ static inline byte SlReadByteInternal()
byte SlReadByte() {return SlReadByteInternal();}
/**
- * Write away a single byte from memory. If the temporary buffer is full,
- * flush it to its destination (file)
- * @param b the byte that is currently written
+ * Wrapper for writing a byte to the dumper.
+ * @param b The byte to write.
*/
-static inline void SlWriteByteInternal(byte b)
+void SlWriteByte(byte b)
{
- if (_sl.bufp == _sl.bufe) SlWriteFill();
- *_sl.bufp++ = b;
+ _sl.dumper->WriteByte(b);
}
-/** Wrapper for SlWriteByteInternal */
-void SlWriteByte(byte b) {SlWriteByteInternal(b);}
-
static inline int SlReadUint16()
{
int x = SlReadByte() << 8;
@@ -801,7 +832,7 @@ static void SlCopyBytes(void *ptr, size_t length)
for (; length != 0; length--) *p++ = SlReadByteInternal();
break;
case SLA_SAVE:
- for (; length != 0; length--) SlWriteByteInternal(*p++);
+ for (; length != 0; length--) SlWriteByte(*p++);
break;
default: NOT_REACHED();
}
@@ -1456,12 +1487,12 @@ void SlAutolength(AutolengthProc *proc, void *arg)
_sl.need_length = NL_WANTLENGTH;
SlSetLength(_sl.obj_len);
- offs = SlGetOffs() + _sl.obj_len;
+ offs = _sl.dumper->GetSize() + _sl.obj_len;
/* And write the stuff */
proc(arg);
- if (offs != SlGetOffs()) SlErrorCorrupt("Invalid chunk size");
+ if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
}
/**
@@ -1799,48 +1830,16 @@ static void UninitNoComp()
free(_sl.buf_ori);
}
-/********************************************
- ********** START OF MEMORY CODE (in ram)****
- ********************************************/
-
#include "../gui.h"
struct ThreadedSave {
- uint count;
byte ff_state;
bool saveinprogress;
CursorID cursor;
};
-/** Save in chunks of 128 KiB. */
-static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
-/** Memory allocation for storing savegames in memory. */
-static AutoFreeSmallVector<byte *, 16> _memory_savegame;
-
static ThreadedSave _ts;
-static void WriteMem(size_t size)
-{
- _ts.count += (uint)size;
-
- _sl.buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
- *_memory_savegame.Append() = _sl.buf;
-}
-
-static void UnInitMem()
-{
- _memory_savegame.Clear();
-}
-
-static bool InitMem()
-{
- _ts.count = 0;
- _sl.bufsize = MEMORY_CHUNK_SIZE;
-
- UnInitMem();
- WriteMem(0);
- return true;
-}
/********************************************
********** START OF ZLIB CODE **************
@@ -2156,6 +2155,15 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin
extern bool AfterLoadGame();
extern bool LoadOldSaveGame(const char *file);
+/**
+ * Clear/free the memory dumper.
+ */
+static inline void ClearMemoryDumper()
+{
+ delete _sl.dumper;
+ _sl.dumper = NULL;
+}
+
/** Small helper function to close the to be loaded savegame and signal error */
static inline SaveOrLoadResult AbortSaveLoad()
{
@@ -2232,25 +2240,10 @@ static SaveOrLoadResult SaveFileToDisk(bool threaded)
if (!fmt->init_write(compression)) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor");
- uint i = 0;
- size_t t = _ts.count;
-
- if (_ts.count != _sl.offs_base) SlErrorCorrupt("Unexpected size of chunk");
- while (t >= MEMORY_CHUNK_SIZE) {
- fmt->writer(_memory_savegame[i++], MEMORY_CHUNK_SIZE);
- t -= MEMORY_CHUNK_SIZE;
- }
-
- if (t != 0) {
- /* The last block is (almost) always not fully filled, so only write away
- * as much data as it is in there */
- assert(t == _ts.count % MEMORY_CHUNK_SIZE);
- fmt->writer(_memory_savegame[i], t);
- }
+ _sl.dumper->Flush(fmt->writer);
+ ClearMemoryDumper();
fmt->uninit_write();
- if (_ts.count != _sl.offs_base) SlErrorCorrupt("Unexpected size of chunk");
- UnInitMem();
fclose(_sl.fh);
if (threaded) SetAsyncSaveFinish(SaveFileDone);
@@ -2364,15 +2357,13 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, boo
if (mode == SL_SAVE) { // SAVE game
DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
- _sl.dump_bytes = WriteMem;
- _sl.excpt_uninit = UnInitMem;
- InitMem();
+ _sl.dumper = new MemoryDumper();
+ _sl.excpt_uninit = ClearMemoryDumper;
_sl_version = SAVEGAME_VERSION;
SaveViewportBeforeSaveGame();
SlSaveChunks();
- SlWriteFill(); // flush the save buffer
SaveFileStart();
if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;