summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--saveload.c78
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();
}
}