mirror of
https://github.com/aaru-dps/Aaru.Compression.Native.git
synced 2025-12-16 19:24:31 +00:00
305 lines
8.8 KiB
C
305 lines
8.8 KiB
C
|
|
/***********************************************************************
|
||
|
|
This file is part of HA, a general purpose file archiver.
|
||
|
|
Copyright (C) 1995 Harri Hirvola
|
||
|
|
|
||
|
|
This program is free software; you can redistribute it and/or modify
|
||
|
|
it under the terms of the GNU General Public License as published by
|
||
|
|
the Free Software Foundation; either version 2 of the License, or
|
||
|
|
(at your option) any later version.
|
||
|
|
|
||
|
|
This program 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 General Public License for more details.
|
||
|
|
|
||
|
|
You should have received a copy of the GNU General Public License
|
||
|
|
along with this program; if not, write to the Free Software
|
||
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
|
|
************************************************************************
|
||
|
|
HA ASC method
|
||
|
|
***********************************************************************/
|
||
|
|
|
||
|
|
/***********************************************************************
|
||
|
|
Modified to work with memory buffers instead of files by
|
||
|
|
Copyright (C) 2005 Natalia Portillo
|
||
|
|
************************************************************************/
|
||
|
|
|
||
|
|
#include "internal.h"
|
||
|
|
#include "acoder.h"
|
||
|
|
#include "swdict.h"
|
||
|
|
#include "asc.h"
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
static decompress_context_t *g_ctx = NULL;
|
||
|
|
|
||
|
|
static void tabinit(U16B t[], U16B tl, U16B ival)
|
||
|
|
{
|
||
|
|
register U16B i, j;
|
||
|
|
|
||
|
|
for(i = tl; i < 2 * tl; ++i) t[i] = ival;
|
||
|
|
for(i = tl - 1, j = (tl << 1) - 2; i; --i, j -= 2) { t[i] = t[j] + t[j + 1]; }
|
||
|
|
}
|
||
|
|
|
||
|
|
static void tscale(U16B t[], U16B tl)
|
||
|
|
{
|
||
|
|
register U16B i, j;
|
||
|
|
|
||
|
|
for(i = (tl << 1) - 1; i >= tl; --i) { if(t[i] > 1) t[i] >>= 1; }
|
||
|
|
for(i = tl - 1, j = (tl << 1) - 2; i; --i, j -= 2) { t[i] = t[j] + t[j + 1]; }
|
||
|
|
}
|
||
|
|
|
||
|
|
static void tupd(U16B t[], U16B tl, U16B maxt, U16B step, U16B p)
|
||
|
|
{
|
||
|
|
register S16B i;
|
||
|
|
|
||
|
|
for(i = p + tl; i; i >>= 1) t[i] += step;
|
||
|
|
if(t[1] >= maxt) tscale(t, tl);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void tzero(U16B t[], U16B tl, U16B p)
|
||
|
|
{
|
||
|
|
register S16B i, step;
|
||
|
|
|
||
|
|
for(i = p + tl, step = t[i]; i; i >>= 1) t[i] -= step;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void model_init(void)
|
||
|
|
{
|
||
|
|
register S16B i;
|
||
|
|
|
||
|
|
ces = CTSTEP;
|
||
|
|
les = LTSTEP;
|
||
|
|
ccnt = 0;
|
||
|
|
ttcon = 0;
|
||
|
|
npt = pmax = 1;
|
||
|
|
for(i = 0; i < TTORD; ++i) ttab[i][0] = ttab[i][1] = TTSTEP;
|
||
|
|
tabinit(ltab, LTCODES, 0);
|
||
|
|
tabinit(eltab, LTCODES, 1);
|
||
|
|
tabinit(ctab, CTCODES, 0);
|
||
|
|
tabinit(ectab, CTCODES, 1);
|
||
|
|
tabinit(ptab, PTCODES, 0);
|
||
|
|
tupd(ptab, PTCODES, MAXPT, PTSTEP, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void unpack_init(decompress_context_t *ctx)
|
||
|
|
{
|
||
|
|
g_ctx = ctx;
|
||
|
|
model_init();
|
||
|
|
ac_init_decode(ctx);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void ttscale(U16B con)
|
||
|
|
{
|
||
|
|
ttab[con][0] >>= 1;
|
||
|
|
if(ttab[con][0] == 0) ttab[con][0] = 1;
|
||
|
|
ttab[con][1] >>= 1;
|
||
|
|
if(ttab[con][1] == 0) ttab[con][1] = 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void flush_output(void)
|
||
|
|
{
|
||
|
|
/* Output flushing is handled by the buffer management */
|
||
|
|
}
|
||
|
|
|
||
|
|
int asc_unpack(decompress_context_t *ctx)
|
||
|
|
{
|
||
|
|
register U16B l, p, tv, i, lt;
|
||
|
|
|
||
|
|
swd_dinit(ctx, POSCODES);
|
||
|
|
if(ctx->output.error) return -1;
|
||
|
|
|
||
|
|
unpack_init(ctx);
|
||
|
|
if(ctx->input.error)
|
||
|
|
{
|
||
|
|
swd_cleanup();
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
for(;;)
|
||
|
|
{
|
||
|
|
if(ctx->input.error || ctx->output.error) break;
|
||
|
|
|
||
|
|
tv = ac_threshold_val(ttab[ttcon][0] + ttab[ttcon][1] + 1);
|
||
|
|
i = ttab[ttcon][0] + ttab[ttcon][1];
|
||
|
|
|
||
|
|
if(ttab[ttcon][0] > tv)
|
||
|
|
{
|
||
|
|
ac_in(0, ttab[ttcon][0], i + 1);
|
||
|
|
ttab[ttcon][0] += TTSTEP;
|
||
|
|
if(i >= MAXTT) ttscale(ttcon);
|
||
|
|
ttcon = (ttcon << 1) & TTOMASK;
|
||
|
|
|
||
|
|
tv = ac_threshold_val(ctab[1] + ces);
|
||
|
|
if(tv >= ctab[1])
|
||
|
|
{
|
||
|
|
ac_in(ctab[1], ctab[1] + ces, ctab[1] + ces);
|
||
|
|
tv = ac_threshold_val(ectab[1]);
|
||
|
|
for(l = 2, lt = 0;;)
|
||
|
|
{
|
||
|
|
if(lt + ectab[l] <= tv)
|
||
|
|
{
|
||
|
|
lt += ectab[l];
|
||
|
|
++l;
|
||
|
|
}
|
||
|
|
if(l >= CTCODES)
|
||
|
|
{
|
||
|
|
l -= CTCODES;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
l <<= 1;
|
||
|
|
}
|
||
|
|
ac_in(lt, lt + ectab[CTCODES + l], ectab[1]);
|
||
|
|
tzero(ectab, CTCODES, l);
|
||
|
|
if(ectab[1] != 0) ces += CTSTEP;
|
||
|
|
else ces = 0;
|
||
|
|
for(i = l < CPLEN ? 0 : l - CPLEN; i < (l + CPLEN >= CTCODES - 1 ? CTCODES - 1 : l + CPLEN); ++i)
|
||
|
|
{
|
||
|
|
if(ectab[CTCODES + i]) tupd(ectab, CTCODES, MAXCT, 1, i);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
for(l = 2, lt = 0;;)
|
||
|
|
{
|
||
|
|
if(lt + ctab[l] <= tv)
|
||
|
|
{
|
||
|
|
lt += ctab[l];
|
||
|
|
l++;
|
||
|
|
}
|
||
|
|
if(l >= CTCODES)
|
||
|
|
{
|
||
|
|
l -= CTCODES;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
l <<= 1;
|
||
|
|
}
|
||
|
|
ac_in(lt, lt + ctab[CTCODES + l], ctab[1] + ces);
|
||
|
|
}
|
||
|
|
tupd(ctab, CTCODES, MAXCT, CTSTEP, l);
|
||
|
|
if(ctab[CTCODES + l] == CCUTOFF) ces -= CTSTEP < ces ? CTSTEP : ces - 1;
|
||
|
|
swd_dchar(l);
|
||
|
|
if(ccnt < POSCODES) ++ccnt;
|
||
|
|
}
|
||
|
|
else if(i > tv)
|
||
|
|
{
|
||
|
|
ac_in(ttab[ttcon][0], i, i + 1);
|
||
|
|
ttab[ttcon][1] += TTSTEP;
|
||
|
|
if(i >= MAXTT) ttscale(ttcon);
|
||
|
|
ttcon = ((ttcon << 1) | 1) & TTOMASK;
|
||
|
|
|
||
|
|
while(ccnt > pmax)
|
||
|
|
{
|
||
|
|
tupd(ptab, PTCODES, MAXPT, PTSTEP, npt++);
|
||
|
|
pmax <<= 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
tv = ac_threshold_val(ptab[1]);
|
||
|
|
for(p = 2, lt = 0;;)
|
||
|
|
{
|
||
|
|
if(lt + ptab[p] <= tv)
|
||
|
|
{
|
||
|
|
lt += ptab[p];
|
||
|
|
p++;
|
||
|
|
}
|
||
|
|
if(p >= PTCODES)
|
||
|
|
{
|
||
|
|
p -= PTCODES;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
p <<= 1;
|
||
|
|
}
|
||
|
|
ac_in(lt, lt + ptab[PTCODES + p], ptab[1]);
|
||
|
|
tupd(ptab, PTCODES, MAXPT, PTSTEP, p);
|
||
|
|
|
||
|
|
if(p > 1)
|
||
|
|
{
|
||
|
|
for(i = 1; p; i <<= 1, --p);
|
||
|
|
i >>= 1;
|
||
|
|
if(i == (pmax >> 1)) l = ccnt - (pmax >> 1);
|
||
|
|
else l = i;
|
||
|
|
p = ac_threshold_val(l);
|
||
|
|
ac_in(p, p + 1, l);
|
||
|
|
p += i;
|
||
|
|
}
|
||
|
|
|
||
|
|
tv = ac_threshold_val(ltab[1] + les);
|
||
|
|
if(tv >= ltab[1])
|
||
|
|
{
|
||
|
|
ac_in(ltab[1], ltab[1] + les, ltab[1] + les);
|
||
|
|
tv = ac_threshold_val(eltab[1]);
|
||
|
|
for(l = 2, lt = 0;;)
|
||
|
|
{
|
||
|
|
if(lt + eltab[l] <= tv)
|
||
|
|
{
|
||
|
|
lt += eltab[l];
|
||
|
|
++l;
|
||
|
|
}
|
||
|
|
if(l >= LTCODES)
|
||
|
|
{
|
||
|
|
l -= LTCODES;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
l <<= 1;
|
||
|
|
}
|
||
|
|
ac_in(lt, lt + eltab[LTCODES + l], eltab[1]);
|
||
|
|
tzero(eltab, LTCODES, l);
|
||
|
|
if(eltab[1] != 0) les += LTSTEP;
|
||
|
|
else les = 0;
|
||
|
|
for(i = l < LPLEN ? 0 : l - LPLEN; i < (l + LPLEN >= LTCODES - 1 ? LTCODES - 1 : l + LPLEN); ++i)
|
||
|
|
{
|
||
|
|
if(eltab[LTCODES + i]) tupd(eltab, LTCODES, MAXLT, 1, i);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
for(l = 2, lt = 0;;)
|
||
|
|
{
|
||
|
|
if(lt + ltab[l] <= tv)
|
||
|
|
{
|
||
|
|
lt += ltab[l];
|
||
|
|
++l;
|
||
|
|
}
|
||
|
|
if(l >= LTCODES)
|
||
|
|
{
|
||
|
|
l -= LTCODES;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
l <<= 1;
|
||
|
|
}
|
||
|
|
ac_in(lt, lt + ltab[LTCODES + l], ltab[1] + les);
|
||
|
|
}
|
||
|
|
tupd(ltab, LTCODES, MAXLT, LTSTEP, l);
|
||
|
|
if(ltab[LTCODES + l] == LCUTOFF) les -= LTSTEP < les ? LTSTEP : les - 1;
|
||
|
|
|
||
|
|
if(l == SLCODES - 1) l = LENCODES - 1;
|
||
|
|
else if(l >= SLCODES)
|
||
|
|
{
|
||
|
|
i = ac_threshold_val(LLLEN);
|
||
|
|
ac_in(i, i + 1, LLLEN);
|
||
|
|
l = ((l - SLCODES) << LLBITS) + i + SLCODES - 1;
|
||
|
|
}
|
||
|
|
l += 3;
|
||
|
|
|
||
|
|
if(ccnt < POSCODES)
|
||
|
|
{
|
||
|
|
ccnt += l;
|
||
|
|
if(ccnt > POSCODES) ccnt = POSCODES;
|
||
|
|
}
|
||
|
|
swd_dpair(l, p);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
ac_in(i, i + 1, i + 1);
|
||
|
|
flush_output();
|
||
|
|
swd_cleanup();
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
if(ctx->input.error || ctx->output.error) break;
|
||
|
|
}
|
||
|
|
|
||
|
|
swd_cleanup();
|
||
|
|
return -1;
|
||
|
|
}
|