/*
This product contains certain software code or other information
("AT&T Software") proprietary to AT&T Corp. ("AT&T").  The AT&T
Software is provided to you "AS IS".  YOU ASSUME TOTAL RESPONSIBILITY
AND RISK FOR USE OF THE AT&T SOFTWARE.  AT&T DOES NOT MAKE, AND
EXPRESSLY DISCLAIMS, ANY EXPRESS OR IMPLIED WARRANTIES OF ANY KIND
WHATSOEVER, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, WARRANTIES OF
TITLE OR NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS, ANY
WARRANTIES ARISING BY USAGE OF TRADE, COURSE OF DEALING OR COURSE OF
PERFORMANCE, OR ANY WARRANTY THAT THE AT&T SOFTWARE IS "ERROR FREE" OR
WILL MEET YOUR REQUIREMENTS.

Unless you accept a license to use the AT&T Software, you shall not
reverse compile, disassemble or otherwise reverse engineer this
product to ascertain the source code for any AT&T Software.

(c) AT&T Corp. All rights reserved.  AT&T is a registered trademark of AT&T Corp.

***********************************************************************

Description:

		The in-memory API to the XMill (de)compression routines

History:

      10/11/2002  - created by Hedzer Westra <hedzer@adlibsoft.com>

*/

#ifndef __XMILLAPI_H__
#define __XMILLAPI_H__

/* "conversion from 'size_t' to 'int', possible loss of data" */
#pragma warning (disable: 4267)

/* macros */
#ifndef min
#define min(x,y)  ( (x)>(y) ? (y) : (x))
#endif

/* defines */
#ifndef FALSE 
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif

/* general-purpose compression types */
#define XMILL_GPC_NONE             -1
#define XMILL_GPC_GZIP              0
#define XMILL_GPC_BZIP              1
#define XMILL_GPC_PPMDI             2

#define XMILL_GZIP_IDX              6		// default GZIP compression index (0-9)
#define XMILL_PPMDI_IDX             0     // default ppmdi compression index (0-(XMILL_PPMDI_IDXS-1))
#define XMILL_PPMDI_IDXS            19

/* error codes */
#define XMILL_ERR_NOMEM					1
#define XMILL_ERR_CORRUPT				2
#define XMILL_ERR_FILENOTFOUND		3
#define XMILL_ERR_IN_FILE				4
#define XMILL_ERR_NO_XMI				5
#define XMILL_ERR_CREATE_FAILED		6
#define XMILL_ERR_BLOCK_TOO_LARGE	7
#define XMILL_ERR_DECOMPRESS			8
#define XMILL_ERR_FATAL					9
#define XMILL_ERR_NO_COMPRESSOR		10
#define XMILL_ERR_PARSE					11
#define XMILL_ERR_WRITE					12
#define XMILL_ERR_ARGUMENTS			13
#define XMILL_ERR_CREATE				14
#define XMILL_ERR_READ					15
#define XMILL_ERR_ZLIB					16
#define XMILL_ERR_FILETOOLARGE		17
#define XMILL_ERR_XMIFILELARGER		18
#define XMILL_ERR_XMI_IS_XML			19
#define XMILL_ERR_XMILL_SYNTAX		20
#define XMILL_ERR_PRINTCOMPRESSOR	21
#define XMILL_ERR_NULL_POINTER		22

/* Init() types */
#define XMILL_INIT_INIT			1
#define XMILL_INIT_REINIT		2
#define XMILL_INIT_USERINIT	3

/* verbosity levels */
#define XMILL_VERBOSE_SILENT	0
#define XMILL_VERBOSE_ERR		1
#define XMILL_VERBOSE_WARN		2
#define XMILL_VERBOSE_STATS	3
#define XMILL_VERBOSE_ALL		4

/* file extensions */
#define XMILL_EXT_XMI			"xmi"
#define XMILL_EXT_XMILL			"xmill"

/* XML end markers */
#define XMILL_END_NONE	0		// no end-of-data found yet, data was cut off
#define XMILL_END_BLOCK	1		// end-of-block found, more data will follow
#define XMILL_END_DATA	2		// end-of-data, compression ends

/* XML output types */
#define XMILL_OUT_STRING_OR_FILE	0		// output XML as text in a string or file
#define XMILL_OUT_MSXML				1		// create an MSXML instance (WIN32 only)
#define XMILL_OUT_SAX				2		// SAX events (future)
#define XMILL_OUT_AIS_RECORD		3		// Adlib Information Systems special: convert adlibXML directly to a RECORD*
													// this code is not released!
#define XMILL_OUT_AIS_FILES		4		// Adlib Information Systems special: convert to a vector of files
													// this code is not released!

/* forward references */
class Session;
class Settings;
class Input;
class XMLOutput;
class XMLParse;
class Output;
class SAXClient;

/* XMillException struct and class headers */
#define ERRMSG_MAXLEN   8192   // The maximum length of all error messages together

struct ErrLine
{
   ErrLine  *next;
   char     line[1];
};

class XMillException
{
	ErrLine  *curerrline;
	char  errmsg[ERRMSG_MAXLEN+1];
	char  *curptr;
	char  *msgptr;
public:
	int code;

	XMillException(int code, char *str,int len=0);

	void Error(char *str,int len=0);   // Starts a new error msg
	void ErrorCont(char *str,int len=0);  // Continues the current error msg

	void PrintErrorMsg();   // Prints the current error messsages
	char *GetErrorMsg();

	void ResetErr();
};


/* utility functions */
int readfile(char *filename, char **buf, int *buflength);
char* str_save(char *str);

/* the XMill file & memory API class */
class XMill 
{
	SAXClient *saxclient;
	char saved_use_bzip;
	char **decompoutbuf;
	int *decompoutlen;

	int CompressIt(XMLParse *xmlparse, Output *output);
	void UncompressIt(Input *input, XMLOutput *output);

	void EndCompressBlock();
	void InitCompressIt();
	void InitCompressItRun();
	char CompressItRun(XMLParse *xmlparse);
	void EndCompressItRun(Output *output);
	void EndCompressIt();

	void FirstInit();

public:
	Session *session;
	Settings *settings;

	XMill(char *s);
	XMill(int outtype = XMILL_OUT_STRING_OR_FILE, bool lossy = true, 
				  char usebzip = XMILL_GPC_BZIP,
				  char **pathexpr = NULL, 
				  bool usedos = true, 
				  char igntype = 'n', bool ignore = true, 
				  int indenttype = -1, int indentcount = 1,
				  int gpcidx = XMILL_GZIP_IDX);
	~XMill();

	/* Call this for global (re-)initialization of XMill
	* default settings:
	*  lossy compression (drop all whitespace)
	*  no path expressions
	*  use CR/LF
	*  don't ignore PI/CDATA/comments/DOCTYPE
	*  use default indentation (1 space)
	*  zlib compression level XMILL_GZIP_IDX (6)
   * throws XMillException
	*/
	void Init(int outtype = XMILL_OUT_STRING_OR_FILE, char type = XMILL_INIT_INIT,
				  bool lossy = true, 
				  char usebzip = XMILL_GPC_BZIP,
				  char **pathexpr = NULL, 
				  bool usedos = true, 
				  char igntype = 'n', bool ignore = true, 
				  int indenttype = -1, int indentcount = 1,
				  int gpcidx = XMILL_GZIP_IDX,
				  bool copyxml = TRUE);

	/* read an .xmill file to memory
	   Max maxexprs-1 expressions are read; the list is terminated with a NULL char*.
	   The caller must free() all pathexprs char*'s when he/she is done compressing */
	static int readExprsFromFile(char *filename, char **pathexprs, int maxexprs, int *numexprs);

	/* memory operation, all throw XMillException */

	/* block operations */
	void InitCompress(char **outbuf, int *outlen, int *bytesread);
	void CompressBlock(char *inbuf, int inlen, int *endmarker);
	void EndCompress();
	/* compress an ASCIIZ XML buffer, or part of it */
	void Compress(char *inbuf, int inlen, char **outbuf, int *outlen, int *bytesread);

	/* block operations */
	void InitDecompress(char **outbuf, int *outlen, int *bytesread);
	void DecompressBlock(char *inbuf, int inlen, int *endmarker);
	void EndDecompress();
	/* decompress (part of) an XMI buffer to ASCIIZ XML */
	void Decompress(char *inbuf, int buflen, char **outbuf, int *outlen, int *bytesread);

	/* file operations */
	void Compress(char *srcfile, char *destfile);
	void Uncompress(char *sourcefile, char *destfile);

	/* get/set methods */
	void SetVerbose(char verb);
	void SetNoIncrease(bool inc = true);
	char GetCompressionMode();
};

#endif /* __XMILLAPI_H__ */
