From d4964f6a68d2cea980edc1b2b2bacb089b1bc184 Mon Sep 17 00:00:00 2001 From: retro-wertz Date: Sat, 9 Dec 2017 14:19:42 +0800 Subject: [PATCH] chd: Add precache option --- deps/libchdr/chd.c | 95 ++++++++++++++++++++++++++++++++++++++-------- deps/libchdr/chd.h | 2 + 2 files changed, 82 insertions(+), 15 deletions(-) diff --git a/deps/libchdr/chd.c b/deps/libchdr/chd.c index 9adecc66..f9535dab 100644 --- a/deps/libchdr/chd.c +++ b/deps/libchdr/chd.c @@ -59,6 +59,8 @@ typedef unsigned char Byte; #include +#include "../deps/crypto/md5.h" + #define TRUE 1 #define FALSE 0 @@ -316,6 +318,8 @@ struct _chd_file UINT32 async_hunknum; /* hunk index for asynchronous operations */ void * async_buffer; /* buffer pointer for asynchronous operations */ + + UINT8 * file_cache; /* cache of underlying file */ }; @@ -1490,6 +1494,31 @@ chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file ** return err; } +chd_error chd_precache(chd_file *chd) +{ + ssize_t size, count; + + if (chd->file_cache == NULL) + { + core_fseek(chd->file, 0, SEEK_END); + size = core_ftell(chd->file); + if (size <= 0) + return CHDERR_INVALID_DATA; + chd->file_cache = malloc(size); + if (chd->file_cache == NULL) + return CHDERR_OUT_OF_MEMORY; + core_fseek(chd->file, 0, SEEK_SET); + count = core_fread(chd->file, chd->file_cache, size); + if (count != size) + { + free(chd->file_cache); + chd->file_cache = NULL; + return CHDERR_READ_ERROR; + } + } + + return CHDERR_NONE; +} /*------------------------------------------------- chd_close - close a CHD file for access @@ -1567,6 +1596,9 @@ void chd_close(chd_file *chd) if (PRINTF_MAX_HUNK) printf("Max hunk = %d/%d\n", chd->maxhunk, chd->header.totalhunks); + if (chd->file_cache) + free(chd->file_cache); + /* free our memory */ free(chd); } @@ -1990,6 +2022,39 @@ static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum) return CHDERR_NONE; } +static UINT8* read_compressed(chd_file *chd, UINT64 offset, size_t size) +{ + ssize_t bytes; + if (chd->file_cache != NULL) + { + return chd->file_cache + offset; + } + else + { + core_fseek(chd->file, offset, SEEK_SET); + bytes = core_fread(chd->file, chd->compressed, size); + if (bytes != size) + return NULL; + return chd->compressed; + } +} + +static chd_error read_uncompressed(chd_file *chd, UINT64 offset, size_t size, UINT8 *dest) +{ + ssize_t bytes; + if (chd->file_cache != NULL) + { + memcpy(dest, chd->file_cache + offset, size); + } + else + { + core_fseek(chd->file, offset, SEEK_SET); + bytes = core_fread(chd->file, dest, size); + if (bytes != size) + return CHDERR_READ_ERROR; + } + return CHDERR_NONE; +} /*------------------------------------------------- hunk_read_into_memory - read a hunk into @@ -2020,17 +2085,15 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des case V34_MAP_ENTRY_TYPE_COMPRESSED: { void* codec; - /* read it into the decompression buffer */ - core_fseek(chd->file, entry->offset, SEEK_SET); - bytes = core_fread(chd->file, chd->compressed, entry->length); - if (bytes != entry->length) - return CHDERR_READ_ERROR; + UINT8 *bytes = read_compressed(chd, entry->offset, entry->length); + if (bytes == NULL) + return CHDERR_READ_ERROR; /* now decompress using the codec */ err = CHDERR_NONE; codec = &chd->zlib_codec_data; if (chd->codecintf[0]->decompress != NULL) - err = (*chd->codecintf[0]->decompress)(codec, chd->compressed, entry->length, dest, chd->header.hunkbytes); + err = (*chd->codecintf[0]->decompress)(codec, bytes, entry->length, dest, chd->header.hunkbytes); if (err != CHDERR_NONE) return err; } @@ -2038,10 +2101,9 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des /* uncompressed data */ case V34_MAP_ENTRY_TYPE_UNCOMPRESSED: - core_fseek(chd->file, entry->offset, SEEK_SET); - bytes = core_fread(chd->file, dest, chd->header.hunkbytes); - if (bytes != chd->header.hunkbytes) - return CHDERR_READ_ERROR; + err = read_uncompressed(chd, entry->offset, chd->header.hunkbytes, dest); + if (err != CHDERR_NONE) + return err; break; /* mini-compressed data */ @@ -2075,6 +2137,7 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des uint16_t blockcrc; void* codec = NULL; uint8_t *rawmap = &chd->header.rawmap[chd->header.mapentrybytes * hunknum]; + UINT8 *bytes; // uncompressed case /* TODO @@ -2102,8 +2165,9 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des case COMPRESSION_TYPE_1: case COMPRESSION_TYPE_2: case COMPRESSION_TYPE_3: - core_fseek(chd->file, blockoffs, SEEK_SET); - core_fread(chd->file, chd->compressed, blocklen); + bytes = read_compressed(chd, blockoffs, blocklen); + if (bytes == NULL) + return CHDERR_READ_ERROR; switch (chd->codecintf[rawmap[0]]->compression) { case CHD_CODEC_CD_LZMA: @@ -2120,14 +2184,15 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des } if (codec==NULL) return CHDERR_DECOMPRESSION_ERROR; - chd->codecintf[rawmap[0]]->decompress(codec, chd->compressed, blocklen, dest, chd->header.hunkbytes); + chd->codecintf[rawmap[0]]->decompress(codec, bytes, blocklen, dest, chd->header.hunkbytes); if (dest != NULL && crc16(dest, chd->header.hunkbytes) != blockcrc) return CHDERR_DECOMPRESSION_ERROR; return CHDERR_NONE; case COMPRESSION_NONE: - core_fseek(chd->file, blockoffs, SEEK_SET); - core_fread(chd->file, dest, chd->header.hunkbytes); + err = read_uncompressed(chd, blockoffs, blocklen, dest); + if (err != CHDERR_NONE) + return err; if (crc16(dest, chd->header.hunkbytes) != blockcrc) return CHDERR_DECOMPRESSION_ERROR; return CHDERR_NONE; diff --git a/deps/libchdr/chd.h b/deps/libchdr/chd.h index a3a44b84..37aeab40 100644 --- a/deps/libchdr/chd.h +++ b/deps/libchdr/chd.h @@ -349,6 +349,8 @@ struct _chd_verify_result /* open an existing CHD file */ chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd); +/* precache underlying file */ +chd_error chd_precache(chd_file *chd); /* close a CHD file */ void chd_close(chd_file *chd);