#include "tn_ra.h"

#ifdef DEBUG
#define Fail(errorMsg) { dbug((errorMsg)); return 0; }
#else
#define Fail(errorMsg) return 0
#endif

static int GetCodec(unsigned char *buf, unsigned int *freq, unsigned int *chans,
	unsigned int *blocksize)
{
	int codec = 0;

	if (buf[0]=='.' && buf[1]=='r' && buf[2]=='a' && buf[3]==0xfd)
	{
		if (buf[5]==4)
		{
			int i;

			i = buf[56] + 58;
			if (buf[i]=='2' && buf[i+1]=='8' && buf[i+2]=='_' && buf[i+3]=='8') codec = 2;
			else if (buf[i]=='d' && buf[i+1]=='n' && buf[i+2]=='e' && buf[i+3]=='t') codec = 3;
//			else if (buf[i]=='s' && buf[i+1]=='i' && buf[i+2]=='p' && buf[i+3]=='r') codec = 4;

			*freq = (buf[48]<<8 | buf[49]);
			*chans = (buf[54]<<8 | buf[55]);
			*blocksize = (buf[24]<<24 | buf[25]<<16 | buf[26]<<8 | buf[27]);

			#if 0
			if (verbose)
			{
				int j;
				char *c, *s, *s2;

				s = buf + 57;
				j = buf[56] + 57;
				c = buf + j;
				j += *c + 1;
				*c = 0;
				s2 = c + 1;
				c = buf + j;
				*c = 0;
				FPrintf(StdErr, "Codec:     %s/%s (v%ld)\n", (ULONG)s, (ULONG)s2, (ULONG)codec);
				s = buf + 70;
				j = buf[69] + 70;
				c = buf + j;
				j += *c + 1;
				*c = 0;
				FPrintf(StdErr, "Title:     %s\n", (ULONG)s);
				s = c + 1;
				c = buf + j;
				j += *c + 1;
				*c = 0;
				FPrintf(StdErr, "Author:    %s\n", (ULONG)s);
				s = c + 1;
				c = buf + j;
				*c = 0;
				FPrintf(StdErr, "Copyright: %s\n\n", (ULONG)s);
			}
			#endif
		}
		else if (buf[5]==3)
		{
			codec = 1;
			*freq = 8000;
			*chans = (buf[8]<<8 | buf[9]);
			*blocksize = (buf[10]<<24 | buf[11]<<16 | buf[12]<<8 | buf[13]);

			#if 0
			if (verbose)
			{
				int j;
				char *c, *s;

				FPrintf(StdErr, "Codec:     14_4 (v%ld)\n", (ULONG)codec);
				s = buf + 23;
				j = buf[22] + 23;
				c = buf + j;
				j += *c + 1;
				*c = 0;
				FPrintf(StdErr, "Title:     %s\n", (ULONG)s);
				s = c + 1;
				c = buf + j;
				j += *c + 1;
				*c = 0;
				FPrintf(StdErr, "Author:    %s\n", (ULONG)s);
				s = c + 1;
				c = buf + j;
				*c = 0;
				FPrintf(StdErr, "Copyright: %s\n\n", (ULONG)s);
			}
			#endif
		}
	}

	return codec;
}

LONG ReadPackets(APTR inHandle, LONG (*ReadFunc)(APTR,APTR,LONG), unsigned char *buf,
	unsigned int chunksize, unsigned int *packets, unsigned short *streamid,
	unsigned short *rmf)
{
	LONG ret = 0;

	if (*rmf)
	{
		int i;
		unsigned short len, id;

		while ((ret < chunksize) && (*packets))
		{
			do {
				if (ReadFunc(inHandle, buf, 12) <= 0)
					Fail("Unexpected EOF or error while reading.");
				if (buf[0] != 0 || buf[1] != 0)
					Fail("Unsupported packet-version in RealMedia file!");

				len = (buf[2]<<8 | buf[3]) - 12;
				id = (buf[4]<<8 | buf[5]);

				if ((ret + len) > chunksize)
				{
					#if 0
					if (id == *streamid)
					{
						FPrintf(StdErr, "RealMedia packet won't fit in buffer, skipping...\n");
					}
					#endif

					i = chunksize - ret;

					while (len)
					{
						if (len < i) i = len;

						if (ReadFunc(inHandle, buf, i) <= 0)
							Fail("Unexpected EOF or error while reading.");
						len -= i;
					}

					i = 0;
				} else {
					if ((i = ReadFunc(inHandle, buf, len)) <= 0)
						Fail("Unexpected EOF or error while reading.");
				}

				--*packets;
			} while ((id != *streamid) && (*packets));

			if (id == *streamid)
			{
				ret += i;
				buf += i;
			}
		}
	} else {
		ret = ReadFunc(inHandle, buf, chunksize);
	}

	if ((ret > 0) && (ret < chunksize))
	{
		int i = chunksize - ret;

		/* Clear the rest of the buffer */
		memset(buf + ret, 0, i);
	}

	return ret;
}

int ReadHeader(APTR inHandle, LONG (*ReadFunc)(APTR,APTR,LONG), unsigned char *buf,
	unsigned int *freq, unsigned int *chans, unsigned int *blocksize, unsigned int *packets,
	unsigned short *streamid, unsigned short *rmf)
{
	int i;
	int codec = 0;
	unsigned char *in = buf;

	if ((i = ReadFunc(inHandle, in, 8)) <= 0) Fail("Unexpected EOF or error while reading.");
	in += i;

	if (buf[0]=='.' && buf[1]=='R' && buf[2]=='M' && buf[3]=='F')
	{
		int j;
		int size;
		int headers;

		*rmf = 1;
		size = (buf[4]<<24 | buf[5]<<16 | buf[6]<<8 | buf[7]) - 8;

		if ((i = ReadFunc(inHandle, in, size)) <= 0) Fail("Unexpected EOF or error while reading.");
		in += i;

		if (buf[8] != 0 || buf[9] != 0) Fail("Unsupported chunk-version in RealMedia file!");

		headers = (buf[14]<<24 | buf[15]<<16 | buf[16]<<8 | buf[17]);

		for (j=0; j<headers; j++)
		{
			in = buf;

			if ((i = ReadFunc(inHandle, in, 10)) <= 0) Fail("Unexpected EOF or error while reading.");
			in += i;

			if (buf[0]=='D' && buf[1]=='A' && buf[2]=='T' && buf[3]=='A')
			{
				if (ReadFunc(inHandle, in, 8) <= 0) Fail("Unexpected EOF or error while reading.");
				*packets = (in[0]<<24 | in[1]<<16 | in[2]<<8 | in[3]);

				break;
			}

			size = (buf[4]<<24 | buf[5]<<16 | buf[6]<<8 | buf[7]) - 10;

			if ((size + 10) > DATACHUNK2)
			{
				#if 0
				if (buf[0]=='M' && buf[1]=='D' && buf[2]=='P' && buf[3]=='R')
				{
					FPrintf(StdErr, "RealMedia MDPR-chunk won't fit in buffer, skipping...\n");
				}
				#endif

				i = DATACHUNK2 - 10;

				while (size)
				{
					if (size < i) i = size;

					if (ReadFunc(inHandle, buf, i) <= 0) Fail("Unexpected EOF or error while reading.");
					size -= i;
				}
			} else {
				if (ReadFunc(inHandle, in, size) <= 0) Fail("Unexpected EOF or error while reading.");

				#if 0
				if (verbose)
				{
					if (buf[0]=='C' && buf[1]=='O' && buf[2]=='N' && buf[3]=='T')
					{
						if (buf[8] == 0 && buf[9] == 0)
						{
							int j;
							char *c, *s;

							s = buf + 12;
							j = (buf[10]<<8) + buf[11] + 12;
							c = buf + j;
							j += (c[0]<<8) + c[1] + 2;
							*c = 0;
							FPrintf(StdErr, "Title:     %s\n", (ULONG)s);
							s = c + 2;
							c = buf + j;
							j += (c[0]<<8) + c[1] + 2;
							*c = 0;
							FPrintf(StdErr, "Author:    %s\n", (ULONG)s);
							s = c + 2;
							c = buf + j;
							j += (c[0]<<8) + c[1] + 2;
							*c = 0;
							FPrintf(StdErr, "Copyright: %s\n", (ULONG)s);
							s = c + 2;
							c = buf + j;
							*c = 0;
							FPrintf(StdErr, "Comment:   %s\n\n", (ULONG)s);
						}
					}
				}
				#endif

				if (buf[0]=='M' && buf[1]=='D' && buf[2]=='P' && buf[3]=='R')
				{
					if (codec) continue;
					if (buf[8] != 0 || buf[9] != 0) Fail("Unsupported chunk-version in RealMedia file!");

					*streamid = (buf[10]<<8 | buf[11]);

					i = buf[40] + 1;
					i += buf[40+i] + 1;
					in = buf+40+i+4;

					codec = GetCodec(in, freq, chans, blocksize);
				}
			}
		}
	} else if (buf[0]=='.' && buf[1]=='r' && buf[2]=='a' && buf[3]==0xfd) {
		if (buf[5]==4)
		{
			int size;

			if ((i = ReadFunc(inHandle, in, 14)) <= 0) Fail("Unexpected EOF or error while reading.");
			in += i;

			size = (buf[18]<<24 | buf[19]<<16 | buf[20]<<8 | buf[21]) - 6;

			if (ReadFunc(inHandle, in, size) <= 0) Fail("Unexpected EOF or error while reading.");

			codec = GetCodec(buf, freq, chans, blocksize);
		}
		else if (buf[5]==3)
		{
			in = buf + 8;

			while (buf[6])
			{
				if (ReadFunc(inHandle, in, 256) <= 0) Fail("Unexpected EOF or error while reading.");
			}

			if (ReadFunc(inHandle, in, buf[7]) <= 0) Fail("Unexpected EOF or error while reading.");

			codec = GetCodec(buf, freq, chans, blocksize);
		}
	} else {
		Fail("Unrecognized format!!!");
	}

	return codec;
}
