/* ProWizard
 * Copyright (C) 1997 Sylvain "Asle" Chipaux
 * Modified in 2006,2007,2014 by Claudio Matsuoka
 * Modified in 2020 by Alice Rowan
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/*
 * gmc.c
 *
 * Depacks musics in the Game Music Creator format and saves in ptk.
 */

#include "prowiz.h"


static int depack_GMC(HIO_HANDLE *in, FILE *out)
{
	uint8 tmp[1024];
	uint8 ptable[128];
	uint8 max;
	uint8 pat_pos;
	uint16 len, looplen;
	long ssize = 0;
	long i = 0, j = 0;

	memset(ptable, 0, sizeof(ptable));

	pw_write_zero(out, 20);			/* title */

	for (i = 0; i < 15; i++) {
		pw_write_zero(out, 22);		/* name */
		hio_read32b(in);		/* bypass 4 address bytes */
		len = hio_read16b(in);
		write16b(out, len);		/* size */
		ssize += len * 2;
		hio_read8(in);
		write8(out, 0);			/* finetune */
		write8(out, hio_read8(in));	/* volume */
		hio_read32b(in);		/* bypass 4 address bytes */

		looplen = hio_read16b(in);	/* loop size */
		write16b(out, looplen > 2 ? len - looplen : 0);
		write16b(out, looplen <= 2 ? 1 : looplen);
		hio_read16b(in);		/* always zero? */
	}

	memset(tmp, 0, 30);
	tmp[29] = 0x01;
	for (i = 0; i < 16; i++)
		fwrite(tmp, 30, 1, out);

	hio_seek(in, 0xf3, 0);
	write8(out, pat_pos = hio_read8(in));	/* pattern list size */
	write8(out, 0x7f);			/* ntk byte */

	/* read and write size of pattern list */
	/*printf ( "Creating the pattern table ... " ); */
	for (i = 0; i < 100; i++)
		ptable[i] = hio_read16b(in) / 1024;
	fwrite(ptable, 128, 1, out);

	/* get number of pattern */
	for (max = i = 0; i < 128; i++) {
		if (ptable[i] > max)
			max = ptable[i];
	}

	/* write ID */
	write32b(out, PW_MOD_MAGIC);

	/* pattern data */
	hio_seek(in, 444, SEEK_SET);
	for (i = 0; i <= max; i++) {
		memset(tmp, 0, sizeof(tmp));
		hio_read(tmp, 1024, 1, in);
		for (j = 0; j < 256; j++) {
			switch (tmp[(j * 4) + 2] & 0x0f) {
			case 3:	/* replace by C */
				tmp[(j * 4) + 2] += 0x09;
				break;
			case 4:	/* replace by D */
				tmp[(j * 4) + 2] += 0x09;
				break;
			case 5:	/* replace by B */
				tmp[(j * 4) + 2] += 0x06;
				break;
			case 6:	/* replace by E0 */
				tmp[(j * 4) + 2] += 0x08;
				break;
			case 7:	/* replace by E0 */
				tmp[(j * 4) + 2] += 0x07;
				break;
			case 8:	/* replace by F */
				tmp[(j * 4) + 2] += 0x07;
				break;
			default:
				break;
			}
		}
		fwrite(tmp, 1024, 1, out);
	}

	/* sample data */
	pw_move_data(out, in, ssize);

	return 0;
}

static int test_GMC(const uint8 *data, char *t, int s)
{
	int i, j, k;
	int ssize, numpat;

	PW_REQUEST_DATA(s, 1024);

#if 0
	/* test #1 */
	if (i < 7) {
		return -1;
	}
	start = i - 7;
#endif

	/* samples descriptions */
	ssize = 0;
	for (i = 0; i < 15; i++) {
		int len, lsize;
		const uint8 *d = data + 16 * i;

		/* volumes */
		if (d[7] > 0x40)
			return -1;

		len = readmem16b(d + 4) << 1;
		lsize = readmem16b(d + 12);

		/* size */
		if (len > 0xffff)
			return -1;

		if (lsize > len)
			return -1;

		ssize += len;
	}
	if (ssize <= 4)
		return -1;

	/* pattern table size */
	if (data[243] > 0x64 || data[243] == 0)
		return -1;

	/* pattern order table */
	numpat = 0;
	for (i = 0; i < 100; i++) {
		k = readmem16b(data + 244 + i * 2);
		if (k & 0x03ff)
			return -1;
		if ((k >> 10) > numpat)
			numpat = k >> 10;
	}
	numpat++;

	if (numpat == 1 || numpat > 100)
		return -1;

	PW_REQUEST_DATA(s, 444 + k * 1024 + i * 4 + 3);

	/* test pattern data */
	for (i = 0; i < numpat; i++) {
		for (j = 0; j < 256; j++) {
			int offset = 444 + i * 1024 + j * 4;
			const uint8 *d;

			PW_REQUEST_DATA(s, offset + 4);

			d = &data[offset];

			if (offset > (PW_TEST_CHUNK - 4))
				return -1;

#if 0
			/* First test fails with Jumping Jackson */
			/* Second test never succeeds! */
			if (/*d[0] > 0x03 ||*/ (d[2] & 0x0f) >= 0x90)
				return -1;
#endif

#if 0
			/* Test fails with Jumping Jackson */
			/* x is the highest jot jull sample */
			if (((d[2] & 0xf0) >> 4) > x)
				return -1;
#endif
			if ((d[2] & 0x0f) == 3 && d[3] > 0x40)
				return -1;

			if ((d[2] & 0x0f) == 4 && d[3] > 0x63)
				return -1;

			if ((d[2] & 0x0f) == 5 && d[3] > (data[243] + 1))
				return -1;

			if ((d[2] & 0x0f) == 6 && d[3] >= 0x02)
				return -1;

			if ((d[2] & 0x0f) == 7 && d[3] >= 0x02)
				return -1;
		}
	}

	pw_read_title(NULL, t, 0);

	return 0;
}

const struct pw_format pw_gmc = {
	"Game Music Creator",
	test_GMC,
	depack_GMC
};
