#include "uade_tnplug.h"
#include <libraries/iffparse.h>
#include <proto/xpkmaster.h>
#include <proto/xfdmaster.h>
#include <ctype.h>

#define ID_XPKF MAKE_ID('X','P','K','F')

static BOOL IsValidID (uint32 id) {
	BOOL res = FALSE;
	if (isalnum(id >> 24) &&
		isalnum((id >> 16) & 0xff) &&
		isalnum((id >> 8) & 0xff) &&
		isalnum(id & 0xff))
	{
		res = TRUE;
	}
	dbug(("IsValidID: %ld\n", res));
	return res;
}

BOOL IsXPK (uint8 *testbuffer, int32 testsize) {
	BOOL res = FALSE;
	if (testbuffer && testsize > 0 && IXpk) {
		if (((uint32 *)testbuffer)[0] == ID_XPKF &&
			IsValidID(((uint32 *)testbuffer)[2]))
		{
			res = TRUE;
		}
	}
	dbug(("IsXPK: %ld\n", res));
	return res;
}

BOOL IsXFD (uint8 *testbuffer, int32 testsize) {
	BOOL res = FALSE;
	if (testbuffer && testsize > 0 && IXfd) {
		struct xfdBufferInfo *bi;
		BOOL xfd_res;
		bi = IXfd->xfdAllocObject(XFDOBJ_BUFFERINFO);
		if (bi) {
			bi->xfdbi_SourceBuffer = testbuffer;
			bi->xfdbi_SourceBufLen = testsize;
			bi->xfdbi_Flags = XFDFF_RECOGTARGETLEN|XFDFF_RECOGUSERTARGET;
			xfd_res = IXfd->xfdRecogBuffer(bi);
			IXfd->xfdFreeObject(bi);
			if (xfd_res) {
				res = TRUE;
			}
		}
	}
	dbug(("IsXFD: %ld\n", res));
	return res;
}

int32 IsCompressed (CONST_STRPTR filename) {
	if (IXpk || IXfd) {
		BPTR file;
		file = IDOS->Open(filename, MODE_OLDFILE);
		if (file) {
			uint8 testbuffer[8192];
			int32 testsize;
			testsize = IDOS->Read(file, testbuffer, sizeof(testbuffer));
			IDOS->Close(file);
			if (IsXPK(testbuffer, testsize)) {
				return FORMAT_XPK;
			}
			if (IsXFD(testbuffer, testsize)) {
				return FORMAT_XFD;
			}
			if (IsPT36(testbuffer, testsize)) {
				return FORMAT_PT36;
			}
		}
	}
	return FORMAT_RAW;
}

BOOL UnpackXPK (CONST_STRPTR infilename, CONST_STRPTR outfilename) {
	dbug(("UnpackXPK called.\n"));
	int32 res = IXpk->XpkUnpackTags(
		XPK_InName,  infilename,
		XPK_OutName, outfilename,
		TAG_END);
	return res == XPKERR_OK;
}

BOOL ReadFile (CONST_STRPTR filename, uint8 **buffer, int32 *size) {
	BPTR file;
	dbug(("ReadFile called.\n"));
	file = IDOS->Open(filename, MODE_OLDFILE);
	if (file) {
		*size = IDOS->GetFileSize(file);
		if (*size >= 0) {
			*buffer = IExec->AllocVecTags(*size,
				AVT_Type, MEMF_SHARED,
				AVT_Lock, FALSE,
				TAG_END);
			if (*buffer) {
				if (IDOS->Read(file, *buffer, *size) == *size) {
					IDOS->Close(file);
					return TRUE;
				}
				IExec->FreeVec(*buffer);
			}
		}
		IDOS->Close(file);
	}
	*buffer = NULL;
	*size = 0;
	return FALSE;
}

BOOL WriteFile (CONST_STRPTR filename, uint8 *buffer, int32 size) {
	BPTR file;
	BOOL res = FALSE;
	dbug(("WriteFile called.\n"));
	file = IDOS->Open(filename, MODE_NEWFILE);
	if (file) {
		if (IDOS->Write(file, buffer, size) == size) {
			res = TRUE;
		}
		IDOS->Close(file);
	}
	return res;
}

BOOL UnpackXFD (CONST_STRPTR infilename, CONST_STRPTR outfilename) {
	uint8 *inbuffer;
	int32 insize;
	BOOL res = FALSE;
	dbug(("UnpackXFD called.\n"));
	if (ReadFile(infilename, &inbuffer, &insize)) {
		struct xfdBufferInfo *bi;
		bi = IXfd->xfdAllocObject(XFDOBJ_BUFFERINFO);
		if (bi) {
			bi->xfdbi_SourceBuffer = inbuffer;
			bi->xfdbi_SourceBufLen = insize;
			bi->xfdbi_Flags = XFDFF_RECOGTARGETLEN|XFDFF_RECOGUSERTARGET;
			if (IXfd->xfdRecogBuffer(bi)) {
				uint8 *outbuffer;
				int32 outsize;
				outsize = bi->xfdbi_MinTargetLen;
				outbuffer = IExec->AllocVecTags(outsize,
					AVT_Type, MEMF_SHARED,
					AVT_Lock, FALSE,
					TAG_END);
				if (outbuffer) {
					bi->xfdbi_UserTargetBuf = outbuffer;
					bi->xfdbi_UserTargetBufLen = outsize;
					if (IXfd->xfdDecrunchBuffer(bi)) {
						if (WriteFile(outfilename, bi->xfdbi_TargetBuffer,
							bi->xfdbi_TargetBufSaveLen))
						{
							res = TRUE;
						}
					}
					IExec->FreeVec(outbuffer);
				}
			}
			IXfd->xfdFreeObject(bi);
		}
		IExec->FreeVec(inbuffer);
	}
	return res;
}

