diff --git a/CMakeLists.txt b/CMakeLists.txt index 881b378..148bdf3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/library.h b/library.h index 25da777..0d4f017 100644 --- a/library.h +++ b/library.h @@ -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(); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 19963aa..c606db6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -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") diff --git a/tests/data/alice29.lh5 b/tests/data/alice29.lh5 new file mode 100644 index 0000000..a715179 Binary files /dev/null and b/tests/data/alice29.lh5 differ diff --git a/tests/lh5.cpp b/tests/lh5.cpp new file mode 100644 index 0000000..5f9e8d8 --- /dev/null +++ b/tests/lh5.cpp @@ -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 . + */ + +#include "../zoo/lh5.h" + +#include +#include +#include + +#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); +} \ No newline at end of file diff --git a/zoo/ar.h b/zoo/ar.h new file mode 100644 index 0000000..728acb4 --- /dev/null +++ b/zoo/ar.h @@ -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 +#include + +/* 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) diff --git a/zoo/decode.c b/zoo/decode.c new file mode 100644 index 0000000..c697e7d --- /dev/null +++ b/zoo/decode.c @@ -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 +#include + +#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; + } + } + } +} diff --git a/zoo/huf.c b/zoo/huf.c new file mode 100644 index 0000000..5da36cc --- /dev/null +++ b/zoo/huf.c @@ -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 + +#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; +} diff --git a/zoo/io.c b/zoo/io.c new file mode 100644 index 0000000..acae40f --- /dev/null +++ b/zoo/io.c @@ -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 + +#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; +} diff --git a/zoo/lh5.c b/zoo/lh5.c new file mode 100644 index 0000000..f048b24 --- /dev/null +++ b/zoo/lh5.c @@ -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 . + */ + +/* 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 +#include +#include +#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; +} diff --git a/zoo/lh5.h b/zoo/lh5.h new file mode 100644 index 0000000..2f45874 --- /dev/null +++ b/zoo/lh5.h @@ -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 . + */ + +/* 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 +#include + +/* -------------------------------------------------------------------------- + * 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 diff --git a/zoo/lzd.c b/zoo/lzd.c index 0127346..b153ea5 100644 --- a/zoo/lzd.c +++ b/zoo/lzd.c @@ -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); } \ No newline at end of file diff --git a/zoo/lzh.c b/zoo/lzh.c new file mode 100644 index 0000000..2931a52 --- /dev/null +++ b/zoo/lzh.c @@ -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 +#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; +} diff --git a/zoo/lzh.h b/zoo/lzh.h new file mode 100644 index 0000000..fc4918c --- /dev/null +++ b/zoo/lzh.h @@ -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 + +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[]; \ No newline at end of file diff --git a/zoo/maketbl.c b/zoo/maketbl.c new file mode 100644 index 0000000..c34155e --- /dev/null +++ b/zoo/maketbl.c @@ -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; + } +}