// PCompress Library
// Copyright (C) 1999 Britt Yenne
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU Library General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
// 
// To contact the author, visit:  http://www.jump.net/~syenne/pilot/

//
// This magic number and version number should be the first two
// bytes of any PCompress'ed file.
//
#define PCompMagic	0x6a
#define PCompVersion	0

//
// The "table" is the string cache.  A larger table means better compression
// but more memory requirement.  Note that an attempt to allocate 32k or
// more bytes on a loaded palmtop may always fail.  The string table
// size actually varies depending on compression level -- see the
// definition of levelParms in pcomp.c.  TableNil should be an invalid
// 16-bit table index for any compression level.
//
#define TableNil	65535

//
// MinMatch is the minimum string length to consider when looking for
// a match.  MaxMatch is the maximum string length we can match, as
// determined by the way we output a match.
//
#define MinMatch	4
#define MaxMatch	258

//
// The hash holds pointers into the string table based on a function
// calculated on the first MinMatch bytes of the string.
//
#define HashBits	11	// number of bits in hash index
#define HashSize	(1<<HashBits)
#define HashShift	((HashBits+MinMatch-1)/MinMatch)
#define HashMask	(HashSize-1)

//
// Long runs of the same character are treated specially.
//
// Why do anything with runs if the compression algorithm can
// actually do a better job if we don't do this?  The answer
// is performance.  Long runs just kill the string table loop,
// so we process runs manually to gain CPU cycles at the expense
// of a small bit of compression.  It really does work.  I've
// tried to take this out on three occasions... :-)
//
// Note that a desktop version of this program should disable
// RUN_HACK in order to get better compression, except that
// disabling RUN_HACK seems to hurt the compression stats.
// Something's weird...  I'll figure it out later.   XXX
// Maybe long runs in the string table make you hit the chain
// maximum before you analyze more than one reasonable match.
//
#define RUN_HACK

//
// Tokens.  All tokens in 0..255 are raw bytes of data.  Gzip actually
// uses individual tokens for each match length, which eliminates the need
// for a special TokMatch1 and TokMatch2.  I tried this, and the net win
// was about 1k for each 40k of input, at the cost of 2-4k of extra
// runtime memory for the expanded code, trees, and histogram arrays.
// I judged this to not be worth the complexity.  I'm guessing I can
// win more by using a special Huffman tree for match lengths and offsets
// later (memory permitting).
//
#define TokMatch1	0x100	// begins a copy of a string, 8bit offset
#define TokMatch2	0x101	// begins a copy of a string, 16bit offset
#define TokEOR		0x102	// end of record
#define TokEOS		0x103	// end of section
#define TokEOF		0x104	// end of file

#define TokLast		TokEOF

//
// The tree structure is for Huffman bitfield generation.  XXX is it
// really a win to optimize the space used by this tree versus the
// extra CPU time required to decode bitfields?
//
typedef struct {
  u32bit token : 10;	// token
  u32bit unused : 2;	// unused
  u32bit left : 10;	// left branch
  u32bit right: 10;	// right branch
} Tree;

#define TreeNil		1023
#define TreeMax		((2 * TokLast) + 1)	// max number of nodes

//
// The compression control structure.
//
typedef struct pCompCtl *PCompCtl;
struct pCompCtl {
  //
  // Callback functions for PCompress methods.
  //
  void*  (*Alloc)(u32bit);
  void	 (*Free)(void*);
  int	 (*Progress)(PCompCtl, s32bit);
  s32bit (*Flush)(PCompCtl, u8bit*, u16bit, Vector**);
  int	 (*NewRecord)(PCompCtl);
  int	 (*NewSection)(PCompCtl);
  s32bit (*GetChunk)(PCompCtl, u8bit**);

  //
  // Compression variables.
  //
  int level;		// compression level (0-9)
  u32bit *hist;		// token histogram array
  Tree *tree;		// token Huffman tree
  u16bit treeHead;	// head of Huffman tree
  u32bit *tokBits;	// token bitfield array
  u8bit *tokLen;	// token bitfield length array

  //
  // User-defined data.
  //
  void *userData;
};
