From 12afd64d62088cb2dc5111cb8bd081a16a56aecd Mon Sep 17 00:00:00 2001 From: sonninnos Date: Tue, 14 May 2024 07:33:52 +0300 Subject: [PATCH 1/3] Libretro: Update audio before video_cb --- libretro/libretro.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libretro/libretro.c b/libretro/libretro.c index 11ecfba97..0d07ea931 100644 --- a/libretro/libretro.c +++ b/libretro/libretro.c @@ -3806,6 +3806,8 @@ void retro_run(void) bool updated = false; int vwoffset = 0; int bmdoffset = 0; + int soundbuffer_size = 0; + is_running = true; #ifdef HAVE_OVERCLOCK @@ -3894,6 +3896,8 @@ void retro_run(void) system_frame_sms(do_skip); } + soundbuffer_size = audio_update(soundbuffer); + if (bitmap.viewport.changed & 9) { bool geometry_updated = update_viewport(); @@ -3956,7 +3960,7 @@ void retro_run(void) video_cb(NULL, vwidth - vwoffset, vheight, 720 * 2); } - audio_cb(soundbuffer, audio_update(soundbuffer)); + audio_cb(soundbuffer, soundbuffer_size); } #undef CHUNKSIZE From a1b8039c3599311c231803e66ebbfef7fa2f1858 Mon Sep 17 00:00:00 2001 From: sonninnos Date: Tue, 14 May 2024 20:32:12 +0300 Subject: [PATCH 2/3] Remove warning in blip_buf.c --- core/sound/blip_buf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/sound/blip_buf.c b/core/sound/blip_buf.c index 812676160..1a47157d8 100644 --- a/core/sound/blip_buf.c +++ b/core/sound/blip_buf.c @@ -86,7 +86,7 @@ struct blip_t #define BLIP_BUFFER_STATE_BUFFER_SIZE 16 -typedef struct blip_buffer_state_t +struct blip_buffer_state_t { fixed_t offset; #ifdef BLIP_MONO From f00b1d1e3e29d0209506178b0c41946e3da37b50 Mon Sep 17 00:00:00 2001 From: sonninnos Date: Tue, 14 May 2024 22:27:51 +0300 Subject: [PATCH 3/3] libchdr update + precache option --- core/cd_hw/cdd.c | 10 + core/cd_hw/libchdr/src/bitstream.c | 14 +- core/cd_hw/libchdr/src/bitstream.h | 2 +- core/cd_hw/libchdr/src/cdrom.c | 53 +- core/cd_hw/libchdr/src/cdrom.h | 56 +- core/cd_hw/libchdr/src/chd.c | 666 ++++++++++++++---------- core/cd_hw/libchdr/src/chd.h | 73 ++- core/cd_hw/libchdr/src/flac.c | 272 +++++----- core/cd_hw/libchdr/src/flac.h | 51 +- core/cd_hw/libchdr/src/huffman.c | 64 ++- core/cd_hw/libchdr/src/huffman.h | 70 +-- libretro/deps/libchdr/src/libchdr_chd.c | 2 +- libretro/libretro.c | 15 +- libretro/libretro_core_options.h | 18 +- libretro/osd.h | 2 + 15 files changed, 781 insertions(+), 587 deletions(-) diff --git a/core/cd_hw/cdd.c b/core/cd_hw/cdd.c index 54275341c..cc5e65dbf 100644 --- a/core/cd_hw/cdd.c +++ b/core/cd_hw/cdd.c @@ -397,6 +397,16 @@ int cdd_load(char *filename, char *header) return -1; } +#ifdef __LIBRETRO__ + if (config.cd_precache) + { + log_cb(RETRO_LOG_INFO, "Pre-caching \"%s\" ...\n", filename); + if (chd_precache(cdd.chd.file) != CHDERR_NONE) + return -1; + log_cb(RETRO_LOG_INFO, "Pre-cache done.\n"); + } +#endif + /* retrieve CHD header */ head = chd_get_header(cdd.chd.file); diff --git a/core/cd_hw/libchdr/src/bitstream.c b/core/cd_hw/libchdr/src/bitstream.c index 922d8aa32..c82a67ddc 100644 --- a/core/cd_hw/libchdr/src/bitstream.c +++ b/core/cd_hw/libchdr/src/bitstream.c @@ -1,7 +1,6 @@ /* license:BSD-3-Clause - * copyright-holders:Aaron Giles - */ -/*************************************************************************** + * copyright-holders:Aaron Giles +*************************************************************************** bitstream.c @@ -9,8 +8,8 @@ ***************************************************************************/ -#include "bitstream.h" #include +#include /*************************************************************************** * INLINE FUNCTIONS @@ -108,9 +107,10 @@ uint32_t bitstream_read_offset(struct bitstream* bitstream) } -//------------------------------------------------- -// flush - flush to the nearest byte -//------------------------------------------------- +/*------------------------------------------------- + * flush - flush to the nearest byte + *------------------------------------------------- + */ uint32_t bitstream_flush(struct bitstream* bitstream) { diff --git a/core/cd_hw/libchdr/src/bitstream.h b/core/cd_hw/libchdr/src/bitstream.h index a30a9f2ff..d376373b7 100644 --- a/core/cd_hw/libchdr/src/bitstream.h +++ b/core/cd_hw/libchdr/src/bitstream.h @@ -1,6 +1,6 @@ /* license:BSD-3-Clause * copyright-holders:Aaron Giles - *************************************************************************** +*************************************************************************** bitstream.h diff --git a/core/cd_hw/libchdr/src/cdrom.c b/core/cd_hw/libchdr/src/cdrom.c index 159b358fd..44fa66466 100644 --- a/core/cd_hw/libchdr/src/cdrom.c +++ b/core/cd_hw/libchdr/src/cdrom.c @@ -1,6 +1,6 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles -/*************************************************************************** +/* license:BSD-3-Clause + * copyright-holders:Aaron Giles +*************************************************************************** cdrom.c @@ -15,12 +15,12 @@ schemes will differ after track 1! ***************************************************************************/ -#ifdef WANT_RAW_DATA_SECTOR - #include #include -#include "cdrom.h" +#include + +#ifdef WANT_RAW_DATA_SECTOR /*************************************************************************** DEBUGGING @@ -64,8 +64,6 @@ void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2); #define LOG(x) #endif - - /*************************************************************************** CONSTANTS ***************************************************************************/ @@ -92,8 +90,6 @@ void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2); /** @brief 43 bytes each. */ #define ECC_Q_COMP 43 - - /** * @brief ------------------------------------------------- * ECC lookup tables pre-calculated tables for ECC data calcs @@ -301,16 +297,16 @@ static const uint16_t qoffsets[ECC_Q_NUM_BYTES][ECC_Q_COMP] = { 0x867,0x003,0x05b,0x0b3,0x10b,0x163,0x1bb,0x213,0x26b,0x2c3,0x31b,0x373,0x3cb,0x423,0x47b,0x4d3,0x52b,0x583,0x5db,0x633,0x68b,0x6e3,0x73b,0x793,0x7eb,0x843,0x89b,0x037,0x08f,0x0e7,0x13f,0x197,0x1ef,0x247,0x29f,0x2f7,0x34f,0x3a7,0x3ff,0x457,0x4af,0x507,0x55f } }; +/*------------------------------------------------- + * ecc_source_byte - return data from the sector + * at the given offset, masking anything + * particular to a mode + *------------------------------------------------- + */ -//------------------------------------------------- -// ecc_source_byte - return data from the sector -// at the given offset, masking anything -// particular to a mode -//------------------------------------------------- - -static inline uint8_t ecc_source_byte(const uint8_t *sector, uint32_t offset) +INLINE uint8_t ecc_source_byte(const uint8_t *sector, uint32_t offset) { - // in mode 2 always treat these as 0 bytes + /* in mode 2 always treat these as 0 bytes */ return (sector[MODE_OFFSET] == 2 && offset < 4) ? 0x00 : sector[SYNC_OFFSET + SYNC_NUM_BYTES + offset]; } @@ -330,8 +326,9 @@ static inline uint8_t ecc_source_byte(const uint8_t *sector, uint32_t offset) void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, uint8_t *val1, uint8_t *val2) { + int component; *val1 = *val2 = 0; - for (int component = 0; component < rowlen; component++) + for (component = 0; component < rowlen; component++) { *val1 ^= ecc_source_byte(sector, row[component]); *val2 ^= ecc_source_byte(sector, row[component]); @@ -355,8 +352,9 @@ void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, u int ecc_verify(const uint8_t *sector) { - // first verify P bytes - for (int byte = 0; byte < ECC_P_NUM_BYTES; byte++) + int byte; + /* first verify P bytes */ + for (byte = 0; byte < ECC_P_NUM_BYTES; byte++) { uint8_t val1, val2; ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, &val1, &val2); @@ -364,8 +362,8 @@ int ecc_verify(const uint8_t *sector) return 0; } - // then verify Q bytes - for (int byte = 0; byte < ECC_Q_NUM_BYTES; byte++) + /* then verify Q bytes */ + for (byte = 0; byte < ECC_Q_NUM_BYTES; byte++) { uint8_t val1, val2; ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, &val1, &val2); @@ -388,12 +386,13 @@ int ecc_verify(const uint8_t *sector) void ecc_generate(uint8_t *sector) { - // first verify P bytes - for (int byte = 0; byte < ECC_P_NUM_BYTES; byte++) + int byte; + /* first verify P bytes */ + for (byte = 0; byte < ECC_P_NUM_BYTES; byte++) ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, §or[ECC_P_OFFSET + byte], §or[ECC_P_OFFSET + ECC_P_NUM_BYTES + byte]); - // then verify Q bytes - for (int byte = 0; byte < ECC_Q_NUM_BYTES; byte++) + /* then verify Q bytes */ + for (byte = 0; byte < ECC_Q_NUM_BYTES; byte++) ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, §or[ECC_Q_OFFSET + byte], §or[ECC_Q_OFFSET + ECC_Q_NUM_BYTES + byte]); } diff --git a/core/cd_hw/libchdr/src/cdrom.h b/core/cd_hw/libchdr/src/cdrom.h index 609492f5a..5bd4a2e02 100644 --- a/core/cd_hw/libchdr/src/cdrom.h +++ b/core/cd_hw/libchdr/src/cdrom.h @@ -1,6 +1,6 @@ -/* license:BSD-3-Clause */ -/* copyright-holders:Aaron Giles */ -/*************************************************************************** +/* license:BSD-3-Clause + * copyright-holders:Aaron Giles +*************************************************************************** cdrom.h @@ -14,15 +14,14 @@ #define __CDROM_H__ #include - +#include /*************************************************************************** CONSTANTS ***************************************************************************/ /* tracks are padded to a multiple of this many frames */ -#define CD_TRACK_PADDING (4) - +#define CD_TRACK_PADDING (4) #define CD_MAX_TRACKS (99) /* AFAIK the theoretical limit */ #define CD_MAX_SECTOR_DATA (2352) #define CD_MAX_SUBCODE_DATA (96) @@ -53,8 +52,8 @@ enum CD_SUB_NONE /* no subcode data stored */ }; -#define CD_FLAG_GDROM 0x00000001 // disc is a GD-ROM, all tracks should be stored with GD-ROM metadata -#define CD_FLAG_GDROMLE 0x00000002 // legacy GD-ROM, with little-endian CDDA data +#define CD_FLAG_GDROM 0x00000001 /* disc is a GD-ROM, all tracks should be stored with GD-ROM metadata */ +#define CD_FLAG_GDROMLE 0x00000002 /* legacy GD-ROM, with little-endian CDDA data */ /*************************************************************************** FUNCTION PROTOTYPES @@ -67,4 +66,45 @@ void ecc_generate(uint8_t *sector); void ecc_clear(uint8_t *sector); #endif + + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +INLINE uint32_t msf_to_lba(uint32_t msf) +{ + return ( ((msf&0x00ff0000)>>16) * 60 * 75) + (((msf&0x0000ff00)>>8) * 75) + ((msf&0x000000ff)>>0); +} + +INLINE uint32_t lba_to_msf(uint32_t lba) +{ + uint8_t m, s, f; + + m = lba / (60 * 75); + lba -= m * (60 * 75); + s = lba / 75; + f = lba % 75; + + return ((m / 10) << 20) | ((m % 10) << 16) | + ((s / 10) << 12) | ((s % 10) << 8) | + ((f / 10) << 4) | ((f % 10) << 0); +} + +/** + * segacd needs it like this.. investigate + * Angelo also says PCE tracks often start playing at the + * wrong address.. related? + **/ +INLINE uint32_t lba_to_msf_alt(int lba) +{ + uint32_t ret = 0; + + ret |= ((lba / (60 * 75))&0xff)<<16; + ret |= (((lba / 75) % 60)&0xff)<<8; + ret |= ((lba % 75)&0xff)<<0; + + return ret; +} + #endif /* __CDROM_H__ */ diff --git a/core/cd_hw/libchdr/src/chd.c b/core/cd_hw/libchdr/src/chd.c index a2ad056fa..632426ee7 100644 --- a/core/cd_hw/libchdr/src/chd.c +++ b/core/cd_hw/libchdr/src/chd.c @@ -41,13 +41,13 @@ #include #include #include -#include "types.h" -#include "osd.h" -#include "macros.h" -#include "chd.h" -#include "cdrom.h" -#include "flac.h" -#include "huffman.h" +#include + +#include +#include +#include +#include + #include "zlib.h" #include "LzmaEnc.h" #include "LzmaDec.h" @@ -62,7 +62,7 @@ #define MAX(x, y) (((x) > (y)) ? (x) : (y)) #define MIN(x, y) (((x) < (y)) ? (x) : (y)) -#define CHD_MAKE_TAG(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) +#define SHA1_DIGEST_SIZE 20 /*************************************************************************** DEBUGGING @@ -70,8 +70,6 @@ #define PRINTF_MAX_HUNK (0) - - /*************************************************************************** CONSTANTS ***************************************************************************/ @@ -145,15 +143,12 @@ enum COMPRESSION_PARENT_1 }; - /*************************************************************************** MACROS ***************************************************************************/ #define EARLY_EXIT(x) do { (void)(x); goto cleanup; } while (0) - - /*************************************************************************** TYPE DEFINITIONS ***************************************************************************/ @@ -171,7 +166,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 @@ -182,7 +176,6 @@ struct _map_entry UINT8 flags; /* misc flags */ }; - /* a single metadata entry */ typedef struct _metadata_entry metadata_entry; struct _metadata_entry @@ -297,6 +290,8 @@ struct _chd_file #ifdef NEED_CACHE_HUNK UINT32 maxhunk; /* maximum hunk accessed */ #endif + + UINT8 * file_cache; /* cache of underlying file */ }; @@ -307,16 +302,13 @@ struct _chd_file 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 */ #ifdef NEED_CACHE_HUNK @@ -330,13 +322,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); @@ -363,15 +355,15 @@ static chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t *************************************************************************** */ -void *lzma_fast_alloc(void *p, size_t size); -void lzma_fast_free(void *p, void *address); +static void *lzma_fast_alloc(void *p, size_t size); +static void lzma_fast_free(void *p, void *address); /*------------------------------------------------- * lzma_allocator_init *------------------------------------------------- */ -void lzma_allocator_init(void* p) +static void lzma_allocator_init(void* p) { lzma_allocator *codec = (lzma_allocator *)(p); @@ -387,12 +379,12 @@ void lzma_allocator_init(void* p) *------------------------------------------------- */ -void lzma_allocator_free(void* p ) +static void lzma_allocator_free(void* p ) { + int i; lzma_allocator *codec = (lzma_allocator *)(p); /* free our memory */ - int i; for (i = 0 ; i < MAX_LZMA_ALLOCS ; i++) { if (codec->allocptr[i] != NULL) @@ -410,7 +402,7 @@ void lzma_allocator_free(void* p ) #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) +static void *lzma_fast_alloc(void *p, size_t size) { int scan; uint32_t *addr = NULL; @@ -466,7 +458,7 @@ void *lzma_fast_alloc(void *p, size_t size) *------------------------------------------------- */ -void lzma_fast_free(void *p, void *address) +static void lzma_fast_free(void *p, void *address) { int scan; uint32_t *ptr = NULL; @@ -495,19 +487,18 @@ void lzma_fast_free(void *p, void *address) *************************************************************************** */ - /*------------------------------------------------- * lzma_codec_init - constructor *------------------------------------------------- */ -chd_error lzma_codec_init(void* codec, uint32_t hunkbytes) +static chd_error lzma_codec_init(void* codec, uint32_t hunkbytes) { + CLzmaEncHandle enc; CLzmaEncProps encoder_props; - CLzmaEncHandle enc; Byte decoder_props[LZMA_PROPS_SIZE]; - lzma_allocator* alloc; - SizeT props_size; + SizeT props_size; + lzma_allocator* alloc; lzma_codec_data* lzma_codec = (lzma_codec_data*) codec; /* construct the decoder */ @@ -546,39 +537,36 @@ chd_error lzma_codec_init(void* codec, uint32_t hunkbytes) /* do memory allocations */ if (LzmaDec_Allocate(&lzma_codec->decoder, decoder_props, LZMA_PROPS_SIZE, (ISzAlloc*)alloc) != SZ_OK) return CHDERR_DECOMPRESSION_ERROR; - + /* Okay */ return CHDERR_NONE; } - /*------------------------------------------------- * lzma_codec_free *------------------------------------------------- */ -void lzma_codec_free(void* codec) +static void lzma_codec_free(void* codec) { lzma_codec_data* lzma_codec = (lzma_codec_data*) codec; - lzma_allocator* alloc = &lzma_codec->allocator; /* free memory */ - lzma_allocator_free(alloc); LzmaDec_Free(&lzma_codec->decoder, (ISzAlloc*)&lzma_codec->allocator); + lzma_allocator_free(&lzma_codec->allocator); } - /*------------------------------------------------- * 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) +static 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; + SRes res; + SizeT consumedlen, decodedlen; /* initialize */ lzma_codec_data* lzma_codec = (lzma_codec_data*) codec; LzmaDec_Init(&lzma_codec->decoder); @@ -593,7 +581,7 @@ chd_error lzma_codec_decompress(void* codec, const uint8_t *src, uint32_t comple } /* cdlz */ -chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes) +static chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes) { chd_error ret; cdlz_codec_data* cdlz = (cdlz_codec_data*) codec; @@ -602,33 +590,35 @@ chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes) cdlz->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes); if (cdlz->buffer == NULL) return CHDERR_OUT_OF_MEMORY; - + + /* make sure the CHD's hunk size is an even multiple of the frame size */ ret = lzma_codec_init(&cdlz->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); if (ret != CHDERR_NONE) return ret; #ifdef WANT_SUBCODE - ret = zlib_codec_init(&cdlz->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); + ret = zlib_codec_init(&cdlz->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA); if (ret != CHDERR_NONE) return ret; #endif + if (hunkbytes % CD_FRAME_SIZE != 0) + return CHDERR_CODEC_ERROR; + return CHDERR_NONE; } -void cdlz_codec_free(void* codec) +static void cdlz_codec_free(void* codec) { cdlz_codec_data* cdlz = (cdlz_codec_data*) codec; - + free(cdlz->buffer); lzma_codec_free(&cdlz->base_decompressor); #ifdef WANT_SUBCODE zlib_codec_free(&cdlz->subcode_decompressor); #endif - if (cdlz->buffer) - free(cdlz->buffer); } -chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +static chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) { uint32_t framenum; cdlz_codec_data* cdlz = (cdlz_codec_data*)codec; @@ -653,6 +643,8 @@ chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t comple /* reassemble the data */ for (framenum = 0; framenum < frames; framenum++) { + uint8_t *sector; + memcpy(&dest[framenum * CD_FRAME_SIZE], &cdlz->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); #ifdef WANT_SUBCODE 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); @@ -660,7 +652,7 @@ chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t comple #ifdef WANT_RAW_DATA_SECTOR /* reconstitute the ECC data and sync header */ - uint8_t *sector = &dest[framenum * CD_FRAME_SIZE]; + 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)); @@ -671,10 +663,9 @@ chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t comple return CHDERR_NONE; } - /* cdzl */ -chd_error cdzl_codec_init(void *codec, uint32_t hunkbytes) +static chd_error cdzl_codec_init(void *codec, uint32_t hunkbytes) { chd_error ret; cdzl_codec_data* cdzl = (cdzl_codec_data*)codec; @@ -692,7 +683,7 @@ chd_error cdzl_codec_init(void *codec, uint32_t hunkbytes) return ret; #ifdef WANT_SUBCODE - ret = zlib_codec_init(&cdzl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); + ret = zlib_codec_init(&cdzl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA); if (ret != CHDERR_NONE) return ret; #endif @@ -700,19 +691,17 @@ chd_error cdzl_codec_init(void *codec, uint32_t hunkbytes) return CHDERR_NONE; } -void cdzl_codec_free(void *codec) +static void cdzl_codec_free(void *codec) { cdzl_codec_data* cdzl = (cdzl_codec_data*)codec; - zlib_codec_free(&cdzl->base_decompressor); #ifdef WANT_SUBCODE zlib_codec_free(&cdzl->subcode_decompressor); #endif - if (cdzl->buffer) - free(cdzl->buffer); + free(cdzl->buffer); } -chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +static chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) { uint32_t framenum; cdzl_codec_data* cdzl = (cdzl_codec_data*)codec; @@ -737,6 +726,8 @@ chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t comple /* reassemble the data */ for (framenum = 0; framenum < frames; framenum++) { + uint8_t *sector; + memcpy(&dest[framenum * CD_FRAME_SIZE], &cdzl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); #ifdef WANT_SUBCODE 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); @@ -744,7 +735,7 @@ chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t comple #ifdef WANT_RAW_DATA_SECTOR /* reconstitute the ECC data and sync header */ - uint8_t *sector = &dest[framenum * CD_FRAME_SIZE]; + 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)); @@ -760,8 +751,6 @@ chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t comple *************************************************************************** */ - - /*------------------------------------------------------ * cdfl_codec_blocksize - return the optimal block size *------------------------------------------------------ @@ -777,12 +766,12 @@ static uint32_t cdfl_codec_blocksize(uint32_t bytes) return hunkbytes; } -chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes) +static chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes) { #ifdef WANT_SUBCODE - chd_error ret; + chd_error ret; #endif - uint16_t native_endian = 0; + uint16_t native_endian = 0; cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; /* make sure the CHD's hunk size is an even multiple of the frame size */ @@ -805,14 +794,13 @@ chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes) #endif /* flac decoder init */ - flac_decoder_init(&cdfl->decoder); - if (cdfl->decoder.decoder == NULL) + if (flac_decoder_init(&cdfl->decoder)) return CHDERR_OUT_OF_MEMORY; return CHDERR_NONE; } -void cdfl_codec_free(void *codec) +static void cdfl_codec_free(void *codec) { cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; flac_decoder_free(&cdfl->decoder); @@ -823,13 +811,13 @@ void cdfl_codec_free(void *codec) free(cdfl->buffer); } -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) { uint32_t framenum; - uint8_t *buffer; + uint8_t *buffer; #ifdef WANT_SUBCODE - uint32_t offset; - chd_error ret; + uint32_t offset; + chd_error ret; #endif cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; @@ -867,13 +855,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 */ @@ -909,6 +890,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, @@ -918,7 +910,7 @@ static const codec_interface codec_interfaces[] = cdzl_codec_free, cdzl_codec_decompress, NULL - }, + }, /* V5 CD lzma compression */ { @@ -929,7 +921,7 @@ static const codec_interface codec_interfaces[] = cdlz_codec_free, cdlz_codec_decompress, NULL - }, + }, /* V5 CD flac compression */ { @@ -940,7 +932,7 @@ static const codec_interface codec_interfaces[] = cdfl_codec_free, cdfl_codec_decompress, NULL - }, + }, }; /*************************************************************************** @@ -958,7 +950,6 @@ 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 @@ -994,7 +985,7 @@ INLINE UINT64 get_bigendian_uint48(const UINT8 *base) 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; @@ -1012,27 +1003,25 @@ 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 -------------------------------------------------*/ -INLINE void put_bigendian_uint24(UINT8 *base, UINT32 value) +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 -------------------------------------------------*/ -INLINE void put_bigendian_uint32(UINT8 *base, UINT32 value) +INLINE void put_bigendian_uint24(UINT8 *base, UINT32 value) { value &= 0xffffff; base[0] = value >> 16; @@ -1060,7 +1049,6 @@ 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 @@ -1072,7 +1060,6 @@ INLINE void put_bigendian_uint16(UINT8 *base, UINT16 value) base[1] = value; } - /*------------------------------------------------- map_extract - extract a single map entry from the datastream @@ -1086,7 +1073,6 @@ INLINE void map_extract(const UINT8 *base, map_entry *entry) entry->flags = base[15]; } - /*------------------------------------------------- map_assemble - write a single map entry to the datastream @@ -1109,7 +1095,6 @@ INLINE int map_size_v5(chd_header* header) return header->hunkcount * header->mapentrybytes; } - /*------------------------------------------------- crc16 - calculate CRC16 (from hashing.cpp) -------------------------------------------------*/ @@ -1161,37 +1146,50 @@ uint16_t crc16(const void *data, uint32_t length) return crc; } +/*------------------------------------------------- + compressed - test if CHD file is compressed ++-------------------------------------------------*/ +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) { - uint8_t rawbuf[16]; - uint16_t mapcrc; - uint32_t mapbytes; - uint64_t firstoffs; + int result = 0; + int hunknum; + int repcount = 0; + uint8_t lastcomp = 0; 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) + 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; + int rawmapsize = map_size_v5(header); + + if (!chd_compressed(header)) { -#if 0 - memset(header->rawmap, 0xff,map_size_v5(header)); -#endif - return CHDERR_READ_ERROR; + header->rawmap = (uint8_t*)malloc(rawmapsize); + core_fseek(chd->file, header->mapoffset, SEEK_SET); + result = core_fread(chd->file, header->rawmap, rawmapsize); + return CHDERR_NONE; } /* 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]); @@ -1200,32 +1198,17 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header) parentbits = rawbuf[14]; /* now read the map */ - compressed = (uint8_t*)malloc(sizeof(uint8_t) * mapbytes); - if (compressed == NULL) - return CHDERR_OUT_OF_MEMORY; - + 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); - if (bitbuf == NULL) - { - free(compressed); - return CHDERR_OUT_OF_MEMORY; - } - - header->rawmap = (uint8_t*)malloc(sizeof(uint8_t) * map_size_v5(header)); - if (header->rawmap == NULL) - { - free(compressed); - free(bitbuf); - return CHDERR_OUT_OF_MEMORY; - } + 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 */ decoder = create_huffman_decoder(16, 8); if (decoder == NULL) { - free(compressed); + free(compressed_ptr); free(bitbuf); return CHDERR_OUT_OF_MEMORY; } @@ -1233,7 +1216,7 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header) err = huffman_import_tree_rle(decoder, bitbuf); if (err != HUFFERR_NONE) { - free(compressed); + free(compressed_ptr); free(bitbuf); delete_huffman_decoder(decoder); return CHDERR_DECOMPRESSION_ERROR; @@ -1320,7 +1303,7 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header) } /* free memory */ - free(compressed); + free(compressed_ptr); free(bitbuf); delete_huffman_decoder(decoder); @@ -1349,17 +1332,15 @@ INLINE void map_extract_old(const UINT8 *base, map_entry *entry, UINT32 hunkbyte #endif } - /*************************************************************************** CHD FILE MANAGEMENT ***************************************************************************/ - /*------------------------------------------------- chd_open_file - open a CHD file for access -------------------------------------------------*/ -chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **chd) +CHD_EXPORT chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **chd) { chd_file *newchd = NULL; chd_error err; @@ -1383,7 +1364,7 @@ chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file ** 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); @@ -1427,13 +1408,15 @@ chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file ** if (err != CHDERR_NONE) EARLY_EXIT(err); } - else + else { err = decompress_v5_map(newchd, &(newchd->header)); } + if (err != CHDERR_NONE) + EARLY_EXIT(err); #ifdef NEED_CACHE_HUNK - /* allocate and init the hunk cache */ + /* allocate and init the hunk cache */ newchd->cache = (UINT8 *)malloc(newchd->header.hunkbytes); newchd->compare = (UINT8 *)malloc(newchd->header.hunkbytes); if (newchd->cache == NULL || newchd->compare == NULL) @@ -1451,65 +1434,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 i, decompnum; + int decompnum; /* verify the compression types and initialize the codecs */ for (decompnum = 0; decompnum < ARRAY_LENGTH(newchd->header.compression); decompnum++) { + 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); + } } } -#if 0 - /* HACK */ - if (err != CHDERR_NONE) - EARLY_EXIT(err); -#endif - /* all done */ *chd = newchd; return CHDERR_NONE; @@ -1520,12 +1515,47 @@ chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file ** return err; } +/*------------------------------------------------- + chd_precache - precache underlying file in + memory +-------------------------------------------------*/ + +CHD_EXPORT chd_error chd_precache(chd_file *chd) +{ +#ifdef _MSC_VER + size_t size, count; +#else + ssize_t size, count; +#endif + + 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 -------------------------------------------------*/ -chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd) +CHD_EXPORT chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd) { chd_error err; core_file *file = NULL; @@ -1563,12 +1593,11 @@ chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file ** return err; } - /*------------------------------------------------- chd_close - close a CHD file for access -------------------------------------------------*/ -void chd_close(chd_file *chd) +CHD_EXPORT void chd_close(chd_file *chd) { /* punt if NULL or invalid */ if (chd == NULL || chd->cookie != COOKIE_VALUE) @@ -1584,15 +1613,23 @@ void chd_close(chd_file *chd) { int i; /* Free the codecs */ - for (i = 0 ; i < 4 ; i++) + 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; @@ -1601,6 +1638,7 @@ void chd_close(chd_file *chd) codec = &chd->cdfl_codec_data; break; } + if (codec) { (*chd->codecintf[i]->free)(codec); @@ -1635,29 +1673,29 @@ void chd_close(chd_file *chd) #ifdef NEED_CACHE_HUNK if (PRINTF_MAX_HUNK) printf("Max hunk = %d/%d\n", chd->maxhunk, chd->header.totalhunks); #endif + if (chd->file_cache) + free(chd->file_cache); /* free our memory */ free(chd); } - /*------------------------------------------------- chd_core_file - return the associated core_file -------------------------------------------------*/ -core_file *chd_core_file(chd_file *chd) +CHD_EXPORT core_file *chd_core_file(chd_file *chd) { return chd->file; } - /*------------------------------------------------- chd_error_string - return an error string for the given CHD error -------------------------------------------------*/ -const char *chd_error_string(chd_error err) +CHD_EXPORT const char *chd_error_string(chd_error err) { switch (err) { @@ -1693,8 +1731,6 @@ const char *chd_error_string(chd_error err) } } - - /*************************************************************************** CHD HEADER MANAGEMENT ***************************************************************************/ @@ -1704,7 +1740,7 @@ const char *chd_error_string(chd_error err) extracted header data -------------------------------------------------*/ -const chd_header *chd_get_header(chd_file *chd) +CHD_EXPORT const chd_header *chd_get_header(chd_file *chd) { /* punt if NULL or invalid */ if (chd == NULL || chd->cookie != COOKIE_VALUE) @@ -1713,8 +1749,6 @@ const chd_header *chd_get_header(chd_file *chd) return &chd->header; } - - /*************************************************************************** CORE DATA READ/WRITE ***************************************************************************/ @@ -1724,20 +1758,20 @@ const chd_header *chd_get_header(chd_file *chd) file -------------------------------------------------*/ -chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer) +CHD_EXPORT chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer) { /* punt if NULL or invalid */ if (chd == NULL || chd->cookie != COOKIE_VALUE) return CHDERR_INVALID_PARAMETER; + /* if we're past the end, fail */ + if (hunknum >= chd->header.totalhunks) + return CHDERR_HUNK_OUT_OF_RANGE; + /* perform the read */ return hunk_read_into_memory(chd, hunknum, (UINT8 *)buffer); } - - - - /*************************************************************************** METADATA MANAGEMENT ***************************************************************************/ @@ -1747,7 +1781,7 @@ chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer) of the given type -------------------------------------------------*/ -chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 *resultlen, UINT32 *resulttag, UINT8 *resultflags) +CHD_EXPORT chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 *resultlen, UINT32 *resulttag, UINT8 *resultflags) { metadata_entry metaentry; chd_error err; @@ -1797,8 +1831,6 @@ chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, return CHDERR_NONE; } - - /*************************************************************************** CODEC INTERFACES ***************************************************************************/ @@ -1808,23 +1840,21 @@ chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, parameters -------------------------------------------------*/ -chd_error chd_codec_config(chd_file *chd, int param, void *config) +CHD_EXPORT 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 -------------------------------------------------*/ -const char *chd_get_codec_name(UINT32 codec) +CHD_EXPORT const char *chd_get_codec_name(UINT32 codec) { return "Unknown"; } - /*************************************************************************** INTERNAL HEADER OPERATIONS ***************************************************************************/ @@ -1893,13 +1923,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; @@ -1909,12 +1964,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; @@ -1943,6 +1998,9 @@ static chd_error header_read(core_file *file, chd_header *header) /* 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) @@ -1957,6 +2015,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; } @@ -1969,6 +2029,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); } @@ -1980,6 +2042,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); @@ -1989,30 +2053,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; */ + header->mapentrybytes = chd_compressed(header) ? 12 : 4; /* hack */ header->totalhunks = header->hunkcount; } /* Unknown version */ - else + else { /* TODO */ } @@ -2021,11 +2085,62 @@ static chd_error header_read(core_file *file, chd_header *header) return CHDERR_NONE; } - /*************************************************************************** INTERNAL HUNK READ/WRITE ***************************************************************************/ +/*------------------------------------------------- + hunk_read_compressed - read a compressed + hunk +-------------------------------------------------*/ + +static UINT8* hunk_read_compressed(chd_file *chd, UINT64 offset, size_t size) +{ +#ifdef _MSC_VER + size_t bytes; +#else + ssize_t bytes; +#endif + if (chd->file_cache != NULL) + { + return chd->file_cache + offset; + } + else + { + core_fseek(chd->file, offset, SEEK_SET); + bytes = core_fread(chd->file, chd->compressed, size); + if (bytes != size) + return NULL; + return chd->compressed; + } +} + +/*------------------------------------------------- + hunk_read_uncompressed - read an uncompressed + hunk +-------------------------------------------------*/ + +static chd_error hunk_read_uncompressed(chd_file *chd, UINT64 offset, size_t size, UINT8 *dest) +{ +#ifdef _MSC_VER + size_t bytes; +#else + ssize_t bytes; +#endif + if (chd->file_cache != NULL) + { + memcpy(dest, chd->file_cache + offset, size); + } + else + { + core_fseek(chd->file, offset, SEEK_SET); + bytes = core_fread(chd->file, dest, size); + if (bytes != size) + return CHDERR_READ_ERROR; + } + return CHDERR_NONE; +} + #ifdef NEED_CACHE_HUNK /*------------------------------------------------- hunk_read_into_cache - read a hunk into @@ -2078,37 +2193,38 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des if (chd->header.version < 5) { - void* codec; map_entry *entry = &chd->map[hunknum]; UINT32 bytes; + UINT8* compressed_bytes; /* switch off the entry type */ switch (entry->flags & MAP_ENTRY_FLAG_TYPE_MASK) { /* compressed data */ case V34_MAP_ENTRY_TYPE_COMPRESSED: + { + void *codec = NULL; /* read it into the decompression buffer */ - core_fseek(chd->file, entry->offset, SEEK_SET); - bytes = core_fread(chd->file, chd->compressed, entry->length); - if (bytes != entry->length) + 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; + err = CHDERR_NONE; codec = &chd->zlib_codec_data; 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, compressed_bytes, entry->length, dest, chd->header.hunkbytes); if (err != CHDERR_NONE) return err; break; + } /* uncompressed data */ case V34_MAP_ENTRY_TYPE_UNCOMPRESSED: - core_fseek(chd->file, entry->offset, SEEK_SET); - bytes = core_fread(chd->file, dest, chd->header.hunkbytes); - if (bytes != chd->header.hunkbytes) - return CHDERR_READ_ERROR; + err = hunk_read_uncompressed(chd, entry->offset, chd->header.hunkbytes, dest); + if (err != CHDERR_NONE) + return err; break; /* mini-compressed data */ @@ -2145,22 +2261,29 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des uint16_t blockcrc; #endif uint8_t *rawmap = &chd->header.rawmap[chd->header.mapentrybytes * hunknum]; + UINT8* compressed_bytes; /* uncompressed case */ - /* TODO - if (!compressed()) + 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 */ blocklen = get_bigendian_uint24(&rawmap[1]); @@ -2168,20 +2291,26 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des #ifdef VERIFY_BLOCK_CRC blockcrc = get_bigendian_uint16(&rawmap[10]); #endif + codec = NULL; switch (rawmap[0]) { case COMPRESSION_TYPE_0: case COMPRESSION_TYPE_1: case COMPRESSION_TYPE_2: case COMPRESSION_TYPE_3: - core_fseek(chd->file, blockoffs, SEEK_SET); - core_fread(chd->file, chd->compressed, blocklen); + compressed_bytes = hunk_read_compressed(chd, blockoffs, blocklen); + if (compressed_bytes == NULL) + return CHDERR_READ_ERROR; switch (chd->codecintf[rawmap[0]]->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; @@ -2192,7 +2321,7 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des } if (codec==NULL) return CHDERR_CODEC_ERROR; - err = (*chd->codecintf[rawmap[0]]->decompress)(codec, chd->compressed, blocklen, dest, chd->header.hunkbytes); + err = chd->codecintf[rawmap[0]]->decompress(codec, compressed_bytes, blocklen, dest, chd->header.hunkbytes); if (err != CHDERR_NONE) return err; #ifdef VERIFY_BLOCK_CRC @@ -2202,8 +2331,9 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des return CHDERR_NONE; case COMPRESSION_NONE: - core_fseek(chd->file, blockoffs, SEEK_SET); - core_fread(chd->file, dest, chd->header.hunkbytes); + err = hunk_read_uncompressed(chd, blockoffs, blocklen, dest); + if (err != CHDERR_NONE) + return err; #ifdef VERIFY_BLOCK_CRC if (crc16(dest, chd->header.hunkbytes) != blockcrc) return CHDERR_DECOMPRESSION_ERROR; @@ -2214,11 +2344,11 @@ 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 0 - 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); + /* 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; } @@ -2229,20 +2359,10 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des return CHDERR_DECOMPRESSION_ERROR; } - /*************************************************************************** INTERNAL MAP ACCESS ***************************************************************************/ -static size_t core_fsize(core_file *f) -{ - long rv,p = ftell(f); - fseek(f, 0, SEEK_END); - rv = ftell(f); - fseek(f, p, SEEK_SET); - return rv; -} - /*------------------------------------------------- map_read - read the initial sector map -------------------------------------------------*/ @@ -2324,9 +2444,6 @@ static chd_error map_read(chd_file *chd) return err; } - - - /*************************************************************************** INTERNAL METADATA ACCESS ***************************************************************************/ @@ -2376,8 +2493,6 @@ static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metai return CHDERR_METADATA_NOT_FOUND; } - - /*************************************************************************** ZLIB COMPRESSION CODEC ***************************************************************************/ @@ -2411,10 +2526,13 @@ static chd_error zlib_codec_init(void *codec, uint32_t hunkbytes) else err = CHDERR_NONE; + /* handle an error */ + if (err != CHDERR_NONE) + zlib_codec_free(data); + return err; } - /*------------------------------------------------- zlib_codec_free - free data for the ZLIB codec @@ -2428,21 +2546,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 -------------------------------------------------*/ @@ -2470,7 +2583,6 @@ 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 @@ -2526,7 +2638,6 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size) return (voidpf)paddr; } - /*------------------------------------------------- zlib_fast_free - fast free for ZLIB, which allocates and frees memory frequently @@ -2547,3 +2658,16 @@ static void zlib_fast_free(voidpf opaque, voidpf address) 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]); +} diff --git a/core/cd_hw/libchdr/src/chd.h b/core/cd_hw/libchdr/src/chd.h index 4fe3e6411..61b149dcf 100644 --- a/core/cd_hw/libchdr/src/chd.h +++ b/core/cd_hw/libchdr/src/chd.h @@ -46,8 +46,8 @@ extern "C" { #endif -#include "coretypes.h" - +#include +#include /*************************************************************************** @@ -194,12 +194,21 @@ extern "C" { #define CHDFLAGS_IS_WRITEABLE 0x00000002 #define CHDFLAGS_UNDEFINED 0xfffffffc +#define CHD_MAKE_TAG(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) + /* compression types */ #define CHDCOMPRESSION_NONE 0 #define CHDCOMPRESSION_ZLIB 1 #define CHDCOMPRESSION_ZLIB_PLUS 2 #define CHDCOMPRESSION_AV 3 +#define CHD_CODEC_NONE 0 +#define CHD_CODEC_ZLIB CHD_MAKE_TAG('z','l','i','b') +/* 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') + /* A/V codec configuration parameters */ #define AV_CODEC_COMPRESS_CONFIG 1 #define AV_CODEC_DECOMPRESS_CONFIG 2 @@ -212,33 +221,34 @@ extern "C" { #define CHD_MDFLAGS_CHECKSUM 0x01 /* indicates data is checksummed */ /* standard hard disk metadata */ -#define HARD_DISK_METADATA_TAG 0x47444444 /* 'GDDD' */ +#define HARD_DISK_METADATA_TAG CHD_MAKE_TAG('G','D','D','D') #define HARD_DISK_METADATA_FORMAT "CYLS:%d,HEADS:%d,SECS:%d,BPS:%d" /* hard disk identify information */ -#define HARD_DISK_IDENT_METADATA_TAG 0x49444e54 /* 'IDNT' */ +#define HARD_DISK_IDENT_METADATA_TAG CHD_MAKE_TAG('I','D','N','T') /* hard disk key information */ -#define HARD_DISK_KEY_METADATA_TAG 0x4b455920 /* 'KEY ' */ +#define HARD_DISK_KEY_METADATA_TAG CHD_MAKE_TAG('K','E','Y',' ') /* pcmcia CIS information */ -#define PCMCIA_CIS_METADATA_TAG 0x43495320 /* 'CIS ' */ +#define PCMCIA_CIS_METADATA_TAG CHD_MAKE_TAG('C','I','S',' ') /* standard CD-ROM metadata */ -#define CDROM_OLD_METADATA_TAG 0x43484344 /* 'CHCD' */ -#define CDROM_TRACK_METADATA_TAG 0x43485452 /* 'CHTR' */ +#define CDROM_OLD_METADATA_TAG CHD_MAKE_TAG('C','H','C','D') +#define CDROM_TRACK_METADATA_TAG CHD_MAKE_TAG('C','H','T','R') #define CDROM_TRACK_METADATA_FORMAT "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d" -#define CDROM_TRACK_METADATA2_TAG 0x43485432 /* 'CHT2' */ +#define CDROM_TRACK_METADATA2_TAG CHD_MAKE_TAG('C','H','T','2') #define CDROM_TRACK_METADATA2_FORMAT "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d" -#define GDROM_TRACK_METADATA_TAG 0x43484744 /* 'CHTD' */ +#define GDROM_OLD_METADATA_TAG CHD_MAKE_TAG('C','H','G','T') +#define GDROM_TRACK_METADATA_TAG CHD_MAKE_TAG('C', 'H', 'G', 'D') #define GDROM_TRACK_METADATA_FORMAT "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PAD:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d" /* standard A/V metadata */ -#define AV_METADATA_TAG 0x41564156 /* 'AVAV' */ +#define AV_METADATA_TAG CHD_MAKE_TAG('A','V','A','V') #define AV_METADATA_FORMAT "FPS:%d.%06d WIDTH:%d HEIGHT:%d INTERLACED:%d CHANNELS:%d SAMPLERATE:%d" /* A/V laserdisc frame metadata */ -#define AV_LD_METADATA_TAG 0x41564C44 /* 'AVLD' */ +#define AV_LD_METADATA_TAG CHD_MAKE_TAG('A','V','L','D') /* CHD open values */ #define CHD_OPEN_READ 1 @@ -305,9 +315,9 @@ struct _chd_header UINT8 parentmd5[CHD_MD5_BYTES]; /* overall MD5 checksum of parent */ UINT8 sha1[CHD_SHA1_BYTES]; /* overall SHA1 checksum */ UINT8 rawsha1[CHD_SHA1_BYTES]; /* SHA1 checksum of raw data */ - UINT8 parentsha1[CHD_SHA1_BYTES]; /* overall SHA1 checksum of parent */ + UINT8 parentsha1[CHD_SHA1_BYTES]; /* overall SHA1 checksum of parent */ UINT32 unitbytes; /* TODO V5 */ - UINT64 unitcount; /* TODO V5 */ + UINT64 unitcount; /* TODO V5 */ UINT32 hunkcount; /* TODO V5 */ /* map information */ @@ -337,6 +347,19 @@ struct _chd_verify_result FUNCTION PROTOTYPES ***************************************************************************/ +#ifdef _MSC_VER +#ifdef CHD_DLL +#ifdef CHD_DLL_EXPORTS +#define CHD_EXPORT __declspec(dllexport) +#else +#define CHD_EXPORT __declspec(dllimport) +#endif +#else +#define CHD_EXPORT +#endif +#else +#define CHD_EXPORT __attribute__ ((visibility("default"))) +#endif /* ----- CHD file management ----- */ @@ -347,25 +370,27 @@ struct _chd_verify_result /* chd_error chd_create_file(core_file *file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent); */ /* open an existing CHD file */ -chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **chd); -chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd); +CHD_EXPORT chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **chd); +CHD_EXPORT chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd); +/* precache underlying file */ +CHD_EXPORT chd_error chd_precache(chd_file *chd); /* close a CHD file */ -void chd_close(chd_file *chd); +CHD_EXPORT void chd_close(chd_file *chd); /* return the associated core_file */ -core_file *chd_core_file(chd_file *chd); +CHD_EXPORT core_file *chd_core_file(chd_file *chd); /* return an error string for the given CHD error */ -const char *chd_error_string(chd_error err); +CHD_EXPORT const char *chd_error_string(chd_error err); /* ----- CHD header management ----- */ /* return a pointer to the extracted CHD header data */ -const chd_header *chd_get_header(chd_file *chd); +CHD_EXPORT const chd_header *chd_get_header(chd_file *chd); @@ -373,14 +398,14 @@ const chd_header *chd_get_header(chd_file *chd); /* ----- core data read/write ----- */ /* read one hunk from the CHD file */ -chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer); +CHD_EXPORT chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer); /* ----- metadata management ----- */ /* get indexed metadata of a particular sort */ -chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 *resultlen, UINT32 *resulttag, UINT8 *resultflags); +CHD_EXPORT chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 *resultlen, UINT32 *resulttag, UINT8 *resultflags); @@ -388,10 +413,10 @@ chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, /* ----- codec interfaces ----- */ /* set internal codec parameters */ -chd_error chd_codec_config(chd_file *chd, int param, void *config); +CHD_EXPORT chd_error chd_codec_config(chd_file *chd, int param, void *config); /* return a string description of a codec */ -const char *chd_get_codec_name(UINT32 codec); +CHD_EXPORT const char *chd_get_codec_name(UINT32 codec); #ifdef __cplusplus } diff --git a/core/cd_hw/libchdr/src/flac.c b/core/cd_hw/libchdr/src/flac.c index 281980fb4..4ded43ba4 100644 --- a/core/cd_hw/libchdr/src/flac.c +++ b/core/cd_hw/libchdr/src/flac.c @@ -1,6 +1,6 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles -/*************************************************************************** +/* license:BSD-3-Clause + * copyright-holders:Aaron Giles +*************************************************************************** flac.c @@ -10,28 +10,35 @@ #include #include -#include "flac.h" -//************************************************************************** -// FLAC DECODER -//************************************************************************** +#include +#define DR_FLAC_IMPLEMENTATION +#include + +/*************************************************************************** + * FLAC DECODER + *************************************************************************** + */ -static FLAC__StreamDecoderReadStatus flac_decoder_read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); -FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC__byte buffer[], size_t *bytes); -static void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); -static FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); -static 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(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 size_t flac_decoder_read_callback(void *userdata, void *buffer, size_t bytes); +static drflac_bool32 flac_decoder_seek_callback(void *userdata, int offset, drflac_seek_origin origin); +static void flac_decoder_metadata_callback(void *userdata, drflac_metadata *metadata); +static void flac_decoder_write_callback(void *userdata, void *buffer, size_t len); + + +/* getters (valid after reset) */ +static uint32_t sample_rate(flac_decoder *decoder) { return decoder->sample_rate; } +static uint8_t channels(flac_decoder *decoder) { return decoder->channels; } +static uint8_t bits_per_sample(flac_decoder *decoder) { return decoder->bits_per_sample; } /*------------------------------------------------- * flac_decoder - constructor *------------------------------------------------- */ -void flac_decoder_init(flac_decoder *decoder) +int flac_decoder_init(flac_decoder *decoder) { - decoder->decoder = FLAC__stream_decoder_new(); + decoder->decoder = NULL; decoder->sample_rate = 0; decoder->channels = 0; decoder->bits_per_sample = 0; @@ -43,6 +50,7 @@ void flac_decoder_init(flac_decoder *decoder) decoder->uncompressed_offset = 0; decoder->uncompressed_length = 0; decoder->uncompressed_swap = 0; + return 0; } /*------------------------------------------------- @@ -53,10 +61,10 @@ void flac_decoder_init(flac_decoder *decoder) void flac_decoder_free(flac_decoder* decoder) { if ((decoder != NULL) && (decoder->decoder != NULL)) - FLAC__stream_decoder_delete(decoder->decoder); + drflac_close(decoder->decoder); + decoder->decoder = NULL; } - /*------------------------------------------------- * reset - reset state with the original * parameters @@ -66,21 +74,13 @@ void flac_decoder_free(flac_decoder* decoder) static int flac_decoder_internal_reset(flac_decoder* decoder) { decoder->compressed_offset = 0; - if (FLAC__stream_decoder_init_stream(decoder->decoder, - &flac_decoder_read_callback_static, - NULL, - &flac_decoder_tell_callback_static, - NULL, - NULL, - &flac_decoder_write_callback_static, - &flac_decoder_metadata_callback_static, - &flac_decoder_error_callback_static, decoder) != FLAC__STREAM_DECODER_INIT_STATUS_OK) - return 0; - return FLAC__stream_decoder_process_until_end_of_metadata(decoder->decoder); + flac_decoder_free(decoder); + decoder->decoder = drflac_open_with_metadata( + flac_decoder_read_callback, flac_decoder_seek_callback, + flac_decoder_metadata_callback, decoder, NULL); + return (decoder->decoder != NULL); } - - /*------------------------------------------------- * reset - reset state with new memory parameters * and a custom-generated header @@ -94,43 +94,46 @@ int flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_ { 0x66, 0x4C, 0x61, 0x43, /* +00: 'fLaC' stream header */ 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, /* +08: minimum block size */ 0x00, 0x00, /* +0A: maximum block size */ 0x00, 0x00, 0x00, /* +0C: minimum 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), */ - /* numchannels (2), sample bits (16), */ - /* samples in stream (0 == unknown) */ + /* numchannels (2), sample bits (16), */ + /* 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 /* */ - /* +2A: start of stream data */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* +2A: start of stream data */ }; 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[0x09] = decoder->custom_header[0x0b] = block_size & 0xff; + decoder->custom_header[0x08] = decoder->custom_header[0x0a] = (block_size*num_channels) >> 8; + decoder->custom_header[0x09] = decoder->custom_header[0x0b] = (block_size*num_channels) & 0xff; decoder->custom_header[0x12] = sample_rate >> 12; decoder->custom_header[0x13] = sample_rate >> 4; decoder->custom_header[0x14] = (sample_rate << 4) | ((num_channels - 1) << 1); /* configure the header ahead of the provided buffer */ - decoder->compressed_start = (const FLAC__byte *)(decoder->custom_header); + decoder->compressed_start = (const uint8_t *)(decoder->custom_header); decoder->compressed_length = sizeof(decoder->custom_header); - decoder->compressed2_start = (const FLAC__byte *)(buffer); + decoder->compressed2_start = (const uint8_t *)(buffer); decoder->compressed2_length = length; return flac_decoder_internal_reset(decoder); } - /*------------------------------------------------- * decode_interleaved - decode to an interleaved * sound stream *------------------------------------------------- */ +#define BUFFER 2352 /* bytes per CD audio sector */ + int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian) { + int16_t buffer[BUFFER]; + uint32_t buf_samples; + /* configure the uncompressed buffer */ memset(decoder->uncompressed_start, 0, sizeof(decoder->uncompressed_start)); decoder->uncompressed_start[0] = samples; @@ -138,45 +141,18 @@ int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uin decoder->uncompressed_length = num_samples; decoder->uncompressed_swap = swap_endian; + buf_samples = BUFFER / channels(decoder); /* loop until we get everything we want */ - while (decoder->uncompressed_offset < decoder->uncompressed_length) - if (!FLAC__stream_decoder_process_single(decoder->decoder)) + while (decoder->uncompressed_offset < decoder->uncompressed_length) { + uint32_t frames = (num_samples < buf_samples ? num_samples : buf_samples); + if (!drflac_read_pcm_frames_s16(decoder->decoder, frames, buffer)) return 0; + flac_decoder_write_callback(decoder, buffer, frames*sizeof(*buffer)*channels(decoder)); + num_samples -= frames; + } return 1; } - -#if 0 -/* - *------------------------------------------------- - * decode - decode to an multiple independent - * data streams - *------------------------------------------------- - */ - -bool flac_decoder::decode(int16_t **samples, uint32_t num_samples, bool swap_endian) -{ - /* make sure we don't have too many channels */ - int chans = channels(); - if (chans > ARRAY_LENGTH(m_uncompressed_start)) - return false; - - /* configure the uncompressed buffer */ - memset(m_uncompressed_start, 0, sizeof(m_uncompressed_start)); - for (int curchan = 0; curchan < chans; curchan++) - m_uncompressed_start[curchan] = samples[curchan]; - m_uncompressed_offset = 0; - m_uncompressed_length = num_samples; - m_uncompressed_swap = swap_endian; - - /* loop until we get everything we want */ - while (m_uncompressed_offset < m_uncompressed_length) - if (!FLAC__stream_decoder_process_single(m_decoder)) - return false; - return true; -} -#endif - /*------------------------------------------------- * finish - finish up the decode *------------------------------------------------- @@ -185,19 +161,24 @@ bool flac_decoder::decode(int16_t **samples, uint32_t num_samples, bool swap_end uint32_t flac_decoder_finish(flac_decoder* decoder) { /* get the final decoding position and move forward */ - FLAC__uint64 position = 0; - FLAC__stream_decoder_get_decode_position(decoder->decoder, &position); - FLAC__stream_decoder_finish(decoder->decoder); + drflac *flac = decoder->decoder; + uint64_t position = decoder->compressed_offset; + + /* ugh... there's no function to obtain bytes used in drflac :-/ */ + position -= DRFLAC_CACHE_L2_LINES_REMAINING(&flac->bs) * sizeof(drflac_cache_t); + position -= DRFLAC_CACHE_L1_BITS_REMAINING(&flac->bs) / 8; + position -= flac->bs.unalignedByteCount; /* adjust position if we provided the header */ if (position == 0) return 0; - if (decoder->compressed_start == (const FLAC__byte *)(decoder->custom_header)) + if (decoder->compressed_start == (const uint8_t *)(decoder->custom_header)) position -= decoder->compressed_length; + + flac_decoder_free(decoder); return position; } - /*------------------------------------------------- * read_callback - handle reads from the input * stream @@ -206,128 +187,119 @@ uint32_t flac_decoder_finish(flac_decoder* decoder) #define MIN(x, y) ((x) < (y) ? (x) : (y)) -FLAC__StreamDecoderReadStatus flac_decoder_read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) +static size_t flac_decoder_read_callback(void *userdata, void *buffer, size_t bytes) { - return flac_decoder_read_callback(client_data, buffer, bytes); -} - -FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC__byte buffer[], size_t *bytes) -{ - flac_decoder* decoder = (flac_decoder*)client_data; - - uint32_t expected = *bytes; + flac_decoder* decoder = (flac_decoder*)userdata; + uint8_t *dst = buffer; /* copy from primary buffer first */ uint32_t outputpos = 0; - if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length) + if (outputpos < bytes && decoder->compressed_offset < decoder->compressed_length) { - uint32_t bytes_to_copy = MIN(*bytes - outputpos, decoder->compressed_length - decoder->compressed_offset); - memcpy(&buffer[outputpos], decoder->compressed_start + decoder->compressed_offset, bytes_to_copy); + uint32_t bytes_to_copy = MIN(bytes - outputpos, decoder->compressed_length - decoder->compressed_offset); + memcpy(&dst[outputpos], decoder->compressed_start + decoder->compressed_offset, bytes_to_copy); outputpos += bytes_to_copy; decoder->compressed_offset += bytes_to_copy; } /* 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)); - memcpy(&buffer[outputpos], decoder->compressed2_start + decoder->compressed_offset - decoder->compressed_length, bytes_to_copy); + uint32_t bytes_to_copy = MIN(bytes - outputpos, decoder->compressed2_length - (decoder->compressed_offset - decoder->compressed_length)); + memcpy(&dst[outputpos], decoder->compressed2_start + decoder->compressed_offset - decoder->compressed_length, bytes_to_copy); outputpos += bytes_to_copy; decoder->compressed_offset += bytes_to_copy; } - *bytes = outputpos; - /* 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 outputpos; } - /*------------------------------------------------- * metadata_callback - handle STREAMINFO metadata *------------------------------------------------- */ -void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +static void flac_decoder_metadata_callback(void *userdata, drflac_metadata *metadata) { - flac_decoder *fldecoder; + flac_decoder *decoder = userdata; + /* ignore all but STREAMINFO metadata */ - if (metadata->type != FLAC__METADATA_TYPE_STREAMINFO) + if (metadata->type != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO) return; /* parse out the data we care about */ - fldecoder = (flac_decoder *)(client_data); - fldecoder->sample_rate = metadata->data.stream_info.sample_rate; - fldecoder->bits_per_sample = metadata->data.stream_info.bits_per_sample; - fldecoder->channels = metadata->data.stream_info.channels; + decoder->sample_rate = metadata->data.streaminfo.sampleRate; + decoder->bits_per_sample = metadata->data.streaminfo.bitsPerSample; + decoder->channels = metadata->data.streaminfo.channels; } - -/*------------------------------------------------- - * tell_callback - handle requests to find out - * 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) -{ - *absolute_byte_offset = ((flac_decoder *)client_data)->compressed_offset; - return FLAC__STREAM_DECODER_TELL_STATUS_OK; -} - - /*------------------------------------------------- * write_callback - handle writes to the output * stream *------------------------------------------------- */ -FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) -{ - return flac_decoder_write_callback(client_data, frame, buffer); -} - -FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void *client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]) +static void flac_decoder_write_callback(void *userdata, void *buffer, size_t bytes) { int sampnum, chan; - int shift, blocksize; - flac_decoder * decoder = (flac_decoder *)client_data; - - assert(frame->header.channels == decoder->channels); + int shift, blocksize; + flac_decoder * decoder = (flac_decoder *)userdata; + int16_t *sampbuf = (int16_t *)buffer; + int sampch = channels(decoder); + uint32_t offset = decoder->uncompressed_offset; + uint16_t usample; /* interleaved case */ shift = decoder->uncompressed_swap ? 8 : 0; - blocksize = frame->header.blocksize; + blocksize = bytes / (sampch * sizeof(sampbuf[0])); if (decoder->uncompressed_start[1] == NULL) { - int16_t *dest = decoder->uncompressed_start[0] + decoder->uncompressed_offset * frame->header.channels; - for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++) - for (chan = 0; chan < frame->header.channels; chan++) - *dest++ = (int16_t)((((uint16_t)buffer[chan][sampnum]) << shift) | (((uint16_t)buffer[chan][sampnum]) >> shift)); + int16_t *dest = decoder->uncompressed_start[0] + offset * sampch; + for (sampnum = 0; sampnum < blocksize && offset < decoder->uncompressed_length; sampnum++, offset++) + for (chan = 0; chan < sampch; chan++) { + usample = (uint16_t)*sampbuf++; + *dest++ = (int16_t)((usample << shift) | (usample >> shift)); + } } /* non-interleaved case */ else { - for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++) - for (chan = 0; chan < frame->header.channels; chan++) + for (sampnum = 0; sampnum < blocksize && offset < decoder->uncompressed_length; sampnum++, offset++) + for (chan = 0; chan < sampch; chan++) { + usample = (uint16_t)*sampbuf++; if (decoder->uncompressed_start[chan] != NULL) - decoder->uncompressed_start[chan][decoder->uncompressed_offset] = (int16_t) ( (((uint16_t)(buffer[chan][sampnum])) << shift) | ( ((uint16_t)(buffer[chan][sampnum])) >> shift) ); + decoder->uncompressed_start[chan][offset] = (int16_t) ((usample << shift) | (usample >> shift)); + } } - return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; + decoder->uncompressed_offset = offset; } -/** - * @fn void flac_decoder::error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) - * - * @brief ------------------------------------------------- - * error_callback - handle errors (ignore them) - * -------------------------------------------------. - * - * @param decoder The decoder. - * @param status The status. - * @param [in,out] client_data If non-null, information describing the client. + +/*------------------------------------------------- + * seek_callback - handle seeks on the output + * stream + *------------------------------------------------- */ -void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +static drflac_bool32 flac_decoder_seek_callback(void *userdata, int offset, drflac_seek_origin origin) { + flac_decoder * decoder = (flac_decoder *)userdata; + uint32_t length = decoder->compressed_length + decoder->compressed2_length; + + if (origin == drflac_seek_origin_start) { + uint32_t pos = offset; + if (pos <= length) { + decoder->compressed_offset = pos; + return 1; + } + } else if (origin == drflac_seek_origin_current) { + uint32_t pos = decoder->compressed_offset + offset; + if (pos <= length) { + decoder->compressed_offset = pos; + return 1; + } + } + return 0; } + diff --git a/core/cd_hw/libchdr/src/flac.h b/core/cd_hw/libchdr/src/flac.h index 03721c99b..bff255b21 100644 --- a/core/cd_hw/libchdr/src/flac.h +++ b/core/cd_hw/libchdr/src/flac.h @@ -1,6 +1,6 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles -/*************************************************************************** +/* license:BSD-3-Clause + * copyright-holders:Aaron Giles + *************************************************************************** flac.h @@ -14,38 +14,37 @@ #define __FLAC_H__ #include -#include "FLAC/ordinals.h" -#include "FLAC/stream_decoder.h" -//************************************************************************** -// TYPE DEFINITIONS -//************************************************************************** +/*************************************************************************** + * TYPE DEFINITIONS + *************************************************************************** + */ typedef struct _flac_decoder flac_decoder; struct _flac_decoder { - // output state - FLAC__StreamDecoder* decoder; // actual encoder - uint32_t sample_rate; // decoded sample rate - uint8_t channels; // decoded number of channels - uint8_t bits_per_sample; // decoded bits per sample - uint32_t compressed_offset; // current offset in compressed data - const FLAC__byte * compressed_start; // start of compressed data - uint32_t compressed_length; // length of compressed data - const FLAC__byte * compressed2_start; // start of compressed data - uint32_t compressed2_length; // length of compressed data - int16_t * uncompressed_start[8]; // pointer to start of uncompressed data (up to 8 streams) - uint32_t uncompressed_offset; // current position in uncompressed data - uint32_t uncompressed_length; // length of uncompressed data - int uncompressed_swap; // swap uncompressed sample data - uint8_t custom_header[0x2a]; // custom header + /* output state */ + void * decoder; /* actual encoder */ + uint32_t sample_rate; /* decoded sample rate */ + uint8_t channels; /* decoded number of channels */ + uint8_t bits_per_sample; /* decoded bits per sample */ + uint32_t compressed_offset; /* current offset in compressed data */ + const uint8_t * compressed_start; /* start of compressed data */ + uint32_t compressed_length; /* length of compressed data */ + const uint8_t * compressed2_start; /* start of compressed data */ + uint32_t compressed2_length; /* length of compressed data */ + int16_t * uncompressed_start[8]; /* pointer to start of uncompressed data (up to 8 streams) */ + uint32_t uncompressed_offset; /* current position in uncompressed data */ + uint32_t uncompressed_length; /* length of uncompressed data */ + int uncompressed_swap; /* swap uncompressed sample data */ + uint8_t custom_header[0x2a]; /* custom header */ }; -// ======================> flac_decoder +/* ======================> flac_decoder */ -void flac_decoder_init(flac_decoder* decoder); +int flac_decoder_init(flac_decoder* decoder); void flac_decoder_free(flac_decoder* decoder); 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_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian); uint32_t flac_decoder_finish(flac_decoder* decoder); -#endif // __FLAC_H__ +#endif /* __FLAC_H__ */ diff --git a/core/cd_hw/libchdr/src/huffman.c b/core/cd_hw/libchdr/src/huffman.c index 93478a845..6a50f1344 100644 --- a/core/cd_hw/libchdr/src/huffman.c +++ b/core/cd_hw/libchdr/src/huffman.c @@ -1,6 +1,6 @@ /* license:BSD-3-Clause * copyright-holders:Aaron Giles - *************************************************************************** +**************************************************************************** huffman.c @@ -101,7 +101,7 @@ #include #include -#include "huffman.h" +#include #define MAX(x,y) ((x) > (y) ? (x) : (y)) @@ -112,10 +112,9 @@ #define MAKE_LOOKUP(code,bits) (((code) << 5) | ((bits) & 0x1f)) - /*************************************************************************** * IMPLEMENTATION - * ************************************************************************** + *************************************************************************** */ /*------------------------------------------------- @@ -126,7 +125,8 @@ struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits) { - struct huffman_decoder* decoder; + struct huffman_decoder* decoder = NULL; + /* limit to 24 bits */ if (maxbits > 24) return NULL; @@ -181,10 +181,10 @@ uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* b enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf) { - enum huffman_error error; + int numbits, curnode; + enum huffman_error error; + /* bits per entry depends on the maxbits */ - int numbits; - int curnode; if (decoder->maxbits >= 16) numbits = 5; else if (decoder->maxbits >= 8) @@ -243,19 +243,18 @@ enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, stru enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf) { + int start; int last = 0; + int count = 0; + int index; int curcode; - uint32_t temp; - enum huffman_error error; uint8_t rlefullbits = 0; - int index, count = 0; - int start; + uint32_t temp; + enum huffman_error error; /* 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++) { if (index < start || count == 7) @@ -310,7 +309,6 @@ enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE; } - /*------------------------------------------------- * compute_tree_from_histo - common backend for * computing a tree based on the data histogram @@ -319,15 +317,16 @@ enum huffman_error huffman_import_tree_huffman(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 */ int i; - uint32_t upperweight; - uint32_t lowerweight = 0; + uint32_t lowerweight; + uint32_t upperweight; + /* compute the number of data items in the histogram */ uint32_t sdatacount = 0; for (i = 0; i < decoder->numcodes; i++) sdatacount += decoder->datahisto[i]; /* binary search to achieve the optimum encoding */ + lowerweight = 0; upperweight = sdatacount * 2; while (1) { @@ -352,8 +351,6 @@ enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decod return huffman_assign_canonical_codes(decoder); } - - /*************************************************************************** * INTERNAL FUNCTIONS *************************************************************************** @@ -376,7 +373,6 @@ static int huffman_tree_node_compare(const void *item1, const void *item2) return (int)node1->bits - (int)node2->bits; } - /*------------------------------------------------- * build_tree - build a huffman tree based on the * data distribution @@ -385,11 +381,12 @@ static int huffman_tree_node_compare(const void *item1, const void *item2) int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight) { - int nextalloc; + int curcode; + int nextalloc; + int listitems = 0; 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); - int curcode, listitems = 0; memset(decoder->huffnode, 0, decoder->numcodes * sizeof(decoder->huffnode[0])); for (curcode = 0; curcode < decoder->numcodes; curcode++) if (decoder->datahisto[curcode] != 0) @@ -403,24 +400,27 @@ int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint if (decoder->huffnode[curcode].weight == 0) decoder->huffnode[curcode].weight = 1; } -/* + +#if 0 fprintf(stderr, "Pre-sort:\n"); for (int i = 0; i < listitems; i++) { fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits); } -*/ +#endif + /* sort the list by weight, largest weight first */ qsort(&list[0], listitems, sizeof(list[0]), huffman_tree_node_compare); -/* + +#if 0 fprintf(stderr, "Post-sort:\n"); for (int i = 0; i < listitems; i++) { fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits); } fprintf(stderr, "===================\n"); -*/ +#endif + /* now build the tree */ nextalloc = decoder->numcodes; - while (listitems > 1) { int curitem; @@ -453,7 +453,7 @@ int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint node->numbits = 0; node->bits = 0; - // 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) { /* determine the number of bits for this node */ @@ -469,7 +469,6 @@ int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint return maxbits; } - /*------------------------------------------------- * assign_canonical_codes - assign canonical codes * to all the nodes based on the number of bits @@ -479,9 +478,9 @@ int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder) { + int curcode, codelen; uint32_t curstart = 0; /* build up a histogram of bit lengths */ - int curcode, codelen; uint32_t bithisto[33] = { 0 }; for (curcode = 0; curcode < decoder->numcodes; curcode++) { @@ -512,7 +511,6 @@ enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decode return HUFFERR_NONE; } - /*------------------------------------------------- * build_lookup_table - build a lookup table for * fast decoding @@ -521,8 +519,8 @@ enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decode void huffman_build_lookup_table(struct huffman_decoder* decoder) { - /* iterate over all codes */ int curcode; + /* iterate over all codes */ for (curcode = 0; curcode < decoder->numcodes; curcode++) { /* process all nodes which have non-zero bits */ diff --git a/core/cd_hw/libchdr/src/huffman.h b/core/cd_hw/libchdr/src/huffman.h index 777ca4ec4..6c9f51136 100644 --- a/core/cd_hw/libchdr/src/huffman.h +++ b/core/cd_hw/libchdr/src/huffman.h @@ -1,6 +1,6 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles -/*************************************************************************** +/* license:BSD-3-Clause + * copyright-holders:Aaron Giles + *************************************************************************** huffman.h @@ -13,12 +13,13 @@ #ifndef __HUFFMAN_H__ #define __HUFFMAN_H__ -#include "bitstream.h" +#include -//************************************************************************** -// CONSTANTS -//************************************************************************** +/*************************************************************************** + * CONSTANTS + *************************************************************************** + */ enum huffman_error { @@ -31,49 +32,50 @@ enum huffman_error HUFFERR_TOO_MANY_CONTEXTS }; - - -//************************************************************************** -// TYPE DEFINITIONS -//************************************************************************** +/*************************************************************************** + * TYPE DEFINITIONS + *************************************************************************** + */ typedef uint16_t lookup_value; -// a node in the huffman tree +/* a node in the huffman tree */ struct node_t { - struct node_t* parent; // pointer to parent node - uint32_t count; // number of hits on this node - uint32_t weight; // assigned weight of this node - uint32_t bits; // bits used to encode the node - uint8_t numbits; // number of bits needed for this node + struct node_t* parent; /* pointer to parent node */ + uint32_t count; /* number of hits on this node */ + uint32_t weight; /* assigned weight of this node */ + uint32_t bits; /* bits used to encode the node */ + uint8_t numbits; /* number of bits needed for this node */ }; -// ======================> huffman_context_base +/* ======================> huffman_context_base */ -// context class for decoding +/* context class for decoding */ struct huffman_decoder { - // internal state - uint32_t numcodes; // number of total codes being processed - uint8_t maxbits; // maximum bits per code - uint8_t prevdata; // value of the previous data (for delta-RLE encoding) - int rleremaining; // number of RLE bytes remaining (for delta-RLE encoding) - lookup_value * lookup; // pointer to the lookup table - struct node_t * huffnode; // array of nodes - uint32_t * datahisto; // histogram of data values - - // array versions of the info we need - //node_t* huffnode_array; //[_NumCodes]; - //lookup_value* lookup_array; //[1 << _MaxBits]; + /* internal state */ + uint32_t numcodes; /* number of total codes being processed */ + uint8_t maxbits; /* maximum bits per code */ + uint8_t prevdata; /* value of the previous data (for delta-RLE encoding) */ + int rleremaining; /* number of RLE bytes remaining (for delta-RLE encoding) */ + lookup_value * lookup; /* pointer to the lookup table */ + struct node_t * huffnode; /* array of nodes */ + uint32_t * datahisto; /* histogram of data values */ + + /* array versions of the info we need */ +#if 0 + node_t* huffnode_array; /* [_NumCodes]; */ + lookup_value* lookup_array; /* [1 << _MaxBits]; */ +#endif }; -// ======================> huffman_decoder +/* ======================> huffman_decoder */ struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits); void delete_huffman_decoder(struct huffman_decoder* decoder); -// single item operations +/* single item operations */ uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf); enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf); diff --git a/libretro/deps/libchdr/src/libchdr_chd.c b/libretro/deps/libchdr/src/libchdr_chd.c index 8a78a8b24..632426ee7 100644 --- a/libretro/deps/libchdr/src/libchdr_chd.c +++ b/libretro/deps/libchdr/src/libchdr_chd.c @@ -2528,7 +2528,7 @@ static chd_error zlib_codec_init(void *codec, uint32_t hunkbytes) /* handle an error */ if (err != CHDERR_NONE) - free(data); + zlib_codec_free(data); return err; } diff --git a/libretro/libretro.c b/libretro/libretro.c index 0d07ea931..7a7b5d1cf 100644 --- a/libretro/libretro.c +++ b/libretro/libretro.c @@ -152,7 +152,7 @@ static const void *g_rom_data = NULL; static size_t g_rom_size = 0; static char *save_dir = NULL; -static retro_log_printf_t log_cb; +retro_log_printf_t log_cb; static retro_video_refresh_t video_cb; static retro_input_poll_t input_poll_cb; static retro_input_state_t input_state_cb; @@ -400,7 +400,7 @@ int load_archive(char *filename, unsigned char *buffer, int maxsize, char *exten if (!strcmp(filename,CD_BIOS_US) || !strcmp(filename,CD_BIOS_EU) || !strcmp(filename,CD_BIOS_JP)) { if (log_cb) - log_cb(RETRO_LOG_ERROR, "Unable to open CD BIOS: %s.\n", filename); + log_cb(RETRO_LOG_ERROR, "Unable to open CD BIOS: \"%s\".\n", filename); return 0; } @@ -426,7 +426,7 @@ int load_archive(char *filename, unsigned char *buffer, int maxsize, char *exten size = maxsize; if (log_cb) - log_cb(RETRO_LOG_INFO, "INFORMATION - Loading %d bytes ...\n", size); + log_cb(RETRO_LOG_INFO, "Loading %d bytes ...\n", size); /* Read into buffer */ left = size; @@ -1710,6 +1710,15 @@ static void check_variables(bool first_run) config.cd_latency = 0; } + var.key = "genesis_plus_gx_cd_precache"; + environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var); + { + if (!var.value || !strcmp(var.value, "disabled")) + config.cd_precache = 0; + else + config.cd_precache = 1; + } + var.key = "genesis_plus_gx_add_on"; environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var); { diff --git a/libretro/libretro_core_options.h b/libretro/libretro_core_options.h index 93ba14be6..dbce6332a 100644 --- a/libretro/libretro_core_options.h +++ b/libretro/libretro_core_options.h @@ -936,9 +936,9 @@ struct retro_core_option_v2_definition option_defs_us[] = { }, { "genesis_plus_gx_cd_latency", - "CD access time", + "CD Access Time", NULL, - "Simulate original CD hardware latency when initiating a read or seeking to a specific location on loaded disc. This is required by a few CD games that crash if CD data is available too soon and also fixes CD audio desync issues in some games. Disabling this can be useful with MSU-MD games as it makes CD audio tracks loops more seamless.", + "Simulate original CD hardware latency when initiating a read or seeking to a specific location on loaded disc. This is required by a few CD games that crash if CD data is available too soon and also fixes CD audio desync issues in some games. Disabling this can be useful with MSU-MD games as it makes CD audio tracks loops more seamless.", NULL, "hacks", { @@ -948,6 +948,20 @@ struct retro_core_option_v2_definition option_defs_us[] = { }, "enabled" }, + { + "genesis_plus_gx_cd_precache", + "CD Image Cache", + NULL, + "Load CD image to memory on startup. CHD supported only. Restart Required.", + NULL, + "hacks", + { + { "disabled", NULL }, + { "enabled", NULL }, + { NULL, NULL }, + }, + "disabled" + }, #ifdef USE_PER_SOUND_CHANNELS_CONFIG { "genesis_plus_gx_show_advanced_audio_settings", diff --git a/libretro/osd.h b/libretro/osd.h index 892028d2d..ec253aa92 100644 --- a/libretro/osd.h +++ b/libretro/osd.h @@ -136,6 +136,7 @@ typedef struct uint8 enhanced_vscroll; uint8 enhanced_vscroll_limit; uint8 cd_latency; + bool cd_precache; #ifdef USE_PER_SOUND_CHANNELS_CONFIG unsigned int psg_ch_volumes[4]; int32 md_ch_volumes[6]; @@ -161,6 +162,7 @@ extern char MS_BIOS_JP[256]; extern void osd_input_update(void); extern int load_archive(char *filename, unsigned char *buffer, int maxsize, char *extension); extern void ROMCheatUpdate(void); +extern retro_log_printf_t log_cb; #ifndef cdStream #define cdStream RFILE