X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=deps%2Flibchdr%2Fsrc%2Flibchdr_chd.c;h=d2bf4d04eea00c7f2381651ab549bea7b1448fa6;hb=e2fb1389dc12376acb84e4993ed3b08760257252;hp=913abaa2a9f977960067815fb481dd91366d0ad5;hpb=2ff0b5124f2e17a290121e1eeecf45db1d9e2c85;p=pcsx_rearmed.git diff --git a/deps/libchdr/src/libchdr_chd.c b/deps/libchdr/src/libchdr_chd.c index 913abaa2..d2bf4d04 100644 --- a/deps/libchdr/src/libchdr_chd.c +++ b/deps/libchdr/src/libchdr_chd.c @@ -50,6 +50,9 @@ #include "LzmaEnc.h" #include "LzmaDec.h" +#if defined(__PS3__) || defined(__PSL1GHT__) +#define __MACTYPES__ +#endif #include "zlib.h" #undef TRUE @@ -224,6 +227,12 @@ struct _lzma_codec_data lzma_allocator allocator; }; +typedef struct _huff_codec_data huff_codec_data; +struct _huff_codec_data +{ + struct huffman_decoder* decoder; +}; + /* codec-private data for the CDZL codec */ typedef struct _cdzl_codec_data cdzl_codec_data; struct _cdzl_codec_data { @@ -246,6 +255,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 { @@ -264,7 +281,6 @@ 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,6 +299,9 @@ 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 */ 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 */ @@ -306,6 +325,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 +362,16 @@ 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); + /* cdzl compression codec */ static chd_error cdzl_codec_init(void* codec, uint32_t hunkbytes); static void cdzl_codec_free(void* codec); @@ -746,24 +783,121 @@ 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 err; + } + + // then decode the data + for (uint32_t 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) @@ -901,6 +1035,39 @@ 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 CD zlib compression */ { CHD_CODEC_CD_ZLIB, @@ -1160,7 +1327,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 +1349,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 +1368,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 +1517,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; @@ -1382,8 +1576,15 @@ CHD_EXPORT chd_error chd_open_file(core_file *file, int mode, chd_file *parent, EARLY_EXIT(err = CHDERR_UNSUPPORTED_VERSION); /* if we need a parent, make sure we have one */ - if (parent == NULL && (newchd->header.flags & CHDFLAGS_HAS_PARENT)) - EARLY_EXIT(err = CHDERR_REQUIRES_PARENT); + if (parent == NULL) + { + /* Detect parent requirement for versions below 5 */ + if (newchd->header.version < 5 && newchd->header.flags & CHDFLAGS_HAS_PARENT) + EARLY_EXIT(err = CHDERR_REQUIRES_PARENT); + /* Detection for version 5 and above - if parentsha1 != 0, we have a parent */ + else if (newchd->header.version >= 5 && memcmp(nullsha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0) + EARLY_EXIT(err = CHDERR_REQUIRES_PARENT); + } /* make sure we have a valid parent */ if (parent != NULL) @@ -1482,6 +1683,18 @@ 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_CD_ZLIB: codec = &newchd->cdzl_codec_data; break; @@ -1522,17 +1735,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) @@ -1560,6 +1769,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) { @@ -1572,7 +1787,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; @@ -1580,12 +1795,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)) @@ -1622,18 +1832,30 @@ 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_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; @@ -1667,7 +1889,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 @@ -1676,6 +1898,9 @@ CHD_EXPORT void chd_close(chd_file *chd) if (chd->file_cache) free(chd->file_cache); + if (chd->parent) + chd_close(chd->parent); + /* free our memory */ free(chd); } @@ -1749,6 +1974,41 @@ CHD_EXPORT const chd_header *chd_get_header(chd_file *chd) return &chd->header; } +/*------------------------------------------------- + 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 = CHDERR_NONE; + chd_file chd; + + /* punt if NULL */ + if (filename == NULL || header == NULL) + EARLY_EXIT(err = CHDERR_INVALID_PARAMETER); + + /* open the file */ + chd.file = core_stdio_fopen(filename); + if (chd.file == NULL) + EARLY_EXIT(err = CHDERR_FILE_NOT_FOUND); + + /* attempt to read the header */ + err = header_read(&chd, header); + if (err != CHDERR_NONE) + EARLY_EXIT(err); + + /* validate the header */ + err = header_validate(header); + if (err != CHDERR_NONE) + EARLY_EXIT(err); + +cleanup: + if (chd.file != NULL) + core_fclose(chd.file); + + return err; +} + /*************************************************************************** CORE DATA READ/WRITE ***************************************************************************/ @@ -2016,6 +2276,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; } @@ -2030,6 +2292,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); @@ -2043,6 +2307,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); @@ -2061,8 +2327,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); @@ -2302,18 +2572,30 @@ 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_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; @@ -2343,13 +2625,33 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des return hunk_read_into_memory(chd, blockoffs, dest); case COMPRESSION_PARENT: -#if 0 - /* TODO */ - if (m_parent_missing) + if (chd->parent == NULL) return CHDERR_REQUIRES_PARENT; - return m_parent->read_bytes(uint64_t(blockoffs) * uint64_t(m_parent->unit_bytes()), dest, m_hunkbytes); -#endif - return CHDERR_DECOMPRESSION_ERROR; + UINT8 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); + /* Read first half of hunk which contains blockoffs */ + err = hunk_read_into_memory(chd->parent, blockoffs / units_in_hunk, buf); + if (err != CHDERR_NONE) { + free(buf); + return err; + } + memcpy(dest, buf + unit_in_hunk * chd->header.unitbytes, (units_in_hunk - unit_in_hunk) * chd->header.unitbytes); + /* Read second half of hunk which contains blockoffs */ + err = hunk_read_into_memory(chd->parent, (blockoffs / units_in_hunk) + 1, buf); + if (err != CHDERR_NONE) { + free(buf); + return err; + } + memcpy(dest + (units_in_hunk - unit_in_hunk) * chd->header.unitbytes, buf, unit_in_hunk * chd->header.unitbytes); + free(buf); + } } return CHDERR_NONE; } @@ -2374,7 +2676,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); @@ -2525,10 +2827,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; } @@ -2544,8 +2842,6 @@ static void zlib_codec_free(void *codec) /* deinit the streams */ if (data != NULL) { - int i; - inflateEnd(&data->inflater); /* free our fast memory */ @@ -2670,3 +2966,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); +}