mirror of
https://github.com/aaru-dps/Aaru.Compression.Native.git
synced 2025-12-16 11:14:30 +00:00
Add support for decompressing Lempel-Ziv-Huffman, LH5 variant.
This commit is contained in:
@@ -130,7 +130,16 @@ add_subdirectory(3rdparty)
|
||||
|
||||
add_library("Aaru.Compression.Native" SHARED library.c apple_rle.c apple_rle.h adc.c adc.h lzip.c flac.c flac.h
|
||||
zoo/lzd.c
|
||||
zoo/lzd.h)
|
||||
zoo/lzd.h
|
||||
zoo/lzh.c
|
||||
zoo/decode.c
|
||||
zoo/huf.c
|
||||
zoo/io.c
|
||||
zoo/lh5.h
|
||||
zoo/lh5.c
|
||||
zoo/lzh.h
|
||||
zoo/ar.h
|
||||
zoo/maketbl.c)
|
||||
|
||||
include(3rdparty/bzip2.cmake)
|
||||
include(3rdparty/flac.cmake)
|
||||
|
||||
@@ -112,6 +112,8 @@ AARU_EXPORT int AARU_CALL LZD_FeedNative(void *ctx, const unsigned char *data, s
|
||||
|
||||
AARU_EXPORT int AARU_CALL LZD_DrainNative(void *ctx, unsigned char *outBuf, size_t outBufLen, size_t *produced);
|
||||
|
||||
AARU_EXPORT int AARU_CALL lh5_decompress(const uint8_t *in_buf, size_t in_len, uint8_t *out_buf, size_t *out_len);
|
||||
|
||||
#define AARU_CHECKUMS_NATIVE_VERSION 0x06000089
|
||||
|
||||
AARU_EXPORT uint64_t AARU_CALL AARU_get_acn_version();
|
||||
|
||||
@@ -42,8 +42,12 @@ file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/data.bin
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/alice29.lzd
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/data/)
|
||||
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data/alice29.lh5
|
||||
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)
|
||||
zoo/lzd.cpp
|
||||
lh5.cpp)
|
||||
target_link_libraries(tests_run gtest gtest_main "Aaru.Compression.Native")
|
||||
|
||||
BIN
tests/data/alice29.lh5
Normal file
BIN
tests/data/alice29.lh5
Normal file
Binary file not shown.
84
tests/lh5.cpp
Normal file
84
tests/lh5.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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 "../zoo/lh5.h"
|
||||
|
||||
#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 lh5Fixture : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
lh5Fixture()
|
||||
{
|
||||
// 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/alice29.lh5", path);
|
||||
|
||||
FILE *file = fopen(filename, "rb");
|
||||
buffer = (const uint8_t *)malloc(59104);
|
||||
fread((void *)buffer, 1, 59104, file);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
void TearDown() { free((void *)buffer); }
|
||||
|
||||
~lh5Fixture()
|
||||
{
|
||||
// resources cleanup, no exceptions allowed
|
||||
}
|
||||
|
||||
// shared user data
|
||||
};
|
||||
|
||||
TEST_F(lh5Fixture, lh5)
|
||||
{
|
||||
uint8_t params[] = {0x5D, 0x00, 0x00, 0x00, 0x02};
|
||||
size_t destLen = 152089;
|
||||
size_t srcLen = 59104;
|
||||
auto *outBuf = (uint8_t *)malloc(152089);
|
||||
|
||||
auto err = lh5_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);
|
||||
}
|
||||
40
zoo/ar.h
Normal file
40
zoo/ar.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*$Source: /usr/home/dhesi/zoo/RCS/ar.h,v $*/
|
||||
/*$Id: ar.h,v 1.17 91/07/09 01:39:50 dhesi Exp $*/
|
||||
/***********************************************************
|
||||
ar.h
|
||||
|
||||
Adapted from "ar" archiver written by Haruhiko Okumura.
|
||||
***********************************************************/
|
||||
// Modified for in-memory decompression by Natalia Portillo, 2025
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* all the prototypes follow here for all files */
|
||||
|
||||
/* DECODE.C */
|
||||
void decode_start();
|
||||
int decode(uint32_t count, uint8_t *buffer);
|
||||
|
||||
/* HUF.C */
|
||||
void output(uint32_t c, uint32_t p);
|
||||
uint32_t decode_c(void);
|
||||
uint32_t decode_p(void);
|
||||
void huf_decode_start(void);
|
||||
|
||||
/* IO.C */
|
||||
void fillbuf(int n);
|
||||
uint32_t getbits(int n);
|
||||
void putbits(int n, uint32_t x);
|
||||
void init_getbits(void);
|
||||
void init_putbits(void);
|
||||
|
||||
/* MAKETBL.C */
|
||||
void make_table(int nchar, uint8_t bitlen[], int tablebits, uint16_t table[]);
|
||||
|
||||
/* MAKETREE.C */
|
||||
int make_tree(int nparm, uint16_t freqparm[], uint8_t lenparm[], uint16_t codeparm[]);
|
||||
|
||||
/* for lzh modules and also for ar.c to use in defining buffer size */
|
||||
#define DICBIT 13 /* 12(-lh4-) or 13(-lh5-) */
|
||||
#define DICSIZ ((unsigned)1 << DICBIT)
|
||||
71
zoo/decode.c
Normal file
71
zoo/decode.c
Normal file
@@ -0,0 +1,71 @@
|
||||
/*$Source: /usr/home/dhesi/zoo/RCS/decode.c,v $*/
|
||||
/*$Id: decode.c,v 1.6 91/07/09 01:39:49 dhesi Exp $*/
|
||||
/***********************************************************
|
||||
decode.c
|
||||
|
||||
Adapted from "ar" archiver written by Haruhiko Okumura.
|
||||
***********************************************************/
|
||||
// Modified for in-memory decompression by Natalia Portillo, 2025
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ar.h"
|
||||
#include "lzh.h"
|
||||
|
||||
extern int decoded; /* from huf.c */
|
||||
|
||||
static int j; /* remaining bytes to copy */
|
||||
|
||||
void decode_start()
|
||||
{
|
||||
huf_decode_start();
|
||||
j = 0;
|
||||
decoded = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
decodes; returns no. of chars decoded
|
||||
*/
|
||||
|
||||
int decode(uint32_t count, uint8_t *buffer)
|
||||
/* The calling function must keep the number of
|
||||
bytes to be processed. This function decodes
|
||||
either 'count' bytes or 'DICSIZ' bytes, whichever
|
||||
is smaller, into the array 'buffer[]' of size
|
||||
'DICSIZ' or more.
|
||||
Call decode_start() once for each new file
|
||||
before calling this function. */
|
||||
{
|
||||
static uint32_t i;
|
||||
uint32_t r, c;
|
||||
|
||||
r = 0;
|
||||
while(--j >= 0)
|
||||
{
|
||||
buffer[r] = buffer[i];
|
||||
i = (i + 1) & (DICSIZ - 1);
|
||||
if(++r == count) return r;
|
||||
}
|
||||
for(;;)
|
||||
{
|
||||
c = decode_c();
|
||||
if(decoded) return r;
|
||||
if(c <= UCHAR_MAX)
|
||||
{
|
||||
buffer[r] = c;
|
||||
if(++r == count) return r;
|
||||
}
|
||||
else
|
||||
{
|
||||
j = c - (UCHAR_MAX + 1 - THRESHOLD);
|
||||
i = (r - decode_p() - 1) & (DICSIZ - 1);
|
||||
while(--j >= 0)
|
||||
{
|
||||
buffer[r] = buffer[i];
|
||||
i = (i + 1) & (DICSIZ - 1);
|
||||
if(++r == count) return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
187
zoo/huf.c
Normal file
187
zoo/huf.c
Normal file
@@ -0,0 +1,187 @@
|
||||
/*$Source: /usr/home/dhesi/zoo/RCS/huf.c,v $*/
|
||||
/*$Id: huf.c,v 1.9 91/07/09 01:39:55 dhesi Exp $*/
|
||||
/***********************************************************
|
||||
huf.c -- static Huffman
|
||||
|
||||
Adapted from "ar" archiver written by Haruhiko Okumura.
|
||||
***********************************************************/
|
||||
// Modified for in-memory decompression by Natalia Portillo, 2025
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "ar.h"
|
||||
#include "lzh.h"
|
||||
|
||||
#define NP (DICBIT + 1)
|
||||
#define NT (CODE_BIT + 3)
|
||||
#define PBIT 4 /* smallest integer such that (1U << PBIT) > NP */
|
||||
#define TBIT 5 /* smallest integer such that (1U << TBIT) > NT */
|
||||
#if NT > NP
|
||||
#define NPT NT
|
||||
#else
|
||||
#define NPT NP
|
||||
#endif
|
||||
|
||||
static void read_pt_len(int, int, int);
|
||||
static void read_c_len();
|
||||
|
||||
int decoded; /* for use in decode.c */
|
||||
|
||||
uint16_t left[2 * NC - 1], right[2 * NC - 1];
|
||||
static uint8_t *buf, c_len[NC], pt_len[NPT];
|
||||
static uint32_t bufsiz = 0, blocksize;
|
||||
static uint16_t c_freq[2 * NC - 1], c_table[4096], c_code[NC], p_freq[2 * NP - 1], pt_table[256], pt_code[NPT],
|
||||
t_freq[2 * NT - 1];
|
||||
|
||||
/***** decoding *****/
|
||||
|
||||
static void read_pt_len(int nn, int nbit, int i_special)
|
||||
{
|
||||
int i, c, n;
|
||||
uint32_t mask;
|
||||
|
||||
n = getbits(nbit);
|
||||
if(n == 0)
|
||||
{
|
||||
c = getbits(nbit);
|
||||
for(i = 0; i < nn; i++) pt_len[i] = 0;
|
||||
for(i = 0; i < 256; i++) pt_table[i] = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = 0;
|
||||
while(i < n)
|
||||
{
|
||||
c = bitbuf >> (BITBUFSIZ - 3);
|
||||
if(c == 7)
|
||||
{
|
||||
mask = (unsigned)1 << (BITBUFSIZ - 1 - 3);
|
||||
while(mask & bitbuf)
|
||||
{
|
||||
mask >>= 1;
|
||||
c++;
|
||||
}
|
||||
}
|
||||
fillbuf((c < 7) ? 3 : c - 3);
|
||||
pt_len[i++] = c;
|
||||
if(i == i_special)
|
||||
{
|
||||
c = getbits(2);
|
||||
while(--c >= 0) pt_len[i++] = 0;
|
||||
}
|
||||
}
|
||||
while(i < nn) pt_len[i++] = 0;
|
||||
make_table(nn, pt_len, 8, pt_table);
|
||||
}
|
||||
}
|
||||
|
||||
static void read_c_len()
|
||||
{
|
||||
int i, c, n;
|
||||
uint32_t mask;
|
||||
|
||||
n = getbits(CBIT);
|
||||
if(n == 0)
|
||||
{
|
||||
c = getbits(CBIT);
|
||||
for(i = 0; i < NC; i++) c_len[i] = 0;
|
||||
for(i = 0; i < 4096; i++) c_table[i] = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = 0;
|
||||
while(i < n)
|
||||
{
|
||||
c = pt_table[bitbuf >> (BITBUFSIZ - 8)];
|
||||
if(c >= NT)
|
||||
{
|
||||
mask = (unsigned)1 << (BITBUFSIZ - 1 - 8);
|
||||
do {
|
||||
if(bitbuf & mask)
|
||||
c = right[c];
|
||||
else
|
||||
c = left[c];
|
||||
mask >>= 1;
|
||||
} while(c >= NT);
|
||||
}
|
||||
fillbuf(pt_len[c]);
|
||||
if(c <= 2)
|
||||
{
|
||||
if(c == 0)
|
||||
c = 1;
|
||||
else if(c == 1)
|
||||
c = getbits(4) + 3;
|
||||
else
|
||||
c = getbits(CBIT) + 20;
|
||||
while(--c >= 0) c_len[i++] = 0;
|
||||
}
|
||||
else
|
||||
c_len[i++] = c - 2;
|
||||
}
|
||||
while(i < NC) c_len[i++] = 0;
|
||||
make_table(NC, c_len, 12, c_table);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t decode_c()
|
||||
{
|
||||
uint32_t j, mask;
|
||||
|
||||
if(blocksize == 0)
|
||||
{
|
||||
blocksize = getbits(16);
|
||||
if(blocksize == 0)
|
||||
{
|
||||
#if 0
|
||||
(void) fprintf(stderr, "block size = 0, decoded\n"); /* debug */
|
||||
#endif
|
||||
decoded = 1;
|
||||
return 0;
|
||||
}
|
||||
read_pt_len(NT, TBIT, 3);
|
||||
read_c_len();
|
||||
read_pt_len(NP, PBIT, -1);
|
||||
}
|
||||
blocksize--;
|
||||
j = c_table[bitbuf >> (BITBUFSIZ - 12)];
|
||||
if(j >= NC)
|
||||
{
|
||||
mask = (unsigned)1 << (BITBUFSIZ - 1 - 12);
|
||||
do {
|
||||
if(bitbuf & mask)
|
||||
j = right[j];
|
||||
else
|
||||
j = left[j];
|
||||
mask >>= 1;
|
||||
} while(j >= NC);
|
||||
}
|
||||
fillbuf(c_len[j]);
|
||||
return j;
|
||||
}
|
||||
|
||||
uint32_t decode_p()
|
||||
{
|
||||
uint32_t j, mask;
|
||||
|
||||
j = pt_table[bitbuf >> (BITBUFSIZ - 8)];
|
||||
if(j >= NP)
|
||||
{
|
||||
mask = (unsigned)1 << (BITBUFSIZ - 1 - 8);
|
||||
do {
|
||||
if(bitbuf & mask)
|
||||
j = right[j];
|
||||
else
|
||||
j = left[j];
|
||||
mask >>= 1;
|
||||
} while(j >= NP);
|
||||
}
|
||||
fillbuf(pt_len[j]);
|
||||
if(j != 0) j = ((unsigned)1 << (j - 1)) + getbits((int)(j - 1));
|
||||
return j;
|
||||
}
|
||||
|
||||
void huf_decode_start()
|
||||
{
|
||||
init_getbits();
|
||||
blocksize = 0;
|
||||
}
|
||||
105
zoo/io.c
Normal file
105
zoo/io.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/*$Source: /usr/home/dhesi/zoo/RCS/io.c,v $*/
|
||||
/*$Id: io.c,v 1.14 91/07/09 01:39:54 dhesi Exp $*/
|
||||
/***********************************************************
|
||||
io.c -- input/output (modified for in-memory I/O)
|
||||
|
||||
Adapted from "ar" archiver written by Haruhiko Okumura.
|
||||
This version reads compressed bytes from an input buffer
|
||||
via mem_getc() and writes output bytes to a buffer via
|
||||
mem_putc(), removing all FILE* dependencies for decompression.
|
||||
***********************************************************/
|
||||
// Modified for in-memory decompression by Natalia Portillo, 2025
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "ar.h"
|
||||
#include "lzh.h"
|
||||
|
||||
#include "lh5.h" /* mem_getc(), mem_putc(), in_ptr/in_left, out_ptr/out_left */
|
||||
|
||||
uint16_t bitbuf;
|
||||
int unpackable;
|
||||
size_t compsize, origsize;
|
||||
uint32_t subbitbuf;
|
||||
int bitcount;
|
||||
|
||||
/*
|
||||
* fillbuf(n) -- shift bitbuf left by n bits and read in n new bits
|
||||
* now reads bytes directly from in-memory input buffer
|
||||
*/
|
||||
void fillbuf(int n) /* Shift bitbuf n bits left, read n bits */
|
||||
{
|
||||
bitbuf <<= n;
|
||||
while(n > bitcount)
|
||||
{
|
||||
bitbuf |= subbitbuf << (n -= bitcount);
|
||||
|
||||
/* fetch next compressed byte from in_buf */
|
||||
{
|
||||
int c = mem_getc();
|
||||
subbitbuf = (c == EOF ? 0 : (uint8_t)c);
|
||||
}
|
||||
|
||||
bitcount = CHAR_BIT;
|
||||
}
|
||||
bitbuf |= subbitbuf >> (bitcount -= n);
|
||||
}
|
||||
|
||||
/*
|
||||
* getbits(n) -- return next n bits from the bit buffer
|
||||
*/
|
||||
uint32_t getbits(int n)
|
||||
{
|
||||
uint32_t x = bitbuf >> (BITBUFSIZ - n);
|
||||
fillbuf(n);
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* putbits(n,x) -- write the lowest n bits of x to the bit buffer
|
||||
* now writes bytes directly to in-memory output buffer
|
||||
*/
|
||||
void putbits(int n, uint32_t x) /* Write rightmost n bits of x */
|
||||
{
|
||||
if(n < bitcount) { subbitbuf |= x << (bitcount -= n); }
|
||||
else
|
||||
{
|
||||
/* output first byte */
|
||||
{
|
||||
int w = (int)(subbitbuf | (x >> (n -= bitcount)));
|
||||
mem_putc(w);
|
||||
compsize++;
|
||||
}
|
||||
if(n < CHAR_BIT) { subbitbuf = x << (bitcount = CHAR_BIT - n); }
|
||||
else
|
||||
{
|
||||
/* output second byte */
|
||||
{
|
||||
int w2 = (int)(x >> (n - CHAR_BIT));
|
||||
mem_putc(w2);
|
||||
compsize++;
|
||||
}
|
||||
subbitbuf = x << (bitcount = 2 * CHAR_BIT - n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* init_getbits -- initialize bit reader state
|
||||
*/
|
||||
void init_getbits()
|
||||
{
|
||||
bitbuf = 0;
|
||||
subbitbuf = 0;
|
||||
bitcount = 0;
|
||||
fillbuf(BITBUFSIZ);
|
||||
}
|
||||
|
||||
/*
|
||||
* init_putbits -- initialize bit writer state
|
||||
*/
|
||||
void init_putbits()
|
||||
{
|
||||
bitcount = CHAR_BIT;
|
||||
subbitbuf = 0;
|
||||
}
|
||||
94
zoo/lh5.c
Normal file
94
zoo/lh5.c
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/* lh5_mem.c
|
||||
*
|
||||
* In-memory I/O glue for LH5 decompression.
|
||||
* Implements mem_getc(), mem_putc(), and the top-level
|
||||
* lh5_decompress() entry point.
|
||||
*/
|
||||
|
||||
#include "lh5.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "../library.h"
|
||||
|
||||
/* Forward-declaration of the decompression driver in lzh.c */
|
||||
extern int lzh_decode(void);
|
||||
|
||||
/* Buffer I/O state (see lh5_mem.h for externs) */
|
||||
const uint8_t *in_ptr;
|
||||
size_t in_left;
|
||||
uint8_t *out_ptr;
|
||||
size_t out_left;
|
||||
int mem_error;
|
||||
|
||||
/*
|
||||
* mem_getc(): return next compressed byte, or 0 when in_left==0.
|
||||
* Never sets mem_error on input underflow.
|
||||
*/
|
||||
int mem_getc(void)
|
||||
{
|
||||
if(in_left == 0) { return 0; /* mimic feof → subbitbuf = 0 */ }
|
||||
int c = *in_ptr++;
|
||||
in_left--;
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
* mem_putc(): write one output byte, set mem_error on overflow.
|
||||
*/
|
||||
int mem_putc(int c)
|
||||
{
|
||||
if(out_left == 0)
|
||||
{
|
||||
mem_error = 1;
|
||||
return EOF;
|
||||
}
|
||||
*out_ptr++ = (uint8_t)c;
|
||||
out_left--;
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
* Top-level in-memory decompressor.
|
||||
*
|
||||
* in_buf points to 'in_len' bytes of compressed data.
|
||||
* out_buf must have at least *out_len bytes available.
|
||||
* On return *out_len is set to the number of bytes written.
|
||||
*
|
||||
* Returns 0 on success
|
||||
* -1 on error (bad stream or output too small)
|
||||
*/
|
||||
AARU_EXPORT int AARU_CALL lh5_decompress(const uint8_t *in_buf, size_t in_len, uint8_t *out_buf, size_t *out_len)
|
||||
{
|
||||
/* Initialize buffer pointers and error flag */
|
||||
in_ptr = in_buf;
|
||||
in_left = in_len;
|
||||
out_ptr = out_buf;
|
||||
out_left = *out_len;
|
||||
mem_error = 0;
|
||||
|
||||
/* Invoke the core LH5 decode routine (now buffer-based) */
|
||||
if(lzh_decode() != 0 || mem_error) { return -1; }
|
||||
|
||||
/* Compute actual output size */
|
||||
*out_len = (size_t)(out_ptr - out_buf);
|
||||
return 0;
|
||||
}
|
||||
54
zoo/lh5.h
Normal file
54
zoo/lh5.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/* lh5_mem.h
|
||||
*
|
||||
* In-memory I/O glue for LH5 decompression.
|
||||
* Defines the mem_getc()/mem_putc() buffer readers/writers
|
||||
* and declares the lh5_decompress() entry point.
|
||||
*/
|
||||
#ifndef AARU_COMPRESSION_NATIVE_LH5_H
|
||||
#define AARU_COMPRESSION_NATIVE_LH5_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* State for in-memory I/O
|
||||
* --------------------------------------------------------------------------
|
||||
* in_ptr/in_left: where to read next compressed byte
|
||||
* out_ptr/out_left: where to write next decompressed byte
|
||||
* mem_error: set to 1 on underflow/overflow
|
||||
*/
|
||||
extern const uint8_t *in_ptr;
|
||||
extern size_t in_left;
|
||||
extern uint8_t *out_ptr;
|
||||
extern size_t out_left;
|
||||
extern int mem_error;
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* Fetch one byte from in_buf; returns EOF on underflow
|
||||
* -------------------------------------------------------------------------- */
|
||||
int mem_getc(void);
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* Write one byte into out_buf; returns c or EOF on overflow
|
||||
* -------------------------------------------------------------------------- */
|
||||
int mem_putc(int c);
|
||||
|
||||
#endif // AARU_COMPRESSION_NATIVE_LH5_H
|
||||
@@ -220,11 +220,11 @@ AARU_EXPORT void AARU_CALL DestroyLZDContext(void *ctx)
|
||||
// Public API wrapper to feed new compressed data
|
||||
AARU_EXPORT int AARU_CALL LZD_FeedNative(void *ctx, const unsigned char *data, size_t length)
|
||||
{
|
||||
return (int)LZD_Feed(ctx, data, length);
|
||||
return LZD_Feed(ctx, data, length);
|
||||
}
|
||||
|
||||
// Public API wrapper to drain decompressed data
|
||||
AARU_EXPORT int AARU_CALL LZD_DrainNative(void *ctx, unsigned char *outBuf, size_t outBufLen, size_t *produced)
|
||||
{
|
||||
return (int)LZD_Drain(ctx, outBuf, outBufLen, produced);
|
||||
return LZD_Drain(ctx, outBuf, outBufLen, produced);
|
||||
}
|
||||
31
zoo/lzh.c
Normal file
31
zoo/lzh.c
Normal file
@@ -0,0 +1,31 @@
|
||||
/* $Id: lzh.c,v 1.15 91/07/06 19:18:51 dhesi Exp $ */
|
||||
// Modified for in-memory decompression by Natalia Portillo, 2025
|
||||
|
||||
#include "lzh.h" /* prototypes for encode(), lzh_decode() */
|
||||
#include <stdint.h>
|
||||
#include "ar.h"
|
||||
#include "lh5.h" /* mem_getc(), mem_putc(), in_ptr/in_left, out_ptr/out_left */
|
||||
|
||||
extern int decoded; /* from huf.c */
|
||||
|
||||
/*
|
||||
* lzh_decode now reads from in_buf/in_len and writes into out_buf/out_len
|
||||
* entirely in memory, via mem_getc()/mem_putc().
|
||||
*/
|
||||
int lzh_decode(void)
|
||||
{
|
||||
int n, i;
|
||||
uint8_t buffer[DICSIZ];
|
||||
|
||||
/* Initialize the Huffman bit reader and sliding-window state */
|
||||
decode_start();
|
||||
|
||||
/* Decode blocks of up to DICSIZ bytes until end‐of‐stream */
|
||||
while(!decoded)
|
||||
{
|
||||
n = decode(DICSIZ, buffer);
|
||||
for(i = 0; i < n; i++) { mem_putc(buffer[i]); }
|
||||
}
|
||||
|
||||
return mem_error ? -1 : 0;
|
||||
}
|
||||
31
zoo/lzh.h
Normal file
31
zoo/lzh.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*$Source: /usr/home/dhesi/zoo/RCS/lzh.h,v $*/
|
||||
/*$Id: lzh.h,v 1.3 91/07/09 01:39:23 dhesi Exp $*/
|
||||
|
||||
/*
|
||||
Adapted from "ar" archiver written by Haruhiko Okumura.
|
||||
*/
|
||||
|
||||
// Modified for in-memory decompression by Natalia Portillo, 2025
|
||||
|
||||
/* io.c */
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern uint16_t bitbuf;
|
||||
#define BITBUFSIZ (CHAR_BIT * sizeof bitbuf)
|
||||
|
||||
/* encode.c and decode.c */
|
||||
|
||||
#define MATCHBIT 8 /* bits for MAXMATCH - THRESHOLD */
|
||||
#define MAXMATCH 256 /* formerly F (not more than UCHAR_MAX + 1) */
|
||||
#define THRESHOLD 3 /* choose optimal value */
|
||||
#define PERC_FLAG ((unsigned)0x8000)
|
||||
|
||||
/* huf.c */
|
||||
|
||||
#define NC (UCHAR_MAX + MAXMATCH + 2 - THRESHOLD)
|
||||
/* alphabet = {0, 1, 2, ..., NC - 1} */
|
||||
#define CBIT 9 /* $\lfloor \log_2 NC \rfloor + 1$ */
|
||||
#define CODE_BIT 16 /* codeword length */
|
||||
|
||||
extern uint16_t left[], right[];
|
||||
77
zoo/maketbl.c
Normal file
77
zoo/maketbl.c
Normal file
@@ -0,0 +1,77 @@
|
||||
/*$Source: /usr/home/dhesi/zoo/RCS/maketbl.c,v $*/
|
||||
/*$Id: maketbl.c,v 1.8 91/07/09 01:39:52 dhesi Exp $*/
|
||||
/***********************************************************
|
||||
maketbl.c -- make table for decoding
|
||||
|
||||
Adapted from "ar" archiver written by Haruhiko Okumura.
|
||||
***********************************************************/
|
||||
// Modified for in-memory decompression by Natalia Portillo, 2025
|
||||
|
||||
#include "ar.h"
|
||||
#include "lzh.h"
|
||||
|
||||
void make_table(int nchar, uint8_t *bitlen, int tablebits, uint16_t *table)
|
||||
{
|
||||
uint16_t count[17], weight[17], start[18], *p;
|
||||
uint32_t i, k, len, ch, jutbits, avail, nextcode, mask;
|
||||
|
||||
for(i = 1; i <= 16; i++) count[i] = 0;
|
||||
for(i = 0; i < nchar; i++) count[bitlen[i]]++;
|
||||
|
||||
start[1] = 0;
|
||||
for(i = 1; i <= 16; i++) start[i + 1] = start[i] + (count[i] << (16 - i));
|
||||
if(start[17] != (uint16_t)((unsigned)1 << 16)) fprintf(stderr, "Bad decode table\n");
|
||||
|
||||
jutbits = 16 - tablebits;
|
||||
for(i = 1; i <= tablebits; i++)
|
||||
{
|
||||
start[i] >>= jutbits;
|
||||
weight[i] = (unsigned)1 << (tablebits - i);
|
||||
}
|
||||
while(i <= 16)
|
||||
{
|
||||
weight[i] = (unsigned)1 << (16 - i);
|
||||
i++;
|
||||
}
|
||||
|
||||
i = start[tablebits + 1] >> jutbits;
|
||||
if(i != (uint16_t)((unsigned)1 << 16))
|
||||
{
|
||||
k = 1 << tablebits;
|
||||
while(i != k) table[i++] = 0;
|
||||
}
|
||||
|
||||
avail = nchar;
|
||||
mask = (unsigned)1 << (15 - tablebits);
|
||||
for(ch = 0; ch < nchar; ch++)
|
||||
{
|
||||
if((len = bitlen[ch]) == 0) continue;
|
||||
nextcode = start[len] + weight[len];
|
||||
if(len <= tablebits)
|
||||
{
|
||||
for(i = start[len]; i < nextcode; i++) table[i] = ch;
|
||||
}
|
||||
else
|
||||
{
|
||||
k = start[len];
|
||||
p = &table[k >> jutbits];
|
||||
i = len - tablebits;
|
||||
while(i != 0)
|
||||
{
|
||||
if(*p == 0)
|
||||
{
|
||||
right[avail] = left[avail] = 0;
|
||||
*p = avail++;
|
||||
}
|
||||
if(k & mask)
|
||||
p = &right[*p];
|
||||
else
|
||||
p = &left[*p];
|
||||
k <<= 1;
|
||||
i--;
|
||||
}
|
||||
*p = ch;
|
||||
}
|
||||
start[len] = nextcode;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user