Merge branch 'save_ext' into jgrpp
# Conflicts: # src/saveload/saveload.cpp
This commit is contained in:
@@ -932,6 +932,7 @@
|
|||||||
<ClInclude Include="..\src\saveload\saveload.h" />
|
<ClInclude Include="..\src\saveload\saveload.h" />
|
||||||
<ClInclude Include="..\src\saveload\saveload_filter.h" />
|
<ClInclude Include="..\src\saveload\saveload_filter.h" />
|
||||||
<ClInclude Include="..\src\saveload\saveload_internal.h" />
|
<ClInclude Include="..\src\saveload\saveload_internal.h" />
|
||||||
|
<ClInclude Include="..\src\saveload\saveload_buffer.h" />
|
||||||
<ClCompile Include="..\src\saveload\signs_sl.cpp" />
|
<ClCompile Include="..\src\saveload\signs_sl.cpp" />
|
||||||
<ClCompile Include="..\src\saveload\station_sl.cpp" />
|
<ClCompile Include="..\src\saveload\station_sl.cpp" />
|
||||||
<ClCompile Include="..\src\saveload\storage_sl.cpp" />
|
<ClCompile Include="..\src\saveload\storage_sl.cpp" />
|
||||||
|
@@ -1956,6 +1956,9 @@
|
|||||||
<ClInclude Include="..\src\saveload\saveload_internal.h">
|
<ClInclude Include="..\src\saveload\saveload_internal.h">
|
||||||
<Filter>Save/Load handlers</Filter>
|
<Filter>Save/Load handlers</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\src\saveload\saveload_buffer.h">
|
||||||
|
<Filter>Save/Load handlers</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClCompile Include="..\src\saveload\signs_sl.cpp">
|
<ClCompile Include="..\src\saveload\signs_sl.cpp">
|
||||||
<Filter>Save/Load handlers</Filter>
|
<Filter>Save/Load handlers</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@@ -953,6 +953,7 @@
|
|||||||
<ClInclude Include="..\src\saveload\saveload.h" />
|
<ClInclude Include="..\src\saveload\saveload.h" />
|
||||||
<ClInclude Include="..\src\saveload\saveload_filter.h" />
|
<ClInclude Include="..\src\saveload\saveload_filter.h" />
|
||||||
<ClInclude Include="..\src\saveload\saveload_internal.h" />
|
<ClInclude Include="..\src\saveload\saveload_internal.h" />
|
||||||
|
<ClInclude Include="..\src\saveload\saveload_buffer.h" />
|
||||||
<ClCompile Include="..\src\saveload\signs_sl.cpp" />
|
<ClCompile Include="..\src\saveload\signs_sl.cpp" />
|
||||||
<ClCompile Include="..\src\saveload\station_sl.cpp" />
|
<ClCompile Include="..\src\saveload\station_sl.cpp" />
|
||||||
<ClCompile Include="..\src\saveload\storage_sl.cpp" />
|
<ClCompile Include="..\src\saveload\storage_sl.cpp" />
|
||||||
|
@@ -1956,6 +1956,9 @@
|
|||||||
<ClInclude Include="..\src\saveload\saveload_internal.h">
|
<ClInclude Include="..\src\saveload\saveload_internal.h">
|
||||||
<Filter>Save/Load handlers</Filter>
|
<Filter>Save/Load handlers</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\src\saveload\saveload_buffer.h">
|
||||||
|
<Filter>Save/Load handlers</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClCompile Include="..\src\saveload\signs_sl.cpp">
|
<ClCompile Include="..\src\saveload\signs_sl.cpp">
|
||||||
<Filter>Save/Load handlers</Filter>
|
<Filter>Save/Load handlers</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@@ -953,6 +953,7 @@
|
|||||||
<ClInclude Include="..\src\saveload\saveload.h" />
|
<ClInclude Include="..\src\saveload\saveload.h" />
|
||||||
<ClInclude Include="..\src\saveload\saveload_filter.h" />
|
<ClInclude Include="..\src\saveload\saveload_filter.h" />
|
||||||
<ClInclude Include="..\src\saveload\saveload_internal.h" />
|
<ClInclude Include="..\src\saveload\saveload_internal.h" />
|
||||||
|
<ClInclude Include="..\src\saveload\saveload_buffer.h" />
|
||||||
<ClCompile Include="..\src\saveload\signs_sl.cpp" />
|
<ClCompile Include="..\src\saveload\signs_sl.cpp" />
|
||||||
<ClCompile Include="..\src\saveload\station_sl.cpp" />
|
<ClCompile Include="..\src\saveload\station_sl.cpp" />
|
||||||
<ClCompile Include="..\src\saveload\storage_sl.cpp" />
|
<ClCompile Include="..\src\saveload\storage_sl.cpp" />
|
||||||
|
@@ -1956,6 +1956,9 @@
|
|||||||
<ClInclude Include="..\src\saveload\saveload_internal.h">
|
<ClInclude Include="..\src\saveload\saveload_internal.h">
|
||||||
<Filter>Save/Load handlers</Filter>
|
<Filter>Save/Load handlers</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\src\saveload\saveload_buffer.h">
|
||||||
|
<Filter>Save/Load handlers</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClCompile Include="..\src\saveload\signs_sl.cpp">
|
<ClCompile Include="..\src\saveload\signs_sl.cpp">
|
||||||
<Filter>Save/Load handlers</Filter>
|
<Filter>Save/Load handlers</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@@ -2934,6 +2934,10 @@
|
|||||||
RelativePath=".\..\src\saveload\saveload_internal.h"
|
RelativePath=".\..\src\saveload\saveload_internal.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\..\src\saveload\saveload_buffer.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\..\src\saveload\signs_sl.cpp"
|
RelativePath=".\..\src\saveload\signs_sl.cpp"
|
||||||
>
|
>
|
||||||
|
@@ -2931,6 +2931,10 @@
|
|||||||
RelativePath=".\..\src\saveload\saveload_internal.h"
|
RelativePath=".\..\src\saveload\saveload_internal.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\..\src\saveload\saveload_buffer.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\..\src\saveload\signs_sl.cpp"
|
RelativePath=".\..\src\saveload\signs_sl.cpp"
|
||||||
>
|
>
|
||||||
|
@@ -670,6 +670,7 @@ saveload/saveload.cpp
|
|||||||
saveload/saveload.h
|
saveload/saveload.h
|
||||||
saveload/saveload_filter.h
|
saveload/saveload_filter.h
|
||||||
saveload/saveload_internal.h
|
saveload/saveload_internal.h
|
||||||
|
saveload/saveload_buffer.h
|
||||||
saveload/signs_sl.cpp
|
saveload/signs_sl.cpp
|
||||||
saveload/station_sl.cpp
|
saveload/station_sl.cpp
|
||||||
saveload/storage_sl.cpp
|
saveload/storage_sl.cpp
|
||||||
|
@@ -393,13 +393,32 @@ static inline T ROR(const T x, const uint8 n)
|
|||||||
* (since it will use hardware swapping if available).
|
* (since it will use hardware swapping if available).
|
||||||
* Even though they should return uint16 and uint32, we get
|
* Even though they should return uint16 and uint32, we get
|
||||||
* warnings if we don't cast those (why?) */
|
* warnings if we don't cast those (why?) */
|
||||||
|
#define BSWAP64(x) ((uint32)CFSwapInt64(x))
|
||||||
#define BSWAP32(x) ((uint32)CFSwapInt32(x))
|
#define BSWAP32(x) ((uint32)CFSwapInt32(x))
|
||||||
#define BSWAP16(x) ((uint16)CFSwapInt16(x))
|
#define BSWAP16(x) ((uint16)CFSwapInt16(x))
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
/* MSVC has intrinsics for swapping, resulting in faster code */
|
/* MSVC has intrinsics for swapping, resulting in faster code */
|
||||||
|
#define BSWAP64(x) (_byteswap_uint64(x))
|
||||||
#define BSWAP32(x) (_byteswap_ulong(x))
|
#define BSWAP32(x) (_byteswap_ulong(x))
|
||||||
#define BSWAP16(x) (_byteswap_ushort(x))
|
#define BSWAP16(x) (_byteswap_ushort(x))
|
||||||
#else
|
#else
|
||||||
|
/**
|
||||||
|
* Perform a 64 bits endianness bitswap on x.
|
||||||
|
* @param x the variable to bitswap
|
||||||
|
* @return the bitswapped value.
|
||||||
|
*/
|
||||||
|
static inline uint64 BSWAP64(uint64 x)
|
||||||
|
{
|
||||||
|
#if !defined(__ICC) && (defined(__GNUC__) || defined(__clang__))
|
||||||
|
/* GCC >= 4.3 provides a builtin, resulting in faster code */
|
||||||
|
return (uint64)__builtin_bswap64((uint64)x);
|
||||||
|
#else
|
||||||
|
return ((x >> 56) & 0xFFULL) | ((x >> 40) & 0xFF00ULL) | ((x >> 24) & 0xFF0000ULL) | ((x >> 8) & 0xFF000000ULL) |
|
||||||
|
((x << 8) & 0xFF00000000ULL) | ((x << 24) & 0xFF0000000000ULL) | ((x << 40) & 0xFF000000000000ULL) | ((x << 56) & 0xFF000000000000ULL);
|
||||||
|
;
|
||||||
|
#endif /* __GNUC__ || __clang__ */
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform a 32 bits endianness bitswap on x.
|
* Perform a 32 bits endianness bitswap on x.
|
||||||
* @param x the variable to bitswap
|
* @param x the variable to bitswap
|
||||||
|
@@ -19,25 +19,33 @@
|
|||||||
#if TTD_ENDIAN == TTD_BIG_ENDIAN
|
#if TTD_ENDIAN == TTD_BIG_ENDIAN
|
||||||
#define FROM_BE16(x) (x)
|
#define FROM_BE16(x) (x)
|
||||||
#define FROM_BE32(x) (x)
|
#define FROM_BE32(x) (x)
|
||||||
|
#define FROM_BE64(x) (x)
|
||||||
#define TO_BE16(x) (x)
|
#define TO_BE16(x) (x)
|
||||||
#define TO_BE32(x) (x)
|
#define TO_BE32(x) (x)
|
||||||
#define TO_BE32X(x) (x)
|
#define TO_BE32X(x) (x)
|
||||||
|
#define TO_BE64(x) (x)
|
||||||
#define FROM_LE16(x) BSWAP16(x)
|
#define FROM_LE16(x) BSWAP16(x)
|
||||||
#define FROM_LE32(x) BSWAP32(x)
|
#define FROM_LE32(x) BSWAP32(x)
|
||||||
|
#define FROM_LE64(x) BSWAP64(x)
|
||||||
#define TO_LE16(x) BSWAP16(x)
|
#define TO_LE16(x) BSWAP16(x)
|
||||||
#define TO_LE32(x) BSWAP32(x)
|
#define TO_LE32(x) BSWAP32(x)
|
||||||
#define TO_LE32X(x) BSWAP32(x)
|
#define TO_LE32X(x) BSWAP32(x)
|
||||||
|
#define TO_LE64(x) BSWAP64(x)
|
||||||
#else
|
#else
|
||||||
#define FROM_BE16(x) BSWAP16(x)
|
#define FROM_BE16(x) BSWAP16(x)
|
||||||
#define FROM_BE32(x) BSWAP32(x)
|
#define FROM_BE32(x) BSWAP32(x)
|
||||||
|
#define FROM_BE64(x) BSWAP64(x)
|
||||||
#define TO_BE16(x) BSWAP16(x)
|
#define TO_BE16(x) BSWAP16(x)
|
||||||
#define TO_BE32(x) BSWAP32(x)
|
#define TO_BE32(x) BSWAP32(x)
|
||||||
#define TO_BE32X(x) BSWAP32(x)
|
#define TO_BE32X(x) BSWAP32(x)
|
||||||
|
#define TO_BE64(x) BSWAP64(x)
|
||||||
#define FROM_LE16(x) (x)
|
#define FROM_LE16(x) (x)
|
||||||
#define FROM_LE32(x) (x)
|
#define FROM_LE32(x) (x)
|
||||||
|
#define FROM_LE64(x) (x)
|
||||||
#define TO_LE16(x) (x)
|
#define TO_LE16(x) (x)
|
||||||
#define TO_LE32(x) (x)
|
#define TO_LE32(x) (x)
|
||||||
#define TO_LE32X(x) (x)
|
#define TO_LE32X(x) (x)
|
||||||
|
#define TO_LE64(x) (x)
|
||||||
#endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
|
#endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
|
||||||
|
|
||||||
static inline uint16 ReadLE16Aligned(const void *x)
|
static inline uint16 ReadLE16Aligned(const void *x)
|
||||||
|
@@ -52,6 +52,7 @@
|
|||||||
|
|
||||||
#include "saveload_internal.h"
|
#include "saveload_internal.h"
|
||||||
#include "saveload_filter.h"
|
#include "saveload_filter.h"
|
||||||
|
#include "saveload_buffer.h"
|
||||||
#include "extended_ver_sl.h"
|
#include "extended_ver_sl.h"
|
||||||
|
|
||||||
#include "../safeguards.h"
|
#include "../safeguards.h"
|
||||||
@@ -301,108 +302,113 @@ enum SaveLoadAction {
|
|||||||
enum NeedLength {
|
enum NeedLength {
|
||||||
NL_NONE = 0, ///< not working in NeedLength mode
|
NL_NONE = 0, ///< not working in NeedLength mode
|
||||||
NL_WANTLENGTH = 1, ///< writing length and data
|
NL_WANTLENGTH = 1, ///< writing length and data
|
||||||
NL_CALCLENGTH = 2, ///< need to calculate the length
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Save in chunks of 128 KiB. */
|
void ReadBuffer::SkipBytesSlowPath(size_t bytes)
|
||||||
static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
|
{
|
||||||
|
bytes -= (this->bufe - this->bufp);
|
||||||
/** A buffer for reading (and buffering) savegame data. */
|
while (true) {
|
||||||
struct ReadBuffer {
|
size_t len = this->reader->Read(this->buf, lengthof(this->buf));
|
||||||
byte buf[MEMORY_CHUNK_SIZE]; ///< Buffer we're going to read from.
|
if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
|
||||||
byte *bufp; ///< Location we're at reading the buffer.
|
this->read += len;
|
||||||
byte *bufe; ///< End of the buffer we can read from.
|
if (len >= bytes) {
|
||||||
LoadFilter *reader; ///< The filter used to actually read.
|
this->bufp = this->buf + bytes;
|
||||||
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)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline 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;
|
this->bufe = this->buf + len;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
bytes -= len;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return *this->bufp++;
|
void ReadBuffer::AcquireBytes()
|
||||||
|
{
|
||||||
|
size_t remainder = this->bufe - this->bufp;
|
||||||
|
if (remainder) {
|
||||||
|
memmove(this->buf, this->bufp, remainder);
|
||||||
|
}
|
||||||
|
size_t len = this->reader->Read(this->buf + remainder, lengthof(this->buf) - remainder);
|
||||||
|
if (len == 0) SlErrorCorrupt("Unexpected end of chunk");
|
||||||
|
|
||||||
|
this->read += len;
|
||||||
|
this->bufp = this->buf;
|
||||||
|
this->bufe = this->buf + remainder + len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryDumper::FinaliseBlock()
|
||||||
|
{
|
||||||
|
assert(this->saved_buf == nullptr);
|
||||||
|
if (!this->blocks.empty()) {
|
||||||
|
size_t s = MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
|
||||||
|
this->blocks.back().size = s;
|
||||||
|
this->completed_block_bytes += s;
|
||||||
|
}
|
||||||
|
this->buf = this->bufe = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryDumper::AllocateBuffer()
|
||||||
|
{
|
||||||
|
if (this->saved_buf) {
|
||||||
|
const size_t offset = this->buf - this->autolen_buf;
|
||||||
|
const size_t size = (this->autolen_buf_end - this->autolen_buf) * 2;
|
||||||
|
this->autolen_buf = ReallocT<byte>(this->autolen_buf, size);
|
||||||
|
this->autolen_buf_end = this->autolen_buf + size;
|
||||||
|
this->buf = this->autolen_buf + offset;
|
||||||
|
this->bufe = this->autolen_buf_end;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->FinaliseBlock();
|
||||||
|
this->buf = CallocT<byte>(MEMORY_CHUNK_SIZE);
|
||||||
|
this->blocks.emplace_back(this->buf);
|
||||||
|
this->bufe = this->buf + MEMORY_CHUNK_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flush this dumper into a writer.
|
||||||
|
* @param writer The filter we want to use.
|
||||||
|
*/
|
||||||
|
void MemoryDumper::Flush(SaveFilter *writer)
|
||||||
|
{
|
||||||
|
this->FinaliseBlock();
|
||||||
|
|
||||||
|
uint block_count = this->blocks.size();
|
||||||
|
for (uint i = 0; i < block_count; i++) {
|
||||||
|
writer->Write(this->blocks[i].data, this->blocks[i].size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
writer->Finish();
|
||||||
* Get the size of the memory dump made so far.
|
}
|
||||||
* @return The size.
|
|
||||||
*/
|
|
||||||
size_t GetSize() const
|
|
||||||
{
|
|
||||||
return this->read - (this->bufe - this->bufp);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
void MemoryDumper::StartAutoLength()
|
||||||
|
{
|
||||||
|
assert(this->saved_buf == nullptr);
|
||||||
|
|
||||||
/** Container for dumping the savegame (quickly) to memory. */
|
this->saved_buf = this->buf;
|
||||||
struct MemoryDumper {
|
this->saved_bufe = this->bufe;
|
||||||
AutoFreeSmallVector<byte *, 16> blocks; ///< Buffer with blocks of allocated memory.
|
this->buf = this->autolen_buf;
|
||||||
byte *buf; ///< Buffer we're going to write to.
|
this->bufe = this->autolen_buf_end;
|
||||||
byte *bufe; ///< End of the buffer we write to.
|
}
|
||||||
|
|
||||||
/** Initialise our variables. */
|
std::pair<byte *, size_t> MemoryDumper::StopAutoLength()
|
||||||
MemoryDumper() : buf(NULL), bufe(NULL)
|
{
|
||||||
{
|
assert(this->saved_buf != nullptr);
|
||||||
}
|
auto res = std::make_pair(this->autolen_buf, this->buf - this->autolen_buf);
|
||||||
|
|
||||||
/**
|
this->buf = this->saved_buf;
|
||||||
* Write a single byte into the dumper.
|
this->bufe = this->saved_bufe;
|
||||||
* @param b The byte to write.
|
this->saved_buf = this->saved_bufe = nullptr;
|
||||||
*/
|
return res;
|
||||||
inline 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;
|
/**
|
||||||
}
|
* Get the size of the memory dump made so far.
|
||||||
|
* @return The size.
|
||||||
/**
|
*/
|
||||||
* Flush this dumper into a writer.
|
size_t MemoryDumper::GetSize() const
|
||||||
* @param writer The filter we want to use.
|
{
|
||||||
*/
|
assert(this->saved_buf == nullptr);
|
||||||
void Flush(SaveFilter *writer)
|
return this->completed_block_bytes + (this->bufe ? (MEMORY_CHUNK_SIZE - (this->bufe - this->buf)) : 0);
|
||||||
{
|
}
|
||||||
uint i = 0;
|
|
||||||
size_t t = this->GetSize();
|
|
||||||
|
|
||||||
while (t > 0) {
|
|
||||||
size_t to_write = min(MEMORY_CHUNK_SIZE, t);
|
|
||||||
|
|
||||||
writer->Write(this->blocks[i++], to_write);
|
|
||||||
t -= to_write;
|
|
||||||
}
|
|
||||||
|
|
||||||
writer->Finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the size of the memory dump made so far.
|
|
||||||
* @return The size.
|
|
||||||
*/
|
|
||||||
size_t GetSize() const
|
|
||||||
{
|
|
||||||
return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** The saveload struct, containing reader-writer functions, buffer, version, etc. */
|
/** The saveload struct, containing reader-writer functions, buffer, version, etc. */
|
||||||
struct SaveLoadParams {
|
struct SaveLoadParams {
|
||||||
@@ -429,6 +435,16 @@ struct SaveLoadParams {
|
|||||||
|
|
||||||
static SaveLoadParams _sl; ///< Parameters used for/at saveload.
|
static SaveLoadParams _sl; ///< Parameters used for/at saveload.
|
||||||
|
|
||||||
|
ReadBuffer *ReadBuffer::GetCurrent()
|
||||||
|
{
|
||||||
|
return _sl.reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryDumper *MemoryDumper::GetCurrent()
|
||||||
|
{
|
||||||
|
return _sl.dumper;
|
||||||
|
}
|
||||||
|
|
||||||
/* these define the chunks */
|
/* these define the chunks */
|
||||||
extern const ChunkHandler _version_ext_chunk_handlers[];
|
extern const ChunkHandler _version_ext_chunk_handlers[];
|
||||||
extern const ChunkHandler _gamelog_chunk_handlers[];
|
extern const ChunkHandler _gamelog_chunk_handlers[];
|
||||||
@@ -665,6 +681,34 @@ byte SlReadByte()
|
|||||||
return _sl.reader->ReadByte();
|
return _sl.reader->ReadByte();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read in bytes from the file/data structure but don't do
|
||||||
|
* anything with them, discarding them in effect
|
||||||
|
* @param length The amount of bytes that is being treated this way
|
||||||
|
*/
|
||||||
|
void SlSkipBytes(size_t length)
|
||||||
|
{
|
||||||
|
return _sl.reader->SkipBytes(length);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SlReadUint16()
|
||||||
|
{
|
||||||
|
_sl.reader->CheckBytes(2);
|
||||||
|
return _sl.reader->RawReadUint16();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 SlReadUint32()
|
||||||
|
{
|
||||||
|
_sl.reader->CheckBytes(4);
|
||||||
|
return _sl.reader->RawReadUint32();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64 SlReadUint64()
|
||||||
|
{
|
||||||
|
_sl.reader->CheckBytes(8);
|
||||||
|
return _sl.reader->RawReadUint64();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for writing a byte to the dumper.
|
* Wrapper for writing a byte to the dumper.
|
||||||
* @param b The byte to write.
|
* @param b The byte to write.
|
||||||
@@ -674,6 +718,24 @@ void SlWriteByte(byte b)
|
|||||||
_sl.dumper->WriteByte(b);
|
_sl.dumper->WriteByte(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SlWriteUint16(uint16 v)
|
||||||
|
{
|
||||||
|
_sl.dumper->CheckBytes(2);
|
||||||
|
_sl.dumper->RawWriteUint16(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlWriteUint32(uint32 v)
|
||||||
|
{
|
||||||
|
_sl.dumper->CheckBytes(4);
|
||||||
|
_sl.dumper->RawWriteUint32(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlWriteUint64(uint64 v)
|
||||||
|
{
|
||||||
|
_sl.dumper->CheckBytes(8);
|
||||||
|
_sl.dumper->RawWriteUint64(v);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns number of bytes read so far
|
* Returns number of bytes read so far
|
||||||
* May only be called during a load/load check action
|
* May only be called during a load/load check action
|
||||||
@@ -942,10 +1004,6 @@ void SlSetLength(size_t length)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NL_CALCLENGTH:
|
|
||||||
_sl.obj_len += (int)length;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: NOT_REACHED();
|
default: NOT_REACHED();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -963,10 +1021,10 @@ static void SlCopyBytes(void *ptr, size_t length)
|
|||||||
switch (_sl.action) {
|
switch (_sl.action) {
|
||||||
case SLA_LOAD_CHECK:
|
case SLA_LOAD_CHECK:
|
||||||
case SLA_LOAD:
|
case SLA_LOAD:
|
||||||
for (; length != 0; length--) *p++ = SlReadByte();
|
_sl.reader->CopyBytes(p, length);
|
||||||
break;
|
break;
|
||||||
case SLA_SAVE:
|
case SLA_SAVE:
|
||||||
for (; length != 0; length--) SlWriteByte(*p++);
|
_sl.dumper->CopyBytes(p, length);
|
||||||
break;
|
break;
|
||||||
default: NOT_REACHED();
|
default: NOT_REACHED();
|
||||||
}
|
}
|
||||||
@@ -1279,8 +1337,6 @@ void SlArray(void *array, size_t length, VarType conv)
|
|||||||
/* Automatically calculate the length? */
|
/* Automatically calculate the length? */
|
||||||
if (_sl.need_length != NL_NONE) {
|
if (_sl.need_length != NL_NONE) {
|
||||||
SlSetLength(SlCalcArrayLen(length, conv));
|
SlSetLength(SlCalcArrayLen(length, conv));
|
||||||
/* Determine length only? */
|
|
||||||
if (_sl.need_length == NL_CALCLENGTH) return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTICE - handle some buggy stuff, in really old versions everything was saved
|
/* NOTICE - handle some buggy stuff, in really old versions everything was saved
|
||||||
@@ -1480,8 +1536,6 @@ static void SlList(void *list, SLRefType conv)
|
|||||||
/* Automatically calculate the length? */
|
/* Automatically calculate the length? */
|
||||||
if (_sl.need_length != NL_NONE) {
|
if (_sl.need_length != NL_NONE) {
|
||||||
SlSetLength(SlCalcListLen<PtrList>(list));
|
SlSetLength(SlCalcListLen<PtrList>(list));
|
||||||
/* Determine length only? */
|
|
||||||
if (_sl.need_length == NL_CALCLENGTH) return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PtrList *l = (PtrList *)list;
|
PtrList *l = (PtrList *)list;
|
||||||
@@ -1538,8 +1592,6 @@ static void SlVarList(void *list, VarType conv)
|
|||||||
/* Automatically calculate the length? */
|
/* Automatically calculate the length? */
|
||||||
if (_sl.need_length != NL_NONE) {
|
if (_sl.need_length != NL_NONE) {
|
||||||
SlSetLength(SlCalcVarListLen<PtrList>(list, size_len));
|
SlSetLength(SlCalcVarListLen<PtrList>(list, size_len));
|
||||||
/* Determine length only? */
|
|
||||||
if (_sl.need_length == NL_CALCLENGTH) return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PtrList *l = (PtrList *)list;
|
PtrList *l = (PtrList *)list;
|
||||||
@@ -1813,7 +1865,6 @@ void SlObject(void *object, const SaveLoad *sld)
|
|||||||
/* Automatically calculate the length? */
|
/* Automatically calculate the length? */
|
||||||
if (_sl.need_length != NL_NONE) {
|
if (_sl.need_length != NL_NONE) {
|
||||||
SlSetLength(SlCalcObjLength(object, sld));
|
SlSetLength(SlCalcObjLength(object, sld));
|
||||||
if (_sl.need_length == NL_CALCLENGTH) return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; sld->cmd != SL_END; sld++) {
|
for (; sld->cmd != SL_END; sld++) {
|
||||||
@@ -1838,25 +1889,17 @@ void SlGlobList(const SaveLoadGlobVarList *sldg)
|
|||||||
*/
|
*/
|
||||||
void SlAutolength(AutolengthProc *proc, void *arg)
|
void SlAutolength(AutolengthProc *proc, void *arg)
|
||||||
{
|
{
|
||||||
size_t offs;
|
|
||||||
|
|
||||||
assert(_sl.action == SLA_SAVE);
|
assert(_sl.action == SLA_SAVE);
|
||||||
|
assert(_sl.need_length == NL_WANTLENGTH);
|
||||||
|
|
||||||
/* Tell it to calculate the length */
|
_sl.need_length = NL_NONE;
|
||||||
_sl.need_length = NL_CALCLENGTH;
|
_sl.dumper->StartAutoLength();
|
||||||
_sl.obj_len = 0;
|
|
||||||
proc(arg);
|
proc(arg);
|
||||||
|
auto result = _sl.dumper->StopAutoLength();
|
||||||
/* Setup length */
|
/* Setup length */
|
||||||
_sl.need_length = NL_WANTLENGTH;
|
_sl.need_length = NL_WANTLENGTH;
|
||||||
SlSetLength(_sl.obj_len);
|
SlSetLength(result.second);
|
||||||
|
_sl.dumper->CopyBytes(result.first, result.second);
|
||||||
offs = _sl.dumper->GetSize() + _sl.obj_len;
|
|
||||||
|
|
||||||
/* And write the stuff */
|
|
||||||
proc(arg);
|
|
||||||
|
|
||||||
if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -694,52 +694,15 @@ size_t SlCalcObjLength(const void *object, const SaveLoad *sld);
|
|||||||
byte SlReadByte();
|
byte SlReadByte();
|
||||||
void SlWriteByte(byte b);
|
void SlWriteByte(byte b);
|
||||||
|
|
||||||
static inline int SlReadUint16()
|
int SlReadUint16();
|
||||||
{
|
uint32 SlReadUint32();
|
||||||
int x = SlReadByte() << 8;
|
uint64 SlReadUint64();
|
||||||
return x | SlReadByte();
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint32 SlReadUint32()
|
void SlWriteUint16(uint16 v);
|
||||||
{
|
void SlWriteUint32(uint32 v);
|
||||||
uint32 x = SlReadUint16() << 16;
|
void SlWriteUint64(uint64 v);
|
||||||
return x | SlReadUint16();
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint64 SlReadUint64()
|
void SlSkipBytes(size_t length);
|
||||||
{
|
|
||||||
uint32 x = SlReadUint32();
|
|
||||||
uint32 y = SlReadUint32();
|
|
||||||
return (uint64)x << 32 | y;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void SlWriteUint16(uint16 v)
|
|
||||||
{
|
|
||||||
SlWriteByte(GB(v, 8, 8));
|
|
||||||
SlWriteByte(GB(v, 0, 8));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void SlWriteUint32(uint32 v)
|
|
||||||
{
|
|
||||||
SlWriteUint16(GB(v, 16, 16));
|
|
||||||
SlWriteUint16(GB(v, 0, 16));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void SlWriteUint64(uint64 x)
|
|
||||||
{
|
|
||||||
SlWriteUint32((uint32)(x >> 32));
|
|
||||||
SlWriteUint32((uint32)x);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read in bytes from the file/data structure but don't do
|
|
||||||
* anything with them, discarding them in effect
|
|
||||||
* @param length The amount of bytes that is being treated this way
|
|
||||||
*/
|
|
||||||
static inline void SlSkipBytes(size_t length)
|
|
||||||
{
|
|
||||||
for (; length != 0; length--) SlReadByte();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t SlGetBytesRead();
|
size_t SlGetBytesRead();
|
||||||
size_t SlGetBytesWritten();
|
size_t SlGetBytesWritten();
|
||||||
|
266
src/saveload/saveload_buffer.h
Normal file
266
src/saveload/saveload_buffer.h
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
/* $Id$ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of OpenTTD.
|
||||||
|
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||||
|
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file saveload_buffer.h Functions/types related to buffers used for saving and loading games. */
|
||||||
|
|
||||||
|
#ifndef SAVELOAD_BUFFER_H
|
||||||
|
#define SAVELOAD_BUFFER_H
|
||||||
|
|
||||||
|
#include "../core/alloc_func.hpp"
|
||||||
|
#include "../core/endian_type.hpp"
|
||||||
|
#include "../core/endian_func.hpp"
|
||||||
|
#include "../core/math_func.hpp"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
struct LoadFilter;
|
||||||
|
struct SaveFilter;
|
||||||
|
|
||||||
|
/** Save in chunks of 128 KiB. */
|
||||||
|
static const size_t MEMORY_CHUNK_SIZE = 128 * 1024;
|
||||||
|
|
||||||
|
/** 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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static ReadBuffer *GetCurrent();
|
||||||
|
|
||||||
|
void SkipBytesSlowPath(size_t bytes);
|
||||||
|
void AcquireBytes();
|
||||||
|
|
||||||
|
inline void SkipBytes(size_t bytes)
|
||||||
|
{
|
||||||
|
byte *b = this->bufp + bytes;
|
||||||
|
if (likely(b <= this->bufe)) {
|
||||||
|
this->bufp = b;
|
||||||
|
} else {
|
||||||
|
SkipBytesSlowPath(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline byte RawReadByte()
|
||||||
|
{
|
||||||
|
return *this->bufp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline byte ReadByte()
|
||||||
|
{
|
||||||
|
if (unlikely(this->bufp == this->bufe)) {
|
||||||
|
this->AcquireBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
return RawReadByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void CheckBytes(size_t bytes)
|
||||||
|
{
|
||||||
|
while (unlikely(this->bufp + bytes > this->bufe)) this->AcquireBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int RawReadUint16()
|
||||||
|
{
|
||||||
|
#if OTTD_ALIGNMENT == 0
|
||||||
|
int x = FROM_BE16(*((const uint16*) this->bufp));
|
||||||
|
this->bufp += 2;
|
||||||
|
return x;
|
||||||
|
#else
|
||||||
|
int x = this->RawReadByte() << 8;
|
||||||
|
return x | this->RawReadByte();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32 RawReadUint32()
|
||||||
|
{
|
||||||
|
#if OTTD_ALIGNMENT == 0
|
||||||
|
uint32 x = FROM_BE32(*((const uint32*) this->bufp));
|
||||||
|
this->bufp += 4;
|
||||||
|
return x;
|
||||||
|
#else
|
||||||
|
uint32 x = this->RawReadUint16() << 16;
|
||||||
|
return x | this->RawReadUint16();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64 RawReadUint64()
|
||||||
|
{
|
||||||
|
#if OTTD_ALIGNMENT == 0
|
||||||
|
uint64 x = FROM_BE64(*((const uint64*) this->bufp));
|
||||||
|
this->bufp += 8;
|
||||||
|
return x;
|
||||||
|
#else
|
||||||
|
uint32 x = this->RawReadUint32();
|
||||||
|
uint32 y = this->RawReadUint32();
|
||||||
|
return (uint64)x << 32 | y;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void CopyBytes(byte *ptr, size_t length)
|
||||||
|
{
|
||||||
|
while (length) {
|
||||||
|
if (unlikely(this->bufp == this->bufe)) {
|
||||||
|
this->AcquireBytes();
|
||||||
|
}
|
||||||
|
size_t to_copy = min<size_t>(this->bufe - this->bufp, length);
|
||||||
|
memcpy(ptr, this->bufp, to_copy);
|
||||||
|
this->bufp += to_copy;
|
||||||
|
ptr += to_copy;
|
||||||
|
length -= to_copy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the size of the memory dump made so far.
|
||||||
|
* @return The size.
|
||||||
|
*/
|
||||||
|
inline size_t GetSize() const
|
||||||
|
{
|
||||||
|
return this->read - (this->bufe - this->bufp);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** Container for dumping the savegame (quickly) to memory. */
|
||||||
|
struct MemoryDumper {
|
||||||
|
struct BufferInfo {
|
||||||
|
byte *data;
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
|
BufferInfo(byte *d) : data(d) {}
|
||||||
|
~BufferInfo() { free(this->data); }
|
||||||
|
|
||||||
|
BufferInfo(const BufferInfo &) = delete;
|
||||||
|
BufferInfo(BufferInfo &&other) : data(other.data), size(other.size) { other.data = nullptr; };
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<BufferInfo> blocks; ///< Buffer with blocks of allocated memory.
|
||||||
|
byte *buf = nullptr; ///< Buffer we're going to write to.
|
||||||
|
byte *bufe = nullptr; ///< End of the buffer we write to.
|
||||||
|
size_t completed_block_bytes = 0; ///< Total byte count of completed blocks.
|
||||||
|
|
||||||
|
byte *autolen_buf = nullptr;
|
||||||
|
byte *autolen_buf_end = nullptr;
|
||||||
|
byte *saved_buf = nullptr;
|
||||||
|
byte *saved_bufe = nullptr;
|
||||||
|
|
||||||
|
MemoryDumper()
|
||||||
|
{
|
||||||
|
const size_t size = 8192;
|
||||||
|
this->autolen_buf = CallocT<byte>(size);
|
||||||
|
this->autolen_buf_end = this->autolen_buf + size;
|
||||||
|
}
|
||||||
|
|
||||||
|
~MemoryDumper()
|
||||||
|
{
|
||||||
|
free(this->autolen_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MemoryDumper *GetCurrent();
|
||||||
|
|
||||||
|
void FinaliseBlock();
|
||||||
|
void AllocateBuffer();
|
||||||
|
|
||||||
|
inline void CheckBytes(size_t bytes)
|
||||||
|
{
|
||||||
|
if (unlikely(this->buf + bytes > this->bufe)) this->AllocateBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a single byte into the dumper.
|
||||||
|
* @param b The byte to write.
|
||||||
|
*/
|
||||||
|
inline void WriteByte(byte b)
|
||||||
|
{
|
||||||
|
/* Are we at the end of this chunk? */
|
||||||
|
if (unlikely(this->buf == this->bufe)) {
|
||||||
|
this->AllocateBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
*this->buf++ = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void CopyBytes(byte *ptr, size_t length)
|
||||||
|
{
|
||||||
|
while (length) {
|
||||||
|
if (unlikely(this->buf == this->bufe)) {
|
||||||
|
this->AllocateBuffer();
|
||||||
|
}
|
||||||
|
size_t to_copy = min<size_t>(this->bufe - this->buf, length);
|
||||||
|
memcpy(this->buf, ptr, to_copy);
|
||||||
|
this->buf += to_copy;
|
||||||
|
ptr += to_copy;
|
||||||
|
length -= to_copy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void RawWriteByte(byte b)
|
||||||
|
{
|
||||||
|
*this->buf++ = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void RawWriteUint16(uint16 v)
|
||||||
|
{
|
||||||
|
#if OTTD_ALIGNMENT == 0
|
||||||
|
*((uint16 *) this->buf) = TO_BE16(v);
|
||||||
|
#else
|
||||||
|
this->buf[0] = GB(v, 8, 8));
|
||||||
|
this->buf[1] = GB(v, 0, 8));
|
||||||
|
#endif
|
||||||
|
this->buf += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void RawWriteUint32(uint32 v)
|
||||||
|
{
|
||||||
|
#if OTTD_ALIGNMENT == 0
|
||||||
|
*((uint32 *) this->buf) = TO_BE32(v);
|
||||||
|
#else
|
||||||
|
this->buf[0] = GB(v, 24, 8));
|
||||||
|
this->buf[1] = GB(v, 16, 8));
|
||||||
|
this->buf[2] = GB(v, 8, 8));
|
||||||
|
this->buf[3] = GB(v, 0, 8));
|
||||||
|
#endif
|
||||||
|
this->buf += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void RawWriteUint64(uint64 v)
|
||||||
|
{
|
||||||
|
#if OTTD_ALIGNMENT == 0
|
||||||
|
*((uint64 *) this->buf) = TO_BE64(v);
|
||||||
|
#else
|
||||||
|
this->buf[0] = GB(v, 56, 8));
|
||||||
|
this->buf[1] = GB(v, 48, 8));
|
||||||
|
this->buf[2] = GB(v, 40, 8));
|
||||||
|
this->buf[3] = GB(v, 32, 8));
|
||||||
|
this->buf[4] = GB(v, 24, 8));
|
||||||
|
this->buf[5] = GB(v, 16, 8));
|
||||||
|
this->buf[6] = GB(v, 8, 8));
|
||||||
|
this->buf[7] = GB(v, 0, 8));
|
||||||
|
#endif
|
||||||
|
this->buf += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Flush(SaveFilter *writer);
|
||||||
|
size_t GetSize() const;
|
||||||
|
void StartAutoLength();
|
||||||
|
std::pair<byte *, size_t> StopAutoLength();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Reference in New Issue
Block a user