From 72a9f18456a56d0e574285885782d60600dcb561 Mon Sep 17 00:00:00 2001 From: TheLastRar Date: Wed, 18 Dec 2024 22:03:40 +0000 Subject: [PATCH] 3rdparty: Sync libchdr to commit cb077337d53392454e7100a0fd07139ca678e527 --- 3rdparty/libchdr/include/libchdr/chd.h | 194 +++---- 3rdparty/libchdr/include/libchdr/coretypes.h | 31 +- 3rdparty/libchdr/include/libchdr/huffman.h | 2 +- 3rdparty/libchdr/src/libchdr_chd.c | 548 ++++++++++++------- 3rdparty/libchdr/src/libchdr_huffman.c | 32 +- 5 files changed, 495 insertions(+), 312 deletions(-) diff --git a/3rdparty/libchdr/include/libchdr/chd.h b/3rdparty/libchdr/include/libchdr/chd.h index e13dca03a4..82e638f9af 100644 --- a/3rdparty/libchdr/include/libchdr/chd.h +++ b/3rdparty/libchdr/include/libchdr/chd.h @@ -58,67 +58,67 @@ extern "C" { V1 header: [ 0] char tag[8]; // 'MComprHD' - [ 8] UINT32 length; // length of header (including tag and length fields) - [ 12] UINT32 version; // drive format version - [ 16] UINT32 flags; // flags (see below) - [ 20] UINT32 compression; // compression type - [ 24] UINT32 hunksize; // 512-byte sectors per hunk - [ 28] UINT32 totalhunks; // total # of hunks represented - [ 32] UINT32 cylinders; // number of cylinders on hard disk - [ 36] UINT32 heads; // number of heads on hard disk - [ 40] UINT32 sectors; // number of sectors on hard disk - [ 44] UINT8 md5[16]; // MD5 checksum of raw data - [ 60] UINT8 parentmd5[16]; // MD5 checksum of parent file + [ 8] uint32_t length; // length of header (including tag and length fields) + [ 12] uint32_t version; // drive format version + [ 16] uint32_t flags; // flags (see below) + [ 20] uint32_t compression; // compression type + [ 24] uint32_t hunksize; // 512-byte sectors per hunk + [ 28] uint32_t totalhunks; // total # of hunks represented + [ 32] uint32_t cylinders; // number of cylinders on hard disk + [ 36] uint32_t heads; // number of heads on hard disk + [ 40] uint32_t sectors; // number of sectors on hard disk + [ 44] uint8_t md5[16]; // MD5 checksum of raw data + [ 60] uint8_t parentmd5[16]; // MD5 checksum of parent file [ 76] (V1 header length) V2 header: [ 0] char tag[8]; // 'MComprHD' - [ 8] UINT32 length; // length of header (including tag and length fields) - [ 12] UINT32 version; // drive format version - [ 16] UINT32 flags; // flags (see below) - [ 20] UINT32 compression; // compression type - [ 24] UINT32 hunksize; // seclen-byte sectors per hunk - [ 28] UINT32 totalhunks; // total # of hunks represented - [ 32] UINT32 cylinders; // number of cylinders on hard disk - [ 36] UINT32 heads; // number of heads on hard disk - [ 40] UINT32 sectors; // number of sectors on hard disk - [ 44] UINT8 md5[16]; // MD5 checksum of raw data - [ 60] UINT8 parentmd5[16]; // MD5 checksum of parent file - [ 76] UINT32 seclen; // number of bytes per sector + [ 8] uint32_t length; // length of header (including tag and length fields) + [ 12] uint32_t version; // drive format version + [ 16] uint32_t flags; // flags (see below) + [ 20] uint32_t compression; // compression type + [ 24] uint32_t hunksize; // seclen-byte sectors per hunk + [ 28] uint32_t totalhunks; // total # of hunks represented + [ 32] uint32_t cylinders; // number of cylinders on hard disk + [ 36] uint32_t heads; // number of heads on hard disk + [ 40] uint32_t sectors; // number of sectors on hard disk + [ 44] uint8_t md5[16]; // MD5 checksum of raw data + [ 60] uint8_t parentmd5[16]; // MD5 checksum of parent file + [ 76] uint32_t seclen; // number of bytes per sector [ 80] (V2 header length) V3 header: [ 0] char tag[8]; // 'MComprHD' - [ 8] UINT32 length; // length of header (including tag and length fields) - [ 12] UINT32 version; // drive format version - [ 16] UINT32 flags; // flags (see below) - [ 20] UINT32 compression; // compression type - [ 24] UINT32 totalhunks; // total # of hunks represented - [ 28] UINT64 logicalbytes; // logical size of the data (in bytes) - [ 36] UINT64 metaoffset; // offset to the first blob of metadata - [ 44] UINT8 md5[16]; // MD5 checksum of raw data - [ 60] UINT8 parentmd5[16]; // MD5 checksum of parent file - [ 76] UINT32 hunkbytes; // number of bytes per hunk - [ 80] UINT8 sha1[20]; // SHA1 checksum of raw data - [100] UINT8 parentsha1[20];// SHA1 checksum of parent file + [ 8] uint32_t length; // length of header (including tag and length fields) + [ 12] uint32_t version; // drive format version + [ 16] uint32_t flags; // flags (see below) + [ 20] uint32_t compression; // compression type + [ 24] uint32_t totalhunks; // total # of hunks represented + [ 28] uint64_t logicalbytes; // logical size of the data (in bytes) + [ 36] uint64_t metaoffset; // offset to the first blob of metadata + [ 44] uint8_t md5[16]; // MD5 checksum of raw data + [ 60] uint8_t parentmd5[16]; // MD5 checksum of parent file + [ 76] uint32_t hunkbytes; // number of bytes per hunk + [ 80] uint8_t sha1[20]; // SHA1 checksum of raw data + [100] uint8_t parentsha1[20];// SHA1 checksum of parent file [120] (V3 header length) V4 header: [ 0] char tag[8]; // 'MComprHD' - [ 8] UINT32 length; // length of header (including tag and length fields) - [ 12] UINT32 version; // drive format version - [ 16] UINT32 flags; // flags (see below) - [ 20] UINT32 compression; // compression type - [ 24] UINT32 totalhunks; // total # of hunks represented - [ 28] UINT64 logicalbytes; // logical size of the data (in bytes) - [ 36] UINT64 metaoffset; // offset to the first blob of metadata - [ 44] UINT32 hunkbytes; // number of bytes per hunk - [ 48] UINT8 sha1[20]; // combined raw+meta SHA1 - [ 68] UINT8 parentsha1[20];// combined raw+meta SHA1 of parent - [ 88] UINT8 rawsha1[20]; // raw data SHA1 + [ 8] uint32_t length; // length of header (including tag and length fields) + [ 12] uint32_t version; // drive format version + [ 16] uint32_t flags; // flags (see below) + [ 20] uint32_t compression; // compression type + [ 24] uint32_t totalhunks; // total # of hunks represented + [ 28] uint64_t logicalbytes; // logical size of the data (in bytes) + [ 36] uint64_t metaoffset; // offset to the first blob of metadata + [ 44] uint32_t hunkbytes; // number of bytes per hunk + [ 48] uint8_t sha1[20]; // combined raw+meta SHA1 + [ 68] uint8_t parentsha1[20];// combined raw+meta SHA1 of parent + [ 88] uint8_t rawsha1[20]; // raw data SHA1 [108] (V4 header length) Flags: @@ -130,17 +130,17 @@ extern "C" { V5 header: [ 0] char tag[8]; // 'MComprHD' - [ 8] uint32_t length; // length of header (including tag and length fields) - [ 12] uint32_t version; // drive format version - [ 16] uint32_t compressors[4];// which custom compressors are used? - [ 32] uint64_t logicalbytes; // logical size of the data (in bytes) - [ 40] uint64_t mapoffset; // offset to the map - [ 48] uint64_t metaoffset; // offset to the first blob of metadata - [ 56] uint32_t hunkbytes; // number of bytes per hunk (512k maximum) - [ 60] uint32_t unitbytes; // number of bytes per unit within each hunk - [ 64] uint8_t rawsha1[20]; // raw data SHA1 - [ 84] uint8_t sha1[20]; // combined raw+meta SHA1 - [104] uint8_t parentsha1[20];// combined raw+meta SHA1 of parent + [ 8] uint32_t_t length; // length of header (including tag and length fields) + [ 12] uint32_t_t version; // drive format version + [ 16] uint32_t_t compressors[4];// which custom compressors are used? + [ 32] uint64_t_t logicalbytes; // logical size of the data (in bytes) + [ 40] uint64_t_t mapoffset; // offset to the map + [ 48] uint64_t_t metaoffset; // offset to the first blob of metadata + [ 56] uint32_t_t hunkbytes; // number of bytes per hunk (512k maximum) + [ 60] uint32_t_t unitbytes; // number of bytes per unit within each hunk + [ 64] uint8_t_t rawsha1[20]; // raw data SHA1 + [ 84] uint8_t_t sha1[20]; // combined raw+meta SHA1 + [104] uint8_t_t parentsha1[20];// combined raw+meta SHA1 of parent [124] (V5 header length) If parentsha1 != 0, we have a parent (no need for flags) @@ -148,22 +148,22 @@ extern "C" { V5 uncompressed map format: - [ 0] uint32_t offset; // starting offset / hunk size + [ 0] uint32_t_t offset; // starting offset / hunk size V5 compressed map format header: - [ 0] uint32_t length; // length of compressed map + [ 0] uint32_t_t length; // length of compressed map [ 4] UINT48 datastart; // offset of first block [ 10] uint16_t crc; // crc-16 of the map - [ 12] uint8_t lengthbits; // bits used to encode complength - [ 13] uint8_t hunkbits; // bits used to encode self-refs - [ 14] uint8_t parentunitbits; // bits used to encode parent unit refs - [ 15] uint8_t reserved; // future use + [ 12] uint8_t_t lengthbits; // bits used to encode complength + [ 13] uint8_t_t hunkbits; // bits used to encode self-refs + [ 14] uint8_t_t parentunitbits; // bits used to encode parent unit refs + [ 15] uint8_t_t reserved; // future use [ 16] (compressed header length) Each compressed map entry, once expanded, looks like: - [ 0] uint8_t compression; // compression type + [ 0] uint8_t_t compression; // compression type [ 1] UINT24 complength; // compressed length [ 4] UINT48 offset; // offset [ 10] uint16_t crc; // crc-16 of the data @@ -220,7 +220,7 @@ extern "C" { /* metadata parameters */ #define CHDMETATAG_WILDCARD 0 -#define CHD_METAINDEX_APPEND ((UINT32)-1) +#define CHD_METAINDEX_APPEND ((uint32_t)-1) /* metadata flags */ #define CHD_MDFLAGS_CHECKSUM 0x01 /* indicates data is checksummed */ @@ -307,32 +307,32 @@ typedef struct _chd_file chd_file; typedef struct _chd_header chd_header; struct _chd_header { - UINT32 length; /* length of header data */ - UINT32 version; /* drive format version */ - UINT32 flags; /* flags field */ - UINT32 compression[4]; /* compression type */ - UINT32 hunkbytes; /* number of bytes per hunk */ - UINT32 totalhunks; /* total # of hunks represented */ - UINT64 logicalbytes; /* logical size of the data */ - UINT64 metaoffset; /* offset in file of first metadata */ - UINT64 mapoffset; /* TOOD V5 */ - UINT8 md5[CHD_MD5_BYTES]; /* overall MD5 checksum */ - 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 */ - UINT32 unitbytes; /* TODO V5 */ - UINT64 unitcount; /* TODO V5 */ - UINT32 hunkcount; /* TODO V5 */ + uint32_t length; /* length of header data */ + uint32_t version; /* drive format version */ + uint32_t flags; /* flags field */ + uint32_t compression[4]; /* compression type */ + uint32_t hunkbytes; /* number of bytes per hunk */ + uint32_t totalhunks; /* total # of hunks represented */ + uint64_t logicalbytes; /* logical size of the data */ + uint64_t metaoffset; /* offset in file of first metadata */ + uint64_t mapoffset; /* TOOD V5 */ + uint8_t md5[CHD_MD5_BYTES]; /* overall MD5 checksum */ + uint8_t parentmd5[CHD_MD5_BYTES]; /* overall MD5 checksum of parent */ + uint8_t sha1[CHD_SHA1_BYTES]; /* overall SHA1 checksum */ + uint8_t rawsha1[CHD_SHA1_BYTES]; /* SHA1 checksum of raw data */ + uint8_t parentsha1[CHD_SHA1_BYTES]; /* overall SHA1 checksum of parent */ + uint32_t unitbytes; /* TODO V5 */ + uint64_t unitcount; /* TODO V5 */ + uint32_t hunkcount; /* TODO V5 */ /* map information */ - UINT32 mapentrybytes; /* length of each entry in a map (V5) */ - UINT8* rawmap; /* raw map data */ + uint32_t mapentrybytes; /* length of each entry in a map (V5) */ + uint8_t* rawmap; /* raw map data */ - UINT32 obsolete_cylinders; /* obsolete field -- do not use! */ - UINT32 obsolete_sectors; /* obsolete field -- do not use! */ - UINT32 obsolete_heads; /* obsolete field -- do not use! */ - UINT32 obsolete_hunksize; /* obsolete field -- do not use! */ + uint32_t obsolete_cylinders; /* obsolete field -- do not use! */ + uint32_t obsolete_sectors; /* obsolete field -- do not use! */ + uint32_t obsolete_heads; /* obsolete field -- do not use! */ + uint32_t obsolete_hunksize; /* obsolete field -- do not use! */ }; @@ -340,10 +340,10 @@ struct _chd_header typedef struct _chd_verify_result chd_verify_result; struct _chd_verify_result { - UINT8 md5[CHD_MD5_BYTES]; /* overall MD5 checksum */ - UINT8 sha1[CHD_SHA1_BYTES]; /* overall SHA1 checksum */ - UINT8 rawsha1[CHD_SHA1_BYTES]; /* SHA1 checksum of raw data */ - UINT8 metasha1[CHD_SHA1_BYTES]; /* SHA1 checksum of metadata */ + uint8_t md5[CHD_MD5_BYTES]; /* overall MD5 checksum */ + uint8_t sha1[CHD_SHA1_BYTES]; /* overall SHA1 checksum */ + uint8_t rawsha1[CHD_SHA1_BYTES]; /* SHA1 checksum of raw data */ + uint8_t metasha1[CHD_SHA1_BYTES]; /* SHA1 checksum of metadata */ }; @@ -369,10 +369,10 @@ struct _chd_verify_result /* ----- CHD file management ----- */ /* create a new CHD file fitting the given description */ -/* chd_error chd_create(const char *filename, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent); */ +/* chd_error chd_create(const char *filename, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t compression, chd_file *parent); */ /* same as chd_create(), but accepts an already-opened core_file object */ -/* chd_error chd_create_file(core_file *file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent); */ +/* chd_error chd_create_file(core_file *file, uint64_t logicalbytes, uint32_t hunkbytes, uint32_t compression, chd_file *parent); */ /* open an existing CHD file */ CHD_EXPORT chd_error chd_open_core_file(core_file *file, int mode, chd_file *parent, chd_file **chd); @@ -408,14 +408,14 @@ CHD_EXPORT chd_error chd_read_header(const char *filename, chd_header *header); /* ----- core data read/write ----- */ /* read one hunk from the CHD file */ -CHD_EXPORT chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer); +CHD_EXPORT chd_error chd_read(chd_file *chd, uint32_t hunknum, void *buffer); /* ----- metadata management ----- */ /* get indexed metadata of a particular sort */ -CHD_EXPORT 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_t searchtag, uint32_t searchindex, void *output, uint32_t outputlen, uint32_t *resultlen, uint32_t *resulttag, uint8_t *resultflags); @@ -426,7 +426,7 @@ CHD_EXPORT chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 se CHD_EXPORT chd_error chd_codec_config(chd_file *chd, int param, void *config); /* return a string description of a codec */ -CHD_EXPORT const char *chd_get_codec_name(UINT32 codec); +CHD_EXPORT const char *chd_get_codec_name(uint32_t codec); #ifdef __cplusplus } diff --git a/3rdparty/libchdr/include/libchdr/coretypes.h b/3rdparty/libchdr/include/libchdr/coretypes.h index 805359b5ab..cb516934a2 100644 --- a/3rdparty/libchdr/include/libchdr/coretypes.h +++ b/3rdparty/libchdr/include/libchdr/coretypes.h @@ -8,26 +8,13 @@ #include #endif +#ifndef ARRAY_LENGTH #define ARRAY_LENGTH(x) (sizeof(x)/sizeof(x[0])) - -#if defined(__PS3__) || defined(__PSL1GHT__) -#undef UINT32 -#undef UINT16 -#undef UINT8 -#undef INT32 -#undef INT16 -#undef INT8 #endif -typedef uint64_t UINT64; -typedef uint32_t UINT32; -typedef uint16_t UINT16; -typedef uint8_t UINT8; - -typedef int64_t INT64; -typedef int32_t INT32; -typedef int16_t INT16; -typedef int8_t INT8; +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) +#endif typedef struct chd_core_file { /* @@ -41,9 +28,9 @@ typedef struct chd_core_file { * undefined because many implementations will seek to the end of the * file and call ftell. * - * on error, (UINT64)-1 is returned. + * on error, (uint64_t)-1 is returned. */ - UINT64(*fsize)(struct chd_core_file*); + uint64_t(*fsize)(struct chd_core_file*); /* * should match the behavior of fread, except the FILE* argument at the end @@ -55,7 +42,7 @@ typedef struct chd_core_file { int (*fclose)(struct chd_core_file*); // fseek clone - int (*fseek)(struct chd_core_file*, INT64, int); + int (*fseek)(struct chd_core_file*, int64_t, int); } core_file; static inline int core_fclose(core_file *fp) { @@ -66,11 +53,11 @@ static inline size_t core_fread(core_file *fp, void *ptr, size_t len) { return fp->fread(ptr, 1, len, fp); } -static inline int core_fseek(core_file* fp, INT64 offset, int whence) { +static inline int core_fseek(core_file* fp, int64_t offset, int whence) { return fp->fseek(fp, offset, whence); } -static inline UINT64 core_fsize(core_file *fp) +static inline uint64_t core_fsize(core_file *fp) { return fp->fsize(fp); } diff --git a/3rdparty/libchdr/include/libchdr/huffman.h b/3rdparty/libchdr/include/libchdr/huffman.h index 6c9f511368..d771c299ac 100644 --- a/3rdparty/libchdr/include/libchdr/huffman.h +++ b/3rdparty/libchdr/include/libchdr/huffman.h @@ -85,6 +85,6 @@ int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder); enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder); -void huffman_build_lookup_table(struct huffman_decoder* decoder); +enum huffman_error huffman_build_lookup_table(struct huffman_decoder* decoder); #endif diff --git a/3rdparty/libchdr/src/libchdr_chd.c b/3rdparty/libchdr/src/libchdr_chd.c index ec37a490dc..83f5d2a9af 100644 --- a/3rdparty/libchdr/src/libchdr_chd.c +++ b/3rdparty/libchdr/src/libchdr_chd.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -88,6 +89,11 @@ #define CHD_V1_SECTOR_SIZE 512 /* size of a "sector" in the V1 header */ +#define CHD_MAX_HUNK_SIZE (128 * 1024 * 1024) /* hunk size probably shouldn't be more than 128MB */ + +/* we're currently only using this for CD/DVDs, if we end up with more than 10GB data, it's probably invalid */ +#define CHD_MAX_FILE_SIZE (10ULL * 1024 * 1024 * 1024) + #define COOKIE_VALUE 0xbaadf00d #define MAX_ZLIB_ALLOCS 64 @@ -161,10 +167,10 @@ enum typedef struct _codec_interface codec_interface; struct _codec_interface { - UINT32 compression; /* type of compression */ + uint32_t compression; /* type of compression */ const char *compname; /* name of the algorithm */ - UINT8 lossy; /* is this a lossy algorithm? */ - chd_error (*init)(void *codec, UINT32 hunkbytes); /* codec initialize */ + uint8_t lossy; /* is this a lossy algorithm? */ + chd_error (*init)(void *codec, uint32_t hunkbytes); /* codec initialize */ void (*free)(void *codec); /* codec free */ chd_error (*decompress)(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); /* decompress data */ chd_error (*config)(void *codec, int param, void *config); /* configure */ @@ -174,22 +180,22 @@ struct _codec_interface typedef struct _map_entry map_entry; struct _map_entry { - UINT64 offset; /* offset within the file of the data */ - UINT32 crc; /* 32-bit CRC of the data */ - UINT32 length; /* length of the data */ - UINT8 flags; /* misc flags */ + uint64_t offset; /* offset within the file of the data */ + uint32_t crc; /* 32-bit CRC of the data */ + uint32_t length; /* length of the data */ + uint8_t flags; /* misc flags */ }; /* a single metadata entry */ typedef struct _metadata_entry metadata_entry; struct _metadata_entry { - UINT64 offset; /* offset within the file of the header */ - UINT64 next; /* offset within the file of the next header */ - UINT64 prev; /* offset within the file of the previous header */ - UINT32 length; /* length of the metadata */ - UINT32 metatag; /* metadata tag */ - UINT8 flags; /* flag bits */ + uint64_t offset; /* offset within the file of the header */ + uint64_t next; /* offset within the file of the next header */ + uint64_t prev; /* offset within the file of the previous header */ + uint32_t length; /* length of the metadata */ + uint32_t metatag; /* metadata tag */ + uint8_t flags; /* flag bits */ }; /* codec-private data for the ZLIB codec */ @@ -197,8 +203,8 @@ struct _metadata_entry typedef struct _zlib_allocator zlib_allocator; struct _zlib_allocator { - UINT32 * allocptr[MAX_ZLIB_ALLOCS]; - UINT32 * allocptr2[MAX_ZLIB_ALLOCS]; + uint32_t * allocptr[MAX_ZLIB_ALLOCS]; + uint32_t * allocptr2[MAX_ZLIB_ALLOCS]; }; typedef struct _zlib_codec_data zlib_codec_data; @@ -283,7 +289,7 @@ struct _cdfl_codec_data { }; typedef struct _cdzs_codec_data cdzs_codec_data; -struct _cdzs_codec_data +struct _cdzs_codec_data { zstd_codec_data base_decompressor; #ifdef WANT_SUBCODE @@ -295,9 +301,10 @@ struct _cdzs_codec_data /* internal representation of an open CHD file */ struct _chd_file { - UINT32 cookie; /* cookie, should equal COOKIE_VALUE */ + uint32_t cookie; /* cookie, should equal COOKIE_VALUE */ core_file * file; /* handle to the open core file */ + uint64_t file_size; /* size of the core file */ chd_header header; /* header, extracted from file */ chd_file * parent; /* pointer to parent file, or NULL */ @@ -305,14 +312,14 @@ struct _chd_file map_entry * map; /* array of map entries */ #ifdef NEED_CACHE_HUNK - UINT8 * cache; /* hunk cache pointer */ - UINT32 cachehunk; /* index of currently cached hunk */ + uint8_t * cache; /* hunk cache pointer */ + uint32_t cachehunk; /* index of currently cached hunk */ - UINT8 * compare; /* hunk compare pointer */ - UINT32 comparehunk; /* index of current compare data */ + uint8_t * compare; /* hunk compare pointer */ + uint32_t comparehunk; /* index of current compare data */ #endif - UINT8 * compressed; /* pointer to buffer for compressed data */ + uint8_t * compressed; /* pointer to buffer for compressed data */ const codec_interface * codecintf[4]; /* interface to the codec */ zlib_codec_data zlib_codec_data; /* zlib codec data */ @@ -326,10 +333,10 @@ struct _chd_file cdzs_codec_data cdzs_codec_data; /* cdzs codec data */ #ifdef NEED_CACHE_HUNK - UINT32 maxhunk; /* maximum hunk accessed */ + uint32_t maxhunk; /* maximum hunk accessed */ #endif - UINT8 * file_cache; /* cache of underlying file */ + uint8_t * file_cache; /* cache of underlying file */ }; @@ -337,8 +344,8 @@ struct _chd_file GLOBAL VARIABLES ***************************************************************************/ -static const UINT8 nullmd5[CHD_MD5_BYTES] = { 0 }; -static const UINT8 nullsha1[CHD_SHA1_BYTES] = { 0 }; +static const uint8_t nullmd5[CHD_MD5_BYTES] = { 0 }; +static const uint8_t nullsha1[CHD_SHA1_BYTES] = { 0 }; /*************************************************************************** PROTOTYPES @@ -346,11 +353,11 @@ static const UINT8 nullsha1[CHD_SHA1_BYTES] = { 0 }; /* core_file wrappers over stdio */ static core_file *core_stdio_fopen(char const *path); -static UINT64 core_stdio_fsize(core_file *file); +static uint64_t 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); +static int core_stdio_fseek(core_file* file, int64_t offset, int whence); /* internal header operations */ static chd_error header_validate(const chd_header *header); @@ -358,15 +365,15 @@ static chd_error header_read(chd_file *chd, chd_header *header); /* internal hunk read/write */ #ifdef NEED_CACHE_HUNK -static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum); +static chd_error hunk_read_into_cache(chd_file *chd, uint32_t hunknum); #endif -static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest); +static chd_error hunk_read_into_memory(chd_file *chd, uint32_t hunknum, uint8_t *dest); /* internal map access */ 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); +static chd_error metadata_find_entry(chd_file *chd, uint32_t metatag, uint32_t metaindex, metadata_entry *metaentry); /* zlib compression codec */ static chd_error zlib_codec_init(void *codec, uint32_t hunkbytes); @@ -459,6 +466,28 @@ static void lzma_allocator_free(void* p ) } } +/*------------------------------------------------- + * lzma_allocator_free_unused + * free unused buffers only + *------------------------------------------------- + */ + +static void lzma_allocator_free_unused(lzma_allocator *codec) +{ + int i; + + for (i = 0; i < MAX_LZMA_ALLOCS; i++) + { + uint32_t *ptr = codec->allocptr[i]; + if (ptr && (*ptr & 1) == 0) + { + free(codec->allocptr[i]); + codec->allocptr[i] = NULL; + codec->allocptr2[i] = NULL; + } + } +} + /*------------------------------------------------- * lzma_fast_alloc - fast malloc for lzma, which * allocates and frees memory frequently @@ -600,6 +629,7 @@ static chd_error lzma_codec_init(void* codec, uint32_t hunkbytes) return CHDERR_DECOMPRESSION_ERROR; } LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc); + lzma_allocator_free_unused(alloc); /* do memory allocations */ if (LzmaDec_Allocate(&lzma_codec->decoder, decoder_props, LZMA_PROPS_SIZE, (ISzAlloc*)alloc) != SZ_OK) @@ -689,22 +719,39 @@ static chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t { uint32_t framenum; cdlz_codec_data* cdlz = (cdlz_codec_data*)codec; + chd_error decomp_err; + uint32_t complen_base; /* 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; + const uint32_t frames = destlen / CD_FRAME_SIZE; + const uint32_t complen_bytes = (destlen < 65536) ? 2 : 3; + const uint32_t ecc_bytes = (frames + 7) / 8; + const uint32_t header_bytes = ecc_bytes + complen_bytes; + + /* input may be truncated, double-check */ + if (complen < (ecc_bytes + 2)) + return CHDERR_DECOMPRESSION_ERROR; /* extract compressed length of base */ - uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1]; + complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1]; if (complen_bytes > 2) + { + if (complen < (ecc_bytes + 3)) + return CHDERR_DECOMPRESSION_ERROR; + complen_base = (complen_base << 8) | src[ecc_bytes + 2]; + } + if (complen < (header_bytes + complen_base)) + return CHDERR_DECOMPRESSION_ERROR; /* reset and decode */ - lzma_codec_decompress(&cdlz->base_decompressor, &src[header_bytes], complen_base, &cdlz->buffer[0], frames * CD_MAX_SECTOR_DATA); + decomp_err = lzma_codec_decompress(&cdlz->base_decompressor, &src[header_bytes], complen_base, &cdlz->buffer[0], frames * CD_MAX_SECTOR_DATA); + if (decomp_err != CHDERR_NONE) + return decomp_err; #ifdef WANT_SUBCODE - zlib_codec_decompress(&cdlz->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdlz->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA); + decomp_err = zlib_codec_decompress(&cdlz->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdlz->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA); + if (decomp_err != CHDERR_NONE) + return decomp_err; #endif /* reassemble the data */ @@ -772,22 +819,39 @@ static chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t { uint32_t framenum; cdzl_codec_data* cdzl = (cdzl_codec_data*)codec; + chd_error decomp_err; + uint32_t complen_base; /* 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; + const uint32_t frames = destlen / CD_FRAME_SIZE; + const uint32_t complen_bytes = (destlen < 65536) ? 2 : 3; + const uint32_t ecc_bytes = (frames + 7) / 8; + const uint32_t header_bytes = ecc_bytes + complen_bytes; + + /* input may be truncated, double-check */ + if (complen < (ecc_bytes + 2)) + return CHDERR_DECOMPRESSION_ERROR; /* extract compressed length of base */ - uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1]; + complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1]; if (complen_bytes > 2) + { + if (complen < (ecc_bytes + 3)) + return CHDERR_DECOMPRESSION_ERROR; + complen_base = (complen_base << 8) | src[ecc_bytes + 2]; + } + if (complen < (header_bytes + complen_base)) + return CHDERR_DECOMPRESSION_ERROR; /* reset and decode */ - zlib_codec_decompress(&cdzl->base_decompressor, &src[header_bytes], complen_base, &cdzl->buffer[0], frames * CD_MAX_SECTOR_DATA); + decomp_err = zlib_codec_decompress(&cdzl->base_decompressor, &src[header_bytes], complen_base, &cdzl->buffer[0], frames * CD_MAX_SECTOR_DATA); + if (decomp_err != CHDERR_NONE) + return decomp_err; #ifdef WANT_SUBCODE - zlib_codec_decompress(&cdzl->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdzl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA); + decomp_err = zlib_codec_decompress(&cdzl->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdzl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA); + if (decomp_err != CHDERR_NONE) + return decomp_err; #endif /* reassemble the data */ @@ -1132,22 +1196,39 @@ static chd_error cdzs_codec_decompress(void *codec, const uint8_t *src, uint32_t { uint32_t framenum; cdzs_codec_data* cdzs = (cdzs_codec_data*)codec; + chd_error decomp_err; + uint32_t complen_base; /* 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; + const uint32_t frames = destlen / CD_FRAME_SIZE; + const uint32_t complen_bytes = (destlen < 65536) ? 2 : 3; + const uint32_t ecc_bytes = (frames + 7) / 8; + const uint32_t header_bytes = ecc_bytes + complen_bytes; + + /* input may be truncated, double-check */ + if (complen < (ecc_bytes + 2)) + return CHDERR_DECOMPRESSION_ERROR; /* extract compressed length of base */ - uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1]; + complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1]; if (complen_bytes > 2) + { + if (complen < (ecc_bytes + 3)) + return CHDERR_DECOMPRESSION_ERROR; + complen_base = (complen_base << 8) | src[ecc_bytes + 2]; + } + if (complen < (header_bytes + complen_base)) + return CHDERR_DECOMPRESSION_ERROR; /* reset and decode */ - zstd_codec_decompress(&cdzs->base_decompressor, &src[header_bytes], complen_base, &cdzs->buffer[0], frames * CD_MAX_SECTOR_DATA); + decomp_err = zstd_codec_decompress(&cdzs->base_decompressor, &src[header_bytes], complen_base, &cdzs->buffer[0], frames * CD_MAX_SECTOR_DATA); + if (decomp_err != CHDERR_NONE) + return decomp_err; #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); + decomp_err = 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); + if (decomp_err != CHDERR_NONE) + return decomp_err; #endif /* reassemble the data */ @@ -1316,22 +1397,22 @@ static const codec_interface codec_interfaces[] = ***************************************************************************/ /*------------------------------------------------- - get_bigendian_uint64 - fetch a UINT64 from + get_bigendian_uint64_t - fetch a uint64_t from the data stream in bigendian order -------------------------------------------------*/ -static inline UINT64 get_bigendian_uint64(const UINT8 *base) +static inline uint64_t get_bigendian_uint64_t(const uint8_t *base) { - return ((UINT64)base[0] << 56) | ((UINT64)base[1] << 48) | ((UINT64)base[2] << 40) | ((UINT64)base[3] << 32) | - ((UINT64)base[4] << 24) | ((UINT64)base[5] << 16) | ((UINT64)base[6] << 8) | (UINT64)base[7]; + return ((uint64_t)base[0] << 56) | ((uint64_t)base[1] << 48) | ((uint64_t)base[2] << 40) | ((uint64_t)base[3] << 32) | + ((uint64_t)base[4] << 24) | ((uint64_t)base[5] << 16) | ((uint64_t)base[6] << 8) | (uint64_t)base[7]; } /*------------------------------------------------- - put_bigendian_uint64 - write a UINT64 to + put_bigendian_uint64_t - write a uint64_t to the data stream in bigendian order -------------------------------------------------*/ -static inline void put_bigendian_uint64(UINT8 *base, UINT64 value) +static inline void put_bigendian_uint64_t(uint8_t *base, uint64_t value) { base[0] = value >> 56; base[1] = value >> 48; @@ -1348,10 +1429,10 @@ static inline void put_bigendian_uint64(UINT8 *base, UINT64 value) the data stream in bigendian order -------------------------------------------------*/ -static inline UINT64 get_bigendian_uint48(const UINT8 *base) +static inline uint64_t get_bigendian_uint48(const uint8_t *base) { - return ((UINT64)base[0] << 40) | ((UINT64)base[1] << 32) | - ((UINT64)base[2] << 24) | ((UINT64)base[3] << 16) | ((UINT64)base[4] << 8) | (UINT64)base[5]; + return ((uint64_t)base[0] << 40) | ((uint64_t)base[1] << 32) | + ((uint64_t)base[2] << 24) | ((uint64_t)base[3] << 16) | ((uint64_t)base[4] << 8) | (uint64_t)base[5]; } /*------------------------------------------------- @@ -1359,7 +1440,7 @@ static inline UINT64 get_bigendian_uint48(const UINT8 *base) the data stream in bigendian order -------------------------------------------------*/ -static inline void put_bigendian_uint48(UINT8 *base, UINT64 value) +static inline void put_bigendian_uint48(uint8_t *base, uint64_t value) { value &= 0xffffffffffff; base[0] = value >> 40; @@ -1370,21 +1451,21 @@ static inline void put_bigendian_uint48(UINT8 *base, UINT64 value) base[5] = value; } /*------------------------------------------------- - get_bigendian_uint32 - fetch a UINT32 from + get_bigendian_uint32_t - fetch a uint32_t from the data stream in bigendian order -------------------------------------------------*/ -static inline UINT32 get_bigendian_uint32(const UINT8 *base) +static inline uint32_t get_bigendian_uint32_t(const uint8_t *base) { return (base[0] << 24) | (base[1] << 16) | (base[2] << 8) | base[3]; } /*------------------------------------------------- - put_bigendian_uint32 - write a UINT32 to + put_bigendian_uint32_t - write a uint32_t to the data stream in bigendian order -------------------------------------------------*/ -static inline void put_bigendian_uint32(UINT8 *base, UINT32 value) +static inline void put_bigendian_uint32_t(uint8_t *base, uint32_t value) { base[0] = value >> 24; base[1] = value >> 16; @@ -1397,7 +1478,7 @@ static inline void put_bigendian_uint32(UINT8 *base, UINT32 value) the data stream in bigendian order -------------------------------------------------*/ -static inline void put_bigendian_uint24(UINT8 *base, UINT32 value) +static inline void put_bigendian_uint24(uint8_t *base, uint32_t value) { value &= 0xffffff; base[0] = value >> 16; @@ -1410,27 +1491,27 @@ static inline void put_bigendian_uint24(UINT8 *base, UINT32 value) the data stream in bigendian order -------------------------------------------------*/ -static inline UINT32 get_bigendian_uint24(const UINT8 *base) +static inline uint32_t get_bigendian_uint24(const uint8_t *base) { return (base[0] << 16) | (base[1] << 8) | base[2]; } /*------------------------------------------------- - get_bigendian_uint16 - fetch a UINT16 from + get_bigendian_uint16 - fetch a uint16_t from the data stream in bigendian order -------------------------------------------------*/ -static inline UINT16 get_bigendian_uint16(const UINT8 *base) +static inline uint16_t get_bigendian_uint16(const uint8_t *base) { return (base[0] << 8) | base[1]; } /*------------------------------------------------- - put_bigendian_uint16 - write a UINT16 to + put_bigendian_uint16 - write a uint16_t to the data stream in bigendian order -------------------------------------------------*/ -static inline void put_bigendian_uint16(UINT8 *base, UINT16 value) +static inline void put_bigendian_uint16(uint8_t *base, uint16_t value) { base[0] = value >> 8; base[1] = value; @@ -1441,10 +1522,10 @@ static inline void put_bigendian_uint16(UINT8 *base, UINT16 value) entry from the datastream -------------------------------------------------*/ -static inline void map_extract(const UINT8 *base, map_entry *entry) +static inline void map_extract(const uint8_t *base, map_entry *entry) { - entry->offset = get_bigendian_uint64(&base[0]); - entry->crc = get_bigendian_uint32(&base[8]); + entry->offset = get_bigendian_uint64_t(&base[0]); + entry->crc = get_bigendian_uint32_t(&base[8]); entry->length = get_bigendian_uint16(&base[12]) | (base[14] << 16); entry->flags = base[15]; } @@ -1454,10 +1535,10 @@ static inline void map_extract(const UINT8 *base, map_entry *entry) entry to the datastream -------------------------------------------------*/ -static inline void map_assemble(UINT8 *base, map_entry *entry) +static inline void map_assemble(uint8_t *base, map_entry *entry) { - put_bigendian_uint64(&base[0], entry->offset); - put_bigendian_uint32(&base[8], entry->crc); + put_bigendian_uint64_t(&base[0], entry->offset); + put_bigendian_uint32_t(&base[8], entry->crc); put_bigendian_uint16(&base[12], entry->length); base[14] = entry->length >> 16; base[15] = entry->flags; @@ -1468,6 +1549,11 @@ static inline void map_assemble(UINT8 *base, map_entry *entry) -------------------------------------------------*/ static inline int map_size_v5(chd_header* header) { + // Avoid overflow due to corrupted data. + const uint32_t max_hunkcount = (UINT32_MAX / header->mapentrybytes); + if (header->hunkcount > max_hunkcount) + return -1; + return header->hunkcount * header->mapentrybytes; } @@ -1552,11 +1638,16 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header) uint8_t rawbuf[16]; struct huffman_decoder* decoder; enum huffman_error err; - uint64_t curoffset; + uint64_t curoffset; int rawmapsize = map_size_v5(header); + if (rawmapsize < 0) + return CHDERR_INVALID_FILE; if (!chd_compressed(header)) { + if ((header->mapoffset + rawmapsize) >= chd->file_size || (header->mapoffset + rawmapsize) < header->mapoffset) + return CHDERR_INVALID_FILE; + header->rawmap = (uint8_t*)malloc(rawmapsize); if (header->rawmap == NULL) return CHDERR_OUT_OF_MEMORY; @@ -1568,7 +1659,7 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header) /* read the reader */ core_fseek(chd->file, header->mapoffset, SEEK_SET); result = core_fread(chd->file, rawbuf, sizeof(rawbuf)); - mapbytes = get_bigendian_uint32(&rawbuf[0]); + mapbytes = get_bigendian_uint32_t(&rawbuf[0]); firstoffs = get_bigendian_uint48(&rawbuf[4]); mapcrc = get_bigendian_uint16(&rawbuf[10]); lengthbits = rawbuf[12]; @@ -1576,6 +1667,8 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header) parentbits = rawbuf[14]; /* now read the map */ + if ((header->mapoffset + mapbytes) < header->mapoffset || (header->mapoffset + mapbytes) >= chd->file_size) + return CHDERR_INVALID_FILE; compressed_ptr = (uint8_t*)malloc(sizeof(uint8_t) * mapbytes); if (compressed_ptr == NULL) return CHDERR_OUT_OF_MEMORY; @@ -1615,7 +1708,16 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header) rawmap[0] = lastcomp, repcount--; else { - uint8_t val = huffman_decode_one(decoder, bitbuf); + uint8_t val; + if (bitstream_overflow(bitbuf)) + { + free(compressed_ptr); + free(bitbuf); + delete_huffman_decoder(decoder); + return CHDERR_DECOMPRESSION_ERROR; + } + + val = huffman_decode_one(decoder, bitbuf); if (val == COMPRESSION_RLE_SMALL) rawmap[0] = lastcomp, repcount = 2 + huffman_decode_one(decoder, bitbuf); else if (val == COMPRESSION_RLE_LARGE) @@ -1705,9 +1807,9 @@ static chd_error decompress_v5_map(chd_file* chd, chd_header* header) entry in old format from the datastream -------------------------------------------------*/ -static inline void map_extract_old(const UINT8 *base, map_entry *entry, UINT32 hunkbytes) +static inline void map_extract_old(const uint8_t *base, map_entry *entry, uint32_t hunkbytes) { - entry->offset = get_bigendian_uint64(&base[0]); + entry->offset = get_bigendian_uint64_t(&base[0]); entry->crc = 0; entry->length = entry->offset >> 44; entry->flags = MAP_ENTRY_FLAG_NO_CRC | ((entry->length == hunkbytes) ? V34_MAP_ENTRY_TYPE_UNCOMPRESSED : V34_MAP_ENTRY_TYPE_COMPRESSED); @@ -1765,6 +1867,9 @@ CHD_EXPORT chd_error chd_open_core_file(core_file *file, int mode, chd_file *par newchd->cookie = COOKIE_VALUE; newchd->parent = parent; newchd->file = file; + newchd->file_size = core_fsize(file); + if ((int64_t)newchd->file_size <= 0) + EARLY_EXIT(err = CHDERR_INVALID_FILE); /* now attempt to read the header */ err = header_read(newchd, &newchd->header); @@ -1827,8 +1932,8 @@ CHD_EXPORT chd_error chd_open_core_file(core_file *file, int mode, chd_file *par #ifdef NEED_CACHE_HUNK /* allocate and init the hunk cache */ - newchd->cache = (UINT8 *)malloc(newchd->header.hunkbytes); - newchd->compare = (UINT8 *)malloc(newchd->header.hunkbytes); + newchd->cache = (uint8_t *)malloc(newchd->header.hunkbytes); + newchd->compare = (uint8_t *)malloc(newchd->header.hunkbytes); if (newchd->cache == NULL || newchd->compare == NULL) EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY); newchd->cachehunk = ~0; @@ -1836,7 +1941,7 @@ CHD_EXPORT chd_error chd_open_core_file(core_file *file, int mode, chd_file *par #endif /* allocate the temporary compressed buffer */ - newchd->compressed = (UINT8 *)malloc(newchd->header.hunkbytes); + newchd->compressed = (uint8_t *)malloc(newchd->header.hunkbytes); if (newchd->compressed == NULL) EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY); @@ -1865,7 +1970,8 @@ CHD_EXPORT chd_error chd_open_core_file(core_file *file, int mode, chd_file *par } else { - int decompnum; + int decompnum, needsinit; + /* verify the compression types and initialize the codecs */ for (decompnum = 0; decompnum < ARRAY_LENGTH(newchd->header.compression); decompnum++) { @@ -1882,8 +1988,21 @@ CHD_EXPORT chd_error chd_open_core_file(core_file *file, int mode, chd_file *par if (newchd->codecintf[decompnum] == NULL && newchd->header.compression[decompnum] != 0) EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT); + /* ensure we don't try to initialize the same codec twice */ + /* this is "normal" for chds where the user overrides the codecs, it'll have none repeated */ + needsinit = (newchd->codecintf[decompnum]->init != NULL); + for (i = 0; i < decompnum; i++) + { + if (newchd->codecintf[decompnum] == newchd->codecintf[i]) + { + /* already initialized */ + needsinit = 0; + break; + } + } + /* initialize the codec */ - if (newchd->codecintf[decompnum]->init != NULL) + if (needsinit) { void* codec = NULL; switch (newchd->header.compression[decompnum]) @@ -1952,20 +2071,16 @@ cleanup: CHD_EXPORT chd_error chd_precache(chd_file *chd) { - INT64 count; - UINT64 size; + int64_t count; if (chd->file_cache == NULL) { - size = core_fsize(chd->file); - if ((INT64)size <= 0) - return CHDERR_INVALID_DATA; - chd->file_cache = malloc(size); + chd->file_cache = malloc(chd->file_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) + count = core_fread(chd->file, chd->file_cache, chd->file_size); + if (count != chd->file_size) { free(chd->file_cache); chd->file_cache = NULL; @@ -2043,10 +2158,24 @@ CHD_EXPORT void chd_close(chd_file *chd) for (i = 0 ; i < ARRAY_LENGTH(chd->codecintf); i++) { void* codec = NULL; + int j, needsfree; if (chd->codecintf[i] == NULL) continue; + /* only free each codec at max once */ + needsfree = 1; + for (j = 0; j < i; j++) + { + if (chd->codecintf[i] == chd->codecintf[j]) + { + needsfree = 0; + break; + } + } + if (!needsfree) + continue; + switch (chd->codecintf[i]->compression) { case CHD_CODEC_ZLIB: @@ -2203,13 +2332,20 @@ CHD_EXPORT const chd_header *chd_get_header(chd_file *chd) chd_read_header - read CHD header data from file into the pointed struct -------------------------------------------------*/ -CHD_EXPORT chd_error chd_read_header_core_file(core_file* file, chd_header* header) + +CHD_EXPORT chd_error chd_read_header_core_file(core_file *file, chd_header *header) { + chd_error err = CHDERR_NONE; chd_file chd; + + /* verify parameters */ + if (file == NULL || header == NULL) + return CHDERR_INVALID_PARAMETER; + chd.file = file; /* attempt to read the header */ - const chd_error err = header_read(&chd, header); + err = header_read(&chd, header); if (err != CHDERR_NONE) return err; @@ -2217,30 +2353,57 @@ CHD_EXPORT chd_error chd_read_header_core_file(core_file* file, chd_header* head return header_validate(header); } +/*------------------------------------------------- + chd_read_header - read CHD header data + from file into the pointed struct +-------------------------------------------------*/ + CHD_EXPORT chd_error chd_read_header_file(FILE *file, chd_header *header) { - core_file stream; - stream.argp = file; - stream.fsize = core_stdio_fsize; - stream.fread = core_stdio_fread; - stream.fclose = core_stdio_fclose_nonowner; - stream.fseek = core_stdio_fseek; + chd_error err; + 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_read_header_core_file(&stream, header); + err = chd_read_header_core_file(stream, header); + core_fclose(stream); + return err; } +/*------------------------------------------------- + chd_read_header - read CHD header data + from file into the pointed struct +-------------------------------------------------*/ + CHD_EXPORT chd_error chd_read_header(const char *filename, chd_header *header) { + chd_error err; + core_file *file = NULL; + if (filename == NULL) - return CHDERR_INVALID_PARAMETER; + { + err = CHDERR_INVALID_PARAMETER; + goto cleanup; + } - core_file* file = core_stdio_fopen(filename); - if (file == NULL) - return CHDERR_FILE_NOT_FOUND; + /* open the file */ + file = core_stdio_fopen(filename); + if (file == 0) + { + err = CHDERR_FILE_NOT_FOUND; + goto cleanup; + } - chd_error err = chd_read_header_core_file(file, header); - - core_fclose(file); + err = chd_read_header_core_file(file, header); + + cleanup: + if (file != NULL) + core_fclose(file); return err; } @@ -2253,7 +2416,7 @@ CHD_EXPORT chd_error chd_read_header(const char *filename, chd_header *header) file -------------------------------------------------*/ -CHD_EXPORT chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer) +CHD_EXPORT chd_error chd_read(chd_file *chd, uint32_t hunknum, void *buffer) { /* punt if NULL or invalid */ if (chd == NULL || chd->cookie != COOKIE_VALUE) @@ -2264,7 +2427,7 @@ CHD_EXPORT chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer) return CHDERR_HUNK_OUT_OF_RANGE; /* perform the read */ - return hunk_read_into_memory(chd, hunknum, (UINT8 *)buffer); + return hunk_read_into_memory(chd, hunknum, (uint8_t *)buffer); } /*************************************************************************** @@ -2276,11 +2439,11 @@ CHD_EXPORT chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer) of the given type -------------------------------------------------*/ -CHD_EXPORT 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_t searchtag, uint32_t searchindex, void *output, uint32_t outputlen, uint32_t *resultlen, uint32_t *resulttag, uint8_t *resultflags) { metadata_entry metaentry; chd_error err; - UINT32 count; + uint32_t count; /* if we didn't find it, just return */ err = metadata_find_entry(chd, searchtag, searchindex, &metaentry); @@ -2290,11 +2453,11 @@ CHD_EXPORT chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 se if (chd->header.version < 3 && (searchtag == HARD_DISK_METADATA_TAG || searchtag == CHDMETATAG_WILDCARD) && searchindex == 0) { char faux_metadata[256]; - UINT32 faux_length; + uint32_t faux_length; /* fill in the faux metadata */ - sprintf(faux_metadata, HARD_DISK_METADATA_FORMAT, chd->header.obsolete_cylinders, chd->header.obsolete_heads, chd->header.obsolete_sectors, chd->header.hunkbytes / chd->header.obsolete_hunksize); - faux_length = (UINT32)strlen(faux_metadata) + 1; + sprintf(faux_metadata, HARD_DISK_METADATA_FORMAT, chd->header.obsolete_cylinders, chd->header.obsolete_heads, chd->header.obsolete_sectors, (chd->header.obsolete_hunksize != 0) ? (chd->header.hunkbytes / chd->header.obsolete_hunksize) : 0); + faux_length = (uint32_t)strlen(faux_metadata) + 1; /* copy the metadata itself */ memcpy(output, faux_metadata, MIN(outputlen, faux_length)); @@ -2345,7 +2508,7 @@ CHD_EXPORT chd_error chd_codec_config(chd_file *chd, int param, void *config) particular codec -------------------------------------------------*/ -CHD_EXPORT const char *chd_get_codec_name(UINT32 codec) +CHD_EXPORT const char *chd_get_codec_name(uint32_t codec) { return "Unknown"; } @@ -2415,6 +2578,10 @@ static chd_error header_validate(const chd_header *header) return CHDERR_INVALID_PARAMETER; } + /* some basic size checks to prevent huge mallocs */ + if (header->hunkbytes >= CHD_MAX_HUNK_SIZE || ((uint64_t)header->hunkbytes * (uint64_t)header->totalhunks) >= CHD_MAX_FILE_SIZE) + return CHDERR_INVALID_PARAMETER; + return CHDERR_NONE; } @@ -2423,7 +2590,7 @@ static chd_error header_validate(const chd_header *header) guess at the bytes/unit based on metadata -------------------------------------------------*/ -static UINT32 header_guess_unitbytes(chd_file *chd) +static uint32_t header_guess_unitbytes(chd_file *chd) { /* look for hard disk metadata; if found, then the unit size == sector size */ char metadata[512]; @@ -2451,8 +2618,8 @@ static UINT32 header_guess_unitbytes(chd_file *chd) static chd_error header_read(chd_file *chd, chd_header *header) { - UINT8 rawheader[CHD_MAX_HEADER_SIZE]; - UINT32 count; + uint8_t rawheader[CHD_MAX_HEADER_SIZE]; + uint32_t count; /* punt if NULL */ if (header == NULL) @@ -2474,8 +2641,8 @@ static chd_error header_read(chd_file *chd, chd_header *header) /* extract the direct data */ memset(header, 0, sizeof(*header)); - header->length = get_bigendian_uint32(&rawheader[8]); - header->version = get_bigendian_uint32(&rawheader[12]); + header->length = get_bigendian_uint32_t(&rawheader[8]); + header->version = get_bigendian_uint32_t(&rawheader[12]); /* make sure it's a version we understand */ if (header->version == 0 || header->version > CHD_HEADER_VERSION) @@ -2491,8 +2658,8 @@ static chd_error header_read(chd_file *chd, chd_header *header) return CHDERR_INVALID_DATA; /* extract the common data */ - header->flags = get_bigendian_uint32(&rawheader[16]); - header->compression[0] = get_bigendian_uint32(&rawheader[20]); + header->flags = get_bigendian_uint32_t(&rawheader[16]); + header->compression[0] = get_bigendian_uint32_t(&rawheader[20]); header->compression[1] = CHD_CODEC_NONE; header->compression[2] = CHD_CODEC_NONE; header->compression[3] = CHD_CODEC_NONE; @@ -2500,15 +2667,15 @@ static chd_error header_read(chd_file *chd, chd_header *header) /* extract the V1/V2-specific data */ if (header->version < 3) { - int seclen = (header->version == 1) ? CHD_V1_SECTOR_SIZE : get_bigendian_uint32(&rawheader[76]); - header->obsolete_hunksize = get_bigendian_uint32(&rawheader[24]); - header->totalhunks = get_bigendian_uint32(&rawheader[28]); - header->obsolete_cylinders = get_bigendian_uint32(&rawheader[32]); - header->obsolete_heads = get_bigendian_uint32(&rawheader[36]); - header->obsolete_sectors = get_bigendian_uint32(&rawheader[40]); + int seclen = (header->version == 1) ? CHD_V1_SECTOR_SIZE : get_bigendian_uint32_t(&rawheader[76]); + header->obsolete_hunksize = get_bigendian_uint32_t(&rawheader[24]); + header->totalhunks = get_bigendian_uint32_t(&rawheader[28]); + header->obsolete_cylinders = get_bigendian_uint32_t(&rawheader[32]); + header->obsolete_heads = get_bigendian_uint32_t(&rawheader[36]); + header->obsolete_sectors = get_bigendian_uint32_t(&rawheader[40]); memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES); 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->logicalbytes = (uint64_t)header->obsolete_cylinders * (uint64_t)header->obsolete_heads * (uint64_t)header->obsolete_sectors * (uint64_t)seclen; header->hunkbytes = seclen * header->obsolete_hunksize; header->unitbytes = header_guess_unitbytes(chd); if (header->unitbytes == 0) @@ -2520,12 +2687,12 @@ static chd_error header_read(chd_file *chd, chd_header *header) /* extract the V3-specific data */ else if (header->version == 3) { - header->totalhunks = get_bigendian_uint32(&rawheader[24]); - header->logicalbytes = get_bigendian_uint64(&rawheader[28]); - header->metaoffset = get_bigendian_uint64(&rawheader[36]); + header->totalhunks = get_bigendian_uint32_t(&rawheader[24]); + header->logicalbytes = get_bigendian_uint64_t(&rawheader[28]); + header->metaoffset = get_bigendian_uint64_t(&rawheader[36]); memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES); memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES); - header->hunkbytes = get_bigendian_uint32(&rawheader[76]); + header->hunkbytes = get_bigendian_uint32_t(&rawheader[76]); header->unitbytes = header_guess_unitbytes(chd); if (header->unitbytes == 0) return CHDERR_INVALID_DATA; @@ -2537,10 +2704,10 @@ static chd_error header_read(chd_file *chd, chd_header *header) /* extract the V4-specific data */ else if (header->version == 4) { - header->totalhunks = get_bigendian_uint32(&rawheader[24]); - header->logicalbytes = get_bigendian_uint64(&rawheader[28]); - header->metaoffset = get_bigendian_uint64(&rawheader[36]); - header->hunkbytes = get_bigendian_uint32(&rawheader[44]); + header->totalhunks = get_bigendian_uint32_t(&rawheader[24]); + header->logicalbytes = get_bigendian_uint64_t(&rawheader[28]); + header->metaoffset = get_bigendian_uint64_t(&rawheader[36]); + header->hunkbytes = get_bigendian_uint32_t(&rawheader[44]); header->unitbytes = header_guess_unitbytes(chd); if (header->unitbytes == 0) return CHDERR_INVALID_DATA; @@ -2554,18 +2721,18 @@ static chd_error header_read(chd_file *chd, 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->compression[0] = get_bigendian_uint32_t(&rawheader[16]); + header->compression[1] = get_bigendian_uint32_t(&rawheader[20]); + header->compression[2] = get_bigendian_uint32_t(&rawheader[24]); + header->compression[3] = get_bigendian_uint32_t(&rawheader[28]); + header->logicalbytes = get_bigendian_uint64_t(&rawheader[32]); + header->mapoffset = get_bigendian_uint64_t(&rawheader[40]); + header->metaoffset = get_bigendian_uint64_t(&rawheader[48]); + header->hunkbytes = get_bigendian_uint32_t(&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]); + header->unitbytes = get_bigendian_uint32_t(&rawheader[60]); if (header->unitbytes == 0) return CHDERR_INVALID_DATA; header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes; @@ -2599,7 +2766,7 @@ static chd_error header_read(chd_file *chd, chd_header *header) hunk -------------------------------------------------*/ -static UINT8* hunk_read_compressed(chd_file *chd, UINT64 offset, size_t size) +static uint8_t* hunk_read_compressed(chd_file *chd, uint64_t offset, size_t size) { #ifdef _MSC_VER size_t bytes; @@ -2608,10 +2775,17 @@ static UINT8* hunk_read_compressed(chd_file *chd, UINT64 offset, size_t size) #endif if (chd->file_cache != NULL) { - return chd->file_cache + offset; + if ((offset + size) > chd->file_size || (offset + size) < offset) + return NULL; + else + return chd->file_cache + offset; } else { + /* make sure it isn't larger than the compressed buffer */ + if (size > chd->header.hunkbytes) + return NULL; + core_fseek(chd->file, offset, SEEK_SET); bytes = core_fread(chd->file, chd->compressed, size); if (bytes != size) @@ -2625,7 +2799,7 @@ static UINT8* hunk_read_compressed(chd_file *chd, UINT64 offset, size_t size) hunk -------------------------------------------------*/ -static chd_error hunk_read_uncompressed(chd_file *chd, UINT64 offset, size_t size, UINT8 *dest) +static chd_error hunk_read_uncompressed(chd_file *chd, uint64_t offset, size_t size, uint8_t *dest) { #ifdef _MSC_VER size_t bytes; @@ -2634,6 +2808,9 @@ static chd_error hunk_read_uncompressed(chd_file *chd, UINT64 offset, size_t siz #endif if (chd->file_cache != NULL) { + if ((offset + size) > chd->file_size || (offset + size) < offset) + return CHDERR_READ_ERROR; + memcpy(dest, chd->file_cache + offset, size); } else @@ -2652,7 +2829,7 @@ static chd_error hunk_read_uncompressed(chd_file *chd, UINT64 offset, size_t siz the CHD's hunk cache -------------------------------------------------*/ -static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum) +static chd_error hunk_read_into_cache(chd_file *chd, uint32_t hunknum) { chd_error err; @@ -2681,7 +2858,7 @@ static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum) memory at the given location -------------------------------------------------*/ -static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest) +static chd_error hunk_read_into_memory(chd_file *chd, uint32_t hunknum, uint8_t *dest) { chd_error err; @@ -2699,8 +2876,8 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des if (chd->header.version < 5) { map_entry *entry = &chd->map[hunknum]; - UINT32 bytes; - UINT8* compressed_bytes; + uint32_t bytes; + uint8_t* compressed_bytes; /* switch off the entry type */ switch (entry->flags & MAP_ENTRY_FLAG_TYPE_MASK) @@ -2736,7 +2913,7 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des /* mini-compressed data */ case V34_MAP_ENTRY_TYPE_MINI: - put_bigendian_uint64(&dest[0], entry->offset); + put_bigendian_uint64_t(&dest[0], entry->offset); for (bytes = 8; bytes < chd->header.hunkbytes; bytes++) dest[bytes] = dest[bytes - 8]; break; @@ -2768,12 +2945,12 @@ 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; + uint8_t* compressed_bytes; /* uncompressed case */ if (!chd_compressed(&chd->header)) { - blockoffs = (uint64_t)get_bigendian_uint32(rawmap) * (uint64_t)chd->header.hunkbytes; + blockoffs = (uint64_t)get_bigendian_uint32_t(rawmap) * (uint64_t)chd->header.hunkbytes; if (blockoffs != 0) { core_fseek(chd->file, blockoffs, SEEK_SET); int result = core_fread(chd->file, dest, chd->header.hunkbytes); @@ -2872,15 +3049,15 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des case COMPRESSION_PARENT: if (chd->parent == NULL) return CHDERR_REQUIRES_PARENT; - UINT8 units_in_hunk = chd->header.hunkbytes / chd->header.unitbytes; + uint8_t units_in_hunk = chd->header.hunkbytes / chd->header.unitbytes; /* blockoffs is aligned to units_in_hunk */ if (blockoffs % units_in_hunk == 0) { return hunk_read_into_memory(chd->parent, blockoffs / units_in_hunk, dest); /* blockoffs is not aligned to units_in_hunk */ } else { - UINT32 unit_in_hunk = blockoffs % units_in_hunk; - UINT8 *buf = malloc(chd->header.hunkbytes); + uint32_t unit_in_hunk = blockoffs % units_in_hunk; + uint8_t *buf = malloc(chd->header.hunkbytes); /* Read first half of hunk which contains blockoffs */ err = hunk_read_into_memory(chd->parent, blockoffs / units_in_hunk, buf); if (err != CHDERR_NONE) { @@ -2915,13 +3092,13 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des static chd_error map_read(chd_file *chd) { - UINT32 entrysize = (chd->header.version < 3) ? OLD_MAP_ENTRY_SIZE : MAP_ENTRY_SIZE; - UINT8 raw_map_entries[MAP_STACK_ENTRIES * MAP_ENTRY_SIZE]; - UINT64 fileoffset, maxoffset = 0; - UINT8 cookie[MAP_ENTRY_SIZE]; - UINT32 count; + uint32_t entrysize = (chd->header.version < 3) ? OLD_MAP_ENTRY_SIZE : MAP_ENTRY_SIZE; + uint8_t raw_map_entries[MAP_STACK_ENTRIES * MAP_ENTRY_SIZE]; + uint64_t fileoffset, maxoffset = 0; + uint8_t cookie[MAP_ENTRY_SIZE]; + uint32_t count; chd_error err; - UINT32 i; + uint32_t i; /* first allocate memory */ chd->map = (map_entry *)malloc(sizeof(chd->map[0]) * chd->header.totalhunks); @@ -2976,7 +3153,7 @@ static chd_error map_read(chd_file *chd) } /* verify the length */ - if (maxoffset > core_fsize(chd->file)) + if (maxoffset > chd->file_size) { err = CHDERR_INVALID_FILE; goto cleanup; @@ -2998,7 +3175,7 @@ cleanup: metadata_find_entry - find a metadata entry -------------------------------------------------*/ -static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry) +static chd_error metadata_find_entry(chd_file *chd, uint32_t metatag, uint32_t metaindex, metadata_entry *metaentry) { /* start at the beginning */ metaentry->offset = chd->header.metaoffset; @@ -3007,19 +3184,20 @@ static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metai /* loop until we run out of options */ while (metaentry->offset != 0) { - UINT8 raw_meta_header[METADATA_HEADER_SIZE]; - UINT32 count; + uint8_t raw_meta_header[METADATA_HEADER_SIZE]; + uint32_t count; /* read the raw header */ - core_fseek(chd->file, metaentry->offset, SEEK_SET); + if (core_fseek(chd->file, metaentry->offset, SEEK_SET) != 0) + break; count = core_fread(chd->file, raw_meta_header, sizeof(raw_meta_header)); if (count != sizeof(raw_meta_header)) break; /* extract the data */ - metaentry->metatag = get_bigendian_uint32(&raw_meta_header[0]); - metaentry->length = get_bigendian_uint32(&raw_meta_header[4]); - metaentry->next = get_bigendian_uint64(&raw_meta_header[8]); + metaentry->metatag = get_bigendian_uint32_t(&raw_meta_header[0]); + metaentry->length = get_bigendian_uint32_t(&raw_meta_header[4]); + metaentry->next = get_bigendian_uint64_t(&raw_meta_header[8]); /* flags are encoded in the high byte of length */ metaentry->flags = metaentry->length >> 24; @@ -3136,7 +3314,7 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size) { zlib_allocator *alloc = (zlib_allocator *)opaque; uintptr_t paddr = 0; - UINT32 *ptr; + uint32_t *ptr; int i; /* compute the size, rounding to the nearest 1k */ @@ -3157,7 +3335,7 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size) } /* alloc a new one */ - ptr = (UINT32 *)malloc(size + sizeof(UINT32) + ZLIB_MIN_ALIGNMENT_BYTES); + ptr = (uint32_t *)malloc(size + sizeof(uint32_t) + ZLIB_MIN_ALIGNMENT_BYTES); if (!ptr) return NULL; @@ -3166,7 +3344,7 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size) if (!alloc->allocptr[i]) { alloc->allocptr[i] = ptr; - paddr = (((uintptr_t)ptr) + sizeof(UINT32) + (ZLIB_MIN_ALIGNMENT_BYTES-1)) & (~(ZLIB_MIN_ALIGNMENT_BYTES-1)); + paddr = (((uintptr_t)ptr) + sizeof(uint32_t) + (ZLIB_MIN_ALIGNMENT_BYTES-1)) & (~(ZLIB_MIN_ALIGNMENT_BYTES-1)); alloc->allocptr2[i] = (uint32_t*)paddr; break; } @@ -3186,7 +3364,7 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size) static void zlib_fast_free(voidpf opaque, voidpf address) { zlib_allocator *alloc = (zlib_allocator *)opaque; - UINT32 *ptr = (UINT32 *)address; + uint32_t *ptr = (uint32_t *)address; int i; /* find the hunk */ @@ -3234,7 +3412,7 @@ static core_file *core_stdio_fopen(char const *path) { core_stdio_fsize - core_file function for getting file size with stdio -------------------------------------------------*/ -static UINT64 core_stdio_fsize(core_file *file) { +static uint64_t core_stdio_fsize(core_file *file) { #if defined USE_LIBRETRO_VFS #define core_stdio_fseek_impl fseek #define core_stdio_ftell_impl ftell @@ -3252,7 +3430,7 @@ static UINT64 core_stdio_fsize(core_file *file) { #define core_stdio_ftell_impl ftello #endif FILE *fp; - UINT64 p, rv; + uint64_t p, rv; fp = (FILE*)file->argp; p = core_stdio_ftell_impl(fp); @@ -3292,6 +3470,6 @@ static int core_stdio_fclose_nonowner(core_file *file) { /*------------------------------------------------- core_stdio_fseek - core_file wrapper over fclose -------------------------------------------------*/ -static int core_stdio_fseek(core_file* file, INT64 offset, int whence) { +static int core_stdio_fseek(core_file* file, int64_t offset, int whence) { return core_stdio_fseek_impl((FILE*)file->argp, offset, whence); } diff --git a/3rdparty/libchdr/src/libchdr_huffman.c b/3rdparty/libchdr/src/libchdr_huffman.c index 556aa346fb..2332104b05 100644 --- a/3rdparty/libchdr/src/libchdr_huffman.c +++ b/3rdparty/libchdr/src/libchdr_huffman.c @@ -230,7 +230,9 @@ enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, stru return error; /* build the lookup table */ - huffman_build_lookup_table(decoder); + error = huffman_build_lookup_table(decoder); + if (error != HUFFERR_NONE) + return error; /* determine final input length and report errors */ return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE; @@ -271,8 +273,16 @@ enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, /* then regenerate the tree */ error = huffman_assign_canonical_codes(smallhuff); if (error != HUFFERR_NONE) + { + delete_huffman_decoder(smallhuff); return error; - huffman_build_lookup_table(smallhuff); + } + error = huffman_build_lookup_table(smallhuff); + if (error != HUFFERR_NONE) + { + delete_huffman_decoder(smallhuff); + return error; + } /* determine the maximum length of an RLE count */ temp = decoder->numcodes - 9; @@ -308,7 +318,9 @@ enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, return error; /* build the lookup table */ - huffman_build_lookup_table(decoder); + error = huffman_build_lookup_table(decoder); + if (error != HUFFERR_NONE) + return error; /* determine final input length and report errors */ return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE; @@ -523,8 +535,9 @@ enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decode *------------------------------------------------- */ -void huffman_build_lookup_table(struct huffman_decoder* decoder) +enum huffman_error huffman_build_lookup_table(struct huffman_decoder* decoder) { + const lookup_value* lookupend = &decoder->lookup[(1u << decoder->maxbits)]; uint32_t curcode; /* iterate over all codes */ for (curcode = 0; curcode < decoder->numcodes; curcode++) @@ -533,9 +546,10 @@ void huffman_build_lookup_table(struct huffman_decoder* decoder) struct node_t* node = &decoder->huffnode[curcode]; if (node->numbits > 0) { - int shift; - lookup_value *dest; - lookup_value *destend; + int shift; + lookup_value *dest; + lookup_value *destend; + /* set up the entry */ lookup_value value = MAKE_LOOKUP(curcode, node->numbits); @@ -543,8 +557,12 @@ void huffman_build_lookup_table(struct huffman_decoder* decoder) shift = decoder->maxbits - node->numbits; dest = &decoder->lookup[node->bits << shift]; destend = &decoder->lookup[((node->bits + 1) << shift) - 1]; + if (dest >= lookupend || destend >= lookupend || destend < dest) + return HUFFERR_INTERNAL_INCONSISTENCY; while (dest <= destend) *dest++ = value; } } + + return HUFFERR_NONE; }