save_ext: Initial support for save/load of RIFF chunk sizes > 28 bits.
Add a chunk extension header with a flag for increased RIFF size.
This commit is contained in:
@@ -888,9 +888,20 @@ void SlSetLength(size_t length)
|
|||||||
case CH_RIFF:
|
case CH_RIFF:
|
||||||
/* Ugly encoding of >16M RIFF chunks
|
/* Ugly encoding of >16M RIFF chunks
|
||||||
* The lower 24 bits are normal
|
* The lower 24 bits are normal
|
||||||
* The uppermost 4 bits are bits 24:27 */
|
* The uppermost 4 bits are bits 24:27
|
||||||
assert(length < (1 << 28));
|
*
|
||||||
|
* If we have more than 28 bits, use an extra uint32 and
|
||||||
|
* signal this using the extended chunk header */
|
||||||
|
assert(length < (1LL << 32));
|
||||||
|
if (length >= (1 << 28)) {
|
||||||
|
/* write out extended chunk header */
|
||||||
|
SlWriteByte(CH_EXT_HDR);
|
||||||
|
SlWriteUint32(static_cast<uint32>(SLCEHF_BIG_RIFF));
|
||||||
|
}
|
||||||
SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
|
SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28)));
|
||||||
|
if (length >= (1 << 28)) {
|
||||||
|
SlWriteUint32(length >> 28);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CH_ARRAY:
|
case CH_ARRAY:
|
||||||
assert(_sl.last_array_index <= _sl.array_index);
|
assert(_sl.last_array_index <= _sl.array_index);
|
||||||
@@ -1661,6 +1672,16 @@ void SlAutolength(AutolengthProc *proc, void *arg)
|
|||||||
if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
|
if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Notes on extended chunk header:
|
||||||
|
*
|
||||||
|
* If the chunk type is CH_EXT_HDR (15), then a u32 flags field follows.
|
||||||
|
* This flag field may define additional fields which follow the flags field in future.
|
||||||
|
* The standard chunk header follows, though it my be modified by the flags field.
|
||||||
|
* At present SLCEHF_BIG_RIFF increases the RIFF size limit to a theoretical 60 bits,
|
||||||
|
* by adding a further u32 field for the high bits after the existing RIFF size field.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load a chunk of data (eg vehicles, stations, etc.)
|
* Load a chunk of data (eg vehicles, stations, etc.)
|
||||||
* @param ch The chunkhandler that will be used for the operation
|
* @param ch The chunkhandler that will be used for the operation
|
||||||
@@ -1674,6 +1695,15 @@ static void SlLoadChunk(const ChunkHandler *ch)
|
|||||||
_sl.block_mode = m;
|
_sl.block_mode = m;
|
||||||
_sl.obj_len = 0;
|
_sl.obj_len = 0;
|
||||||
|
|
||||||
|
SaveLoadChunkExtHeaderFlags ext_flags = static_cast<SaveLoadChunkExtHeaderFlags>(0);
|
||||||
|
if ((m & 0xF) == CH_EXT_HDR) {
|
||||||
|
ext_flags = static_cast<SaveLoadChunkExtHeaderFlags>(SlReadUint32());
|
||||||
|
|
||||||
|
/* read in real header */
|
||||||
|
m = SlReadByte();
|
||||||
|
_sl.block_mode = m;
|
||||||
|
}
|
||||||
|
|
||||||
switch (m) {
|
switch (m) {
|
||||||
case CH_ARRAY:
|
case CH_ARRAY:
|
||||||
_sl.array_index = 0;
|
_sl.array_index = 0;
|
||||||
@@ -1689,6 +1719,10 @@ static void SlLoadChunk(const ChunkHandler *ch)
|
|||||||
/* Read length */
|
/* Read length */
|
||||||
len = (SlReadByte() << 16) | ((m >> 4) << 24);
|
len = (SlReadByte() << 16) | ((m >> 4) << 24);
|
||||||
len += SlReadUint16();
|
len += SlReadUint16();
|
||||||
|
if (ext_flags & SLCEHF_BIG_RIFF) {
|
||||||
|
len |= SlReadUint32() << 28;
|
||||||
|
}
|
||||||
|
|
||||||
_sl.obj_len = len;
|
_sl.obj_len = len;
|
||||||
endoffs = _sl.reader->GetSize() + len;
|
endoffs = _sl.reader->GetSize() + len;
|
||||||
ch->load_proc();
|
ch->load_proc();
|
||||||
@@ -1714,9 +1748,21 @@ static void SlLoadCheckChunk(const ChunkHandler *ch)
|
|||||||
_sl.block_mode = m;
|
_sl.block_mode = m;
|
||||||
_sl.obj_len = 0;
|
_sl.obj_len = 0;
|
||||||
|
|
||||||
|
SaveLoadChunkExtHeaderFlags ext_flags = static_cast<SaveLoadChunkExtHeaderFlags>(0);
|
||||||
|
if ((m & 0xF) == CH_EXT_HDR) {
|
||||||
|
ext_flags = static_cast<SaveLoadChunkExtHeaderFlags>(SlReadUint32());
|
||||||
|
|
||||||
|
/* read in real header */
|
||||||
|
m = SlReadByte();
|
||||||
|
_sl.block_mode = m;
|
||||||
|
}
|
||||||
|
|
||||||
switch (m) {
|
switch (m) {
|
||||||
case CH_ARRAY:
|
case CH_ARRAY:
|
||||||
_sl.array_index = 0;
|
_sl.array_index = 0;
|
||||||
|
if (ext_flags) {
|
||||||
|
SlErrorCorruptFmt("CH_ARRAY does not take chunk header extension flags: 0x%X", ext_flags);
|
||||||
|
}
|
||||||
if (ch && ch->load_check_proc) {
|
if (ch && ch->load_check_proc) {
|
||||||
ch->load_check_proc();
|
ch->load_check_proc();
|
||||||
} else {
|
} else {
|
||||||
@@ -1724,6 +1770,9 @@ static void SlLoadCheckChunk(const ChunkHandler *ch)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CH_SPARSE_ARRAY:
|
case CH_SPARSE_ARRAY:
|
||||||
|
if (ext_flags) {
|
||||||
|
SlErrorCorruptFmt("CH_SPARSE_ARRAY does not take chunk header extension flags: 0x%X", ext_flags);
|
||||||
|
}
|
||||||
if (ch && ch->load_check_proc) {
|
if (ch && ch->load_check_proc) {
|
||||||
ch->load_check_proc();
|
ch->load_check_proc();
|
||||||
} else {
|
} else {
|
||||||
@@ -1732,9 +1781,19 @@ static void SlLoadCheckChunk(const ChunkHandler *ch)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if ((m & 0xF) == CH_RIFF) {
|
if ((m & 0xF) == CH_RIFF) {
|
||||||
|
if (ext_flags != (ext_flags & SLCEHF_BIG_RIFF)) {
|
||||||
|
SlErrorCorruptFmt("Unknown chunk header extension flags for CH_RIFF: 0x%X", ext_flags);
|
||||||
|
}
|
||||||
/* Read length */
|
/* Read length */
|
||||||
len = (SlReadByte() << 16) | ((m >> 4) << 24);
|
len = (SlReadByte() << 16) | ((m >> 4) << 24);
|
||||||
len += SlReadUint16();
|
len += SlReadUint16();
|
||||||
|
if (ext_flags & SLCEHF_BIG_RIFF) {
|
||||||
|
uint64 full_len = len | (static_cast<uint64>(SlReadUint32()) << 28);
|
||||||
|
if (full_len >= (1LL << 32)) {
|
||||||
|
SlErrorCorrupt("Chunk size too large: " OTTD_PRINTFHEX64, full_len);
|
||||||
|
}
|
||||||
|
len = static_cast<size_t>(full_len);
|
||||||
|
}
|
||||||
_sl.obj_len = len;
|
_sl.obj_len = len;
|
||||||
endoffs = _sl.reader->GetSize() + len;
|
endoffs = _sl.reader->GetSize() + len;
|
||||||
if (ch && ch->load_check_proc) {
|
if (ch && ch->load_check_proc) {
|
||||||
|
@@ -99,10 +99,17 @@ enum ChunkType {
|
|||||||
CH_ARRAY = 1,
|
CH_ARRAY = 1,
|
||||||
CH_SPARSE_ARRAY = 2,
|
CH_SPARSE_ARRAY = 2,
|
||||||
CH_TYPE_MASK = 3,
|
CH_TYPE_MASK = 3,
|
||||||
|
CH_EXT_HDR = 15, ///< Extended chunk header
|
||||||
CH_LAST = 8, ///< Last chunk in this array.
|
CH_LAST = 8, ///< Last chunk in this array.
|
||||||
CH_AUTO_LENGTH = 16,
|
CH_AUTO_LENGTH = 16,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Flags for chunk extended headers */
|
||||||
|
enum SaveLoadChunkExtHeaderFlags {
|
||||||
|
SLCEHF_BIG_RIFF = 1 << 0, ///< This block uses a 60-bit RIFF chunk size
|
||||||
|
};
|
||||||
|
DECLARE_ENUM_AS_BIT_SET(SaveLoadChunkExtHeaderFlags)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* VarTypes is the general bitmasked magic type that tells us
|
* VarTypes is the general bitmasked magic type that tells us
|
||||||
* certain characteristics about the variable it refers to. For example
|
* certain characteristics about the variable it refers to. For example
|
||||||
|
Reference in New Issue
Block a user