/*

	MakeUEF by Thomas Harte 2000

	Distributed under the GPL - see 'Copying' for details

*/
#include "uef.h"
#include <stdio.h>
#include <string.h>

C_UEF::C_UEF(void)
{
	file = NULL;
}

C_UEF::~C_UEF(void)
{
	Close();
}

int C_UEF::GetVersion(void)
{
	return fminor | (fmajor << 8);
}

bool C_UEF::Open(char *name, char *mode, unsigned __int8 minor, unsigned __int8 major) //at present mode is ignored, as writing is disabled
{
	char testtext[10];

	Close();

	if(strcmp(mode, "r") && strcmp(mode, "w"))
		return true;

	if(!strcmp(mode, "r"))
	{
		input = true;

		if(file = gzopen(name, "rb"))
		{
			gzread(file, testtext, 10);
			if(!strcmp(testtext, "UEF File!"))
			{
				gzread(file, &fminor, 1);
				gzread(file, &fmajor, 1);

				if(fmajor > major)
				{
					gzclose(file);
					file = NULL;
					return true;
				}

				if(fminor > minor)
				{
					gzclose(file);
					file = NULL;
					return true;
				}

				Restart();

				return false;
			}

			gzclose(file);
			file = NULL;
			return true;
		}
		else
			return true;
	}
	else
	{
		input = false;

		if(file = gzopen(name, "wb9"))
		{
			sprintf(testtext, "UEF File!");
			gzwrite(file, testtext, 10);

			gzwrite(file, &minor, 1);
			gzwrite(file, &major, 1);

			return false;
		}
		else
			return true;
	}
}

bool C_UEF::Restart(void)
{
	if(input)
	{
		gzseek(file, 12, SEEK_SET);
		len_remaining = 0;
		FindNext();
		return false;
	}

	return true;
}

bool C_UEF::Close(void)
{
	if(file)
	{
		gzclose(file);
		file = NULL;
	}

	return false;
}

bool C_UEF::FindNext(void)
{
	int eofcheck;
	overeof = false;

	if(file && input)
	{
		while(1)
		{
			gzseek(file, len_remaining, SEEK_CUR);
			chunk_id.b.l = gzgetc(file);
			chunk_id.b.h = gzgetc(file);

			chunk_len.b.b0 = gzgetc(file);
			chunk_len.b.b1 = gzgetc(file);
			chunk_len.b.b2 = gzgetc(file);
			chunk_len.b.b3 = (eofcheck = gzgetc(file));
			len_remaining = chunk_len.a;

			if(eofcheck == -1)
			{
				overeof = true;
				gzseek(file, 12, SEEK_SET);
			}
			else
				break;
		}

		return false;
	}

	return true;
}

bool C_UEF::FindIdMajor(unsigned __int8 id)
{
	bool result;
	int eofc = 0;

	do
	{
		result = FindNext();
		if(overeof)
			eofc++;
	}
	while(!result && (eofc<2) && chunk_id.b.h != id);

	overeof = eofc ? true : false;

	return chunk_id.b.h == id;
}

bool C_UEF::FindId(unsigned __int16 id)
{
	bool result;
	int eofc = 0;

	do
	{
		result = FindNext();
		if(overeof)
			eofc++;
	}
	while(!result && (eofc<2) && chunk_id.a != id);

	return chunk_id.a == id;
}

unsigned __int32 C_UEF::GetLength(void)
{
	return chunk_len.a;
}

unsigned __int16 C_UEF::GetId(void)
{
	return chunk_id.a;
}

unsigned __int32 C_UEF::ReadSome(unsigned __int8 *ptr, unsigned __int32 length)
{
	unsigned __int32 olen_remaining = len_remaining;

	if(file && input)
	{
		if(length > len_remaining)
		{
			length = len_remaining;
		}

		len_remaining -= gzread(file, ptr, length);

		return olen_remaining - len_remaining;
	}
	else
		return 0;
}

unsigned __int32 C_UEF::ReadAll(unsigned __int8 *ptr)
{
	unsigned __int32 olen_remaining = len_remaining;

	if(file && input)
	{
		len_remaining -= gzread(file, ptr, len_remaining);

		return olen_remaining - len_remaining;
	}
	else
		return 0;
}

bool C_UEF::WriteChunk(unsigned __int16 id, unsigned __int32 len, unsigned __int8 *ptr)
{
	if(!input && file)
	{
		chunk_id.a = id;
		chunk_len.a = len;

		gzwrite(file, &chunk_id.b.l, 1);
		gzwrite(file, &chunk_id.b.h, 1);

		gzwrite(file, &chunk_len.b.b0, 1);
		gzwrite(file, &chunk_len.b.b1, 1);
		gzwrite(file, &chunk_len.b.b2, 1);
		gzwrite(file, &chunk_len.b.b3, 1);

		gzwrite(file, ptr, len);

		return false;
	}

	return true;
}

bool C_UEF::HasFile(void)
{
	return file != NULL;
}

bool C_UEF::EOC(void)
{
	return (!len_remaining);
}

bool C_UEF::OverRan(void)
{
	return overeof;
}
