mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-28 04:34:50 +00:00
6f499d8fa1
svn-id: r6503
937 lines
24 KiB
C++
937 lines
24 KiB
C++
/* 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"
|
|
#include "file.h"
|
|
|
|
uint16 imcTable1[] = {
|
|
0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x0010, 0x0011,
|
|
0x0013, 0x0015, 0x0017, 0x0019, 0x001C, 0x001F, 0x0022, 0x0025, 0x0029, 0x002D,
|
|
0x0032, 0x0037, 0x003C, 0x0042, 0x0049, 0x0050, 0x0058, 0x0061, 0x006B, 0x0076,
|
|
0x0082, 0x008F, 0x009D, 0x00AD, 0x00BE, 0x00D1, 0x00E6, 0x00FD, 0x0117, 0x0133,
|
|
0x0151, 0x0173, 0x0198, 0x01C1, 0x01EE, 0x0220, 0x0256, 0x0292, 0x02D4, 0x031C,
|
|
0x036C, 0x03C3, 0x0424, 0x048E, 0x0502, 0x0583, 0x0610, 0x06AB, 0x0756, 0x0812,
|
|
0x08E0, 0x09C3, 0x0ABD, 0x0BD0, 0x0CFF, 0x0E4C, 0x0FBA, 0x114C, 0x1307, 0x14EE,
|
|
0x1706, 0x1954, 0x1BDC, 0x1EA5, 0x21B6, 0x2515, 0x28CA, 0x2CDF, 0x315B, 0x364B,
|
|
0x3BB9, 0x41B2, 0x4844, 0x4F7E, 0x5771, 0x602F, 0x69CE, 0x7462, 0x7FFF
|
|
};
|
|
|
|
byte imxOtherTable1[] = {
|
|
0xFF, 0x04, 0xFF, 0x04
|
|
};
|
|
|
|
byte imxOtherTable2[] = {
|
|
0xFF, 0xFF, 0x02, 0x08, 0xFF, 0xFF, 0x02, 0x08
|
|
};
|
|
|
|
byte imxOtherTable3[] = {
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x02, 0x04, 0x06,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x02, 0x04, 0x06
|
|
};
|
|
|
|
byte imxOtherTable4[] = {
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0x01, 0x02, 0x04, 0x06, 0x08, 0x0C, 0x10, 0x20,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0x01, 0x02, 0x04, 0x06, 0x08, 0x0C, 0x10, 0x20
|
|
};
|
|
|
|
byte imxOtherTable5[] = {
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0x01, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E,
|
|
0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x20,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0x01, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E,
|
|
0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x20
|
|
};
|
|
|
|
byte imxOtherTable6[] = {
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
|
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
|
|
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
|
0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
|
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
|
|
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
|
0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20
|
|
};
|
|
|
|
uint16 imxShortTable[] = {
|
|
0x0000, 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F
|
|
};
|
|
|
|
Bundle::Bundle()
|
|
{
|
|
_lastSong = -1;
|
|
_initializedImcTables = false;
|
|
|
|
_bundleVoiceTable = NULL;
|
|
_bundleMusicTable = NULL;
|
|
}
|
|
|
|
Bundle::~Bundle()
|
|
{
|
|
if (_bundleVoiceTable)
|
|
free(_bundleVoiceTable);
|
|
if (_bundleMusicTable)
|
|
free(_bundleMusicTable);
|
|
}
|
|
|
|
void Bundle::initializeImcTables()
|
|
{
|
|
if (_initializedImcTables == true)
|
|
return;
|
|
|
|
int32 destTablePos = 0;
|
|
int32 imcTable1Pos = 0;
|
|
do {
|
|
int16 put = 1;
|
|
int32 tableValue = ((imcTable1[imcTable1Pos] << 2) / 7) / 2;
|
|
if (tableValue != 0) {
|
|
do {
|
|
tableValue /= 2;
|
|
put++;
|
|
} while (tableValue != 0);
|
|
}
|
|
if (put < 3) {
|
|
put = 3;
|
|
}
|
|
if (put > 8) {
|
|
put = 8;
|
|
}
|
|
put--;
|
|
imcTable1Pos++;
|
|
_destImcTable[destTablePos] = (byte)put;
|
|
destTablePos++;
|
|
} while (imcTable1Pos <= 88);
|
|
_destImcTable[89] = 0;
|
|
|
|
for (int n = 0; n < 63; n++) {
|
|
imcTable1Pos = 0;
|
|
int32 destTable2Pos = n;
|
|
do {
|
|
int32 count = 32;
|
|
int32 putD = 0;
|
|
int32 tableValue = imcTable1[imcTable1Pos];
|
|
do {
|
|
if ((count & n) != 0) {
|
|
putD = putD + tableValue;
|
|
}
|
|
count >>= 1;
|
|
tableValue >>= 1;
|
|
} while (count != 0);
|
|
_destImcTable2[destTable2Pos] = putD;
|
|
destTable2Pos += 64;
|
|
imcTable1Pos++;
|
|
} while (imcTable1Pos <= 88);
|
|
}
|
|
|
|
_initializedImcTables = true;
|
|
}
|
|
|
|
bool Bundle::openVoiceFile(const char *filename, const char *directory)
|
|
{
|
|
int32 tag, offset;
|
|
|
|
initializeImcTables();
|
|
|
|
if (_voiceFile.isOpen() == true)
|
|
return true;
|
|
|
|
if (_voiceFile.open(filename, directory) == false) {
|
|
warning("Bundle: Can't open voice bundle file: %s", filename);
|
|
return false;
|
|
}
|
|
|
|
tag = _voiceFile.readUint32BE();
|
|
offset = _voiceFile.readUint32BE();
|
|
_numVoiceFiles = _voiceFile.readUint32BE();
|
|
|
|
_bundleVoiceTable = (BundleAudioTable *) malloc(_numVoiceFiles * sizeof(BundleAudioTable));
|
|
|
|
_voiceFile.seek(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 = _voiceFile.readByte()) != 0)
|
|
name[z++] = c;
|
|
name[z++] = '.';
|
|
for (z2 = 0; z2 < 4; z2++)
|
|
if ((c = _voiceFile.readByte()) != 0)
|
|
name[z++] = c;
|
|
name[z] = '\0';
|
|
strcpy(_bundleVoiceTable[i].filename, name);
|
|
_bundleVoiceTable[i].offset = _voiceFile.readUint32BE();
|
|
_bundleVoiceTable[i].size = _voiceFile.readUint32BE();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Bundle::openMusicFile(const char *filename, const char *directory)
|
|
{
|
|
int32 tag, offset;
|
|
|
|
initializeImcTables();
|
|
|
|
if (_musicFile.isOpen() == true)
|
|
return true;
|
|
|
|
if (_musicFile.open(filename, directory) == false) {
|
|
warning("Bundle: Can't open music bundle file: %s", filename);
|
|
return false;
|
|
}
|
|
|
|
tag = _musicFile.readUint32BE();
|
|
offset = _musicFile.readUint32BE();
|
|
_numMusicFiles = _musicFile.readUint32BE();
|
|
|
|
_bundleMusicTable = (BundleAudioTable *) malloc(_numMusicFiles * sizeof(BundleAudioTable));
|
|
|
|
_musicFile.seek(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 = _musicFile.readByte()) != 0)
|
|
name[z++] = c;
|
|
name[z++] = '.';
|
|
for (z2 = 0; z2 < 4; z2++)
|
|
if ((c = _musicFile.readByte()) != 0)
|
|
name[z++] = c;
|
|
name[z] = '\0';
|
|
strcpy(_bundleMusicTable[i].filename, name);
|
|
_bundleMusicTable[i].offset = _musicFile.readUint32BE();
|
|
_bundleMusicTable[i].size = _musicFile.readUint32BE();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
int32 Bundle::decompressVoiceSampleByIndex(int32 index, byte *comp_final, int32 & channels)
|
|
{
|
|
int32 i, tag, num, final_size, output_size;
|
|
byte *comp_input, *comp_output;
|
|
|
|
if (_voiceFile.isOpen() == false) {
|
|
warning("Bundle: voice file is not open!");
|
|
return 0;
|
|
}
|
|
|
|
_voiceFile.seek(_bundleVoiceTable[index].offset, SEEK_SET);
|
|
tag = _voiceFile.readUint32BE();
|
|
num = _voiceFile.readUint32BE();
|
|
_voiceFile.readUint32BE();
|
|
_voiceFile.readUint32BE();
|
|
|
|
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;
|
|
}
|
|
|
|
if (_compVoiceTable)
|
|
free(_compVoiceTable);
|
|
|
|
_compVoiceTable = (CompTable*)malloc(sizeof(CompTable) * num);
|
|
for (i = 0; i < num; i++) {
|
|
_compVoiceTable[i].offset = _voiceFile.readUint32BE();
|
|
_compVoiceTable[i].size = _voiceFile.readUint32BE();
|
|
_compVoiceTable[i].codec = _voiceFile.readUint32BE();
|
|
_voiceFile.readUint32BE();
|
|
}
|
|
|
|
final_size = 0;
|
|
|
|
comp_output = (byte *)malloc(10000);
|
|
|
|
for (i = 0; i < num; i++) {
|
|
comp_input = (byte *)malloc(_compVoiceTable[i].size);
|
|
|
|
_voiceFile.seek(_bundleVoiceTable[index].offset + _compVoiceTable[i].offset, SEEK_SET);
|
|
_voiceFile.read(comp_input, _compVoiceTable[i].size);
|
|
|
|
output_size =
|
|
decompressCodec(_compVoiceTable[i].codec, comp_input, comp_output, _compVoiceTable[i].size, i, channels);
|
|
assert(output_size <= 10000);
|
|
memcpy(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 & channels)
|
|
{
|
|
int32 i = 0;
|
|
int tag, num, final_size;
|
|
byte *comp_input;
|
|
|
|
if (_musicFile.isOpen() == false) {
|
|
warning("Bundle: music file is not open!");
|
|
return 0;
|
|
}
|
|
|
|
if (_lastSong != index) {
|
|
_musicFile.seek(_bundleMusicTable[index].offset, SEEK_SET);
|
|
tag = _musicFile.readUint32BE();
|
|
num = _musicFile.readUint32BE();
|
|
_musicFile.readUint32BE();
|
|
_musicFile.readUint32BE();
|
|
|
|
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;
|
|
}
|
|
|
|
if (_compMusicTable)
|
|
free(_compMusicTable);
|
|
_compMusicTable = (CompTable*)malloc(sizeof(CompTable) * num);
|
|
|
|
for (i = 0; i < num; i++) {
|
|
_compMusicTable[i].offset = _musicFile.readUint32BE();
|
|
_compMusicTable[i].size = _musicFile.readUint32BE();
|
|
_compMusicTable[i].codec = _musicFile.readUint32BE();
|
|
_musicFile.readUint32BE();
|
|
}
|
|
}
|
|
|
|
comp_input = (byte *)malloc(_compMusicTable[number].size);
|
|
|
|
_musicFile.seek(_bundleMusicTable[index].offset + _compMusicTable[number].offset, SEEK_SET);
|
|
_musicFile.read(comp_input, _compMusicTable[number].size);
|
|
|
|
// FIXME - if _lastSong == index then i will be 0 - is the right / the desired behaviour?!?
|
|
final_size =
|
|
decompressCodec(_compMusicTable[number].codec, comp_input, comp_final, _compMusicTable[number].size, number, channels);
|
|
|
|
free(comp_input);
|
|
|
|
_lastSong = index;
|
|
|
|
return final_size;
|
|
}
|
|
|
|
int32 Bundle::decompressVoiceSampleByName(char *name, byte *comp_final, int32 & channels)
|
|
{
|
|
int32 final_size = 0, i;
|
|
|
|
if (_voiceFile.isOpen() == false) {
|
|
warning("Bundle: voice file is not open!");
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < _numVoiceFiles; i++) {
|
|
if (!scumm_stricmp(name, _bundleVoiceTable[i].filename)) {
|
|
final_size = decompressVoiceSampleByIndex(i, comp_final, channels);
|
|
return final_size;
|
|
}
|
|
}
|
|
warning("Failed finding voice %s", name);
|
|
return final_size;
|
|
}
|
|
|
|
int32 Bundle::decompressMusicSampleByName(char *name, int32 number, byte *comp_final, int32 & channels) {
|
|
int32 final_size = 0, i;
|
|
|
|
if (!name) {
|
|
warning("Bundle: decompressMusicSampleByName called with no name!");
|
|
return 0;
|
|
}
|
|
|
|
if (_musicFile.isOpen() == false) {
|
|
warning("Bundle: music file is not open!");
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < _numMusicFiles; i++) {
|
|
if (!scumm_stricmp(name, _bundleMusicTable[i].filename)) {
|
|
final_size = decompressMusicSampleByIndex(i, number, comp_final, channels);
|
|
return final_size;
|
|
}
|
|
}
|
|
warning("Couldn't find sample %s", name);
|
|
return final_size;
|
|
}
|
|
|
|
int32 Bundle::getNumberOfMusicSamplesByIndex(int32 index)
|
|
{
|
|
if (_musicFile.isOpen() == false) {
|
|
warning("Bundle: music file is not open!");
|
|
return 0;
|
|
}
|
|
|
|
_musicFile.seek(_bundleMusicTable[index].offset, SEEK_SET);
|
|
_musicFile.readUint32BE();
|
|
return _musicFile.readUint32BE();
|
|
}
|
|
|
|
int32 Bundle::getNumberOfMusicSamplesByName(char *name)
|
|
{
|
|
int32 number = 0, i;
|
|
|
|
if (_musicFile.isOpen() == false) {
|
|
warning("Bundle: music file is not open!");
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < _numMusicFiles; i++) {
|
|
if (!scumm_stricmp(name, _bundleMusicTable[i].filename)) {
|
|
number = getNumberOfMusicSamplesByIndex(i);
|
|
return number;
|
|
}
|
|
}
|
|
warning("Couldn't find numsample %s\n", name);
|
|
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 index, int32 & channels)
|
|
{
|
|
int32 output_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, input_size);
|
|
output_size = input_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;
|
|
|
|
case 13:
|
|
case 15:
|
|
{
|
|
uint16 firstWord;
|
|
int32 startPos;
|
|
byte sByte[4];
|
|
int32 sDWord[4];
|
|
int32 channel;
|
|
int32 left, origLeft;
|
|
int32 tableEntrySum;
|
|
int32 curTablePos;
|
|
int32 outputWord;
|
|
int32 imcTableEntry;
|
|
int32 destPos = 0;
|
|
int32 curTableEntry;
|
|
byte decompTable;
|
|
uint16 readWord;
|
|
byte * readPos;
|
|
byte otherTablePos;
|
|
int32 esiReg;
|
|
byte var3b;
|
|
int32 adder;
|
|
|
|
byte *endPos = comp_input + input_size;
|
|
|
|
src = comp_input;
|
|
memset (comp_output, 0, 0x2000);
|
|
firstWord = READ_BE_UINT16(src);
|
|
src += 2;
|
|
assert(src < endPos);
|
|
|
|
|
|
if (firstWord != 0) {
|
|
if (index != 0) {
|
|
startPos = 0;
|
|
} else {
|
|
memcpy(comp_output, src, firstWord);
|
|
startPos = firstWord;
|
|
uint32 tag;
|
|
ptr = src;
|
|
do {
|
|
tag = READ_BE_UINT32(ptr); ptr += 4;
|
|
} while (tag != MKID_BE('FRMT'));
|
|
channels = READ_BE_UINT32(ptr + 20);
|
|
}
|
|
src += firstWord;
|
|
origLeft = 0x2000 - firstWord;
|
|
// At this point we are at the start of the content of the 'DATA' chunk.
|
|
} else {
|
|
sByte[0] = *src++;
|
|
sDWord[0] = (int32)READ_BE_UINT32(src);
|
|
src += 4;
|
|
sDWord[1] = (int32)READ_BE_UINT32(src);
|
|
src += 4;
|
|
if (channels > 1) {
|
|
sByte[1] = *src++;
|
|
sDWord[2] = (int32)READ_BE_UINT32(src);
|
|
src += 4;
|
|
sDWord[3] = (int32)READ_BE_UINT32(src);
|
|
src += 4;
|
|
}
|
|
startPos = 0;
|
|
origLeft = 0x2000;
|
|
}
|
|
assert(src < endPos);
|
|
|
|
tableEntrySum = 0;
|
|
for (channel = 0; channel < channels; channel++) {
|
|
if (firstWord == 0) {
|
|
curTablePos = sByte[channel];
|
|
outputWord = sDWord[channel * 2 + 1];
|
|
imcTableEntry = sDWord[channel * 2];
|
|
} else {
|
|
curTablePos = 0;
|
|
outputWord = 0;
|
|
imcTableEntry = 7;
|
|
}
|
|
|
|
left = (origLeft - 1) / (2 * (channels - channel)) + 1;
|
|
origLeft -= 2* left;
|
|
|
|
destPos = startPos + 2 * channel;
|
|
while (left--) {
|
|
curTableEntry = _destImcTable[curTablePos];
|
|
decompTable = curTableEntry - 2;
|
|
var3b = (1 << decompTable) << 1;
|
|
readPos = src + (tableEntrySum >> 3);
|
|
if (readPos >= endPos) {
|
|
error("readPos exceeds endPos: %d >= %d (%d, %d)!" , readPos, endPos, left, origLeft);
|
|
}
|
|
assert(readPos < endPos);
|
|
readWord = (uint16)(READ_BE_UINT16(readPos) << (tableEntrySum & 7));
|
|
otherTablePos = (byte)(readWord >> (16 - curTableEntry));
|
|
tableEntrySum += curTableEntry;
|
|
esiReg = imxShortTable[curTableEntry];
|
|
esiReg = (esiReg & otherTablePos) << (7 - curTableEntry);
|
|
esiReg += (curTablePos << 6);
|
|
imcTableEntry >>= (curTableEntry - 1);
|
|
adder = imcTableEntry + _destImcTable2[esiReg];
|
|
if ((otherTablePos & var3b) != 0) {
|
|
adder = -adder;
|
|
}
|
|
outputWord += adder;
|
|
if (outputWord > 0x7fff)
|
|
outputWord = 0x7fff;
|
|
if (outputWord < -0x8000)
|
|
outputWord = -0x8000;
|
|
comp_output[destPos] = (byte)(outputWord >> 8);
|
|
comp_output[destPos + 1] = (byte)(outputWord);
|
|
switch (decompTable) {
|
|
case 0: curTablePos += (signed char)imxOtherTable1[otherTablePos];
|
|
break;
|
|
case 1: curTablePos += (signed char)imxOtherTable2[otherTablePos];
|
|
break;
|
|
case 2: curTablePos += (signed char)imxOtherTable3[otherTablePos];
|
|
break;
|
|
case 3: curTablePos += (signed char)imxOtherTable4[otherTablePos];
|
|
break;
|
|
case 4: curTablePos += (signed char)imxOtherTable5[otherTablePos];
|
|
break;
|
|
case 5: curTablePos += (signed char)imxOtherTable6[otherTablePos];
|
|
break;
|
|
}
|
|
if (curTablePos < 0)
|
|
curTablePos = 0;
|
|
if (curTablePos > 88)
|
|
curTablePos = 88;
|
|
destPos += 2 * channels;
|
|
imcTableEntry = imcTable1[curTablePos];
|
|
}
|
|
}
|
|
if (index == 0) {
|
|
output_size = 0x2000 - firstWord;
|
|
} else {
|
|
output_size = 0x2000;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
warning("Bundle: Unknown codec %d!", (int)codec);
|
|
output_size = 0;
|
|
break;
|
|
}
|
|
|
|
return output_size;
|
|
}
|