/*********************************************************************** 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 #include 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; }