[Scummvm-git-logs] scummvm master -> ea2165908490a99f41115badeac211c29a61209c
somaen
einarjohants at gmail.com
Sat Feb 6 00:05:07 UTC 2021
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
ea21659084 TINSEL: Implement LZSS decompression for Noir
Commit: ea2165908490a99f41115badeac211c29a61209c
https://github.com/scummvm/scummvm/commit/ea2165908490a99f41115badeac211c29a61209c
Author: Einar Johan Trøan SømaÌen (somaen at scummvm.org)
Date: 2021-02-06T01:04:54+01:00
Commit Message:
TINSEL: Implement LZSS decompression for Noir
Changed paths:
engines/tinsel/noir/lzss.cpp
engines/tinsel/noir/lzss.h
engines/tinsel/tinsel.cpp
diff --git a/engines/tinsel/noir/lzss.cpp b/engines/tinsel/noir/lzss.cpp
index adb37cd4b2..ca4488c9a0 100644
--- a/engines/tinsel/noir/lzss.cpp
+++ b/engines/tinsel/noir/lzss.cpp
@@ -26,10 +26,101 @@
namespace Tinsel {
-int decompressLZSS(Common::ReadStream &input, byte *output) {
- error("TODO: Implement decompression");
- return 0;
+static byte HIGH_BITS(byte byteValue, int numBits) {
+ unsigned int mask = ((1 << numBits) - 1) << (8 - numBits);
+ return (byteValue & mask) >> (8 - numBits);
}
+static byte LOW_BITS(byte byteValue, int numBits) {
+ unsigned int mask = ((1 << numBits) - 1);
+ return byteValue & mask;
}
+int decompressLZSS(Common::SeekableReadStream &input, byte *output) {
+ static const int kDictionarySize = 4096;
+ byte dictionary[kDictionarySize] = {};
+ int dictionaryOffset = 1;
+ int outputOffset = 0;
+
+ byte *data = new byte[input.size()];
+ input.read(data, input.size());
+ unsigned int offset = 0;
+
+ int bitShift = 0;
+ int bytesWritten = 0;
+
+ while (true) {
+ byte value = data[offset];
+ byte bitMask = 0x80 >> bitShift++;
+ // First bit:
+ // 0 -> Copy data from dictionary
+ // 1 -> Copy raw byte from input
+ bool useRawByte = value & bitMask;
+ if (bitShift == 8) {
+ bitShift = 0;
+ offset++;
+ }
+ if (!useRawByte) {
+ unsigned int bitsFromFirst = 8 - bitShift;
+ unsigned int bitsFromLast = 16 - 8 - bitsFromFirst;
+
+ // The dictionary lookup is 16 bit:
+ // 12 bits for the offset
+ // 4 bits for the run-length
+
+ // Combined with the first bit this makes for 17 bits,
+ // So we will be reading from three bytes, except when
+ // the first bit was read from the end of a byte, then
+ // bitShift will be 0, and bitsFromLast will be 8.
+
+ // We make the assumption that we can dereference the third byte
+ // even if we aren't using it. We will check "offset" after decompression
+ // to verify this assumption.
+ unsigned int byte1 = LOW_BITS(data[offset], bitsFromFirst);
+ unsigned int byte2 = data[offset + 1];
+ unsigned int byte3 = HIGH_BITS(data[offset + 2], bitsFromLast);
+
+ unsigned int lookup = (byte1 << (8 + bitsFromLast)) | (byte2 << bitsFromLast) | byte3;
+
+ int lookupOffset = (lookup >> 4) & 0xFFF;
+ if (lookupOffset == 0) {
+ break;
+ }
+ int lookupRunLength = (lookup & 0xF) + 2;
+ for (int j = 0; j < lookupRunLength; j++) {
+ output[outputOffset++] = dictionary[(lookupOffset + j) % kDictionarySize];
+ dictionary[dictionaryOffset++] = dictionary[(lookupOffset + j) % kDictionarySize];
+ dictionaryOffset %= kDictionarySize;
+ }
+
+ offset += 2;
+ bytesWritten += lookupRunLength;
+ } else {
+ // Raw byte, but since we spent a bit first,
+ // we must reassemble it from potentially two bytes.
+ unsigned int bitsFromFirst = 8 - bitShift;
+ unsigned int bitsFromLast = 8 - bitsFromFirst;
+
+ byte byteValue = LOW_BITS(data[offset], bitsFromFirst) << bitsFromLast;
+ byteValue |= HIGH_BITS(data[offset + 1], bitsFromLast);
+
+ offset++;
+
+ output[outputOffset++] = byteValue;
+ dictionary[dictionaryOffset++] = byteValue;
+ dictionaryOffset %= kDictionarySize;
+
+ bytesWritten++;
+ }
+
+ }
+ delete[] data;
+
+ if (offset > input.size()) {
+ error("Read too far during decompression");
+ }
+
+ return bytesWritten;
+}
+
+}
diff --git a/engines/tinsel/noir/lzss.h b/engines/tinsel/noir/lzss.h
index d311601cd6..e7735f3cfe 100644
--- a/engines/tinsel/noir/lzss.h
+++ b/engines/tinsel/noir/lzss.h
@@ -28,7 +28,7 @@
namespace Tinsel {
-int decompressLZSS(Common::ReadStream &input, byte *output);
+int decompressLZSS(Common::SeekableReadStream &input, byte *output);
}
diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp
index ed4a231a38..53d2eb7110 100644
--- a/engines/tinsel/tinsel.cpp
+++ b/engines/tinsel/tinsel.cpp
@@ -725,6 +725,10 @@ void LoadBasicChunks() {
byte *cptr;
int numObjects;
+ if (TinselV3) {
+ error("TODO: Implement LoadBasicChunks for Noir");
+ }
+
// Allocate RAM for savescene data
InitializeSaveScenes();
More information about the Scummvm-git-logs
mailing list