mirror of
https://github.com/aaru-dps/Aaru.Compression.Native.git
synced 2025-12-16 19:24:31 +00:00
Implement HA's ASC and HSC algorithms.
This commit is contained in:
@@ -132,7 +132,17 @@ add_library("Aaru.Compression.Native" SHARED library.c apple_rle.c apple_rle.h a
|
||||
zoo/lzd.c zoo/lzd.h zoo/lzh.c zoo/decode.c zoo/huf.c zoo/io.c zoo/lh5.c zoo/lh5.h zoo/lzh.h zoo/ar.h zoo/maketbl.c
|
||||
arc/pack.c arc/squeeze.c arc/crunch.c arc/lzw.c
|
||||
pak/crush.c pak/distill.c pak/bitstream.c pak/bitstream.h pak/lzw.c pak/lzw.h pak/prefixcode.c
|
||||
pak/prefixcode.h)
|
||||
pak/prefixcode.h
|
||||
ha/acoder.c
|
||||
ha/acoder.h
|
||||
ha/asc.c
|
||||
ha/asc.h
|
||||
ha/decompress.c
|
||||
ha/hsc.c
|
||||
ha/hsc.h
|
||||
ha/internal.h
|
||||
ha/swdict.c
|
||||
ha/swdict.h)
|
||||
|
||||
include(3rdparty/bzip2.cmake)
|
||||
include(3rdparty/flac.cmake)
|
||||
|
||||
134
ha/acoder.c
Normal file
134
ha/acoder.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/***********************************************************************
|
||||
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 arithmetic coder
|
||||
***********************************************************************/
|
||||
|
||||
/***********************************************************************
|
||||
This file contains some small changes made by Nico de Vries (AIP-NL)
|
||||
allowing it to be compiled with Borland C++ 3.1.
|
||||
***********************************************************************/
|
||||
|
||||
/***********************************************************************
|
||||
Modified to work with memory buffers instead of files by
|
||||
Copyright (C) 2005 Natalia Portillo
|
||||
************************************************************************/
|
||||
|
||||
#include "internal.h"
|
||||
#include "acoder.h"
|
||||
#include <string.h>
|
||||
|
||||
static decompress_context_t *g_ctx = NULL;
|
||||
static U16B h, l, v;
|
||||
static S16B gpat;
|
||||
|
||||
/* Get byte from input buffer */
|
||||
static int getbyte_from_buffer(void)
|
||||
{
|
||||
if(!g_ctx || g_ctx->input.pos >= g_ctx->input.size) { return -1; }
|
||||
return g_ctx->input.data[g_ctx->input.pos++];
|
||||
}
|
||||
|
||||
/* Bit input from memory buffer */
|
||||
static int getbit_from_buffer(void)
|
||||
{
|
||||
if(!g_ctx || g_ctx->input.error) { return -1; }
|
||||
|
||||
gpat <<= 1;
|
||||
if(!(gpat & 0xff))
|
||||
{
|
||||
int byte = getbyte_from_buffer();
|
||||
if(byte < 0) { gpat = 0x100; }
|
||||
else
|
||||
{
|
||||
gpat = byte;
|
||||
gpat <<= 1;
|
||||
gpat |= 1;
|
||||
}
|
||||
}
|
||||
return (gpat & 0x100) >> 8;
|
||||
}
|
||||
|
||||
#define getbit(b) { \
|
||||
int _bit = getbit_from_buffer(); \
|
||||
if (_bit < 0) { \
|
||||
g_ctx->input.error = 1; \
|
||||
b = 0; \
|
||||
} else { \
|
||||
b |= _bit; \
|
||||
} \
|
||||
}
|
||||
|
||||
void ac_init_decode(decompress_context_t *ctx)
|
||||
{
|
||||
g_ctx = ctx;
|
||||
h = 0xffff;
|
||||
l = 0;
|
||||
gpat = 0;
|
||||
|
||||
int b1 = getbyte_from_buffer();
|
||||
int b2 = getbyte_from_buffer();
|
||||
|
||||
if(b1 < 0 || b2 < 0)
|
||||
{
|
||||
ctx->input.error = 1;
|
||||
v = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
v = (b1 << 8) | (0xff & b2);
|
||||
}
|
||||
|
||||
void ac_in(U16B low, U16B high, U16B tot)
|
||||
{
|
||||
if(!g_ctx || g_ctx->input.error) return;
|
||||
|
||||
U32B r = (U32B)(h - l) + 1;
|
||||
h = (U16B)(r * high / tot - 1) + l;
|
||||
l += (U16B)(r * low / tot);
|
||||
|
||||
while(!((h ^ l) & 0x8000))
|
||||
{
|
||||
l <<= 1;
|
||||
h <<= 1;
|
||||
h |= 1;
|
||||
v <<= 1;
|
||||
getbit(v);
|
||||
if(g_ctx->input.error) return;
|
||||
}
|
||||
|
||||
while((l & 0x4000) && !(h & 0x4000))
|
||||
{
|
||||
l <<= 1;
|
||||
l &= 0x7fff;
|
||||
h <<= 1;
|
||||
h |= 0x8001;
|
||||
v <<= 1;
|
||||
v ^= 0x8000;
|
||||
getbit(v);
|
||||
if(g_ctx->input.error) return;
|
||||
}
|
||||
}
|
||||
|
||||
U16B ac_threshold_val(U16B tot)
|
||||
{
|
||||
if(!g_ctx || g_ctx->input.error) return 0;
|
||||
|
||||
U32B r = (U32B)(h - l) + 1;
|
||||
return (U16B)((((U32B)(v - l) + 1) * tot - 1) / r);
|
||||
}
|
||||
38
ha/acoder.h
Normal file
38
ha/acoder.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/***********************************************************************
|
||||
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 arithmetic coder
|
||||
***********************************************************************/
|
||||
|
||||
/***********************************************************************
|
||||
Modified to work with memory buffers instead of files by
|
||||
Copyright (C) 2005 Natalia Portillo
|
||||
************************************************************************/
|
||||
|
||||
#ifndef ACODER_H
|
||||
#define ACODER_H
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
void ac_init_decode(decompress_context_t *ctx);
|
||||
|
||||
void ac_in(U16B low, U16B high, U16B tot);
|
||||
|
||||
U16B ac_threshold_val(U16B tot);
|
||||
|
||||
#endif /* ACODER_H */
|
||||
304
ha/asc.c
Normal file
304
ha/asc.c
Normal file
@@ -0,0 +1,304 @@
|
||||
/***********************************************************************
|
||||
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;
|
||||
}
|
||||
71
ha/asc.h
Normal file
71
ha/asc.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/***********************************************************************
|
||||
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
|
||||
************************************************************************/
|
||||
|
||||
#ifndef ASC_H
|
||||
#define ASC_H
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
int asc_unpack(decompress_context_t *ctx);
|
||||
|
||||
#define POSCODES 31200
|
||||
#define SLCODES 16
|
||||
#define LLCODES 48
|
||||
#define LLLEN 16
|
||||
#define LLBITS 4
|
||||
#define LLMASK (LLLEN-1)
|
||||
#define LENCODES (SLCODES+LLCODES*LLLEN)
|
||||
#define LTCODES (SLCODES+LLCODES)
|
||||
#define CTCODES 256
|
||||
#define PTCODES 16
|
||||
#define LTSTEP 8
|
||||
#define MAXLT (750*LTSTEP)
|
||||
#define CTSTEP 1
|
||||
#define MAXCT (1000*CTSTEP)
|
||||
#define PTSTEP 24
|
||||
#define MAXPT (250*PTSTEP)
|
||||
#define TTSTEP 40
|
||||
#define MAXTT (150*TTSTEP)
|
||||
#define TTORD 4
|
||||
#define TTOMASK (TTORD-1)
|
||||
#define LCUTOFF (3*LTSTEP)
|
||||
#define CCUTOFF (3*CTSTEP)
|
||||
#define CPLEN 8
|
||||
#define LPLEN 4
|
||||
#define MINLENLIM 4096
|
||||
|
||||
static U16B ltab[2 * LTCODES];
|
||||
static U16B eltab[2 * LTCODES];
|
||||
static U16B ptab[2 * PTCODES];
|
||||
static U16B ctab[2 * CTCODES];
|
||||
static U16B ectab[2 * CTCODES];
|
||||
static U16B ttab[TTORD][2];
|
||||
static U16B ccnt, pmax, npt;
|
||||
static U16B ces;
|
||||
static U16B les;
|
||||
static U16B ttcon;
|
||||
|
||||
#endif /* ASC_H */
|
||||
70
ha/decompress.c
Normal file
70
ha/decompress.c
Normal file
@@ -0,0 +1,70 @@
|
||||
|
||||
/***********************************************************************
|
||||
Modified to work with memory buffers instead of files by
|
||||
Copyright (C) 2005 Natalia Portillo
|
||||
************************************************************************/
|
||||
|
||||
#include "internal.h"
|
||||
#include "asc.h"
|
||||
#include "hsc.h"
|
||||
#include "../library.h"
|
||||
#include <string.h>
|
||||
|
||||
int ha_algorithm_decompress(ha_algorithm_t algorithm,
|
||||
const unsigned char *in_buf,
|
||||
size_t in_len,
|
||||
unsigned char * out_buf,
|
||||
size_t * out_len)
|
||||
{
|
||||
if(!in_buf || !out_buf || !out_len || in_len == 0) { return -1; }
|
||||
|
||||
decompress_context_t ctx;
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
|
||||
/* Initialize input buffer */
|
||||
ctx.input.data = in_buf;
|
||||
ctx.input.size = in_len;
|
||||
ctx.input.pos = 0;
|
||||
ctx.input.error = 0;
|
||||
|
||||
/* Initialize output buffer */
|
||||
ctx.output.data = out_buf;
|
||||
ctx.output.size = 0;
|
||||
ctx.output.pos = 0;
|
||||
ctx.output.max_size = *out_len;
|
||||
ctx.output.error = 0;
|
||||
|
||||
ctx.algorithm = algorithm;
|
||||
|
||||
int result;
|
||||
switch(algorithm)
|
||||
{
|
||||
case HA_ALGORITHM_ASC:
|
||||
result = asc_unpack(&ctx);
|
||||
break;
|
||||
case HA_ALGORITHM_HSC:
|
||||
result = hsc_unpack(&ctx);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
*out_len = ctx.output.size;
|
||||
return result;
|
||||
}
|
||||
|
||||
AARU_EXPORT int AARU_CALL ha_asc_decompress(const unsigned char *in_buf,
|
||||
size_t in_len,
|
||||
unsigned char * out_buf,
|
||||
size_t * out_len)
|
||||
{
|
||||
return ha_algorithm_decompress(HA_ALGORITHM_ASC, in_buf, in_len, out_buf, out_len);
|
||||
}
|
||||
|
||||
AARU_EXPORT int AARU_CALL ha_hsc_decompress(const unsigned char *in_buf,
|
||||
size_t in_len,
|
||||
unsigned char * out_buf,
|
||||
size_t * out_len)
|
||||
{
|
||||
return ha_algorithm_decompress(HA_ALGORITHM_HSC, in_buf, in_len, out_buf, out_len);
|
||||
}
|
||||
568
ha/hsc.c
Normal file
568
ha/hsc.c
Normal file
@@ -0,0 +1,568 @@
|
||||
/***********************************************************************
|
||||
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 HSC method
|
||||
***********************************************************************/
|
||||
|
||||
/***********************************************************************
|
||||
Modified to work with memory buffers instead of files by
|
||||
Copyright (C) 2005 Natalia Portillo
|
||||
************************************************************************/
|
||||
|
||||
#include "internal.h"
|
||||
#include "acoder.h"
|
||||
#include "hsc.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static decompress_context_t *g_ctx = NULL;
|
||||
|
||||
static void hsc_cleanup(void)
|
||||
{
|
||||
if(ht != NULL) free(ht), ht = NULL;
|
||||
if(fc != NULL) free(fc), fc = NULL;
|
||||
if(fa != NULL) free(fa), fa = NULL;
|
||||
if(ft != NULL) free(ft), ft = NULL;
|
||||
if(fe != NULL) free(fe), fe = NULL;
|
||||
if(nb != NULL) free(nb), nb = NULL;
|
||||
if(hp != NULL) free(hp), hp = NULL;
|
||||
if(elp != NULL) free(elp), elp = NULL;
|
||||
if(eln != NULL) free(eln), eln = NULL;
|
||||
if(cl != NULL) free(cl), cl = NULL;
|
||||
if(cc != NULL) free(cc), cc = NULL;
|
||||
if(rfm != NULL) free(rfm), rfm = NULL;
|
||||
if(con != NULL) free(con), con = NULL;
|
||||
}
|
||||
|
||||
static int putbyte_to_buffer(unsigned char c)
|
||||
{
|
||||
if(!g_ctx || g_ctx->output.pos >= g_ctx->output.max_size)
|
||||
{
|
||||
if(g_ctx) g_ctx->output.error = 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_ctx->output.data[g_ctx->output.pos++] = c;
|
||||
if(g_ctx->output.pos > g_ctx->output.size) { g_ctx->output.size = g_ctx->output.pos; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
static U16B make_context(unsigned char cl, S16B c);
|
||||
|
||||
static int init_model(void)
|
||||
{
|
||||
register S16B i;
|
||||
S32B z, l, h, t;
|
||||
|
||||
ht = malloc(HTLEN * sizeof(*ht));
|
||||
hp = malloc(NUMCON * sizeof(*hp));
|
||||
elp = malloc(NUMCON * sizeof(*elp));
|
||||
eln = malloc(NUMCON * sizeof(*eln));
|
||||
cl = malloc(NUMCON * sizeof(*cl));
|
||||
cc = malloc(NUMCON * sizeof(*cc));
|
||||
ft = malloc(NUMCON * sizeof(*ft));
|
||||
fe = malloc(NUMCON * sizeof(*fe));
|
||||
rfm = malloc(NUMCON * sizeof(*rfm));
|
||||
con = malloc(NUMCON * sizeof(*con));
|
||||
fc = malloc(NUMCFB * sizeof(*fc));
|
||||
fa = malloc(NUMCFB * sizeof(*fa));
|
||||
nb = malloc(NUMCFB * sizeof(*nb));
|
||||
|
||||
if(hp == NULL || elp == NULL || eln == NULL || cl == NULL || rfm == NULL || con == NULL || cc == NULL || ft == NULL
|
||||
|| fe == NULL || fc == NULL || fa == NULL || nb == NULL || ht == NULL)
|
||||
{
|
||||
hsc_cleanup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
maxclen = MAXCLEN;
|
||||
iec[0] = (IECLIM >> 1);
|
||||
for(i = 1; i <= MAXCLEN; ++i) iec[i] = (IECLIM >> 1) - 1;
|
||||
dropcnt = NUMCON / 4;
|
||||
nec = 0;
|
||||
nrel = 0;
|
||||
hs[0] = 0;
|
||||
|
||||
for(i = 0; i < HTLEN; ++i) ht[i] = NIL;
|
||||
for(i = 0; i < NUMCON; ++i)
|
||||
{
|
||||
eln[i] = i + 1;
|
||||
elp[i] = i - 1;
|
||||
cl[i] = 0xff;
|
||||
nb[i] = NIL;
|
||||
}
|
||||
elf = 0;
|
||||
ell = NUMCON - 1;
|
||||
|
||||
for(i = NUMCON; i < NUMCFB - 1; ++i) nb[i] = i + 1;
|
||||
nb[i] = NIL;
|
||||
fcfbl = NUMCON;
|
||||
|
||||
curcon[3] = curcon[2] = curcon[1] = curcon[0] = 0;
|
||||
cmsp = 0;
|
||||
for(i = 0; i < 256; ++i) cmask[i] = 0;
|
||||
|
||||
for(z = 10, i = 0; i < HTLEN; ++i)
|
||||
{
|
||||
h = z / (2147483647L / 16807L);
|
||||
l = z % (2147483647L / 16807L);
|
||||
if((t = 16807L * l - (2147483647L % 16807L) * h) > 0) z = t;
|
||||
else z = t + 2147483647L;
|
||||
hrt[i] = (U16B)z & (HTLEN - 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_unpack(decompress_context_t *ctx)
|
||||
{
|
||||
g_ctx = ctx;
|
||||
if(init_model() < 0) return -1;
|
||||
ac_init_decode(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define HASH(s,l,h) { \
|
||||
h = 0; \
|
||||
if (l) h = hrt[s[0]]; \
|
||||
if (l > 1) h = hrt[(s[1] + h) & (HTLEN - 1)]; \
|
||||
if (l > 2) h = hrt[(s[2] + h) & (HTLEN - 1)]; \
|
||||
if (l > 3) h = hrt[(s[3] + h) & (HTLEN - 1)]; \
|
||||
}
|
||||
|
||||
#define move_context(c) curcon[3] = curcon[2], curcon[2] = curcon[1], \
|
||||
curcon[1] = curcon[0], curcon[0] = c
|
||||
|
||||
static void release_cfblocks(void)
|
||||
{
|
||||
register U16B i, j, d;
|
||||
|
||||
do
|
||||
{
|
||||
do if(++nrel == NUMCON) nrel = 0; while(nb[nrel] == NIL);
|
||||
for(i = 0; i <= usp; ++i) if((cps[i] & 0x7fff) == nrel) break;
|
||||
}
|
||||
while(i <= usp);
|
||||
|
||||
for(i = nb[nrel], d = fa[nrel]; i != NIL; i = nb[i]) if(fa[i] < d) d = fa[i];
|
||||
++d;
|
||||
|
||||
if(fa[nrel] < d)
|
||||
{
|
||||
for(i = nb[nrel]; fa[i] < d && nb[i] != NIL; i = nb[i]);
|
||||
fa[nrel] = fa[i];
|
||||
fc[nrel] = fc[i];
|
||||
j = nb[i];
|
||||
nb[i] = fcfbl;
|
||||
fcfbl = nb[nrel];
|
||||
if((nb[nrel] = j) == NIL)
|
||||
{
|
||||
cc[nrel] = 0;
|
||||
fe[nrel] = (ft[nrel] = fa[nrel]) < ESCTH ? 1 : 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fe[nrel] = (ft[nrel] = fa[nrel] /= d) < ESCTH ? 1 : 0;
|
||||
cc[nrel] = 0;
|
||||
|
||||
for(j = nrel, i = nb[j]; i != NIL;)
|
||||
{
|
||||
if(fa[i] < d)
|
||||
{
|
||||
nb[j] = nb[i];
|
||||
nb[i] = fcfbl;
|
||||
fcfbl = i;
|
||||
i = nb[j];
|
||||
}
|
||||
else
|
||||
{
|
||||
++cc[nrel];
|
||||
ft[nrel] += fa[i] /= d;
|
||||
if(fa[i] < ESCTH) fe[nrel]++;
|
||||
j = i;
|
||||
i = nb[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static U16B make_context(unsigned char conlen, S16B c)
|
||||
{
|
||||
register S16B i;
|
||||
register U16B nc, fp;
|
||||
|
||||
nc = ell;
|
||||
ell = elp[nc];
|
||||
elp[elf] = nc;
|
||||
eln[nc] = elf;
|
||||
elf = nc;
|
||||
|
||||
if(cl[nc] != 0xff)
|
||||
{
|
||||
if(cl[nc] == MAXCLEN && --dropcnt == 0) maxclen = MAXCLEN - 1;
|
||||
HASH(con[nc], cl[nc], i);
|
||||
if(ht[i] == nc) ht[i] = hp[nc];
|
||||
else
|
||||
{
|
||||
for(i = ht[i]; hp[i] != nc; i = hp[i]);
|
||||
hp[i] = hp[nc];
|
||||
}
|
||||
if(nb[nc] != NIL)
|
||||
{
|
||||
for(fp = nb[nc]; nb[fp] != NIL; fp = nb[fp]);
|
||||
nb[fp] = fcfbl;
|
||||
fcfbl = nb[nc];
|
||||
}
|
||||
}
|
||||
|
||||
nb[nc] = NIL;
|
||||
fe[nc] = ft[nc] = fa[nc] = 1;
|
||||
fc[nc] = c;
|
||||
rfm[nc] = RFMINI;
|
||||
cc[nc] = 0;
|
||||
cl[nc] = conlen;
|
||||
con[nc][0] = curcon[0];
|
||||
con[nc][1] = curcon[1];
|
||||
con[nc][2] = curcon[2];
|
||||
con[nc][3] = curcon[3];
|
||||
|
||||
HASH(curcon, conlen, i);
|
||||
hp[nc] = ht[i];
|
||||
ht[i] = nc;
|
||||
return nc;
|
||||
}
|
||||
|
||||
static void el_movefront(U16B cp)
|
||||
{
|
||||
if(cp == elf) return;
|
||||
if(cp == ell) ell = elp[cp];
|
||||
else
|
||||
{
|
||||
elp[eln[cp]] = elp[cp];
|
||||
eln[elp[cp]] = eln[cp];
|
||||
}
|
||||
elp[elf] = cp;
|
||||
eln[cp] = elf;
|
||||
elf = cp;
|
||||
}
|
||||
|
||||
static void add_model(S16B c)
|
||||
{
|
||||
register U16B i;
|
||||
register S16B cp;
|
||||
|
||||
while(usp != 0)
|
||||
{
|
||||
i = as[--usp];
|
||||
cp = cps[usp];
|
||||
if(cp & 0x8000)
|
||||
{
|
||||
cp &= 0x7fff;
|
||||
if(fcfbl == NIL) release_cfblocks();
|
||||
nb[i] = fcfbl;
|
||||
i = nb[i];
|
||||
fcfbl = nb[fcfbl];
|
||||
nb[i] = NIL;
|
||||
fa[i] = 1;
|
||||
fc[i] = c;
|
||||
++cc[cp];
|
||||
++fe[cp];
|
||||
}
|
||||
else if(++fa[i] == ESCTH) --fe[cp];
|
||||
|
||||
if((fa[i] << 1) < ++ft[cp] / (cc[cp] + 1)) --rfm[cp];
|
||||
else if(rfm[cp] < RFMINI) ++rfm[cp];
|
||||
|
||||
if(!rfm[cp] || ft[cp] >= MAXTVAL)
|
||||
{
|
||||
++rfm[cp];
|
||||
fe[cp] = ft[cp] = 0;
|
||||
for(i = cp; i != NIL; i = nb[i])
|
||||
{
|
||||
if(fa[i] > 1)
|
||||
{
|
||||
ft[cp] += fa[i] >>= 1;
|
||||
if(fa[i] < ESCTH) ++fe[cp];
|
||||
}
|
||||
else
|
||||
{
|
||||
++ft[cp];
|
||||
++fe[cp];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static U16B find_next(void)
|
||||
{
|
||||
register S16B i, k;
|
||||
register U16B cp;
|
||||
|
||||
for(i = cslen - 1; i >= 0; --i)
|
||||
{
|
||||
k = hs[i];
|
||||
for(cp = ht[k]; cp != NIL; cp = hp[cp])
|
||||
{
|
||||
if(cl[cp] == i)
|
||||
{
|
||||
switch(i)
|
||||
{
|
||||
case 4:
|
||||
if(curcon[3] != con[cp][3]) break;
|
||||
case 3:
|
||||
if(curcon[2] != con[cp][2]) break;
|
||||
case 2:
|
||||
if(curcon[1] != con[cp][1]) break;
|
||||
case 1:
|
||||
if(curcon[0] != con[cp][0]) break;
|
||||
case 0:
|
||||
cslen = i;
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
static U16B find_longest(void)
|
||||
{
|
||||
hs[1] = hrt[curcon[0]];
|
||||
hs[2] = hrt[(curcon[1] + hs[1]) & (HTLEN - 1)];
|
||||
hs[3] = hrt[(curcon[2] + hs[2]) & (HTLEN - 1)];
|
||||
hs[4] = hrt[(curcon[3] + hs[3]) & (HTLEN - 1)];
|
||||
usp = 0;
|
||||
while(cmsp) cmask[cmstack[--cmsp]] = 0;
|
||||
cslen = MAXCLEN + 1;
|
||||
return find_next();
|
||||
}
|
||||
|
||||
static U16B adj_escape_prob(U16B esc, U16B cp)
|
||||
{
|
||||
if(ft[cp] == 1) return iec[cl[cp]] >= (IECLIM >> 1) ? 2 : 1;
|
||||
if(cc[cp] == 255) return 1;
|
||||
if(cc[cp] && ((cc[cp] + 1) << 1) >= ft[cp])
|
||||
{
|
||||
esc = (S16B)((S32B)esc * ((cc[cp] + 1) << 1) / ft[cp]);
|
||||
if(cc[cp] + 1 == ft[cp]) esc += (cc[cp] + 1) >> 1;
|
||||
}
|
||||
return esc ? esc : 1;
|
||||
}
|
||||
|
||||
static S16B decode_first(U16B cp)
|
||||
{
|
||||
register U16B c;
|
||||
register U16B tv;
|
||||
register U16B i;
|
||||
register S16B sum, tot, esc, cf;
|
||||
register unsigned char sv;
|
||||
|
||||
esc = adj_escape_prob(fe[cp], cp);
|
||||
tot = ft[cp];
|
||||
if(nec >= NECLIM)
|
||||
{
|
||||
if(tot <= NECTLIM && nec == NECMAX) sv = 2;
|
||||
else sv = 1;
|
||||
tot <<= sv;
|
||||
tv = ac_threshold_val(tot + esc) >> sv;
|
||||
for(c = cp, sum = 0;; c = nb[c])
|
||||
{
|
||||
if(c == NIL) break;
|
||||
if(sum + fa[c] <= tv) sum += fa[c];
|
||||
else
|
||||
{
|
||||
cf = fa[c] << sv;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sum <<= sv;
|
||||
}
|
||||
else
|
||||
{
|
||||
tv = ac_threshold_val(tot + esc);
|
||||
for(c = cp, sum = 0;; c = nb[c])
|
||||
{
|
||||
if(c == NIL) break;
|
||||
if(sum + fa[c] <= tv) sum += fa[c];
|
||||
else
|
||||
{
|
||||
cf = fa[c];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
usp = 1;
|
||||
if(c != NIL)
|
||||
{
|
||||
ac_in(sum, sum + cf, tot + esc);
|
||||
if(ft[cp] == 1 && iec[cl[cp]]) --iec[cl[cp]];
|
||||
as[0] = c;
|
||||
cps[0] = cp;
|
||||
c = fc[c];
|
||||
if(nec < NECMAX) ++nec;
|
||||
}
|
||||
else
|
||||
{
|
||||
ac_in(tot, tot + esc, tot + esc);
|
||||
if(ft[cp] == 1 && iec[cl[cp]] < IECLIM) ++iec[cl[cp]];
|
||||
for(i = cp; i != NIL; sum = i, i = nb[i])
|
||||
{
|
||||
cmstack[cmsp++] = fc[i];
|
||||
cmask[fc[i]] = 1;
|
||||
}
|
||||
cps[0] = 0x8000 | cp;
|
||||
as[0] = sum;
|
||||
c = ESC;
|
||||
nec = 0;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
static S16B decode_rest(U16B cp)
|
||||
{
|
||||
register U16B c;
|
||||
register U16B tv;
|
||||
register U16B i;
|
||||
register S16B sum, tot, esc, cf;
|
||||
|
||||
esc = tot = 0;
|
||||
for(i = cp; i != NIL; i = nb[i])
|
||||
{
|
||||
if(!cmask[fc[i]])
|
||||
{
|
||||
tot += fa[i];
|
||||
if(fa[i] < ESCTH) ++esc;
|
||||
}
|
||||
}
|
||||
esc = adj_escape_prob(esc, cp);
|
||||
tv = ac_threshold_val(tot + esc);
|
||||
|
||||
for(c = cp, sum = 0;; c = nb[c])
|
||||
{
|
||||
if(c == NIL) break;
|
||||
if(!cmask[fc[c]])
|
||||
{
|
||||
if(sum + fa[c] <= tv) sum += fa[c];
|
||||
else
|
||||
{
|
||||
cf = fa[c];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(c != NIL)
|
||||
{
|
||||
ac_in(sum, sum + cf, tot + esc);
|
||||
if(ft[cp] == 1 && iec[cl[cp]]) --iec[cl[cp]];
|
||||
as[usp] = c;
|
||||
cps[usp++] = cp;
|
||||
c = fc[c];
|
||||
++nec;
|
||||
}
|
||||
else
|
||||
{
|
||||
ac_in(tot, tot + esc, tot + esc);
|
||||
if(ft[cp] == 1 && iec[cl[cp]] < IECLIM) ++iec[cl[cp]];
|
||||
for(i = cp; i != NIL; sum = i, i = nb[i])
|
||||
{
|
||||
if(!cmask[fc[i]])
|
||||
{
|
||||
cmstack[cmsp++] = fc[i];
|
||||
cmask[fc[i]] = 1;
|
||||
}
|
||||
}
|
||||
cps[usp] = 0x8000 | cp;
|
||||
as[usp++] = sum;
|
||||
c = ESC;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
static S16B decode_new(void)
|
||||
{
|
||||
register S16B c;
|
||||
register U16B tv, sum, tot;
|
||||
|
||||
tot = 257 - cmsp;
|
||||
tv = ac_threshold_val(tot);
|
||||
for(c = sum = 0; c < 256; ++c)
|
||||
{
|
||||
if(cmask[c]) continue;
|
||||
if(sum + 1 <= tv) ++sum;
|
||||
else break;
|
||||
}
|
||||
ac_in(sum, sum + 1, tot);
|
||||
return c;
|
||||
}
|
||||
|
||||
#define decode_byte(cp) (cmsp ? decode_rest(cp) : decode_first(cp))
|
||||
|
||||
static void flush_output(void)
|
||||
{
|
||||
/* Output flushing is handled by the buffer management */
|
||||
}
|
||||
|
||||
int hsc_unpack(decompress_context_t *ctx)
|
||||
{
|
||||
S16B c;
|
||||
U16B cp;
|
||||
unsigned char ncmax, ncmin;
|
||||
|
||||
if(init_unpack(ctx) < 0) return -1;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if(ctx->input.error || ctx->output.error) break;
|
||||
|
||||
cp = find_longest();
|
||||
ncmin = cp == NIL ? 0 : cl[cp] + 1;
|
||||
ncmax = maxclen + 1;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if(cp == NIL)
|
||||
{
|
||||
c = decode_new();
|
||||
break;
|
||||
}
|
||||
if((c = decode_byte(cp)) != ESC)
|
||||
{
|
||||
el_movefront(cp);
|
||||
break;
|
||||
}
|
||||
cp = find_next();
|
||||
}
|
||||
|
||||
if(c == ESC) break;
|
||||
|
||||
add_model(c);
|
||||
while(ncmax > ncmin) make_context(--ncmax, c);
|
||||
|
||||
if(putbyte_to_buffer(c) < 0) break;
|
||||
move_context(c);
|
||||
|
||||
if(ctx->input.error || ctx->output.error) break;
|
||||
}
|
||||
|
||||
flush_output();
|
||||
hsc_cleanup();
|
||||
return (ctx->input.error || ctx->output.error) ? -1 : 0;
|
||||
}
|
||||
90
ha/hsc.h
Normal file
90
ha/hsc.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/***********************************************************************
|
||||
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 HSC method
|
||||
***********************************************************************/
|
||||
|
||||
/***********************************************************************
|
||||
Modified to work with memory buffers instead of files by
|
||||
Copyright (C) 2005 Natalia Portillo
|
||||
************************************************************************/
|
||||
|
||||
#ifndef HSC_H
|
||||
#define HSC_H
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
int hsc_unpack(decompress_context_t *ctx);
|
||||
|
||||
#define IECLIM 32
|
||||
#define NECLIM 5
|
||||
#define NECTLIM 4
|
||||
#define NECMAX 10
|
||||
#define MAXCLEN 4
|
||||
#define NUMCON 10000
|
||||
#define NUMCFB 32760
|
||||
#define ESCTH 3
|
||||
#define MAXTVAL 8000
|
||||
#define RFMINI 4
|
||||
#define HTLEN 16384
|
||||
#define NIL 0xffff
|
||||
#define ESC 256
|
||||
|
||||
typedef unsigned char Context[4];
|
||||
|
||||
/* Model data */
|
||||
static Context curcon;
|
||||
static U16B * ht = NULL;
|
||||
static U16B * hp = NULL;
|
||||
static Context * con = NULL;
|
||||
static unsigned char *cl = NULL;
|
||||
static unsigned char *cc = NULL;
|
||||
static U16B * ft = NULL;
|
||||
static unsigned char *fe = NULL;
|
||||
static U16B * elp = NULL;
|
||||
static U16B * eln = NULL;
|
||||
static U16B elf, ell;
|
||||
static unsigned char *rfm = NULL;
|
||||
static U16B * fa = NULL;
|
||||
static unsigned char *fc = NULL;
|
||||
static U16B * nb = NULL;
|
||||
static U16B fcfbl;
|
||||
static U16B nrel;
|
||||
|
||||
/* Frequency mask system */
|
||||
static unsigned char cmask[256];
|
||||
static unsigned char cmstack[256];
|
||||
static S16B cmsp;
|
||||
|
||||
/* Escape probability modifying system variables */
|
||||
static unsigned char nec;
|
||||
static unsigned char iec[MAXCLEN + 1];
|
||||
|
||||
/* Update stack variables */
|
||||
static U16B usp;
|
||||
static U16B cps[MAXCLEN + 1];
|
||||
static U16B as[MAXCLEN + 1];
|
||||
|
||||
/* Miscellaneous */
|
||||
static S16B dropcnt;
|
||||
static unsigned char maxclen;
|
||||
static U16B hrt[HTLEN];
|
||||
static U16B hs[MAXCLEN + 1];
|
||||
static S16B cslen;
|
||||
|
||||
#endif /* HSC_H */
|
||||
45
ha/internal.h
Normal file
45
ha/internal.h
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
/***********************************************************************
|
||||
Modified to work with memory buffers instead of files by
|
||||
Copyright (C) 2005 Natalia Portillo
|
||||
************************************************************************/
|
||||
|
||||
#ifndef INTERNAL_H
|
||||
#define INTERNAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* Type definitions matching original HA code */
|
||||
typedef int16_t S16B;
|
||||
typedef uint16_t U16B;
|
||||
typedef int32_t S32B;
|
||||
typedef uint32_t U32B;
|
||||
|
||||
/* Memory buffer management */
|
||||
typedef struct
|
||||
{
|
||||
const unsigned char *data;
|
||||
size_t size;
|
||||
size_t pos;
|
||||
int error;
|
||||
} input_buffer_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char *data;
|
||||
size_t size;
|
||||
size_t pos;
|
||||
size_t max_size;
|
||||
int error;
|
||||
} output_buffer_t;
|
||||
|
||||
/* Decompression context */
|
||||
typedef struct
|
||||
{
|
||||
input_buffer_t input;
|
||||
output_buffer_t output;
|
||||
int algorithm;
|
||||
} decompress_context_t;
|
||||
|
||||
#endif /* INTERNAL_H */
|
||||
99
ha/swdict.c
Normal file
99
ha/swdict.c
Normal file
@@ -0,0 +1,99 @@
|
||||
/***********************************************************************
|
||||
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 sliding window dictionary
|
||||
***********************************************************************/
|
||||
|
||||
/***********************************************************************
|
||||
Modified to work with memory buffers instead of files by
|
||||
Copyright (C) 2005 Natalia Portillo
|
||||
************************************************************************/
|
||||
|
||||
#include "internal.h"
|
||||
#include "swdict.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
U16B swd_bpos, swd_mlf;
|
||||
S16B swd_char;
|
||||
|
||||
static decompress_context_t *g_ctx = NULL;
|
||||
static U16B cblen, bbf;
|
||||
static unsigned char * b = NULL;
|
||||
|
||||
void swd_cleanup(void)
|
||||
{
|
||||
if(b != NULL)
|
||||
{
|
||||
free(b);
|
||||
b = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void swd_dinit(decompress_context_t *ctx, U16B bufl)
|
||||
{
|
||||
g_ctx = ctx;
|
||||
cblen = bufl;
|
||||
|
||||
b = malloc(cblen * sizeof(unsigned char));
|
||||
if(b == NULL)
|
||||
{
|
||||
ctx->output.error = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
bbf = 0;
|
||||
}
|
||||
|
||||
static int putbyte_to_buffer(unsigned char c)
|
||||
{
|
||||
if(!g_ctx || g_ctx->output.pos >= g_ctx->output.max_size)
|
||||
{
|
||||
if(g_ctx) g_ctx->output.error = 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_ctx->output.data[g_ctx->output.pos++] = c;
|
||||
if(g_ctx->output.pos > g_ctx->output.size) { g_ctx->output.size = g_ctx->output.pos; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
void swd_dpair(U16B l, U16B p)
|
||||
{
|
||||
if(!g_ctx || g_ctx->output.error) return;
|
||||
|
||||
if(bbf > p) p = bbf - 1 - p;
|
||||
else p = cblen - 1 - p + bbf;
|
||||
|
||||
while(l--)
|
||||
{
|
||||
b[bbf] = b[p];
|
||||
if(putbyte_to_buffer(b[p]) < 0) return;
|
||||
if(++bbf == cblen) bbf = 0;
|
||||
if(++p == cblen) p = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void swd_dchar(S16B c)
|
||||
{
|
||||
if(!g_ctx || g_ctx->output.error) return;
|
||||
|
||||
b[bbf] = c;
|
||||
if(putbyte_to_buffer(c) < 0) return;
|
||||
if(++bbf == cblen) bbf = 0;
|
||||
}
|
||||
45
ha/swdict.h
Normal file
45
ha/swdict.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/***********************************************************************
|
||||
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 sliding window dictionary
|
||||
***********************************************************************/
|
||||
|
||||
/***********************************************************************
|
||||
Modified to work with memory buffers instead of files by
|
||||
Copyright (C) 2005 Natalia Portillo
|
||||
************************************************************************/
|
||||
|
||||
#ifndef SWDICT_H
|
||||
#define SWDICT_H
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#define MINLEN 3 /* Minimum possible match length */
|
||||
|
||||
void swd_dinit(decompress_context_t *ctx, U16B bufl);
|
||||
|
||||
void swd_cleanup(void);
|
||||
|
||||
void swd_dpair(U16B l, U16B p);
|
||||
|
||||
void swd_dchar(S16B c);
|
||||
|
||||
extern U16B swd_bpos, swd_mlf;
|
||||
extern S16B swd_char;
|
||||
|
||||
#endif /* SWDICT_H */
|
||||
12
library.h
12
library.h
@@ -150,4 +150,16 @@ AARU_EXPORT int AARU_CALL pak_decompress_crush(const unsigned char *in_buf, size
|
||||
AARU_EXPORT int AARU_CALL pak_decompress_distill(const unsigned char *in_buf, size_t in_len, unsigned char *out_buf,
|
||||
size_t *out_len);
|
||||
|
||||
/**
|
||||
* HA Algorithm Types
|
||||
*/
|
||||
typedef enum {
|
||||
HA_ALGORITHM_ASC = 0, /* ASC algorithm */
|
||||
HA_ALGORITHM_HSC = 1 /* HSC algorithm */
|
||||
} ha_algorithm_t;
|
||||
|
||||
AARU_EXPORT int AARU_CALL ha_asc_decompress(const unsigned char *in_buf, size_t in_len, unsigned char *out_buf, size_t *out_len);
|
||||
|
||||
AARU_EXPORT int AARU_CALL ha_hsc_decompress(const unsigned char *in_buf, size_t in_len, unsigned char *out_buf, size_t *out_len);
|
||||
|
||||
#endif // AARU_COMPRESSION_NATIVE_LIBRARY_H
|
||||
|
||||
@@ -66,11 +66,15 @@ file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/pak_crush.bin
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/pak_distill.bin
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
|
||||
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/ha_asc.bin
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
|
||||
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/ha_hsc.bin
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
|
||||
|
||||
# 'Google_Tests_run' is the target name
|
||||
# 'test1.cpp tests2.cpp' are source files with tests
|
||||
add_executable(tests_run apple_rle.cpp crc32.c crc32.h adc.cpp bzip2.cpp lzip.cpp lzfse.cpp zstd.cpp lzma.cpp flac.cpp
|
||||
zoo/lzd.cpp arc/pack.cpp lh5.cpp arc/squeeze.cpp arc/crunch.cpp
|
||||
arc/squash.cpp
|
||||
pak/crush.cpp
|
||||
pak/distill.cpp)
|
||||
zoo/lzd.cpp arc/pack.cpp lh5.cpp arc/squeeze.cpp arc/crunch.cpp arc/squash.cpp pak/crush.cpp
|
||||
pak/distill.cpp ha.cpp)
|
||||
target_link_libraries(tests_run gtest gtest_main "Aaru.Compression.Native")
|
||||
|
||||
133
tests/ha.cpp
Normal file
133
tests/ha.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* This file is part of the Aaru Data Preservation Suite.
|
||||
* Copyright (c) 2019-2025 Natalia Portillo.
|
||||
*
|
||||
* 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include "../library.h"
|
||||
#include "crc32.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#define EXPECTED_CRC32 0x66007dba
|
||||
|
||||
static const uint8_t *buffer;
|
||||
|
||||
class ha_ascFixture : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
ha_ascFixture()
|
||||
{
|
||||
// initialization;
|
||||
// can also be done in SetUp()
|
||||
}
|
||||
|
||||
protected:
|
||||
void SetUp()
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
char filename[PATH_MAX];
|
||||
|
||||
getcwd(path, PATH_MAX);
|
||||
snprintf(filename, PATH_MAX, "%s/data/ha_asc.bin", path);
|
||||
|
||||
FILE *file = fopen(filename, "rb");
|
||||
buffer = (const uint8_t *)malloc(53654);
|
||||
fread((void *)buffer, 1, 53654, file);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
void TearDown() { free((void *)buffer); }
|
||||
|
||||
~ha_ascFixture()
|
||||
{
|
||||
// resources cleanup, no exceptions allowed
|
||||
}
|
||||
|
||||
// shared user data
|
||||
};
|
||||
|
||||
TEST_F(ha_ascFixture, ha_asc)
|
||||
{
|
||||
size_t destLen = 152089;
|
||||
size_t srcLen = 53654;
|
||||
auto * outBuf = (uint8_t *)malloc(53654);
|
||||
|
||||
auto err = ha_asc_decompress(buffer, srcLen, outBuf, &destLen);
|
||||
|
||||
EXPECT_EQ(err, 0);
|
||||
EXPECT_EQ(destLen, 152089);
|
||||
|
||||
auto crc = crc32_data(outBuf, 152089);
|
||||
|
||||
free(outBuf);
|
||||
|
||||
EXPECT_EQ(crc, EXPECTED_CRC32);
|
||||
}
|
||||
|
||||
class ha_hscFixture : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
ha_hscFixture()
|
||||
{
|
||||
// initialization;
|
||||
// can also be done in SetUp()
|
||||
}
|
||||
|
||||
protected:
|
||||
void SetUp()
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
char filename[PATH_MAX];
|
||||
|
||||
getcwd(path, PATH_MAX);
|
||||
snprintf(filename, PATH_MAX, "%s/data/ha_hsc.bin", path);
|
||||
|
||||
FILE *file = fopen(filename, "rb");
|
||||
buffer = (const uint8_t *)malloc(41839);
|
||||
fread((void *)buffer, 1, 41839, file);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
void TearDown() { free((void *)buffer); }
|
||||
|
||||
~ha_hscFixture()
|
||||
{
|
||||
// resources cleanup, no exceptions allowed
|
||||
}
|
||||
|
||||
// shared user data
|
||||
};
|
||||
|
||||
TEST_F(ha_hscFixture, ha_hsc)
|
||||
{
|
||||
size_t destLen = 152089;
|
||||
size_t srcLen = 41839;
|
||||
auto * outBuf = (uint8_t *)malloc(152089);
|
||||
|
||||
auto err = ha_hsc_decompress(buffer, srcLen, outBuf, &destLen);
|
||||
|
||||
EXPECT_EQ(err, 0);
|
||||
EXPECT_EQ(destLen, 152089);
|
||||
|
||||
auto crc = crc32_data(outBuf, 152089);
|
||||
|
||||
free(outBuf);
|
||||
|
||||
EXPECT_EQ(crc, EXPECTED_CRC32);
|
||||
}
|
||||
Submodule tests/lib updated: 16f637fbf4...614f05d1c0
Reference in New Issue
Block a user