diff options
-rw-r--r-- | src/saveload/saveload.cpp | 107 |
1 files changed, 61 insertions, 46 deletions
diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index e096b8892..49ecba4b4 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -273,6 +273,48 @@ struct LoadFilter { virtual size_t Read(byte *buf, size_t len) = 0; }; + +/** A buffer for reading (and buffering) savegame data. */ +struct ReadBuffer { + byte buf[MEMORY_CHUNK_SIZE]; ///< Buffer we're going to read from. + byte *bufp; ///< Location we're at reading the buffer. + byte *bufe; ///< End of the buffer we can read from. + LoadFilter *reader; ///< The filter used to actually read. + size_t read; ///< The amount of read bytes so far from the filter. + + /** + * Initialise our variables. + * @param reader The filter to actually read data. + */ + ReadBuffer(LoadFilter *reader) : bufp(NULL), bufe(NULL), reader(reader), read(0) + { + } + + FORCEINLINE byte ReadByte() + { + if (this->bufp == this->bufe) { + size_t len = this->reader->Read(this->buf, lengthof(this->buf)); + if (len == 0) SlErrorCorrupt("Unexpected end of chunk"); + + this->read += len; + this->bufp = this->buf; + this->bufe = this->buf + len; + } + + return *this->bufp++; + } + + /** + * Get the size of the memory dump made so far. + * @return The size. + */ + size_t GetSize() const + { + return this->read - (this->bufe - this->bufp); + } +}; + + /** * Instantiator for a load filter. * @param chain The next filter in this chain. @@ -379,7 +421,7 @@ struct MemoryDumper { * Get the size of the memory dump made so far. * @return The size. */ - size_t GetSize() + size_t GetSize() const { return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf); } @@ -395,17 +437,11 @@ struct SaveLoadParams { size_t obj_len; ///< the length of the current object we are busy with int array_index, last_array_index; ///< in the case of an array, the current and last positions - size_t offs_base; ///< the offset in number of bytes since we started writing data (eg uncompressed savegame size) - MemoryDumper *dumper; ///< Memory dumper to write the savegame to. SaveFilter *sf; ///< Filter to write the savegame to. - LoadFilter *lf; ///< Filter to read the savegame from. - /* When saving/loading savegames, they are always saved to a temporary memory-place - * to be flushed to file (save) or to final place (load) when full. */ - byte *bufp, *bufe; ///< bufp(ointer) gives the current position in the buffer bufe(nd) gives the end of the buffer - - byte buf[MEMORY_CHUNK_SIZE]; ///< memory for reading savegame data + ReadBuffer *reader; ///< Savegame reading buffer. + LoadFilter *lf; ///< Filter to read the savegame from. StringID error_str; ///< the translatable error message to show char *extra_msg; ///< the error message @@ -577,37 +613,14 @@ void ProcessAsyncSaveFinish() } /** - * Fill the input buffer by reading from the file with the given reader - */ -static void SlReadFill() -{ - size_t len = _sl.lf->Read(_sl.buf, sizeof(_sl.buf)); - if (len == 0) SlErrorCorrupt("Unexpected end of chunk"); - - _sl.bufp = _sl.buf; - _sl.bufe = _sl.buf + len; - _sl.offs_base += len; -} - -static inline size_t SlGetOffs() -{ - return _sl.offs_base - (_sl.bufe - _sl.bufp); -} - -/** - * 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 + * Wrapper for reading a byte from the buffer. + * @return The read byte. */ -static inline byte SlReadByteInternal() +byte SlReadByte() { - if (_sl.bufp == _sl.bufe) SlReadFill(); - return *_sl.bufp++; + return _sl.reader->ReadByte(); } -/** Wrapper for SlReadByteInternal */ -byte SlReadByte() {return SlReadByteInternal();} - /** * Wrapper for writing a byte to the dumper. * @param b The byte to write. @@ -818,7 +831,7 @@ int SlIterateArray() /* After reading in the whole array inside the loop * we must have read in all the data, so we must be at end of current block. */ - if (_next_offs != 0 && SlGetOffs() != _next_offs) SlErrorCorrupt("Invalid chunk size"); + if (_next_offs != 0 && _sl.reader->GetSize() != _next_offs) SlErrorCorrupt("Invalid chunk size"); while (true) { uint length = SlReadArrayLength(); @@ -828,7 +841,7 @@ int SlIterateArray() } _sl.obj_len = --length; - _next_offs = SlGetOffs() + length; + _next_offs = _sl.reader->GetSize() + length; switch (_sl.block_mode) { case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break; @@ -848,7 +861,7 @@ int SlIterateArray() void SlSkipArray() { while (SlIterateArray() != -1) { - SlSkipBytes(_next_offs - SlGetOffs()); + SlSkipBytes(_next_offs - _sl.reader->GetSize()); } } @@ -908,7 +921,7 @@ static void SlCopyBytes(void *ptr, size_t length) switch (_sl.action) { case SLA_LOAD_CHECK: case SLA_LOAD: - for (; length != 0; length--) *p++ = SlReadByteInternal(); + for (; length != 0; length--) *p++ = SlReadByte(); break; case SLA_SAVE: for (; length != 0; length--) SlWriteByte(*p++); @@ -1601,9 +1614,9 @@ static void SlLoadChunk(const ChunkHandler *ch) len = (SlReadByte() << 16) | ((m >> 4) << 24); len += SlReadUint16(); _sl.obj_len = len; - endoffs = SlGetOffs() + len; + endoffs = _sl.reader->GetSize() + len; ch->load_proc(); - if (SlGetOffs() != endoffs) SlErrorCorrupt("Invalid chunk size"); + if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size"); } else { SlErrorCorrupt("Invalid chunk type"); } @@ -1647,13 +1660,13 @@ static void SlLoadCheckChunk(const ChunkHandler *ch) len = (SlReadByte() << 16) | ((m >> 4) << 24); len += SlReadUint16(); _sl.obj_len = len; - endoffs = SlGetOffs() + len; + endoffs = _sl.reader->GetSize() + len; if (ch->load_check_proc) { ch->load_check_proc(); } else { SlSkipBytes(len); } - if (SlGetOffs() != endoffs) SlErrorCorrupt("Invalid chunk size"); + if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size"); } else { SlErrorCorrupt("Invalid chunk type"); } @@ -2348,6 +2361,9 @@ static inline void ClearSaveLoadState() delete _sl.sf; _sl.sf = NULL; + delete _sl.reader; + _sl.reader = NULL; + delete _sl.lf; _sl.lf = NULL; } @@ -2505,8 +2521,6 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, boo /* Mark SL_LOAD_CHECK as supported for this savegame. */ if (mode == SL_LOAD_CHECK) _load_check_data.checkable = true; - _sl.bufe = _sl.bufp = NULL; - _sl.offs_base = 0; switch (mode) { case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break; case SL_LOAD: _sl.action = SLA_LOAD; break; @@ -2609,6 +2623,7 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, boo } _sl.lf = fmt->init_load(_sl.lf); + _sl.reader = new ReadBuffer(_sl.lf); if (mode != SL_LOAD_CHECK) { _engine_mngr.ResetToDefaultMapping(); |