aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Kiewitz2015-07-04 01:50:07 +0200
committerMartin Kiewitz2015-07-04 01:50:07 +0200
commit7753f2d51610766fc273e810af1accbbcf013624 (patch)
tree4944aafd69d4bc19a5c4e1bdf6d5b12f8cae005c
parent2bd07431257927968a7ca89f72982d0090812e2c (diff)
downloadscummvm-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.cpp351
-rw-r--r--engines/agos/midi.h6
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