#ifndef XPKMASTER_XPKMASTER_H
#define XPKMASTER_XPKMASTER_H

/* Includeheader

	Name:		xpkmaster.h
	Main:		xpkmaster
	Versionstring:	$VER: xpkmaster.h 1.15 (13.09.1998)
	Author:		SDI
	Distribution:	Freeware
	Description:	Master library global definitions and declarations
			and prototypes

 1.0   05.10.96 : first real version
 1.1   27.12.96 : removed library protos - call now via library interface,
 	allows patching
 1.2   30.01.97 : change of cchecksum proto
 1.3   31.01.97 : checksum changed again
 1.4   01.03.97 : added new flags
 1.5   08.03.97 : changed XpkBuffer a bit
 1.6   31.03.97 : some little corrections
 1.7   02.04.97 : removed obsolete stuff
 1.8   12.04.97 : added DebugTagList
 1.9   14.08.97 : fixed defines
 1.10  20.12.97 : changed a lot in defines and structures
 1.11  09.01.98 : added better key-fields to xbuf
 1.12  24.01.98 : removed PP support --> done by xfdmaster now
 1.13  21.02.98 : added code independence
 1.14  25.06.98 : now uses SDI_compiler.h
 1.15  13.09.98 : added seek, removed Powerpacker completely
*/

#define A4SUPP
#define A4SUPP2
#define A4PROTO

#ifndef XPK_ALLINONE /* This allows some optimizations, when All.c is used */
  #define XPK_ALLINONE
#endif

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>

#include <xpk/xpk.h>
#include <xpk/xpksub.h>

#include <emul/emulinterface.h>
#include <emul/emulregs.h>
#include <public/proto/libamiga/amiga_protos.h>

#define M68C5(func, rt, name, t1, v1, r1, t2, v2, r2, t3, v3, r3, t4, v4, r4, t5, v5, r5)  \
({                                                              \
   struct EmulCaos MyCaos;                                      \
      rt _##name##_re;                                          \
      MyCaos.reg_##r1           = (ULONG) (v1);                 \
      MyCaos.reg_##r2           = (ULONG) (v2);                 \
      MyCaos.reg_##r3           = (ULONG) (v3);                 \
      MyCaos.reg_##r4           = (ULONG) (v4);                 \
      MyCaos.reg_##r5           = (ULONG) (v5);                 \
      MyCaos.caos_Un.Function   = (APTR) (func);                \
      _##name##_re = (rt) (*MyEmulHandle->EmulCall68k)(&MyCaos);\
      _##name##_re;                                             \
})

#define M68C3(func, rt, name, t1, v1, r1, t2, v2, r2, t3, v3, r3)  \
({                                                              \
   struct EmulCaos MyCaos;                                      \
      rt _##name##_re;                                          \
      MyCaos.reg_##r1           = (ULONG) (v1);                 \
      MyCaos.reg_##r2           = (ULONG) (v2);                 \
      MyCaos.reg_##r3           = (ULONG) (v3);                 \
      MyCaos.caos_Un.Function   = (APTR) (func);                \
      _##name##_re = (rt) (*MyEmulHandle->EmulCall68k)(&MyCaos);\
      _##name##_re;                                             \
})

#define CallRecogHook(func, buffer, filename, size, len, tag) \
	M68C5(func, struct XpkTypeData *, RecogFunc, STRPTR, buffer, a0, STRPTR, filename, a1, ULONG, size, d0, ULONG, len, d1, struct TagItem *, tag, a2)

#define CallRegHook(func, hook, msg, data) \
	M68C3(func, ULONG, regfunc, struct Hook *, hook, a0, APTR, msg, a1, APTR, data, a2)

#define REGFUNC_HOOK(name, arg) \
	static LONG name##_GATE(void); \
	static LONG name##func(arg); \
	struct EmulLibEntry name = { TRAP_LIB, 0, (void (*)(void))name##_GATE }; \
	static LONG name##_GATE(void) { return (name##func((void *)REG_A1)); } \
	struct Hook name##hook = { NULL, NULL, (void *)&name, NULL, NULL }; \
	static LONG name##func(arg)

#define ROUNDLONG(x)		(((x)+3)&(~3))	/* round to next longword */
#define DEFAULTCHUNKSIZE	0x8000

#ifndef Min
  #define Min(a,b) ((a) < (b) ? (a) : (b))
  #define max(a,b) ((a) > (b) ? (a) : (b))
#endif

/* The structure used for I/O, special master library version */
struct XpkMasterMsg {
  ULONG  xmm_Type;		/* Read/Write/Alloc/Free/Abort		*/
  STRPTR xmm_Ptr;		/* The mem area to read from/write to	*/
  LONG   xmm_Size;		/* The size of the read/write		*/
  ULONG  xmm_IOError;		/* The IoErr() that occurred		*/
  ULONG  xmm_Reserved;		/* Reserved for future use		*/
  STRPTR xmm_Buf;		/* Specific to the internal hooks	*/
  LONG   xmm_Error;		/* The XPKERR that occurred		*/
  ULONG  xmm_BufLen;
  ULONG  xmm_BufOfs;
  ULONG  xmm_Len;
  ULONG  xmm_Flags;
  ULONG  xmm_FH;
  ULONG  xmm_MemType;
  STRPTR xmm_FileName;
}__attribute__((packed));

#define XIO_GETOUTBUF 1		/* flag for xmm_Flags - allocate buffer	*/

/* These structures define the file format for compressed streams */
struct XpkStreamHeader {
  ULONG xsh_Pack;
  ULONG xsh_CLen;
  ULONG xsh_Type;
  ULONG xsh_ULen;
  UBYTE xsh_Initial[16];
  UBYTE xsh_Flags;
  UBYTE xsh_HChk;
  UBYTE xsh_SubVrs;
  UBYTE xsh_MasVrs;
}__attribute__((packed));

#define XPK_COOKIE	0x58504b46	/* 'XPKF' - ID for xsh_Pack */
#define ROW_OF_MINUS	0x2d2d2d2d	/* '----' */
#define XFD_COOKIE	0x58464444	/* 'XFDD' */
#define USER_COOKIE	0x55534552	/* 'USER' */

#define XPKSTREAMF_LONGHEADERS  0x01	/* Use XpkLongLocHeaders	*/
#define XPKSTREAMF_PASSWORD     0x02	/* This file encoded		*/
#define XPKSTREAMF_EXTHEADER    0x04	/* Extended globhdr		*/

struct XpkChunkHdrWord {
  UBYTE xchw_Type;
  UBYTE xchw_HChk;
  UWORD xchw_CChk;
  UWORD xchw_CLen;
  UWORD xchw_ULen;
}__attribute__((packed));

struct XpkChunkHdrLong {
  UBYTE xchl_Type;
  UBYTE xchl_HChk;
  UWORD xchl_CChk;
  ULONG xchl_CLen;
  ULONG xchl_ULen;
}__attribute__((packed));

typedef union __attribute__((packed)) {
  struct XpkChunkHdrLong xch_Long;
  struct XpkChunkHdrWord xch_Word;
} XpkChunkHeader;

#define XPKCHUNK_RAW		0x00 /* raw copy of source */
#define XPKCHUNK_PACKED		0x01 /* packed data */
#define XPKCHUNK_END		0x0F /* empty end Chunk */

struct Headers {
  struct XpkStreamHeader h_Glob;
  XpkChunkHeader	 h_Loc;
  ULONG			 h_LocSize;
}__attribute__((packed));

#define XPKMODE_UPUP    1
#define XPKMODE_UPSTD   2
#define XPKMODE_UPPP    3
#define XPKMODE_UPXFD	4
#define XPKMODE_PKSTD  20

#define AUTO_PASS_SIZE	50

struct SeekData {
  ULONG sd_FilePos;
  ULONG sd_ULen;
  ULONG sd_CLen;
}__attribute__((packed));

#define SEEKENTRYNUM	10

struct SeekDataList {
  struct SeekDataList *	sdl_Next;
  ULONG			sdl_Used;
  struct SeekData	sdl_Data[SEEKENTRYNUM];
}__attribute__((packed));

/* This is what XPK "handles" really point to */
struct XpkBuffer {
  struct XpkFib	xb_Fib;		/* file info about this file		*/
  UWORD   xb_PackingMode;	/* desired packing efficiency, 0..100   */
  struct Headers xb_Headers;	/* global and local file header 	*/
  ULONG   xb_Format;		/* type of file				*/
  LONG    xb_Result;		/* error code from last call		*/
  STRPTR  xb_ErrBuf;		/* Where user wants the error		*/
  STRPTR *xb_GetOutBuf;		/* Where user wants the out buf addr	*/
  ULONG  *xb_GetOutLen;		/* Where user wants the output len	*/
  ULONG  *xb_GetOutBufLen;	/* Where user wants the out buf len	*/
  ULONG   xb_Secs;		/* Start time, the seconds		*/
  ULONG   xb_Mics;		/* Start time, the micros		*/
  struct Hook * xb_RHook;	/* input data hook			*/
  struct Hook * xb_WHook;	/* output data hook			*/
  struct Hook * xb_ChunkHook;	/* Hook to call between chunks		*/
  STRPTR  xb_Password;		/* password for de/encoding		*/
  ULONG   xb_PasswordSize;	/* password buffer size for own password*/
  ULONG   xb_PassKey32;		/* password key, 32 bit			*/
  UWORD   xb_PassKey16;		/* password key, 16 bit			*/
  WORD    xb_Priority;		/* task pri during packing		*/
  ULONG   xb_SubID;		/* currently active sub ID		*/
  ULONG   xb_ChunkSize;		/* Chunk size to use for packing	*/
  ULONG   xb_FirstChunk;	/* First chunk size - largest chunk	*/
  ULONG   xb_Flags;		/* private for xpkmaster		*/
  ULONG   xb_InLen;		/* Number of bytes to (un)pack		*/
  ULONG   xb_UCur;		/* Current Uncrunched size (next chunk)	*/
  ULONG   xb_CCur;		/* Current Crunched size (next chunk)	*/
  LONG	  xb_InBufferPos;	/* buffer position for seek		*/
  STRPTR  xb_LastMsg;		/* The last progress message		*/
  struct xfdBufferInfo * xb_xfd;/* xfdBufferInfo			*/
  struct XpkInfo * xb_SubInfo;	/* Info of current open sub-lib		*/
  struct Library * xb_SubBase;	/* Currently open sub-library		*/
  struct XpkMasterMsg xb_RMsg;	/* Parameters for reading		*/
  struct XpkMasterMsg xb_WMsg;	/* Parameters for writing		*/
  struct XpkSubParams xb_PackParam;/* Parameters to (Un)PackChunk()	*/
  struct XpkProgress  xb_Prog;	/* Parameters to progress report	*/
  struct SeekDataList * xb_SeekDataList; /* this is used for seek	*/
}__attribute__((packed));

/* Values for MasterFlags */
#define XMF_PRIVFH	(1<< 0)	/* We opened the FH, so we close it.	*/
#define XMF_PACKING	(1<< 1)	/* This is a packing operation.		*/
#define XMF_PASSTHRU	(1<< 2)	/* Pass uncompressed data through	*/
#define XMF_GETOUTBUF	(1<< 3)	/* Get output buffer when size known	*/
#define XMF_NOCLOBBER	(1<< 4)	/* Don't overwrite			*/
#define XMF_EOF		(1<< 5)	/* End of file				*/
#define XMF_INITED	(1<< 6)	/* Sublib buffers have been allocted	*/
#define XMF_GLOBHDR	(1<< 7)	/* GlobHdr is already written		*/
#define XMF_LOSSYOK	(1<< 8)	/* Lossy compression permitted		*/
#define XMF_OWNTASKPRI	(1<< 9) /* Altered task pri, restore		*/
#define XMF_NOCRC	(1<<10)	/* Do not check the checksum on decomp	*/
#define XMF_NOPREFS	(1<<11) /* Are prefs allowed ?			*/
#define XMF_XFD		(1<<12) /* Is XFD unpacking allowed ?		*/
#define XMF_EXTERNALS	(1<<13) /* Is extern allowed ?			*/
#define XMF_AUTOPASSWD	(1<<14) /* Automatic password			*/
#define XMF_AUTOPRHOOK  (1<<15) /* Automatic Progress hook		*/
#define XMF_NOPACK	(1<<16) /* destination file equals source	*/
#define XMF_OWNPASSWORD (1<<17) /* free password buffer later !!!	*/
#define XMF_KEY16	(1<<18) /* got a 16 bit key (needed, as key may */
#define XMF_KEY32	(1<<19) /* got a 32 bit key  be 0 - no check)   */
#define XMF_SEEK	(1<<20)	/* we need to built seek buffers	*/

#ifdef DEBUG
void 	DebugError(STRPTR, ...);			/* debug.c */
void 	DebugRunTime(STRPTR, ...);			/* debug.c */
void    DebugTagList(STRPTR, struct TagItem *);		/* debug.c */
#endif

extern struct DosLibrary       *DOSBase;		/* libinit.a */
extern struct Hook		fhinhook;		/* hook_fh.c */
extern struct Hook		fhouthook;		/* hook_fh.c */
extern struct IntuitionBase    *IntuitionBase;		/* libinit.a */
extern struct Hook		meminhook;		/* hook_mem.c */
extern struct Hook		memouthook;		/* hook_mem.c */
extern struct ExecBase         *SysBase;		/* libinit.a */
extern struct UtilityBase      *UtilityBase;		/* libinit.a */
extern struct Library	       *XpkBase;		/* libinit.a */

XPK_ALLINONE LONG	addseek(struct XpkBuffer *);
XPK_ALLINONE LONG	callprogress(struct XpkBuffer *);			/* progress.c */
XPK_ALLINONE UWORD	cchecksum(ULONG *, ULONG);				/* checksum.c */
XPK_ALLINONE void	closesub(struct XpkBuffer *);				/* sublibs.c */
XPK_ALLINONE LONG	freebufs(struct XpkBuffer *);				/* xbuf.h */
XPK_ALLINONE void	freeseek(struct XpkBuffer *);
XPK_ALLINONE struct XpkPrefsSemaphore *	GetPrefsSem(void);			/* objects.c */
XPK_ALLINONE void	getUClen(struct XpkBuffer *, LONG *, LONG *);
XPK_ALLINONE UBYTE	hchecksum(STRPTR, ULONG);				/* checksum.c */
XPK_ALLINONE APTR	hookread(struct XpkBuffer *, ULONG, APTR, LONG);	/* hook.c */
XPK_ALLINONE APTR	hookwrite(struct XpkBuffer *, ULONG, APTR, LONG);	/* hook.c */
XPK_ALLINONE ULONG	idfromname(STRPTR);					/* sublibs.c */
XPK_ALLINONE struct XpkBuffer *		initxbuf(void);				/* xbuf.h */
XPK_ALLINONE struct Library *		opensub(struct XpkBuffer *, ULONG);	/* sublibs.c */
XPK_ALLINONE LONG	parsebuftags(struct XpkBuffer*, struct TagItem*);	/* tags.c */
XPK_ALLINONE LONG	parseerrortags(struct TagItem *, LONG);			/* tags.c */
XPK_ALLINONE void	parsegettags(struct XpkBuffer *);			/* tags.c */
XPK_ALLINONE void	percentages(struct XpkFib *);				/* fib.c */
XPK_ALLINONE LONG	updatefib(struct XpkBuffer *);				/* fib.c */
XPK_ALLINONE LONG	xpkopen(struct XpkBuffer **, struct TagItem *, ULONG);	/* open.c */

LONG  LIBXpkExamine(void);
LONG  LIBXpkPack(void);
LONG  LIBXpkUnpack(void);
LONG  LIBXpkOpen(void);
LONG  LIBXpkRead(void);
LONG  LIBXpkWrite(void);
LONG  LIBXpkSeek(void);
LONG  LIBXpkClose(void);
LONG  LIBXpkQuery(void);
APTR  LIBXpkAllocObject(void);
void  LIBXpkFreeObject(void);
BOOL  LIBXpkPrintFault(void);
ULONG LIBXpkFault(void);
LONG  LIBXpkPassRequest(void);

#endif /* XPKMASTER_XPKMASTER_H */
