/***********************************************************
    shuf.c -- extract static Huffman coding
***********************************************************/
#include <stdio.h>
#include "slidehuf.h"
#ifdef __STDC__
#include <stdlib.h>
#endif

#define N1 286  /* alphabet size */
#define N2 (2 * N1 - 1)  /* # of nodes in Huffman tree */
#define EXTRABITS 8
/* >= log2(F-THRESHOLD+258-N1) */
#define BUFBITS  16  /* >= log2(MAXBUF) */
#define LENFIELD  4  /* bit size of length field for tree output */
#define NP (8 * 1024 / 64)
#define NP2 (NP * 2 - 1)

static unsigned int np;

void decode_start_st0()
{
    n_max = 286;
    maxmatch = MAXMATCH;
    init_getbits();
    np = 1 << (MAX_DICBIT - 6);
}

void encode_p_st0(j)
unsigned short j;
{
    unsigned short i;

    i = j >> 6;
    putcode(pt_len[i], pt_code[i]);
    putbits(6, j & 0x3f);
}

int fixed[2][16] = {
    {3, 0x01, 0x04, 0x0c, 0x18, 0x30, 0},               /* old compatible */
    {2, 0x01, 0x01, 0x03, 0x06, 0x0D, 0x1F, 0x4E, 0}    /* 8K buf */
};

static void ready_made(method)
int method;
{
    int i, j;
    unsigned int code, weight;
    int *tbl;

    tbl = fixed[method];
    j = *tbl++;
    weight = 1 << (16 - j);
    code = 0; 
    for (i = 0; i < np; i++) {
        while (*tbl == i) {
            j++;
            tbl++;
            weight >>= 1;
        }
        pt_len[i] = j;
        pt_code[i] = code;
        code += weight;
    }
}

void encode_start_fix()
{
    n_max = 314;
    maxmatch = 60;
    np = 1 << (12 - 6);
    init_putbits();
    start_c_dyn();
    ready_made(0);
}

static void read_tree_c()  /* read tree from file */
{
    int i, c;

    i = 0;
    while (i < N1) {
        if (getbits(1)) c_len[i] = getbits(LENFIELD) + 1;
        else            c_len[i] = 0;
        if (++i == 3 && c_len[0] == 1 && c_len[1] == 1 && c_len[2] == 1) {
            c = getbits(CBIT);
            for (i = 0; i < N1; i++) c_len[i] = 0;
            for (i = 0; i < 4096; i++) c_table[i] = c;
            return;
        }
    }
    make_table(N1, c_len, 12, c_table);
}

static void read_tree_p()  /* read tree from file */
{
    int i, c;

    i = 0;
    while (i < NP) {
        pt_len[i] = getbits(LENFIELD);
        if (++i == 3 && pt_len[0] == 1 && pt_len[1] == 1 && pt_len[2] == 1) {
            c = getbits(MAX_DICBIT - 6);
            for (i = 0; i < NP; i++) c_len[i] = 0;
            for (i = 0; i < 256; i++) c_table[i] = c;
            return;
        }
    }
}

void decode_start_fix()
{
    n_max = 314;
    maxmatch = 60;
    init_getbits();
    np = 1 << (12 - 6);
    start_c_dyn();
    ready_made(0);
    make_table(np, pt_len, 8, pt_table);
}

unsigned short decode_c_st0()
{
    int i, j;
    static unsigned short blocksize = 0;

    if (blocksize == 0) {  /* read block head */
        blocksize = getbits(BUFBITS);  /* read block blocksize */
        read_tree_c();
        if (getbits(1)) {
            read_tree_p();
        } 
        else {
            ready_made(1);
        }
        make_table(NP, pt_len, 8, pt_table);
    }
    blocksize--;
    j = c_table[bitbuf >> 4];
    if (j < N1) fillbuf(c_len[j]);
    else {
        fillbuf(12); 
        i = bitbuf;
        do {
            if ((short)i < 0) j = right[j];
            else              j = left [j];
            i <<= 1;
        } 
        while (j >= N1);
        fillbuf(c_len[j] - 12);
    }
    if (j == N1 - 1)
        j += getbits(EXTRABITS);
    return j;
}

unsigned short decode_p_st0()
{
    int i, j;

    j = pt_table[bitbuf >> 8];
    if (j < np) {
        fillbuf(pt_len[j]);
    } 
    else {
        fillbuf(8); 
        i = bitbuf;
        do {
            if ((short)i < 0) j = right[j];
            else              j = left [j];
            i <<= 1;
        } 
        while (j >= np);
        fillbuf(pt_len[j] - 8);
    }
    return (j << 6) + getbits(6);
}
