aboutsummaryrefslogtreecommitdiff
path: root/engines/cine/unpack.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/cine/unpack.cpp')
-rw-r--r--engines/cine/unpack.cpp137
1 files changed, 72 insertions, 65 deletions
diff --git a/engines/cine/unpack.cpp b/engines/cine/unpack.cpp
index 4409af4b07..364331e439 100644
--- a/engines/cine/unpack.cpp
+++ b/engines/cine/unpack.cpp
@@ -30,94 +30,101 @@
namespace Cine {
-struct UnpackCtx {
- int size, datasize;
- uint32 crc;
- uint32 chk;
- byte *dst;
- const byte *src;
-};
+uint32 CineUnpacker::readSource() {
+ uint32 value = READ_BE_UINT32(_src);
+ _src -= 4;
+ return value;
+}
-static int rcr(UnpackCtx *uc, int CF) {
- int rCF = (uc->chk & 1);
- uc->chk >>= 1;
- if (CF) {
- uc->chk |= 0x80000000;
+int CineUnpacker::rcr(int inputCarry) {
+ int outputCarry = (_chunk32b & 1);
+ _chunk32b >>= 1;
+ if (inputCarry) {
+ _chunk32b |= 0x80000000;
}
- return rCF;
+ return outputCarry;
}
-static int nextChunk(UnpackCtx *uc) {
- int CF = rcr(uc, 0);
- if (uc->chk == 0) {
- uc->chk = READ_BE_UINT32(uc->src); uc->src -= 4;
- uc->crc ^= uc->chk;
- CF = rcr(uc, 1);
+int CineUnpacker::nextBit() {
+ int carry = rcr(0);
+ // Normally if the chunk becomes zero then the carry is one as
+ // the end of chunk marker is always the last to be shifted out.
+ if (_chunk32b == 0) {
+ _chunk32b = readSource();
+ _crc ^= _chunk32b;
+ carry = rcr(1); // Put the end of chunk marker in the most significant bit
}
- return CF;
+ return carry;
}
-static uint16 getCode(UnpackCtx *uc, byte numChunks) {
+uint16 CineUnpacker::getBits(byte numBits) {
uint16 c = 0;
- while (numChunks--) {
+ while (numBits--) {
c <<= 1;
- if (nextChunk(uc)) {
- c |= 1;
- }
+ c |= nextBit();
}
return c;
}
-static void unpackHelper1(UnpackCtx *uc, byte numChunks, byte addCount) {
- uint16 count = getCode(uc, numChunks) + addCount + 1;
- uc->datasize -= count;
- while (count--) {
- *uc->dst = (byte)getCode(uc, 8);
- --uc->dst;
+void CineUnpacker::unpackRawBytes(uint16 numBytes) {
+ _datasize -= numBytes;
+ while (numBytes--) {
+ *_dst = (byte)getBits(8);
+ --_dst;
}
}
-static void unpackHelper2(UnpackCtx *uc, byte numChunks) {
- uint16 i = getCode(uc, numChunks);
- uint16 count = uc->size + 1;
- uc->datasize -= count;
- while (count--) {
- *uc->dst = *(uc->dst + i);
- --uc->dst;
+void CineUnpacker::copyRelocatedBytes(uint16 offset, uint16 numBytes) {
+ _datasize -= numBytes;
+ while (numBytes--) {
+ *_dst = *(_dst + offset);
+ --_dst;
}
}
-bool delphineUnpack(byte *dst, const byte *src, int len) {
- UnpackCtx uc;
- uc.src = src + len - 4;
- uc.datasize = READ_BE_UINT32(uc.src); uc.src -= 4;
- uc.dst = dst + uc.datasize - 1;
- uc.size = 0;
- uc.crc = READ_BE_UINT32(uc.src); uc.src -= 4;
- uc.chk = READ_BE_UINT32(uc.src); uc.src -= 4;
- uc.crc ^= uc.chk;
+bool CineUnpacker::unpack(byte *dst, const byte *src, int srcLen) {
+ _src = src + srcLen - 4;
+ _datasize = readSource(); // Unpacked length in bytes
+ _dst = dst + _datasize - 1;
+ _crc = readSource();
+ _chunk32b = readSource();
+ _crc ^= _chunk32b;
do {
- if (!nextChunk(&uc)) {
- uc.size = 1;
- if (!nextChunk(&uc)) {
- unpackHelper1(&uc, 3, 0);
- } else {
- unpackHelper2(&uc, 8);
+ /*
+ Bits => Action:
+ 0 0 => unpackRawBytes(3 bits + 1) i.e. unpackRawBytes(1..9)
+ 1 1 1 => unpackRawBytes(8 bits + 9) i.e. unpackRawBytes(9..264)
+ 0 1 => copyRelocatedBytes(8 bits, 2) i.e. copyRelocatedBytes(0..255, 2)
+ 1 0 0 => copyRelocatedBytes(9 bits, 3) i.e. copyRelocatedBytes(0..511, 3)
+ 1 0 1 => copyRelocatedBytes(10 bits, 4) i.e. copyRelocatedBytes(0..1023, 4)
+ 1 1 0 => copyRelocatedBytes(12 bits, 8 bits + 1) i.e. copyRelocatedBytes(0..4095, 1..256)
+ */
+ if (!nextBit()) { // 0...
+ if (!nextBit()) { // 0 0
+ uint16 numBytes = getBits(3) + 1;
+ unpackRawBytes(numBytes);
+ } else { // 0 1
+ uint16 numBytes = 2;
+ uint16 offset = getBits(8);
+ copyRelocatedBytes(offset, numBytes);
}
- } else {
- uint16 c = getCode(&uc, 2);
- if (c == 3) {
- unpackHelper1(&uc, 8, 8);
- } else if (c < 2) {
- uc.size = c + 2;
- unpackHelper2(&uc, c + 9);
- } else {
- uc.size = getCode(&uc, 8);
- unpackHelper2(&uc, 12);
+ } else { // 1...
+ uint16 c = getBits(2);
+ if (c == 3) { // 1 1 1
+ uint16 numBytes = getBits(8) + 9;
+ unpackRawBytes(numBytes);
+ } else if (c < 2) { // 1 0 x
+ uint16 numBytes = c + 3;
+ uint16 offset = getBits(c + 9);
+ copyRelocatedBytes(offset, numBytes);
+ } else { // 1 1 0
+ uint16 numBytes = getBits(8) + 1;
+ uint16 offset = getBits(12);
+ copyRelocatedBytes(offset, numBytes);
}
}
- } while (uc.datasize > 0 && uc.src >= src - 4);
- return uc.crc == 0;
+ } while (_datasize > 0 && _src >= src - 4);
+ return _crc == 0;
}
} // End of namespace Cine