/*! \brief Rewrites the header of the archive file * \param stk STK/ITK archive file * \param chunkCount Number of chunks * \param chunks List of chunks * * This function rewrites the header of the archive, replacing dummy values * by the one computed during execution. * The structure of the header is the following : * + 2 bytes : numbers of files archived in the .stk/.itk * Then, for each files : * + 13 bytes : the filename, terminated by '\0'. In original, there's * garbage after if the filename has not the maximum length * + 4 bytes : size of the chunk * + 4 bytes : start position of the chunk in the file * + 1 byte : If 0 : not compressed, if 1 : compressed * * The duplicate files are defined using the same information * as the one of the replacement file. */ void CompressGob::rewriteHeader(Common::File &stk, uint16 chunkCount, Chunk *chunks) { uint16 i; char buffer[1024]; Chunk *curChunk = chunks; stk.rewind(); buffer[0] = chunkCount & 0xFF; buffer[1] = chunkCount >> 8; stk.write(buffer, 2); // TODO : Implement STK21 while (curChunk) { for (i = 0; i < 13; i++) if (i < strlen(curChunk->name)) buffer[i] = curChunk->name[i]; else buffer[i] = '\0'; stk.write(buffer, 13); if (curChunk->packed == 2) { buffer[0] = curChunk->replChunk->size; buffer[1] = curChunk->replChunk->size >> 8; buffer[2] = curChunk->replChunk->size >> 16; buffer[3] = curChunk->replChunk->size >> 24; buffer[4] = curChunk->replChunk->offset; buffer[5] = curChunk->replChunk->offset >> 8; buffer[6] = curChunk->replChunk->offset >> 16; buffer[7] = curChunk->replChunk->offset >> 24; buffer[8] = curChunk->replChunk->packed; } else {
/*! \brief Write the body of the STK archive * \param stk STK/ITK archive file * \param chunks Chunk list * * This function writes the body of the STK archive by storing or compressing * (or skipping duplicate files) the files. It also updates the chunk information * with the size of the chunk in the archive, the compression method (if modified), * ... */ void CompressGob::writeBody(Common::Filename *inpath, Common::File &stk, Chunk *chunks) { Chunk *curChunk = chunks; Common::File src; while (curChunk) { inpath->setFullName(curChunk->name); src.open(*inpath, "rb"); if (curChunk->packed == 2) print("Identical file %12s\t(compressed size %d bytes)", curChunk->name, curChunk->replChunk->size); curChunk->offset = stk.pos(); if (curChunk->packed == 1) { curChunk->size = writeBodyPackFile(stk, src); if (curChunk->size >= curChunk->realSize) { // If compressed size >= realsize, compression is useless // => Store instead curChunk->packed = 0; stk.seek(curChunk->offset, SEEK_SET); src.rewind(); } else print("Compressing %12s\t%d -> %d bytes", curChunk->name, curChunk->realSize, curChunk->size); } if (curChunk->packed == 0) { curChunk->size = writeBodyStoreFile(stk, src); print("Storing %12s\t%d bytes", curChunk->name, curChunk->size); } curChunk = curChunk->next; } }
void ExtractZakC64::execute() { int i, j; unsigned short signature; char fname[256]; // Two disks... Common::Filename inpath1(_inputPaths[0].path); Common::Filename inpath2(_inputPaths[1].path); Common::Filename &outpath = _outputPath; if (outpath.empty()) // Standard output path outpath.setFullPath("out/"); Common::File input1(inpath1, "rb"); Common::File input2(inpath2, "rb"); /* check signature */ signature = input1.readUint16LE(); if (signature != 0x0A31) error("Signature not found in disk 1!"); signature = input2.readUint16LE(); if (signature != 0x0132) error("Signature not found in disk 2!"); outpath.setFullName("00.LFL"); Common::File output(outpath, "wb"); output.setXorMode(0xFF); print("Creating 00.LFL..."); /* write signature */ output.writeUint16LE(signature); /* copy object flags */ for (i = 0; i < 775; i++) output.writeByte(input1.readByte()); /* copy room offsets */ for (i = 0; i < NUM_ROOMS; i++) { room_disks_c64[i] = input1.readByte(); output.writeByte(room_disks_c64[i]); } for (i = 0; i < NUM_ROOMS; i++) { room_sectors_c64[i] = input1.readByte(); output.writeByte(room_sectors_c64[i]); room_tracks_c64[i] = input1.readByte(); output.writeByte(room_tracks_c64[i]); } /* copy costume offsets */ for (i = 0; i < 38; i++) output.writeByte(input1.readByte()); for (i = 0; i < 38; i++) output.writeUint16LE(input1.readUint16LE()); /* copy script offsets */ for (i = 0; i < 155; i++) output.writeByte(input1.readByte()); for (i = 0; i < 155; i++) output.writeUint16LE(input1.readUint16LE()); /* copy sound offsets */ for (i = 0; i < 127; i++) output.writeByte(input1.readByte()); for (i = 0; i < 127; i++) output.writeUint16LE(input1.readUint16LE()); output.close(); for (i = 0; i < NUM_ROOMS; i++) { Common::File *input; if (room_disks_c64[i] == '1') input = &input1; else if (room_disks_c64[i] == '2') input = &input2; else continue; sprintf(fname, "%02i.LFL", i); outpath.setFullName(fname); output.open(outpath, "wb"); print("Creating %s...", fname); input->seek((SectorOffset[room_tracks_c64[i]] + room_sectors_c64[i]) * 256, SEEK_SET); for (j = 0; j < ResourcesPerFile[i]; j++) { unsigned short len; do { len = input->readUint16LE(); output.writeUint16LE(len); } while (len == 0xffff); for (len -= 2; len > 0; len--) { output.writeByte(input->readByte()); } } input->rewind(); } print("All done!"); }
void ExtractMMApple::execute() { int i, j; unsigned short signature; char fname[256]; Common::Filename inpath1(_inputPaths[0].path); Common::Filename inpath2(_inputPaths[1].path); Common::Filename &outpath = _outputPath; if (outpath.empty()) // Standard output path outpath.setFullPath("out/"); Common::File input1(inpath1, "rb"); Common::File input2(inpath2, "rb"); input1.seek(142080, SEEK_SET); input2.seek(143104, SEEK_SET); /* check signature */ signature = input1.readUint16LE(); if (signature != 0x0A31) error("Signature not found in disk 1!"); signature = input2.readUint16LE(); if (signature != 0x0032) error("Signature not found in disk 2!"); outpath.setFullName("00.LFL"); Common::File output(outpath, "wb"); // All output should be xored output.setXorMode(0xFF); print("Creating 00.LFL...\n"); /* write signature */ output.writeUint16LE(signature); /* copy object flags */ for (i = 0; i < 256; i++) output.writeByte(input1.readByte()); /* copy room offsets */ for (i = 0; i < NUM_ROOMS; i++) { room_disks_apple[i] = input1.readByte(); output.writeByte(room_disks_apple[i]); } for (i = 0; i < NUM_ROOMS; i++) { room_sectors_apple[i] = input1.readByte(); output.writeByte(room_sectors_apple[i]); room_tracks_apple[i] = input1.readByte(); output.writeByte(room_tracks_apple[i]); } /* copy costume offsets */ for (i = 0; i < 25; i++) output.writeByte(input1.readByte()); for (i = 0; i < 25; i++) output.writeUint16LE(input1.readUint16LE()); /* copy script offsets */ for (i = 0; i < 160; i++) output.writeByte(input1.readByte()); for (i = 0; i < 160; i++) output.writeUint16LE(input1.readUint16LE()); /* copy sound offsets */ for (i = 0; i < 70; i++) output.writeByte(input1.readByte()); for (i = 0; i < 70; i++) output.writeUint16LE(input1.readUint16LE()); /* NOTE: Extra 92 bytes of unknown data */ for (i = 0; i < NUM_ROOMS; i++) { Common::File *input; if (room_disks_apple[i] == '1') input = &input1; else if (room_disks_apple[i] == '2') input = &input2; else continue; sprintf(fname, "%02i.LFL", i); outpath.setFullName(fname); output.open(outpath, "wb"); print("Creating %s...\n", fname); input->seek((SectorOffset[room_tracks_apple[i]] + room_sectors_apple[i]) * 256, SEEK_SET); for (j = 0; j < ResourcesPerFile[i]; j++) { unsigned short len = input->readUint16LE(); output.writeUint16LE(len); for (len -= 2; len > 0; len--) output.writeByte(input->readByte()); } input->rewind(); } print("All done!"); }