/*! \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!");
}