2006-04-13 20:47:06 +00:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
2009-01-10 07:38:50 +00:00
|
|
|
#include "compat.h"
|
2006-04-13 20:47:06 +00:00
|
|
|
#if defined(__POWERPC__)
|
2009-01-09 09:29:17 +00:00
|
|
|
static uint32_t LSWAPIB(uint32_t a) { return(((a>>8)&0xff00)+((a&0xff00)<<8)+(a<<24)+(a>>24)); }
|
|
|
|
static uint16_t SSWAPIB(uint16_t a) { return((a>>8)+(a<<8)); }
|
2006-04-13 20:47:06 +00:00
|
|
|
#else
|
|
|
|
#define LSWAPIB(a) (a)
|
|
|
|
#define SSWAPIB(a) (a)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define USENEW 1
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t lzwcompress(char *ucompbuf, int32_t ucompleng, char *compbuf)
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t i, j, numnodes, *lptr, bitcnt, nbits, oneupnbits, hmask, *child;
|
|
|
|
int32_t *sibly;
|
2006-04-13 20:47:06 +00:00
|
|
|
#if USENEW
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t *sibry;
|
2006-04-13 20:47:06 +00:00
|
|
|
#endif
|
2009-01-09 09:29:17 +00:00
|
|
|
char *nodev, *cptr, *eptr;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
nodev = (char *)malloc((ucompleng+256)*sizeof(uint8_t)); if (!nodev) return(0);
|
|
|
|
child = (int32_t *)malloc((ucompleng+256)*sizeof(int32_t)); if (!child) { free(nodev); return(0); }
|
|
|
|
sibly = (int32_t *)malloc((ucompleng+256)*sizeof(int32_t)); if (!sibly) { free(child); free(nodev); return(0); }
|
2006-04-13 20:47:06 +00:00
|
|
|
#if USENEW
|
2009-01-09 09:29:17 +00:00
|
|
|
sibry = (int32_t *)malloc((ucompleng+256)*sizeof(int32_t)); if (!sibry) { free(sibly); free(child); free(nodev); return(0); }
|
2006-04-13 20:47:06 +00:00
|
|
|
#endif
|
|
|
|
|
2009-02-19 16:47:54 +00:00
|
|
|
for (i=255; i>=0; i--) { nodev[i] = i; child[i] = -1; }
|
2006-04-24 19:04:22 +00:00
|
|
|
memset(compbuf,0,ucompleng+15);
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
cptr = ucompbuf; eptr = &ucompbuf[ucompleng];
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
numnodes = 256; bitcnt = (4<<3); nbits = 8; oneupnbits = (1<<8); hmask = ((oneupnbits>>1)-1);
|
|
|
|
do
|
|
|
|
{
|
2009-02-19 16:47:54 +00:00
|
|
|
for (i=cptr[0]; i>=0; i=j)
|
2006-04-24 19:04:22 +00:00
|
|
|
{
|
|
|
|
cptr++; if (cptr >= eptr) goto lzwcompbreak2b;
|
2007-12-12 17:42:14 +00:00
|
|
|
j = child[i]; if (j < 0) { child[i] = numnodes; break; }
|
2006-04-13 20:47:06 +00:00
|
|
|
#if USENEW
|
2006-04-24 19:04:22 +00:00
|
|
|
//This is about 2x faster when ucompbuf is more random, 5% slower when very compressible
|
|
|
|
while (cptr[0] != nodev[j])
|
|
|
|
{
|
|
|
|
if (cptr[0] < nodev[j])
|
2007-12-12 17:42:14 +00:00
|
|
|
{ if (sibly[j] < 0) { sibly[j] = numnodes; goto lzwcompbreak2a; } j = sibly[j]; }
|
2006-04-24 19:04:22 +00:00
|
|
|
else { if (sibry[j] < 0) { sibry[j] = numnodes; goto lzwcompbreak2a; } j = sibry[j]; }
|
|
|
|
}
|
2006-04-13 20:47:06 +00:00
|
|
|
#else
|
2009-02-19 16:47:54 +00:00
|
|
|
for (; nodev[j]!=cptr[0]; j=sibly[j])
|
2007-12-12 17:42:14 +00:00
|
|
|
if (sibly[j] < 0) { sibly[j] = numnodes; goto lzwcompbreak2a; }
|
2006-04-13 20:47:06 +00:00
|
|
|
#endif
|
2006-04-24 19:04:22 +00:00
|
|
|
}
|
2006-11-13 23:12:47 +00:00
|
|
|
lzwcompbreak2a:
|
|
|
|
nodev[numnodes] = cptr[0];
|
|
|
|
lzwcompbreak2b:
|
|
|
|
child[numnodes] = sibly[numnodes] = -1;
|
2006-04-13 20:47:06 +00:00
|
|
|
#if USENEW
|
2006-04-24 19:04:22 +00:00
|
|
|
sibry[numnodes] = -1;
|
2006-04-13 20:47:06 +00:00
|
|
|
#endif
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
lptr = (int32_t *)&compbuf[bitcnt>>3]; lptr[0] |= LSWAPIB(i<<(bitcnt&7));
|
2006-04-24 19:04:22 +00:00
|
|
|
bitcnt += nbits; if ((i&hmask) > ((numnodes-1)&hmask)) bitcnt--;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2007-12-12 17:42:14 +00:00
|
|
|
numnodes++; if (numnodes > oneupnbits) { nbits++; oneupnbits <<= 1; hmask = ((oneupnbits>>1)-1); }
|
|
|
|
}
|
|
|
|
while ((cptr < eptr) && (bitcnt < (ucompleng<<3)));
|
2006-04-13 20:47:06 +00:00
|
|
|
|
|
|
|
#if USENEW
|
2006-04-24 19:04:22 +00:00
|
|
|
free(sibry);
|
2006-04-13 20:47:06 +00:00
|
|
|
#endif
|
2006-04-24 19:04:22 +00:00
|
|
|
free(sibly);
|
|
|
|
free(child); free(nodev);
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
lptr = (int32_t *)compbuf;
|
2007-12-12 17:42:14 +00:00
|
|
|
if (((bitcnt+7)>>3) < ucompleng) { lptr[0] = LSWAPIB(numnodes); return((bitcnt+7)>>3); }
|
2009-06-09 06:19:58 +00:00
|
|
|
Bmemcpy(compbuf,ucompbuf,ucompleng); return(ucompleng);
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t lzwuncompress(char *compbuf, int32_t compleng, char *ucompbuf, int32_t ucompleng)
|
2006-04-13 20:47:06 +00:00
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
int32_t i, dat, leng, bitcnt, *lptr, numnodes, totnodes, nbits, oneupnbits, hmask, *prefix;
|
|
|
|
char ch, *ucptr, *suffix;
|
|
|
|
int32_t ucomp = (int32_t)ucompbuf;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2009-06-09 06:19:58 +00:00
|
|
|
if (compleng >= ucompleng) { Bmemcpy(ucompbuf,compbuf,ucompleng); return ucompleng; }
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
totnodes = LSWAPIB(((int32_t *)compbuf)[0]); if (totnodes <= 0 || totnodes >= ucompleng+256) return 0;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
prefix = (int32_t *)malloc(totnodes*sizeof(int32_t)); if (!prefix) return 0;
|
|
|
|
suffix = (char *)malloc(totnodes*sizeof(uint8_t)); if (!suffix) { free(prefix); return 0; }
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
numnodes = 256; bitcnt = (4<<3); nbits = 8; oneupnbits = (1<<8); hmask = ((oneupnbits>>1)-1);
|
|
|
|
do
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
lptr = (int32_t *)&compbuf[bitcnt>>3]; dat = ((LSWAPIB(lptr[0])>>(bitcnt&7))&(oneupnbits-1));
|
2006-04-24 19:04:22 +00:00
|
|
|
bitcnt += nbits; if ((dat&hmask) > ((numnodes-1)&hmask)) { dat &= hmask; bitcnt--; }
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
prefix[numnodes] = dat;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
ucompbuf++;
|
2009-02-19 16:47:54 +00:00
|
|
|
for (leng=0; dat>=256; dat=prefix[dat])
|
2007-12-12 17:42:14 +00:00
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
if ((int32_t)ucompbuf+leng-ucomp > ucompleng) goto bail;
|
2006-04-24 19:04:22 +00:00
|
|
|
ucompbuf[leng++] = suffix[dat];
|
|
|
|
}
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
ucptr = &ucompbuf[leng-1];
|
2009-02-19 16:47:54 +00:00
|
|
|
for (i=(leng>>1)-1; i>=0; i--) { ch = ucompbuf[i]; ucompbuf[i] = ucptr[-i]; ucptr[-i] = ch; }
|
2006-04-24 19:04:22 +00:00
|
|
|
ucompbuf[-1] = dat; ucompbuf += leng;
|
2006-04-13 20:47:06 +00:00
|
|
|
|
2006-04-24 19:04:22 +00:00
|
|
|
suffix[numnodes-1] = suffix[numnodes] = dat;
|
|
|
|
|
|
|
|
numnodes++; if (numnodes > oneupnbits) { nbits++; oneupnbits <<= 1; hmask = ((oneupnbits>>1)-1); }
|
2007-12-12 17:42:14 +00:00
|
|
|
}
|
|
|
|
while (numnodes < totnodes);
|
2006-04-13 20:47:06 +00:00
|
|
|
|
|
|
|
bail:
|
2006-04-24 19:04:22 +00:00
|
|
|
free(suffix); free(prefix);
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
return (int32_t)ucompbuf-ucomp;
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|