#include <windows.h>
#pragma hdrstop
#include <stdio.h>
#include <stdlib.h>
#include "unlzh.h"

#ifndef UCHAR_MAX
#define UCHAR_MAX 255		/* max value for an unsigned char */
#endif
#ifndef CHAR_BIT
#define CHAR_BIT  8
#endif
#define MAX_DICBIT 16   //15
#define MAXMATCH 256    // formerly F (not more than UCHAR_MAX + 1)
#define THRESHOLD  3    // choose optimal value

#define NC (UCHAR_MAX + MAXMATCH + 2 - THRESHOLD)
                // alphabet = {0, 1, 2, ..., NC - 1}
#define CBIT 9  // $\lfloor \log_2 NC \rfloor + 1$
#define USHRT_BIT 16    // (CHAR_BIT * sizeof(ushort))
#define NP (MAX_DICBIT + 1)
#define NT (USHRT_BIT + 3)
#define PBIT 4 // smallest integer such that (1 << PBIT) > NP
#define TBIT 5 // smallest integer such that (1 << TBIT) > NT
#define NPT 0x80
#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 SNP (8 * 1024 / 64)
#define SNP2 (SNP * 2 - 1)
#define N_CHAR      (256 + 60 - THRESHOLD + 1)
#define TREESIZE_C  (N_CHAR * 2)
#define TREESIZE_P  (128 * 2)
#define TREESIZE    (TREESIZE_C + TREESIZE_P)
#define ROOT_C      0
#define ROOT_P      TREESIZE_C
#define MAGIC0 18
#define MAGIC5 19
#define INBUFSIZ 2048 //BUFSIZ

struct _UNLZHHandler
{
    void *user_val;
    long (__fastcall *read_func)(char *buff, long buff_size, void *user_val);
    long (__fastcall *seek_func)(int, int, void*);
    int method;

    unsigned char inbuf[INBUFSIZ];
    int inbuf_size;
    int inbuf_cnt;
    int initflag;

    int cpylen;
    int cpypos;
    unsigned long origsize;
    unsigned long compsize;
    void           (__fastcall *decode_s)(UNLZHHandler decoder);
    unsigned short (__fastcall *decode_c)(UNLZHHandler decoder);
    unsigned short (__fastcall *decode_p)(UNLZHHandler decoder);
    int dicbit;
    unsigned short maxmatch;
    unsigned long count;
    unsigned short loc;
    unsigned char  text[1L<<MAX_DICBIT];
    unsigned short bitbuf;
    unsigned char  subbitbuf, bitcount;
    unsigned short left[2 * NC - 1], right[2 * NC - 1];
    unsigned char  c_len[NC], pt_len[NPT];
    unsigned short c_table[4096], pt_table[256];
    unsigned short blocksize;
    unsigned int n_max;
    short child [TREESIZE],
          parent[TREESIZE],
          block [TREESIZE],
          edge  [TREESIZE],
          stock [TREESIZE],
          node  [TREESIZE / 2];
    unsigned short freq[TREESIZE];
    unsigned short total_p;
    int avail, n1;
    int most_p, nn;
    unsigned long nextcount;
    unsigned int snp;
    int flag, flagcnt, matchpos;
    int offset;
    unsigned int pbit;
    // ここから下は lzhseek 用
    // ・ある程度のサイズ(SEEK_BLOCK)を解凍する毎に decoder の状態(context)を保存する。
    // ・シークが要求されたら、要求位置より手前でかつ要求位置に最も近い context を復帰後、
    //   要求位置まで解凍する。
    // ・↑により解凍済み位置までのシークが高速化。
    // ・SEEK_BLOCK が小さいほど、解凍済み位置へのシークは高速になるが、その分メモリ使用量
    //   が大きくなり、SEEK_BLOCK == sizeof(_UNLZHHandler) のとき、全てをメモリ上に解凍する
    //   のに必要なメモリ使用量とほぼ同じになる。
    // ・終端に近い位置へのシークは、全部解凍するのと同じ時間がかかってしまう。（初回のみ）
    // ・終端に近い位置にシークしない形式であれば、通常のファイルに近いレスポンスで扱うことが
    //   可能になる。
    // ・シークバックが連続的に呼ばれると、極端に遅くなることがある。
    // ・戻るサイズがトータルである程度小さければ、シークバックが連続的に呼ばれてもそれほど
    //   問題はない（どの程度小さければ問題ないのかは、本体のバッファリング処理に依存し、
    //   現時点では 8KB 未満であれば問題なく動作する）
    HANDLE hHeap;
    DWORD  dwCompSize;          //compsize 初期値（compsize は unlzh() を呼び出す度に値が変化する）
    UINT64 qwStartFilePointer;//ファイルポインタ初期値
    UINT64 qwFilePointer;     //
    struct _UNLZHHandler *pContext;
};
#define SEEK_BLOCK (sizeof(struct _UNLZHHandler) * 4)

static void __fastcall init_unlzh_handler(UNLZHHandler decoder,
                                          long (__fastcall *read_func)(char *, long, void *),
                                          long (__fastcall *seek_func)(int,  int, void*),
                                          const wchar_t *method,
				                          long           compsize, 
                                          long           origsize, 
                                          void          *user_val,
                                          UINT64         qwFilePointer);
static void __fastcall lzhseek_SaveContext(UNLZHHandler decoder);
static void __fastcall lzhseek_RestoreContext(UNLZHHandler decoder, UINT64 qwPos);

static unsigned short __fastcall decode_c_cpy(UNLZHHandler decoder);
static unsigned short __fastcall decode_p_cpy(UNLZHHandler decoder);
static void __fastcall decode_start_cpy(UNLZHHandler decoder);
static void __fastcall read_pt_len(UNLZHHandler decoder,
			short k, short nbit, short i_special);
static void __fastcall read_c_len(UNLZHHandler decoder);
static unsigned short __fastcall decode_c_st1(UNLZHHandler decoder);
static unsigned short __fastcall decode_p_st1(UNLZHHandler decoder);
static void __fastcall decode_start_st1(UNLZHHandler decoder);
static void __fastcall start_c_dyn(UNLZHHandler decoder);
static void __fastcall start_p_dyn(UNLZHHandler decoder);
static void __fastcall decode_start_dyn(UNLZHHandler decoder);
static void __fastcall reconst(UNLZHHandler decoder, int start, int end);
static int __fastcall swap_inc(UNLZHHandler decoder, int p);
static void __fastcall update_c(UNLZHHandler decoder, int p);
static void __fastcall update_p(UNLZHHandler decoder, int p);
static void __fastcall make_new_node(UNLZHHandler decoder, int p);
static unsigned short __fastcall decode_c_dyn(UNLZHHandler decoder);
static unsigned short __fastcall decode_p_dyn(UNLZHHandler decoder);
static void __fastcall decode_start_st0(UNLZHHandler decoder);
static void __fastcall ready_made(UNLZHHandler decoder, int method);
static void __fastcall read_tree_c(UNLZHHandler decoder);
static void __fastcall read_tree_p(UNLZHHandler decoder);
static void __fastcall decode_start_fix(UNLZHHandler decoder);
static unsigned short __fastcall decode_c_st0(UNLZHHandler decoder);
static unsigned short __fastcall decode_p_st0(UNLZHHandler decoder);
static unsigned short __fastcall decode_c_lzs(UNLZHHandler decoder);
static unsigned short __fastcall decode_p_lzs(UNLZHHandler decoder);
static void __fastcall decode_start_lzs(UNLZHHandler decoder);
static unsigned short __fastcall decode_c_lz5(UNLZHHandler decoder);
static unsigned short __fastcall decode_p_lz5(UNLZHHandler decoder);
static void __fastcall decode_start_lz5(UNLZHHandler decoder);
static void __fastcall make_table(UNLZHHandler decoder,
		       int nchar, unsigned char bitlen[],
		       int tablebits, unsigned short table[]);
static int __fastcall fill_inbuf(UNLZHHandler decoder);
static void __fastcall fillbuf(UNLZHHandler decoder, unsigned char n);
static unsigned short __fastcall getbits(UNLZHHandler decoder, unsigned char n);
static void __fastcall init_getbits(UNLZHHandler decoder);

#define NEXTBYTE (decoder->inbuf_cnt < decoder->inbuf_size ? (int)decoder->inbuf[decoder->inbuf_cnt++] : fill_inbuf(decoder))

static struct
{
    wchar_t *id;
    int dicbit;
    void (__fastcall *decode_s)(UNLZHHandler decoder);
    unsigned short (__fastcall *decode_c)(UNLZHHandler decoder);
    unsigned short (__fastcall *decode_p)(UNLZHHandler decoder);
} method_table[] =
{
// 8k sliding dictionary(max 256 bytes)
//   + static Huffman + improved encoding of position and trees
    {L"-lh5-", 13, decode_start_st1, decode_c_st1, decode_p_st1},

// No compression
    {L"-lh0-",  0, decode_start_cpy, decode_c_cpy, decode_p_cpy},

// 32k sliding dictionary + static Huffman
    {L"-lh6-", 15, decode_start_st1, decode_c_st1, decode_p_st1},

// 64k sliding dictionary + static Huffman
    {L"-lh7-", 16, decode_start_st1, decode_c_st1, decode_p_st1},
//
// 4k sliding dictionary(max 60 bytes)
//   + dynamic Huffman + fixed encoding of position
    {L"-lh1-", 12, decode_start_fix, decode_c_dyn, decode_p_st0},

// 8k sliding dictionary(max 256 bytes) + dynamic Huffman
    {L"-lh2-", 13, decode_start_dyn, decode_c_dyn, decode_p_dyn},

// 8k sliding dictionary(max 256 bytes) + static Huffman
    {L"-lh3-", 13, decode_start_st0, decode_c_st0, decode_p_st0},

// 4k sliding dictionary(max 256 bytes)
//   + static Huffman + improved encoding of position and trees
    {L"-lh4-", 12, decode_start_st1, decode_c_st1, decode_p_st1},


// 2k sliding dictionary(max 17 bytes)
    {L"-lzs-", 11, decode_start_lzs, decode_c_lzs, decode_p_lzs},

// No compression
    {L"-lz5-", 12, decode_start_lz5, decode_c_lz5, decode_p_lz5},

// 4k sliding dictionary(max 17 bytes)
    {L"-lz4-",  0, decode_start_cpy, decode_c_cpy, decode_p_cpy},

// Directory
    {L"-lhd-",  0, NULL, NULL, NULL},

    {NULL, 0, NULL, NULL}

};
/*
char *lzh_methods[] =
{
    "-lh0-", "-lh1-", "-lh2-", "-lh3-", "-lh4-", "-lh5-",
    "-lzs-", "-lz5-", "-lz4-", "-lhd-", "-lh6-", "-lh7-", NULL
};*/
void __fastcall init_unlzh_handler(UNLZHHandler decoder,
                                   long (__fastcall *read_func)(char *, long, void *),
                                   long (__fastcall *seek_func)(int,  int, void*),
                                   const wchar_t *method,
				                   long        compsize, 
                                   long        origsize, 
                                   void       *user_val,
                                   UINT64      qwFilePointer)
{
    int i;
    for(i = 0; method_table[i].id != NULL; i++){
	    if(!wcscmp(method_table[i].id, method)){
	        break;
        }
    }
    memset(decoder, 0, sizeof(*decoder));
    if(method_table[i].id == NULL){
	    return; /* Invalid method */
    }
    if(wcscmp(method, L"-lhd-") == 0)
	    origsize = 0;

    decoder->method = i;
    decoder->dicbit   = method_table[i].dicbit;
    decoder->decode_s = method_table[i].decode_s;
    decoder->decode_c = method_table[i].decode_c;
    decoder->decode_p = method_table[i].decode_p;
    decoder->compsize = compsize;
    decoder->origsize = origsize;
    decoder->user_val = user_val;
    decoder->cpylen = 0;
    decoder->cpypos = 0;
    decoder->offset = (decoder->method == 6) ? 0x100 - 2 : 0x100 - 3;
    decoder->count = 0;
    decoder->loc = 0;
    decoder->initflag = 0;

    decoder->read_func = read_func;
    decoder->seek_func = seek_func;
    //追加 2000/08/22
    if(wcscmp(method, L"-lh1-") == 0){
        decoder->flagcnt = 0;
        for(i = 0; i < 256; i++)
        	memset(&decoder->text[i * 13 + 18], i, 13);
        for(i = 0; i < 256; i++)
         	decoder->text[256 * 13 + 18 + i] = i;   
        for(i = 0; i < 256; i++)
	        decoder->text[256 * 13 + 256 + 18 + i] = 255 - i;
        memset(&decoder->text[256 * 13 + 512 + 18], 0, 128);
        memset(&decoder->text[256 * 13 + 512 + 128 + 18], ' ', 128 - 18);
    }    
    //ここまで
    decoder->dwCompSize = decoder->compsize;
    decoder->qwFilePointer = decoder->qwStartFilePointer = qwFilePointer;
}
UNLZHHandler __fastcall open_unlzh_handler(long (__fastcall *read_func)(char *, long, void *),
                                           long (__fastcall *seek_func)(int,  int, void*),
                                           const wchar_t *method,
				                           long compsize, long origsize, void *user_val)
{
    HANDLE hHeap;
    DWORD  dwHeapSize;
    UNLZHHandler decoder;
    UINT64 qwStartFilePointer;
    int i;
    for(i = 0; method_table[i].id != NULL; i++){
	    if(!wcscmp(method_table[i].id, method)){
	        break;
        }
    }
    if(method_table[i].id == NULL){
	    return NULL; /* Invalid method */
    }
    //シーク用
    //context 用に作成する struct _UNLZHHandler の数は最大で origsize/SEEK_BLOCK + 1
    dwHeapSize = origsize / SEEK_BLOCK + 1;
    dwHeapSize *= (sizeof(struct _UNLZHHandler) + 128);
    //・HeapAlloc は lzhseek から呼ばれる。
    //・lzhseek は IKpiFile::Seek から呼ばれる。
    //・同じ IKpiFile のインスタンスに対して IKpiFile の各メソッドは排他的に
    //  呼ばれることが保証されている。
    //以上より、HeapCreate の第１引数は HEAP_NO_SERIALIZE で良い。
    hHeap = HeapCreate(HEAP_NO_SERIALIZE, dwHeapSize, 0);
    decoder = (UNLZHHandler)HeapAlloc(hHeap, HEAP_NO_SERIALIZE, sizeof(struct _UNLZHHandler));
    qwStartFilePointer = seek_func(0, FILE_CURRENT, user_val);
    init_unlzh_handler(decoder,
                       read_func, 
                       seek_func, 
                       method, 
                       compsize, 
                       origsize, 
                       user_val, 
                       qwStartFilePointer);
    decoder->hHeap = hHeap;
    return decoder;
}

void __fastcall close_unlzh_handler(UNLZHHandler decoder)
{
    /*
    UNLZHHandler del = decoder;
    UNLZHHandler delnext;
    while(del){
        delnext = del->pContext;
        free(del);
        del = delnext;
    }
    */
    HeapDestroy(decoder->hHeap);
}

long __fastcall unlzh(UNLZHHandler decoder, char *buff, long buff_size)
{
    long n;
    unsigned short dicsiz1;
    int offset;
    int cpylen, cpypos, loc;
    unsigned char *text;
    unsigned long origsize;

    if((origsize = decoder->origsize) <= 0 || buff_size <= 0)
	    return 0;

    if(!decoder->initflag){
	    decoder->initflag = 1;
	    decoder->decode_s(decoder);
    }

    dicsiz1 = (1 << decoder->dicbit) - 1;
    n = 0;
    text = decoder->text;

    if(decoder->cpylen > 0){
	    cpylen = decoder->cpylen;
	    cpypos = decoder->cpypos;
	    loc    = decoder->loc;
	    while(cpylen > 0 && n < buff_size){
	        buff[n++] = text[loc++] = text[cpypos++];
	        loc &= dicsiz1;
	        cpypos &= dicsiz1;
	        cpylen--;
	    }
	    decoder->cpylen = cpylen;
	    decoder->cpypos = cpypos;
	    decoder->loc = loc;
    }

    if(n == buff_size)
	    return buff_size;

    offset = decoder->offset;
    while(decoder->count < origsize && n < buff_size){
	    int c;
	    c = decoder->decode_c(decoder);
	    if(c <= UCHAR_MAX){
	        buff[n++] = decoder->text[decoder->loc++] = c;
	        decoder->loc &= dicsiz1;
	        decoder->count++;
	    }
	    else{
	        int i, j, k, m;

	        j = c - offset;
	        i = (decoder->loc - decoder->decode_p(decoder) - 1) & dicsiz1;
	        decoder->count += j;
	        loc = decoder->loc;
	        m = buff_size - n;
	        if(m > j)
		        m = j;
	        for(k = 0; k < m; k++){
		        buff[n++] = text[loc++] = text[i++];
		        loc &= dicsiz1;
		        i &= dicsiz1;
	        }
	        decoder->loc = loc;
	        if(k < j){
		        decoder->cpylen = j - k;
		        decoder->cpypos = i;
		        break;
	        }
	    }
    }
    return n;
}

static unsigned short __fastcall decode_c_cpy(UNLZHHandler decoder)
{
    int c;
    if((c = NEXTBYTE) == EOF)
	    return 0;
    return (unsigned short)c;
}

/*ARGSUSED*/
static unsigned short __fastcall decode_p_cpy(UNLZHHandler decoder)
{
    return 0;
}

static void __fastcall decode_start_cpy(UNLZHHandler decoder)
{
    init_getbits(decoder);
    decoder->inbuf_cnt = 0;
}

static void __fastcall read_pt_len(UNLZHHandler decoder,
			short k, short nbit, short i_special)
{
    int i, c, n;

    n = getbits(decoder, nbit);
    if(n == 0){
	    c = getbits(decoder, nbit);
	    for(i = 0; i < k; i++)
	        decoder->pt_len[i] = 0;
	    for(i = 0; i < 256; i++)
	        decoder->pt_table[i] = c;
    }
    else{
        ZeroMemory(decoder->pt_len, sizeof(decoder->pt_len));//追加
        ZeroMemory(decoder->pt_table, sizeof(decoder->pt_table));//追加
	    //for(i = 0; i < 256; i++)     //追加
	    //    decoder->pt_table[i] = 0;//追加
	    i = 0;
	    while(i < n){
	        c = decoder->bitbuf >> (16 - 3);
	        if (c == 7){
		        unsigned short mask = 1 << (16 - 4);
		        while(mask & decoder->bitbuf){
		            mask >>= 1;
		            c++;
		        }
	        }
	        fillbuf(decoder, (c < 7) ? 3 : c - 3);
	        decoder->pt_len[i++] = c;
            //if(c >= 17){
            //    int t = 0;
            //}
	        if(i == i_special){
		        c = getbits(decoder, 2);
		        //while(--c >= 0)//削除
		        while(--c >= 0 && i < 128)//追加
		            decoder->pt_len[i++] = 0;
	        }
	    }
	    while(i < k)
	        decoder->pt_len[i++] = 0;
	    make_table(decoder, k, decoder->pt_len, 8, decoder->pt_table);
    }
}

static void __fastcall read_c_len(UNLZHHandler decoder)
{
    short i, c, n;

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

static unsigned short __fastcall decode_c_st1(UNLZHHandler decoder)
{
    unsigned short j, mask;

    if(decoder->blocksize == 0){
	    decoder->blocksize = getbits(decoder, 16);
	    read_pt_len(decoder, NT, TBIT, 3);
	    read_c_len(decoder);
	    read_pt_len(decoder, decoder->snp, decoder->pbit, -1);
    }
    decoder->blocksize--;
    j = decoder->c_table[decoder->bitbuf >> 4];
    if(j < NC)
	    fillbuf(decoder, decoder->c_len[j]);
    else{
	    fillbuf(decoder, 12);
	    mask = 1 << (16 - 1);
	    do{
	        if(decoder->bitbuf & mask)
		        j = decoder->right[j];
	        else
		        j = decoder->left[j];
	        mask >>= 1;
	    }while(j >= NC);
	    fillbuf(decoder, decoder->c_len[j] - 12);
    }
    return j;
}

static unsigned short __fastcall decode_p_st1(UNLZHHandler decoder)
{
    unsigned short j, mask;
    
    unsigned int np = decoder->snp;

    j = decoder->pt_table[decoder->bitbuf >> (16 - 8)];
    if(j < np)
	    fillbuf(decoder, decoder->pt_len[j]);
    else{
	    fillbuf(decoder, 8);
	    mask = 1 << (16 - 1);
	    do{
	        if(decoder->bitbuf & mask)
		        j = decoder->right[j];
	        else
		        j = decoder->left[j];
	        mask >>= 1;
	    }while(j >= np);
	    fillbuf(decoder, decoder->pt_len[j] - 8);
    }
    if(j != 0)
	    j = (1 << (j - 1)) + getbits(decoder, j - 1);
    return j;
}


static void __fastcall decode_start_st1(UNLZHHandler decoder)
{
    //if(decoder->dicbit <= (MAX_DICBIT - 2)){
    if(decoder->dicbit <= (MAX_DICBIT - 3)){
	    decoder->snp = 14;
	    decoder->pbit = 4;
    }
    else if(decoder->dicbit == 15){//lh6
	    decoder->snp = 16;
	    decoder->pbit = 5;
    }
    else{//lh7
	    decoder->snp = 17;
	    decoder->pbit = 5;
    }
    init_getbits(decoder);
    decoder->blocksize = 0;
}

static void __fastcall start_c_dyn(UNLZHHandler decoder)
{
    int i, j, f;

    decoder->n1 = (decoder->n_max >= 256 + decoder->maxmatch - THRESHOLD + 1)
	? 512 : decoder->n_max - 1;
    for(i = 0; i < TREESIZE_C; i++){
	    decoder->stock[i] = i;
	    decoder->block[i] = 0;
    }
    for(i = 0, j = decoder->n_max * 2 - 2; i < decoder->n_max; i++, j--){
	    decoder->freq[j] = 1;
	    decoder->child[j] = ~i;
	    decoder->node[i] = j;
	    decoder->block[j] = 1;
    }
    decoder->avail = 2;
    decoder->edge[1] = decoder->n_max - 1;
    i = decoder->n_max * 2 - 2;
    while(j >= 0){
	    f = decoder->freq[j] = decoder->freq[i] + decoder->freq[i - 1];
	    decoder->child[j] = i;
	    decoder->parent[i] = decoder->parent[i - 1] = j;
	    if(f == decoder->freq[j + 1]){
	        decoder->edge[decoder->block[j] = decoder->block[j + 1]] = j;
	    }
	    else{
	        decoder->edge[decoder->block[j] =
			    decoder->stock[decoder->avail++]] = j;
	    }
	    i -= 2;
	    j--;
    }
}

static void __fastcall start_p_dyn(UNLZHHandler decoder)
{
    decoder->freq[ROOT_P] = 1;
    decoder->child[ROOT_P] = ~(N_CHAR);
    decoder->node[N_CHAR] = ROOT_P;
    decoder->edge[decoder->block[ROOT_P] =
		  decoder->stock[decoder->avail++]] = ROOT_P;
    decoder->most_p = ROOT_P;
    decoder->total_p = 0;
    decoder->nn = 1 << decoder->dicbit;
    decoder->nextcount = 64;
}

static void __fastcall decode_start_dyn(UNLZHHandler decoder)
{
    decoder->n_max = 286;
    decoder->maxmatch = MAXMATCH;
    init_getbits(decoder);
    start_c_dyn(decoder);
    start_p_dyn(decoder);
}

static void __fastcall reconst(UNLZHHandler decoder, int start, int end)
{
    int i, j, k, l, b;
    unsigned int f, g;

    b = 0;
    for(i = j = start; i < end; i++){
	    if((k = decoder->child[i]) < 0){
	        decoder->freq[j] = (decoder->freq[i] + 1) / 2;
	        decoder->child[j] = k;
	        j++;
	    }
	    if(decoder->edge[b = decoder->block[i]] == i){
	        decoder->stock[--decoder->avail] = b;
	    }
    }
    j--;
    i = end - 1;
    l = end - 2;
    while(i >= start){
	    while (i >= l){
	        decoder->freq[i] = decoder->freq[j];
	        decoder->child[i] = decoder->child[j];
	        i--;
	        j--;
	    }
	    f = decoder->freq[l] + decoder->freq[l + 1];
	    for(k = start; f < decoder->freq[k]; k++)
	        ;
	    while(j >= k){
	        decoder->freq[i] = decoder->freq[j];
	        decoder->child[i] = decoder->child[j];
	        i--;
	        j--;
	    }
	    decoder->freq[i] = f;
	    decoder->child[i] = l + 1;
	    i--;
	    l -= 2;
    }
    f = 0;
    for(i = start; i < end; i++){
	    if((j = decoder->child[i]) < 0)
	        decoder->node[~j] = i;
	    else
	        decoder->parent[j] = decoder->parent[j - 1] = i;
	    if((g = decoder->freq[i]) == f){
	        decoder->block[i] = b;
	    }
	    else{
	        decoder->edge[b = decoder->block[i]
			    = decoder->stock[decoder->avail++]] = i;
	        f = g;
	    }
    }
}

static int __fastcall swap_inc(UNLZHHandler decoder, int p)
{
    int b, q, r, s;

    b = decoder->block[p];
    if((q = decoder->edge[b]) != p){	/* swap for leader */
	    r = decoder->child[p];
	    s = decoder->child[q];
	    decoder->child[p] = s;
	    decoder->child[q] = r;
	    if(r >= 0)
	        decoder->parent[r] = decoder->parent[r - 1] = q;
	    else
	        decoder->node[~r] = q;
	    if(s >= 0)
	        decoder->parent[s] = decoder->parent[s - 1] = p;
	    else
	        decoder->node[~s] = p;
	    p = q;
	    goto Adjust;
    }
    else if(b == decoder->block[p + 1]){
        Adjust:
	    decoder->edge[b]++;
	    if(++decoder->freq[p] == decoder->freq[p - 1]){
	        decoder->block[p] = decoder->block[p - 1];
	    }
	    else{
	        decoder->edge[decoder->block[p] =
		        decoder->stock[decoder->avail++]] = p;	/* create block */
	    }
    }
    else if(++decoder->freq[p] == decoder->freq[p - 1]){
	    decoder->stock[--decoder->avail] = b;		/* delete block */
	    decoder->block[p] = decoder->block[p - 1];
    }
    return decoder->parent[p];
}

static void __fastcall update_c(UNLZHHandler decoder, int p)
{
    int q;

    if(decoder->freq[ROOT_C] == 0x8000){
	    reconst(decoder, 0, decoder->n_max * 2 - 1);
    }
    decoder->freq[ROOT_C]++;
    q = decoder->node[p];
    do{
	    q = swap_inc(decoder, q);
    }while(q != ROOT_C);
}

static void __fastcall update_p(UNLZHHandler decoder, int p)
{
    int q;

    if(decoder->total_p == 0x8000){
	    reconst(decoder, ROOT_P, decoder->most_p + 1);
	    decoder->total_p = decoder->freq[ROOT_P];
	    decoder->freq[ROOT_P] = 0xffff;
    }
    q = decoder->node[p + N_CHAR];
    while(q != ROOT_P){
	    q = swap_inc(decoder, q);
    }
    decoder->total_p++;
}

static void __fastcall make_new_node(UNLZHHandler decoder, int p)
{
    int q, r;

    r = decoder->most_p + 1;
    q = r + 1;
    decoder->node[~(decoder->child[r] = decoder->child[decoder->most_p])] = r;
    decoder->child[q] = ~(p + N_CHAR);
    decoder->child[decoder->most_p] = q;
    decoder->freq[r] = decoder->freq[decoder->most_p];
    decoder->freq[q] = 0;
    decoder->block[r] = decoder->block[decoder->most_p];
    if(decoder->most_p == ROOT_P){
	    decoder->freq[ROOT_P] = 0xffff;
	    decoder->edge[decoder->block[ROOT_P]]++;
    }
    decoder->parent[r] = decoder->parent[q] = decoder->most_p;
    decoder->edge[decoder->block[q] = decoder->stock[decoder->avail++]]
	                = decoder->node[p + N_CHAR] = decoder->most_p = q;
    update_p(decoder, p);
}

static unsigned short __fastcall decode_c_dyn(UNLZHHandler decoder)
{
    int c;
    short buf, cnt;

    c = decoder->child[ROOT_C];
    buf = decoder->bitbuf;
    cnt = 0;
    do{
	    c = decoder->child[c - (buf < 0)];
	    buf <<= 1;
	    if(++cnt == 16){
	        fillbuf(decoder, 16);
	        buf = decoder->bitbuf;
	        cnt = 0;
	    }
    }while (c > 0);
    fillbuf(decoder, cnt);
    c = ~c;
    update_c(decoder, c);
    if(c == decoder->n1)
	    c += getbits(decoder, 8);
    return c;
}

static unsigned short __fastcall decode_p_dyn(UNLZHHandler decoder)
{
    int c;
    short buf, cnt;

    while(decoder->count > decoder->nextcount){
	    make_new_node(decoder, (int)(decoder->nextcount / 64));
	    if((decoder->nextcount += 64) >= decoder->nn)
	        decoder->nextcount = 0xffffffff;
    }
    c = decoder->child[ROOT_P];
    buf = decoder->bitbuf;
    cnt = 0;
    while(c > 0){
	    c = decoder->child[c - (buf < 0)];
	    buf <<= 1;
	    if(++cnt == 16){
	        fillbuf(decoder, 16);
	        buf = decoder->bitbuf;
	        cnt = 0;
        }
    }
    fillbuf(decoder, cnt);
    c = (~c) - N_CHAR;
    update_p(decoder, c);

    return (c << 6) + getbits(decoder, 6);
}

static void __fastcall decode_start_st0(UNLZHHandler decoder)
{
    decoder->n_max = 286;
    decoder->maxmatch = MAXMATCH;
    init_getbits(decoder);
    //decoder->snp = 1 << (MAX_DICBIT - 6);
    decoder->snp = 1 << (MAX_DICBIT - 7);
    decoder->blocksize = 0;
}

static 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 __fastcall ready_made(UNLZHHandler decoder, 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 < decoder->snp; i++){
	    while(*tbl == i){
	        j++;
	        tbl++;
	        weight >>= 1;
	    }
	    decoder->pt_len[i] = j;
	    code += weight;
    }
}

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

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

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

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

static void __fastcall decode_start_fix(UNLZHHandler decoder)
{
    decoder->n_max = 314;
    decoder->maxmatch = 60;
    init_getbits(decoder);
    decoder->snp = 1 << (12 - 6);
    start_c_dyn(decoder);
    ready_made(decoder, 0);
    make_table(decoder, decoder->snp, decoder->pt_len, 8, decoder->pt_table);
}

static unsigned short __fastcall decode_c_st0(UNLZHHandler decoder)
{
    int i, j;

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

static unsigned short __fastcall decode_p_st0(UNLZHHandler decoder)
{
    int i, j;

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

static unsigned short __fastcall decode_c_lzs(UNLZHHandler decoder)
{
    if(getbits(decoder, 1))
	return getbits(decoder, 8);
    decoder->matchpos = getbits(decoder, 11);
    return getbits(decoder, 4) + 0x100;
}

static unsigned short __fastcall decode_p_lzs(UNLZHHandler decoder)
{
    return (decoder->loc - decoder->matchpos - MAGIC0) & 0x7ff;
}

static void __fastcall decode_start_lzs(UNLZHHandler decoder)
{
    init_getbits(decoder);
}

static unsigned short __fastcall decode_c_lz5(UNLZHHandler decoder)
{
    int c;

    if(decoder->flagcnt == 0)
    {
	decoder->flagcnt = 8;
	decoder->flag = NEXTBYTE;
    }
    decoder->flagcnt--;
    c = NEXTBYTE;
    if((decoder->flag & 1) == 0)
    {
	decoder->matchpos = c;
	c = NEXTBYTE;
	decoder->matchpos += (c & 0xf0) << 4;
	c &= 0x0f;
	c += 0x100;
    }
    decoder->flag >>= 1;
    return c;
}

static unsigned short __fastcall decode_p_lz5(UNLZHHandler decoder)
{
    return (decoder->loc - decoder->matchpos - MAGIC5) & 0xfff;
}

static void __fastcall decode_start_lz5(UNLZHHandler decoder)
{
    int i;

    decoder->flagcnt = 0;
    for(i = 0; i < 256; i++)
	memset(&decoder->text[i * 13 + 18], i, 13);
    for(i = 0; i < 256; i++)
	decoder->text[256 * 13 + 18 + i] = i;
    for(i = 0; i < 256; i++)
	decoder->text[256 * 13 + 256 + 18 + i] = 255 - i;
    memset(&decoder->text[256 * 13 + 512 + 18], 0, 128);
    memset(&decoder->text[256 * 13 + 512 + 128 + 18], ' ', 128 - 18);
}

static void __fastcall make_table(UNLZHHandler decoder,
		       int nchar, unsigned char bitlen[],
		       int tablebits, unsigned short table[])
{
	//try{
    unsigned short cnttable[17];// count of bitlen
    unsigned short weight[17];  // 0x10000ul >> bitlen
    unsigned short start[17];   // first code of bitlen
    unsigned short total;
    unsigned int i;
    int j, k, l, m, n, available;
    unsigned short *p;

    available = nchar;

// initialize
    for(i = 1; i <= 16; i++)
    {
	cnttable[i] = 0;
	weight[i] = 1 << (16 - i);
    }

// cnttable
    for(i = 0; i < nchar; i++){
	    if(bitlen[i] <= 16){//2015/12/26追加(E:\Minor_Audio\MIDI\FEI\MCML2.LZH>MCML2.MID で落ちるのを回避)
            cnttable[bitlen[i]]++;
        }                   //2015/12/26追加
        //else{
        //    int t = 0;
        //}
    }

// calculate first code
    total = 0;
    for(i = 1; i <= 16; i++)
    {
	start[i] = total;
	total += weight[i] * cnttable[i];
    }
    if((total & 0xffff) != 0)
    {
	//fprintf(stderr, "Decode: Bad table (5)\n");
	//exit(1);
        //MessageBeep(MB_OK);
        return;
    }

// shift data for make table.
    m = 16 - tablebits;
    for(i = 1; i <= tablebits; i++)
    {
	start[i] >>= m;
	weight[i] >>= m;
    }

// initialize
    j = start[tablebits + 1] >> m;
    k = 1 << tablebits;
    if(j != 0)
	for(i = j; i < k; i++)
	    table[i] = 0;

// create table and tree
    for(j = 0; j < nchar; j++)
    {
	k = bitlen[j];
	if(k == 0)
	    continue;
	l = start[k] + weight[k];
    if(k <= tablebits)
	{
	    //code in table
	    for(i = start[k]; i < l; i++)
		table[i] = j;
	}
	else
	{
	    //code not in table
	    p = &table[(i = start[k]) >> m];
	    i <<= tablebits;
	    n = k - tablebits;
	    //make tree (n length)
	    while(--n >= 0)
	    {
		if(*p == 0)
		{
		    decoder->right[available] = decoder->left[available] = 0;
		    *p = available++;
		}
		if(i & 0x8000)
		    p = &decoder->right[*p];
		else
		    p = &decoder->left[*p];
		i <<= 1;
	    }
	    *p = j;
	}
	start[k] = l;
    }
    //}catch(...){
    //    int t = 0;
   // }
}
static int __fastcall fill_inbuf(UNLZHHandler decoder)
{
    long n, i;

    if(decoder->compsize == 0)
	return EOF;
    i = INBUFSIZ;
    if(i > decoder->compsize)
	i = (long)decoder->compsize;
    n = decoder->read_func((char *)decoder->inbuf, i, decoder->user_val);
    if(n <= 0)
	return EOF;
    decoder->inbuf_size = n;
    decoder->inbuf_cnt = 1;
    decoder->compsize -= n;
    return (int)decoder->inbuf[0];
}

//Shift bitbuf n bits left, read n bits
static void __fastcall fillbuf(UNLZHHandler decoder, unsigned char n)
{
    unsigned char bitcount;
    unsigned short bitbuf;

    bitcount = decoder->bitcount;
    bitbuf   = decoder->bitbuf;
    while(n > bitcount)
    {
	n -= bitcount;
	bitbuf = (bitbuf << bitcount)
	    + (decoder->subbitbuf >> (CHAR_BIT - bitcount));
	decoder->subbitbuf = (unsigned char)NEXTBYTE;
	bitcount = CHAR_BIT;
    }
    bitcount -= n;
    bitbuf = (bitbuf << n) + (decoder->subbitbuf >> (CHAR_BIT - n));
    decoder->subbitbuf <<= n;
    decoder->bitcount = bitcount;
    decoder->bitbuf   = bitbuf;
}

static unsigned short __fastcall getbits(UNLZHHandler decoder, unsigned char n)
{
    unsigned short x;

    x = decoder->bitbuf >> (2 * CHAR_BIT - n);
    fillbuf(decoder, n);
    return x;
}

static void __fastcall init_getbits(UNLZHHandler decoder)
{
    decoder->bitbuf = 0;
    decoder->subbitbuf = 0;
    decoder->bitcount = 0;
    decoder->inbuf_cnt = 0;
    decoder->inbuf_size = 0;
    fillbuf(decoder, 2 * CHAR_BIT);
}

DWORD  __fastcall lzhread(UNLZHHandler decoder, void *pBuffer, DWORD dwSize)
{
    DWORD dwRet;
    if(dwSize > SEEK_BLOCK){
        dwRet = 0;
        while(dwRet < dwSize){
            DWORD dwRead = SEEK_BLOCK;
            DWORD r;
            if(dwRet + SEEK_BLOCK > dwSize){
                dwRead = dwSize - dwRet;
            }
            r = unlzh(decoder, (char*)pBuffer + dwRet, dwRead);
            dwRet += r;
            if(r < dwRead){
                break;
            }
            lzhseek_SaveContext(decoder);
        }
        return dwRet;
    }
    else{
        dwRet = unlzh(decoder, (char*)pBuffer, dwSize);
        lzhseek_SaveContext(decoder);
        return dwRet;
    }
}
UINT64 __fastcall lzhseek(UNLZHHandler decoder, INT64 i64Pos, DWORD dwOrigin)
{
    switch(dwOrigin){
        case FILE_BEGIN:
            break;
        case FILE_CURRENT:
            i64Pos += (decoder->count - decoder->cpylen);
            break;
        case FILE_END:
            i64Pos += decoder->origsize;
            break;
    }
    if(i64Pos > decoder->origsize){
        i64Pos = decoder->origsize;
    }
    else if(i64Pos < 0){
        i64Pos = 0;
    }
    lzhseek_RestoreContext(decoder, i64Pos);
    return (decoder->count - decoder->cpylen);
    /*if(i64Pos > (decoder->count - decoder->cpylen)){
        BYTE tmp[16384];
        DWORD dwDiscard = i64Pos - (decoder->count - decoder->cpylen);
        while(dwDiscard){
            DWORD dwSize = dwDiscard;
            DWORD dwRet;
            if(dwSize > sizeof(tmp)){
                dwSize = sizeof(tmp);
            }
            dwRet = lzhread(decoder, tmp, dwSize);
            dwDiscard -= dwRet;
            if(dwRet < dwSize){
                break;
            }
        }
        i64Pos -= dwDiscard;
    }
    return i64Pos;
    */
}
void __fastcall lzhseek_SaveContext(UNLZHHandler decoder)
{//lzhseek 用に decoder の状態を保存する。
 //最新の context よりも SEEK_BLOCK だけ解凍したら保存する。
    UNLZHHandler pContext = decoder->pContext;
    DWORD dwCurrentPos = decoder->count - decoder->cpylen;
    DWORD dwNextBlock = SEEK_BLOCK;
    if(pContext){
        dwNextBlock += (pContext->count - pContext->cpylen);
    }
    if(dwCurrentPos > dwNextBlock){
        UNLZHHandler pNewContext = (UNLZHHandler)HeapAlloc(decoder->hHeap,
                                                           HEAP_NO_SERIALIZE,
                                                           sizeof(struct _UNLZHHandler));
        memcpy(pNewContext, decoder, sizeof(struct _UNLZHHandler));
        pNewContext->qwFilePointer = decoder->seek_func(0, FILE_CURRENT, decoder->user_val);
        pNewContext->pContext = pContext;
        decoder->pContext = pNewContext;
    }
}
void __fastcall lzhseek_RestoreContext(UNLZHHandler decoder, UINT64 qwPos)
{//lzhseek 用に decoder の状態を復帰する。
 //現在位置 <= qwPos < 現在位置 + SEEK_BLOCK であれば何もしない。
 //そうでなければ qwPos より手前で最も qwPos に近い context を探す。
    UNLZHHandler pContext = decoder->pContext;
    DWORD dwCurrentPos = decoder->count - decoder->cpylen;
    if(dwCurrentPos <= qwPos && qwPos < dwCurrentPos + SEEK_BLOCK){
        return;
    }
    while(pContext){
        if(qwPos >= (pContext->count - pContext->cpylen)){
            break;
        }
        pContext = pContext->pContext;
    }
    if(pContext){
        UNLZHHandler pContextSaved = decoder->pContext;
        memcpy(decoder, pContext, sizeof(struct _UNLZHHandler));
        decoder->pContext = pContextSaved;
        decoder->seek_func(decoder->qwFilePointer, FILE_BEGIN, decoder->user_val);
    }
    else{
        UNLZHHandler pContextSaved = decoder->pContext;
        HANDLE hHeapSaved = decoder->hHeap;
        init_unlzh_handler(decoder,
                           decoder->read_func, 
                           decoder->seek_func, 
                           method_table[decoder->method].id,
                           decoder->dwCompSize, 
                           decoder->origsize, 
                           decoder->user_val, 
                           decoder->qwStartFilePointer);
        decoder->hHeap = hHeapSaved;
        decoder->pContext = pContextSaved;
        decoder->seek_func(decoder->qwStartFilePointer, FILE_BEGIN, decoder->user_val);
    }
}
