diff options
author | Max Horn | 2011-04-09 23:47:35 +0200 |
---|---|---|
committer | Max Horn | 2011-04-09 23:47:35 +0200 |
commit | 6cf1de87acdb878e3a3e4ef7cc33d45adee4a592 (patch) | |
tree | d20295fc02d514a62ee4f22a5a34136316d0916c /devtools/create_kyradat/extract.cpp | |
parent | ae49865e9e48b8569922d2ea1792541fb23b4a64 (diff) | |
download | scummvm-rg350-6cf1de87acdb878e3a3e4ef7cc33d45adee4a592.tar.gz scummvm-rg350-6cf1de87acdb878e3a3e4ef7cc33d45adee4a592.tar.bz2 scummvm-rg350-6cf1de87acdb878e3a3e4ef7cc33d45adee4a592.zip |
DEVTOOLS: Renamed 'tools' directory to 'devtools'
Diffstat (limited to 'devtools/create_kyradat/extract.cpp')
-rw-r--r-- | devtools/create_kyradat/extract.cpp | 987 |
1 files changed, 987 insertions, 0 deletions
diff --git a/devtools/create_kyradat/extract.cpp b/devtools/create_kyradat/extract.cpp new file mode 100644 index 0000000000..6b801d14f9 --- /dev/null +++ b/devtools/create_kyradat/extract.cpp @@ -0,0 +1,987 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "extract.h" + +#include <algorithm> + +namespace { + +// Extraction function prototypes + +bool extractRaw(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id); +bool extractStrings(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id); +bool extractStrings10(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id); +bool extractRooms(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id); +bool extractShapes(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id); +bool extractKyraForestSeqData(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id); +bool extractAmigaSfx(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id); +bool extractWdSfx(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id); + +bool extractHofSeqData(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id); +bool extractHofShapeAnimDataV1(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id); +bool extractHofShapeAnimDataV2(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id); + +bool extractStringsWoSuffix(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id); +bool extractPaddedStrings(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id); +bool extractRaw16to8(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id); +bool extractMrShapeAnimData(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id); +bool extractRaw16(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id); +bool extractRaw32(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id); +bool extractLolButtonDefs(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id); + +// Extraction type table + +const ExtractType extractTypeTable[] = { + { kTypeStringList, extractStrings }, + { kTypeRoomList, extractRooms }, + { kTypeShapeList, extractShapes }, + { kTypeRawData, extractRaw }, + { kTypeForestSeqData, extractKyraForestSeqData }, + { kTypeAmigaSfxTable, extractAmigaSfx }, + { kTypeTownsWDSfxTable, extractWdSfx }, + + { k2TypeSeqData, extractHofSeqData }, + { k2TypeShpDataV1, extractHofShapeAnimDataV1 }, + { k2TypeShpDataV2, extractHofShapeAnimDataV2 }, + { k2TypeSoundList, extractStringsWoSuffix }, + { k2TypeLangSoundList, extractStringsWoSuffix }, + { k2TypeSize10StringList, extractStrings10 }, + { k2TypeSfxList, extractPaddedStrings }, + { k3TypeRaw16to8, extractRaw16to8 }, + { k3TypeShpData, extractMrShapeAnimData }, + + { kLolTypeCharData, extractRaw }, + { kLolTypeSpellData, extractRaw }, + { kLolTypeCompassData, extractRaw16to8 }, + { kLolTypeFlightShpData, extractRaw16to8 }, + { kLolTypeRaw16, extractRaw16 }, + { kLolTypeRaw32, extractRaw32 }, + { kLolTypeButtonDef, extractLolButtonDefs }, + + { -1, 0 } +}; + +// TODO: Clean up the mess of data types we have... it seems some special types +// we have (even in the main KYRA code, is just raw data access, but used specially +// to have a nice wrapper from inside StaticResource...). +const TypeTable typeTable[] = { + { kTypeStringList, 0 }, + { kTypeRawData, 1 }, + { kTypeRoomList, 2 }, + { kTypeShapeList, 3 }, + { kTypeForestSeqData, 1 }, + { kTypeAmigaSfxTable, 4 }, + { kTypeTownsWDSfxTable, 1 }, + { k2TypeSeqData, 5 }, + { k2TypeShpDataV1, 6 }, + { k2TypeShpDataV2, 7 }, + { k2TypeSoundList, 0 }, + { k2TypeLangSoundList, 0 }, + { k2TypeSize10StringList, 0 }, + { k2TypeSfxList, 0 }, + { k3TypeRaw16to8, 1 }, + { k3TypeShpData, 7 }, + { kLolTypeRaw16, 13 }, + { kLolTypeRaw32, 14 }, + { kLolTypeButtonDef, 12 }, + { kLolTypeCharData, 8 }, + { kLolTypeSpellData, 9 }, + { kLolTypeCompassData, 10 }, + { kLolTypeFlightShpData, 11 }, + { -1, 1 } +}; + +} // end of anonymous namespace + +// misc + +const ExtractType *findExtractType(const int type) { + for (const ExtractType *i = extractTypeTable; i->type != -1; ++i) { + if (i->type == type) + return i; + } + return 0; +} + +byte getTypeID(int type) { + return std::find(typeTable, typeTable + ARRAYSIZE(typeTable) - 1, type)->value; +} +// Extractor implementation + +namespace { + +bool extractRaw(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id) { + uint8 *buffer = new uint8[size]; + assert(buffer); + memcpy(buffer, data, size); + + return out.addFile(filename, buffer, size); +} + +bool extractStrings(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id) { + int fmtPatch = 0; + // FM Towns files that need addional patches + if (info->platform == kPlatformFMTowns) { + if (id == k1TakenStrings || id == k1NoDropStrings || id == k1PoisonGoneString || + id == k1ThePoisonStrings || id == k1FluteStrings || id == k1WispJewelStrings) + fmtPatch = 1; + else if (id == k1IntroStrings) + fmtPatch = 2; + else if (id == k2SeqplayStrings) + fmtPatch = 3; + } else if (info->platform == kPlatformPC) { + if (id == k2IngamePakFiles) + fmtPatch = 4; + + // HACK + if (id == k2SeqplayIntroTracks && info->game == kLol) + return extractStringsWoSuffix(out, info, data, size, filename, id); + } + + uint32 entries = 0; + uint32 targetsize = size + 4; + for (uint32 i = 0; i < size; ++i) { + if (!data[i]) { + if (info->platform == kPlatformAmiga) { + if (i + 1 >= size) + ++entries; + else if (!data[i+1] && !(i & 1)) + continue; + else + ++entries; + } else { + ++entries; + } + + if (info->platform == kPlatformFMTowns) { + // prevents creation of empty entries (which we have mostly between all strings in the FM-TOWNS version) + while (!data[++i]) { + if (i == size) + break; + targetsize--; + } + if (fmtPatch == 1) { + // Here is the first step of the extra treatment for all FM-TOWNS string arrays that + // contain more than one string and which the original code + // addresses via stringname[boolJapanese]. + // We simply skip every other string + if (i == size) + continue; + uint32 len = strlen((const char*) data + i); + i += len; + + targetsize = targetsize - 1 - len; + + while (!data[++i]) { + if (i == len) + break; + targetsize--; + } + } + } + } + } + + if (fmtPatch == 2) { + if (info->lang == EN_ANY) { + targetsize--; + entries += 1; + } else if (info->lang == JA_JPN) { + targetsize += 2; + entries += 2; + } + } + + if (fmtPatch == 3) { + entries++; + targetsize++; + } + + if (fmtPatch == 4) { + targetsize -= 9; + } + + uint8 *buffer = new uint8[targetsize]; + assert(buffer); + memset(buffer, 0, targetsize); + uint8 *output = buffer; + const uint8 *input = (const uint8*) data; + + WRITE_BE_UINT32(output, entries); output += 4; + if (info->platform == kPlatformFMTowns) { + const byte *c = data + size; + do { + if (fmtPatch == 2 && input - data == 0x3C0 && input[0x10] == 0x32) { + memcpy(output, input, 0x0F); + input += 0x11; output += 0x0F; + } + + strcpy((char*) output, (const char*) input); + uint32 stringsize = strlen((const char*)output) + 1; + input += stringsize; output += stringsize; + // skip empty entries + while (!*input) { + // Write one empty string into intro strings file + if (fmtPatch == 2) { + if ((info->lang == EN_ANY && input - data == 0x260) || + (info->lang == JA_JPN && (input - data == 0x2BD || input - data == 0x2BE))) + *output++ = *input; + } + + // insert one dummy string at hof sequence strings position 59 + if (fmtPatch == 3) { + if ((info->lang == EN_ANY && input - data == 0x695) || + (info->lang == JA_JPN && input - data == 0x598)) + *output++ = *input; + } + + if (++input == c) + break; + } + + if (fmtPatch == 1) { + // Here is the extra treatment for all FM-TOWNS string arrays that + // contain more than one string and which the original code + // addresses via stringname[boolJapanese]. + // We simply skip every other string + if (input == c) + continue; + input += strlen((const char*)input); + while (!*input) { + if (++input == c) + break; + } + } + + } while (input < c); + } else if (info->platform == kPlatformAmiga) { + // we need to strip some aligment zeros out here + int dstPos = 0; + for (uint32 i = 0; i < size; ++i) { + if (!data[i] && !(i & 1)) { + if (i + 1 > size) + continue; + else if (i + 1 < size && !data[i+1]) + continue; + } + + *output++ = data[i]; + ++dstPos; + } + targetsize = dstPos + 4; + } else { + uint32 copySize = size; + if (fmtPatch == 4) { + memcpy(output, data, 44); + output += 44; + data += 44; + for (int t = 1; t != 10; t++) { + sprintf((char*) output, "COST%d_SH.PAK", t); + output += 13; + } + data += 126; + copySize -= 170; + } + memcpy(output, data, copySize); + } + + return out.addFile(filename, buffer, targetsize); +} + +bool extractStrings10(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id) { + // HACK... + if (info->platform == kPlatformFMTowns && id == k2IngameSfxFiles) + return extractStringsWoSuffix(out, info, data, size, filename, id); + + const int strSize = 10; + uint32 entries = (size + (strSize - 1)) / strSize; + + uint8 *buffer = new uint8[size + 4]; + assert(buffer); + uint8 *output = buffer; + WRITE_BE_UINT32(output, entries); output += 4; + + for (uint32 i = 0; i < entries; ++i) { + const byte *src = data + i * strSize; + + while (*src) + *output++ = *src++; + *output++ = '\0'; + } + + return out.addFile(filename, buffer, output - buffer); +} + +bool extractRooms(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id) { + // different entry size for the FM-TOWNS version + const int roomEntrySize = (info->platform == kPlatformFMTowns) ? (0x69) : ((info->platform == kPlatformAmiga) ? 0x52 : 0x51); + const int countRooms = size / roomEntrySize; + + uint8 *buffer = new uint8[countRooms * 9 + 4]; + assert(buffer); + uint8 *output = buffer; + + WRITE_BE_UINT32(output, countRooms); output += 4; + + const byte *src = data; + if (info->platform == kPlatformAmiga) { + for (int i = 0; i < countRooms; ++i) { + *output++ = *src++; assert(*src == 0); ++src; + memcpy(output, src, 8); output += 0x8; + src += roomEntrySize - 0x2; + } + } else { + for (int i = 0; i < countRooms; ++i) { + *output++ = *src++; + WRITE_BE_UINT16(output, READ_LE_UINT16(src)); output += 2; src += 2; + WRITE_BE_UINT16(output, READ_LE_UINT16(src)); output += 2; src += 2; + WRITE_BE_UINT16(output, READ_LE_UINT16(src)); output += 2; src += 2; + WRITE_BE_UINT16(output, READ_LE_UINT16(src)); output += 2; src += 2; + src += roomEntrySize - 0x9; + } + } + + return out.addFile(filename, buffer, countRooms * 9 + 4); +} + +bool extractShapes(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id) { + byte *buffer = new byte[size + 1 * 4]; + assert(buffer); + byte *output = buffer; + + const int count = size / 0x07; + WRITE_BE_UINT32(output, count); output += 4; + memcpy(output, data, size); + + return out.addFile(filename, buffer, size + 1 * 4); +} + +bool extractKyraForestSeqData(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id) { + if (info->platform != kPlatformPC98) + return extractRaw(out, info, data, size, filename, id); + + struct PatchEntry { + uint16 pos; + uint8 val; + }; + + // This data has been taken from the FM-Towns version + static const PatchEntry patchData[] = { + { 0x0019, 0x06 }, { 0x001A, 0x09 }, { 0x001B, 0x00 }, { 0x002E, 0x06 }, { 0x002F, 0x09 }, { 0x0030, 0x00 }, + { 0x003D, 0x06 }, { 0x003E, 0x09 }, { 0x003F, 0x00 }, { 0x004C, 0x06 }, { 0x004D, 0x09 }, { 0x004E, 0x00 }, + { 0x005B, 0x06 }, { 0x005C, 0x09 }, { 0x005D, 0x00 }, { 0x0064, 0x06 }, { 0x0065, 0x09 }, { 0x0066, 0x00 }, + { 0x0079, 0x06 }, { 0x007A, 0x09 }, { 0x007B, 0x00 }, { 0x0088, 0x06 }, { 0x0089, 0x09 }, { 0x008A, 0x00 }, + { 0x0097, 0x06 }, { 0x0098, 0x09 }, { 0x0099, 0x00 }, { 0x00A6, 0x06 }, { 0x00A7, 0x09 }, { 0x00A8, 0x00 }, + { 0x00AD, 0x06 }, { 0x00AE, 0x09 }, { 0x00AF, 0x00 }, { 0x00B4, 0x06 }, { 0x00B5, 0x09 }, { 0x00B6, 0x00 }, + { 0x00C3, 0x06 }, { 0x00C4, 0x09 }, { 0x00C5, 0x00 }, { 0x00CA, 0x06 }, { 0x00CB, 0x09 }, { 0x00CC, 0x00 }, + { 0x00D1, 0x06 }, { 0x00D2, 0x09 }, { 0x00D3, 0x00 }, { 0x00E0, 0x06 }, { 0x00E1, 0x09 }, { 0x00E2, 0x00 }, + { 0x00E7, 0x06 }, { 0x00E8, 0x09 }, { 0x00E9, 0x00 }, { 0x00EE, 0x06 }, { 0x00EF, 0x09 }, { 0x00F0, 0x00 }, + { 0x00FD, 0x06 }, { 0x00FE, 0x09 }, { 0x00FF, 0x00 }, { 0x010A, 0x06 }, { 0x010B, 0x09 }, { 0x010C, 0x00 }, + { 0x011D, 0x06 }, { 0x011E, 0x09 }, { 0x011F, 0x00 }, { 0x012C, 0x06 }, { 0x012D, 0x09 }, { 0x012E, 0x00 }, + { 0x013D, 0x06 }, { 0x013E, 0x09 }, { 0x013F, 0x00 }, { 0x0148, 0x06 }, { 0x0149, 0x09 }, { 0x014A, 0x00 }, + { 0x0153, 0x06 }, { 0x0154, 0x09 }, { 0x0155, 0x00 }, { 0x015E, 0x06 }, { 0x015F, 0x09 }, { 0x0160, 0x00 }, + { 0x0169, 0x06 }, { 0x016A, 0x09 }, { 0x016B, 0x00 }, { 0x016C, 0x06 }, { 0x016D, 0x12 }, { 0x016E, 0x00 }, + { 0x017B, 0x06 }, { 0x017C, 0x09 }, { 0x017D, 0x00 }, { 0x0188, 0x06 }, { 0x0189, 0x09 }, { 0x018A, 0x00 }, + { 0x0190, 0x13 }, { 0x0000, 0x00 } + }; + + uint32 outsize = size + (ARRAYSIZE(patchData) - 1); + uint8 *buffer = new uint8[outsize]; + assert(buffer); + + const uint8 *src = data; + uint8 *dst = buffer; + const PatchEntry *patchPos = patchData; + + while (dst < (buffer + outsize)) { + if ((dst - buffer) == patchPos->pos) { + *dst++ = patchPos->val; + patchPos++; + } else { + *dst++ = *src++; + } + } + + return out.addFile(filename, buffer, outsize); +} + +bool extractAmigaSfx(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id) { + const uint32 entries = size / 8; + byte *buffer = new byte[entries * 6 + 1 * 4]; + + byte *output = buffer; + WRITE_BE_UINT32(output, entries); output += 4; + + for (uint32 i = 0; i < entries; ++i) { + *output++ = *data++; // Note + *output++ = *data++; // Patch + data += 2; // Unused + WRITE_BE_UINT16(output, READ_BE_UINT16(data)); output += 2; data += 2; // Duration + *output++ = *data++; // Volume + *output++ = *data++; // Pan + } + + return out.addFile(filename, buffer, entries * 6 + 1 * 4); +} + +bool extractWdSfx(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id) { + const int bufferSize = 0x12602; + + uint8 *buffer = new uint8[0x12602]; + assert(buffer); + memcpy(buffer, data, 0x7EE5); + memcpy(buffer + 0x7EE5, data + 0x7EE7, 0x7FFF); + memcpy(buffer + 0xFEE4, data + 0xFEE8, 0x271E); + + return out.addFile(filename, buffer, bufferSize); +} + +int extractHofSeqData_checkString(const void *ptr, uint8 checkSize); +int extractHofSeqData_isSequence(const void *ptr, const ExtractInformation *info, uint32 maxCheckSize); +int extractHofSeqData_isControl(const void *ptr, uint32 size); + +bool extractHofSeqData(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id) { + int numSequences = 0; + int numNestedSequences = 0; + + uint16 headerSize = 50 * sizeof(uint16); + uint16 bufferSize = size + headerSize; + byte *buffer = new byte[bufferSize]; + assert(buffer); + memset(buffer, 0, bufferSize ); + uint16 *header = (uint16*) buffer; + byte *output = buffer + headerSize; + uint16 *hdout = header; + + //debug(1, "\nProcessing Hand of Fate sequence data:\n--------------------------------------\n"); + for (int cycle = 0; cycle < 2; cycle++) { + const byte *ptr = data; + hdout++; + + const byte *endOffs = (const byte *)(data + size); + + // detect sequence structs + while (ptr < endOffs) { + if (ptr[1]) { + error("invalid sequence data encountered"); + delete[] buffer; + return false; + } + + int v = extractHofSeqData_isSequence(ptr, info, endOffs - ptr); + + if (cycle == 0 && v == 1) { + if ((info->platform == kPlatformPC && info->special == kNoSpecial && *ptr == 5) || (info->special == kDemoVersion && (ptr - data == 312))) { + // patch for floppy version: skips invalid ferb sequence + // patch for demo: skips invalid title sequence + ptr += 54; + continue; + } + + numSequences++; + uint16 relOffs = (uint16) (output - buffer); + WRITE_BE_UINT16(hdout, relOffs); + hdout++; + + WRITE_BE_UINT16(output, READ_LE_UINT16(ptr)); // flags + ptr += 2; + output += 2; + + memcpy(output, ptr, 28); // wsa and cps file names + ptr += 28; + output += 28; + + if (info->platform == kPlatformFMTowns) { // startupCommand + finalCommand + memcpy(output, ptr, 2); + ptr += 2; + output += 2; + } else { + *output++ = READ_LE_UINT16(ptr) & 0xff; + ptr += 2; + *output++ = READ_LE_UINT16(ptr) & 0xff; + ptr += 2; + } + + for (int w = 0; w < 7; w++) { //stringIndex1 to yPos + WRITE_BE_UINT16(output, READ_LE_UINT16(ptr)); + ptr += 2; + output += 2; + } + + ptr += 4; + WRITE_BE_UINT16(output, READ_LE_UINT16(ptr)); // duration + ptr += 2; + output+= 2; + + } else if (cycle == 1 && v != 1 && v != -2) { + uint16 controlOffs = 0; + uint16 ctrSize = 0; + if (v) { + const byte *ctrStart = ptr; + while (v && v != -2) { + ptr++; + v = extractHofSeqData_isSequence(ptr, info, endOffs - ptr); + } + + if (v == -2) + break; + + ctrSize = (uint16)(ptr - ctrStart); + + if (info->special != kDemoVersion && + extractHofSeqData_isControl(ctrStart, ctrSize)) { + controlOffs = (uint16) (output - buffer); + *output++ = ctrSize >> 2; + + for (int cc = 0; cc < ctrSize; cc += 2) + WRITE_BE_UINT16(output + cc, READ_LE_UINT16(ctrStart + cc)); // frame control + output += ctrSize; + } + } + + numNestedSequences++; + uint16 relOffs = (uint16) (output - buffer); + WRITE_BE_UINT16(hdout, relOffs); + hdout++; + + WRITE_BE_UINT16(output, READ_LE_UINT16(ptr)); // flags + ptr += 2; + output += 2; + + memcpy(output, ptr, 14); // wsa file name + ptr += 14; + output += 14; + + // startframe + WRITE_BE_UINT16(output, READ_LE_UINT16(ptr)); + ptr += 2; + output += 2; + + // endFrame + WRITE_BE_UINT16(output, (ctrSize && ((ctrSize >> 2) < READ_LE_UINT16(ptr))) ? (ctrSize >> 2) : READ_LE_UINT16(ptr)); + ptr += 2; + output += 2; + + // frameDelay + WRITE_BE_UINT16(output, READ_LE_UINT16(ptr)); + ptr += 2; + output += 2; + + ptr += 4; + + for (int w = 0; w < 2; w++) { //x, y + WRITE_BE_UINT16(output, READ_LE_UINT16(ptr)); + ptr += 2; + output += 2; + } + + if (!READ_LE_UINT32(ptr)) + controlOffs = 0; + + WRITE_BE_UINT16(output, controlOffs); + if (info->special != kDemoVersion) + ptr += 4; + output += 2; + + if (info->special != kDemoVersion) { + for (int w = 0; w < 2; w++) { //startupCommand, finalCommand + WRITE_BE_UINT16(output, READ_LE_UINT16(ptr)); + ptr += 2; + output += 2; + } + } else { + memset(output, 0, 4); + output += 4; + } + + if (info->platform == kPlatformFMTowns) + ptr += 2; + + } else if (cycle == 0) { + while (v != 1 && v != -2) { + ptr++; + v = extractHofSeqData_isSequence(ptr, info, endOffs - ptr); + } + + if (v == -2) + break; + + + } else if (cycle == 1) { + while (v == 1 && v != -2) { + ptr++; + v = extractHofSeqData_isSequence(ptr, info, endOffs - ptr); + } + + if (v == -2) + break; + } + } + } + + uint16 finHeaderSize = (2 + numSequences + numNestedSequences) * sizeof(uint16); + uint16 finBufferSize = ((output - buffer) - headerSize) + finHeaderSize; + byte *finBuffer = new byte[finBufferSize]; + assert(finBuffer); + uint16 diff = headerSize - finHeaderSize; + uint16 *finHeader = (uint16*) finBuffer; + + for (int i = 1; i < finHeaderSize; i++) + WRITE_BE_UINT16(&finHeader[i], (READ_BE_UINT16(&header[i]) - diff)); + WRITE_BE_UINT16(finHeader, numSequences); + WRITE_BE_UINT16(&finHeader[numSequences + 1], numNestedSequences); + memcpy (finBuffer + finHeaderSize, buffer + headerSize, finBufferSize - finHeaderSize); + delete[] buffer; + + finHeader = (uint16*) (finBuffer + ((numSequences + 2) * sizeof(uint16))); + for (int i = 0; i < numNestedSequences; i++) { + uint8 * offs = finBuffer + READ_BE_UINT16(finHeader++) + 26; + uint16 ctrl = READ_BE_UINT16(offs); + if (ctrl) + ctrl -= diff; + WRITE_BE_UINT16(offs, ctrl); + } + + return out.addFile(filename, finBuffer, finBufferSize); +} + +int extractHofSeqData_checkString(const void *ptr, uint8 checkSize) { + // return values: 1 = text; 0 = zero string; -1 = other + + int t = 0; + int c = checkSize; + const uint8 *s = (const uint8*)ptr; + + // check for character string + while (c--) { + if (*s > 31 && *s < 123) + t++; + s++; + } + + if (t == checkSize) + return 1; + + // check for zero string + c = checkSize; + uint32 sum = 0; + s = (const uint8*)ptr; + while (c--) + sum += *s++; + + return (sum) ? -1 : 0; +} + +int extractHofSeqData_isSequence(const void *ptr, const ExtractInformation *info, uint32 maxCheckSize) { + // return values: 1 = Sequence; 0 = Nested Sequence; -1 = other; -2 = overflow + + if (maxCheckSize < 30) + return -2; + + const uint8 * s = (const uint8*)ptr; + int c1 = extractHofSeqData_checkString(s + 2, 6); + int c2 = extractHofSeqData_checkString(s + 16, 6); + int c3 = extractHofSeqData_checkString(s + 2, 14); + int c4 = extractHofSeqData_checkString(s + 16, 14); + int c0 = s[1]; + int c5 = s[0]; + + if (c0 == 0 && c5 && ((c1 + c2) >= 1) && (!(c3 == 0 && c2 != 1)) && (!(c4 == 0 && c1 != 1))) { + if (maxCheckSize < 41) + return -2; + + if (info->platform == kPlatformFMTowns) { + if (!(s[37] | s[39]) && s[38] > s[36]) + return 1; + } else { + if (!(s[39] | s[41]) && s[40] > s[38]) + return 1; + } + } + + if (c0 == 0 && c5 == 4 && c3 == 0 && c4 == 0) { + if (maxCheckSize >= 41 && READ_LE_UINT32(s + 34) && !(s[39] | s[41]) && s[40] > s[38]) + return 1; + } + + if (c0 == 0 && c5 && c1 == 1 && c4 == -1 && s[20]) + return 0; + + return -1; +} + +int extractHofSeqData_isControl(const void *ptr, uint32 size) { + // return values: 1 = possible frame control data; 0 = definitely not frame control data + + const uint8 *s = (const uint8*)ptr; + for (uint32 i = 2; i < size; i += 4) { + if (!s[i]) + return 0; + } + + for (uint32 i = 1; i < size; i += 2) { + if (s[i]) + return 0; + } + return 1; +} + +bool extractHofShapeAnimDataV1(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id) { + int outsize = 1; + uint8 *buffer = new uint8[size + 1]; + const uint8 *src = data; + uint8 *dst = buffer + 1; + + for (int i = 0; i < 4; i++) { + WRITE_BE_UINT16(dst, READ_LE_UINT16(src)); + src += 2; + dst += 2; + WRITE_BE_UINT16(dst, READ_LE_UINT16(src)); + src += 4; + dst += 2; + outsize += 4; + + for (int j = 0; j < 20; j++) { + WRITE_BE_UINT16(dst, READ_LE_UINT16(src)); + src += 2; + dst += 2; + outsize += 2; + } + + }; + + *buffer = 4; // number of items + + return out.addFile(filename, buffer, outsize); +} + +bool extractHofShapeAnimDataV2(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id) { + int outsize = 1; + uint8 *buffer = new uint8[size + 1]; + const uint8 *src = data; + uint8 *dst = buffer + 1; + const uint8 *fin = data + size; + int count = 0; + + do { + if (READ_LE_UINT16(src) == 0xffff) + break; + + count++; + + WRITE_BE_UINT16(dst, READ_LE_UINT16(src)); + src += 2; + dst += 2; + + uint8 numFrames = *src; + *dst++ = numFrames; + src += 6; + outsize += 3; + + for (int i = 0; i < (numFrames << 1); i++) { + WRITE_BE_UINT16(dst, READ_LE_UINT16(src)); + src += 2; + dst += 2; + outsize += 2; + } + + src += (48 - (numFrames << 2)); + + } while (src < fin); + + *buffer = count; // number of items + + return out.addFile(filename, buffer, outsize); +} + +bool extractStringsWoSuffix(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id) { + int outsize = size + 4; + uint8 *buffer = new uint8[outsize]; + const uint8 *src = data; + uint8 *dst = buffer + 4; + const uint8 *fin = src + size; + int entries = 0; + + while (src < fin) { + while (!*src && src < fin) + src++; + while (*src && *src != '.' && src < fin) + *dst++ = *src++; + + *dst++ = '\0'; + entries++; + + if (*src == '.') { + while (*src && src < fin) + src++; + } + } + + WRITE_BE_UINT32(buffer, entries); + outsize = dst - buffer; + + return out.addFile(filename, buffer, outsize); +} + +bool extractPaddedStrings(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id) { + int outsize = size + 4; + uint8 *buffer = new uint8[outsize]; + const uint8 *src = data; + uint8 *dst = buffer + 4; + const uint8 *fin = src + size; + int entries = 0; + + while (src < fin) { + while (!*src && src < fin) + src++; + while (*src && src < fin) + *dst++ = *src++; + + *dst++ = '\0'; + entries++; + } + + WRITE_BE_UINT32(buffer, entries); + outsize = dst - buffer; + + return out.addFile(filename, buffer, outsize); +} + +bool extractRaw16to8(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id) { + int outsize = size >> 1; + uint8 *buffer = new uint8[outsize]; + const uint8 *src = data; + uint8 *dst = buffer; + + for (int i = 0; i < outsize; i++) { + *dst++ = *src++; + src++; + } + + return out.addFile(filename, buffer, outsize); +} + +bool extractRaw16(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id) { + uint8 *buffer = new uint8[size]; + const uint8 *src = data; + uint8 *dst = buffer; + + for (uint32 i = 0; i < (size >> 1); i++) { + WRITE_BE_UINT16(dst, READ_LE_UINT16(src)); + src += 2; + dst += 2; + } + + return out.addFile(filename, buffer, size); +} + +bool extractRaw32(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id) { + uint8 *buffer = new uint8[size]; + const uint8 *src = data; + uint8 *dst = buffer; + + for (uint32 i = 0; i < (size >> 2); i++) { + WRITE_BE_UINT32(dst, READ_LE_UINT32(src)); + src += 4; + dst += 4; + } + + return out.addFile(filename, buffer, size); +} + +bool extractLolButtonDefs(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id) { + int num = size / 22; + uint8 *buffer = new uint8[size]; + uint32 outsize = num * 18; + const uint8 *src = data; + uint8 *dst = buffer; + + for (int i = 0; i < num; i++) { + WRITE_BE_UINT16(dst, READ_LE_UINT16(src)); + src += 2; dst += 2; + WRITE_BE_UINT16(dst, READ_LE_UINT16(src)); + src += 2; dst += 2; + WRITE_BE_UINT16(dst, READ_LE_UINT16(src)); + src += 6; dst += 2; + WRITE_BE_UINT16(dst, READ_LE_UINT16(src)); + src += 2; dst += 2; + WRITE_BE_UINT16(dst, READ_LE_UINT16(src)); + src += 2; dst += 2; + WRITE_BE_UINT16(dst, READ_LE_UINT16(src)); + src += 2; dst += 2; + WRITE_BE_UINT16(dst, READ_LE_UINT16(src)); + src += 2; dst += 2; + WRITE_BE_UINT16(dst, READ_LE_UINT16(src)); + src += 2; dst += 2; + WRITE_BE_UINT16(dst, READ_LE_UINT16(src)); + src += 2; dst += 2; + } + + return out.addFile(filename, buffer, outsize); +} + +bool extractMrShapeAnimData(PAKFile &out, const ExtractInformation *info, const byte *data, const uint32 size, const char *filename, int id) { + int outsize = 1; + uint8 *buffer = new uint8[size + 1]; + const uint8 *src2 = data; + const uint8 *src1 = data + 324; + uint8 *dst = buffer + 1; + const uint8 *fin = data + size; + int count = 0; + + do { + if (READ_LE_UINT16(src1) == 0xffff) + break; + + count++; + + WRITE_BE_UINT16(dst, READ_LE_UINT16(src1)); + src1 += 2; + dst += 2; + + uint8 numFrames = *src1; + *dst++ = numFrames; + src1 += 10; + outsize += 3; + + for (int i = 0; i < (numFrames << 1); i++) { + WRITE_BE_UINT16(dst, READ_LE_UINT16(src2)); + src2 += 2; + dst += 2; + outsize += 2; + } + } while (src1 < fin); + + *buffer = count; // number of items + + return out.addFile(filename, buffer, outsize); +} + +} // end of anonymous namespace + |