X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=deps%2Flibchdr%2Fchd.c;h=a77a5237e7f580f6fb94b2c16ed6da3860f7c987;hb=dcd8e4fd48205ae70f8d9a353d9d3a70c0537df2;hp=bf6d3428310875031b91c39b7a492056c2258ff4;hpb=ce188d4d7f3b9ad04867c49b424e8497c2ade92b;p=pcsx_rearmed.git diff --git a/deps/libchdr/chd.c b/deps/libchdr/chd.c index bf6d3428..a77a5237 100644 --- a/deps/libchdr/chd.c +++ b/deps/libchdr/chd.c @@ -36,28 +36,21 @@ POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ -#define DONT_SET_BYTE -typedef unsigned char Byte; +#include +#include +#include +#include +#include #include "chd.h" #include "cdrom.h" -#include "huffman.h" #include "flac.h" - -#include "md5.h" -#include "sha1.h" +#include "huffman.h" #include "LzmaEnc.h" #include "LzmaDec.h" - -#include -#include - -#include -#include -#include -#include - -#include "../deps/crypto/md5.h" +#include "md5.h" +#include "sha1.h" +#include "zlib.h" #define TRUE 1 #define FALSE 0 @@ -67,16 +60,12 @@ typedef unsigned char Byte; #define SHA1_DIGEST_SIZE 20 -#define CHD_MAKE_TAG(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) - /*************************************************************************** DEBUGGING ***************************************************************************/ #define PRINTF_MAX_HUNK (0) - - /*************************************************************************** CONSTANTS ***************************************************************************/ @@ -101,63 +90,60 @@ typedef unsigned char Byte; static const uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 }; -// V3-V4 entry types +/* V3-V4 entry types */ enum { - V34_MAP_ENTRY_TYPE_INVALID = 0, // invalid type - V34_MAP_ENTRY_TYPE_COMPRESSED = 1, // standard compression - V34_MAP_ENTRY_TYPE_UNCOMPRESSED = 2, // uncompressed 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_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_INVALID = 0, /* invalid type */ + V34_MAP_ENTRY_TYPE_COMPRESSED = 1, /* standard compression */ + V34_MAP_ENTRY_TYPE_UNCOMPRESSED = 2, /* uncompressed 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_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) */ }; -// V5 compression types +/* V5 compression types */ enum { - ///< codec #0 - // these types are live when running + /* codec #0 + * these types are live when running */ COMPRESSION_TYPE_0 = 0, - ///< codec #1 + /* codec #1 */ COMPRESSION_TYPE_1 = 1, - ///< codec #2 + /* codec #2 */ COMPRESSION_TYPE_2 = 2, - ///< codec #3 + /* codec #3 */ COMPRESSION_TYPE_3 = 3, - ///< no compression; implicit length = hunkbytes + /* no compression; implicit length = hunkbytes */ COMPRESSION_NONE = 4, - ///< same as another block in this chd + /* same as another block in this chd */ 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, - ///< start of small RLE run (4-bit length) - // these additional pseudo-types are used for compressed encodings: + /* start of small RLE run (4-bit length) + * these additional pseudo-types are used for compressed encodings: */ COMPRESSION_RLE_SMALL, - ///< start of large RLE run (8-bit length) + /* start of large RLE run (8-bit length) */ COMPRESSION_RLE_LARGE, - ///< same as the last COMPRESSION_SELF block + /* same as the last COMPRESSION_SELF block */ COMPRESSION_SELF_0, - ///< same as the last COMPRESSION_SELF block + 1 + /* same as the last COMPRESSION_SELF block + 1 */ COMPRESSION_SELF_1, - ///< same block in the parent + /* same block in the parent */ COMPRESSION_PARENT_SELF, - ///< same as the last COMPRESSION_PARENT block + /* same as the last COMPRESSION_PARENT block */ COMPRESSION_PARENT_0, - ///< same as the last COMPRESSION_PARENT block + 1 + /* same as the last COMPRESSION_PARENT block + 1 */ COMPRESSION_PARENT_1 }; - /*************************************************************************** MACROS ***************************************************************************/ #define EARLY_EXIT(x) do { (void)(x); goto cleanup; } while (0) - - /*************************************************************************** TYPE DEFINITIONS ***************************************************************************/ @@ -175,7 +161,6 @@ struct _codec_interface chd_error (*config)(void *codec, int param, void *config); /* configure */ }; - /* a single map entry */ typedef struct _map_entry map_entry; struct _map_entry @@ -186,7 +171,6 @@ struct _map_entry UINT8 flags; /* misc flags */ }; - /* simple linked-list of hunks used for our CRC map */ typedef struct _crcmap_entry crcmap_entry; struct _crcmap_entry @@ -195,7 +179,6 @@ struct _crcmap_entry crcmap_entry * next; /* next entry in list */ }; - /* a single metadata entry */ typedef struct _metadata_entry metadata_entry; struct _metadata_entry @@ -214,6 +197,7 @@ typedef struct _zlib_allocator zlib_allocator; struct _zlib_allocator { UINT32 * allocptr[MAX_ZLIB_ALLOCS]; + UINT32 * allocptr2[MAX_ZLIB_ALLOCS]; }; typedef struct _zlib_codec_data zlib_codec_data; @@ -233,10 +217,11 @@ struct _lzma_allocator void (*Free)(void *p, void *address); /* address can be 0 */ void (*FreeSz)(void *p, void *address, size_t size); /* address can be 0 */ uint32_t* allocptr[MAX_LZMA_ALLOCS]; + uint32_t* allocptr2[MAX_LZMA_ALLOCS]; }; typedef struct _lzma_codec_data lzma_codec_data; -struct _lzma_codec_data +struct _lzma_codec_data { CLzmaDec decoder; lzma_allocator allocator; @@ -245,7 +230,7 @@ struct _lzma_codec_data /* codec-private data for the CDZL codec */ typedef struct _cdzl_codec_data cdzl_codec_data; struct _cdzl_codec_data { - // internal state + /* internal state */ zlib_codec_data base_decompressor; zlib_codec_data subcode_decompressor; uint8_t* buffer; @@ -254,7 +239,7 @@ struct _cdzl_codec_data { /* codec-private data for the CDLZ codec */ typedef struct _cdlz_codec_data cdlz_codec_data; struct _cdlz_codec_data { - // internal state + /* internal state */ lzma_codec_data base_decompressor; zlib_codec_data subcode_decompressor; uint8_t* buffer; @@ -263,7 +248,7 @@ struct _cdlz_codec_data { /* codec-private data for the CDFL codec */ typedef struct _cdfl_codec_data cdfl_codec_data; struct _cdfl_codec_data { - // internal state + /* internal state */ int swap_endian; flac_decoder decoder; z_stream inflater; @@ -317,10 +302,9 @@ struct _chd_file UINT32 async_hunknum; /* hunk index for asynchronous operations */ void * async_buffer; /* buffer pointer for asynchronous operations */ - UINT8 * file_cache; /* cache of underlying file */ + UINT8 * file_cache; /* cache of underlying file */ }; - /* a single metadata hash entry */ typedef struct _metadata_hash metadata_hash; struct _metadata_hash @@ -329,8 +313,6 @@ struct _metadata_hash UINT8 sha1[CHD_SHA1_BYTES]; /* hash */ }; - - /*************************************************************************** GLOBAL VARIABLES ***************************************************************************/ @@ -338,16 +320,13 @@ struct _metadata_hash static const UINT8 nullmd5[CHD_MD5_BYTES] = { 0 }; static const UINT8 nullsha1[CHD_SHA1_BYTES] = { 0 }; - - /*************************************************************************** PROTOTYPES ***************************************************************************/ /* internal header operations */ static chd_error header_validate(const chd_header *header); -static chd_error header_read(core_file *file, chd_header *header); - +static chd_error header_read(chd_file *chd, chd_header *header); /* internal hunk read/write */ static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum); @@ -359,13 +338,13 @@ static chd_error map_read(chd_file *chd); /* metadata management */ static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry); - /* zlib compression codec */ static chd_error zlib_codec_init(void *codec, uint32_t hunkbytes); static void zlib_codec_free(void *codec); static chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size); static void zlib_fast_free(voidpf opaque, voidpf address); +static void zlib_allocator_free(voidpf opaque); /* lzma compression codec */ static chd_error lzma_codec_init(void *codec, uint32_t hunkbytes); @@ -387,37 +366,41 @@ static chd_error cdfl_codec_init(void* codec, uint32_t hunkbytes); 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); -//************************************************************************** -// LZMA ALLOCATOR HELPER -//************************************************************************** +/*************************************************************************** + * LZMA ALLOCATOR HELPER + *************************************************************************** + */ void *lzma_fast_alloc(void *p, size_t size); void lzma_fast_free(void *p, void *address); -//------------------------------------------------- -// lzma_allocator_init -//------------------------------------------------- +/*------------------------------------------------- + * lzma_allocator_init + *------------------------------------------------- + */ void lzma_allocator_init(void* p) { lzma_allocator *codec = (lzma_allocator *)(p); - // reset pointer list + /* reset pointer list */ memset(codec->allocptr, 0, sizeof(codec->allocptr)); + memset(codec->allocptr2, 0, sizeof(codec->allocptr2)); codec->Alloc = lzma_fast_alloc; codec->Free = lzma_fast_free; } -//------------------------------------------------- -// lzma_allocator_free -//------------------------------------------------- +/*------------------------------------------------- + * lzma_allocator_free + *------------------------------------------------- + */ void lzma_allocator_free(void* p ) { - int i; + int i; lzma_allocator *codec = (lzma_allocator *)(p); - // free our memory + /* free our memory */ for (i = 0 ; i < MAX_LZMA_ALLOCS ; i++) { if (codec->allocptr[i] != NULL) @@ -425,112 +408,122 @@ void lzma_allocator_free(void* p ) } } -//------------------------------------------------- -// lzma_fast_alloc - fast malloc for lzma, which -// allocates and frees memory frequently -//------------------------------------------------- +/*------------------------------------------------- + * lzma_fast_alloc - fast malloc for lzma, which + * allocates and frees memory frequently + *------------------------------------------------- + */ +#define LZMA_MIN_ALIGNMENT_BITS 512 +#define LZMA_MIN_ALIGNMENT_BYTES (LZMA_MIN_ALIGNMENT_BITS / 8) void *lzma_fast_alloc(void *p, size_t size) { - int scan; - uint32_t *addr = NULL; + int scan; + uint32_t *addr = NULL; lzma_allocator *codec = (lzma_allocator *)(p); + + uintptr_t vaddr = 0; - // compute the size, rounding to the nearest 1k + /* compute the size, rounding to the nearest 1k */ size = (size + 0x3ff) & ~0x3ff; - // reuse a hunk if we can + /* reuse a hunk if we can */ for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++) { uint32_t *ptr = codec->allocptr[scan]; if (ptr != NULL && size == *ptr) { - // set the low bit of the size so we don't match next time + /* set the low bit of the size so we don't match next time */ *ptr |= 1; - return ptr + 1; + return codec->allocptr2[scan]; } } - // alloc a new one and put it into the list - addr = (uint32_t *)malloc(sizeof(uint8_t) * (size + sizeof(uint32_t))); + /* alloc a new one and put it into the list */ + addr = (uint32_t *)malloc(size + sizeof(uint32_t) + LZMA_MIN_ALIGNMENT_BYTES); if (addr==NULL) return NULL; - for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++) + for (int scan = 0; scan < MAX_LZMA_ALLOCS; scan++) { if (codec->allocptr[scan] == NULL) { codec->allocptr[scan] = addr; + vaddr = (uintptr_t)addr; + vaddr = (vaddr + sizeof(uint32_t) + (LZMA_MIN_ALIGNMENT_BYTES-1)) & (~(LZMA_MIN_ALIGNMENT_BYTES-1)); + codec->allocptr2[scan] = (uint32_t*)vaddr; break; } } - // set the low bit of the size so we don't match next time + /* set the low bit of the size so we don't match next time */ *addr = size | 1; - return addr + 1; + return (void*)vaddr; } - -//------------------------------------------------- -// lzma_fast_free - fast free for lzma, which -// allocates and frees memory frequently -//------------------------------------------------- +/*------------------------------------------------- + * lzma_fast_free - fast free for lzma, which + * allocates and frees memory frequently + *------------------------------------------------- + */ void lzma_fast_free(void *p, void *address) { - int scan; - uint32_t *ptr; - lzma_allocator *codec; + int scan; + uint32_t *ptr = NULL; + lzma_allocator *codec = NULL; + if (address == NULL) return; codec = (lzma_allocator *)(p); - // find the hunk - ptr = (uint32_t *)(address) - 1; + /* find the hunk */ + ptr = (uint32_t *)address; for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++) { - if (ptr == codec->allocptr[scan]) + if (ptr == codec->allocptr2[scan]) { - // clear the low bit of the size to allow matches - *ptr &= ~1; + /* clear the low bit of the size to allow matches */ + *codec->allocptr[scan] &= ~1; return; } } } -//************************************************************************** -// LZMA DECOMPRESSOR -//************************************************************************** - +/*************************************************************************** + * LZMA DECOMPRESSOR + *************************************************************************** + */ -//------------------------------------------------- -// lzma_codec_init - constructor -//------------------------------------------------- +/*------------------------------------------------- + * lzma_codec_init - constructor + *------------------------------------------------- + */ chd_error lzma_codec_init(void* codec, uint32_t hunkbytes) { - CLzmaEncHandle enc; + CLzmaEncHandle enc; CLzmaEncProps encoder_props; Byte decoder_props[LZMA_PROPS_SIZE]; - SizeT props_size; - lzma_allocator* alloc; + SizeT props_size; + lzma_allocator* alloc; lzma_codec_data* lzma_codec = (lzma_codec_data*) codec; - // construct the decoder + /* construct the decoder */ LzmaDec_Construct(&lzma_codec->decoder); - // 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 - // 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. + /* 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 + * 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. - // configure the properties like the compressor did + * configure the properties like the compressor did */ LzmaEncProps_Init(&encoder_props); encoder_props.level = 9; encoder_props.reduceSize = hunkbytes; LzmaEncProps_Normalize(&encoder_props); - // convert to decoder properties + /* convert to decoder properties */ alloc = &lzma_codec->allocator; lzma_allocator_init(alloc); enc = LzmaEnc_Create((ISzAlloc*)alloc); @@ -549,43 +542,44 @@ chd_error lzma_codec_init(void* codec, uint32_t hunkbytes) } 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) return CHDERR_DECOMPRESSION_ERROR; - - // Okay + + /* Okay */ return CHDERR_NONE; } - -//------------------------------------------------- -// lzma_codec_free -//------------------------------------------------- +/*------------------------------------------------- + * lzma_codec_free + *------------------------------------------------- + */ void lzma_codec_free(void* codec) { lzma_codec_data* lzma_codec = (lzma_codec_data*) codec; - // free memory + /* free memory */ LzmaDec_Free(&lzma_codec->decoder, (ISzAlloc*)&lzma_codec->allocator); + lzma_allocator_free(&lzma_codec->allocator); } - -//------------------------------------------------- -// decompress - decompress data using the LZMA -// codec -//------------------------------------------------- +/*------------------------------------------------- + * decompress - decompress data using the LZMA + * codec + *------------------------------------------------- + */ 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 + SRes res; + SizeT consumedlen, decodedlen; + /* initialize */ lzma_codec_data* lzma_codec = (lzma_codec_data*) codec; LzmaDec_Init(&lzma_codec->decoder); - // decode + /* decode */ consumedlen = complen; decodedlen = destlen; res = LzmaDec_DecodeToBuf(&lzma_codec->decoder, dest, &decodedlen, src, &consumedlen, LZMA_FINISH_END, &status); @@ -594,15 +588,15 @@ chd_error lzma_codec_decompress(void* codec, const uint8_t *src, uint32_t comple return CHDERR_NONE; } -// cdlz +/* cdlz */ chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes) { cdlz_codec_data* cdlz = (cdlz_codec_data*) codec; - // allocate buffer + /* allocate buffer */ cdlz->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes); - - // 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 */ lzma_codec_init(&cdlz->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); zlib_codec_init(&cdlz->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA); @@ -614,39 +608,42 @@ chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes) void cdlz_codec_free(void* codec) { - // TODO + cdlz_codec_data* cdlz = (cdlz_codec_data*) codec; + free(cdlz->buffer); + lzma_codec_free(&cdlz->base_decompressor); + zlib_codec_free(&cdlz->subcode_decompressor); } chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) { - uint32_t framenum; + uint32_t framenum; cdlz_codec_data* cdlz = (cdlz_codec_data*)codec; - // determine header bytes + /* determine header bytes */ uint32_t frames = destlen / CD_FRAME_SIZE; uint32_t complen_bytes = (destlen < 65536) ? 2 : 3; uint32_t ecc_bytes = (frames + 7) / 8; uint32_t header_bytes = ecc_bytes + complen_bytes; - // extract compressed length of base + /* extract compressed length of base */ uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1]; if (complen_bytes > 2) complen_base = (complen_base << 8) | src[ecc_bytes + 2]; - // reset and decode + /* reset and decode */ lzma_codec_decompress(&cdlz->base_decompressor, &src[header_bytes], complen_base, &cdlz->buffer[0], frames * CD_MAX_SECTOR_DATA); zlib_codec_decompress(&cdlz->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdlz->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA); - // reassemble the data + /* reassemble the data */ for (framenum = 0; framenum < frames; framenum++) { - uint8_t *sector; + uint8_t *sector; memcpy(&dest[framenum * CD_FRAME_SIZE], &cdlz->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdlz->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA); - // reconstitute the ECC data and sync header - sector = &dest[framenum * CD_FRAME_SIZE]; + /* reconstitute the ECC data and sync header */ + sector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE]; if ((src[framenum / 8] & (1 << (framenum % 8))) != 0) { memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header)); @@ -656,14 +653,13 @@ chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t comple return CHDERR_NONE; } - -// cdzl +/* cdzl */ chd_error cdzl_codec_init(void *codec, uint32_t hunkbytes) { cdzl_codec_data* cdzl = (cdzl_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 */ zlib_codec_init(&cdzl->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); zlib_codec_init(&cdzl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA); @@ -676,38 +672,42 @@ chd_error cdzl_codec_init(void *codec, uint32_t hunkbytes) void cdzl_codec_free(void *codec) { - // TODO + cdzl_codec_data* cdzl = (cdzl_codec_data*)codec; + zlib_codec_free(&cdzl->base_decompressor); + zlib_codec_free(&cdzl->subcode_decompressor); + free(cdzl->buffer); } chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) { - uint32_t framenum; + uint32_t framenum; cdzl_codec_data* cdzl = (cdzl_codec_data*)codec; - - // determine header bytes + + /* determine header bytes */ uint32_t frames = destlen / CD_FRAME_SIZE; uint32_t complen_bytes = (destlen < 65536) ? 2 : 3; uint32_t ecc_bytes = (frames + 7) / 8; uint32_t header_bytes = ecc_bytes + complen_bytes; - // extract compressed length of base + /* extract compressed length of base */ uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1]; if (complen_bytes > 2) complen_base = (complen_base << 8) | src[ecc_bytes + 2]; - // reset and decode + /* reset and decode */ zlib_codec_decompress(&cdzl->base_decompressor, &src[header_bytes], complen_base, &cdzl->buffer[0], frames * CD_MAX_SECTOR_DATA); zlib_codec_decompress(&cdzl->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdzl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA); - // reassemble the data + /* reassemble the data */ for (framenum = 0; framenum < frames; framenum++) { - uint8_t *sector; + uint8_t *sector; + memcpy(&dest[framenum * CD_FRAME_SIZE], &cdzl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdzl->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA); - // reconstitute the ECC data and sync header - sector = &dest[framenum * CD_FRAME_SIZE]; + /* reconstitute the ECC data and sync header */ + sector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE]; if ((src[framenum / 8] & (1 << (framenum % 8))) != 0) { memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header)); @@ -717,20 +717,20 @@ chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t comple return CHDERR_NONE; } -//************************************************************************** -// CD FLAC DECOMPRESSOR -//************************************************************************** - - +/*************************************************************************** + * CD FLAC DECOMPRESSOR + *************************************************************************** + */ -//------------------------------------------------------ -// cdfl_codec_blocksize - return the optimal block size -//------------------------------------------------------ +/*------------------------------------------------------ + * cdfl_codec_blocksize - return the optimal block size + *------------------------------------------------------ + */ static uint32_t cdfl_codec_blocksize(uint32_t bytes) { - // determine FLAC block size, which must be 16-65535 - // clamp to 2k since that's supposed to be the sweet spot + /* determine FLAC block size, which must be 16-65535 + * clamp to 2k since that's supposed to be the sweet spot */ uint32_t hunkbytes = bytes / 4; while (hunkbytes > 2048) hunkbytes /= 2; @@ -739,63 +739,70 @@ static uint32_t cdfl_codec_blocksize(uint32_t bytes) chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes) { - int zerr; + int zerr; uint16_t native_endian = 0; cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; cdfl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes); - // 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) return CHDERR_CODEC_ERROR; - // determine whether we want native or swapped samples + /* determine whether we want native or swapped samples */ *(uint8_t *)(&native_endian) = 1; cdfl->swap_endian = (native_endian & 1); - // init the inflater - cdfl->inflater.next_in = (Bytef *)cdfl; // bogus, but that's ok + /* init the inflater */ + cdfl->inflater.next_in = (Bytef *)cdfl; /* bogus, but that's ok */ cdfl->inflater.avail_in = 0; - //cdfl->allocator.install(cdfl->inflater); +#if 0 + cdfl->allocator.install(cdfl->inflater); +#endif cdfl->inflater.zalloc = zlib_fast_alloc; cdfl->inflater.zfree = zlib_fast_free; cdfl->inflater.opaque = &cdfl->allocator; zerr = inflateInit2(&cdfl->inflater, -MAX_WBITS); - // convert errors + /* convert errors */ if (zerr == Z_MEM_ERROR) return CHDERR_OUT_OF_MEMORY; else if (zerr != Z_OK) return CHDERR_CODEC_ERROR; - // init flac decoder + /* flac decoder init */ flac_decoder_init(&cdfl->decoder); - return CHDERR_NONE; } void cdfl_codec_free(void *codec) { cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; + free(cdfl->buffer); inflateEnd(&cdfl->inflater); + flac_decoder_free(&cdfl->decoder); + + /* free our fast memory */ + zlib_allocator_free(&cdfl->allocator); } chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) { - int zerr; - uint8_t *buffer; - uint32_t framenum, offset; + int zerr; + uint8_t *buffer; + uint32_t framenum, offset; cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; - // reset and decode + /* reset and decode */ 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)) return CHDERR_DECOMPRESSION_ERROR; buffer = &cdfl->buffer[0]; if (!flac_decoder_decode_interleaved(&cdfl->decoder, (int16_t *)(buffer), frames * CD_MAX_SECTOR_DATA/4, cdfl->swap_endian)) return CHDERR_DECOMPRESSION_ERROR; - // inflate the subcode data + /* inflate the subcode data */ offset = flac_decoder_finish(&cdfl->decoder); cdfl->inflater.next_in = (Bytef *)(src + offset); cdfl->inflater.avail_in = complen - offset; @@ -807,14 +814,14 @@ chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t comple if (zerr != Z_OK) return CHDERR_DECOMPRESSION_ERROR; - // do it + /* do it */ zerr = inflate(&cdfl->inflater, Z_FINISH); if (zerr != Z_STREAM_END) return CHDERR_DECOMPRESSION_ERROR; if (cdfl->inflater.total_out != frames * CD_MAX_SUBCODE_DATA) return CHDERR_DECOMPRESSION_ERROR; - // reassemble the data + /* reassemble the data */ for (framenum = 0; framenum < frames; framenum++) { memcpy(&dest[framenum * CD_FRAME_SIZE], &cdfl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); @@ -827,13 +834,6 @@ chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t comple CODEC INTERFACES ***************************************************************************/ -#define CHD_MAKE_TAG(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) - -// general codecs with CD frontend -#define CHD_CODEC_CD_ZLIB CHD_MAKE_TAG('c','d','z','l') -#define CHD_CODEC_CD_LZMA CHD_MAKE_TAG('c','d','l','z') -#define CHD_CODEC_CD_FLAC CHD_MAKE_TAG('c','d','f','l') - static const codec_interface codec_interfaces[] = { /* "none" or no compression */ @@ -869,6 +869,17 @@ static const codec_interface codec_interfaces[] = NULL }, + /* V5 zlib compression */ + { + CHD_CODEC_ZLIB, + "zlib (Deflate)", + FALSE, + zlib_codec_init, + zlib_codec_free, + zlib_codec_decompress, + NULL + }, + /* V5 CD zlib compression */ { CHD_CODEC_CD_ZLIB, @@ -878,7 +889,7 @@ static const codec_interface codec_interfaces[] = cdzl_codec_free, cdzl_codec_decompress, NULL - }, + }, /* V5 CD lzma compression */ { @@ -889,7 +900,7 @@ static const codec_interface codec_interfaces[] = cdlz_codec_free, cdlz_codec_decompress, NULL - }, + }, /* V5 CD flac compression */ { @@ -900,7 +911,7 @@ static const codec_interface codec_interfaces[] = cdfl_codec_free, cdfl_codec_decompress, NULL - }, + }, }; /*************************************************************************** @@ -918,7 +929,6 @@ static inline UINT64 get_bigendian_uint64(const UINT8 *base) ((UINT64)base[4] << 24) | ((UINT64)base[5] << 16) | ((UINT64)base[6] << 8) | (UINT64)base[7]; } - /*------------------------------------------------- put_bigendian_uint64 - write a UINT64 to the data stream in bigendian order @@ -954,7 +964,7 @@ static inline UINT64 get_bigendian_uint48(const UINT8 *base) static inline void put_bigendian_uint48(UINT8 *base, UINT64 value) { - value &= 0xffffffffffff; + value &= 0xffffffffffff; base[0] = value >> 40; base[1] = value >> 32; base[2] = value >> 24; @@ -972,27 +982,25 @@ static inline UINT32 get_bigendian_uint32(const UINT8 *base) return (base[0] << 24) | (base[1] << 16) | (base[2] << 8) | base[3]; } - /*------------------------------------------------- put_bigendian_uint32 - write a UINT32 to the data stream in bigendian order -------------------------------------------------*/ -static inline void put_bigendian_uint24(UINT8 *base, UINT32 value) +static inline void put_bigendian_uint32(UINT8 *base, UINT32 value) { - value &= 0xffffff; - base[0] = value >> 16; - base[1] = value >> 8; - base[2] = value; + base[0] = value >> 24; + base[1] = value >> 16; + base[2] = value >> 8; + base[3] = value; } - /*------------------------------------------------- put_bigendian_uint24 - write a UINT24 to the data stream in bigendian order -------------------------------------------------*/ -static inline void put_bigendian_uint32(UINT8 *base, UINT32 value) +static inline void put_bigendian_uint24(UINT8 *base, UINT32 value) { value &= 0xffffff; base[0] = value >> 16; @@ -1020,7 +1028,6 @@ static inline UINT16 get_bigendian_uint16(const UINT8 *base) return (base[0] << 8) | base[1]; } - /*------------------------------------------------- put_bigendian_uint16 - write a UINT16 to the data stream in bigendian order @@ -1032,7 +1039,6 @@ static inline void put_bigendian_uint16(UINT8 *base, UINT16 value) base[1] = value; } - /*------------------------------------------------- map_extract - extract a single map entry from the datastream @@ -1046,7 +1052,6 @@ static inline void map_extract(const UINT8 *base, map_entry *entry) entry->flags = base[15]; } - /*------------------------------------------------- map_assemble - write a single map entry to the datastream @@ -1069,7 +1074,6 @@ static inline int map_size_v5(chd_header* header) return header->hunkcount * header->mapentrybytes; } - /*------------------------------------------------- crc16 - calculate CRC16 (from hashing.cpp) -------------------------------------------------*/ @@ -1115,45 +1119,58 @@ uint16_t crc16(const void *data, uint32_t length) const uint8_t *src = (uint8_t*)data; - // fetch the current value into a local and rip through the source data + /* fetch the current value into a local and rip through the source data */ while (length-- != 0) crc = (crc << 8) ^ s_table[(crc >> 8) ^ *src++]; return crc; } +/*------------------------------------------------- + compressed - test if CHD file is compressed ++-------------------------------------------------*/ + +static inline int chd_compressed(chd_header* header) { + return header->compression[0] != CHD_CODEC_NONE; +} + /*------------------------------------------------- decompress_v5_map - decompress the v5 map -------------------------------------------------*/ static chd_error decompress_v5_map(chd_file* chd, chd_header* header) { - int hunknum; - uint8_t lastcomp = 0; + int result = 0; + int hunknum; int repcount = 0; + uint8_t lastcomp = 0; uint32_t last_self = 0; uint64_t last_parent = 0; - struct bitstream* bitbuf; - uint32_t mapbytes; - uint64_t firstoffs; - uint16_t mapcrc; - uint8_t lengthbits; - uint8_t selfbits; - uint8_t parentbits; - uint8_t *compressed; + struct bitstream* bitbuf; + uint32_t mapbytes; + uint64_t firstoffs; + uint16_t mapcrc; + uint8_t lengthbits; + uint8_t selfbits; + uint8_t parentbits; + uint8_t *compressed_ptr; uint8_t rawbuf[16]; - struct huffman_decoder* decoder; - enum huffman_error err; - uint64_t curoffset; + struct huffman_decoder* decoder; + enum huffman_error err; + uint64_t curoffset; + int rawmapsize = map_size_v5(header); - if (header->mapoffset == 0) + if (!chd_compressed(header)) { - //memset(header->rawmap, 0xff,map_size_v5(header)); - return CHDERR_READ_ERROR; + header->rawmap = (uint8_t*)malloc(rawmapsize); + int result; + core_fseek(chd->file, header->mapoffset, SEEK_SET); + result = core_fread(chd->file, header->rawmap, rawmapsize); + return CHDERR_NONE; } - // read the reader + /* read the reader */ core_fseek(chd->file, header->mapoffset, SEEK_SET); - core_fread(chd->file, rawbuf, sizeof(rawbuf)); + result = core_fread(chd->file, rawbuf, sizeof(rawbuf)); mapbytes = get_bigendian_uint32(&rawbuf[0]); firstoffs = get_bigendian_uint48(&rawbuf[4]); mapcrc = get_bigendian_uint16(&rawbuf[10]); @@ -1161,14 +1178,14 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header) selfbits = rawbuf[13]; parentbits = rawbuf[14]; - // now read the map - compressed = (uint8_t*)malloc(sizeof(uint8_t) * mapbytes); + /* now read the map */ + compressed_ptr = (uint8_t*)malloc(sizeof(uint8_t) * mapbytes); core_fseek(chd->file, header->mapoffset + 16, SEEK_SET); - core_fread(chd->file, compressed, mapbytes); - bitbuf = create_bitstream(compressed, sizeof(uint8_t) * mapbytes); - header->rawmap = (uint8_t*)malloc(sizeof(uint8_t) * map_size_v5(header)); + result = core_fread(chd->file, compressed_ptr, mapbytes); + bitbuf = create_bitstream(compressed_ptr, sizeof(uint8_t) * mapbytes); + header->rawmap = (uint8_t*)malloc(rawmapsize); - // first decode the compression types + /* first decode the compression types */ decoder = create_huffman_decoder(16, 8); err = huffman_import_tree_rle(decoder, bitbuf); if (err != HUFFERR_NONE) @@ -1190,7 +1207,7 @@ 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 */ curoffset = firstoffs; for (hunknum = 0; hunknum < header->hunkcount; hunknum++) { @@ -1200,7 +1217,7 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header) uint16_t crc = 0; switch (rawmap[0]) { - // base types + /* base types */ case COMPRESSION_TYPE_0: case COMPRESSION_TYPE_1: case COMPRESSION_TYPE_2: @@ -1223,7 +1240,7 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header) last_parent = offset; break; - // pseudo-types; convert into base types + /* pseudo-types; convert into base types */ case COMPRESSION_SELF_1: last_self++; case COMPRESSION_SELF_0: @@ -1243,17 +1260,23 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header) offset = last_parent; break; } - // UINT24 length + /* UINT24 length */ put_bigendian_uint24(&rawmap[1], length); - // UINT48 offset + /* UINT48 offset */ put_bigendian_uint48(&rawmap[4], offset); - // crc16 + /* crc16 */ put_bigendian_uint16(&rawmap[10], crc); } - // verify the final CRC + free(compressed_ptr); + free(bitbuf); + free(decoder->lookup); + free(decoder->huffnode); + free(decoder); + + /* verify the final CRC */ if (crc16(&header->rawmap[0], header->hunkcount * 12) != mapcrc) return CHDERR_DECOMPRESSION_ERROR; @@ -1278,12 +1301,10 @@ static inline void map_extract_old(const UINT8 *base, map_entry *entry, UINT32 h #endif } - /*************************************************************************** CHD FILE MANAGEMENT ***************************************************************************/ - /*------------------------------------------------- chd_open_file - open a CHD file for access -------------------------------------------------*/ @@ -1303,16 +1324,16 @@ chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file ** EARLY_EXIT(err = CHDERR_INVALID_PARAMETER); /* allocate memory for the final result */ - newchd = (chd_file *)malloc(sizeof(chd_file)); + newchd = (chd_file *)malloc(sizeof(**chd)); if (newchd == NULL) EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY); - memset(newchd, 0, sizeof(chd_file)); + memset(newchd, 0, sizeof(*newchd)); newchd->cookie = COOKIE_VALUE; newchd->parent = parent; newchd->file = file; /* now attempt to read the header */ - err = header_read(newchd->file, &newchd->header); + err = header_read(newchd, &newchd->header); if (err != CHDERR_NONE) EARLY_EXIT(err); @@ -1353,13 +1374,14 @@ chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file ** if (newchd->header.version < 5) { err = map_read(newchd); - if (err != CHDERR_NONE) - EARLY_EXIT(err); } - else + else { err = decompress_v5_map(newchd, &(newchd->header)); } + if (err != CHDERR_NONE) + EARLY_EXIT(err); + /* allocate and init the hunk cache */ newchd->cache = (UINT8 *)malloc(newchd->header.hunkbytes); @@ -1378,66 +1400,77 @@ chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file ** if (newchd->header.version < 5) { for (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++) + { if (codec_interfaces[intfnum].compression == newchd->header.compression[0]) { newchd->codecintf[0] = &codec_interfaces[intfnum]; break; } + } + if (intfnum == ARRAY_LENGTH(codec_interfaces)) EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT); /* initialize the codec */ if (newchd->codecintf[0]->init != NULL) + { err = (*newchd->codecintf[0]->init)(&newchd->zlib_codec_data, newchd->header.hunkbytes); + if (err != CHDERR_NONE) + EARLY_EXIT(err); + } } else { - int decompnum; - - // verify the compression types and initialize the codecs + int decompnum; + /* verify the compression types and initialize the codecs */ for (decompnum = 0; decompnum < ARRAY_LENGTH(newchd->header.compression); decompnum++) { - int i; + int i; for (i = 0 ; i < ARRAY_LENGTH(codec_interfaces) ; i++) { if (codec_interfaces[i].compression == newchd->header.compression[decompnum]) { newchd->codecintf[decompnum] = &codec_interfaces[i]; - if (newchd->codecintf[decompnum] == NULL && newchd->header.compression[decompnum] != 0) - err = CHDERR_UNSUPPORTED_FORMAT; - - /* initialize the codec */ - if (newchd->codecintf[decompnum]->init != NULL) - { - void* codec = NULL; - switch (newchd->header.compression[decompnum]) - { - case CHD_CODEC_CD_ZLIB: - codec = &newchd->cdzl_codec_data; - break; - - case CHD_CODEC_CD_LZMA: - codec = &newchd->cdlz_codec_data; - break; - - case CHD_CODEC_CD_FLAC: - codec = &newchd->cdfl_codec_data; - break; - } - if (codec != NULL) - { - err = (*newchd->codecintf[decompnum]->init)(codec, newchd->header.hunkbytes); - } - } + break; } } + + if (newchd->codecintf[decompnum] == NULL && newchd->header.compression[decompnum] != 0) + EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT); + + /* initialize the codec */ + if (newchd->codecintf[decompnum]->init != NULL) + { + void* codec = NULL; + switch (newchd->header.compression[decompnum]) + { + case CHD_CODEC_ZLIB: + codec = &newchd->zlib_codec_data; + break; + + case CHD_CODEC_CD_ZLIB: + codec = &newchd->cdzl_codec_data; + break; + + case CHD_CODEC_CD_LZMA: + codec = &newchd->cdlz_codec_data; + break; + + case CHD_CODEC_CD_FLAC: + codec = &newchd->cdfl_codec_data; + break; + } + + if (codec == NULL) + EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT); + + err = (*newchd->codecintf[decompnum]->init)(codec, newchd->header.hunkbytes); + if (err != CHDERR_NONE) + EARLY_EXIT(err); + } } } - // HACK - //if (err != CHDERR_NONE) - // EARLY_EXIT(err); - /* all done */ *chd = newchd; return CHDERR_NONE; @@ -1448,6 +1481,37 @@ cleanup: return err; } +/*------------------------------------------------- + chd_precache - precache underlying file in + memory +-------------------------------------------------*/ + +chd_error chd_precache(chd_file *chd) +{ + ssize_t size, count; + + if (chd->file_cache == NULL) + { + core_fseek(chd->file, 0, SEEK_END); + size = core_ftell(chd->file); + if (size <= 0) + return CHDERR_INVALID_DATA; + chd->file_cache = malloc(size); + if (chd->file_cache == NULL) + return CHDERR_OUT_OF_MEMORY; + core_fseek(chd->file, 0, SEEK_SET); + count = core_fread(chd->file, chd->file_cache, size); + if (count != size) + { + free(chd->file_cache); + chd->file_cache = NULL; + return CHDERR_READ_ERROR; + } + } + + return CHDERR_NONE; +} + /*------------------------------------------------- chd_open - open a CHD file by filename @@ -1492,32 +1556,6 @@ cleanup: return err; } -chd_error chd_precache(chd_file *chd) -{ - ssize_t size, count; - - if (chd->file_cache == NULL) - { - core_fseek(chd->file, 0, SEEK_END); - size = core_ftell(chd->file); - if (size <= 0) - return CHDERR_INVALID_DATA; - chd->file_cache = malloc(size); - if (chd->file_cache == NULL) - return CHDERR_OUT_OF_MEMORY; - core_fseek(chd->file, 0, SEEK_SET); - count = core_fread(chd->file, chd->file_cache, size); - if (count != size) - { - free(chd->file_cache); - chd->file_cache = NULL; - return CHDERR_READ_ERROR; - } - } - - return CHDERR_NONE; -} - /*------------------------------------------------- chd_close - close a CHD file for access -------------------------------------------------*/ @@ -1531,22 +1569,30 @@ void chd_close(chd_file *chd) /* deinit the codec */ if (chd->header.version < 5) { - if (chd->codecintf[0] != NULL && chd->codecintf[0]->free != NULL) - (*chd->codecintf[0]->free)(&chd->zlib_codec_data); + if (chd->codecintf[0] != NULL && chd->codecintf[0]->free != NULL) + (*chd->codecintf[0]->free)(&chd->zlib_codec_data); } else { - int i; - // Free the codecs - for (i = 0 ; i < 4 ; i++) + int i; + /* Free the codecs */ + for (i = 0 ; i < ARRAY_LENGTH(chd->codecintf); i++) { void* codec = NULL; + + if (chd->codecintf[i] == NULL) + continue; + switch (chd->codecintf[i]->compression) { case CHD_CODEC_CD_LZMA: codec = &chd->cdlz_codec_data; break; + case CHD_CODEC_ZLIB: + codec = &chd->zlib_codec_data; + break; + case CHD_CODEC_CD_ZLIB: codec = &chd->cdzl_codec_data; break; @@ -1554,14 +1600,15 @@ void chd_close(chd_file *chd) case CHD_CODEC_CD_FLAC: codec = &chd->cdfl_codec_data; break; - } + } + if (codec) { (*chd->codecintf[i]->free)(codec); } } - // Free the raw map + /* Free the raw map */ if (chd->header.rawmap != NULL) free(chd->header.rawmap); } @@ -1601,7 +1648,6 @@ void chd_close(chd_file *chd) free(chd); } - /*------------------------------------------------- chd_core_file - return the associated core_file @@ -1612,7 +1658,6 @@ core_file *chd_core_file(chd_file *chd) return chd->file; } - /*------------------------------------------------- chd_error_string - return an error string for the given CHD error @@ -1654,8 +1699,6 @@ const char *chd_error_string(chd_error err) } } - - /*************************************************************************** CHD HEADER MANAGEMENT ***************************************************************************/ @@ -1674,8 +1717,6 @@ const chd_header *chd_get_header(chd_file *chd) return &chd->header; } - - /*************************************************************************** CORE DATA READ/WRITE ***************************************************************************/ @@ -1699,10 +1740,6 @@ chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer) return hunk_read_into_memory(chd, hunknum, (UINT8 *)buffer); } - - - - /*************************************************************************** METADATA MANAGEMENT ***************************************************************************/ @@ -1762,8 +1799,6 @@ chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, return CHDERR_NONE; } - - /*************************************************************************** CODEC INTERFACES ***************************************************************************/ @@ -1775,11 +1810,9 @@ chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, chd_error chd_codec_config(chd_file *chd, int param, void *config) { - return CHDERR_INVALID_PARAMETER; } - /*------------------------------------------------- chd_get_codec_name - get the name of a particular codec @@ -1790,7 +1823,6 @@ const char *chd_get_codec_name(UINT32 codec) return "Unknown"; } - /*************************************************************************** INTERNAL HEADER OPERATIONS ***************************************************************************/ @@ -1803,11 +1835,11 @@ const char *chd_get_codec_name(UINT32 codec) static chd_error header_validate(const chd_header *header) { int intfnum; - + /* require a valid version */ if (header->version == 0 || header->version > CHD_HEADER_VERSION) return CHDERR_UNSUPPORTED_VERSION; - + /* require a valid length */ if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) || (header->version == 2 && header->length != CHD_V2_HEADER_SIZE) || @@ -1815,7 +1847,7 @@ static chd_error header_validate(const chd_header *header) (header->version == 4 && header->length != CHD_V4_HEADER_SIZE) || (header->version == 5 && header->length != CHD_V5_HEADER_SIZE)) return CHDERR_INVALID_PARAMETER; - + /* Do not validate v5 header */ if (header->version <= 4) { @@ -1859,13 +1891,38 @@ static chd_error header_validate(const chd_header *header) return CHDERR_NONE; } +/*------------------------------------------------- + header_guess_unitbytes - for older CHD formats, + guess at the bytes/unit based on metadata +-------------------------------------------------*/ + +static UINT32 header_guess_unitbytes(chd_file *chd) +{ + /* look for hard disk metadata; if found, then the unit size == sector size */ + char metadata[512]; + int i0, i1, i2, i3; + if (chd_get_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE && + sscanf(metadata, HARD_DISK_METADATA_FORMAT, &i0, &i1, &i2, &i3) == 4) + return i3; + + /* look for CD-ROM metadata; if found, then the unit size == CD frame size */ + if (chd_get_metadata(chd, CDROM_OLD_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE || + chd_get_metadata(chd, CDROM_TRACK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE || + chd_get_metadata(chd, CDROM_TRACK_METADATA2_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE || + chd_get_metadata(chd, GDROM_OLD_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE || + chd_get_metadata(chd, GDROM_TRACK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE) + return CD_FRAME_SIZE; + + /* otherwise, just map 1:1 with the hunk size */ + return chd->header.hunkbytes; +} /*------------------------------------------------- header_read - read a CHD header into the internal data structure -------------------------------------------------*/ -static chd_error header_read(core_file *file, chd_header *header) +static chd_error header_read(chd_file *chd, chd_header *header) { UINT8 rawheader[CHD_MAX_HEADER_SIZE]; UINT32 count; @@ -1875,12 +1932,12 @@ static chd_error header_read(core_file *file, chd_header *header) return CHDERR_INVALID_PARAMETER; /* punt if invalid file */ - if (file == NULL) + if (chd->file == NULL) return CHDERR_INVALID_FILE; /* seek and read */ - core_fseek(file, 0, SEEK_SET); - count = core_fread(file, rawheader, sizeof(rawheader)); + core_fseek(chd->file, 0, SEEK_SET); + count = core_fread(chd->file, rawheader, sizeof(rawheader)); if (count != sizeof(rawheader)) return CHDERR_READ_ERROR; @@ -1903,12 +1960,15 @@ static chd_error header_read(core_file *file, chd_header *header) (header->version == 3 && header->length != CHD_V3_HEADER_SIZE) || (header->version == 4 && header->length != CHD_V4_HEADER_SIZE) || (header->version == 5 && header->length != CHD_V5_HEADER_SIZE)) - + return CHDERR_INVALID_DATA; /* extract the common data */ header->flags = get_bigendian_uint32(&rawheader[16]); header->compression[0] = get_bigendian_uint32(&rawheader[20]); + header->compression[1] = CHD_CODEC_NONE; + header->compression[2] = CHD_CODEC_NONE; + header->compression[3] = CHD_CODEC_NONE; /* extract the V1/V2-specific data */ if (header->version < 3) @@ -1923,6 +1983,8 @@ static chd_error header_read(core_file *file, chd_header *header) memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES); header->logicalbytes = (UINT64)header->obsolete_cylinders * (UINT64)header->obsolete_heads * (UINT64)header->obsolete_sectors * (UINT64)seclen; header->hunkbytes = seclen * header->obsolete_hunksize; + header->unitbytes = header_guess_unitbytes(chd); + header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes; header->metaoffset = 0; } @@ -1935,6 +1997,8 @@ static chd_error header_read(core_file *file, chd_header *header) memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES); memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES); header->hunkbytes = get_bigendian_uint32(&rawheader[76]); + header->unitbytes = header_guess_unitbytes(chd); + header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes; memcpy(header->sha1, &rawheader[80], CHD_SHA1_BYTES); memcpy(header->parentsha1, &rawheader[100], CHD_SHA1_BYTES); } @@ -1946,6 +2010,8 @@ static chd_error header_read(core_file *file, chd_header *header) header->logicalbytes = get_bigendian_uint64(&rawheader[28]); header->metaoffset = get_bigendian_uint64(&rawheader[36]); header->hunkbytes = get_bigendian_uint32(&rawheader[44]); + header->unitbytes = header_guess_unitbytes(chd); + header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes; memcpy(header->sha1, &rawheader[48], CHD_SHA1_BYTES); memcpy(header->parentsha1, &rawheader[68], CHD_SHA1_BYTES); memcpy(header->rawsha1, &rawheader[88], CHD_SHA1_BYTES); @@ -1955,30 +2021,30 @@ static chd_error header_read(core_file *file, chd_header *header) else if (header->version == 5) { /* TODO */ - header->compression[0] = get_bigendian_uint32(&rawheader[16]); - header->compression[1] = get_bigendian_uint32(&rawheader[20]); - header->compression[2] = get_bigendian_uint32(&rawheader[24]); - header->compression[3] = get_bigendian_uint32(&rawheader[28]); - header->logicalbytes = get_bigendian_uint64(&rawheader[32]); - header->mapoffset = get_bigendian_uint64(&rawheader[40]); - header->metaoffset = get_bigendian_uint64(&rawheader[48]); - header->hunkbytes = get_bigendian_uint32(&rawheader[56]); - header->hunkcount = (header->logicalbytes + header->hunkbytes - 1) / header->hunkbytes; - header->unitbytes = get_bigendian_uint32(&rawheader[60]); - header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes; + header->compression[0] = get_bigendian_uint32(&rawheader[16]); + header->compression[1] = get_bigendian_uint32(&rawheader[20]); + header->compression[2] = get_bigendian_uint32(&rawheader[24]); + header->compression[3] = get_bigendian_uint32(&rawheader[28]); + header->logicalbytes = get_bigendian_uint64(&rawheader[32]); + header->mapoffset = get_bigendian_uint64(&rawheader[40]); + header->metaoffset = get_bigendian_uint64(&rawheader[48]); + header->hunkbytes = get_bigendian_uint32(&rawheader[56]); + header->hunkcount = (header->logicalbytes + header->hunkbytes - 1) / header->hunkbytes; + header->unitbytes = get_bigendian_uint32(&rawheader[60]); + header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes; memcpy(header->sha1, &rawheader[84], CHD_SHA1_BYTES); memcpy(header->parentsha1, &rawheader[104], CHD_SHA1_BYTES); memcpy(header->rawsha1, &rawheader[64], CHD_SHA1_BYTES); - // determine properties of map entries - header->mapentrybytes = 12; //TODO compressed() ? 12 : 4; + /* determine properties of map entries */ + header->mapentrybytes = chd_compressed(header) ? 12 : 4; - // hack + /* hack */ header->totalhunks = header->hunkcount; } /* Unknown version */ - else + else { /* TODO */ } @@ -1987,41 +2053,16 @@ static chd_error header_read(core_file *file, chd_header *header) return CHDERR_NONE; } - /*************************************************************************** INTERNAL HUNK READ/WRITE ***************************************************************************/ /*------------------------------------------------- - hunk_read_into_cache - read a hunk into - the CHD's hunk cache + hunk_read_compressed - read a compressed + hunk -------------------------------------------------*/ -static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum) -{ - chd_error err; - - /* track the max */ - if (hunknum > chd->maxhunk) - chd->maxhunk = hunknum; - - /* if we're already in the cache, we're done */ - if (chd->cachehunk == hunknum) - return CHDERR_NONE; - chd->cachehunk = ~0; - - /* otherwise, read the data */ - err = hunk_read_into_memory(chd, hunknum, chd->cache); - if (err != CHDERR_NONE) - return err; - - /* mark the hunk successfully cached in */ - chd->cachehunk = hunknum; - return CHDERR_NONE; -} - - -static UINT8* read_compressed(chd_file *chd, UINT64 offset, size_t size) +static UINT8* hunk_read_compressed(chd_file *chd, UINT64 offset, size_t size) { ssize_t bytes; if (chd->file_cache != NULL) @@ -2038,7 +2079,12 @@ static UINT8* read_compressed(chd_file *chd, UINT64 offset, size_t size) } } -static chd_error read_uncompressed(chd_file *chd, UINT64 offset, size_t size, UINT8 *dest) +/*------------------------------------------------- + hunk_read_uncompressed - read an uncompressed + hunk +-------------------------------------------------*/ + +static chd_error hunk_read_uncompressed(chd_file *chd, UINT64 offset, size_t size, UINT8 *dest) { ssize_t bytes; if (chd->file_cache != NULL) @@ -2055,6 +2101,34 @@ static chd_error read_uncompressed(chd_file *chd, UINT64 offset, size_t size, UI return CHDERR_NONE; } +/*------------------------------------------------- + hunk_read_into_cache - read a hunk into + the CHD's hunk cache +-------------------------------------------------*/ + +static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum) +{ + chd_error err; + + /* track the max */ + if (hunknum > chd->maxhunk) + chd->maxhunk = hunknum; + + /* if we're already in the cache, we're done */ + if (chd->cachehunk == hunknum) + return CHDERR_NONE; + chd->cachehunk = ~0; + + /* otherwise, read the data */ + err = hunk_read_into_memory(chd, hunknum, chd->cache); + if (err != CHDERR_NONE) + return err; + + /* mark the hunk successfully cached in */ + chd->cachehunk = hunknum; + return CHDERR_NONE; +} + /*------------------------------------------------- hunk_read_into_memory - read a hunk into memory at the given location @@ -2064,7 +2138,7 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des { chd_error err; - // punt if no file + /* punt if no file */ if (chd->file == NULL) return CHDERR_INVALID_FILE; @@ -2076,6 +2150,7 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des { map_entry *entry = &chd->map[hunknum]; UINT32 bytes; + UINT8* compressed_bytes; /* switch off the entry type */ switch (entry->flags & MAP_ENTRY_FLAG_TYPE_MASK) @@ -2083,24 +2158,26 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des /* compressed data */ case V34_MAP_ENTRY_TYPE_COMPRESSED: { - void* codec; - UINT8 *bytes = read_compressed(chd, entry->offset, entry->length); - if (bytes == NULL) - return CHDERR_READ_ERROR; - - /* now decompress using the codec */ - err = CHDERR_NONE; - codec = &chd->zlib_codec_data; - if (chd->codecintf[0]->decompress != NULL) - err = (*chd->codecintf[0]->decompress)(codec, bytes, entry->length, dest, chd->header.hunkbytes); - if (err != CHDERR_NONE) - return err; - } + void *codec = NULL; + + /* read it into the decompression buffer */ + compressed_bytes = hunk_read_compressed(chd, entry->offset, entry->length); + if (compressed_bytes == NULL) + return CHDERR_READ_ERROR; + + /* now decompress using the codec */ + err = CHDERR_NONE; + codec = &chd->zlib_codec_data; + if (chd->codecintf[0]->decompress != NULL) + err = (*chd->codecintf[0]->decompress)(codec, compressed_bytes, entry->length, dest, chd->header.hunkbytes); + if (err != CHDERR_NONE) + return err; break; + } /* uncompressed data */ case V34_MAP_ENTRY_TYPE_UNCOMPRESSED: - err = read_uncompressed(chd, entry->offset, chd->header.hunkbytes, dest); + err = hunk_read_uncompressed(chd, entry->offset, chd->header.hunkbytes, dest); if (err != CHDERR_NONE) return err; break; @@ -2129,43 +2206,48 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des } else { - - // get a pointer to the map entry + /* get a pointer to the map entry */ uint64_t blockoffs; uint32_t blocklen; uint16_t blockcrc; - void* codec = NULL; + void* codec = NULL; uint8_t *rawmap = &chd->header.rawmap[chd->header.mapentrybytes * hunknum]; - UINT8 *bytes; + UINT8* compressed_bytes; - // uncompressed case - /* TODO - if (!compressed()) + /* uncompressed case */ + if (!chd_compressed(&chd->header)) { - blockoffs = uint64_t(be_read(rawmap, 4)) * uint64_t(m_hunkbytes); - if (blockoffs != 0) - file_read(blockoffs, dest, m_hunkbytes); + blockoffs = (uint64_t)get_bigendian_uint32(rawmap) * (uint64_t)chd->header.hunkbytes; + if (blockoffs != 0) { + int result; + core_fseek(chd->file, blockoffs, SEEK_SET); + result = core_fread(chd->file, dest, chd->header.hunkbytes); + /* TODO else if (m_parent_missing) - throw CHDERR_REQUIRES_PARENT; - else if (m_parent != nullptr) - m_parent->read_hunk(hunknum, dest); - else - memset(dest, 0, m_hunkbytes); + throw CHDERR_REQUIRES_PARENT; */ + } else if (chd->parent) { + err = hunk_read_into_memory(chd->parent, hunknum, dest); + if (err != CHDERR_NONE) + return err; + } else { + memset(dest, 0, chd->header.hunkbytes); + } return CHDERR_NONE; - }*/ + } - // compressed case + /* compressed case */ blocklen = get_bigendian_uint24(&rawmap[1]); blockoffs = get_bigendian_uint48(&rawmap[4]); blockcrc = get_bigendian_uint16(&rawmap[10]); + codec = NULL; switch (rawmap[0]) { case COMPRESSION_TYPE_0: case COMPRESSION_TYPE_1: case COMPRESSION_TYPE_2: case COMPRESSION_TYPE_3: - bytes = read_compressed(chd, blockoffs, blocklen); - if (bytes == NULL) + compressed_bytes = hunk_read_compressed(chd, blockoffs, blocklen); + if (compressed_bytes == NULL) return CHDERR_READ_ERROR; switch (chd->codecintf[rawmap[0]]->compression) { @@ -2173,6 +2255,10 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des codec = &chd->cdlz_codec_data; break; + case CHD_CODEC_ZLIB: + codec = &chd->zlib_codec_data; + break; + case CHD_CODEC_CD_ZLIB: codec = &chd->cdzl_codec_data; break; @@ -2183,13 +2269,13 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des } if (codec==NULL) return CHDERR_DECOMPRESSION_ERROR; - chd->codecintf[rawmap[0]]->decompress(codec, bytes, blocklen, dest, chd->header.hunkbytes); + chd->codecintf[rawmap[0]]->decompress(codec, compressed_bytes, blocklen, dest, chd->header.hunkbytes); if (dest != NULL && crc16(dest, chd->header.hunkbytes) != blockcrc) return CHDERR_DECOMPRESSION_ERROR; return CHDERR_NONE; case COMPRESSION_NONE: - err = read_uncompressed(chd, blockoffs, blocklen, dest); + err = hunk_read_uncompressed(chd, blockoffs, blocklen, dest); if (err != CHDERR_NONE) return err; if (crc16(dest, chd->header.hunkbytes) != blockcrc) @@ -2200,20 +2286,21 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des return hunk_read_into_memory(chd, blockoffs, dest); case COMPRESSION_PARENT: - // TODO - //if (m_parent_missing) - // return CHDERR_REQUIRES_PARENT; - //return m_parent->read_bytes(uint64_t(blockoffs) * uint64_t(m_parent->unit_bytes()), dest, m_hunkbytes); +#if 0 + /* TODO */ + if (m_parent_missing) + 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_NONE; } - // We should not reach this code + /* We should not reach this code */ return CHDERR_DECOMPRESSION_ERROR; } - /*************************************************************************** INTERNAL MAP ACCESS ***************************************************************************/ @@ -2299,9 +2386,6 @@ cleanup: return err; } - - - /*************************************************************************** INTERNAL METADATA ACCESS ***************************************************************************/ @@ -2351,8 +2435,6 @@ static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metai return CHDERR_METADATA_NOT_FOUND; } - - /*************************************************************************** ZLIB COMPRESSION CODEC ***************************************************************************/ @@ -2393,7 +2475,6 @@ static chd_error zlib_codec_init(void *codec, uint32_t hunkbytes) return err; } - /*------------------------------------------------- zlib_codec_free - free data for the ZLIB codec @@ -2407,21 +2488,16 @@ static void zlib_codec_free(void *codec) if (data != NULL) { int i; - zlib_allocator alloc; inflateEnd(&data->inflater); /* free our fast memory */ - alloc = data->allocator; - for (i = 0; i < MAX_ZLIB_ALLOCS; i++) - if (alloc.allocptr[i]) - free(alloc.allocptr[i]); + zlib_allocator_free(&data->allocator); } } - /*------------------------------------------------- - zlib_codec_decompress - decomrpess data using + zlib_codec_decompress - decompress data using the ZLIB codec -------------------------------------------------*/ @@ -2449,15 +2525,17 @@ static chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t return CHDERR_NONE; } - /*------------------------------------------------- zlib_fast_alloc - fast malloc for ZLIB, which allocates and frees memory frequently -------------------------------------------------*/ +#define ZLIB_MIN_ALIGNMENT_BITS 512 +#define ZLIB_MIN_ALIGNMENT_BYTES (ZLIB_MIN_ALIGNMENT_BITS / 8) static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size) { zlib_allocator *alloc = (zlib_allocator *)opaque; + uintptr_t paddr = 0; UINT32 *ptr; int i; @@ -2472,12 +2550,12 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size) { /* set the low bit of the size so we don't match next time */ *ptr |= 1; - return ptr + 1; + return (voidpf)(alloc->allocptr2[i]); } } /* alloc a new one */ - ptr = (UINT32 *)malloc(size + sizeof(UINT32)); + ptr = (UINT32 *)malloc(size + sizeof(UINT32) + ZLIB_MIN_ALIGNMENT_BYTES); if (!ptr) return NULL; @@ -2486,15 +2564,16 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size) if (!alloc->allocptr[i]) { alloc->allocptr[i] = ptr; + paddr = (((uintptr_t)ptr) + sizeof(UINT32) + (ZLIB_MIN_ALIGNMENT_BYTES-1)) & (~(ZLIB_MIN_ALIGNMENT_BYTES-1)); + alloc->allocptr2[i] = (uint32_t*)paddr; break; } /* set the low bit of the size so we don't match next time */ *ptr = size | 1; - return ptr + 1; + return (voidpf)paddr; } - /*------------------------------------------------- zlib_fast_free - fast free for ZLIB, which allocates and frees memory frequently @@ -2503,15 +2582,28 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size) static void zlib_fast_free(voidpf opaque, voidpf address) { zlib_allocator *alloc = (zlib_allocator *)opaque; - UINT32 *ptr = (UINT32 *)address - 1; + UINT32 *ptr = (UINT32 *)address; int i; /* find the hunk */ for (i = 0; i < MAX_ZLIB_ALLOCS; i++) - if (ptr == alloc->allocptr[i]) + if (ptr == alloc->allocptr2[i]) { /* clear the low bit of the size to allow matches */ - *ptr &= ~1; + *(alloc->allocptr[i]) &= ~1; return; } } + +/*------------------------------------------------- + zlib_allocator_free +-------------------------------------------------*/ +static void zlib_allocator_free(voidpf opaque) +{ + zlib_allocator *alloc = (zlib_allocator *)opaque; + int i; + + for (i = 0; i < MAX_ZLIB_ALLOCS; i++) + if (alloc->allocptr[i]) + free(alloc->allocptr[i]); +}