From 4231c2c83f2b5331e3e38b10a308ee3752315f9c Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Sat, 26 Sep 2020 17:19:07 -0400 Subject: codecs: Add support for the 'VTX' ZX Spectrum chiptunes format. This codec requires floating point. Original author: Peter Sovietov Ported to Rockbox: Roman Skylarov Further integration and bugfixes: Solomon Peachy Change-Id: I781ecd3592dfcdbbc694063334350342534f1d6c --- lib/rbcodec/codecs/libayumi/lzh.c | 420 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 420 insertions(+) create mode 100644 lib/rbcodec/codecs/libayumi/lzh.c (limited to 'lib/rbcodec/codecs/libayumi/lzh.c') diff --git a/lib/rbcodec/codecs/libayumi/lzh.c b/lib/rbcodec/codecs/libayumi/lzh.c new file mode 100644 index 0000000000..786d3bbafe --- /dev/null +++ b/lib/rbcodec/codecs/libayumi/lzh.c @@ -0,0 +1,420 @@ +#include "lzh.h" + +#include + +#define BUFSIZE (1024 * 4) + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; +typedef unsigned long ulong; + +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif + +#ifndef UCHAR_MAX +#define UCHAR_MAX 255 +#endif + +typedef ushort BITBUFTYPE; + +#define BITBUFSIZ (CHAR_BIT * sizeof(BITBUFTYPE)) +#define DICBIT 13 /* 12(-lh4-) or 13(-lh5-) */ +#define DICSIZ (1U << DICBIT) +#define MAXMATCH 256 /* formerly F (not more than UCHAR_MAX + 1) */ +#define THRESHOLD 3 /* choose optimal value */ +#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 */ + +#define MAX_HASH_VAL (3 * DICSIZ + (DICSIZ / 512 + 1) * UCHAR_MAX) + +#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 + +uchar *m_pSrc; +int m_srcSize; +uchar *m_pDst; +int m_dstSize; + +int DataIn(void *pBuffer, int nBytes); +int DataOut(void *pOut, int nBytes); + +void fillbuf(int n); +ushort getbits(int n); +void init_getbits(void); +int make_table(int nchar, uchar *bitlen, int tablebits, ushort *table); +void read_pt_len(int nn, int nbit, int i_special); +void read_c_len(void); +ushort decode_c(void); +ushort decode_p(void); +void huf_decode_start(void); +void decode_start(void); +void decode(uint count, uchar buffer[]); + +int fillbufsize; +uchar buf[BUFSIZE]; +uchar outbuf[DICSIZ]; +ushort left[2 * NC - 1]; +ushort right[2 * NC - 1]; +BITBUFTYPE bitbuf; +uint subbitbuf; +int bitcount; +int decode_j; /* remaining bytes to copy */ +uchar c_len[NC]; +uchar pt_len[NPT]; +uint blocksize; +ushort c_table[4096]; +ushort pt_table[256]; +int with_error; + +uint fillbuf_i; /* NOTE: these ones are not initialized at constructor time but inside the fillbuf and decode func. */ +uint decode_i; + +/* Additions */ + +int DataIn(void *pBuffer, int nBytes) +{ + const int np = (nBytes <= m_srcSize) ? nBytes : m_srcSize; + if (np > 0) { + memcpy(pBuffer, m_pSrc, np); + m_pSrc += np; + m_srcSize -= np; + } + return np; +} + +int DataOut(void *pBuffer, int nBytes) +{ + const int np = (nBytes <= m_dstSize) ? nBytes : m_dstSize; + if (np > 0) { + memcpy(m_pDst, pBuffer, np); + m_pDst += np; + m_dstSize -= np; + } + return np; +} + +/* io.c */ + +/* Shift bitbuf n bits left, read n bits */ +void fillbuf(int n) +{ + bitbuf = (bitbuf << n) & 0xffff; + while (n > bitcount) { + bitbuf |= subbitbuf << (n -= bitcount); + if (fillbufsize == 0) { + fillbuf_i = 0; + fillbufsize = DataIn(buf, BUFSIZE - 32); + } + if (fillbufsize > 0) + fillbufsize--, subbitbuf = buf[fillbuf_i++]; + else + subbitbuf = 0; + bitcount = CHAR_BIT; + } + bitbuf |= subbitbuf >> (bitcount -= n); +} + +ushort getbits(int n) +{ + ushort x; + x = bitbuf >> (BITBUFSIZ - n); + fillbuf(n); + return x; +} + +void init_getbits(void) +{ + bitbuf = 0; + subbitbuf = 0; + bitcount = 0; + fillbuf(BITBUFSIZ); +} + +/* maketbl.c */ + +int make_table(int nchar, uchar * bitlen, int tablebits, ushort * table) +{ + ushort count[17], weight[17], start[18], *p; + uint jutbits, avail, mask; + int i, ch, len, nextcode; + + 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] != (ushort) (1U << 16)) + return (1); /* error: bad table */ + + jutbits = 16 - tablebits; + for (i = 1; i <= tablebits; i++) { + start[i] >>= jutbits; + weight[i] = 1U << (tablebits - i); + } + while (i <= 16) { + weight[i] = 1U << (16 - i); + i++; + } + + i = start[tablebits + 1] >> jutbits; + if (i != (ushort) (1U << 16)) { + int k = 1U << tablebits; + while (i != k) + table[i++] = 0; + } + + avail = nchar; + mask = 1U << (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 { + uint 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; + } + return (0); +} + +/* huf.c */ + +void read_pt_len(int nn, int nbit, int i_special) +{ + int i, n; + short c; + ushort 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 = 1U << (BITBUFSIZ - 1 - 3); + while (mask & bitbuf) { + mask >>= 1; + c++; + } + } + fillbuf((c < 7) ? 3 : c - 3); + pt_len[i++] = (unsigned char) (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); + } +} + +void read_c_len(void) +{ + short i, c, n; + ushort 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 = 1U << (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); + } +} + +ushort decode_c(void) +{ + ushort j, mask; + + if (blocksize == 0) { + blocksize = getbits(16); + 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 = 1U << (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; +} + +ushort decode_p(void) +{ + ushort j, mask; + + j = pt_table[bitbuf >> (BITBUFSIZ - 8)]; + if (j >= NP) { + mask = 1U << (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 = (1U << (j - 1)) + getbits(j - 1); + return j; +} + +void huf_decode_start(void) +{ + init_getbits(); + blocksize = 0; +} + +/* decode.c */ + +void decode_start(void) +{ + fillbufsize = 0; + huf_decode_start(); + decode_j = 0; +} + +/* + * 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. + */ +void decode(uint count, uchar buffer[]) +{ + uint r, c; + + r = 0; + while (--decode_j >= 0) { + buffer[r] = buffer[decode_i]; + decode_i = (decode_i + 1) & (DICSIZ - 1); + if (++r == count) + return; + } + for (;;) { + c = decode_c(); + if (c <= UCHAR_MAX) { + buffer[r] = c; + if (++r == count) + return; + } else { + decode_j = c - (UCHAR_MAX + 1 - THRESHOLD); + decode_i = (r - decode_p() - 1) & (DICSIZ - 1); + while (--decode_j >= 0) { + buffer[r] = buffer[decode_i]; + decode_i = (decode_i + 1) & (DICSIZ - 1); + if (++r == count) + return; + } + } + } +} + +int LzUnpack(void *pSrc, int srcSize, void *pDst, int dstSize) +{ + with_error = 0; + + m_pSrc = (uchar *) pSrc; + m_srcSize = srcSize; + m_pDst = (uchar *) pDst; + m_dstSize = dstSize; + + decode_start(); + + unsigned int origsize = dstSize; + while (origsize != 0) { + int n = (uint) ((origsize > DICSIZ) ? DICSIZ : origsize); + decode(n, outbuf); + if (with_error) + break; + + DataOut(outbuf, n); + origsize -= n; + if (with_error) + break; + } + + return (with_error); +} -- cgit v1.2.3