/*
**	Compress.c
**
**	Copyright (C) 1994,96,97 Bernardo Innocenti
**
**	Compression/Decompression handling functions.
*/

#include <exec/memory.h>
#include <utility/hooks.h>
#include <xpk/xpk.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/powerpacker.h>
#include <proto/xpkmaster.h>
#include <proto/xmodule.h>

#include "XModulePriv.h"
#include "Gui.h"


#define CTYPE_LHA		1
#define CTYPE_XPK		2
#define CTYPE_POWERPACKER	3


/* static struct Library *PPBase = NULL; */
static struct Library *XpkBase = NULL;


XDEF UBYTE LhACommand[64] = "LhA >NIL: e -x0 -q \"%s\"";
XDEF UBYTE TmpDir[PATHNAME_MAX] = "T:XModuleTmp";
XDEF UBYTE LhAFilter[64] = "~(#?readme#?|#?txt#?|#?display#?|#?fileid#?)";



static LONG HOOKCALL XPKProgressFunc (REG(a0,struct Hook *hook), REG(a1,struct XpkProgress *pr))
{
	return (DisplayProgress (pr->xp_UCur, pr->xp_ULen));
}



static struct Hook XPKProgressHook =
{
	{ NULL, NULL },
	XPKProgressFunc,
	NULL,
	0
};



GLOBALCALL BPTR DecompressFile (CONST_STRPTR name, UWORD type)

/* This function will try to decompress the given file and store
 * it in TmpDir.  If TmpDir does not exist, it will be created.
 * The decompressed file is then locked and returned.
 * A return value of NULL means failure.  Call DecompressFileDone()
 * when you are done with the decompressed file.
 */
{
	struct AnchorPath *ap;
	BPTR ret = 0;
	BPTR dir, olddir;
	LONG err = 0;
	UBYTE FullName[PATHNAME_MAX];


	OpenProgressWindow();

	DisplayAction (MSG_DECRUNCHING);

	/* Find the full path name of the given file */
	{
		BPTR lock;

		if (lock = Lock (name, ACCESS_READ))
		{
			if (!NameFromLock (lock, FullName, PATHNAME_MAX))
				err = IoErr();
			UnLock (lock);
		}
		else err = IoErr();
	}

	if (!err)
	{
		/* Try to lock or create TmpDir */

		if (!(dir = Lock (TmpDir, ACCESS_READ)))
		{
			if (dir = CreateDir (TmpDir))
				if (!(ChangeMode (CHANGE_LOCK, dir, ACCESS_READ)))
				{
					UnLock (dir);
					dir = NULL;
				}
		}

		if (dir)
		{
			olddir = CurrentDir (dir);

			switch (type)
			{
				case CTYPE_LHA:
				{
					UBYTE buf[64+PATHNAME_MAX];

					SPrintf (buf, LhACommand, FullName);
					if (!SystemTagList (buf, NULL))
					{
						if (ap = AllocMem (sizeof (struct AnchorPath) + PATHNAME_MAX, MEMF_CLEAR))
						{
							ap->ap_Strlen = PATHNAME_MAX;

							if (!(err = MatchFirst (LhAFilter, ap)))
							{
								if (!(ret = Lock (ap->ap_Buf, ACCESS_READ)))
									err = IoErr();
							}

							MatchEnd (ap);
							FreeMem (ap, sizeof (struct AnchorPath) + PATHNAME_MAX);
						}
						else err = ERROR_NO_FREE_STORE; /* Fail AllocMem() */

					}
					else err = IoErr(); /* Fail SystemTagList() */

					break;
				}

				case CTYPE_XPK:
				{
					UBYTE dest[PATHNAME_MAX];
					UBYTE errstring[XPKERRMSGSIZE];

					if (!(XpkBase = OpenLibrary ("xpkmaster.library", 2L)))
					{
						CantOpenLib ("xpkmaster.library", 2L);
						CloseProgressWindow();
						return 0;
					}

					strcpy (dest, TmpDir);
					if (AddPart (dest, "XPKTmp", PATHNAME_MAX))
					{
						if (XpkUnpackTags (
							XPK_InName,		FullName,
							XPK_OutName,	dest,
							XPK_GetError,	errstring,
							XPK_ChunkHook,	&XPKProgressHook,
							// XPK_TaskPri,	ThisTask->pr_Task.tc_Node.ln_Pri-1,
							TAG_DONE))
						{
							xmDisplayMessage (XMDMF_ERROR | XMDMF_USECATALOG,
								(APTR)MSG_ERROR_DECOMPRESSING, FilePart (FullName),
								errstring);
						}
						else ret = Lock (dest, ACCESS_READ);
					}

					CloseLibrary (XpkBase); XpkBase = NULL;
					break;
				}

/*	 			case CTYPE_POWERPACKER:

					if (!(PPBase = OpenLibrary ("powerpacker.library", 0L)))
					{
						CantOpenLib ("powerpacker.library", 0L);
						CloseProgressWindow();
						return 0;
					}

					xmDisplayMessageA (XMDMF_INFORMATION,
						"PowerPacker compressed files are not supported yet.", NULL);

					CloseLibrary (PPBase); PPBase = NULL;
*/
				default:
					break;
			}

			CurrentDir (olddir);
			UnLock (dir);
		}
		else err = IoErr(); /* Fail CreateDir() */
	}

	/* Report error */

	if (err)
	{
		if (err == ERROR_NO_MORE_ENTRIES)
			xmDisplayMessage (XMDMF_ERROR | XMDMF_USECATALOG,
				(APTR)MSG_NOTHING_IN_ARC, name);
		else
			xmDisplayMessageA (XMDMF_DOSFAULT | XMDMF_USECATALOG,
				(APTR)MSG_CANT_LOAD_COMPRESSED, NULL);
	}

	if (!ret) DecompressFileDone();

	CloseProgressWindow();

	return ret;
}



GLOBALCALL void DecompressFileDone (void)

/* This call releases all resources got by DecompressFile(). */
{
	BPTR dir, olddir;
	struct FileInfoBlock *fib;

	if (dir = Lock (TmpDir, ACCESS_READ))
	{
		olddir = CurrentDir (dir);

		if (fib = AllocDosObject (DOS_FIB, NULL))
		{
			if (Examine (dir, fib))
			{
				/* Delete all files in the temp directory */
				while (ExNext (dir, fib))
					DeleteFile (fib->fib_FileName);
			}

			FreeDosObject (DOS_FIB, fib);
		}

		CurrentDir (olddir);
		UnLock (dir);
	}

	DeleteFile (TmpDir);
}



GLOBALCALL LONG CruncherType (BPTR file)
{
	union
	{
		LONG fileid;
		struct
		{
			UWORD dummy;
			ULONG prefix;
		} lha;
	} id;

	if (Read (file, &id, sizeof (id)) != sizeof (id))
		return 0;

	if ((id.lha.prefix >> 8) == '-lh')
		return CTYPE_LHA;

	if (id.fileid == 'XPKF' || id.fileid == 'PP20' || id.fileid == 'PX20')
		return CTYPE_XPK;

	return 0;
}

