Make libchdr C89-compatible

This commit is contained in:
twinaphex 2017-09-05 23:36:24 +02:00
parent 60ca366941
commit c386f4487b
5 changed files with 454 additions and 369 deletions

View File

@ -1,5 +1,6 @@
// license:BSD-3-Clause /* license:BSD-3-Clause
// copyright-holders:Aaron Giles * copyright-holders:Aaron Giles
*/
/*************************************************************************** /***************************************************************************
bitstream.c bitstream.c
@ -11,15 +12,17 @@
#include "bitstream.h" #include "bitstream.h"
#include <stdlib.h> #include <stdlib.h>
//************************************************************************** /***************************************************************************
// INLINE FUNCTIONS * INLINE FUNCTIONS
//************************************************************************** ***************************************************************************
*/
int bitstream_overflow(struct bitstream* bitstream) { return ((bitstream->doffset - bitstream->bits / 8) > bitstream->dlength); } int bitstream_overflow(struct bitstream* bitstream) { return ((bitstream->doffset - bitstream->bits / 8) > bitstream->dlength); }
//------------------------------------------------- /*-------------------------------------------------
// create_bitstream - constructor * create_bitstream - constructor
//------------------------------------------------- *-------------------------------------------------
*/
struct bitstream* create_bitstream(const void *src, uint32_t srclength) struct bitstream* create_bitstream(const void *src, uint32_t srclength)
{ {
@ -33,17 +36,18 @@ struct bitstream* create_bitstream(const void *src, uint32_t srclength)
} }
//----------------------------------------------------- /*-----------------------------------------------------
// bitstream_peek - fetch the requested number of bits * bitstream_peek - fetch the requested number of bits
// but don't advance the input pointer * but don't advance the input pointer
//----------------------------------------------------- *-----------------------------------------------------
*/
uint32_t bitstream_peek(struct bitstream* bitstream, int numbits) uint32_t bitstream_peek(struct bitstream* bitstream, int numbits)
{ {
if (numbits == 0) if (numbits == 0)
return 0; return 0;
// fetch data if we need more /* fetch data if we need more */
if (numbits > bitstream->bits) if (numbits > bitstream->bits)
{ {
while (bitstream->bits <= 24) while (bitstream->bits <= 24)
@ -55,15 +59,16 @@ uint32_t bitstream_peek(struct bitstream* bitstream, int numbits)
} }
} }
// return the data /* return the data */
return bitstream->buffer >> (32 - numbits); return bitstream->buffer >> (32 - numbits);
} }
//----------------------------------------------------- /*-----------------------------------------------------
// bitstream_remove - advance the input pointer by the * bitstream_remove - advance the input pointer by the
// specified number of bits * specified number of bits
//----------------------------------------------------- *-----------------------------------------------------
*/
void bitstream_remove(struct bitstream* bitstream, int numbits) void bitstream_remove(struct bitstream* bitstream, int numbits)
{ {
@ -72,9 +77,10 @@ void bitstream_remove(struct bitstream* bitstream, int numbits)
} }
//----------------------------------------------------- /*-----------------------------------------------------
// bitstream_read - fetch the requested number of bits * bitstream_read - fetch the requested number of bits
//----------------------------------------------------- *-----------------------------------------------------
*/
uint32_t bitstream_read(struct bitstream* bitstream, int numbits) uint32_t bitstream_read(struct bitstream* bitstream, int numbits)
{ {
@ -84,9 +90,10 @@ uint32_t bitstream_read(struct bitstream* bitstream, int numbits)
} }
//------------------------------------------------- /*-------------------------------------------------
// read_offset - return the current read offset * read_offset - return the current read offset
//------------------------------------------------- *-------------------------------------------------
*/
uint32_t bitstream_read_offset(struct bitstream* bitstream) uint32_t bitstream_read_offset(struct bitstream* bitstream)
{ {

View File

@ -1,6 +1,6 @@
// license:BSD-3-Clause /* license:BSD-3-Clause
// copyright-holders:Aaron Giles * copyright-holders:Aaron Giles
/*************************************************************************** ***************************************************************************
bitstream.h bitstream.h
@ -15,18 +15,19 @@
#include <stdint.h> #include <stdint.h>
//************************************************************************** /***************************************************************************
// TYPE DEFINITIONS * TYPE DEFINITIONS
//************************************************************************** ***************************************************************************
*/
// helper class for reading from a bit buffer /* helper class for reading from a bit buffer */
struct bitstream struct bitstream
{ {
uint32_t buffer; // current bit accumulator uint32_t buffer; /* current bit accumulator */
int bits; // number of bits in the accumulator int bits; /* number of bits in the accumulator */
const uint8_t * read; // read pointer const uint8_t * read; /* read pointer */
uint32_t doffset; // byte offset within the data uint32_t doffset; /* byte offset within the data */
uint32_t dlength; // length of the data uint32_t dlength; /* length of the data */
}; };
struct bitstream* create_bitstream(const void *src, uint32_t srclength); struct bitstream* create_bitstream(const void *src, uint32_t srclength);

View File

@ -90,51 +90,51 @@
static const uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 }; static const uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 };
#endif #endif
// V3-V4 entry types /* V3-V4 entry types */
enum enum
{ {
V34_MAP_ENTRY_TYPE_INVALID = 0, // invalid type V34_MAP_ENTRY_TYPE_INVALID = 0, /* invalid type */
V34_MAP_ENTRY_TYPE_COMPRESSED = 1, // standard compression V34_MAP_ENTRY_TYPE_COMPRESSED = 1, /* standard compression */
V34_MAP_ENTRY_TYPE_UNCOMPRESSED = 2, // uncompressed data V34_MAP_ENTRY_TYPE_UNCOMPRESSED = 2, /* uncompressed data */
V34_MAP_ENTRY_TYPE_MINI = 3, // mini: use offset as raw data V34_MAP_ENTRY_TYPE_MINI = 3, /* mini: use offset as raw data */
V34_MAP_ENTRY_TYPE_SELF_HUNK = 4, // same as another hunk in this file V34_MAP_ENTRY_TYPE_SELF_HUNK = 4, /* same as another hunk in this file */
V34_MAP_ENTRY_TYPE_PARENT_HUNK = 5, // same as a hunk in the parent file V34_MAP_ENTRY_TYPE_PARENT_HUNK = 5, /* same as a hunk in the parent file */
V34_MAP_ENTRY_TYPE_2ND_COMPRESSED = 6 // compressed with secondary algorithm (usually FLAC CDDA) V34_MAP_ENTRY_TYPE_2ND_COMPRESSED = 6 /* compressed with secondary algorithm (usually FLAC CDDA) */
}; };
// V5 compression types /* V5 compression types */
enum enum
{ {
///< codec #0 /* codec #0
// these types are live when running * these types are live when running */
COMPRESSION_TYPE_0 = 0, COMPRESSION_TYPE_0 = 0,
///< codec #1 /* codec #1 */
COMPRESSION_TYPE_1 = 1, COMPRESSION_TYPE_1 = 1,
///< codec #2 /* codec #2 */
COMPRESSION_TYPE_2 = 2, COMPRESSION_TYPE_2 = 2,
///< codec #3 /* codec #3 */
COMPRESSION_TYPE_3 = 3, COMPRESSION_TYPE_3 = 3,
///< no compression; implicit length = hunkbytes /* no compression; implicit length = hunkbytes */
COMPRESSION_NONE = 4, COMPRESSION_NONE = 4,
///< same as another block in this chd /* same as another block in this chd */
COMPRESSION_SELF = 5, COMPRESSION_SELF = 5,
///< same as a hunk's worth of units in the parent chd /* same as a hunk's worth of units in the parent chd */
COMPRESSION_PARENT = 6, COMPRESSION_PARENT = 6,
///< start of small RLE run (4-bit length) /* start of small RLE run (4-bit length)
// these additional pseudo-types are used for compressed encodings: * these additional pseudo-types are used for compressed encodings: */
COMPRESSION_RLE_SMALL, COMPRESSION_RLE_SMALL,
///< start of large RLE run (8-bit length) /* start of large RLE run (8-bit length) */
COMPRESSION_RLE_LARGE, COMPRESSION_RLE_LARGE,
///< same as the last COMPRESSION_SELF block /* same as the last COMPRESSION_SELF block */
COMPRESSION_SELF_0, COMPRESSION_SELF_0,
///< same as the last COMPRESSION_SELF block + 1 /* same as the last COMPRESSION_SELF block + 1 */
COMPRESSION_SELF_1, COMPRESSION_SELF_1,
///< same block in the parent /* same block in the parent */
COMPRESSION_PARENT_SELF, COMPRESSION_PARENT_SELF,
///< same as the last COMPRESSION_PARENT block /* same as the last COMPRESSION_PARENT block */
COMPRESSION_PARENT_0, COMPRESSION_PARENT_0,
///< same as the last COMPRESSION_PARENT block + 1 /* same as the last COMPRESSION_PARENT block + 1 */
COMPRESSION_PARENT_1 COMPRESSION_PARENT_1
}; };
@ -225,7 +225,7 @@ struct _lzma_codec_data
/* codec-private data for the CDZL codec */ /* codec-private data for the CDZL codec */
typedef struct _cdzl_codec_data cdzl_codec_data; typedef struct _cdzl_codec_data cdzl_codec_data;
struct _cdzl_codec_data { struct _cdzl_codec_data {
// internal state /* internal state */
zlib_codec_data base_decompressor; zlib_codec_data base_decompressor;
#ifdef WANT_SUBCODE #ifdef WANT_SUBCODE
zlib_codec_data subcode_decompressor; zlib_codec_data subcode_decompressor;
@ -236,7 +236,7 @@ struct _cdzl_codec_data {
/* codec-private data for the CDLZ codec */ /* codec-private data for the CDLZ codec */
typedef struct _cdlz_codec_data cdlz_codec_data; typedef struct _cdlz_codec_data cdlz_codec_data;
struct _cdlz_codec_data { struct _cdlz_codec_data {
// internal state /* internal state */
lzma_codec_data base_decompressor; lzma_codec_data base_decompressor;
#ifdef WANT_SUBCODE #ifdef WANT_SUBCODE
zlib_codec_data subcode_decompressor; zlib_codec_data subcode_decompressor;
@ -247,7 +247,7 @@ struct _cdlz_codec_data {
/* codec-private data for the CDFL codec */ /* codec-private data for the CDFL codec */
typedef struct _cdfl_codec_data cdfl_codec_data; typedef struct _cdfl_codec_data cdfl_codec_data;
struct _cdfl_codec_data { struct _cdfl_codec_data {
// internal state /* internal state */
int swap_endian; int swap_endian;
flac_decoder decoder; flac_decoder decoder;
#ifdef WANT_SUBCODE #ifdef WANT_SUBCODE
@ -349,36 +349,39 @@ static chd_error cdfl_codec_init(void* codec, uint32_t hunkbytes);
static void cdfl_codec_free(void* codec); static void cdfl_codec_free(void* codec);
static chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); static chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
//************************************************************************** /***************************************************************************
// LZMA ALLOCATOR HELPER * LZMA ALLOCATOR HELPER
//************************************************************************** ***************************************************************************
*/
void *lzma_fast_alloc(void *p, size_t size); void *lzma_fast_alloc(void *p, size_t size);
void lzma_fast_free(void *p, void *address); void lzma_fast_free(void *p, void *address);
//------------------------------------------------- /*-------------------------------------------------
// lzma_allocator_init * lzma_allocator_init
//------------------------------------------------- *-------------------------------------------------
*/
void lzma_allocator_init(void* p) void lzma_allocator_init(void* p)
{ {
lzma_allocator *codec = (lzma_allocator *)(p); lzma_allocator *codec = (lzma_allocator *)(p);
// reset pointer list /* reset pointer list */
memset(codec->allocptr, 0, sizeof(codec->allocptr)); memset(codec->allocptr, 0, sizeof(codec->allocptr));
codec->Alloc = lzma_fast_alloc; codec->Alloc = lzma_fast_alloc;
codec->Free = lzma_fast_free; codec->Free = lzma_fast_free;
} }
//------------------------------------------------- /*-------------------------------------------------
// lzma_allocator_free * lzma_allocator_free
//------------------------------------------------- *-------------------------------------------------
*/
void lzma_allocator_free(void* p ) void lzma_allocator_free(void* p )
{ {
lzma_allocator *codec = (lzma_allocator *)(p); lzma_allocator *codec = (lzma_allocator *)(p);
// free our memory /* free our memory */
int i; int i;
for (i = 0 ; i < MAX_LZMA_ALLOCS ; i++) for (i = 0 ; i < MAX_LZMA_ALLOCS ; i++)
{ {
@ -395,6 +398,7 @@ void lzma_allocator_free(void* p )
void *lzma_fast_alloc(void *p, size_t size) void *lzma_fast_alloc(void *p, size_t size)
{ {
int scan; int scan;
uint32_t *addr;
lzma_allocator *codec = (lzma_allocator *)(p); lzma_allocator *codec = (lzma_allocator *)(p);
// compute the size, rounding to the nearest 1k // compute the size, rounding to the nearest 1k
@ -413,7 +417,7 @@ void *lzma_fast_alloc(void *p, size_t size)
} }
// alloc a new one and put it into the list // alloc a new one and put it into the list
uint32_t *addr = (uint32_t *)malloc(sizeof(uint8_t) * (size + sizeof(uint32_t))); addr = (uint32_t *)malloc(sizeof(uint8_t) * (size + sizeof(uint32_t)));
if (addr==NULL) if (addr==NULL)
return NULL; return NULL;
for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++) for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
@ -438,57 +442,65 @@ void *lzma_fast_alloc(void *p, size_t size)
void lzma_fast_free(void *p, void *address) void lzma_fast_free(void *p, void *address)
{ {
int scan;
uint32_t *ptr;
lzma_allocator *codec;
if (address == NULL) if (address == NULL)
return; return;
int scan; codec = (lzma_allocator *)(p);
lzma_allocator *codec = (lzma_allocator *)(p);
// find the hunk /* find the hunk */
uint32_t *ptr = (uint32_t *)(address) - 1; ptr = (uint32_t *)(address) - 1;
for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++) for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
{ {
if (ptr == codec->allocptr[scan]) if (ptr == codec->allocptr[scan])
{ {
// clear the low bit of the size to allow matches /* clear the low bit of the size to allow matches */
*ptr &= ~1; *ptr &= ~1;
return; return;
} }
} }
} }
//************************************************************************** /***************************************************************************
// LZMA DECOMPRESSOR * LZMA DECOMPRESSOR
//************************************************************************** ***************************************************************************
*/
//------------------------------------------------- /*-------------------------------------------------
// lzma_codec_init - constructor * lzma_codec_init - constructor
//------------------------------------------------- *-------------------------------------------------
*/
chd_error lzma_codec_init(void* codec, uint32_t hunkbytes) chd_error lzma_codec_init(void* codec, uint32_t hunkbytes)
{ {
CLzmaEncProps encoder_props;
CLzmaEncHandle enc;
Byte decoder_props[LZMA_PROPS_SIZE];
lzma_allocator* alloc;
SizeT props_size;
lzma_codec_data* lzma_codec = (lzma_codec_data*) codec; lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;
// construct the decoder /* construct the decoder */
LzmaDec_Construct(&lzma_codec->decoder); LzmaDec_Construct(&lzma_codec->decoder);
// FIXME: this code is written in a way that makes it impossible to safely upgrade the LZMA SDK /* FIXME: this code is written in a way that makes it impossible to safely upgrade the LZMA SDK
// This code assumes that the current version of the encoder imposes the same requirements on the * This code assumes that the current version of the encoder imposes the same requirements on the
// decoder as the encoder used to produce the file. This is not necessarily true. The format * decoder as the encoder used to produce the file. This is not necessarily true. The format
// needs to be changed so the encoder properties are written to the file. * needs to be changed so the encoder properties are written to the file.
// configure the properties like the compressor did * configure the properties like the compressor did */
CLzmaEncProps encoder_props;
LzmaEncProps_Init(&encoder_props); LzmaEncProps_Init(&encoder_props);
encoder_props.level = 9; encoder_props.level = 9;
encoder_props.reduceSize = hunkbytes; encoder_props.reduceSize = hunkbytes;
LzmaEncProps_Normalize(&encoder_props); LzmaEncProps_Normalize(&encoder_props);
// convert to decoder properties /* convert to decoder properties */
lzma_allocator* alloc = &lzma_codec->allocator; alloc = &lzma_codec->allocator;
lzma_allocator_init(alloc); lzma_allocator_init(alloc);
CLzmaEncHandle enc = LzmaEnc_Create((ISzAlloc*)alloc); enc = LzmaEnc_Create((ISzAlloc*)alloc);
if (!enc) if (!enc)
return CHDERR_DECOMPRESSION_ERROR; return CHDERR_DECOMPRESSION_ERROR;
if (LzmaEnc_SetProps(enc, &encoder_props) != SZ_OK) if (LzmaEnc_SetProps(enc, &encoder_props) != SZ_OK)
@ -496,8 +508,7 @@ chd_error lzma_codec_init(void* codec, uint32_t hunkbytes)
LzmaEnc_Destroy(enc, (ISzAlloc*)&alloc, (ISzAlloc*)&alloc); LzmaEnc_Destroy(enc, (ISzAlloc*)&alloc, (ISzAlloc*)&alloc);
return CHDERR_DECOMPRESSION_ERROR; return CHDERR_DECOMPRESSION_ERROR;
} }
Byte decoder_props[LZMA_PROPS_SIZE]; props_size = sizeof(decoder_props);
SizeT props_size = sizeof(decoder_props);
if (LzmaEnc_WriteProperties(enc, decoder_props, &props_size) != SZ_OK) if (LzmaEnc_WriteProperties(enc, decoder_props, &props_size) != SZ_OK)
{ {
LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc); LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc);
@ -505,11 +516,11 @@ chd_error lzma_codec_init(void* codec, uint32_t hunkbytes)
} }
LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc); LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc);
// do memory allocations /* do memory allocations */
if (LzmaDec_Allocate(&lzma_codec->decoder, decoder_props, LZMA_PROPS_SIZE, (ISzAlloc*)alloc) != SZ_OK) if (LzmaDec_Allocate(&lzma_codec->decoder, decoder_props, LZMA_PROPS_SIZE, (ISzAlloc*)alloc) != SZ_OK)
return CHDERR_DECOMPRESSION_ERROR; return CHDERR_DECOMPRESSION_ERROR;
// Okay /* Okay */
return CHDERR_NONE; return CHDERR_NONE;
} }
@ -536,15 +547,17 @@ void lzma_codec_free(void* codec)
chd_error lzma_codec_decompress(void* codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) chd_error lzma_codec_decompress(void* codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
{ {
ELzmaStatus status;
SRes res;
SizeT consumedlen, decodedlen;
// initialize // initialize
lzma_codec_data* lzma_codec = (lzma_codec_data*) codec; lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;
LzmaDec_Init(&lzma_codec->decoder); LzmaDec_Init(&lzma_codec->decoder);
// decode // decode
SizeT consumedlen = complen; consumedlen = complen;
SizeT decodedlen = destlen; decodedlen = destlen;
ELzmaStatus status; res = LzmaDec_DecodeToBuf(&lzma_codec->decoder, dest, &decodedlen, src, &consumedlen, LZMA_FINISH_END, &status);
SRes res = LzmaDec_DecodeToBuf(&lzma_codec->decoder, dest, &decodedlen, src, &consumedlen, LZMA_FINISH_END, &status);
if ((res != SZ_OK && res != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) || consumedlen != complen || decodedlen != destlen) if ((res != SZ_OK && res != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) || consumedlen != complen || decodedlen != destlen)
return CHDERR_DECOMPRESSION_ERROR; return CHDERR_DECOMPRESSION_ERROR;
return CHDERR_NONE; return CHDERR_NONE;
@ -735,9 +748,13 @@ static uint32_t cdfl_codec_blocksize(uint32_t bytes)
chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes) chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes)
{ {
#ifdef WANT_SUBCODE
chd_error ret;
#endif
uint16_t native_endian = 0;
cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;
// make sure the CHD's hunk size is an even multiple of the frame size /* make sure the CHD's hunk size is an even multiple of the frame size */
if (hunkbytes % CD_FRAME_SIZE != 0) if (hunkbytes % CD_FRAME_SIZE != 0)
return CHDERR_CODEC_ERROR; return CHDERR_CODEC_ERROR;
@ -745,19 +762,18 @@ chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes)
if (cdfl->buffer == NULL) if (cdfl->buffer == NULL)
return CHDERR_OUT_OF_MEMORY; return CHDERR_OUT_OF_MEMORY;
// determine whether we want native or swapped samples /* determine whether we want native or swapped samples */
uint16_t native_endian = 0;
*(uint8_t *)(&native_endian) = 1; *(uint8_t *)(&native_endian) = 1;
cdfl->swap_endian = (native_endian & 1); cdfl->swap_endian = (native_endian & 1);
#ifdef WANT_SUBCODE #ifdef WANT_SUBCODE
// init zlib inflater /* init zlib inflater */
chd_error ret = zlib_codec_init(&cdfl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); ret = zlib_codec_init(&cdfl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
if (ret != CHDERR_NONE) if (ret != CHDERR_NONE)
return ret; return ret;
#endif #endif
// flac decoder init /* flac decoder init */
flac_decoder_init(&cdfl->decoder); flac_decoder_init(&cdfl->decoder);
if (cdfl->decoder.decoder == NULL) if (cdfl->decoder.decoder == NULL)
return CHDERR_OUT_OF_MEMORY; return CHDERR_OUT_OF_MEMORY;
@ -779,27 +795,33 @@ void cdfl_codec_free(void *codec)
chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
{ {
uint32_t framenum; uint32_t framenum;
uint8_t *buffer;
#ifdef WANT_SUBCODE
uint32_t offset;
chd_error ret;
#endif
cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;
// reset and decode // reset and decode
uint32_t frames = destlen / CD_FRAME_SIZE; uint32_t frames = destlen / CD_FRAME_SIZE;
if (!flac_decoder_reset(&cdfl->decoder, 44100, 2, cdfl_codec_blocksize(frames * CD_MAX_SECTOR_DATA), src, complen)) if (!flac_decoder_reset(&cdfl->decoder, 44100, 2, cdfl_codec_blocksize(frames * CD_MAX_SECTOR_DATA), src, complen))
return CHDERR_DECOMPRESSION_ERROR; return CHDERR_DECOMPRESSION_ERROR;
uint8_t *buffer = &cdfl->buffer[0]; buffer = &cdfl->buffer[0];
if (!flac_decoder_decode_interleaved(&cdfl->decoder, (int16_t *)(buffer), frames * CD_MAX_SECTOR_DATA/4, cdfl->swap_endian)) if (!flac_decoder_decode_interleaved(&cdfl->decoder, (int16_t *)(buffer), frames * CD_MAX_SECTOR_DATA/4, cdfl->swap_endian))
return CHDERR_DECOMPRESSION_ERROR; return CHDERR_DECOMPRESSION_ERROR;
#ifdef WANT_SUBCODE #ifdef WANT_SUBCODE
// inflate the subcode data /* inflate the subcode data */
uint32_t offset = flac_decoder_finish(&cdfl->decoder); offset = flac_decoder_finish(&cdfl->decoder);
chd_error ret = zlib_codec_decompress(&cdfl->subcode_decompressor, src + offset, complen - offset, &cdfl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA); ret = zlib_codec_decompress(&cdfl->subcode_decompressor, src + offset, complen - offset, &cdfl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);
if (ret != CHDERR_NONE) if (ret != CHDERR_NONE)
return ret; return ret;
#else #else
flac_decoder_finish(&cdfl->decoder); flac_decoder_finish(&cdfl->decoder);
#endif #endif
// reassemble the data /* reassemble the data */
for (framenum = 0; framenum < frames; framenum++) for (framenum = 0; framenum < frames; framenum++)
{ {
memcpy(&dest[framenum * CD_FRAME_SIZE], &cdfl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); memcpy(&dest[framenum * CD_FRAME_SIZE], &cdfl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
@ -899,7 +921,7 @@ static const codec_interface codec_interfaces[] =
the data stream in bigendian order the data stream in bigendian order
-------------------------------------------------*/ -------------------------------------------------*/
static inline UINT64 get_bigendian_uint64(const UINT8 *base) INLINE UINT64 get_bigendian_uint64(const UINT8 *base)
{ {
return ((UINT64)base[0] << 56) | ((UINT64)base[1] << 48) | ((UINT64)base[2] << 40) | ((UINT64)base[3] << 32) | return ((UINT64)base[0] << 56) | ((UINT64)base[1] << 48) | ((UINT64)base[2] << 40) | ((UINT64)base[3] << 32) |
((UINT64)base[4] << 24) | ((UINT64)base[5] << 16) | ((UINT64)base[6] << 8) | (UINT64)base[7]; ((UINT64)base[4] << 24) | ((UINT64)base[5] << 16) | ((UINT64)base[6] << 8) | (UINT64)base[7];
@ -911,7 +933,7 @@ static inline UINT64 get_bigendian_uint64(const UINT8 *base)
the data stream in bigendian order the data stream in bigendian order
-------------------------------------------------*/ -------------------------------------------------*/
static inline void put_bigendian_uint64(UINT8 *base, UINT64 value) INLINE void put_bigendian_uint64(UINT8 *base, UINT64 value)
{ {
base[0] = value >> 56; base[0] = value >> 56;
base[1] = value >> 48; base[1] = value >> 48;
@ -928,7 +950,7 @@ static inline void put_bigendian_uint64(UINT8 *base, UINT64 value)
the data stream in bigendian order the data stream in bigendian order
-------------------------------------------------*/ -------------------------------------------------*/
static inline UINT64 get_bigendian_uint48(const UINT8 *base) INLINE UINT64 get_bigendian_uint48(const UINT8 *base)
{ {
return ((UINT64)base[0] << 40) | ((UINT64)base[1] << 32) | return ((UINT64)base[0] << 40) | ((UINT64)base[1] << 32) |
((UINT64)base[2] << 24) | ((UINT64)base[3] << 16) | ((UINT64)base[4] << 8) | (UINT64)base[5]; ((UINT64)base[2] << 24) | ((UINT64)base[3] << 16) | ((UINT64)base[4] << 8) | (UINT64)base[5];
@ -939,7 +961,7 @@ static inline UINT64 get_bigendian_uint48(const UINT8 *base)
the data stream in bigendian order the data stream in bigendian order
-------------------------------------------------*/ -------------------------------------------------*/
static inline void put_bigendian_uint48(UINT8 *base, UINT64 value) INLINE void put_bigendian_uint48(UINT8 *base, UINT64 value)
{ {
value &= 0xffffffffffff; value &= 0xffffffffffff;
base[0] = value >> 40; base[0] = value >> 40;
@ -954,7 +976,7 @@ static inline void put_bigendian_uint48(UINT8 *base, UINT64 value)
the data stream in bigendian order the data stream in bigendian order
-------------------------------------------------*/ -------------------------------------------------*/
static inline UINT32 get_bigendian_uint32(const UINT8 *base) INLINE UINT32 get_bigendian_uint32(const UINT8 *base)
{ {
return (base[0] << 24) | (base[1] << 16) | (base[2] << 8) | base[3]; return (base[0] << 24) | (base[1] << 16) | (base[2] << 8) | base[3];
} }
@ -965,7 +987,7 @@ static inline UINT32 get_bigendian_uint32(const UINT8 *base)
the data stream in bigendian order the data stream in bigendian order
-------------------------------------------------*/ -------------------------------------------------*/
static inline void put_bigendian_uint24(UINT8 *base, UINT32 value) INLINE void put_bigendian_uint24(UINT8 *base, UINT32 value)
{ {
value &= 0xffffff; value &= 0xffffff;
base[0] = value >> 16; base[0] = value >> 16;
@ -979,7 +1001,7 @@ static inline void put_bigendian_uint24(UINT8 *base, UINT32 value)
the data stream in bigendian order the data stream in bigendian order
-------------------------------------------------*/ -------------------------------------------------*/
static inline void put_bigendian_uint32(UINT8 *base, UINT32 value) INLINE void put_bigendian_uint32(UINT8 *base, UINT32 value)
{ {
value &= 0xffffff; value &= 0xffffff;
base[0] = value >> 16; base[0] = value >> 16;
@ -992,7 +1014,7 @@ static inline void put_bigendian_uint32(UINT8 *base, UINT32 value)
the data stream in bigendian order the data stream in bigendian order
-------------------------------------------------*/ -------------------------------------------------*/
static inline UINT32 get_bigendian_uint24(const UINT8 *base) INLINE UINT32 get_bigendian_uint24(const UINT8 *base)
{ {
return (base[0] << 16) | (base[1] << 8) | base[2]; return (base[0] << 16) | (base[1] << 8) | base[2];
} }
@ -1002,7 +1024,7 @@ static inline UINT32 get_bigendian_uint24(const UINT8 *base)
the data stream in bigendian order the data stream in bigendian order
-------------------------------------------------*/ -------------------------------------------------*/
static inline UINT16 get_bigendian_uint16(const UINT8 *base) INLINE UINT16 get_bigendian_uint16(const UINT8 *base)
{ {
return (base[0] << 8) | base[1]; return (base[0] << 8) | base[1];
} }
@ -1013,7 +1035,7 @@ static inline UINT16 get_bigendian_uint16(const UINT8 *base)
the data stream in bigendian order the data stream in bigendian order
-------------------------------------------------*/ -------------------------------------------------*/
static inline void put_bigendian_uint16(UINT8 *base, UINT16 value) INLINE void put_bigendian_uint16(UINT8 *base, UINT16 value)
{ {
base[0] = value >> 8; base[0] = value >> 8;
base[1] = value; base[1] = value;
@ -1025,7 +1047,7 @@ static inline void put_bigendian_uint16(UINT8 *base, UINT16 value)
entry from the datastream entry from the datastream
-------------------------------------------------*/ -------------------------------------------------*/
static inline void map_extract(const UINT8 *base, map_entry *entry) INLINE void map_extract(const UINT8 *base, map_entry *entry)
{ {
entry->offset = get_bigendian_uint64(&base[0]); entry->offset = get_bigendian_uint64(&base[0]);
entry->crc = get_bigendian_uint32(&base[8]); entry->crc = get_bigendian_uint32(&base[8]);
@ -1039,7 +1061,7 @@ static inline void map_extract(const UINT8 *base, map_entry *entry)
entry to the datastream entry to the datastream
-------------------------------------------------*/ -------------------------------------------------*/
static inline void map_assemble(UINT8 *base, map_entry *entry) INLINE void map_assemble(UINT8 *base, map_entry *entry)
{ {
put_bigendian_uint64(&base[0], entry->offset); put_bigendian_uint64(&base[0], entry->offset);
put_bigendian_uint32(&base[8], entry->crc); put_bigendian_uint32(&base[8], entry->crc);
@ -1051,7 +1073,7 @@ static inline void map_assemble(UINT8 *base, map_entry *entry)
/*------------------------------------------------- /*-------------------------------------------------
map_size_v5 - calculate CHDv5 map size map_size_v5 - calculate CHDv5 map size
-------------------------------------------------*/ -------------------------------------------------*/
static inline int map_size_v5(chd_header* header) INLINE int map_size_v5(chd_header* header)
{ {
return header->hunkcount * header->mapentrybytes; return header->hunkcount * header->mapentrybytes;
} }
@ -1114,31 +1136,46 @@ uint16_t crc16(const void *data, uint32_t length)
static chd_error decompress_v5_map(chd_file* chd, chd_header* header) static chd_error decompress_v5_map(chd_file* chd, chd_header* header)
{ {
uint8_t rawbuf[16];
uint16_t mapcrc;
uint32_t mapbytes;
uint64_t firstoffs;
uint32_t last_self = 0;
uint64_t last_parent = 0;
uint8_t lastcomp = 0;
int hunknum, repcount = 0;
enum huffman_error err;
uint8_t lengthbits, selfbits, parentbits;
uint8_t* compressed;
struct bitstream* bitbuf;
struct huffman_decoder* decoder;
uint64_t curoffset;
if (header->mapoffset == 0) if (header->mapoffset == 0)
{ {
//memset(header->rawmap, 0xff,map_size_v5(header)); #if 0
memset(header->rawmap, 0xff,map_size_v5(header));
#endif
return CHDERR_READ_ERROR; return CHDERR_READ_ERROR;
} }
// read the reader /* read the reader */
uint8_t rawbuf[16];
core_fseek(chd->file, header->mapoffset, SEEK_SET); core_fseek(chd->file, header->mapoffset, SEEK_SET);
core_fread(chd->file, rawbuf, sizeof(rawbuf)); core_fread(chd->file, rawbuf, sizeof(rawbuf));
uint32_t const mapbytes = get_bigendian_uint32(&rawbuf[0]); mapbytes = get_bigendian_uint32(&rawbuf[0]);
uint64_t const firstoffs = get_bigendian_uint48(&rawbuf[4]); firstoffs = get_bigendian_uint48(&rawbuf[4]);
uint16_t const mapcrc = get_bigendian_uint16(&rawbuf[10]); mapcrc = get_bigendian_uint16(&rawbuf[10]);
uint8_t const lengthbits = rawbuf[12]; lengthbits = rawbuf[12];
uint8_t const selfbits = rawbuf[13]; selfbits = rawbuf[13];
uint8_t const parentbits = rawbuf[14]; parentbits = rawbuf[14];
// now read the map /* now read the map */
uint8_t* compressed = (uint8_t*)malloc(sizeof(uint8_t) * mapbytes); compressed = (uint8_t*)malloc(sizeof(uint8_t) * mapbytes);
if (compressed == NULL) if (compressed == NULL)
return CHDERR_OUT_OF_MEMORY; return CHDERR_OUT_OF_MEMORY;
core_fseek(chd->file, header->mapoffset + 16, SEEK_SET); core_fseek(chd->file, header->mapoffset + 16, SEEK_SET);
core_fread(chd->file, compressed, mapbytes); core_fread(chd->file, compressed, mapbytes);
struct bitstream* bitbuf = create_bitstream(compressed, sizeof(uint8_t) * mapbytes); bitbuf = create_bitstream(compressed, sizeof(uint8_t) * mapbytes);
if (bitbuf == NULL) if (bitbuf == NULL)
{ {
free(compressed); free(compressed);
@ -1153,8 +1190,8 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header)
return CHDERR_OUT_OF_MEMORY; return CHDERR_OUT_OF_MEMORY;
} }
// first decode the compression types /* first decode the compression types */
struct huffman_decoder* decoder = create_huffman_decoder(16, 8); decoder = create_huffman_decoder(16, 8);
if (decoder == NULL) if (decoder == NULL)
{ {
free(compressed); free(compressed);
@ -1162,7 +1199,7 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header)
return CHDERR_OUT_OF_MEMORY; return CHDERR_OUT_OF_MEMORY;
} }
enum huffman_error err = huffman_import_tree_rle(decoder, bitbuf); err = huffman_import_tree_rle(decoder, bitbuf);
if (err != HUFFERR_NONE) if (err != HUFFERR_NONE)
{ {
free(compressed); free(compressed);
@ -1171,8 +1208,6 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header)
return CHDERR_DECOMPRESSION_ERROR; return CHDERR_DECOMPRESSION_ERROR;
} }
uint8_t lastcomp = 0;
int hunknum, repcount = 0;
for (hunknum = 0; hunknum < header->hunkcount; hunknum++) for (hunknum = 0; hunknum < header->hunkcount; hunknum++)
{ {
uint8_t *rawmap = header->rawmap + (hunknum * 12); uint8_t *rawmap = header->rawmap + (hunknum * 12);
@ -1190,10 +1225,8 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header)
} }
} }
// then iterate through the hunks and extract the needed data /* then iterate through the hunks and extract the needed data */
uint64_t curoffset = firstoffs; curoffset = firstoffs;
uint32_t last_self = 0;
uint64_t last_parent = 0;
for (hunknum = 0; hunknum < header->hunkcount; hunknum++) for (hunknum = 0; hunknum < header->hunkcount; hunknum++)
{ {
uint8_t *rawmap = header->rawmap + (hunknum * 12); uint8_t *rawmap = header->rawmap + (hunknum * 12);
@ -1245,22 +1278,22 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header)
offset = last_parent; offset = last_parent;
break; break;
} }
// UINT24 length /* UINT24 length */
put_bigendian_uint24(&rawmap[1], length); put_bigendian_uint24(&rawmap[1], length);
// UINT48 offset /* UINT48 offset */
put_bigendian_uint48(&rawmap[4], offset); put_bigendian_uint48(&rawmap[4], offset);
// crc16 /* crc16 */
put_bigendian_uint16(&rawmap[10], crc); put_bigendian_uint16(&rawmap[10], crc);
} }
// free memory /* free memory */
free(compressed); free(compressed);
free(bitbuf); free(bitbuf);
delete_huffman_decoder(decoder); delete_huffman_decoder(decoder);
// verify the final CRC /* verify the final CRC */
if (crc16(&header->rawmap[0], header->hunkcount * 12) != mapcrc) if (crc16(&header->rawmap[0], header->hunkcount * 12) != mapcrc)
return CHDERR_DECOMPRESSION_ERROR; return CHDERR_DECOMPRESSION_ERROR;
@ -1272,7 +1305,7 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header)
entry in old format from the datastream entry in old format from the datastream
-------------------------------------------------*/ -------------------------------------------------*/
static inline void map_extract_old(const UINT8 *base, map_entry *entry, UINT32 hunkbytes) INLINE void map_extract_old(const UINT8 *base, map_entry *entry, UINT32 hunkbytes)
{ {
entry->offset = get_bigendian_uint64(&base[0]); entry->offset = get_bigendian_uint64(&base[0]);
entry->crc = 0; entry->crc = 0;
@ -1402,7 +1435,7 @@ chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **
else else
{ {
int i, decompnum; int i, decompnum;
// verify the compression types and initialize the codecs /* verify the compression types and initialize the codecs */
for (decompnum = 0; decompnum < ARRAY_LENGTH(newchd->header.compression); decompnum++) for (decompnum = 0; decompnum < ARRAY_LENGTH(newchd->header.compression); decompnum++)
{ {
for (i = 0 ; i < ARRAY_LENGTH(codec_interfaces) ; i++) for (i = 0 ; i < ARRAY_LENGTH(codec_interfaces) ; i++)
@ -1440,9 +1473,11 @@ chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **
} }
} }
// HACK #if 0
//if (err != CHDERR_NONE) /* HACK */
// EARLY_EXIT(err); if (err != CHDERR_NONE)
EARLY_EXIT(err);
#endif
/* all done */ /* all done */
*chd = newchd; *chd = newchd;
@ -1517,7 +1552,7 @@ void chd_close(chd_file *chd)
else else
{ {
int i; int i;
// Free the codecs /* Free the codecs */
for (i = 0 ; i < 4 ; i++) for (i = 0 ; i < 4 ; i++)
{ {
void* codec = NULL; void* codec = NULL;
@ -1541,7 +1576,7 @@ void chd_close(chd_file *chd)
} }
} }
// Free the raw map /* Free the raw map */
if (chd->header.rawmap != NULL) if (chd->header.rawmap != NULL)
free(chd->header.rawmap); free(chd->header.rawmap);
} }
@ -1938,10 +1973,10 @@ static chd_error header_read(core_file *file, chd_header *header)
memcpy(header->parentsha1, &rawheader[104], CHD_SHA1_BYTES); memcpy(header->parentsha1, &rawheader[104], CHD_SHA1_BYTES);
memcpy(header->rawsha1, &rawheader[64], CHD_SHA1_BYTES); memcpy(header->rawsha1, &rawheader[64], CHD_SHA1_BYTES);
// determine properties of map entries /* determine properties of map entries */
header->mapentrybytes = 12; //TODO compressed() ? 12 : 4; header->mapentrybytes = 12; /*TODO compressed() ? 12 : 4; */
// hack /* hack */
header->totalhunks = header->hunkcount; header->totalhunks = header->hunkcount;
} }
@ -1999,7 +2034,7 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
{ {
chd_error err; chd_error err;
// punt if no file /* punt if no file */
if (chd->file == NULL) if (chd->file == NULL)
return CHDERR_INVALID_FILE; return CHDERR_INVALID_FILE;
@ -2012,6 +2047,7 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
if (chd->header.version < 5) if (chd->header.version < 5)
{ {
void* codec;
map_entry *entry = &chd->map[hunknum]; map_entry *entry = &chd->map[hunknum];
UINT32 bytes; UINT32 bytes;
@ -2029,7 +2065,7 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
/* now decompress using the codec */ /* now decompress using the codec */
err = CHDERR_NONE; err = CHDERR_NONE;
void* codec = &chd->zlib_codec_data; codec = &chd->zlib_codec_data;
if (chd->codecintf[0]->decompress != NULL) if (chd->codecintf[0]->decompress != NULL)
err = (*chd->codecintf[0]->decompress)(codec, chd->compressed, entry->length, dest, chd->header.hunkbytes); err = (*chd->codecintf[0]->decompress)(codec, chd->compressed, entry->length, dest, chd->header.hunkbytes);
if (err != CHDERR_NONE) if (err != CHDERR_NONE)
@ -2070,8 +2106,8 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
} }
else else
{ {
void* codec = NULL;
// get a pointer to the map entry /* get a pointer to the map entry */
uint64_t blockoffs; uint64_t blockoffs;
uint32_t blocklen; uint32_t blocklen;
#ifdef VERIFY_BLOCK_CRC #ifdef VERIFY_BLOCK_CRC
@ -2079,7 +2115,7 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
#endif #endif
uint8_t *rawmap = &chd->header.rawmap[chd->header.mapentrybytes * hunknum]; uint8_t *rawmap = &chd->header.rawmap[chd->header.mapentrybytes * hunknum];
// uncompressed case /* uncompressed case */
/* TODO /* TODO
if (!compressed()) if (!compressed())
{ {
@ -2095,13 +2131,12 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
return CHDERR_NONE; return CHDERR_NONE;
}*/ }*/
// compressed case /* compressed case */
blocklen = get_bigendian_uint24(&rawmap[1]); blocklen = get_bigendian_uint24(&rawmap[1]);
blockoffs = get_bigendian_uint48(&rawmap[4]); blockoffs = get_bigendian_uint48(&rawmap[4]);
#ifdef VERIFY_BLOCK_CRC #ifdef VERIFY_BLOCK_CRC
blockcrc = get_bigendian_uint16(&rawmap[10]); blockcrc = get_bigendian_uint16(&rawmap[10]);
#endif #endif
void* codec = NULL;
switch (rawmap[0]) switch (rawmap[0])
{ {
case COMPRESSION_TYPE_0: case COMPRESSION_TYPE_0:
@ -2148,16 +2183,18 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
return hunk_read_into_memory(chd, blockoffs, dest); return hunk_read_into_memory(chd, blockoffs, dest);
case COMPRESSION_PARENT: case COMPRESSION_PARENT:
// TODO /* TODO */
//if (m_parent_missing) #if 0
// return CHDERR_REQUIRES_PARENT; if (m_parent_missing)
//return m_parent->read_bytes(uint64_t(blockoffs) * uint64_t(m_parent->unit_bytes()), dest, m_hunkbytes); return CHDERR_REQUIRES_PARENT;
return m_parent->read_bytes(uint64_t(blockoffs) * uint64_t(m_parent->unit_bytes()), dest, m_hunkbytes);
#endif
return CHDERR_DECOMPRESSION_ERROR; return CHDERR_DECOMPRESSION_ERROR;
} }
return CHDERR_NONE; return CHDERR_NONE;
} }
// We should not reach this code /* We should not reach this code */
return CHDERR_DECOMPRESSION_ERROR; return CHDERR_DECOMPRESSION_ERROR;
} }
@ -2360,11 +2397,12 @@ static void zlib_codec_free(void *codec)
if (data != NULL) if (data != NULL)
{ {
int i; int i;
zlib_allocator alloc;
inflateEnd(&data->inflater); inflateEnd(&data->inflater);
/* free our fast memory */ /* free our fast memory */
zlib_allocator alloc = data->allocator; alloc = data->allocator;
for (i = 0; i < MAX_ZLIB_ALLOCS; i++) for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
if (alloc.allocptr[i]) if (alloc.allocptr[i])
free(alloc.allocptr[i]); free(alloc.allocptr[i]);

View File

@ -24,9 +24,10 @@ static FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const F
FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void* client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]); FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void* client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
static void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); static void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
//------------------------------------------------- /*-------------------------------------------------
// flac_decoder - constructor * flac_decoder - constructor
//------------------------------------------------- *-------------------------------------------------
*/
void flac_decoder_init(flac_decoder *decoder) void flac_decoder_init(flac_decoder *decoder)
{ {
@ -44,9 +45,10 @@ void flac_decoder_init(flac_decoder *decoder)
decoder->uncompressed_swap = 0; decoder->uncompressed_swap = 0;
} }
//------------------------------------------------- /*-------------------------------------------------
// flac_decoder - destructor * flac_decoder - destructor
//------------------------------------------------- *-------------------------------------------------
*/
void flac_decoder_free(flac_decoder* decoder) void flac_decoder_free(flac_decoder* decoder)
{ {
@ -55,10 +57,11 @@ void flac_decoder_free(flac_decoder* decoder)
} }
//------------------------------------------------- /*-------------------------------------------------
// reset - reset state with the original * reset - reset state with the original
// parameters * parameters
//------------------------------------------------- *-------------------------------------------------
*/
static int flac_decoder_internal_reset(flac_decoder* decoder) static int flac_decoder_internal_reset(flac_decoder* decoder)
{ {
@ -78,30 +81,31 @@ static int flac_decoder_internal_reset(flac_decoder* decoder)
//------------------------------------------------- /*-------------------------------------------------
// reset - reset state with new memory parameters * reset - reset state with new memory parameters
// and a custom-generated header * and a custom-generated header
//------------------------------------------------- *-------------------------------------------------
*/
int flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length) int flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length)
{ {
// modify the template header with our parameters /* modify the template header with our parameters */
static const uint8_t s_header_template[0x2a] = static const uint8_t s_header_template[0x2a] =
{ {
0x66, 0x4C, 0x61, 0x43, // +00: 'fLaC' stream header 0x66, 0x4C, 0x61, 0x43, /* +00: 'fLaC' stream header */
0x80, // +04: metadata block type 0 (STREAMINFO), 0x80, /* +04: metadata block type 0 (STREAMINFO), */
// flagged as last block /* flagged as last block */
0x00, 0x00, 0x22, // +05: metadata block length = 0x22 0x00, 0x00, 0x22, /* +05: metadata block length = 0x22 */
0x00, 0x00, // +08: minimum block size 0x00, 0x00, /* +08: minimum block size */
0x00, 0x00, // +0A: maximum block size 0x00, 0x00, /* +0A: maximum block size */
0x00, 0x00, 0x00, // +0C: minimum frame size (0 == unknown) 0x00, 0x00, 0x00, /* +0C: minimum frame size (0 == unknown) */
0x00, 0x00, 0x00, // +0F: maximum frame size (0 == unknown) 0x00, 0x00, 0x00, /* +0F: maximum frame size (0 == unknown) */
0x0A, 0xC4, 0x42, 0xF0, 0x00, 0x00, 0x00, 0x00, // +12: sample rate (0x0ac44 == 44100), 0x0A, 0xC4, 0x42, 0xF0, 0x00, 0x00, 0x00, 0x00, /* +12: sample rate (0x0ac44 == 44100), */
// numchannels (2), sample bits (16), /* numchannels (2), sample bits (16), */
// samples in stream (0 == unknown) /* samples in stream (0 == unknown) */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // +1A: MD5 signature (0 == none) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* +1A: MD5 signature (0 == none) */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* */
// +2A: start of stream data /* +2A: start of stream data */
}; };
memcpy(decoder->custom_header, s_header_template, sizeof(s_header_template)); memcpy(decoder->custom_header, s_header_template, sizeof(s_header_template));
decoder->custom_header[0x08] = decoder->custom_header[0x0a] = block_size >> 8; decoder->custom_header[0x08] = decoder->custom_header[0x0a] = block_size >> 8;
@ -110,7 +114,7 @@ int flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_
decoder->custom_header[0x13] = sample_rate >> 4; decoder->custom_header[0x13] = sample_rate >> 4;
decoder->custom_header[0x14] = (sample_rate << 4) | ((num_channels - 1) << 1); decoder->custom_header[0x14] = (sample_rate << 4) | ((num_channels - 1) << 1);
// configure the header ahead of the provided buffer /* configure the header ahead of the provided buffer */
decoder->compressed_start = (const FLAC__byte *)(decoder->custom_header); decoder->compressed_start = (const FLAC__byte *)(decoder->custom_header);
decoder->compressed_length = sizeof(decoder->custom_header); decoder->compressed_length = sizeof(decoder->custom_header);
decoder->compressed2_start = (const FLAC__byte *)(buffer); decoder->compressed2_start = (const FLAC__byte *)(buffer);
@ -119,21 +123,22 @@ int flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_
} }
//------------------------------------------------- /*-------------------------------------------------
// decode_interleaved - decode to an interleaved * decode_interleaved - decode to an interleaved
// sound stream * sound stream
//------------------------------------------------- *-------------------------------------------------
*/
int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian) int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian)
{ {
// configure the uncompressed buffer /* configure the uncompressed buffer */
memset(decoder->uncompressed_start, 0, sizeof(decoder->uncompressed_start)); memset(decoder->uncompressed_start, 0, sizeof(decoder->uncompressed_start));
decoder->uncompressed_start[0] = samples; decoder->uncompressed_start[0] = samples;
decoder->uncompressed_offset = 0; decoder->uncompressed_offset = 0;
decoder->uncompressed_length = num_samples; decoder->uncompressed_length = num_samples;
decoder->uncompressed_swap = swap_endian; decoder->uncompressed_swap = swap_endian;
// loop until we get everything we want /* loop until we get everything we want */
while (decoder->uncompressed_offset < decoder->uncompressed_length) while (decoder->uncompressed_offset < decoder->uncompressed_length)
if (!FLAC__stream_decoder_process_single(decoder->decoder)) if (!FLAC__stream_decoder_process_single(decoder->decoder))
return 0; return 0;
@ -141,20 +146,22 @@ int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uin
} }
#if 0
/* /*
//------------------------------------------------- *-------------------------------------------------
// decode - decode to an multiple independent * decode - decode to an multiple independent
// data streams * data streams
//------------------------------------------------- *-------------------------------------------------
*/
bool flac_decoder::decode(int16_t **samples, uint32_t num_samples, bool swap_endian) bool flac_decoder::decode(int16_t **samples, uint32_t num_samples, bool swap_endian)
{ {
// make sure we don't have too many channels /* make sure we don't have too many channels */
int chans = channels(); int chans = channels();
if (chans > ARRAY_LENGTH(m_uncompressed_start)) if (chans > ARRAY_LENGTH(m_uncompressed_start))
return false; return false;
// configure the uncompressed buffer /* configure the uncompressed buffer */
memset(m_uncompressed_start, 0, sizeof(m_uncompressed_start)); memset(m_uncompressed_start, 0, sizeof(m_uncompressed_start));
for (int curchan = 0; curchan < chans; curchan++) for (int curchan = 0; curchan < chans; curchan++)
m_uncompressed_start[curchan] = samples[curchan]; m_uncompressed_start[curchan] = samples[curchan];
@ -162,26 +169,27 @@ bool flac_decoder::decode(int16_t **samples, uint32_t num_samples, bool swap_end
m_uncompressed_length = num_samples; m_uncompressed_length = num_samples;
m_uncompressed_swap = swap_endian; m_uncompressed_swap = swap_endian;
// loop until we get everything we want /* loop until we get everything we want */
while (m_uncompressed_offset < m_uncompressed_length) while (m_uncompressed_offset < m_uncompressed_length)
if (!FLAC__stream_decoder_process_single(m_decoder)) if (!FLAC__stream_decoder_process_single(m_decoder))
return false; return false;
return true; return true;
} }
*/ #endif
//------------------------------------------------- /*-------------------------------------------------
// finish - finish up the decode * finish - finish up the decode
//------------------------------------------------- *-------------------------------------------------
*/
uint32_t flac_decoder_finish(flac_decoder* decoder) uint32_t flac_decoder_finish(flac_decoder* decoder)
{ {
// get the final decoding position and move forward /* get the final decoding position and move forward */
FLAC__uint64 position = 0; FLAC__uint64 position = 0;
FLAC__stream_decoder_get_decode_position(decoder->decoder, &position); FLAC__stream_decoder_get_decode_position(decoder->decoder, &position);
FLAC__stream_decoder_finish(decoder->decoder); FLAC__stream_decoder_finish(decoder->decoder);
// adjust position if we provided the header /* adjust position if we provided the header */
if (position == 0) if (position == 0)
return 0; return 0;
if (decoder->compressed_start == (const FLAC__byte *)(decoder->custom_header)) if (decoder->compressed_start == (const FLAC__byte *)(decoder->custom_header))
@ -190,10 +198,11 @@ uint32_t flac_decoder_finish(flac_decoder* decoder)
} }
//------------------------------------------------- /*-------------------------------------------------
// read_callback - handle reads from the input * read_callback - handle reads from the input
// stream * stream
//------------------------------------------------- *-------------------------------------------------
*/
#define MIN(x, y) ((x) < (y) ? (x) : (y)) #define MIN(x, y) ((x) < (y) ? (x) : (y))
@ -208,7 +217,7 @@ FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC
uint32_t expected = *bytes; uint32_t expected = *bytes;
// copy from primary buffer first /* copy from primary buffer first */
uint32_t outputpos = 0; uint32_t outputpos = 0;
if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length) if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length)
{ {
@ -218,7 +227,7 @@ FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC
decoder->compressed_offset += bytes_to_copy; decoder->compressed_offset += bytes_to_copy;
} }
// once we're out of that, copy from the secondary buffer /* once we're out of that, copy from the secondary buffer */
if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length + decoder->compressed2_length) if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length + decoder->compressed2_length)
{ {
uint32_t bytes_to_copy = MIN(*bytes - outputpos, decoder->compressed2_length - (decoder->compressed_offset - decoder->compressed_length)); uint32_t bytes_to_copy = MIN(*bytes - outputpos, decoder->compressed2_length - (decoder->compressed_offset - decoder->compressed_length));
@ -228,33 +237,36 @@ FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC
} }
*bytes = outputpos; *bytes = outputpos;
// return based on whether we ran out of data /* return based on whether we ran out of data */
return (*bytes < expected) ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; return (*bytes < expected) ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
} }
//------------------------------------------------- /*-------------------------------------------------
// metadata_callback - handle STREAMINFO metadata * metadata_callback - handle STREAMINFO metadata
//------------------------------------------------- *-------------------------------------------------
*/
void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
{ {
// ignore all but STREAMINFO metadata flac_decoder *fldecoder;
/* ignore all but STREAMINFO metadata */
if (metadata->type != FLAC__METADATA_TYPE_STREAMINFO) if (metadata->type != FLAC__METADATA_TYPE_STREAMINFO)
return; return;
// parse out the data we care about /* parse out the data we care about */
flac_decoder *fldecoder = (flac_decoder *)(client_data); fldecoder = (flac_decoder *)(client_data);
fldecoder->sample_rate = metadata->data.stream_info.sample_rate; fldecoder->sample_rate = metadata->data.stream_info.sample_rate;
fldecoder->bits_per_sample = metadata->data.stream_info.bits_per_sample; fldecoder->bits_per_sample = metadata->data.stream_info.bits_per_sample;
fldecoder->channels = metadata->data.stream_info.channels; fldecoder->channels = metadata->data.stream_info.channels;
} }
//------------------------------------------------- /*-------------------------------------------------
// tell_callback - handle requests to find out * tell_callback - handle requests to find out
// where in the input stream we are * where in the input stream we are
//------------------------------------------------- *-------------------------------------------------
*/
FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
{ {
@ -263,10 +275,11 @@ FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__Stre
} }
//------------------------------------------------- /*-------------------------------------------------
// write_callback - handle writes to the output * write_callback - handle writes to the output
// stream * stream
//------------------------------------------------- *-------------------------------------------------
*/
FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
{ {
@ -275,14 +288,15 @@ FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__St
FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void *client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]) FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void *client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[])
{ {
int sampnum, chan;
int shift, blocksize;
flac_decoder * decoder = (flac_decoder *)client_data; flac_decoder * decoder = (flac_decoder *)client_data;
assert(frame->header.channels == decoder->channels); assert(frame->header.channels == decoder->channels);
// interleaved case /* interleaved case */
int sampnum, chan; shift = decoder->uncompressed_swap ? 8 : 0;
int shift = decoder->uncompressed_swap ? 8 : 0; blocksize = frame->header.blocksize;
int blocksize = frame->header.blocksize;
if (decoder->uncompressed_start[1] == NULL) if (decoder->uncompressed_start[1] == NULL)
{ {
int16_t *dest = decoder->uncompressed_start[0] + decoder->uncompressed_offset * frame->header.channels; int16_t *dest = decoder->uncompressed_start[0] + decoder->uncompressed_offset * frame->header.channels;
@ -291,7 +305,7 @@ FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void *client_data, co
*dest++ = (int16_t)((((uint16_t)buffer[chan][sampnum]) << shift) | (((uint16_t)buffer[chan][sampnum]) >> shift)); *dest++ = (int16_t)((((uint16_t)buffer[chan][sampnum]) << shift) | (((uint16_t)buffer[chan][sampnum]) >> shift));
} }
// non-interleaved case /* non-interleaved case */
else else
{ {
for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++) for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++)

View File

@ -1,6 +1,6 @@
// license:BSD-3-Clause /* license:BSD-3-Clause
// copyright-holders:Aaron Giles * copyright-holders:Aaron Giles
/*************************************************************************** ***************************************************************************
huffman.c huffman.c
@ -105,29 +105,33 @@
#define MAX(x,y) ((x) > (y) ? (x) : (y)) #define MAX(x,y) ((x) > (y) ? (x) : (y))
//************************************************************************** /***************************************************************************
// MACROS * MACROS
//************************************************************************** ***************************************************************************
*/
#define MAKE_LOOKUP(code,bits) (((code) << 5) | ((bits) & 0x1f)) #define MAKE_LOOKUP(code,bits) (((code) << 5) | ((bits) & 0x1f))
//************************************************************************** /***************************************************************************
// IMPLEMENTATION * IMPLEMENTATION
//************************************************************************** * **************************************************************************
*/
//------------------------------------------------- /*-------------------------------------------------
// huffman_context_base - create an encoding/ * huffman_context_base - create an encoding/
// decoding context * decoding context
//------------------------------------------------- *-------------------------------------------------
*/
struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits) struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits)
{ {
// limit to 24 bits struct huffman_decoder* decoder;
/* limit to 24 bits */
if (maxbits > 24) if (maxbits > 24)
return NULL; return NULL;
struct huffman_decoder* decoder = (struct huffman_decoder*)malloc(sizeof(struct huffman_decoder)); decoder = (struct huffman_decoder*)malloc(sizeof(struct huffman_decoder));
decoder->numcodes = numcodes; decoder->numcodes = numcodes;
decoder->maxbits = maxbits; decoder->maxbits = maxbits;
decoder->lookup = (lookup_value*)malloc(sizeof(lookup_value) * (1 << maxbits)); decoder->lookup = (lookup_value*)malloc(sizeof(lookup_value) * (1 << maxbits));
@ -150,33 +154,37 @@ void delete_huffman_decoder(struct huffman_decoder* decoder)
} }
} }
//------------------------------------------------- /*-------------------------------------------------
// decode_one - decode a single code from the * decode_one - decode a single code from the
// huffman stream * huffman stream
//------------------------------------------------- *-------------------------------------------------
*/
uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf) uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf)
{ {
// peek ahead to get maxbits worth of data /* peek ahead to get maxbits worth of data */
uint32_t bits = bitstream_peek(bitbuf, decoder->maxbits); uint32_t bits = bitstream_peek(bitbuf, decoder->maxbits);
// look it up, then remove the actual number of bits for this code /* look it up, then remove the actual number of bits for this code */
lookup_value lookup = decoder->lookup[bits]; lookup_value lookup = decoder->lookup[bits];
bitstream_remove(bitbuf, lookup & 0x1f); bitstream_remove(bitbuf, lookup & 0x1f);
// return the value /* return the value */
return lookup >> 5; return lookup >> 5;
} }
//------------------------------------------------- /*-------------------------------------------------
// import_tree_rle - import an RLE-encoded * import_tree_rle - import an RLE-encoded
// huffman tree from a source data stream * huffman tree from a source data stream
//------------------------------------------------- *-------------------------------------------------
*/
enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf) enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf)
{ {
// bits per entry depends on the maxbits enum huffman_error error;
/* bits per entry depends on the maxbits */
int numbits; int numbits;
int curnode;
if (decoder->maxbits >= 16) if (decoder->maxbits >= 16)
numbits = 5; numbits = 5;
else if (decoder->maxbits >= 8) else if (decoder->maxbits >= 8)
@ -184,24 +192,23 @@ enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, stru
else else
numbits = 3; numbits = 3;
// loop until we read all the nodes /* loop until we read all the nodes */
int curnode;
for (curnode = 0; curnode < decoder->numcodes; ) for (curnode = 0; curnode < decoder->numcodes; )
{ {
// a non-one value is just raw /* a non-one value is just raw */
int nodebits = bitstream_read(bitbuf, numbits); int nodebits = bitstream_read(bitbuf, numbits);
if (nodebits != 1) if (nodebits != 1)
decoder->huffnode[curnode++].numbits = nodebits; decoder->huffnode[curnode++].numbits = nodebits;
// a one value is an escape code /* a one value is an escape code */
else else
{ {
// a double 1 is just a single 1 /* a double 1 is just a single 1 */
nodebits = bitstream_read(bitbuf, numbits); nodebits = bitstream_read(bitbuf, numbits);
if (nodebits == 1) if (nodebits == 1)
decoder->huffnode[curnode++].numbits = nodebits; decoder->huffnode[curnode++].numbits = nodebits;
// otherwise, we need one for value for the repeat count /* otherwise, we need one for value for the repeat count */
else else
{ {
int repcount = bitstream_read(bitbuf, numbits) + 3; int repcount = bitstream_read(bitbuf, numbits) + 3;
@ -211,35 +218,44 @@ enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, stru
} }
} }
// make sure we ended up with the right number /* make sure we ended up with the right number */
if (curnode != decoder->numcodes) if (curnode != decoder->numcodes)
return HUFFERR_INVALID_DATA; return HUFFERR_INVALID_DATA;
// assign canonical codes for all nodes based on their code lengths /* assign canonical codes for all nodes based on their code lengths */
enum huffman_error error = huffman_assign_canonical_codes(decoder); error = huffman_assign_canonical_codes(decoder);
if (error != HUFFERR_NONE) if (error != HUFFERR_NONE)
return error; return error;
// build the lookup table /* build the lookup table */
huffman_build_lookup_table(decoder); huffman_build_lookup_table(decoder);
// determine final input length and report errors /* determine final input length and report errors */
return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE; return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
} }
//------------------------------------------------- /*-------------------------------------------------
// import_tree_huffman - import a huffman-encoded * import_tree_huffman - import a huffman-encoded
// huffman tree from a source data stream * huffman tree from a source data stream
//------------------------------------------------- *-------------------------------------------------
*/
enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf) enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf)
{ {
// start by parsing the lengths for the small tree int last = 0;
struct huffman_decoder* smallhuff = create_huffman_decoder(24, 6); int curcode;
smallhuff->huffnode[0].numbits = bitstream_read(bitbuf, 3); uint32_t temp;
int start = bitstream_read(bitbuf, 3) + 1; enum huffman_error error;
uint8_t rlefullbits = 0;
int index, count = 0; int index, count = 0;
int start;
/* start by parsing the lengths for the small tree */
struct huffman_decoder* smallhuff = create_huffman_decoder(24, 6);
smallhuff->huffnode[0].numbits = bitstream_read(bitbuf, 3);
start = bitstream_read(bitbuf, 3) + 1;
for (index = 1; index < 24; index++) for (index = 1; index < 24; index++)
{ {
if (index < start || count == 7) if (index < start || count == 7)
@ -251,21 +267,18 @@ enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder,
} }
} }
// then regenerate the tree /* then regenerate the tree */
enum huffman_error error = huffman_assign_canonical_codes(smallhuff); error = huffman_assign_canonical_codes(smallhuff);
if (error != HUFFERR_NONE) if (error != HUFFERR_NONE)
return error; return error;
huffman_build_lookup_table(smallhuff); huffman_build_lookup_table(smallhuff);
// determine the maximum length of an RLE count /* determine the maximum length of an RLE count */
uint32_t temp = decoder->numcodes - 9; temp = decoder->numcodes - 9;
uint8_t rlefullbits = 0;
while (temp != 0) while (temp != 0)
temp >>= 1, rlefullbits++; temp >>= 1, rlefullbits++;
// now process the rest of the data /* now process the rest of the data */
int last = 0;
int curcode;
for (curcode = 0; curcode < decoder->numcodes; ) for (curcode = 0; curcode < decoder->numcodes; )
{ {
int value = huffman_decode_one(smallhuff, bitbuf); int value = huffman_decode_one(smallhuff, bitbuf);
@ -281,51 +294,53 @@ enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder,
} }
} }
// make sure we ended up with the right number /* make sure we ended up with the right number */
if (curcode != decoder->numcodes) if (curcode != decoder->numcodes)
return HUFFERR_INVALID_DATA; return HUFFERR_INVALID_DATA;
// assign canonical codes for all nodes based on their code lengths /* assign canonical codes for all nodes based on their code lengths */
error = huffman_assign_canonical_codes(decoder); error = huffman_assign_canonical_codes(decoder);
if (error != HUFFERR_NONE) if (error != HUFFERR_NONE)
return error; return error;
// build the lookup table /* build the lookup table */
huffman_build_lookup_table(decoder); huffman_build_lookup_table(decoder);
// determine final input length and report errors /* determine final input length and report errors */
return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE; return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
} }
//------------------------------------------------- /*-------------------------------------------------
// compute_tree_from_histo - common backend for * compute_tree_from_histo - common backend for
// computing a tree based on the data histogram * computing a tree based on the data histogram
//------------------------------------------------- *-------------------------------------------------
*/
enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder) enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder)
{ {
// compute the number of data items in the histogram /* compute the number of data items in the histogram */
int i; int i;
uint32_t upperweight;
uint32_t lowerweight = 0;
uint32_t sdatacount = 0; uint32_t sdatacount = 0;
for (i = 0; i < decoder->numcodes; i++) for (i = 0; i < decoder->numcodes; i++)
sdatacount += decoder->datahisto[i]; sdatacount += decoder->datahisto[i];
// binary search to achieve the optimum encoding /* binary search to achieve the optimum encoding */
uint32_t lowerweight = 0; upperweight = sdatacount * 2;
uint32_t upperweight = sdatacount * 2;
while (1) while (1)
{ {
// build a tree using the current weight /* build a tree using the current weight */
uint32_t curweight = (upperweight + lowerweight) / 2; uint32_t curweight = (upperweight + lowerweight) / 2;
int curmaxbits = huffman_build_tree(decoder, sdatacount, curweight); int curmaxbits = huffman_build_tree(decoder, sdatacount, curweight);
// apply binary search here /* apply binary search here */
if (curmaxbits <= decoder->maxbits) if (curmaxbits <= decoder->maxbits)
{ {
lowerweight = curweight; lowerweight = curweight;
// early out if it worked with the raw weights, or if we're done searching /* early out if it worked with the raw weights, or if we're done searching */
if (curweight == sdatacount || (upperweight - lowerweight) <= 1) if (curweight == sdatacount || (upperweight - lowerweight) <= 1)
break; break;
} }
@ -333,20 +348,22 @@ enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decod
upperweight = curweight; upperweight = curweight;
} }
// assign canonical codes for all nodes based on their code lengths /* assign canonical codes for all nodes based on their code lengths */
return huffman_assign_canonical_codes(decoder); return huffman_assign_canonical_codes(decoder);
} }
//************************************************************************** /***************************************************************************
// INTERNAL FUNCTIONS * INTERNAL FUNCTIONS
//************************************************************************** ***************************************************************************
*/
//------------------------------------------------- /*-------------------------------------------------
// tree_node_compare - compare two tree nodes * tree_node_compare - compare two tree nodes
// by weight * by weight
//------------------------------------------------- *-------------------------------------------------
*/
static int huffman_tree_node_compare(const void *item1, const void *item2) static int huffman_tree_node_compare(const void *item1, const void *item2)
{ {
@ -360,14 +377,17 @@ static int huffman_tree_node_compare(const void *item1, const void *item2)
} }
//------------------------------------------------- /*-------------------------------------------------
// build_tree - build a huffman tree based on the * build_tree - build a huffman tree based on the
// data distribution * data distribution
//------------------------------------------------- *-------------------------------------------------
*/
int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight) int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight)
{ {
// make a list of all non-zero nodes int nextalloc;
int maxbits = 0;
/* make a list of all non-zero nodes */
struct node_t** list = (struct node_t**)malloc(sizeof(struct node_t*) * decoder->numcodes * 2); struct node_t** list = (struct node_t**)malloc(sizeof(struct node_t*) * decoder->numcodes * 2);
int curcode, listitems = 0; int curcode, listitems = 0;
memset(decoder->huffnode, 0, decoder->numcodes * sizeof(decoder->huffnode[0])); memset(decoder->huffnode, 0, decoder->numcodes * sizeof(decoder->huffnode[0]));
@ -378,7 +398,7 @@ int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint
decoder->huffnode[curcode].count = decoder->datahisto[curcode]; decoder->huffnode[curcode].count = decoder->datahisto[curcode];
decoder->huffnode[curcode].bits = curcode; decoder->huffnode[curcode].bits = curcode;
// scale the weight by the current effective length, ensuring we don't go to 0 /* scale the weight by the current effective length, ensuring we don't go to 0 */
decoder->huffnode[curcode].weight = ((uint64_t)decoder->datahisto[curcode]) * ((uint64_t)totalweight) / ((uint64_t)totaldata); decoder->huffnode[curcode].weight = ((uint64_t)decoder->datahisto[curcode]) * ((uint64_t)totalweight) / ((uint64_t)totaldata);
if (decoder->huffnode[curcode].weight == 0) if (decoder->huffnode[curcode].weight == 0)
decoder->huffnode[curcode].weight = 1; decoder->huffnode[curcode].weight = 1;
@ -389,7 +409,7 @@ int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint
fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits); fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits);
} }
*/ */
// sort the list by weight, largest weight first /* sort the list by weight, largest weight first */
qsort(&list[0], listitems, sizeof(list[0]), huffman_tree_node_compare); qsort(&list[0], listitems, sizeof(list[0]), huffman_tree_node_compare);
/* /*
fprintf(stderr, "Post-sort:\n"); fprintf(stderr, "Post-sort:\n");
@ -398,22 +418,23 @@ int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint
} }
fprintf(stderr, "===================\n"); fprintf(stderr, "===================\n");
*/ */
// now build the tree /* now build the tree */
int nextalloc = decoder->numcodes; nextalloc = decoder->numcodes;
while (listitems > 1) while (listitems > 1)
{ {
// remove lowest two items int curitem;
/* remove lowest two items */
struct node_t* node1 = &(*list[--listitems]); struct node_t* node1 = &(*list[--listitems]);
struct node_t* node0 = &(*list[--listitems]); struct node_t* node0 = &(*list[--listitems]);
// create new node /* create new node */
struct node_t* newnode = &decoder->huffnode[nextalloc++]; struct node_t* newnode = &decoder->huffnode[nextalloc++];
newnode->parent = NULL; newnode->parent = NULL;
node0->parent = node1->parent = newnode; node0->parent = node1->parent = newnode;
newnode->weight = node0->weight + node1->weight; newnode->weight = node0->weight + node1->weight;
// insert into list at appropriate location /* insert into list at appropriate location */
int curitem;
for (curitem = 0; curitem < listitems; curitem++) for (curitem = 0; curitem < listitems; curitem++)
if (newnode->weight > list[curitem]->weight) if (newnode->weight > list[curitem]->weight)
{ {
@ -424,8 +445,7 @@ int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint
listitems++; listitems++;
} }
// compute the number of bits in each code, and fill in another histogram /* compute the number of bits in each code, and fill in another histogram */
int maxbits = 0;
for (curcode = 0; curcode < decoder->numcodes; curcode++) for (curcode = 0; curcode < decoder->numcodes; curcode++)
{ {
struct node_t *curnode; struct node_t *curnode;
@ -436,13 +456,13 @@ int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint
// if we have a non-zero weight, compute the number of bits // if we have a non-zero weight, compute the number of bits
if (node->weight > 0) if (node->weight > 0)
{ {
// determine the number of bits for this node /* determine the number of bits for this node */
for (curnode = node; curnode->parent != NULL; curnode = curnode->parent) for (curnode = node; curnode->parent != NULL; curnode = curnode->parent)
node->numbits++; node->numbits++;
if (node->numbits == 0) if (node->numbits == 0)
node->numbits = 1; node->numbits = 1;
// keep track of the max /* keep track of the max */
maxbits = MAX(maxbits, ((int)node->numbits)); maxbits = MAX(maxbits, ((int)node->numbits));
} }
} }
@ -450,15 +470,17 @@ int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint
} }
//------------------------------------------------- /*-------------------------------------------------
// assign_canonical_codes - assign canonical codes * assign_canonical_codes - assign canonical codes
// to all the nodes based on the number of bits * to all the nodes based on the number of bits
// in each * in each
//------------------------------------------------- *-------------------------------------------------
*/
enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder) enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder)
{ {
// build up a histogram of bit lengths uint32_t curstart = 0;
/* build up a histogram of bit lengths */
int curcode, codelen; int curcode, codelen;
uint32_t bithisto[33] = { 0 }; uint32_t bithisto[33] = { 0 };
for (curcode = 0; curcode < decoder->numcodes; curcode++) for (curcode = 0; curcode < decoder->numcodes; curcode++)
@ -470,8 +492,7 @@ enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decode
bithisto[node->numbits]++; bithisto[node->numbits]++;
} }
// for each code length, determine the starting code number /* for each code length, determine the starting code number */
uint32_t curstart = 0;
for (codelen = 32; codelen > 0; codelen--) for (codelen = 32; codelen > 0; codelen--)
{ {
uint32_t nextstart = (curstart + bithisto[codelen]) >> 1; uint32_t nextstart = (curstart + bithisto[codelen]) >> 1;
@ -481,7 +502,7 @@ enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decode
curstart = nextstart; curstart = nextstart;
} }
// now assign canonical codes /* now assign canonical codes */
for (curcode = 0; curcode < decoder->numcodes; curcode++) for (curcode = 0; curcode < decoder->numcodes; curcode++)
{ {
struct node_t* node = &decoder->huffnode[curcode]; struct node_t* node = &decoder->huffnode[curcode];
@ -492,28 +513,32 @@ enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decode
} }
//------------------------------------------------- /*-------------------------------------------------
// build_lookup_table - build a lookup table for * build_lookup_table - build a lookup table for
// fast decoding * fast decoding
//------------------------------------------------- *-------------------------------------------------
*/
void huffman_build_lookup_table(struct huffman_decoder* decoder) void huffman_build_lookup_table(struct huffman_decoder* decoder)
{ {
// iterate over all codes /* iterate over all codes */
int curcode; int curcode;
for (curcode = 0; curcode < decoder->numcodes; curcode++) for (curcode = 0; curcode < decoder->numcodes; curcode++)
{ {
// process all nodes which have non-zero bits /* process all nodes which have non-zero bits */
struct node_t* node = &decoder->huffnode[curcode]; struct node_t* node = &decoder->huffnode[curcode];
if (node->numbits > 0) if (node->numbits > 0)
{ {
// set up the entry int shift;
lookup_value *dest;
lookup_value *destend;
/* set up the entry */
lookup_value value = MAKE_LOOKUP(curcode, node->numbits); lookup_value value = MAKE_LOOKUP(curcode, node->numbits);
// fill all matching entries /* fill all matching entries */
int shift = decoder->maxbits - node->numbits; shift = decoder->maxbits - node->numbits;
lookup_value *dest = &decoder->lookup[node->bits << shift]; dest = &decoder->lookup[node->bits << shift];
lookup_value *destend = &decoder->lookup[((node->bits + 1) << shift) - 1]; destend = &decoder->lookup[((node->bits + 1) << shift) - 1];
while (dest <= destend) while (dest <= destend)
*dest++ = value; *dest++ = value;
} }