diff options
author | Max Horn | 2002-08-21 16:07:07 +0000 |
---|---|---|
committer | Max Horn | 2002-08-21 16:07:07 +0000 |
commit | ce46866403fdcc479cf9d67e4d430409b15dadc3 (patch) | |
tree | 75ebfaa1ed13f549959d76d3ce101c3e66f5451b /scumm/bundle.cpp | |
parent | 662256f25dbe43abf67077a804e225738765f009 (diff) | |
download | scummvm-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.cpp | 660 |
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; +} |