Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

extract.cpp

/* 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


Generated by  Doxygen 1.6.0   Back to index