diff options
author | Martin Kiewitz | 2015-07-04 01:50:07 +0200 |
---|---|---|
committer | Martin Kiewitz | 2015-07-04 01:50:07 +0200 |
commit | 7753f2d51610766fc273e810af1accbbcf013624 (patch) | |
tree | 4944aafd69d4bc19a5c4e1bdf6d5b12f8cae005c | |
parent | 2bd07431257927968a7ca89f72982d0090812e2c (diff) | |
download | scummvm-rg350-7753f2d51610766fc273e810af1accbbcf013624.tar.gz scummvm-rg350-7753f2d51610766fc273e810af1accbbcf013624.tar.bz2 scummvm-rg350-7753f2d51610766fc273e810af1accbbcf013624.zip |
AGOS: Simon 2: use common PKWARE data comp. lib
use PKWARE data compression library code from COMMON/
AdLib drivers will get changed to use streams too
-rw-r--r-- | engines/agos/midi.cpp | 351 | ||||
-rw-r--r-- | engines/agos/midi.h | 6 |
2 files changed, 24 insertions, 333 deletions
diff --git a/engines/agos/midi.cpp b/engines/agos/midi.cpp index c02dfdb95b..f81721297d 100644 --- a/engines/agos/midi.cpp +++ b/engines/agos/midi.cpp @@ -23,6 +23,7 @@ #include "common/config-manager.h" #include "common/file.h" #include "common/textconsole.h" +#include "common/memstream.h" #include "agos/agos.h" #include "agos/midi.h" @@ -31,6 +32,9 @@ // Miles Audio for Simon 2 #include "audio/miles.h" +// PKWARE data compression library decompressor required for Simon 2 +#include "common/dcl.h" + #include "gui/message.h" namespace AGOS { @@ -806,7 +810,7 @@ void MidiPlayer::loadS1D(Common::File *in, bool sfx) { #define MIDI_SETUP_BUNDLE_FILEHEADER_SIZE 48 #define MIDI_SETUP_BUNDLE_FILENAME_MAX_SIZE 12 -// PKWARE data compression is used for storing files within SETUP.SHR +// PKWARE data compression library (called "DCL" in ScummVM) was used for storing files within SETUP.SHR // we need it to be able to get the file MIDPAK.AD, otherwise we would have to require the user // to "install" the game before being able to actually play it, when using AdLib. // @@ -826,7 +830,7 @@ const byte *MidiPlayer::simon2SetupExtractFile(const Common::String &requestedFi Common::String fileName; uint32 fileCompressedSize = 0; byte *fileCompressedDataPtr = nullptr; - const byte *extractedDataPtr = nullptr; + byte *extractedDataPtr = nullptr; extractedDataSize = 0; @@ -876,12 +880,27 @@ const byte *MidiPlayer::simon2SetupExtractFile(const Common::String &requestedFi if (fileName == requestedFileName) { // requested file found fileCompressedDataPtr = new byte[fileCompressedSize]; + if (setupBundleStream->read(fileCompressedDataPtr, fileCompressedSize) != fileCompressedSize) error("MidiPlayer: setup.shr read error"); - // now extract the data - - extractedDataPtr = simon2SetupDecompressFile(fileCompressedDataPtr, fileCompressedSize, extractedDataSize); + Common::MemoryReadStream *compressedStream = nullptr; + Common::SeekableReadStream *extractedStream = nullptr; + + compressedStream = new Common::MemoryReadStream(fileCompressedDataPtr, fileCompressedSize); + // we don't know the unpacked size, let decompressor figure it out + extractedStream = Common::decompressDCL(compressedStream); + delete compressedStream; + + if (extractedStream) { + // Successfully extracted the data + // TODO: clean up required, but this also requires Miles Audio drivers to use streams + extractedDataPtr = new byte[extractedStream->size()]; + extractedStream->seek(0); + extractedStream->read(extractedDataPtr, extractedStream->size()); + extractedDataSize = extractedStream->size(); + delete extractedStream; + } break; } @@ -897,326 +916,4 @@ const byte *MidiPlayer::simon2SetupExtractFile(const Common::String &requestedFi return extractedDataPtr; } -static byte simon2SetupBitsMask[9] = { - 0, - 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF -}; - -// gets [bitCount] bits from dataPtr, going from LSB to MSB -inline uint16 MidiPlayer::simon2SetupGetBits(byte bitCount, const byte *&dataPtr, const byte *dataEndPtr, byte &dataBitsLeft) { - byte resultBitsLeft = bitCount; - byte resultBitsPos = 0; - uint16 result = 0; - byte currentByte = *dataPtr; - byte currentBits = 0; - - // Get bits of current byte - while (resultBitsLeft) { - if (resultBitsLeft < dataBitsLeft) { - // we need less than we have left - currentBits = (currentByte >> (8 - dataBitsLeft)) & simon2SetupBitsMask[resultBitsLeft]; - result |= (currentBits << resultBitsPos); - dataBitsLeft -= resultBitsLeft; - resultBitsLeft = 0; - - } else { - // we need as much as we have left or more - resultBitsLeft -= dataBitsLeft; - currentBits = currentByte >> (8 - dataBitsLeft); - result |= (currentBits << resultBitsPos); - resultBitsPos += dataBitsLeft; - - // Go to next byte - dataPtr++; - if (dataPtr >= dataEndPtr) - error("MidiPlayer: setup.shr: unexpected end of compressed data stream"); - - dataBitsLeft = 8; - if (resultBitsLeft) { - currentByte = *dataPtr; - } - } - } - return result; -} - -// Decode length from bitstream -inline uint16 MidiPlayer::simon2SetupGetLength(const byte *&dataPtr, const byte *dataEndPtr, byte &dataBitsLeft) { - uint16 bits; - - bits = simon2SetupGetBits(2, dataPtr, dataEndPtr, dataBitsLeft); - - switch (bits) { - case 3: - return 3; // 11b - case 2: - bits = simon2SetupGetBits(1, dataPtr, dataEndPtr, dataBitsLeft); - if (bits) - return 5; // 011b - bits = simon2SetupGetBits(1, dataPtr, dataEndPtr, dataBitsLeft); - if (bits) - return 6; // 0101b - return 7; - case 1: - bits = simon2SetupGetBits(1, dataPtr, dataEndPtr, dataBitsLeft); - if (bits) - return 2; // 101b - return 4; // 100b - case 0: - bits = simon2SetupGetBits(1, dataPtr, dataEndPtr, dataBitsLeft); - if (bits) { - bits = simon2SetupGetBits(1, dataPtr, dataEndPtr, dataBitsLeft); - if (bits) - return 8; // 0011b - bits = simon2SetupGetBits(1, dataPtr, dataEndPtr, dataBitsLeft); - if (bits) - return 9; // 00101b - bits = simon2SetupGetBits(1, dataPtr, dataEndPtr, dataBitsLeft); - if (bits) - return 11; // 001001b - return 10; // 001000b - - } else { - bits = simon2SetupGetBits(1, dataPtr, dataEndPtr, dataBitsLeft); - if (bits) { - bits = simon2SetupGetBits(1, dataPtr, dataEndPtr, dataBitsLeft); - if (bits) { - bits = simon2SetupGetBits(2, dataPtr, dataEndPtr, dataBitsLeft); - return 12 + bits; // 00011XXb - } else { - bits = simon2SetupGetBits(3, dataPtr, dataEndPtr, dataBitsLeft); - return 16 + bits; // 00010XXXb - } - } else { - bits = simon2SetupGetBits(2, dataPtr, dataEndPtr, dataBitsLeft); - switch (bits) { - case 3: - bits = simon2SetupGetBits(4, dataPtr, dataEndPtr, dataBitsLeft); - return 24 + bits; // 000011XXXXb - case 2: - bits = simon2SetupGetBits(6, dataPtr, dataEndPtr, dataBitsLeft); - return 72 + bits; // 000001XXXXXXb - case 1: - bits = simon2SetupGetBits(5, dataPtr, dataEndPtr, dataBitsLeft); - return 40 + bits; // 000010XXXXXb - case 0: - bits = simon2SetupGetBits(1, dataPtr, dataEndPtr, dataBitsLeft); - if (bits) { - bits = simon2SetupGetBits(7, dataPtr, dataEndPtr, dataBitsLeft); - return 136 + bits; // 0000001XXXXXXXXb - } else { - bits = simon2SetupGetBits(8, dataPtr, dataEndPtr, dataBitsLeft); - return 264 + bits; // 0000000XXXXXXXXb - } - default: - break; - } - } - } - break; - default: - break; - } - return 0; -} - -// Decode offset from bitstream -inline uint16 MidiPlayer::simon2SetupGetOffset(byte lowOrderBits, const byte *&dataPtr, const byte *dataEndPtr, byte &dataBitsLeft) { - uint16 baseOffset = 0; - uint16 bits = 0; - - bits = simon2SetupGetBits(2, dataPtr, dataEndPtr, dataBitsLeft); - switch (bits) { - case 3: - baseOffset = 0; // 11b - break; - case 2: - bits = simon2SetupGetBits(4, dataPtr, dataEndPtr, dataBitsLeft); - if (bits) { - baseOffset = 0x16 - simon2SetupReverseBits(bits, 4); - } else { - bits = simon2SetupGetBits(1, dataPtr, dataEndPtr, dataBitsLeft); - baseOffset = 0x17 - bits; - } - break; - case 1: - bits = simon2SetupGetBits(1, dataPtr, dataEndPtr, dataBitsLeft); - if (bits) { - bits = simon2SetupGetBits(1, dataPtr, dataEndPtr, dataBitsLeft); - if (bits) { - baseOffset = 0x01; - } else { - baseOffset = 0x02; - } - } else { - bits = simon2SetupGetBits(2, dataPtr, dataEndPtr, dataBitsLeft); - baseOffset = 0x06 - simon2SetupReverseBits(bits, 2); - } - break; - case 0: - bits = simon2SetupGetBits(1, dataPtr, dataEndPtr, dataBitsLeft); - if (bits) { - bits = simon2SetupGetBits(4, dataPtr, dataEndPtr, dataBitsLeft); - baseOffset = 0x27 - simon2SetupReverseBits(bits, 4); - } else { - bits = simon2SetupGetBits(1, dataPtr, dataEndPtr, dataBitsLeft); - if (bits) { - bits = simon2SetupGetBits(3, dataPtr, dataEndPtr, dataBitsLeft); - baseOffset = 0x2F - simon2SetupReverseBits(bits, 3); - } else { - bits = simon2SetupGetBits(4, dataPtr, dataEndPtr, dataBitsLeft); - baseOffset = 0x3F - simon2SetupReverseBits(bits, 4); - } - } - break; - default: - break; - } - bits = simon2SetupGetBits(lowOrderBits, dataPtr, dataEndPtr, dataBitsLeft); - return (baseOffset << lowOrderBits) + bits; -} - -inline uint16 MidiPlayer::simon2SetupReverseBits(uint16 bits, byte bitCount) { - uint16 result = 0; - - for (byte bitNr = 0; bitNr < bitCount; bitNr++) { - result = (result << 1) | (bits & 0x01); - bits = bits >> 1; - } - return result; -} - -#define MIDI_SETUP_BUNDLE_FILE_MAXIMUM_DICTIONARY_SIZE 4096 - -// Implementation of "PKWARE data compression library" decompression -// Based on information released by Ben Rudiak-Gould in comp.compression on 13.8.2001 -const byte *MidiPlayer::simon2SetupDecompressFile(const byte *compressedDataPtr, uint32 compressedDataSize, uint32 &extractedDataSize) { - byte compressedLiteralType = 0; - byte compressedDictionaryType = 0; - uint16 compressedDictionarySize = 0; - const byte *readDataPtr = compressedDataPtr; - const byte *readDataEndPtr = compressedDataPtr + compressedDataSize; - uint32 readBytesLeft = compressedDataSize; - - // check if there are at least 3 bytes of compressed data - if (readBytesLeft < 3) - error("MidiPlayer: setup.shr compressed file data not enough bytes"); - - compressedLiteralType = readDataPtr[0]; - compressedDictionaryType = readDataPtr[1]; - readDataPtr += 2; - readBytesLeft -= 2; - - if (compressedLiteralType != 0) - error("MidiPlayer: setup.shr: unsupported variable length literals"); - - switch(compressedDictionaryType) { - case 4: - compressedDictionarySize = 1024; - break; - case 5: - compressedDictionarySize = 2048; - break; - case 6: - compressedDictionarySize = 4096; - break; - default: - error("MidiPlayer: setup.shr: invalid dictionary size"); - break; - } - - byte dataBitsLeft = 8; - - byte tokenType = 0; - byte tokenLiteral = 0; - byte tokenLowOrderBits = 0; - uint16 tokenLength = 0; - uint16 tokenOffset = 0; - byte dictionary[MIDI_SETUP_BUNDLE_FILE_MAXIMUM_DICTIONARY_SIZE]; - uint16 dictionaryPos = 0; - - byte *outputDataPtr = nullptr; - byte *outputPtr = nullptr; - uint32 outputSize = 0; - - // First calculate the size of the uncompressed data - do { - tokenType = simon2SetupGetBits(1, readDataPtr, readDataEndPtr, dataBitsLeft); - if (!tokenType) { - // literal - tokenLiteral = simon2SetupGetBits(8, readDataPtr, readDataEndPtr, dataBitsLeft); - outputSize++; - } else { - // length+offset - tokenLength = simon2SetupGetLength(readDataPtr, readDataEndPtr, dataBitsLeft); - if (tokenLength == 519) - break; // end of data - - tokenLowOrderBits = (tokenLength == 2) ? 2 : compressedDictionaryType; - tokenOffset = simon2SetupGetOffset(tokenLowOrderBits, readDataPtr, readDataEndPtr, dataBitsLeft); - outputSize += tokenLength; - } - } while (1); - - // allocate output buffer - outputDataPtr = new byte[outputSize]; - outputPtr = outputDataPtr; - - // reset everything - dataBitsLeft = 8; - readDataPtr = compressedDataPtr + 2; - dictionaryPos = 0; - - do { - tokenType = simon2SetupGetBits(1, readDataPtr, readDataEndPtr, dataBitsLeft); - if (!tokenType) { - // literal - tokenLiteral = simon2SetupGetBits(8, readDataPtr, readDataEndPtr, dataBitsLeft); - - // write literal to output buffer - *outputPtr = tokenLiteral; - outputPtr++; - - dictionary[dictionaryPos] = tokenLiteral; - dictionaryPos++; - if (dictionaryPos >= compressedDictionarySize) - dictionaryPos = 0; - - } else { - // length+offset - tokenLength = simon2SetupGetLength(readDataPtr, readDataEndPtr, dataBitsLeft); - if (tokenLength == 519) - break; // end of data - - tokenLowOrderBits = (tokenLength == 2) ? 2 : compressedDictionaryType; - tokenOffset = simon2SetupGetOffset(tokenLowOrderBits, readDataPtr, readDataEndPtr, dataBitsLeft); - - uint16 dictionaryBaseIndex = (dictionaryPos - 1 - tokenOffset) & (compressedDictionarySize - 1); - uint16 dictionaryIndex = dictionaryBaseIndex; - uint16 dictionaryNextIndex = dictionaryPos; - uint16 copyBytesLeft = tokenLength; - - while (copyBytesLeft) { - // write byte from dictionary - *outputPtr = dictionary[dictionaryIndex]; - outputPtr++; - - dictionary[dictionaryNextIndex] = dictionary[dictionaryIndex]; - dictionaryNextIndex++; dictionaryIndex++; - - if (dictionaryIndex >= dictionaryPos) - dictionaryIndex = dictionaryBaseIndex; - if (dictionaryNextIndex >= compressedDictionarySize) - dictionaryNextIndex = 0; - - copyBytesLeft--; - } - dictionaryPos = dictionaryNextIndex; - } - } while (1); - - extractedDataSize = outputSize; - return outputDataPtr; -} - } // End of namespace AGOS diff --git a/engines/agos/midi.h b/engines/agos/midi.h index 5e4a2bc109..fff87e63c6 100644 --- a/engines/agos/midi.h +++ b/engines/agos/midi.h @@ -130,12 +130,6 @@ private: private: const byte *simon2SetupExtractFile(const Common::String &requestedFileName, uint32 &extractedDataSize); - - inline uint16 simon2SetupGetBits(byte bitCount, const byte *&dataPtr, const byte *dataEndPtr, byte &dataBitsLeft); - inline uint16 simon2SetupGetLength(const byte *&dataPtr, const byte *dataEndPtr, byte &dataBitsLeft); - inline uint16 simon2SetupGetOffset(byte lowOrderBits, const byte *&dataPtr, const byte *dataEndPtr, byte &dataBitsLeft); - inline uint16 simon2SetupReverseBits(uint16 bits, byte bitCount); - const byte *simon2SetupDecompressFile(const byte *compressedDataPtr, uint32 compressedDataSize, uint32 &extractedDataSize); }; } // End of namespace AGOS |