From 571507743c7ae3d61063e9ed1fbb9edb52092226 Mon Sep 17 00:00:00 2001 From: Jean-Philip Desjardins Date: Thu, 29 Dec 2022 21:53:49 -0500 Subject: [PATCH] Add support for 'huff' codec. --- include/libchdr/chd.h | 1 + src/libchdr_chd.c | 80 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/include/libchdr/chd.h b/include/libchdr/chd.h index 9ff2f12..160fcb7 100644 --- a/include/libchdr/chd.h +++ b/include/libchdr/chd.h @@ -205,6 +205,7 @@ extern "C" { #define CHD_CODEC_NONE 0 #define CHD_CODEC_ZLIB CHD_MAKE_TAG('z','l','i','b') #define CHD_CODEC_LZMA CHD_MAKE_TAG('l','z','m','a') +#define CHD_CODEC_HUFFMAN CHD_MAKE_TAG('h','u','f','f') #define CHD_CODEC_FLAC CHD_MAKE_TAG('f','l','a','c') /* general codecs with CD frontend */ #define CHD_CODEC_CD_ZLIB CHD_MAKE_TAG('c','d','z','l') diff --git a/src/libchdr_chd.c b/src/libchdr_chd.c index 1330d61..734ae7a 100644 --- a/src/libchdr_chd.c +++ b/src/libchdr_chd.c @@ -227,6 +227,12 @@ struct _lzma_codec_data lzma_allocator allocator; }; +typedef struct _huff_codec_data huff_codec_data; +struct _huff_codec_data +{ + struct huffman_decoder* decoder; +}; + /* codec-private data for the CDZL codec */ typedef struct _cdzl_codec_data cdzl_codec_data; struct _cdzl_codec_data { @@ -293,8 +299,9 @@ struct _chd_file const codec_interface * codecintf[4]; /* interface to the codec */ zlib_codec_data zlib_codec_data; /* zlib codec data */ - lzma_codec_data lzma_codec_data; /* zlib codec data */ - flac_codec_data flac_codec_data; /* zlib codec data */ + lzma_codec_data lzma_codec_data; /* lzma codec data */ + huff_codec_data huff_codec_data; /* huff codec data */ + flac_codec_data flac_codec_data; /* flac codec data */ cdzl_codec_data cdzl_codec_data; /* cdzl codec data */ cdlz_codec_data cdlz_codec_data; /* cdlz codec data */ cdfl_codec_data cdfl_codec_data; /* cdfl codec data */ @@ -355,6 +362,11 @@ static chd_error lzma_codec_init(void *codec, uint32_t hunkbytes); static void lzma_codec_free(void *codec); static chd_error lzma_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); +/* huff compression codec */ +static chd_error huff_codec_init(void *codec, uint32_t hunkbytes); +static void huff_codec_free(void *codec); +static chd_error huff_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); + /* flac compression codec */ static chd_error flac_codec_init(void *codec, uint32_t hunkbytes); static void flac_codec_free(void *codec); @@ -771,6 +783,47 @@ static chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t return CHDERR_NONE; } +/*************************************************************************** + * HUFFMAN DECOMPRESSOR + *************************************************************************** + */ + +static chd_error huff_codec_init(void* codec, uint32_t hunkbytes) +{ + huff_codec_data* huff_codec = (huff_codec_data*) codec; + huff_codec->decoder = create_huffman_decoder(256, 16); + return CHDERR_NONE; +} + +static void huff_codec_free(void *codec) +{ + huff_codec_data* huff_codec = (huff_codec_data*) codec; + delete_huffman_decoder(huff_codec->decoder); +} + +static chd_error huff_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + huff_codec_data* huff_codec = (huff_codec_data*) codec; + struct bitstream* bitbuf = create_bitstream(src, complen); + + // first import the tree + enum huffman_error err = huffman_import_tree_huffman(huff_codec->decoder, bitbuf); + if (err != HUFFERR_NONE) + { + free(bitbuf); + return err; + } + + // then decode the data + for (uint32_t cur = 0; cur < destlen; cur++) + dest[cur] = huffman_decode_one(huff_codec->decoder, bitbuf); + bitstream_flush(bitbuf); + chd_error result = bitstream_overflow(bitbuf) ? CHDERR_DECOMPRESSION_ERROR : CHDERR_NONE; + + free(bitbuf); + return result; +} + /*************************************************************************** * CD FLAC DECOMPRESSOR *************************************************************************** @@ -993,6 +1046,17 @@ static const codec_interface codec_interfaces[] = NULL }, + /* V5 huffman compression */ + { + CHD_CODEC_HUFFMAN, + "Huffman", + FALSE, + huff_codec_init, + huff_codec_free, + huff_codec_decompress, + NULL + }, + /* V5 flac compression */ { CHD_CODEC_FLAC, @@ -1613,6 +1677,10 @@ CHD_EXPORT chd_error chd_open_core_file(core_file *file, int mode, chd_file *par codec = &newchd->lzma_codec_data; break; + case CHD_CODEC_HUFFMAN: + codec = &newchd->huff_codec_data; + break; + case CHD_CODEC_FLAC: codec = &newchd->flac_codec_data; break; @@ -1762,6 +1830,10 @@ CHD_EXPORT void chd_close(chd_file *chd) codec = &chd->lzma_codec_data; break; + case CHD_CODEC_HUFFMAN: + codec = &chd->huff_codec_data; + break; + case CHD_CODEC_FLAC: codec = &chd->flac_codec_data; break; @@ -2488,6 +2560,10 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des codec = &chd->lzma_codec_data; break; + case CHD_CODEC_HUFFMAN: + codec = &chd->huff_codec_data; + break; + case CHD_CODEC_FLAC: codec = &chd->flac_codec_data; break;