|
|
|
@ -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();
|
|
|
|
|