#include "lh5.h"
#include <time.h>
extern clock_t StrtTime,EndTime,TotTime; extern long NumTimes;

extern long WinSiz, HWinSiz, TotSiz, cursize;
long BCount=0, TotRd=0, CurRd;
char out_buf_adr[16384];
extern unsigned short *BfrPtr;
extern int NotInterruptedCall, ForceReturn;
extern char *archive_name;
/*
       Note!!!! make sure to change following to LZBuf[ HWinSiz ]
       and previous to out_buf_adr[ WinSiz ]
*/
unsigned short LZBuf[8192];

#define NP (DICBIT + 1)
#define NT (CODE_BIT + 3)
#define PBIT 4  /* smallest integer such that (1U << PBIT) > NP */
#define TBIT 5  /* smallest integer such that (1U << TBIT) > NT */
#if NT > NP
# define NPT NT
#else
# define NPT NP
#endif

FILE *arcfile;
ulong bitbuf;

extern unsigned int crccode;

int decoded;            /* for use in decode.c */
int   bitcount;

uint jb;  /* remaining bytes to copy */

ushort left[2 * NC - 1], right[2 * NC - 1];
uchar c_len[NC], pt_len[NPT];
uint  blocksize;
ushort c_table[4096], pt_table[256];

int read_pt_len(nn, nbit, i_special)
int nn;
int nbit;
int i_special;
{
   int i, c, n;
   uint mask;

   n = getbits(nbit);
   if (n == 0) {
      c = getbits(nbit);
      for (i = 0; i < nn; i++) pt_len[i] = 0;
      for (i = 0; i < 256; i++) pt_table[i] = c;
   } else {
      i = 0;
      while (i < n) {
         c = bitbuf >> (BITBUFSIZ - 3);
         if (c == 7) {
            mask = (unsigned) 1 << (BITBUFSIZ - 1 - 3);
            while (mask & bitbuf) {  mask >>= 1;  c++; }
         }
         fillbuf((c < 7) ? 3 : c - 3);
         pt_len[i++] = c;
         if (i == i_special) {
            c = getbits(2);
            while (--c >= 0) pt_len[i++] = 0;
         }
      }
      while (i < nn) pt_len[i++] = 0;
      make_table(nn, pt_len, 8, pt_table);
   }
}

int read_c_len()
{
   int i, c, n;
   uint mask;

   n = getbits(CBIT);
   if (n == 0) {
      c = getbits(CBIT);
      for (i = 0; i < NC; i++) c_len[i] = 0;
      for (i = 0; i < 4096; i++) c_table[i] = c;
   } else {
      i = 0;
      while (i < n) {
         c = pt_table[bitbuf >> (BITBUFSIZ - 8)];
         if (c >= NT) {
            mask = (unsigned) 1 << (BITBUFSIZ - 1 - 8);
            do {
               if (bitbuf & mask) c = right[c];
               else               c = left [c];
               mask >>= 1;
            } while (c >= NT);
         }
         fillbuf((int) pt_len[c]);
         if (c <= 2) {
            if      (c == 0) c = 1;
            else if (c == 1) c = getbits(4) + 3;
            else             c = getbits(CBIT) + 20;
            while (--c >= 0) c_len[i++] = 0;
         } else c_len[i++] = c - 2;
      }
      while (i < NC) c_len[i++] = 0;
      make_table(NC, c_len, 12, c_table);
   }
}

int huf_decode_start()
{
   init_getbits();  blocksize = 1;
}

BufRead()
{
        long n;
        if( TotRd < WinSiz ) {  CurRd = TotRd;  }
        else { TotRd -= WinSiz; CurRd = WinSiz; }
        n = fread( LZBuf, 1, CurRd, arcfile);
        if( n < 0 ) fatal_error(archive_name);
        if( CurRd != WinSiz && (CurRd & 1)) LZBuf[ CurRd>>1 ] &= 0xff00;
        BCount = 0;
}

int fillbuf(n)  /* Shift bitbuf n bits left, read n bits */
int n;
{
        bitbuf <<= n;
        bitcount += n;
        while ( bitcount >= 16) {
           bitcount -= 16;
           if( BCount == HWinSiz ) BufRead();
           bitbuf = (LZBuf[ BCount++] | ((bitbuf >> bitcount) & 0xffff0000)) << bitcount;
        }
}

uint getbits(n)
int n;
{
        uint x;

        x = bitbuf >> (BITBUFSIZ - n);  fillbuf(n);
        return x;
}

int fwrite_crc(p, n)
uchar *p;
int n;
{
        addbfcrc((char *) p, (unsigned) n);
}

int init_getbits()
{
        bitbuf = 0; bitcount = 32;
        fillbuf(0);
}

/* must call this before decoding each file */
int decode_start()
{
   huf_decode_start();
   jb = 0;
   decoded = 0;
}

/*
decode_lh5 decodes its input and sends it to output.
Should return error status or byte count, but currently
returns 0.
*/

int decode_lh5(infile, original_size, name)
FILE *infile;
long original_size;
char *name;
{
   long n;
   extern int decoded;
   arcfile = infile;             /* stream to be decoded */

   if( NotInterruptedCall ) { /* on 1st call with new internal file, reinit */
      gentab();
      crccode = 0;
      decode_start();
   }
   if (!decoded && cursize > 0) {
      if( cursize > WinSiz ) {
         n = decodeit( (uint) WinSiz, (uchar *)out_buf_adr);
      } else {
         n = decodeit( (uint) cursize, (uchar *)out_buf_adr);
      }
      /* n = count of chars decoded */
      fwrite_crc(out_buf_adr, n);
      bmov( out_buf_adr, BfrPtr, n );
/*      memcpy( BfrPtr, out_buf_adr, n ); */
      cursize -= n;
      TotSiz = n;
   }
   if( cursize > 0 ) ForceReturn = 1;
   NotInterruptedCall = 1; /* this will be set to 0 in main if ForceReturn=1 */
   return (int)crccode;
}
