diff options
author | Littleboy | 2012-07-31 00:58:37 -0400 |
---|---|---|
committer | Littleboy | 2012-07-31 01:19:05 -0400 |
commit | acd4cf82e23493e357261eea564a5eaafb6e2647 (patch) | |
tree | c0d548ab0b472a52fbbdb7ee77a3f395bd2d561f | |
parent | 4728505db288b8aa55453ada19fadde76d61ddb8 (diff) | |
download | scummvm-rg350-acd4cf82e23493e357261eea564a5eaafb6e2647.tar.gz scummvm-rg350-acd4cf82e23493e357261eea564a5eaafb6e2647.tar.bz2 scummvm-rg350-acd4cf82e23493e357261eea564a5eaafb6e2647.zip |
LASTEXPRESS: Implement savegame write compression
-rw-r--r-- | engines/lastexpress/game/savegame.cpp | 174 | ||||
-rw-r--r-- | engines/lastexpress/game/savegame.h | 30 |
2 files changed, 191 insertions, 13 deletions
diff --git a/engines/lastexpress/game/savegame.cpp b/engines/lastexpress/game/savegame.cpp index 8eda463f81..54ba45e25e 100644 --- a/engines/lastexpress/game/savegame.cpp +++ b/engines/lastexpress/game/savegame.cpp @@ -73,6 +73,10 @@ uint32 SavegameStream::read(void *dataPtr, uint32 dataSize) { return readCompressed(dataPtr, dataSize); #endif + return readUncompressed(dataPtr, dataSize); +} + +uint32 SavegameStream::readUncompressed(void *dataPtr, uint32 dataSize) { if ((int32)dataSize > size() - pos()) { dataSize = size() - pos(); _eos = true; @@ -84,18 +88,182 @@ uint32 SavegameStream::read(void *dataPtr, uint32 dataSize) { return dataSize; } -void SavegameStream::process() { +void SavegameStream::writeBuffer(uint8 value, bool onlyValue) { + if (_bufferOffset == -1) + _bufferOffset = 0; + + if (_bufferOffset == 256) { + _bufferOffset = 0; + Common::MemoryWriteStreamDynamic::write(_buffer, 256); + } + + if (onlyValue || value < 0xFB) + _buffer[_bufferOffset] = value; + else + _buffer[_bufferOffset] = 0xFE; + + _offset++; + _bufferOffset++; + + if (!onlyValue && value >= 0xFB) + { + if (_bufferOffset == 256) { + _bufferOffset = 0; + Common::MemoryWriteStreamDynamic::write(_buffer, 256); + } + + _buffer[_bufferOffset] = value; + + _bufferOffset++; + _offset++; + } +} + +uint32 SavegameStream::process() { _enableCompression = !_enableCompression; - // TODO Flush compression buffer +#if DISABLE_COMPRESSION + return 0; +#else + switch (_status) { + default: + break; + + case kStatusReading: + _status = kStatusReady; + if (_bufferOffset != -1 && _bufferOffset != 256) { + seek(_bufferOffset - 256, SEEK_CUR); + _bufferOffset = -1; + } + break; + + case kStatusWriting: + switch (_valueCount) { + default: + break; + + case 1: + writeBuffer(_previousValue, false); + break; + + case 2: + if (_previousValue) { + writeBuffer(0xFF, true); + writeBuffer(_repeatCount, true); + writeBuffer(_previousValue, true); + break; + } + + if (_repeatCount == 3) { + writeBuffer(0xFB, true); + break; + } + + if (_repeatCount == -1) { + writeBuffer(0xFC, true); + break; + } + + writeBuffer(0xFD, true); + writeBuffer(_repeatCount, true); + break; + } + + if (_bufferOffset != -1 && _bufferOffset != 0) { + Common::MemoryWriteStreamDynamic::write(_buffer, _bufferOffset); + _bufferOffset = -1; + } + break; + } + + _status = kStatusReady; + _valueCount = 0; + uint32 offset = _offset; + _offset = 0; + return offset; +#endif } uint32 SavegameStream::writeCompressed(const void *dataPtr, uint32 dataSize) { - error("[SavegameStream::writeCompressed] Compression not implemented!"); + if (_status == kStatusReading) + error("[SavegameStream::writeCompressed] Error: Compression buffer is in read mode."); + + _status = kStatusWriting; + byte *data = (byte *)dataPtr; + + while (dataSize) { + switch (_valueCount) { + default: + error("[SavegameStream::writeCompressed] Invalid value count (%d)", _valueCount); + + case 0: + _previousValue = *data++; + _valueCount = 1; + break; + + case 1: + if (*data != _previousValue) { + writeBuffer(_previousValue, false); + _previousValue = *data; + } else { + _valueCount = 2; + _repeatCount = 2; + } + + ++data; + break; + + case 2: + if (*data != _previousValue || _repeatCount >= 255) { + if (_previousValue) { + writeBuffer(0xFF, true); + writeBuffer(_repeatCount, true); + writeBuffer(_previousValue, true); + + _previousValue = *data++; + _valueCount = 1; + break; + } + + if (_repeatCount == 3) { + writeBuffer(0xFB, true); + + _previousValue = *data++; + _valueCount = 1; + break; + } + + if (_repeatCount == -1) { + writeBuffer(0xFC, true); + + _previousValue = *data++; + _valueCount = 1; + break; + } + + writeBuffer(0xFD, true); + writeBuffer(_repeatCount, true); + + _previousValue = *data++; + _valueCount = 1; + } + + ++data; + ++_repeatCount; + break; + } + + --dataSize; + } + + return _offset; } uint32 SavegameStream::readCompressed(void *dataPtr, uint32 dataSize) { + if (_status == kStatusWriting) + error("[SavegameStream::writeCompressed] Error: Compression buffer is in write mode."); + error("[SavegameStream::readCompressed] Compression not implemented!"); } diff --git a/engines/lastexpress/game/savegame.h b/engines/lastexpress/game/savegame.h index dc16a16728..8866fd330d 100644 --- a/engines/lastexpress/game/savegame.h +++ b/engines/lastexpress/game/savegame.h @@ -95,9 +95,9 @@ public: _bufferOffset = -1; _valueCount = 0; _previousValue = 0; - _field_15F = 0; + _repeatCount = 0; _offset = 0; - _status = 0; + _status = kStatusReady; memset(_buffer, 0, 256); } @@ -109,24 +109,34 @@ public: uint32 read(void *dataPtr, uint32 dataSize); uint32 write(const void *dataPtr, uint32 dataSize); - void process(); + uint32 process(); private: + enum CompressedStreamStatus { + kStatusReady, + kStatusReading, + kStatusWriting + }; + + uint32 readUncompressed(void *dataPtr, uint32 dataSize); + // Compressed data uint32 writeCompressed(const void *dataPtr, uint32 dataSize); uint32 readCompressed(void *dataPtr, uint32 dataSize); + void writeBuffer(uint8 value, bool onlyValue); + private: bool _eos; // Compression handling - bool _enableCompression; - int _bufferOffset; - int _valueCount; - byte _previousValue; - byte _field_15F; - int _offset; - int _status; + bool _enableCompression; + int16 _bufferOffset; + byte _valueCount; + byte _previousValue; + int16 _repeatCount; + uint32 _offset; + CompressedStreamStatus _status; byte _buffer[256]; }; |