X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=deps%2Flibchdr%2Fsrc%2Flibchdr_chd.c;h=076202b3bfdfa8506520ac7062e173947910a547;hb=refs%2Fheads%2Flibretro;hp=c5cc1794ec3279cca00020b09f8fd76637cda0dc;hpb=89b1d73d6009cbd561f00f452fc055fcb0e62c33;p=pcsx_rearmed.git diff --git a/deps/libchdr/src/libchdr_chd.c b/deps/libchdr/src/libchdr_chd.c index c5cc1794..076202b3 100644 --- a/deps/libchdr/src/libchdr_chd.c +++ b/deps/libchdr/src/libchdr_chd.c @@ -47,10 +47,14 @@ #include #include #include +#include #include "LzmaEnc.h" #include "LzmaDec.h" -#include "zlib.h" +#if defined(__PS3__) || defined(__PSL1GHT__) +#define __MACTYPES__ +#endif +#include #undef TRUE #undef FALSE @@ -224,6 +228,18 @@ struct _lzma_codec_data lzma_allocator allocator; }; +typedef struct _huff_codec_data huff_codec_data; +struct _huff_codec_data +{ + struct huffman_decoder* decoder; +}; + +typedef struct _zstd_codec_data zstd_codec_data; +struct _zstd_codec_data +{ + ZSTD_DStream *dstream; +}; + /* codec-private data for the CDZL codec */ typedef struct _cdzl_codec_data cdzl_codec_data; struct _cdzl_codec_data { @@ -246,6 +262,14 @@ struct _cdlz_codec_data { uint8_t* buffer; }; +/* codec-private data for the FLAC codec */ +typedef struct _flac_codec_data flac_codec_data; +struct _flac_codec_data { + /* internal state */ + int native_endian; + flac_decoder decoder; +}; + /* codec-private data for the CDFL codec */ typedef struct _cdfl_codec_data cdfl_codec_data; struct _cdfl_codec_data { @@ -258,13 +282,22 @@ struct _cdfl_codec_data { uint8_t* buffer; }; +typedef struct _cdzs_codec_data cdzs_codec_data; +struct _cdzs_codec_data +{ + zstd_codec_data base_decompressor; +#ifdef WANT_SUBCODE + zstd_codec_data subcode_decompressor; +#endif + uint8_t* buffer; +}; + /* internal representation of an open CHD file */ struct _chd_file { UINT32 cookie; /* cookie, should equal COOKIE_VALUE */ core_file * file; /* handle to the open core file */ - UINT8 owns_file; /* flag indicating if this file should be closed on chd_close() */ chd_header header; /* header, extracted from file */ chd_file * parent; /* pointer to parent file, or NULL */ @@ -283,9 +316,14 @@ struct _chd_file const codec_interface * codecintf[4]; /* interface to the codec */ zlib_codec_data zlib_codec_data; /* zlib codec data */ + lzma_codec_data lzma_codec_data; /* lzma codec data */ + huff_codec_data huff_codec_data; /* huff codec data */ + flac_codec_data flac_codec_data; /* flac codec data */ + zstd_codec_data zstd_codec_data; /* zstd codec data */ cdzl_codec_data cdzl_codec_data; /* cdzl codec data */ cdlz_codec_data cdlz_codec_data; /* cdlz codec data */ cdfl_codec_data cdfl_codec_data; /* cdfl codec data */ + cdzs_codec_data cdzs_codec_data; /* cdzs codec data */ #ifdef NEED_CACHE_HUNK UINT32 maxhunk; /* maximum hunk accessed */ @@ -306,6 +344,14 @@ static const UINT8 nullsha1[CHD_SHA1_BYTES] = { 0 }; PROTOTYPES ***************************************************************************/ +/* core_file wrappers over stdio */ +static core_file *core_stdio_fopen(char const *path); +static UINT64 core_stdio_fsize(core_file *file); +static size_t core_stdio_fread(void *ptr, size_t size, size_t nmemb, core_file *file); +static int core_stdio_fclose(core_file *file); +static int core_stdio_fclose_nonowner(core_file *file); // alternate fclose used by chd_open_file +static int core_stdio_fseek(core_file* file, INT64 offset, int whence); + /* internal header operations */ static chd_error header_validate(const chd_header *header); static chd_error header_read(chd_file *chd, chd_header *header); @@ -335,6 +381,22 @@ static chd_error lzma_codec_init(void *codec, uint32_t hunkbytes); static void lzma_codec_free(void *codec); static chd_error lzma_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); +/* huff compression codec */ +static chd_error huff_codec_init(void *codec, uint32_t hunkbytes); +static void huff_codec_free(void *codec); +static chd_error huff_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); + +/* flac compression codec */ +static chd_error flac_codec_init(void *codec, uint32_t hunkbytes); +static void flac_codec_free(void *codec); +static chd_error flac_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); + +/* zstd compression codec */ +static chd_error zstd_codec_init(void *codec, uint32_t hunkbytes); +static void zstd_codec_free(void *codec); +static chd_error zstd_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); + + /* cdzl compression codec */ static chd_error cdzl_codec_init(void* codec, uint32_t hunkbytes); static void cdzl_codec_free(void* codec); @@ -350,6 +412,11 @@ static chd_error cdfl_codec_init(void* codec, uint32_t hunkbytes); static void cdfl_codec_free(void* codec); static chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); +/* cdzs compression codec */ +static chd_error cdzs_codec_init(void *codec, uint32_t hunkbytes); +static void cdzs_codec_free(void *codec); +static chd_error cdzs_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); + /*************************************************************************** * LZMA ALLOCATOR HELPER *************************************************************************** @@ -746,24 +813,122 @@ static chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t return CHDERR_NONE; } +/*************************************************************************** + * HUFFMAN DECOMPRESSOR + *************************************************************************** + */ + +static chd_error huff_codec_init(void* codec, uint32_t hunkbytes) +{ + huff_codec_data* huff_codec = (huff_codec_data*) codec; + huff_codec->decoder = create_huffman_decoder(256, 16); + return CHDERR_NONE; +} + +static void huff_codec_free(void *codec) +{ + huff_codec_data* huff_codec = (huff_codec_data*) codec; + delete_huffman_decoder(huff_codec->decoder); +} + +static chd_error huff_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + huff_codec_data* huff_codec = (huff_codec_data*) codec; + struct bitstream* bitbuf = create_bitstream(src, complen); + + // first import the tree + enum huffman_error err = huffman_import_tree_huffman(huff_codec->decoder, bitbuf); + if (err != HUFFERR_NONE) + { + free(bitbuf); + return CHDERR_DECOMPRESSION_ERROR; + } + + // then decode the data + uint32_t cur; + for (cur = 0; cur < destlen; cur++) + dest[cur] = huffman_decode_one(huff_codec->decoder, bitbuf); + bitstream_flush(bitbuf); + chd_error result = bitstream_overflow(bitbuf) ? CHDERR_DECOMPRESSION_ERROR : CHDERR_NONE; + + free(bitbuf); + return result; +} + /*************************************************************************** * CD FLAC DECOMPRESSOR *************************************************************************** */ /*------------------------------------------------------ - * cdfl_codec_blocksize - return the optimal block size + * flac_codec_blocksize - return the optimal block size *------------------------------------------------------ */ -static uint32_t cdfl_codec_blocksize(uint32_t bytes) +static uint32_t flac_codec_blocksize(uint32_t bytes) { /* determine FLAC block size, which must be 16-65535 * clamp to 2k since that's supposed to be the sweet spot */ - uint32_t hunkbytes = bytes / 4; - while (hunkbytes > 2048) - hunkbytes /= 2; - return hunkbytes; + uint32_t blocksize = bytes / 4; + while (blocksize > 2048) + blocksize /= 2; + return blocksize; +} + +static chd_error flac_codec_init(void *codec, uint32_t hunkbytes) +{ + uint16_t native_endian = 0; + flac_codec_data *flac = (flac_codec_data*)codec; + + /* make sure the CHD's hunk size is an even multiple of the sample size */ + if (hunkbytes % 4 != 0) + return CHDERR_CODEC_ERROR; + + /* determine whether we want native or swapped samples */ + *(uint8_t *)(&native_endian) = 1; + flac->native_endian = (native_endian & 1); + + /* flac decoder init */ + if (flac_decoder_init(&flac->decoder)) + return CHDERR_OUT_OF_MEMORY; + + return CHDERR_NONE; +} + +static void flac_codec_free(void *codec) +{ + flac_codec_data *flac = (flac_codec_data*)codec; + flac_decoder_free(&flac->decoder); +} + +static chd_error flac_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + flac_codec_data *flac = (flac_codec_data*)codec; + int swap_endian; + + if (src[0] == 'L') + swap_endian = !flac->native_endian; + else if (src[0] == 'B') + swap_endian = flac->native_endian; + else + return CHDERR_DECOMPRESSION_ERROR; + + if (!flac_decoder_reset(&flac->decoder, 44100, 2, flac_codec_blocksize(destlen), src + 1, complen - 1)) + return CHDERR_DECOMPRESSION_ERROR; + if (!flac_decoder_decode_interleaved(&flac->decoder, (int16_t *)(dest), destlen/4, swap_endian)) + return CHDERR_DECOMPRESSION_ERROR; + flac_decoder_finish(&flac->decoder); + + return CHDERR_NONE; +} + +static uint32_t cdfl_codec_blocksize(uint32_t bytes) +{ + // for CDs it seems that CD_MAX_SECTOR_DATA is the right target + uint32_t blocksize = bytes / 4; + while (blocksize > CD_MAX_SECTOR_DATA) + blocksize /= 2; + return blocksize; } static chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes) @@ -851,6 +1016,163 @@ static chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t return CHDERR_NONE; } + + +/*************************************************************************** + * ZSTD DECOMPRESSOR + *************************************************************************** + */ + +/*------------------------------------------------- + * zstd_codec_init - constructor + *------------------------------------------------- + */ + +static chd_error zstd_codec_init(void* codec, uint32_t hunkbytes) +{ + zstd_codec_data* zstd_codec = (zstd_codec_data*) codec; + + zstd_codec->dstream = ZSTD_createDStream(); + if (!zstd_codec->dstream) { + printf("NO DSTREAM CREATED!\n"); + return CHDERR_DECOMPRESSION_ERROR; + } + return CHDERR_NONE; +} + +/*------------------------------------------------- + * zstd_codec_free + *------------------------------------------------- + */ + +static void zstd_codec_free(void* codec) +{ + zstd_codec_data* zstd_codec = (zstd_codec_data*) codec; + + ZSTD_freeDStream(zstd_codec->dstream); +} + +/*------------------------------------------------- + * decompress - decompress data using the ZSTD + * codec + *------------------------------------------------- + */ +static chd_error zstd_codec_decompress(void* codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + /* initialize */ + zstd_codec_data* zstd_codec = (zstd_codec_data*) codec; + //reset decompressor + size_t zstd_res = ZSTD_initDStream(zstd_codec->dstream); + if (ZSTD_isError(zstd_res)) + { + printf("INITI DSTREAM FAILED!\n"); + return CHDERR_DECOMPRESSION_ERROR; + } + + ZSTD_inBuffer input = {src, complen, 0}; + ZSTD_outBuffer output = {dest, destlen, 0 }; + + while ((input.pos < input.size) && (output.pos < output.size)) + { + zstd_res = ZSTD_decompressStream(zstd_codec->dstream, &output, &input); + if (ZSTD_isError(zstd_res)) + { + printf("DECOMPRESSION ERROR IN LOOP\n"); + return CHDERR_DECOMPRESSION_ERROR; + } + } + if (output.pos != output.size) + { + printf("OUTPUT DOESN'T MATCH!\n"); + return CHDERR_DECOMPRESSION_ERROR; + } + return CHDERR_NONE; + +} + +/* cdzs */ +static chd_error cdzs_codec_init(void* codec, uint32_t hunkbytes) +{ + chd_error ret; + cdzs_codec_data* cdzs = (cdzs_codec_data*) codec; + + /* allocate buffer */ + cdzs->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes); + if (cdzs->buffer == NULL) + return CHDERR_OUT_OF_MEMORY; + + /* make sure the CHD's hunk size is an even multiple of the frame size */ + ret = zstd_codec_init(&cdzs->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); + if (ret != CHDERR_NONE) + return ret; + +#ifdef WANT_SUBCODE + ret = zstd_codec_init(&cdzs->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; +} + +static void cdzs_codec_free(void* codec) +{ + cdzs_codec_data* cdzs = (cdzs_codec_data*) codec; + free(cdzs->buffer); + zstd_codec_free(&cdzs->base_decompressor); +#ifdef WANT_SUBCODE + zstd_codec_free(&cdzs->subcode_decompressor); +#endif +} + +static chd_error cdzs_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + uint32_t framenum; + cdzs_codec_data* cdzs = (cdzs_codec_data*)codec; + + /* determine header bytes */ + uint32_t frames = destlen / CD_FRAME_SIZE; + uint32_t complen_bytes = (destlen < 65536) ? 2 : 3; + uint32_t ecc_bytes = (frames + 7) / 8; + uint32_t header_bytes = ecc_bytes + complen_bytes; + + /* extract compressed length of base */ + uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1]; + if (complen_bytes > 2) + complen_base = (complen_base << 8) | src[ecc_bytes + 2]; + + /* reset and decode */ + zstd_codec_decompress(&cdzs->base_decompressor, &src[header_bytes], complen_base, &cdzs->buffer[0], frames * CD_MAX_SECTOR_DATA); +#ifdef WANT_SUBCODE + zstd_codec_decompress(&cdzs->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdzs->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA); +#endif + + /* reassemble the data */ + for (framenum = 0; framenum < frames; framenum++) + { + uint8_t *sector; + + memcpy(&dest[framenum * CD_FRAME_SIZE], &cdzs->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); +#ifdef WANT_SUBCODE + memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdzs->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA); +#endif + +#ifdef WANT_RAW_DATA_SECTOR + /* reconstitute the ECC data and sync header */ + sector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE]; + if ((src[framenum / 8] & (1 << (framenum % 8))) != 0) + { + memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header)); + ecc_generate(sector); + } +#endif + } + return CHDERR_NONE; +} + /*************************************************************************** CODEC INTERFACES ***************************************************************************/ @@ -901,6 +1223,49 @@ static const codec_interface codec_interfaces[] = NULL }, + /* V5 lzma compression */ + { + CHD_CODEC_LZMA, + "lzma (LZMA)", + FALSE, + lzma_codec_init, + lzma_codec_free, + lzma_codec_decompress, + NULL + }, + + /* V5 huffman compression */ + { + CHD_CODEC_HUFFMAN, + "Huffman", + FALSE, + huff_codec_init, + huff_codec_free, + huff_codec_decompress, + NULL + }, + + /* V5 flac compression */ + { + CHD_CODEC_FLAC, + "flac (FLAC)", + FALSE, + flac_codec_init, + flac_codec_free, + flac_codec_decompress, + NULL + }, + /* V5 zstd compression */ + { + CHD_CODEC_ZSTD, + "ZStandard", + FALSE, + zstd_codec_init, + zstd_codec_free, + zstd_codec_decompress, + NULL + }, + /* V5 CD zlib compression */ { CHD_CODEC_CD_ZLIB, @@ -933,6 +1298,17 @@ static const codec_interface codec_interfaces[] = cdfl_codec_decompress, NULL }, + /* V5 CD zstd compression */ + { + CHD_CODEC_CD_ZSTD, + "cdzs (CD ZStandard)", + FALSE, + cdzs_codec_init, + cdzs_codec_free, + cdzs_codec_decompress, + NULL + } + }; /*************************************************************************** @@ -1160,7 +1536,7 @@ static inline int chd_compressed(chd_header* header) { static chd_error decompress_v5_map(chd_file* chd, chd_header* header) { int result = 0; - int hunknum; + uint32_t hunknum; int repcount = 0; uint8_t lastcomp = 0; uint32_t last_self = 0; @@ -1182,6 +1558,8 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header) if (!chd_compressed(header)) { header->rawmap = (uint8_t*)malloc(rawmapsize); + if (header->rawmap == NULL) + return CHDERR_OUT_OF_MEMORY; core_fseek(chd->file, header->mapoffset, SEEK_SET); result = core_fread(chd->file, header->rawmap, rawmapsize); return CHDERR_NONE; @@ -1199,10 +1577,18 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header) /* now read the map */ compressed_ptr = (uint8_t*)malloc(sizeof(uint8_t) * mapbytes); + if (compressed_ptr == NULL) + return CHDERR_OUT_OF_MEMORY; core_fseek(chd->file, header->mapoffset + 16, SEEK_SET); result = core_fread(chd->file, compressed_ptr, mapbytes); bitbuf = create_bitstream(compressed_ptr, sizeof(uint8_t) * mapbytes); header->rawmap = (uint8_t*)malloc(rawmapsize); + if (header->rawmap == NULL) + { + free(compressed_ptr); + free(bitbuf); + return CHDERR_OUT_OF_MEMORY; + } /* first decode the compression types */ decoder = create_huffman_decoder(16, 8); @@ -1340,7 +1726,24 @@ static inline void map_extract_old(const UINT8 *base, map_entry *entry, UINT32 h chd_open_file - open a CHD file for access -------------------------------------------------*/ -CHD_EXPORT chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **chd) +CHD_EXPORT chd_error chd_open_file(FILE *file, int mode, chd_file *parent, chd_file **chd) { + core_file *stream = malloc(sizeof(core_file)); + if (!stream) + return CHDERR_OUT_OF_MEMORY; + stream->argp = file; + stream->fsize = core_stdio_fsize; + stream->fread = core_stdio_fread; + stream->fclose = core_stdio_fclose_nonowner; + stream->fseek = core_stdio_fseek; + + return chd_open_core_file(stream, mode, parent, chd); +} + +/*------------------------------------------------- + chd_open_core_file - open a CHD file for access +-------------------------------------------------*/ + +CHD_EXPORT chd_error chd_open_core_file(core_file *file, int mode, chd_file *parent, chd_file **chd) { chd_file *newchd = NULL; chd_error err; @@ -1489,6 +1892,22 @@ CHD_EXPORT chd_error chd_open_file(core_file *file, int mode, chd_file *parent, codec = &newchd->zlib_codec_data; break; + case CHD_CODEC_LZMA: + codec = &newchd->lzma_codec_data; + break; + + case CHD_CODEC_HUFFMAN: + codec = &newchd->huff_codec_data; + break; + + case CHD_CODEC_FLAC: + codec = &newchd->flac_codec_data; + break; + + case CHD_CODEC_ZSTD: + codec = &newchd->zstd_codec_data; + break; + case CHD_CODEC_CD_ZLIB: codec = &newchd->cdzl_codec_data; break; @@ -1500,6 +1919,10 @@ CHD_EXPORT chd_error chd_open_file(core_file *file, int mode, chd_file *parent, case CHD_CODEC_CD_FLAC: codec = &newchd->cdfl_codec_data; break; + + case CHD_CODEC_CD_ZSTD: + codec = &newchd->cdzs_codec_data; + break; } if (codec == NULL) @@ -1529,17 +1952,13 @@ cleanup: CHD_EXPORT chd_error chd_precache(chd_file *chd) { -#ifdef _MSC_VER - size_t size, count; -#else - ssize_t size, count; -#endif + INT64 count; + UINT64 size; if (chd->file_cache == NULL) { - core_fseek(chd->file, 0, SEEK_END); - size = core_ftell(chd->file); - if (size <= 0) + size = core_fsize(chd->file); + if ((INT64)size <= 0) return CHDERR_INVALID_DATA; chd->file_cache = malloc(size); if (chd->file_cache == NULL) @@ -1567,6 +1986,12 @@ CHD_EXPORT chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_error err; core_file *file = NULL; + if (filename == NULL) + { + err = CHDERR_INVALID_PARAMETER; + goto cleanup; + } + /* choose the proper mode */ switch(mode) { @@ -1579,7 +2004,7 @@ CHD_EXPORT chd_error chd_open(const char *filename, int mode, chd_file *parent, } /* open the file */ - file = core_fopen(filename); + file = core_stdio_fopen(filename); if (file == 0) { err = CHDERR_FILE_NOT_FOUND; @@ -1587,12 +2012,7 @@ CHD_EXPORT chd_error chd_open(const char *filename, int mode, chd_file *parent, } /* now open the CHD */ - err = chd_open_file(file, mode, parent, chd); - if (err != CHDERR_NONE) - goto cleanup; - - /* we now own this file */ - (*chd)->owns_file = TRUE; + return chd_open_core_file(file, mode, parent, chd); cleanup: if ((err != CHDERR_NONE) && (file != NULL)) @@ -1629,21 +2049,41 @@ CHD_EXPORT void chd_close(chd_file *chd) 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_LZMA: + codec = &chd->lzma_codec_data; + break; + + case CHD_CODEC_HUFFMAN: + codec = &chd->huff_codec_data; + break; + + case CHD_CODEC_FLAC: + codec = &chd->flac_codec_data; + break; + + case CHD_CODEC_ZSTD: + codec = &chd->zstd_codec_data; + break; + case CHD_CODEC_CD_ZLIB: codec = &chd->cdzl_codec_data; break; + case CHD_CODEC_CD_LZMA: + codec = &chd->cdlz_codec_data; + break; + case CHD_CODEC_CD_FLAC: codec = &chd->cdfl_codec_data; break; + + case CHD_CODEC_CD_ZSTD: + codec = &chd->cdzs_codec_data; + break; } if (codec) @@ -1674,7 +2114,7 @@ CHD_EXPORT void chd_close(chd_file *chd) free(chd->map); /* close the file */ - if (chd->owns_file && chd->file != NULL) + if (chd->file != NULL) core_fclose(chd->file); #ifdef NEED_CACHE_HUNK @@ -1773,7 +2213,7 @@ CHD_EXPORT chd_error chd_read_header(const char *filename, chd_header *header) EARLY_EXIT(err = CHDERR_INVALID_PARAMETER); /* open the file */ - chd.file = core_fopen(filename); + chd.file = core_stdio_fopen(filename); if (chd.file == NULL) EARLY_EXIT(err = CHDERR_FILE_NOT_FOUND); @@ -2061,6 +2501,8 @@ static chd_error header_read(chd_file *chd, chd_header *header) 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); + if (header->unitbytes == 0) + return CHDERR_INVALID_DATA; header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes; header->metaoffset = 0; } @@ -2075,6 +2517,8 @@ static chd_error header_read(chd_file *chd, chd_header *header) memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES); header->hunkbytes = get_bigendian_uint32(&rawheader[76]); header->unitbytes = header_guess_unitbytes(chd); + if (header->unitbytes == 0) + return CHDERR_INVALID_DATA; 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); @@ -2088,6 +2532,8 @@ static chd_error header_read(chd_file *chd, chd_header *header) header->metaoffset = get_bigendian_uint64(&rawheader[36]); header->hunkbytes = get_bigendian_uint32(&rawheader[44]); header->unitbytes = header_guess_unitbytes(chd); + if (header->unitbytes == 0) + return CHDERR_INVALID_DATA; 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); @@ -2106,8 +2552,12 @@ static chd_error header_read(chd_file *chd, chd_header *header) header->mapoffset = get_bigendian_uint64(&rawheader[40]); header->metaoffset = get_bigendian_uint64(&rawheader[48]); header->hunkbytes = get_bigendian_uint32(&rawheader[56]); + if (header->hunkbytes == 0) + return CHDERR_INVALID_DATA; header->hunkcount = (header->logicalbytes + header->hunkbytes - 1) / header->hunkbytes; header->unitbytes = get_bigendian_uint32(&rawheader[60]); + if (header->unitbytes == 0) + return CHDERR_INVALID_DATA; 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); @@ -2253,7 +2703,9 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des /* read it into the decompression buffer */ compressed_bytes = hunk_read_compressed(chd, entry->offset, entry->length); if (compressed_bytes == NULL) + { return CHDERR_READ_ERROR; + } /* now decompress using the codec */ err = CHDERR_NONE; @@ -2347,21 +2799,41 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des 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_LZMA: + codec = &chd->lzma_codec_data; + break; + + case CHD_CODEC_HUFFMAN: + codec = &chd->huff_codec_data; + break; + + case CHD_CODEC_FLAC: + codec = &chd->flac_codec_data; + break; + + case CHD_CODEC_ZSTD: + codec = &chd->zstd_codec_data; + break; + case CHD_CODEC_CD_ZLIB: codec = &chd->cdzl_codec_data; break; + case CHD_CODEC_CD_LZMA: + codec = &chd->cdlz_codec_data; + break; + case CHD_CODEC_CD_FLAC: codec = &chd->cdfl_codec_data; break; + + case CHD_CODEC_CD_ZSTD: + codec = &chd->cdzs_codec_data; + break; } if (codec==NULL) return CHDERR_CODEC_ERROR; @@ -2439,7 +2911,7 @@ static chd_error map_read(chd_file *chd) UINT8 cookie[MAP_ENTRY_SIZE]; UINT32 count; chd_error err; - int i; + UINT32 i; /* first allocate memory */ chd->map = (map_entry *)malloc(sizeof(chd->map[0]) * chd->header.totalhunks); @@ -2590,10 +3062,6 @@ static chd_error zlib_codec_init(void *codec, uint32_t hunkbytes) else err = CHDERR_NONE; - /* handle an error */ - if (err != CHDERR_NONE) - free(data); - return err; } @@ -2609,8 +3077,6 @@ static void zlib_codec_free(void *codec) /* deinit the streams */ if (data != NULL) { - int i; - inflateEnd(&data->inflater); /* free our fast memory */ @@ -2735,3 +3201,87 @@ static void zlib_allocator_free(voidpf opaque) if (alloc->allocptr[i]) free(alloc->allocptr[i]); } + +/*------------------------------------------------- + core_stdio_fopen - core_file wrapper over fopen +-------------------------------------------------*/ +static core_file *core_stdio_fopen(char const *path) { + core_file *file = malloc(sizeof(core_file)); + if (!file) + return NULL; + if (!(file->argp = fopen(path, "rb"))) { + free(file); + return NULL; + } + file->fsize = core_stdio_fsize; + file->fread = core_stdio_fread; + file->fclose = core_stdio_fclose; + file->fseek = core_stdio_fseek; + return file; +} + +/*------------------------------------------------- + core_stdio_fsize - core_file function for + getting file size with stdio +-------------------------------------------------*/ +static UINT64 core_stdio_fsize(core_file *file) { +#if defined USE_LIBRETRO_VFS + #define core_stdio_fseek_impl fseek + #define core_stdio_ftell_impl ftell +#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WIN64__) + #define core_stdio_fseek_impl _fseeki64 + #define core_stdio_ftell_impl _ftelli64 +#elif defined(_LARGEFILE_SOURCE) && defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 + #define core_stdio_fseek_impl fseeko64 + #define core_stdio_ftell_impl ftello64 +#elif defined(__PS3__) && !defined(__PSL1GHT__) || defined(__SWITCH__) || defined(__vita__) + #define core_stdio_fseek_impl(x,y,z) fseek(x,(off_t)y,z) + #define core_stdio_ftell_impl(x) (off_t)ftell(x) +#else + #define core_stdio_fseek_impl fseeko + #define core_stdio_ftell_impl ftello +#endif + FILE *fp; + UINT64 p, rv; + fp = (FILE*)file->argp; + + p = core_stdio_ftell_impl(fp); + core_stdio_fseek_impl(fp, 0, SEEK_END); + rv = core_stdio_ftell_impl(fp); + core_stdio_fseek_impl(fp, p, SEEK_SET); + return rv; +} + +/*------------------------------------------------- + core_stdio_fread - core_file wrapper over fread +-------------------------------------------------*/ +static size_t core_stdio_fread(void *ptr, size_t size, size_t nmemb, core_file *file) { + return fread(ptr, size, nmemb, (FILE*)file->argp); +} + +/*------------------------------------------------- + core_stdio_fclose - core_file wrapper over fclose +-------------------------------------------------*/ +static int core_stdio_fclose(core_file *file) { + int err = fclose((FILE*)file->argp); + if (err == 0) + free(file); + return err; +} + +/*------------------------------------------------- + core_stdio_fclose_nonowner - don't call fclose because + we don't own the underlying file, but do free the + core_file because libchdr did allocate that itself. +-------------------------------------------------*/ +static int core_stdio_fclose_nonowner(core_file *file) { + free(file); + return 0; +} + +/*------------------------------------------------- + core_stdio_fseek - core_file wrapper over fclose +-------------------------------------------------*/ +static int core_stdio_fseek(core_file* file, INT64 offset, int whence) { + return core_stdio_fseek_impl((FILE*)file->argp, offset, whence); +}