aboutsummaryrefslogtreecommitdiff
path: root/scumm/bundle.cpp
diff options
context:
space:
mode:
authorMax Horn2002-08-21 16:07:07 +0000
committerMax Horn2002-08-21 16:07:07 +0000
commitce46866403fdcc479cf9d67e4d430409b15dadc3 (patch)
tree75ebfaa1ed13f549959d76d3ce101c3e66f5451b /scumm/bundle.cpp
parent662256f25dbe43abf67077a804e225738765f009 (diff)
downloadscummvm-rg350-ce46866403fdcc479cf9d67e4d430409b15dadc3.tar.gz
scummvm-rg350-ce46866403fdcc479cf9d67e4d430409b15dadc3.tar.bz2
scummvm-rg350-ce46866403fdcc479cf9d67e4d430409b15dadc3.zip
Initial revision
svn-id: r4785
Diffstat (limited to 'scumm/bundle.cpp')
-rw-r--r--scumm/bundle.cpp660
1 files changed, 660 insertions, 0 deletions
diff --git a/scumm/bundle.cpp b/scumm/bundle.cpp
new file mode 100644
index 0000000000..14486838b5
--- /dev/null
+++ b/scumm/bundle.cpp
@@ -0,0 +1,660 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2002 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ */
+
+#include "stdafx.h"
+#include "scumm.h"
+#include "scummsys.h"
+#include "bundle.h"
+
+Bundle::Bundle(Scumm *parent)
+{
+ _voiceFile = NULL;
+ _musicFile = NULL;
+ _scumm = parent;
+ _lastSong = -1;
+}
+
+Bundle::~Bundle()
+{
+ if (_voiceFile != NULL)
+ fclose(_voiceFile);
+
+ if (_musicFile != NULL)
+ fclose(_musicFile);
+}
+
+bool Bundle::openVoiceFile(char *filename)
+{
+ int32 tag, offset;
+
+ if (_voiceFile != NULL) {
+ return false;
+ }
+
+ _voiceFile = fopen(filename, "rb");
+ if (_voiceFile == NULL) {
+ printf("Bundle: Can't open voice bundle file: %s\n", filename);
+ return false;
+ }
+
+ tag = _scumm->fileReadDwordBE(_voiceFile);
+ offset = _scumm->fileReadDwordBE(_voiceFile);
+ _numVoiceFiles = _scumm->fileReadDwordBE(_voiceFile);
+
+ _bundleVoiceTable = (BundleAudioTable *) malloc(_numVoiceFiles * sizeof(BundleAudioTable));
+
+ _scumm->fileSeek(_voiceFile, offset, SEEK_SET);
+
+ for (int32 i = 0; i < _numVoiceFiles; i++) {
+ char name[13], c;
+ int32 z = 0;
+ int32 z2;
+
+ for (z2 = 0; z2 < 8; z2++)
+ if ((c = _scumm->fileReadByte(_voiceFile)) != 0)
+ name[z++] = c;
+ name[z++] = '.';
+ for (z2 = 0; z2 < 4; z2++)
+ if ((c = _scumm->fileReadByte(_voiceFile)) != 0)
+ name[z++] = c;
+ name[z] = '\0';
+ strcpy(_bundleVoiceTable[i].filename, name);
+ _bundleVoiceTable[i].offset = _scumm->fileReadDwordBE(_voiceFile);
+ _bundleVoiceTable[i].size = _scumm->fileReadDwordBE(_voiceFile);
+ }
+
+ return true;
+}
+
+bool Bundle::openMusicFile(char *filename)
+{
+ int32 tag, offset;
+
+ if (_musicFile != NULL) {
+ return false;
+ }
+
+ _musicFile = fopen(filename, "rb");
+ if (_musicFile == NULL) {
+ printf("Bundle: Can't open music bundle file: %s\n", filename);
+ return false;
+ }
+
+ tag = _scumm->fileReadDwordBE(_musicFile);
+ offset = _scumm->fileReadDwordBE(_musicFile);
+ _numMusicFiles = _scumm->fileReadDwordBE(_musicFile);
+
+ _bundleMusicTable = (BundleAudioTable *) malloc(_numMusicFiles * sizeof(BundleAudioTable));
+
+ _scumm->fileSeek(_musicFile, offset, SEEK_SET);
+
+ for (int32 i = 0; i < _numMusicFiles; i++) {
+ char name[13], c;
+ int z = 0;
+ int z2;
+
+ for (z2 = 0; z2 < 8; z2++)
+ if ((c = _scumm->fileReadByte(_musicFile)) != 0)
+ name[z++] = c;
+ name[z++] = '.';
+ for (z2 = 0; z2 < 4; z2++)
+ if ((c = _scumm->fileReadByte(_musicFile)) != 0)
+ name[z++] = c;
+ name[z] = '\0';
+ strcpy(_bundleMusicTable[i].filename, name);
+ _bundleMusicTable[i].offset = _scumm->fileReadDwordBE(_musicFile);
+ _bundleMusicTable[i].size = _scumm->fileReadDwordBE(_musicFile);
+ }
+
+ return true;
+}
+
+int32 Bundle::decompressVoiceSampleByIndex(int32 index, byte *comp_final)
+{
+ int32 i, tag, num, final_size, output_size;
+ byte *comp_input, *comp_output;
+
+ if (_voiceFile == NULL) {
+ printf("Bundle: voice file is not open !\n");
+ return 0;
+ }
+
+ _scumm->fileSeek(_voiceFile, _bundleVoiceTable[index].offset, SEEK_SET);
+ tag = _scumm->fileReadDwordBE(_voiceFile);
+ num = _scumm->fileReadDwordBE(_voiceFile);
+ _scumm->fileReadDwordBE(_voiceFile);
+ _scumm->fileReadDwordBE(_voiceFile);
+
+ if (tag != MKID_BE('COMP')) {
+ warning("Bundle: Compressed sound %d invalid (%c%c%c%c)", index, tag >> 24, tag >> 16, tag >> 8,
+ tag);
+ return 0;
+ }
+
+ for (i = 0; i < num; i++) {
+ _compVoiceTable[i].offset = _scumm->fileReadDwordBE(_voiceFile);
+ _compVoiceTable[i].size = _scumm->fileReadDwordBE(_voiceFile);
+ _compVoiceTable[i].codec = _scumm->fileReadDwordBE(_voiceFile);
+ _scumm->fileReadDwordBE(_voiceFile);
+ }
+
+ final_size = 0;
+
+ comp_output = (byte *)malloc(10000);
+ for (i = 0; i < num; i++) {
+ comp_input = (byte *)malloc(_compVoiceTable[i].size);
+
+ _scumm->fileSeek(_voiceFile, _bundleVoiceTable[index].offset + _compVoiceTable[i].offset, SEEK_SET);
+ _scumm->fileRead(_voiceFile, comp_input, _compVoiceTable[i].size);
+
+ output_size =
+ decompressCodec(_compVoiceTable[i].codec, comp_input, comp_output, _compVoiceTable[i].size);
+ memcpy((byte *)&comp_final[final_size], comp_output, output_size);
+ final_size += output_size;
+
+ free(comp_input);
+ }
+ free(comp_output);
+
+ return final_size;
+}
+
+int32 Bundle::decompressMusicSampleByIndex(int32 index, int32 number, byte *comp_final)
+{
+ int32 i, tag, num, final_size;
+ byte *comp_input;
+
+ if (_musicFile == NULL) {
+ printf("Bundle: music file is not open !\n");
+ return 0;
+ }
+
+ if (_lastSong != index) {
+ _scumm->fileSeek(_musicFile, _bundleMusicTable[index].offset, SEEK_SET);
+ tag = _scumm->fileReadDwordBE(_musicFile);
+ num = _scumm->fileReadDwordBE(_musicFile);
+ _scumm->fileReadDwordBE(_musicFile);
+ _scumm->fileReadDwordBE(_musicFile);
+
+ if (tag != MKID_BE('COMP')) {
+ warning("Bundle: Compressed sound %d invalid (%c%c%c%c)", index, tag >> 24, tag >> 16, tag >> 8,
+ tag);
+ return 0;
+ }
+
+ for (i = 0; i < num; i++) {
+ _compMusicTable[i].offset = _scumm->fileReadDwordBE(_musicFile);
+ _compMusicTable[i].size = _scumm->fileReadDwordBE(_musicFile);
+ _compMusicTable[i].codec = _scumm->fileReadDwordBE(_musicFile);
+ _scumm->fileReadDwordBE(_musicFile);
+ }
+ }
+
+ comp_input = (byte *)malloc(_compMusicTable[number].size);
+
+ _scumm->fileSeek(_musicFile, _bundleMusicTable[index].offset + _compMusicTable[number].offset,
+ SEEK_SET);
+ _scumm->fileRead(_musicFile, comp_input, _compMusicTable[number].size);
+ final_size =
+ decompressCodec(_compMusicTable[number].codec, comp_input, comp_final, _compMusicTable[number].size);
+
+ free(comp_input);
+
+ _lastSong = index;
+
+ return final_size;
+}
+
+
+int32 Bundle::decompressVoiceSampleByName(char *name, byte *comp_final)
+{
+ int32 final_size = 0, i;
+
+ if (_voiceFile == NULL) {
+ printf("Bundle: voice file is not open !\n");
+ return 0;
+ }
+
+ for (i = 0; i < _numVoiceFiles; i++) {
+ if (!scumm_stricmp(name, _bundleVoiceTable[i].filename)) {
+ final_size = decompressVoiceSampleByIndex(i, comp_final);
+ return final_size;
+ }
+ }
+ return final_size;
+}
+
+int32 Bundle::decompressMusicSampleByName(char *name, int32 number, byte *comp_final)
+{
+ int32 final_size = 0, i;
+
+ if (_voiceFile == NULL) {
+ printf("Bundle: voice file is not open !\n");
+ return 0;
+ }
+
+ for (i = 0; i < _numMusicFiles; i++) {
+ if (!scumm_stricmp(name, _bundleMusicTable[i].filename)) {
+ final_size = decompressMusicSampleByIndex(i, number, comp_final);
+ return final_size;
+ }
+ }
+ return final_size;
+}
+
+int32 Bundle::getNumberOfMusicSamplesByIndex(int32 index)
+{
+ if (_musicFile == NULL) {
+ printf("Bundle: music file is not open !\n");
+ return 0;
+ }
+
+ _scumm->fileSeek(_musicFile, _bundleMusicTable[index].offset, SEEK_SET);
+ _scumm->fileReadDwordBE(_musicFile);
+ return _scumm->fileReadDwordBE(_musicFile);
+}
+
+int32 Bundle::getNumberOfMusicSamplesByName(char *name)
+{
+ int32 number = 0, i;
+
+ if (_musicFile == NULL) {
+ printf("Bundle: music file is not open !\n");
+ return 0;
+ }
+
+ for (i = 0; i < _numMusicFiles; i++) {
+ if (!scumm_stricmp(name, _bundleMusicTable[i].filename)) {
+ number = getNumberOfMusicSamplesByIndex(i);
+ return number;
+ }
+ }
+ return number;
+}
+
+#define NextBit bit = mask & 1; mask >>= 1; if (!--bitsleft) {mask = READ_LE_UINT16(srcptr); srcptr += 2; bitsleft=16;}
+
+int32 Bundle::compDecode(byte *src, byte *dst)
+{
+ byte *result, *srcptr = src, *dstptr = dst;
+ int data, size, bit, bitsleft = 16, mask = READ_LE_UINT16(srcptr);
+ srcptr += 2;
+
+ while (1) {
+ NextBit if (bit) {
+ *dstptr++ = *srcptr++;
+ } else {
+ NextBit if (!bit) {
+ NextBit size = bit << 1;
+ NextBit size = (size | bit) + 3;
+ data = *srcptr++ | 0xffffff00;
+ } else {
+ data = *srcptr++;
+ size = *srcptr++;
+
+ data |= 0xfffff000 + ((size & 0xf0) << 4);
+ size = (size & 0x0f) + 3;
+
+ if (size == 3)
+ if (((*srcptr++) + 1) == 1)
+ return dstptr - dst;
+ }
+ result = dstptr + data;
+ while (size--)
+ *dstptr++ = *result++;
+ }
+ }
+}
+#undef NextBit
+
+int32 Bundle::decompressCodec(int32 codec, byte *comp_input, byte *comp_output, int32 input_size)
+{
+ int32 output_size = input_size;
+ int32 offset1, offset2, offset3, length, k, c, s, j, r, t, z;
+ byte *src, *t_table, *p, *ptr;
+ byte t_tmp1, t_tmp2;
+
+ switch (codec) {
+ case 0:
+ memcpy(comp_output, comp_input, output_size);
+ break;
+
+ case 1:
+ output_size = compDecode(comp_input, comp_output);
+ break;
+
+ case 2:
+ output_size = compDecode(comp_input, comp_output);
+ p = comp_output;
+ for (z = 1; z < output_size; z++)
+ p[z] += p[z - 1];
+ break;
+
+ case 3:
+ output_size = compDecode(comp_input, comp_output);
+ p = comp_output;
+ for (z = 2; z < output_size; z++)
+ p[z] += p[z - 1];
+ for (z = 1; z < output_size; z++)
+ p[z] += p[z - 1];
+ break;
+
+ case 4:
+ output_size = compDecode(comp_input, comp_output);
+ p = comp_output;
+ for (z = 2; z < output_size; z++)
+ p[z] += p[z - 1];
+ for (z = 1; z < output_size; z++)
+ p[z] += p[z - 1];
+
+ t_table = (byte *)malloc(output_size);
+ memset(t_table, 0, output_size);
+
+ src = comp_output;
+ length = (output_size * 8) / 12;
+ k = 0;
+ if (length > 0) {
+ c = -12;
+ s = 0;
+ j = 0;
+ do {
+ ptr = src + length + (k / 2);
+ if (k & 1) {
+ r = c / 8;
+ *(t_table + r + 2) = ((*(src + j) & 0x0f) << 4) | ((*(ptr + 1) & 0xf0) >> 4);
+ *(t_table + r + 1) = (*(src + j) & 0xf0) | (*(t_table + r + 1));
+ } else {
+ r = s / 8;
+ *(t_table + r + 0) = ((*(src + j) & 0x0f) << 4) | (*ptr & 0x0f);
+ *(t_table + r + 1) = (*(src + j) & 0xf0) >> 4;
+ }
+ s += 12;
+ k++;
+ j++;
+ c += 12;
+ } while (k < length);
+ }
+ offset1 = ((length - 1) * 3) / 2;
+ *(t_table + offset1 + 1) = (*(t_table + offset1 + 1)) | *(src + length - 1) & 0xf0;
+ memcpy(src, t_table, output_size);
+ free(t_table);
+ break;
+
+ case 5:
+ output_size = compDecode(comp_input, comp_output);
+ p = comp_output;
+ for (z = 2; z < output_size; z++)
+ p[z] += p[z - 1];
+ for (z = 1; z < output_size; z++)
+ p[z] += p[z - 1];
+
+ t_table = (byte *)malloc(output_size);
+ memset(t_table, 0, output_size);
+
+ src = comp_output;
+ length = (output_size * 8) / 12;
+ k = 1;
+ c = 0;
+ s = 12;
+ *t_table = (*(src + length)) >> 4;
+ t = length + k;
+ j = 1;
+ if (t > k) {
+ do {
+ ptr = src + length + (k / 2);
+ if (k & 1) {
+ r = c / 8;
+ *(t_table + r + 0) = (*(src + j - 1) & 0xf0) | (*(t_table + r));
+ *(t_table + r + 1) = ((*(src + j - 1) & 0x0f) << 4) | (*ptr & 0x0f);
+ } else {
+ r = s / 8;
+ *(t_table + r + 0) = (*(src + j - 1) & 0xf0) >> 4;
+ *(t_table + r - 1) = ((*(src + j - 1) & 0x0f) << 4) | ((*ptr & 0xf0) >> 4);
+ }
+ s += 12;
+ k++;
+ j++;
+ c += 12;
+ } while (k < t);
+ }
+ memcpy(src, t_table, output_size);
+ free(t_table);
+ break;
+
+ case 6:
+ output_size = compDecode(comp_input, comp_output);
+ p = comp_output;
+ for (z = 2; z < output_size; z++)
+ p[z] += p[z - 1];
+ for (z = 1; z < output_size; z++)
+ p[z] += p[z - 1];
+
+ t_table = (byte *)malloc(output_size);
+ memset(t_table, 0, output_size);
+
+ src = comp_output;
+ length = (output_size * 8) / 12;
+ k = 0;
+ c = 0;
+ j = 0;
+ s = -12;
+ *t_table = *(output_size + src - 1);
+ *(t_table + output_size - 1) = *(src + length - 1);
+ t = length - 1;
+ if (t > 0) {
+ do {
+ ptr = src + length + (k / 2);
+ if (k & 1) {
+ r = s / 8;
+ *(t_table + r + 2) = (*(src + j) & 0xf0) | *(t_table + r + 2);
+ *(t_table + r + 3) = ((*(src + j) & 0x0f) << 4) | ((*ptr & 0xf0) >> 4);
+ } else {
+ r = c / 8;
+ *(t_table + r + 2) = (*(src + j) & 0xf0) >> 4;
+ *(t_table + r + 1) = ((*(src + j) & 0x0f) << 4) | (*ptr & 0x0f);
+ }
+ s += 12;
+ k++;
+ j++;
+ c += 12;
+ } while (k < t);
+ }
+ memcpy(src, t_table, output_size);
+ free(t_table);
+ break;
+
+ case 10:
+ output_size = compDecode(comp_input, comp_output);
+ p = comp_output;
+ for (z = 2; z < output_size; z++)
+ p[z] += p[z - 1];
+ for (z = 1; z < output_size; z++)
+ p[z] += p[z - 1];
+
+ t_table = (byte *)malloc(output_size);
+ memcpy(t_table, p, output_size);
+
+ offset1 = output_size / 3;
+ offset2 = offset1 * 2;
+ offset3 = offset2;
+ src = comp_output;
+ do {
+ if (offset1 == 0)
+ break;
+ offset1--;
+ offset2 -= 2;
+ offset3--;
+ *(t_table + offset2 + 0) = *(src + offset1);
+ *(t_table + offset2 + 1) = *(src + offset3);
+ } while (1);
+
+ src = comp_output;
+ length = (output_size * 8) / 12;
+ k = 0;
+ if (length > 0) {
+ c = -12;
+ s = 0;
+ do {
+ j = length + (k / 2);
+ if (k & 1) {
+ r = c / 8;
+ t_tmp1 = *(t_table + k);
+ t_tmp2 = *(t_table + j + 1);
+ *(src + r + 2) = ((t_tmp1 & 0x0f) << 4) | ((t_tmp2 & 0xf0) >> 4);
+ *(src + r + 1) = (*(src + r + 1)) | (t_tmp1 & 0xf0);
+ } else {
+ r = s / 8;
+ t_tmp1 = *(t_table + k);
+ t_tmp2 = *(t_table + j);
+ *(src + r + 0) = ((t_tmp1 & 0x0f) << 4) | (t_tmp2 & 0x0f);
+ *(src + r + 1) = ((t_tmp1 & 0xf0) >> 4);
+ }
+ s += 12;
+ k++;
+ c += 12;
+ } while (k < length);
+ }
+ offset1 = ((length - 1) * 3) / 2;
+ *(src + offset1 + 1) = (*(t_table + length) & 0xf0) | *(src + offset1 + 1);
+ free(t_table);
+ break;
+
+ case 11:
+ output_size = compDecode(comp_input, comp_output);
+ p = comp_output;
+ for (z = 2; z < output_size; z++)
+ p[z] += p[z - 1];
+ for (z = 1; z < output_size; z++)
+ p[z] += p[z - 1];
+
+ t_table = (byte *)malloc(output_size);
+ memcpy(t_table, p, output_size);
+
+ offset1 = output_size / 3;
+ offset2 = offset1 * 2;
+ offset3 = offset2;
+ src = comp_output;
+ do {
+ if (offset1 == 0)
+ break;
+ offset1--;
+ offset2 -= 2;
+ offset3--;
+ *(t_table + offset2 + 0) = *(src + offset1);
+ *(t_table + offset2 + 1) = *(src + offset3);
+ } while (1);
+
+ src = comp_output;
+ length = (output_size * 8) / 12;
+ k = 1;
+ c = 0;
+ s = 12;
+ t_tmp1 = (*(t_table + length)) >> 4;
+ *(src) = t_tmp1;
+ t = length + k;
+ if (t > k) {
+ do {
+ j = length + (k / 2);
+ if (k & 1) {
+ r = c / 8;
+ t_tmp1 = *(t_table + k - 1);
+ t_tmp2 = *(t_table + j);
+ *(src + r + 0) = (*(src + r)) | (t_tmp1 & 0xf0);
+ *(src + r + 1) = ((t_tmp1 & 0x0f) << 4) | (t_tmp2 & 0x0f);
+ } else {
+ r = s / 8;
+ t_tmp1 = *(t_table + k - 1);
+ t_tmp2 = *(t_table + j);
+ *(src + r + 0) = (t_tmp1 & 0xf0) >> 4;
+ *(src + r - 1) = ((t_tmp1 & 0x0f) << 4) | ((t_tmp2 & 0xf0) >> 4);
+ }
+ s += 12;
+ k++;
+ c += 12;
+ } while (k < t);
+ }
+ free(t_table);
+ break;
+
+ case 12:
+ output_size = compDecode(comp_input, comp_output);
+ p = comp_output;
+ for (z = 2; z < output_size; z++)
+ p[z] += p[z - 1];
+ for (z = 1; z < output_size; z++)
+ p[z] += p[z - 1];
+
+ t_table = (byte *)malloc(output_size);
+ memcpy(t_table, p, output_size);
+
+ offset1 = output_size / 3;
+ offset2 = offset1 * 2;
+ offset3 = offset2;
+ src = comp_output;
+ do {
+ if (offset1 == 0)
+ break;
+ offset1--;
+ offset2 -= 2;
+ offset3--;
+ *(t_table + offset2 + 0) = *(src + offset1);
+ *(t_table + offset2 + 1) = *(src + offset3);
+ } while (1);
+
+ src = comp_output;
+ length = (output_size * 8) / 12;
+ k = 0;
+ c = 0;
+ s = -12;
+ *(src) = *(output_size + t_table - 1);
+ *(src + output_size - 1) = *(t_table + length - 1);
+ t = length - 1;
+ if (t > 0) {
+ do {
+ j = length + (k / 2);
+ if (k & 1) {
+ r = s / 8;
+ t_tmp1 = *(t_table + k);
+ t_tmp2 = *(t_table + j);
+ *(src + r + 2) = (*(src + r + 2)) | (t_tmp1 & 0xf0);
+ *(src + r + 3) = ((t_tmp1 & 0x0f) << 4) | ((t_tmp2 & 0xf0) >> 4);
+ } else {
+ r = c / 8;
+ t_tmp1 = *(t_table + k);
+ t_tmp2 = *(t_table + j);
+ *(src + r + 2) = (t_tmp1 & 0xf0) >> 4;
+ *(src + r + 1) = ((t_tmp1 & 0x0f) << 4) | (t_tmp2 & 0x0f);
+ }
+ s += 12;
+ k++;
+ c += 12;
+ } while (k < t);
+ }
+ free(t_table);
+ break;
+
+ default:
+ printf("Bundle: Unknown codec %d!\n", (int)codec);
+ output_size = 0;
+ break;
+ }
+
+ return output_size;
+}