aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/resource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/resource.cpp')
-rw-r--r--engines/sci/resource.cpp293
1 files changed, 207 insertions, 86 deletions
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index f9ae45b6cd..24b4d9beed 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -63,7 +63,7 @@ enum SolFlags {
kSolFlagIsSigned = 1 << 3
};
-const char *sci_error_types[] = {
+static const char *sci_error_types[] = {
"No error",
"I/O error",
"Resource is empty (size 0)",
@@ -78,7 +78,7 @@ const char *sci_error_types[] = {
};
// These are the 20 resource types supported by SCI1.1
-const char *resourceTypeNames[] = {
+static const char *resourceTypeNames[] = {
"view", "pic", "script", "text", "sound",
"memory", "vocab", "font", "cursor",
"patch", "bitmap", "palette", "cdaudio",
@@ -86,7 +86,7 @@ const char *resourceTypeNames[] = {
"audio36", "sync36"
};
-const char *resourceTypeSuffixes[] = {
+static const char *resourceTypeSuffixes[] = {
"v56", "p56", "scr", "tex", "snd",
" ", "voc", "fon", "cur", "pat",
"bit", "pal", "cda", "aud", "syn",
@@ -97,13 +97,6 @@ const char *getResourceTypeName(ResourceType restype) {
return resourceTypeNames[restype];
}
-const char *getResourceTypeSuffix(ResourceType restype) {
- return resourceTypeSuffixes[restype];
-}
-
-typedef int decomp_funct(Resource *result, Common::ReadStream &stream, int sci_version);
-typedef void patch_sprintf_funct(char *string, Resource *res);
-
//-- Resource main functions --
Resource::Resource() {
data = NULL;
@@ -290,7 +283,7 @@ int sci0_get_compression_method(Common::ReadStream &stream) {
return compressionMethod;
}
-int sci_test_view_type(ResourceManager *mgr) {
+int ResourceManager::guessSciVersion() {
Common::File file;
char filename[MAXPATHLEN];
int compression;
@@ -298,7 +291,7 @@ int sci_test_view_type(ResourceManager *mgr) {
int i;
for (i = 0; i < 1000; i++) {
- res = mgr->testResource(kResourceTypeView, i);
+ res = testResource(kResourceTypeView, i);
if (!res)
continue;
@@ -322,7 +315,7 @@ int sci_test_view_type(ResourceManager *mgr) {
// Try the same thing with pics
for (i = 0; i < 1000; i++) {
- res = mgr->testResource(kResourceTypePic, i);
+ res = testResource(kResourceTypePic, i);
if (!res)
continue;
@@ -442,14 +435,14 @@ ResourceManager::ResourceManager(int version, int maxMemory) {
switch (_mapVersion) {
case SCI_VERSION_0:
if (testResource(kResourceTypeVocab, VOCAB_RESOURCE_SCI0_MAIN_VOCAB)) {
- version = sci_test_view_type(this) ? SCI_VERSION_01_VGA : SCI_VERSION_0;
+ version = guessSciVersion() ? SCI_VERSION_01_VGA : SCI_VERSION_0;
} else if (testResource(kResourceTypeVocab, VOCAB_RESOURCE_SCI1_MAIN_VOCAB)) {
- version = sci_test_view_type(this);
+ version = guessSciVersion();
if (version != SCI_VERSION_01_VGA) {
version = testResource(kResourceTypeVocab, 912) ? SCI_VERSION_0 : SCI_VERSION_01;
}
} else {
- version = sci_test_view_type(this) ? SCI_VERSION_01_VGA : SCI_VERSION_0;
+ version = guessSciVersion() ? SCI_VERSION_01_VGA : SCI_VERSION_0;
}
break;
case SCI_VERSION_01_VGA_ODD:
@@ -586,7 +579,7 @@ void ResourceManager::freeOldResources(int last_invulnerable) {
}
}
-Resource *ResourceManager::findResource(ResourceType type, int number, int lock) {
+Resource *ResourceManager::findResource(ResourceType type, int number, bool lock) {
Resource *retval;
if (number >= sci_max_resource_nr[_sciVersion]) {
@@ -863,7 +856,7 @@ void ResourceManager::readResourcePatches(ResourceSource *source) {
SearchMan.listMatchingMembers(files, mask);
// SCI1 and later naming - nnn.typ
mask = "*.";
- mask += getResourceTypeSuffix((ResourceType)i);
+ mask += resourceTypeSuffixes[i];
SearchMan.listMatchingMembers(files, mask);
for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); x++) {
bAdd = false;
@@ -1178,7 +1171,7 @@ void ResourceSync::stopSync() {
AudioResource::AudioResource(ResourceManager *resMgr, int sciVersion) {
_resMgr = resMgr;
_sciVersion = sciVersion;
- _audioRate = 0;
+ _audioRate = 11025;
_lang = 0;
_audioMapSCI1 = 0;
_audioMapSCI11 = 0;
@@ -1238,7 +1231,7 @@ bool AudioResource::findAudEntrySCI1(uint16 audioNumber, byte &volume, uint32 &o
return false;
byte *ptr = _audioMapSCI1;
- while ((n = READ_UINT16(ptr)) != 0xFFFF) {
+ while ((n = READ_LE_UINT16(ptr)) != 0xFFFF) {
if (n == audioNumber) {
off = READ_LE_UINT32(ptr + 2);
size = READ_LE_UINT32(ptr + 6);
@@ -1252,14 +1245,8 @@ bool AudioResource::findAudEntrySCI1(uint16 audioNumber, byte &volume, uint32 &o
return false;
}
-bool AudioResource::findAudEntrySCI11(uint32 audioNumber, uint32 volume, uint32 &offset, bool getSync, uint32 *size) {
- // 65535.MAP structure:
- // =========
- // 6 byte entries:
- // w nEntry
- // dw offset
-
- // Other map files:
+bool AudioResource::findAudEntrySCI11Late(uint32 audioNumber, uint32 &offset, bool getSync, uint32 *size) {
+ // Map structure:
// ===============
// Header:
// dw baseOffset
@@ -1269,8 +1256,116 @@ bool AudioResource::findAudEntrySCI11(uint32 audioNumber, uint32 volume, uint32
// b cond
// b seq
// tb cOffset (cumulative offset)
- // w syncSize (iff seq has bits 7 and 6 set)
- // w syncAscSize (iff seq has bits 7 and 6 set)
+ // w syncSize (iff seq has bit 7 set)
+ // w syncAscSize (iff seq has bit 6 set)
+
+ uint32 n;
+ offset = 0;
+
+ byte *ptr = _audioMapSCI11->data;
+
+ offset = READ_LE_UINT32(ptr);
+ ptr += 4;
+
+ while (ptr < _audioMapSCI11->data + _audioMapSCI11->size) {
+ n = READ_BE_UINT32(ptr);
+ ptr += 4;
+
+ if (n == 0xffffffff)
+ break;
+
+ offset += READ_LE_UINT24(ptr);
+ ptr += 3;
+
+ int syncSkip = 0;
+
+ if (n & 0x80) {
+ n ^= 0x80;
+
+ if (getSync) {
+ if (size)
+ *size = READ_LE_UINT16(ptr);
+ } else {
+ syncSkip = READ_LE_UINT16(ptr);
+ }
+
+ ptr += 2;
+
+ if (n & 0x40) {
+ n ^= 0x40;
+
+ if (!getSync)
+ syncSkip += READ_LE_UINT16(ptr);
+
+ ptr += 2;
+ }
+
+ offset += syncSkip;
+
+ if (n == audioNumber)
+ return true;
+
+ } else {
+ if (n == audioNumber)
+ return !getSync;
+ }
+
+ offset -= syncSkip;
+ }
+
+ return false;
+}
+
+bool AudioResource::findAudEntrySCI11Early(uint32 audioNumber, uint32 &offset, bool getSync, uint32 *size) {
+ // Map structure:
+ // ===============
+ // 10-byte entries:
+ // b noun
+ // b verb
+ // b cond
+ // b seq
+ // dw offset
+ // w syncSize + syncAscSize
+
+ uint32 n;
+ offset = 0;
+
+ byte *ptr = _audioMapSCI11->data;
+
+ while (ptr < _audioMapSCI11->data + _audioMapSCI11->size) {
+ n = READ_BE_UINT32(ptr);
+ ptr += 4;
+
+ if (n == 0xffffffff)
+ break;
+
+ offset = READ_LE_UINT32(ptr);
+ ptr += 4;
+
+ int syncSize = READ_LE_UINT16(ptr);
+ ptr += 2;
+
+ if (n == audioNumber) {
+ if (getSync) {
+ if (size)
+ *size = syncSize;
+ return true;
+ } else {
+ offset += syncSize;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool AudioResource::findAudEntrySCI11(uint32 audioNumber, uint32 volume, uint32 &offset, bool getSync, uint32 *size) {
+ // 65535.MAP structure:
+ // =========
+ // 6 byte entries:
+ // w nEntry
+ // dw offset
uint32 n;
offset = 0;
@@ -1288,65 +1383,93 @@ bool AudioResource::findAudEntrySCI11(uint32 audioNumber, uint32 volume, uint32
if (volume == 65535) {
while (ptr < _audioMapSCI11->data + _audioMapSCI11->size) {
- n = READ_UINT16(ptr);
+ n = READ_LE_UINT16(ptr);
ptr += 2;
if (n == 0xffff)
break;
- offset = READ_UINT32(ptr);
+ offset = READ_LE_UINT32(ptr);
ptr += 4;
if (n == audioNumber)
return true;
}
} else {
- offset = READ_UINT32(ptr);
- ptr += 4;
+ // In early SCI1.1 the map is terminated with 10x 0xff, in late SCI1.1
+ // with 11x 0xff. If we look at the 11th last byte in an early SCI1.1
+ // map, this will be the high byte of the Sync length of the last entry.
+ // As Sync resources are relative small, we should never encounter a
+ // Sync with a size of 0xffnn. As such, the following heuristic should be
+ // sufficient to tell these map formats apart.
+ if (_audioMapSCI11->size >= 11 && (ptr[_audioMapSCI11->size - 11] == 0xff))
+ return findAudEntrySCI11Late(audioNumber, offset, getSync, size);
+ else {
+ return findAudEntrySCI11Early(audioNumber, offset, getSync, size);
+ }
+ }
- while (ptr < _audioMapSCI11->data + _audioMapSCI11->size) {
- n = READ_BE_UINT32(ptr);
- ptr += 4;
+ return false;
+}
- if (n == 0xffffffff)
- break;
+// FIXME: Move this to sound/adpcm.cpp?
+// Note that the 16-bit version is also used in coktelvideo.cpp
+static const uint16 tableDPCM16[128] = {
+ 0x0000, 0x0008, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0070, 0x0080,
+ 0x0090, 0x00A0, 0x00B0, 0x00C0, 0x00D0, 0x00E0, 0x00F0, 0x0100, 0x0110, 0x0120,
+ 0x0130, 0x0140, 0x0150, 0x0160, 0x0170, 0x0180, 0x0190, 0x01A0, 0x01B0, 0x01C0,
+ 0x01D0, 0x01E0, 0x01F0, 0x0200, 0x0208, 0x0210, 0x0218, 0x0220, 0x0228, 0x0230,
+ 0x0238, 0x0240, 0x0248, 0x0250, 0x0258, 0x0260, 0x0268, 0x0270, 0x0278, 0x0280,
+ 0x0288, 0x0290, 0x0298, 0x02A0, 0x02A8, 0x02B0, 0x02B8, 0x02C0, 0x02C8, 0x02D0,
+ 0x02D8, 0x02E0, 0x02E8, 0x02F0, 0x02F8, 0x0300, 0x0308, 0x0310, 0x0318, 0x0320,
+ 0x0328, 0x0330, 0x0338, 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370,
+ 0x0378, 0x0380, 0x0388, 0x0390, 0x0398, 0x03A0, 0x03A8, 0x03B0, 0x03B8, 0x03C0,
+ 0x03C8, 0x03D0, 0x03D8, 0x03E0, 0x03E8, 0x03F0, 0x03F8, 0x0400, 0x0440, 0x0480,
+ 0x04C0, 0x0500, 0x0540, 0x0580, 0x05C0, 0x0600, 0x0640, 0x0680, 0x06C0, 0x0700,
+ 0x0740, 0x0780, 0x07C0, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00,
+ 0x0F00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000
+};
- offset += (READ_UINT16(ptr) | (ptr[2] << 16));
- ptr += 3;
+static const byte tableDPCM8[8] = {0, 1, 2, 3, 6, 10, 15, 21};
- int syncSkip = 0;
+static void deDPCM16(byte *soundBuf, Common::SeekableReadStream &audioStream, uint32 n) {
+ int16 *out = (int16 *) soundBuf;
- if ((n & 0xc0) == 0xc0) {
- n ^= 0xc0;
+ int32 s = 0;
+ for (uint32 i = 0; i < n; i++) {
+ byte b = audioStream.readByte();
+ if (b & 0x80)
+ s -= tableDPCM16[b & 0x7f];
+ else
+ s += tableDPCM16[b];
- if (getSync) {
- if (size)
- *size = READ_UINT16(ptr);
- } else {
- syncSkip = READ_UINT16(ptr) + READ_UINT16(ptr + 2);
- offset += syncSkip;
- }
+ s = CLIP<int32>(s, -32768, 32767);
+ *out++ = TO_BE_16(s);
+ }
+}
- if (n == audioNumber)
- return true;
+static void deDPCM8Nibble(byte *soundBuf, int32 &s, byte b) {
+ if (b & 8)
+ s -= tableDPCM8[7 - (b & 7)];
+ else
+ s += tableDPCM8[b & 7];
+ s = CLIP<int32>(s, 0, 255);
+ *soundBuf = s;
+}
- ptr += 4;
- } else {
- if (n == audioNumber)
- return !getSync;
- }
+static void deDPCM8(byte *soundBuf, Common::SeekableReadStream &audioStream, uint32 n) {
+ int32 s = 0x80;
- offset -= syncSkip;
- }
- }
+ for (uint i = 0; i < n; i++) {
+ byte b = audioStream.readByte();
- return false;
+ deDPCM8Nibble(soundBuf++, s, b >> 4);
+ deDPCM8Nibble(soundBuf++, s, b & 0xf);
+ }
}
// Sierra SOL audio file reader
// Check here for more info: http://wiki.multimedia.cx/index.php?title=Sierra_Audio
-// TODO: improve this for later versions of the format, as this currently only reads
-// raw PCM encoded files (not ADPCM compressed ones)
byte* readSOLAudio(Common::SeekableReadStream *audioStream, uint32 *size, uint16 *audioRate, byte *flags) {
byte audioFlags;
byte type = audioStream->readByte();
@@ -1357,6 +1480,12 @@ byte* readSOLAudio(Common::SeekableReadStream *audioStream, uint32 *size, uint16
}
int headerSize = audioStream->readByte();
+
+ if (headerSize != 11 && headerSize != 12) {
+ warning("SOL audio header of size %i not supported", headerSize);
+ return NULL;
+ }
+
audioStream->readUint32LE(); // skip "SOL" + 0 (4 bytes)
*audioRate = audioStream->readUint16LE();
audioFlags = audioStream->readByte();
@@ -1365,36 +1494,25 @@ byte* readSOLAudio(Common::SeekableReadStream *audioStream, uint32 *size, uint16
*flags = 0;
if (audioFlags & kSolFlag16Bit)
*flags |= Audio::Mixer::FLAG_16BITS;
- if ((audioFlags & kSolFlagCompressed) || !(audioFlags & kSolFlagIsSigned))
+ if (!(audioFlags & kSolFlagIsSigned))
*flags |= Audio::Mixer::FLAG_UNSIGNED;
- *size = audioStream->readUint16LE();
+ *size = audioStream->readUint32LE();
- if (headerSize == 12)
- *size |= audioStream->readByte() << 16;
+ if (headerSize == 12) {
+ // Unknown byte
+ audioStream->readByte();
+ }
byte *buffer;
if (audioFlags & kSolFlagCompressed) {
- if (audioFlags & kSolFlag16Bit) {
- warning("Unsupported DPCM mode");
- return NULL;
- }
-
buffer = new byte[*size * 2];
- byte sample = 0x80;
-
- for (uint i = 0; i < *size; i++) {
- const int delta[] = {0, 1, 2, 3, 6, 10, 15, 21, -21, -15, -10, -6, -3, -2, -1, -0};
-
- byte b = audioStream->readByte();
-
- sample += delta[b >> 4];
- buffer[i * 2] = sample;
- sample += delta[b & 0xf];
- buffer[i * 2 + 1] = sample;
- }
+ if (audioFlags & kSolFlag16Bit)
+ deDPCM16(buffer, *audioStream, *size);
+ else
+ deDPCM8(buffer, *audioStream, *size);
*size *= 2;
} else {
@@ -1498,7 +1616,10 @@ Audio::AudioStream* AudioResource::getAudioStream(uint32 audioNumber, uint32 vol
}
}
- *sampleLen = size * 60 / _audioRate;
+ *sampleLen = (flags & Audio::Mixer::FLAG_16BITS ? size >> 1 : size) * 60 / _audioRate;
+ } else {
+ warning("Failed to find audio entry (%i, %i, %i, %i, %i)", volume, (audioNumber >> 24) & 0xff,
+ (audioNumber >> 16) & 0xff, (audioNumber >> 8) & 0xff, audioNumber & 0xff);
}
return audioStream;