1872 lines
43 KiB
C
1872 lines
43 KiB
C
/* $Id: LhA.c,v 1.16 2010/05/27 16:48:30 stoecker Exp $
|
|
LhA file archiver client
|
|
|
|
XAD library system for archive handling
|
|
Copyright (C) 1998 and later by Dirk Stoecker <soft@dstoecker.de>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library 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
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
/*
|
|
Modified for xmp by Claudio Matsuoka, 20120812
|
|
*/
|
|
|
|
#include "../common.h"
|
|
#include "depacker.h"
|
|
|
|
#define LZHUFF0_METHOD 0x2D6C6830 /* -lh0- */
|
|
#define LZHUFF1_METHOD 0x2D6C6831 /* -lh1- */
|
|
#define LZHUFF2_METHOD 0x2D6C6832 /* -lh2- */
|
|
#define LZHUFF3_METHOD 0x2D6C6833 /* -lh3- */
|
|
#define LZHUFF4_METHOD 0x2D6C6834 /* -lh4- */
|
|
#define LZHUFF5_METHOD 0x2D6C6835 /* -lh5- */
|
|
#define LZHUFF6_METHOD 0x2D6C6836 /* -lh6- */
|
|
#define LZHUFF7_METHOD 0x2D6C6837 /* -lh7- */
|
|
#define LZHUFF8_METHOD 0x2D6C6838 /* -lh8- */
|
|
#define LARC_METHOD 0x2D6C7A73 /* -lzs- */
|
|
#define LARC5_METHOD 0x2D6C7A35 /* -lz5- */
|
|
#define LARC4_METHOD 0x2D6C7A34 /* -lz4- */
|
|
#define PMARC0_METHOD 0x2D706D30 /* -pm0- */
|
|
#define PMARC2_METHOD 0x2D706D32 /* -pm2- */
|
|
|
|
#undef UCHAR_MAX
|
|
#define UCHAR_MAX ((1<<(sizeof(uint8)*8))-1)
|
|
#define MAX_DICBIT 16
|
|
#undef CHAR_BIT
|
|
#define CHAR_BIT 8
|
|
#define USHRT_BIT 16 /* (CHAR_BIT * sizeof(ushort)) */
|
|
#define MAXMATCH 256 /* not more than UCHAR_MAX + 1 */
|
|
#define NC (UCHAR_MAX + MAXMATCH + 2 - THRESHOLD)
|
|
#define THRESHOLD 3 /* choose optimal value */
|
|
#define NPT 0x80
|
|
#define CBIT 9 /* $\lfloor \log_2 NC \rfloor + 1$ */
|
|
#define TBIT 5 /* smallest integer such that (1 << TBIT) > * NT */
|
|
#define NT (USHRT_BIT + 3)
|
|
#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 N1 286 /* alphabet size */
|
|
#define EXTRABITS 8 /* >= log2(F-THRESHOLD+258-N1) */
|
|
#define BUFBITS 16 /* >= log2(MAXBUF) */
|
|
#define NP (MAX_DICBIT + 1)
|
|
#define LENFIELD 4 /* bit size of length field for tree output */
|
|
#define MAGIC0 18
|
|
#define MAGIC5 19
|
|
|
|
#ifdef ENABLE_PMARC
|
|
#define PMARC2_OFFSET (0x100 - 2)
|
|
struct PMARC2_Tree {
|
|
uint8 *leftarr;
|
|
uint8 *rightarr;
|
|
uint8 root;
|
|
};
|
|
#endif
|
|
|
|
struct LhADecrST {
|
|
int32 pbit;
|
|
int32 np;
|
|
int32 nn;
|
|
int32 n1;
|
|
int32 most_p;
|
|
int32 avail;
|
|
uint32 n_max;
|
|
uint16 maxmatch;
|
|
uint16 total_p;
|
|
uint16 blocksize;
|
|
uint16 c_table[4096];
|
|
uint16 pt_table[256];
|
|
uint16 left[2 * NC - 1];
|
|
uint16 right[2 * NC - 1];
|
|
uint16 freq[TREESIZE];
|
|
uint16 pt_code[NPT];
|
|
int16 child[TREESIZE];
|
|
int16 stock[TREESIZE];
|
|
int16 s_node[TREESIZE / 2];
|
|
int16 block[TREESIZE];
|
|
int16 parent[TREESIZE];
|
|
int16 edge[TREESIZE];
|
|
uint8 c_len[NC];
|
|
uint8 pt_len[NPT];
|
|
};
|
|
|
|
#ifdef ENABLE_PMARC
|
|
struct LhADecrPM {
|
|
struct PMARC2_Tree tree1;
|
|
struct PMARC2_Tree tree2;
|
|
|
|
uint16 lastupdate;
|
|
uint16 dicsiz1;
|
|
uint8 gettree1;
|
|
uint8 tree1left[32];
|
|
uint8 tree1right[32];
|
|
uint8 table1[32];
|
|
|
|
uint8 tree2left[8];
|
|
uint8 tree2right[8];
|
|
uint8 table2[8];
|
|
|
|
uint8 tree1bound;
|
|
uint8 mindepth;
|
|
|
|
/* Circular double-linked list. */
|
|
uint8 prev[0x100];
|
|
uint8 next[0x100];
|
|
uint8 parentarr[0x100];
|
|
uint8 lastbyte;
|
|
};
|
|
#endif
|
|
|
|
#ifdef ENABLE_LARC
|
|
struct LhADecrLZ {
|
|
int32 matchpos; /* LARC */
|
|
int32 flag; /* LARC */
|
|
int32 flagcnt; /* LARC */
|
|
};
|
|
#endif
|
|
|
|
struct LhADecrData {
|
|
int error;
|
|
HIO_HANDLE *in;
|
|
char *text;
|
|
uint16 DicBit;
|
|
|
|
uint16 bitbuf;
|
|
uint8 subbitbuf;
|
|
uint8 bitcount;
|
|
uint32 loc;
|
|
uint32 count;
|
|
uint32 nextcount;
|
|
|
|
union {
|
|
struct LhADecrST st;
|
|
#ifdef ENABLE_PMARC
|
|
struct LhADecrPM pm;
|
|
#endif
|
|
#ifdef ENABLE_LARC
|
|
struct LhADecrLZ lz;
|
|
#endif
|
|
} d;
|
|
};
|
|
|
|
/* Shift bitbuf n bits left, read n bits */
|
|
static inline void fillbuf(struct LhADecrData *dat, uint8 n)
|
|
{
|
|
#if 0
|
|
if(dat->error)
|
|
return;
|
|
#endif
|
|
|
|
while(n > dat->bitcount)
|
|
{
|
|
n -= dat->bitcount;
|
|
dat->bitbuf = (dat->bitbuf << dat->bitcount) + (dat->subbitbuf >> (CHAR_BIT - dat->bitcount));
|
|
dat->subbitbuf = hio_read8(dat->in);
|
|
|
|
dat->bitcount = CHAR_BIT;
|
|
}
|
|
dat->bitcount -= n;
|
|
dat->bitbuf = (dat->bitbuf << n) + (dat->subbitbuf >> (CHAR_BIT - n));
|
|
dat->subbitbuf <<= n;
|
|
}
|
|
|
|
static inline uint16 getbits(struct LhADecrData *dat, uint8 n)
|
|
{
|
|
uint16 x;
|
|
|
|
x = dat->bitbuf >> (2 * CHAR_BIT - n);
|
|
fillbuf(dat, n);
|
|
return x;
|
|
}
|
|
|
|
//#define init_getbits(a) fillbuf((a), 2* CHAR_BIT)
|
|
/* this function can be replaced by a define! */
|
|
static void init_getbits(struct LhADecrData *dat)
|
|
{
|
|
dat->bitbuf = 0;
|
|
dat->subbitbuf = 0;
|
|
dat->bitcount = 0;
|
|
fillbuf(dat, 2 * CHAR_BIT);
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
static int make_table(struct LhADecrData *dat, int16 nchar, uint8 bitlen[], int16 tablebits, uint16 table[], int table_size)
|
|
{
|
|
uint16 count[17]; /* count of bitlen */
|
|
uint16 weight[17]; /* 0x10000ul >> bitlen */
|
|
uint16 start[17]; /* first code of bitlen */
|
|
uint16 total;
|
|
uint32 i;
|
|
int32 j, k, l, m, n, avail;
|
|
uint16 *p;
|
|
|
|
#if 0
|
|
if(dat->error)
|
|
return;
|
|
#endif
|
|
|
|
avail = nchar;
|
|
|
|
memset(count, 0, 17*2);
|
|
for(i = 1; i <= 16; i++)
|
|
weight[i] = 1 << (16 - i);
|
|
|
|
/* count */
|
|
for(i = 0; i < nchar; i++)
|
|
{
|
|
if(bitlen[i] >= ARRAY_SIZE(count))
|
|
return -1;
|
|
count[bitlen[i]]++;
|
|
}
|
|
|
|
/* calculate first code */
|
|
total = 0;
|
|
for(i = 1; i <= 16; i++)
|
|
{
|
|
start[i] = total;
|
|
total += weight[i] * count[i];
|
|
}
|
|
if(total & 0xFFFF)
|
|
{
|
|
dat->error = 1;
|
|
return -1;
|
|
}
|
|
|
|
/* 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) {
|
|
|
|
/* Sanity check */
|
|
if (k > table_size) {
|
|
return -1;
|
|
}
|
|
|
|
for(i = j; i < k; i++)
|
|
table[i] = 0;
|
|
}
|
|
|
|
/* create table and tree */
|
|
for(j = 0; j < nchar; j++)
|
|
{
|
|
k = bitlen[j];
|
|
|
|
/* Sanity check */
|
|
if(k >= 17)
|
|
return -1;
|
|
|
|
if(k == 0)
|
|
continue;
|
|
l = start[k] + weight[k];
|
|
|
|
if(k <= tablebits)
|
|
{
|
|
/* Sanity check */
|
|
if (l > table_size) {
|
|
return -1;
|
|
}
|
|
|
|
/* code in table */
|
|
for(i = start[k]; i < l; i++)
|
|
table[i] = j;
|
|
}
|
|
else
|
|
{
|
|
#if 0
|
|
/* CID 156018 (#1 of 1): Logically dead code (DEADCODE)
|
|
* dead_error_line: Execution cannot reach this statement: return -1;
|
|
*/
|
|
/* Sanity check */
|
|
if(k >= 17)
|
|
return -1;
|
|
#endif
|
|
|
|
/* code not in table */
|
|
i = start[k];
|
|
p = &table[i >> m];
|
|
i <<= tablebits;
|
|
n = k - tablebits;
|
|
/* make tree (n length) */
|
|
while(--n >= 0)
|
|
{
|
|
if(*p == 0)
|
|
{
|
|
dat->d.st.right[avail] = dat->d.st.left[avail] = 0;
|
|
*p = avail++;
|
|
}
|
|
if(i & 0x8000)
|
|
p = &dat->d.st.right[*p];
|
|
else
|
|
p = &dat->d.st.left[*p];
|
|
i <<= 1;
|
|
}
|
|
*p = j;
|
|
}
|
|
start[k] = l;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
static int read_pt_len(struct LhADecrData *dat, int16 nn, int16 nbit, int16 i_special)
|
|
{
|
|
int16 i, c, n;
|
|
|
|
if(!(n = getbits(dat, nbit)))
|
|
{
|
|
c = getbits(dat, nbit);
|
|
for(i = 0; i < nn; i++)
|
|
dat->d.st.pt_len[i] = 0;
|
|
for(i = 0; i < 256; i++)
|
|
dat->d.st.pt_table[i] = c;
|
|
}
|
|
else
|
|
{
|
|
i = 0;
|
|
while(i < n)
|
|
{
|
|
c = dat->bitbuf >> (16 - 3);
|
|
if(c == 7)
|
|
{
|
|
uint16 mask;
|
|
|
|
mask = 1 << (16 - 4);
|
|
while(mask & dat->bitbuf)
|
|
{
|
|
mask >>= 1;
|
|
c++;
|
|
}
|
|
}
|
|
fillbuf(dat, (c < 7) ? 3 : c - 3);
|
|
dat->d.st.pt_len[i++] = c;
|
|
if(i == i_special)
|
|
{
|
|
c = getbits(dat, 2);
|
|
while(--c >= 0)
|
|
dat->d.st.pt_len[i++] = 0;
|
|
}
|
|
}
|
|
while(i < nn)
|
|
dat->d.st.pt_len[i++] = 0;
|
|
if (make_table(dat, nn, dat->d.st.pt_len, 8, dat->d.st.pt_table, 256) < 0)
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int read_c_len(struct LhADecrData *dat)
|
|
{
|
|
int16 i, c, n;
|
|
|
|
if(!(n = getbits(dat, CBIT)))
|
|
{
|
|
c = getbits(dat, CBIT);
|
|
for(i = 0; i < NC; i++)
|
|
dat->d.st.c_len[i] = 0;
|
|
for(i = 0; i < 4096; i++)
|
|
dat->d.st.c_table[i] = c;
|
|
}
|
|
else
|
|
{
|
|
/* Sanity check */
|
|
if (n > NC)
|
|
return -1;
|
|
|
|
i = 0;
|
|
while(i < n)
|
|
{
|
|
c = dat->d.st.pt_table[dat->bitbuf >> (16 - 8)];
|
|
if(c >= NT)
|
|
{
|
|
uint16 mask;
|
|
|
|
mask = 1 << (16 - 9);
|
|
do
|
|
{
|
|
if(dat->bitbuf & mask)
|
|
c = dat->d.st.right[c];
|
|
else
|
|
c = dat->d.st.left[c];
|
|
mask >>= 1;
|
|
} while(c >= NT);
|
|
}
|
|
fillbuf(dat, dat->d.st.pt_len[c]);
|
|
if(c <= 2)
|
|
{
|
|
if(!c)
|
|
c = 1;
|
|
else if(c == 1)
|
|
c = getbits(dat, 4) + 3;
|
|
else
|
|
c = getbits(dat, CBIT) + 20;
|
|
|
|
/* Sanity check */
|
|
if (i + c >= NC)
|
|
return -1;
|
|
|
|
while(--c >= 0)
|
|
dat->d.st.c_len[i++] = 0;
|
|
}
|
|
else
|
|
dat->d.st.c_len[i++] = c - 2;
|
|
}
|
|
while(i < NC)
|
|
dat->d.st.c_len[i++] = 0;
|
|
if (make_table(dat, NC, dat->d.st.c_len, 12, dat->d.st.c_table, 4096) < 0)
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int decode_c_st1(struct LhADecrData *dat)
|
|
{
|
|
uint16 j, mask;
|
|
|
|
if(!dat->d.st.blocksize)
|
|
{
|
|
dat->d.st.blocksize = getbits(dat, 16);
|
|
if (read_pt_len(dat, NT, TBIT, 3) < 0)
|
|
return -1;
|
|
if (read_c_len(dat) < 0)
|
|
return -1;
|
|
if (read_pt_len(dat, dat->d.st.np, dat->d.st.pbit, -1) < 0)
|
|
return -1;
|
|
}
|
|
dat->d.st.blocksize--;
|
|
j = dat->d.st.c_table[dat->bitbuf >> 4];
|
|
if(j < NC)
|
|
{
|
|
/* Sanity check - 0-length character encoding on the Huffman tree is
|
|
* invalid and can cause hangs here. */
|
|
if(dat->d.st.c_len[j] == 0)
|
|
return -1;
|
|
fillbuf(dat, dat->d.st.c_len[j]);
|
|
}
|
|
else
|
|
{
|
|
fillbuf(dat, 12);
|
|
mask = 1 << (16 - 1);
|
|
do
|
|
{
|
|
if(dat->bitbuf & mask)
|
|
j = dat->d.st.right[j];
|
|
else
|
|
j = dat->d.st.left[j];
|
|
mask >>= 1;
|
|
} while(j >= NC);
|
|
fillbuf(dat, dat->d.st.c_len[j] - 12);
|
|
}
|
|
return j;
|
|
}
|
|
|
|
static uint16 decode_p_st1(struct LhADecrData *dat)
|
|
{
|
|
uint16 j, mask;
|
|
|
|
j = dat->d.st.pt_table[dat->bitbuf >> (16 - 8)];
|
|
if(j < dat->d.st.np)
|
|
fillbuf(dat, dat->d.st.pt_len[j]);
|
|
else
|
|
{
|
|
fillbuf(dat, 8);
|
|
mask = 1 << (16 - 1);
|
|
do
|
|
{
|
|
if(dat->bitbuf & mask)
|
|
j = dat->d.st.right[j];
|
|
else
|
|
j = dat->d.st.left[j];
|
|
mask >>= 1;
|
|
} while(j >= dat->d.st.np);
|
|
fillbuf(dat, dat->d.st.pt_len[j] - 8);
|
|
}
|
|
if(j)
|
|
j = (1 << (j - 1)) + getbits(dat, j - 1);
|
|
return j;
|
|
}
|
|
|
|
static int decode_start_st1(struct LhADecrData *dat)
|
|
{
|
|
if(dat->DicBit <= 13)
|
|
{
|
|
dat->d.st.np = 14;
|
|
dat->d.st.pbit = 4;
|
|
}
|
|
else
|
|
{
|
|
if(dat->DicBit == 16)
|
|
dat->d.st.np = 17; /* for -lh7- */
|
|
else
|
|
dat->d.st.np = 16;
|
|
dat->d.st.pbit = 5;
|
|
}
|
|
init_getbits(dat);
|
|
// dat->d.st.blocksize = 0; /* done automatically */
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
static void start_c_dyn(struct LhADecrData *dat)
|
|
{
|
|
int32 i, j, f;
|
|
|
|
dat->d.st.n1 = (dat->d.st.n_max >= 256 + dat->d.st.maxmatch - THRESHOLD + 1) ? 512 : dat->d.st.n_max - 1;
|
|
for(i = 0; i < TREESIZE_C; i++)
|
|
{
|
|
dat->d.st.stock[i] = i;
|
|
dat->d.st.block[i] = 0;
|
|
}
|
|
for(i = 0, j = dat->d.st.n_max * 2 - 2; i < (int32) dat->d.st.n_max; i++, j--)
|
|
{
|
|
dat->d.st.freq[j] = 1;
|
|
dat->d.st.child[j] = ~i;
|
|
dat->d.st.s_node[i] = j;
|
|
dat->d.st.block[j] = 1;
|
|
}
|
|
dat->d.st.avail = 2;
|
|
dat->d.st.edge[1] = dat->d.st.n_max - 1;
|
|
i = dat->d.st.n_max * 2 - 2;
|
|
while(j >= 0)
|
|
{
|
|
f = dat->d.st.freq[j] = dat->d.st.freq[i] + dat->d.st.freq[i - 1];
|
|
dat->d.st.child[j] = i;
|
|
dat->d.st.parent[i] = dat->d.st.parent[i - 1] = j;
|
|
if(f == dat->d.st.freq[j + 1])
|
|
{
|
|
dat->d.st.edge[dat->d.st.block[j] = dat->d.st.block[j + 1]] = j;
|
|
}
|
|
else
|
|
{
|
|
dat->d.st.edge[dat->d.st.block[j] = dat->d.st.stock[dat->d.st.avail++]] = j;
|
|
}
|
|
i -= 2;
|
|
j--;
|
|
}
|
|
}
|
|
|
|
#ifdef ENABLE_LH2
|
|
|
|
static void start_p_dyn(struct LhADecrData *dat)
|
|
{
|
|
dat->d.st.freq[ROOT_P] = 1;
|
|
dat->d.st.child[ROOT_P] = ~(N_CHAR);
|
|
dat->d.st.s_node[N_CHAR] = ROOT_P;
|
|
dat->d.st.edge[dat->d.st.block[ROOT_P] = dat->d.st.stock[dat->d.st.avail++]] = ROOT_P;
|
|
dat->d.st.most_p = ROOT_P;
|
|
dat->d.st.total_p = 0;
|
|
dat->d.st.nn = 1 << dat->DicBit;
|
|
dat->nextcount = 64;
|
|
}
|
|
|
|
static void decode_start_dyn(struct LhADecrData *dat)
|
|
{
|
|
dat->d.st.n_max = 286;
|
|
dat->d.st.maxmatch = MAXMATCH;
|
|
init_getbits(dat);
|
|
start_c_dyn(dat);
|
|
start_p_dyn(dat);
|
|
}
|
|
|
|
#endif
|
|
|
|
static void reconst(struct LhADecrData *dat, int32 start, int32 end)
|
|
{
|
|
int32 i, j, k, l, b = 0;
|
|
uint32 f, g;
|
|
|
|
for(i = j = start; i < end; i++)
|
|
{
|
|
if((k = dat->d.st.child[i]) < 0)
|
|
{
|
|
dat->d.st.freq[j] = (dat->d.st.freq[i] + 1) / 2;
|
|
dat->d.st.child[j] = k;
|
|
j++;
|
|
}
|
|
if(dat->d.st.edge[b = dat->d.st.block[i]] == i)
|
|
{
|
|
dat->d.st.stock[--dat->d.st.avail] = b;
|
|
}
|
|
}
|
|
j--;
|
|
i = end - 1;
|
|
l = end - 2;
|
|
while(i >= start)
|
|
{
|
|
while(i >= l)
|
|
{
|
|
dat->d.st.freq[i] = dat->d.st.freq[j];
|
|
dat->d.st.child[i] = dat->d.st.child[j];
|
|
i--, j--;
|
|
}
|
|
f = dat->d.st.freq[l] + dat->d.st.freq[l + 1];
|
|
for(k = start; f < dat->d.st.freq[k]; k++)
|
|
;
|
|
while(j >= k)
|
|
{
|
|
dat->d.st.freq[i] = dat->d.st.freq[j];
|
|
dat->d.st.child[i] = dat->d.st.child[j];
|
|
i--, j--;
|
|
}
|
|
dat->d.st.freq[i] = f;
|
|
dat->d.st.child[i] = l + 1;
|
|
i--;
|
|
l -= 2;
|
|
}
|
|
f = 0;
|
|
for(i = start; i < end; i++)
|
|
{
|
|
if((j = dat->d.st.child[i]) < 0)
|
|
dat->d.st.s_node[~j] = i;
|
|
else
|
|
dat->d.st.parent[j] = dat->d.st.parent[j - 1] = i;
|
|
if((g = dat->d.st.freq[i]) == f) {
|
|
dat->d.st.block[i] = b;
|
|
}
|
|
else
|
|
{
|
|
dat->d.st.edge[b = dat->d.st.block[i] = dat->d.st.stock[dat->d.st.avail++]] = i;
|
|
f = g;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int32 swap_inc(struct LhADecrData *dat, int32 p)
|
|
{
|
|
int32 b, q, r, s;
|
|
|
|
b = dat->d.st.block[p];
|
|
if((q = dat->d.st.edge[b]) != p)
|
|
{ /* swap for leader */
|
|
r = dat->d.st.child[p];
|
|
s = dat->d.st.child[q];
|
|
dat->d.st.child[p] = s;
|
|
dat->d.st.child[q] = r;
|
|
if(r >= 0)
|
|
dat->d.st.parent[r] = dat->d.st.parent[r - 1] = q;
|
|
else
|
|
dat->d.st.s_node[~r] = q;
|
|
if(s >= 0)
|
|
dat->d.st.parent[s] = dat->d.st.parent[s - 1] = p;
|
|
else
|
|
dat->d.st.s_node[~s] = p;
|
|
p = q;
|
|
dat->d.st.edge[b]++;
|
|
if(++dat->d.st.freq[p] == dat->d.st.freq[p - 1])
|
|
{
|
|
dat->d.st.block[p] = dat->d.st.block[p - 1];
|
|
}
|
|
else
|
|
{
|
|
dat->d.st.edge[dat->d.st.block[p] = dat->d.st.stock[dat->d.st.avail++]] = p; /* create block */
|
|
}
|
|
}
|
|
else if(b == dat->d.st.block[p + 1])
|
|
{
|
|
dat->d.st.edge[b]++;
|
|
if(++dat->d.st.freq[p] == dat->d.st.freq[p - 1])
|
|
{
|
|
dat->d.st.block[p] = dat->d.st.block[p - 1];
|
|
}
|
|
else
|
|
{
|
|
dat->d.st.edge[dat->d.st.block[p] = dat->d.st.stock[dat->d.st.avail++]] = p; /* create block */
|
|
}
|
|
}
|
|
else if(++dat->d.st.freq[p] == dat->d.st.freq[p - 1])
|
|
{
|
|
dat->d.st.stock[--dat->d.st.avail] = b; /* delete block */
|
|
dat->d.st.block[p] = dat->d.st.block[p - 1];
|
|
}
|
|
return dat->d.st.parent[p];
|
|
}
|
|
|
|
#ifdef ENABLE_LH2
|
|
|
|
static void update_p(struct LhADecrData *dat, int32 p)
|
|
{
|
|
int32 q;
|
|
|
|
if(dat->d.st.total_p == 0x8000)
|
|
{
|
|
reconst(dat, ROOT_P, dat->d.st.most_p + 1);
|
|
dat->d.st.total_p = dat->d.st.freq[ROOT_P];
|
|
dat->d.st.freq[ROOT_P] = 0xffff;
|
|
}
|
|
q = dat->d.st.s_node[p + N_CHAR];
|
|
while(q != ROOT_P)
|
|
{
|
|
q = swap_inc(dat, q);
|
|
}
|
|
dat->d.st.total_p++;
|
|
}
|
|
|
|
static void make_new_node(struct LhADecrData *dat, int32 p)
|
|
{
|
|
int32 q, r;
|
|
|
|
r = dat->d.st.most_p + 1;
|
|
q = r + 1;
|
|
dat->d.st.s_node[~(dat->d.st.child[r] = dat->d.st.child[dat->d.st.most_p])] = r;
|
|
dat->d.st.child[q] = ~(p + N_CHAR);
|
|
dat->d.st.child[dat->d.st.most_p] = q;
|
|
dat->d.st.freq[r] = dat->d.st.freq[dat->d.st.most_p];
|
|
dat->d.st.freq[q] = 0;
|
|
dat->d.st.block[r] = dat->d.st.block[dat->d.st.most_p];
|
|
if(dat->d.st.most_p == ROOT_P)
|
|
{
|
|
dat->d.st.freq[ROOT_P] = 0xffff;
|
|
dat->d.st.edge[dat->d.st.block[ROOT_P]]++;
|
|
}
|
|
dat->d.st.parent[r] = dat->d.st.parent[q] = dat->d.st.most_p;
|
|
dat->d.st.edge[dat->d.st.block[q] = dat->d.st.stock[dat->d.st.avail++]] =
|
|
dat->d.st.s_node[p + N_CHAR] = dat->d.st.most_p = q;
|
|
update_p(dat, p);
|
|
}
|
|
|
|
#endif
|
|
|
|
static void update_c(struct LhADecrData *dat, int32 p)
|
|
{
|
|
int32 q;
|
|
|
|
if(dat->d.st.freq[ROOT_C] == 0x8000)
|
|
{
|
|
reconst(dat, 0, (int32) dat->d.st.n_max * 2 - 1);
|
|
}
|
|
dat->d.st.freq[ROOT_C]++;
|
|
q = dat->d.st.s_node[p];
|
|
do
|
|
{
|
|
q = swap_inc(dat, q);
|
|
} while(q != ROOT_C);
|
|
}
|
|
|
|
static int decode_c_dyn(struct LhADecrData *dat)
|
|
{
|
|
int32 c;
|
|
int16 buf, cnt;
|
|
|
|
c = dat->d.st.child[ROOT_C];
|
|
buf = dat->bitbuf;
|
|
cnt = 0;
|
|
do
|
|
{
|
|
c = dat->d.st.child[c - (buf < 0)];
|
|
buf <<= 1;
|
|
if(++cnt == 16)
|
|
{
|
|
fillbuf(dat, 16);
|
|
buf = dat->bitbuf;
|
|
cnt = 0;
|
|
}
|
|
} while(c > 0);
|
|
fillbuf(dat, cnt);
|
|
c = ~c;
|
|
update_c(dat, c);
|
|
if(c == dat->d.st.n1)
|
|
c += getbits(dat, 8);
|
|
return (uint16) c;
|
|
}
|
|
|
|
#ifdef ENABLE_LH2
|
|
|
|
static uint16 decode_p_dyn(struct LhADecrData *dat)
|
|
{
|
|
int32 c;
|
|
int16 buf, cnt;
|
|
|
|
while(dat->count > dat->nextcount)
|
|
{
|
|
make_new_node(dat, (int32) dat->nextcount / 64);
|
|
if((dat->nextcount += 64) >= (uint32)dat->d.st.nn)
|
|
dat->nextcount = 0xffffffff;
|
|
}
|
|
c = dat->d.st.child[ROOT_P];
|
|
buf = dat->bitbuf;
|
|
cnt = 0;
|
|
while(c > 0)
|
|
{
|
|
c = dat->d.st.child[c - (buf < 0)];
|
|
buf <<= 1;
|
|
if(++cnt == 16)
|
|
{
|
|
fillbuf(dat, 16);
|
|
buf = dat->bitbuf;
|
|
cnt = 0;
|
|
}
|
|
}
|
|
fillbuf(dat, cnt);
|
|
c = (~c) - N_CHAR;
|
|
update_p(dat, c);
|
|
|
|
return (uint16) ((c << 6) + getbits(dat, 6));
|
|
}
|
|
|
|
#endif
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
static const int32 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(struct LhADecrData *dat, int32 method)
|
|
{
|
|
int32 i, j;
|
|
uint32 code, weight;
|
|
int32 *tbl;
|
|
|
|
tbl = (int32 *) fixed[method];
|
|
j = *tbl++;
|
|
weight = 1 << (16 - j);
|
|
code = 0;
|
|
for(i = 0; i < dat->d.st.np; i++)
|
|
{
|
|
while(*tbl == i)
|
|
{
|
|
j++;
|
|
tbl++;
|
|
weight >>= 1;
|
|
}
|
|
dat->d.st.pt_len[i] = j;
|
|
dat->d.st.pt_code[i] = code;
|
|
code += weight;
|
|
}
|
|
}
|
|
|
|
static int decode_start_fix(struct LhADecrData *dat)
|
|
{
|
|
dat->d.st.n_max = 314;
|
|
dat->d.st.maxmatch = 60;
|
|
init_getbits(dat);
|
|
dat->d.st.np = 1 << (12 - 6);
|
|
start_c_dyn(dat);
|
|
ready_made(dat, 0);
|
|
if (make_table(dat, dat->d.st.np, dat->d.st.pt_len, 8, dat->d.st.pt_table, 256) < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static uint16 decode_p_st0(struct LhADecrData *dat)
|
|
{
|
|
int32 i, j;
|
|
|
|
j = dat->d.st.pt_table[dat->bitbuf >> 8];
|
|
if(j < dat->d.st.np)
|
|
{
|
|
fillbuf(dat, dat->d.st.pt_len[j]);
|
|
}
|
|
else
|
|
{
|
|
fillbuf(dat, 8);
|
|
i = dat->bitbuf;
|
|
do
|
|
{
|
|
if((int16) i < 0)
|
|
j = dat->d.st.right[j];
|
|
else
|
|
j = dat->d.st.left[j];
|
|
i <<= 1;
|
|
} while(j >= dat->d.st.np);
|
|
fillbuf(dat, dat->d.st.pt_len[j] - 8);
|
|
}
|
|
return (uint16)((j << 6) + getbits(dat, 6));
|
|
}
|
|
|
|
#ifdef ENABLE_LH3
|
|
|
|
static void decode_start_st0(struct LhADecrData *dat)
|
|
{
|
|
dat->d.st.n_max = 286;
|
|
dat->d.st.maxmatch = MAXMATCH;
|
|
init_getbits(dat);
|
|
dat->d.st.np = 1 << (MAX_DICBIT - 6);
|
|
}
|
|
|
|
static int read_tree_c(struct LhADecrData *dat) /* read tree from file */
|
|
{
|
|
int32 i, c;
|
|
|
|
i = 0;
|
|
while(i < N1)
|
|
{
|
|
if(getbits(dat, 1))
|
|
dat->d.st.c_len[i] = getbits(dat, LENFIELD) + 1;
|
|
else
|
|
dat->d.st.c_len[i] = 0;
|
|
if(++i == 3 && dat->d.st.c_len[0] == 1 && dat->d.st.c_len[1] == 1 && dat->d.st.c_len[2] == 1)
|
|
{
|
|
c = getbits(dat, CBIT);
|
|
memset(dat->d.st.c_len, 0, N1);
|
|
for(i = 0; i < 4096; i++)
|
|
dat->d.st.c_table[i] = c;
|
|
return 0;
|
|
}
|
|
}
|
|
if (make_table(dat, N1, dat->d.st.c_len, 12, dat->d.st.c_table, 4096) < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void read_tree_p(struct LhADecrData *dat) /* read tree from file */
|
|
{
|
|
int32 i, c;
|
|
|
|
i = 0;
|
|
while(i < NP)
|
|
{
|
|
dat->d.st.pt_len[i] = getbits(dat, LENFIELD);
|
|
if(++i == 3 && dat->d.st.pt_len[0] == 1 && dat->d.st.pt_len[1] == 1 && dat->d.st.pt_len[2] == 1)
|
|
{
|
|
c = getbits(dat, MAX_DICBIT - 6);
|
|
for(i = 0; i < NP; i++)
|
|
dat->d.st.c_len[i] = 0;
|
|
for(i = 0; i < 256; i++)
|
|
dat->d.st.c_table[i] = c;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int decode_c_st0(struct LhADecrData *dat)
|
|
{
|
|
int32 i, j;
|
|
|
|
if(!dat->d.st.blocksize) /* read block head */
|
|
{
|
|
dat->d.st.blocksize = getbits(dat, BUFBITS); /* read block blocksize */
|
|
if (read_tree_c(dat) < 0)
|
|
return -1;
|
|
if(getbits(dat, 1))
|
|
{
|
|
read_tree_p(dat);
|
|
}
|
|
else
|
|
{
|
|
ready_made(dat, 1);
|
|
}
|
|
if (make_table(dat, NP, dat->d.st.pt_len, 8, dat->d.st.pt_table, 256) < 0)
|
|
return -1;
|
|
}
|
|
dat->d.st.blocksize--;
|
|
j = dat->d.st.c_table[dat->bitbuf >> 4];
|
|
if(j < N1)
|
|
fillbuf(dat, dat->d.st.c_len[j]);
|
|
else
|
|
{
|
|
fillbuf(dat, 12);
|
|
i = dat->bitbuf;
|
|
do
|
|
{
|
|
if((int16) i < 0)
|
|
j = dat->d.st.right[j];
|
|
else
|
|
j = dat->d.st.left[j];
|
|
i <<= 1;
|
|
} while(j >= N1);
|
|
fillbuf(dat, dat->d.st.c_len[j] - 12);
|
|
}
|
|
if (j == N1 - 1)
|
|
j += getbits(dat, EXTRABITS);
|
|
return (uint16) j;
|
|
}
|
|
|
|
#endif
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
#ifdef ENABLE_PMARC
|
|
|
|
static const int32 PMARC2_historyBits[8] = { 3, 3, 4, 5, 5, 5, 6, 6};
|
|
static const int32 PMARC2_historyBase[8] = { 0, 8, 16, 32, 64, 96,128,192};
|
|
static const int32 PMARC2_repeatBits[6] = { 3, 3, 5, 6, 7, 0};
|
|
static const int32 PMARC2_repeatBase[6] = {17, 25, 33, 65,129,256};
|
|
|
|
static void PMARC2_hist_update(struct LhADecrData *dat, uint8 data)
|
|
{
|
|
if(data != dat->d.pm.lastbyte)
|
|
{
|
|
uint8 oldNext, oldPrev, newNext;
|
|
|
|
/* detach from old position */
|
|
oldNext = dat->d.pm.next[data];
|
|
oldPrev = dat->d.pm.prev[data];
|
|
dat->d.pm.prev[oldNext] = oldPrev;
|
|
dat->d.pm.next[oldPrev] = oldNext;
|
|
|
|
/* attach to new next */
|
|
newNext = dat->d.pm.next[dat->d.pm.lastbyte];
|
|
dat->d.pm.prev[newNext] = data;
|
|
dat->d.pm.next[data] = newNext;
|
|
|
|
/* attach to new prev */
|
|
dat->d.pm.prev[data] = dat->d.pm.lastbyte;
|
|
dat->d.pm.next[dat->d.pm.lastbyte] = data;
|
|
|
|
dat->d.pm.lastbyte = data;
|
|
}
|
|
}
|
|
|
|
static int32 PMARC2_tree_get(struct LhADecrData *dat, struct PMARC2_Tree *t)
|
|
{
|
|
int32 i;
|
|
i = t->root;
|
|
|
|
while (i < 0x80)
|
|
{
|
|
i = (getbits(dat, 1) == 0 ? t->leftarr[i] : t->rightarr[i] );
|
|
}
|
|
return i & 0x7F;
|
|
}
|
|
|
|
static void PMARC2_tree_rebuild(struct LhADecrData *dat, struct PMARC2_Tree *t,
|
|
uint8 bound, uint8 mindepth, uint8 * table)
|
|
{
|
|
uint8 d;
|
|
int32 i, curr, empty, n;
|
|
|
|
t->root = 0;
|
|
memset(t->leftarr, 0, bound);
|
|
memset(t->rightarr, 0, bound);
|
|
memset(dat->d.pm.parentarr, 0, bound);
|
|
|
|
for(i = 0; i < dat->d.pm.mindepth - 1; i++)
|
|
{
|
|
t->leftarr[i] = i + 1;
|
|
dat->d.pm.parentarr[i+1] = i;
|
|
}
|
|
|
|
curr = dat->d.pm.mindepth - 1;
|
|
empty = dat->d.pm.mindepth;
|
|
for(d = dat->d.pm.mindepth; ; d++)
|
|
{
|
|
for(i = 0; i < bound; i++)
|
|
{
|
|
if(table[i] == d)
|
|
{
|
|
if(t->leftarr[curr] == 0)
|
|
t->leftarr[curr] = i | 128;
|
|
else
|
|
{
|
|
t->rightarr[curr] = i | 128;
|
|
n = 0;
|
|
while(t->rightarr[curr] != 0)
|
|
{
|
|
if(curr == 0) /* root? -> done */
|
|
return;
|
|
curr = dat->d.pm.parentarr[curr];
|
|
n++;
|
|
}
|
|
t->rightarr[curr] = empty;
|
|
for(;;)
|
|
{
|
|
dat->d.pm.parentarr[empty] = curr;
|
|
curr = empty;
|
|
empty++;
|
|
|
|
n--;
|
|
if(n == 0)
|
|
break;
|
|
t->leftarr[curr] = empty;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(t->leftarr[curr] == 0)
|
|
t->leftarr[curr] = empty;
|
|
else
|
|
t->rightarr[curr] = empty;
|
|
|
|
dat->d.pm.parentarr[empty] = curr;
|
|
curr = empty;
|
|
empty++;
|
|
}
|
|
}
|
|
|
|
static uint8 PMARC2_hist_lookup(struct LhADecrData *dat, int32 n)
|
|
{
|
|
uint8 i;
|
|
uint8 *direction = dat->d.pm.prev;
|
|
|
|
if(n >= 0x80)
|
|
{
|
|
/* Speedup: If you have to process more than half the ring,
|
|
it's faster to walk the other way around. */
|
|
direction = dat->d.pm.next;
|
|
n = 0x100 - n;
|
|
}
|
|
for(i = dat->d.pm.lastbyte; n != 0; n--)
|
|
i = direction[i];
|
|
return i;
|
|
}
|
|
|
|
static void PMARC2_maketree1(struct LhADecrData *dat)
|
|
{
|
|
int32 i, nbits, x;
|
|
|
|
dat->d.pm.tree1bound = getbits(dat, 5);
|
|
dat->d.pm.mindepth = getbits(dat, 3);
|
|
|
|
if(dat->d.pm.mindepth == 0)
|
|
dat->d.pm.tree1.root = 128 | (dat->d.pm.tree1bound - 1);
|
|
else
|
|
{
|
|
memset(dat->d.pm.table1, 0, 32);
|
|
nbits = getbits(dat, 3);
|
|
for(i = 0; i < dat->d.pm.tree1bound; i++)
|
|
{
|
|
if((x = getbits(dat, nbits)))
|
|
dat->d.pm.table1[i] = x - 1 + dat->d.pm.mindepth;
|
|
}
|
|
PMARC2_tree_rebuild(dat, &dat->d.pm.tree1, dat->d.pm.tree1bound,
|
|
dat->d.pm.mindepth, dat->d.pm.table1);
|
|
}
|
|
}
|
|
|
|
static void PMARC2_maketree2(struct LhADecrData *dat, int32 par_b)
|
|
/* in use: 5 <= par_b <= 8 */
|
|
{
|
|
int32 i, count, index;
|
|
|
|
if(dat->d.pm.tree1bound < 10)
|
|
return;
|
|
if(dat->d.pm.tree1bound == 29 && dat->d.pm.mindepth == 0)
|
|
return;
|
|
|
|
for(i = 0; i < 8; i++)
|
|
dat->d.pm.table2[i] = 0;
|
|
for(i = 0; i < par_b; i++)
|
|
dat->d.pm.table2[i] = getbits(dat, 3);
|
|
index = 0;
|
|
count = 0;
|
|
for(i = 0; i < 8; i++)
|
|
{
|
|
if(dat->d.pm.table2[i] != 0)
|
|
{
|
|
index = i;
|
|
count++;
|
|
}
|
|
}
|
|
|
|
if(count == 1)
|
|
{
|
|
dat->d.pm.tree2.root = 128 | index;
|
|
}
|
|
else if (count > 1)
|
|
{
|
|
dat->d.pm.mindepth = 1;
|
|
PMARC2_tree_rebuild(dat, &dat->d.pm.tree2, 8, dat->d.pm.mindepth, dat->d.pm.table2);
|
|
}
|
|
/* Note: count == 0 is possible! */
|
|
}
|
|
|
|
static void decode_start_pm2(struct LhADecrData *dat)
|
|
{
|
|
int32 i;
|
|
|
|
dat->d.pm.tree1.leftarr = dat->d.pm.tree1left;
|
|
dat->d.pm.tree1.rightarr = dat->d.pm.tree1right;
|
|
/* dat->d.pm.tree1.root = 0; */
|
|
dat->d.pm.tree2.leftarr = dat->d.pm.tree2left;
|
|
dat->d.pm.tree2.rightarr = dat->d.pm.tree2right;
|
|
/* dat->d.pm.tree2.root = 0; */
|
|
|
|
dat->d.pm.dicsiz1 = (1 << dat->DicBit) - 1;
|
|
init_getbits(dat);
|
|
|
|
/* history init */
|
|
for(i = 0; i < 0x100; i++)
|
|
{
|
|
dat->d.pm.prev[(0xFF + i) & 0xFF] = i;
|
|
dat->d.pm.next[(0x01 + i) & 0xFF] = i;
|
|
}
|
|
dat->d.pm.prev[0x7F] = 0x00; dat->d.pm.next[0x00] = 0x7F;
|
|
dat->d.pm.prev[0xDF] = 0x80; dat->d.pm.next[0x80] = 0xDF;
|
|
dat->d.pm.prev[0x9F] = 0xE0; dat->d.pm.next[0xE0] = 0x9F;
|
|
dat->d.pm.prev[0x1F] = 0xA0; dat->d.pm.next[0xA0] = 0x1F;
|
|
dat->d.pm.prev[0xFF] = 0x20; dat->d.pm.next[0x20] = 0xFF;
|
|
dat->d.pm.lastbyte = 0x20;
|
|
|
|
/* dat->nextcount = 0; */
|
|
/* dat->d.pm.lastupdate = 0; */
|
|
getbits(dat, 1); /* discard bit */
|
|
}
|
|
|
|
static uint16 decode_c_pm2(struct LhADecrData *dat)
|
|
{
|
|
/* various admin: */
|
|
while(dat->d.pm.lastupdate != dat->loc)
|
|
{
|
|
PMARC2_hist_update(dat, dat->text[dat->d.pm.lastupdate]);
|
|
dat->d.pm.lastupdate = (dat->d.pm.lastupdate + 1) & dat->d.pm.dicsiz1;
|
|
}
|
|
while(dat->count >= dat->nextcount)
|
|
/* Actually it will never loop, because count doesn't grow that fast.
|
|
However, this is the way does it.
|
|
Probably other encoding methods can have repeats larger than 256 bytes.
|
|
Note: puts this code in decode_p...
|
|
*/
|
|
{
|
|
if(dat->nextcount == 0x0000)
|
|
{
|
|
PMARC2_maketree1(dat);
|
|
PMARC2_maketree2(dat, 5);
|
|
dat->nextcount = 0x0400;
|
|
}
|
|
else if(dat->nextcount == 0x0400)
|
|
{
|
|
PMARC2_maketree2(dat, 6);
|
|
dat->nextcount = 0x0800;
|
|
}
|
|
else if(dat->nextcount == 0x0800)
|
|
{
|
|
PMARC2_maketree2(dat, 7);
|
|
dat->nextcount = 0x1000;
|
|
}
|
|
else if(dat->nextcount == 0x1000)
|
|
{
|
|
if(getbits(dat, 1) != 0)
|
|
PMARC2_maketree1(dat);
|
|
PMARC2_maketree2(dat, 8);
|
|
dat->nextcount = 0x2000;
|
|
}
|
|
else
|
|
{ /* 0x2000, 0x3000, 0x4000, ... */
|
|
if(getbits(dat, 1) != 0)
|
|
{
|
|
PMARC2_maketree1(dat);
|
|
PMARC2_maketree2(dat, 8);
|
|
}
|
|
dat->nextcount += 0x1000;
|
|
}
|
|
}
|
|
dat->d.pm.gettree1 = PMARC2_tree_get(dat, &dat->d.pm.tree1); /* value preserved for decode_p */
|
|
|
|
/* direct value (ret <= UCHAR_MAX) */
|
|
if(dat->d.pm.gettree1 < 8)
|
|
{
|
|
return (uint16) (PMARC2_hist_lookup(dat, PMARC2_historyBase[dat->d.pm.gettree1]
|
|
+ getbits(dat, PMARC2_historyBits[dat->d.pm.gettree1])));
|
|
}
|
|
|
|
/* repeats: (ret > UCHAR_MAX) */
|
|
if(dat->d.pm.gettree1 < 23)
|
|
{
|
|
return (uint16) (PMARC2_OFFSET + 2 + (dat->d.pm.gettree1 - 8));
|
|
}
|
|
|
|
return (uint16) (PMARC2_OFFSET + PMARC2_repeatBase[dat->d.pm.gettree1 - 23]
|
|
+ getbits(dat, PMARC2_repeatBits[dat->d.pm.gettree1 - 23]));
|
|
}
|
|
|
|
static uint16 decode_p_pm2(struct LhADecrData *dat)
|
|
{
|
|
/* gettree1 value preserved from decode_c */
|
|
int32 nbits, delta, gettree2;
|
|
|
|
if(dat->d.pm.gettree1 == 8)
|
|
{ /* 2-byte repeat with offset 0..63 */
|
|
nbits = 6; delta = 0;
|
|
}
|
|
else if(dat->d.pm.gettree1 < 28)
|
|
{ /* n-byte repeat with offset 0..8191 */
|
|
if(!(gettree2 = PMARC2_tree_get(dat, &dat->d.pm.tree2)))
|
|
{
|
|
nbits = 6;
|
|
delta = 0;
|
|
}
|
|
else
|
|
{ /* 1..7 */
|
|
nbits = 5 + gettree2;
|
|
delta = 1 << nbits;
|
|
}
|
|
}
|
|
else
|
|
{ /* 256 bytes repeat with offset 0 */
|
|
nbits = 0;
|
|
delta = 0;
|
|
}
|
|
return (uint16) (delta + getbits(dat, nbits));
|
|
}
|
|
|
|
#endif
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
#ifdef ENABLE_LARC
|
|
|
|
static uint16 decode_c_lzs(struct LhADecrData *dat)
|
|
{
|
|
if(getbits(dat, 1))
|
|
{
|
|
return getbits(dat, 8);
|
|
}
|
|
else
|
|
{
|
|
dat->d.lz.matchpos = getbits(dat, 11);
|
|
return (uint16) (getbits(dat, 4) + 0x100);
|
|
}
|
|
}
|
|
|
|
static uint16 decode_p_lzs(struct LhADecrData *dat)
|
|
{
|
|
return (uint16) ((dat->loc - dat->d.lz.matchpos - MAGIC0) & 0x7ff);
|
|
}
|
|
|
|
static void decode_start_lzs(struct LhADecrData *dat)
|
|
{
|
|
init_getbits(dat);
|
|
}
|
|
|
|
static uint16 decode_c_lz5(struct LhADecrData *dat)
|
|
{
|
|
int32 c;
|
|
|
|
if(!dat->d.lz.flagcnt)
|
|
{
|
|
dat->d.lz.flagcnt = 8;
|
|
dat->d.lz.flag = fgetc(dat->in);
|
|
}
|
|
dat->d.lz.flagcnt--;
|
|
c = fgetc(dat->in);
|
|
if((dat->d.lz.flag & 1) == 0)
|
|
{
|
|
dat->d.lz.matchpos = c;
|
|
c = fgetc(dat->in);
|
|
dat->d.lz.matchpos += (c & 0xf0) << 4;
|
|
c &= 0x0f;
|
|
c += 0x100;
|
|
}
|
|
dat->d.lz.flag >>= 1;
|
|
return (uint16) c;
|
|
}
|
|
|
|
static uint16 decode_p_lz5(struct LhADecrData *dat)
|
|
{
|
|
return (uint16) ((dat->loc - dat->d.lz.matchpos - MAGIC5) & 0xfff);
|
|
}
|
|
|
|
static void decode_start_lz5(struct LhADecrData *dat)
|
|
{
|
|
int32 i;
|
|
char *text;
|
|
|
|
text = dat->text;
|
|
|
|
dat->d.lz.flagcnt = 0;
|
|
|
|
for(i = 0; i < 256; i++)
|
|
memset(text + i * 13 + 18, i, 13);
|
|
|
|
for(i = 0; i < 256; i++)
|
|
text[256 * 13 + 18 + i] = i;
|
|
|
|
for(i = 0; i < 256; i++)
|
|
text[256 * 13 + 256 + 18 + i] = 255 - i;
|
|
|
|
memset(text + 256 * 13 + 512 + 18, 0, 128);
|
|
memset(text + 256 * 13 + 512 + 128 + 18, ' ', 128-18);
|
|
}
|
|
|
|
#endif
|
|
|
|
static int32 LhA_Decrunch(HIO_HANDLE *in, FILE *out, int size, uint32 Method)
|
|
{
|
|
struct LhADecrData *dd;
|
|
int32 err = 0;
|
|
|
|
dd = (struct LhADecrData *) calloc(1, sizeof(struct LhADecrData));
|
|
if(dd) {
|
|
int (*DecodeStart)(struct LhADecrData *);
|
|
int (*DecodeC)(struct LhADecrData *);
|
|
uint16 (*DecodeP)(struct LhADecrData *);
|
|
|
|
/* most often used stuff */
|
|
dd->in = in;
|
|
dd->DicBit = 13;
|
|
DecodeStart = decode_start_st1;
|
|
DecodeP = decode_p_st1;
|
|
DecodeC = decode_c_st1;
|
|
|
|
switch(Method)
|
|
{
|
|
case LZHUFF1_METHOD:
|
|
dd->DicBit = 12;
|
|
DecodeStart = decode_start_fix;
|
|
DecodeC = decode_c_dyn;
|
|
DecodeP = decode_p_st0;
|
|
break;
|
|
|
|
#ifdef ENABLE_LH2
|
|
case LZHUFF2_METHOD:
|
|
DecodeStart = decode_start_dyn;
|
|
DecodeC = decode_c_dyn;
|
|
DecodeP = decode_p_dyn;
|
|
break;
|
|
#endif
|
|
|
|
#ifdef ENABLE_LH3
|
|
case LZHUFF3_METHOD:
|
|
DecodeStart = decode_start_st0;
|
|
DecodeP = decode_p_st0;
|
|
DecodeC = decode_c_st0;
|
|
break;
|
|
#endif
|
|
|
|
#ifdef ENABLE_PMARC
|
|
case PMARC2_METHOD:
|
|
DecodeStart = decode_start_pm2;
|
|
DecodeP = decode_p_pm2;
|
|
DecodeC = decode_c_pm2;
|
|
break;
|
|
#endif
|
|
|
|
case LZHUFF4_METHOD:
|
|
dd->DicBit = 12;
|
|
// break;
|
|
case LZHUFF5_METHOD:
|
|
break;
|
|
case LZHUFF6_METHOD:
|
|
dd->DicBit = 15;
|
|
break;
|
|
case LZHUFF7_METHOD:
|
|
dd->DicBit = 16;
|
|
break;
|
|
case LZHUFF8_METHOD:
|
|
dd->DicBit = 17;
|
|
break;
|
|
|
|
#ifdef ENABLE_LARC
|
|
case LARC_METHOD:
|
|
dd->DicBit = 11;
|
|
DecodeStart = decode_start_lzs;
|
|
DecodeC = decode_c_lzs;
|
|
DecodeP = decode_p_lzs;
|
|
break;
|
|
case LARC5_METHOD:
|
|
dd->DicBit = 12;
|
|
DecodeStart = decode_start_lz5;
|
|
DecodeC = decode_c_lz5;
|
|
DecodeP = decode_p_lz5;
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
err = 1; break;
|
|
}
|
|
if(!err)
|
|
{
|
|
char *text;
|
|
int32 i, c, offset;
|
|
uint32 dicsiz;
|
|
|
|
dicsiz = 1 << dd->DicBit;
|
|
|
|
#ifdef ENABLE_LARC
|
|
offset = (Method == LARC_METHOD || Method == PMARC2_METHOD) ? 0x100 - 2 : 0x100 - 3;
|
|
#else
|
|
offset = 0x100 - 3;
|
|
#endif
|
|
|
|
text = dd->text = (char *) malloc(dicsiz);
|
|
if (text)
|
|
{
|
|
/* if(Method == LZHUFF1_METHOD || Method == LZHUFF2_METHOD || Method == LZHUFF3_METHOD ||
|
|
Method == LZHUFF6_METHOD || Method == LARC_METHOD || Method == LARC5_METHOD)
|
|
*/
|
|
memset(text, ' ', dicsiz);
|
|
|
|
if (DecodeStart(dd) < 0) {
|
|
goto error;
|
|
}
|
|
|
|
--dicsiz; /* now used with AND */
|
|
while(1)
|
|
{
|
|
if (dd->count >= size)
|
|
break;
|
|
|
|
if(hio_eof(dd->in))
|
|
break;
|
|
|
|
c = DecodeC(dd);
|
|
if (c < 0) {
|
|
goto error;
|
|
}
|
|
|
|
if(dd->error)
|
|
break;
|
|
|
|
if(c <= UCHAR_MAX)
|
|
{
|
|
int res = fputc(c, out);
|
|
if (res < 0) {
|
|
goto error;
|
|
}
|
|
text[dd->loc++] = res;
|
|
dd->loc &= dicsiz;
|
|
dd->count++;
|
|
}
|
|
else
|
|
{
|
|
c -= offset;
|
|
i = dd->loc - DecodeP(dd) - 1;
|
|
dd->count += c;
|
|
while(c--)
|
|
{
|
|
int res = fputc(text[i++ & dicsiz], out);
|
|
if (res < 0) {
|
|
goto error;
|
|
}
|
|
text[dd->loc++] = res;
|
|
dd->loc &= dicsiz;
|
|
}
|
|
}
|
|
}
|
|
err = dd->error;
|
|
free(text);
|
|
}
|
|
else
|
|
err = -1;
|
|
}
|
|
free(dd);
|
|
}
|
|
else
|
|
err = -1;
|
|
return err;
|
|
|
|
error:
|
|
free(dd->text);
|
|
free(dd);
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* For xmp
|
|
*/
|
|
|
|
struct lha_data {
|
|
int method;
|
|
char name[256];
|
|
int packed_size;
|
|
int original_size;
|
|
int crc;
|
|
};
|
|
|
|
/*
|
|
* level 0 header
|
|
*
|
|
*
|
|
* offset size field name
|
|
* ----------------------------------
|
|
* 0 1 header size [*1]
|
|
* 1 1 header sum
|
|
* ---------------------------------------
|
|
* 2 5 method ID ^
|
|
* 7 4 packed size [*2] |
|
|
* 11 4 original size |
|
|
* 15 2 time |
|
|
* 17 2 date |
|
|
* 19 1 attribute | [*1] header size (X+Y+22)
|
|
* 20 1 level (0x00 fixed) |
|
|
* 21 1 name length |
|
|
* 22 X pathname |
|
|
* X +22 2 file crc (CRC-16) |
|
|
* X +24 Y ext-header(old style) v
|
|
* -------------------------------------------------
|
|
* X+Y+24 data ^
|
|
* : | [*2] packed size
|
|
* : v
|
|
* -------------------------------------------------
|
|
*
|
|
* ext-header(old style)
|
|
* 0 1 ext-type ('U')
|
|
* 1 1 minor version
|
|
* 2 4 UNIX time
|
|
* 6 2 mode
|
|
* 8 2 uid
|
|
* 10 2 gid
|
|
*
|
|
* attribute (MS-DOS)
|
|
* bit1 read only
|
|
* bit2 hidden
|
|
* bit3 system
|
|
* bit4 volume label
|
|
* bit5 directory
|
|
* bit6 archive bit (need to backup)
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* level 1 header
|
|
*
|
|
*
|
|
* offset size field name
|
|
* -----------------------------------
|
|
* 0 1 header size [*1]
|
|
* 1 1 header sum
|
|
* -------------------------------------
|
|
* 2 5 method ID ^
|
|
* 7 4 skip size [*2] |
|
|
* 11 4 original size |
|
|
* 15 2 time |
|
|
* 17 2 date |
|
|
* 19 1 attribute (0x20 fixed) | [*1] header size (X+Y+25)
|
|
* 20 1 level (0x01 fixed) |
|
|
* 21 1 name length |
|
|
* 22 X filename |
|
|
* X+ 22 2 file crc (CRC-16) |
|
|
* X+ 24 1 OS ID |
|
|
* X +25 Y ??? |
|
|
* X+Y+25 2 next-header size v
|
|
* -------------------------------------------------
|
|
* X+Y+27 Z ext-header ^
|
|
* : |
|
|
* ----------------------------------- | [*2] skip size
|
|
* X+Y+Z+27 data |
|
|
* : v
|
|
* -------------------------------------------------
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* level 2 header
|
|
*
|
|
*
|
|
* offset size field name
|
|
* --------------------------------------------------
|
|
* 0 2 total header size [*1] ^
|
|
* ----------------------- |
|
|
* 2 5 method ID |
|
|
* 7 4 packed size [*2] |
|
|
* 11 4 original size |
|
|
* 15 4 time |
|
|
* 19 1 RESERVED (0x20 fixed) | [*1] total header size
|
|
* 20 1 level (0x02 fixed) | (X+26+(1))
|
|
* 21 2 file crc (CRC-16) |
|
|
* 23 1 OS ID |
|
|
* 24 2 next-header size |
|
|
* ----------------------------------- |
|
|
* 26 X ext-header |
|
|
* : |
|
|
* ----------------------------------- |
|
|
* X +26 (1) padding v
|
|
* -------------------------------------------------
|
|
* X +26+(1) data ^
|
|
* : | [*2] packed size
|
|
* : v
|
|
* -------------------------------------------------
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* level 3 header
|
|
*
|
|
*
|
|
* offset size field name
|
|
* --------------------------------------------------
|
|
* 0 2 size field length (4 fixed) ^
|
|
* 2 5 method ID |
|
|
* 7 4 packed size [*2] |
|
|
* 11 4 original size |
|
|
* 15 4 time |
|
|
* 19 1 RESERVED (0x20 fixed) | [*1] total header size
|
|
* 20 1 level (0x03 fixed) | (X+32)
|
|
* 21 2 file crc (CRC-16) |
|
|
* 23 1 OS ID |
|
|
* 24 4 total header size [*1] |
|
|
* 28 4 next-header size |
|
|
* ----------------------------------- |
|
|
* 32 X ext-header |
|
|
* : v
|
|
* -------------------------------------------------
|
|
* X +32 data ^
|
|
* : | [*2] packed size
|
|
* : v
|
|
* -------------------------------------------------
|
|
*
|
|
*/
|
|
|
|
static int get_header(HIO_HANDLE *f, struct lha_data *data)
|
|
{
|
|
uint8 buf[21];
|
|
int size, level, namelen;
|
|
|
|
memset(data, 0, sizeof(struct lha_data));
|
|
if (hio_read(buf, 1, 21, f) != 21)
|
|
return -1;
|
|
level = buf[20];
|
|
|
|
switch (level) {
|
|
case 0:
|
|
size = buf[0];
|
|
data->method = readmem32b(buf + 2);
|
|
data->packed_size = readmem32l(buf + 7);
|
|
data->original_size = readmem32l(buf + 11);
|
|
namelen = hio_read8(f);
|
|
if (hio_error(f) != 0) {
|
|
return -1;
|
|
}
|
|
if (hio_read(data->name, 1, namelen, f) != namelen) {
|
|
return -1;
|
|
}
|
|
data->crc = hio_read16l(f);
|
|
if (hio_error(f) != 0) {
|
|
return -1;
|
|
}
|
|
if (hio_seek(f, size + 2 - 24 - namelen, SEEK_CUR) < 0) {
|
|
return -1;
|
|
}
|
|
break;
|
|
case 1:
|
|
size = buf[0];
|
|
data->method = readmem32b(buf + 2);
|
|
data->packed_size = readmem32l(buf + 7);
|
|
data->original_size = readmem32l(buf + 11);
|
|
namelen = hio_read8(f);
|
|
if (hio_error(f) != 0) {
|
|
return -1;
|
|
}
|
|
if (data->packed_size <= 0)
|
|
return -1;
|
|
if (hio_read(data->name, 1, namelen, f) != namelen) {
|
|
return -1;
|
|
}
|
|
data->crc = hio_read16l(f);
|
|
if (hio_error(f) != 0) {
|
|
return -1;
|
|
}
|
|
if (hio_seek(f, size - (22 + namelen) - 2, SEEK_CUR) < 0) {
|
|
return -1;
|
|
}
|
|
while ((size = hio_read16l(f)) != 0) {
|
|
if (hio_error(f) != 0) {
|
|
return -1;
|
|
}
|
|
if (hio_seek(f, size - 2, SEEK_CUR) < 0) {
|
|
return -1;
|
|
}
|
|
data->packed_size -= size;
|
|
}
|
|
break;
|
|
case 2:
|
|
size = readmem16l(buf);
|
|
/* fall through */
|
|
case 3:
|
|
data->method = readmem32b(buf + 2);
|
|
data->packed_size = readmem32l(buf + 7);
|
|
data->original_size = readmem32l(buf + 11);
|
|
data->crc = hio_read16l(f);
|
|
if (hio_error(f) != 0) {
|
|
return -1;
|
|
}
|
|
hio_read8(f); /* skip OS id */
|
|
if (hio_error(f) != 0) {
|
|
return -1;
|
|
}
|
|
while ((size = hio_read16l(f)) != 0) {
|
|
int type;
|
|
int s = size - 3;
|
|
if (hio_error(f) != 0) {
|
|
return -1;
|
|
}
|
|
type = hio_read8(f);
|
|
if (hio_error(f) != 0) {
|
|
return -1;
|
|
}
|
|
if (type == 0x01) {
|
|
/* Sanity check */
|
|
if (s < 0 || s > 256) {
|
|
return -1;
|
|
}
|
|
if (hio_read(data->name, 1, s, f) != s) {
|
|
return -1;
|
|
}
|
|
} else {
|
|
if (hio_seek(f, s, SEEK_CUR) < 0) {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int test_lha(unsigned char *b) {
|
|
return b[2] == '-' && b[3] == 'l' && b[4] == 'h' && b[6] == '-' &&
|
|
b[20] <= 3;
|
|
}
|
|
|
|
static int decrunch_lha(HIO_HANDLE *in, FILE *out, long inlen)
|
|
{
|
|
struct lha_data data;
|
|
|
|
while (1) {
|
|
if (get_header(in, &data) < 0)
|
|
break;
|
|
|
|
#if 0
|
|
printf("method = %x\n", data.method);
|
|
printf("name = %s\n", data.name);
|
|
printf("packed size = %d\n", data.packed_size);
|
|
printf("original size = %d\n", data.original_size);
|
|
printf("position = %lx\n", hio_tell(in));
|
|
#endif
|
|
|
|
if (data.packed_size <= 0)
|
|
return -1;
|
|
|
|
if (libxmp_exclude_match(data.name)) {
|
|
if (hio_seek(in, data.packed_size, SEEK_CUR) < 0) {
|
|
return -1;
|
|
}
|
|
continue;
|
|
}
|
|
return LhA_Decrunch(in, out, data.original_size, data.method);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
struct depacker libxmp_depacker_lha = {
|
|
test_lha,
|
|
decrunch_lha,
|
|
NULL
|
|
};
|