diff options
-rw-r--r-- | saveload.c | 78 |
1 files changed, 53 insertions, 25 deletions
diff --git a/saveload.c b/saveload.c index e2c130366..b120f0535 100644 --- a/saveload.c +++ b/saveload.c @@ -152,8 +152,18 @@ static uint SlReadSimpleGamma(void) { uint i = SlReadByte(); if (HASBIT(i, 7)) { - i = (i << 8) + SlReadByte(); - CLRBIT(i, 15); + i &= ~0x80; + if (HASBIT(i, 6)) { + i &= ~0x40; + if (HASBIT(i, 5)) { + i &= ~0x20; + if (HASBIT(i, 4)) + SlError("Unsupported gamma"); + i = (i << 8) | SlReadByte(); + } + i = (i << 8) | SlReadByte(); + } + i = (i << 8) | SlReadByte(); } return i; } @@ -162,25 +172,37 @@ static uint SlReadSimpleGamma(void) * Write the header descriptor of an object or an array. * If the element is bigger than 127, use 2 bytes for saving * and use the highest byte of the first written one as a notice - * that the length consists of 2 bytes. The length is fixed to a - * maximum of 16384 since any higher value will have bit 15 set - * and the notice, would obfuscate the real value + * that the length consists of 2 bytes, etc.. like this: + * 0xxxxxxx + * 10xxxxxx xxxxxxxx + * 110xxxxx xxxxxxxx xxxxxxxx + * 1110xxxx xxxxxxxx xxxxxxxx xxxxxxxx * @param i Index being written - * @todo the maximum of 16384 can easily be reached with vehicles, so raise this artificial limit */ + static void SlWriteSimpleGamma(uint i) { - assert(i < (1 << 14)); - if (i >= (1 << 7)) { - SlWriteByte((byte)((1 << 7) | (i >> 8))); - SlWriteByte((byte)i); - } else - SlWriteByte(i); + if (i >= (1 << 14)) { + if (i >= (1 << 21)) { + assert(i < (1 << 28)); + SlWriteByte((byte)0xE0 | (i>>24)); + SlWriteByte((byte)(i>>16)); + } else { + SlWriteByte((byte)0xC0 | (i>>16)); + } + SlWriteByte((byte)(i>>8)); + } else { + SlWriteByte((byte)(0x80 | (i>>8))); + } + } + SlWriteByte(i); } -/** Return if the length will use up 1 or two bytes in a savegame */ -static inline uint SlGetGammaLength(uint i) {return (i >= (1 << 7)) ? 2 : 1;} +/** Return how many bytes used to encode a gamma value */ +static inline uint SlGetGammaLength(uint i) { + return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21)); +} static inline int SlReadSparseIndex(void) {return SlReadSimpleGamma();} static inline void SlWriteSparseIndex(uint index) {SlWriteSimpleGamma(index);} @@ -241,8 +263,11 @@ void SlSetLength(size_t length) _sl.need_length = NL_NONE; switch (_sl.block_mode) { case CH_RIFF: - // Really simple to write a RIFF length :) - SlWriteUint32(length); + // Ugly encoding of >16M RIFF chunks + // The lower 24 bits are normal + // The uppermost 4 bits are bits 24:27 + assert(length < (1<<28)); + SlWriteUint32((length & 0xFFFFFF) | ((length >> 24) << 28)); break; case CH_ARRAY: assert(_sl.last_array_index <= _sl.array_index); @@ -614,16 +639,19 @@ static void SlLoadChunk(const ChunkHandler *ch) case CH_SPARSE_ARRAY: ch->load_proc(); break; - case CH_RIFF: - // Read length - len = SlReadByte() << 16; - len += SlReadUint16(); - _sl.obj_len = len; - endoffs = SlGetOffs() + len; - ch->load_proc(); - assert(SlGetOffs() == endoffs); + default: + if ((m & 0xF) == CH_RIFF) { + // Read length + len = (SlReadByte() << 16) | ((m >> 4) << 24); + len += SlReadUint16(); + _sl.obj_len = len; + endoffs = SlGetOffs() + len; + ch->load_proc(); + assert(SlGetOffs() == endoffs); + } else { + SlError("Invalid chunk type"); + } break; - default: NOT_REACHED(); } } |