/* 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; } Bundle::~Bundle() { if (_voiceFile != NULL) fclose (_voiceFile); if (_musicFile != NULL) fclose (_musicFile); } int32 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; } int32 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(_bundleVoiceTable[i].filename, name); _bundleVoiceTable[i].offset = _scumm->fileReadDwordBE(_musicFile); _bundleVoiceTable[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; } _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[i].size); _scumm->fileSeek(_musicFile, _bundleMusicTable[index].offset + _compMusicTable[i].offset, SEEK_SET); _scumm->fileRead(_musicFile, comp_input, _compMusicTable[i].size); final_size = decompressCodec(_compMusicTable[i].codec, comp_input, comp_final, _compMusicTable[i].size); free(comp_input); 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; byte t_tmp1, t_tmp2; switch(codec) { case 0: memcpy(comp_input, comp_output, 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); // FIXME: not implemented yet memset (comp_output, 0, output_size); break; case 5: output_size = compDecode(comp_input, comp_output); // FIXME: not implemented yet memset (comp_output, 0, output_size); break; case 6: output_size = compDecode(comp_input, comp_output); // FIXME: not implemented yet memset (comp_output, 0, output_size); 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); } 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", codec); output_size = 0; break; } return output_size; }