Add chd_precache code to libchdr

This commit is contained in:
twinaphex 2018-04-22 18:04:45 +02:00
parent 1fd2cf1ff5
commit 7bef8746a3
2 changed files with 88 additions and 30 deletions

View File

@ -282,6 +282,7 @@ struct _chd_file
#ifdef NEED_CACHE_HUNK #ifdef NEED_CACHE_HUNK
UINT32 maxhunk; /* maximum hunk accessed */ UINT32 maxhunk; /* maximum hunk accessed */
#endif #endif
UINT8 * file_cache; /* cache of underlying file */
}; };
/*************************************************************************** /***************************************************************************
@ -1530,6 +1531,32 @@ cleanup:
return err; return err;
} }
chd_error chd_precache(chd_file *chd)
{
ssize_t size, count;
if (!chd->file_cache)
{
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 chd_close - close a CHD file for access
-------------------------------------------------*/ -------------------------------------------------*/
@ -1602,6 +1629,9 @@ void chd_close(chd_file *chd)
if (PRINTF_MAX_HUNK) printf("Max hunk = %d/%d\n", chd->maxhunk, chd->header.totalhunks); if (PRINTF_MAX_HUNK) printf("Max hunk = %d/%d\n", chd->maxhunk, chd->header.totalhunks);
#endif #endif
if (chd->file_cache)
free(chd->file_cache);
/* free our memory */ /* free our memory */
free(chd); free(chd);
} }
@ -2037,6 +2067,35 @@ static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum)
} }
#endif #endif
static UINT8* read_compressed(chd_file *chd, UINT64 offset, size_t size)
{
ssize_t bytes;
if (chd->file_cache)
return chd->file_cache + offset;
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)
{
memcpy(dest, chd->file_cache + offset, size);
return CHDERR_NONE;
}
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 hunk_read_into_memory - read a hunk into
memory at the given location memory at the given location
@ -2068,30 +2127,28 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
{ {
/* compressed data */ /* compressed data */
case V34_MAP_ENTRY_TYPE_COMPRESSED: case V34_MAP_ENTRY_TYPE_COMPRESSED:
{
void *codec;
UINT8 *bytes = read_compressed(chd, entry->offset,
entry->length);
if (bytes == NULL)
return CHDERR_READ_ERROR;
/* read it into the decompression buffer */ /* now decompress using the codec */
if (core_fseek(chd->file, entry->offset, SEEK_SET) != 0) err = CHDERR_NONE;
return CHDERR_READ_ERROR; codec = &chd->zlib_codec_data;
bytes = core_fread(chd->file, chd->compressed, entry->length); if (chd->codecintf[0]->decompress != NULL)
if (bytes != entry->length) err = (*chd->codecintf[0]->decompress)(codec, chd->compressed, entry->length, dest, chd->header.hunkbytes);
return CHDERR_READ_ERROR; if (err != CHDERR_NONE)
return err;
/* 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);
if (err != CHDERR_NONE)
return err;
break; break;
/* uncompressed data */ /* uncompressed data */
case V34_MAP_ENTRY_TYPE_UNCOMPRESSED: case V34_MAP_ENTRY_TYPE_UNCOMPRESSED:
if (core_fseek(chd->file, entry->offset, SEEK_SET) != 0) err = read_uncompressed(chd, entry->offset, chd->header.hunkbytes, dest);
return CHDERR_READ_ERROR; if (err != CHDERR_NONE)
bytes = core_fread(chd->file, dest, chd->header.hunkbytes); return err;
if (bytes != chd->header.hunkbytes)
return CHDERR_READ_ERROR;
break; break;
/* mini-compressed data */ /* mini-compressed data */
@ -2128,6 +2185,7 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
uint16_t blockcrc; uint16_t blockcrc;
#endif #endif
uint8_t *rawmap = &chd->header.rawmap[chd->header.mapentrybytes * hunknum]; uint8_t *rawmap = &chd->header.rawmap[chd->header.mapentrybytes * hunknum];
UINT8 *bytes;
#if 0 #if 0
/* uncompressed case - TODO */ /* uncompressed case - TODO */
@ -2158,11 +2216,9 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
case COMPRESSION_TYPE_1: case COMPRESSION_TYPE_1:
case COMPRESSION_TYPE_2: case COMPRESSION_TYPE_2:
case COMPRESSION_TYPE_3: case COMPRESSION_TYPE_3:
if (core_fseek(chd->file, blockoffs, SEEK_SET) != 0) bytes = read_compressed(chd, blockoffs, blocklen);
return CHDERR_READ_ERROR; if (bytes == NULL)
if(core_fread(chd->file, chd->compressed, blocklen) != blocklen) return CHDERR_READ_ERROR;
return CHDERR_READ_ERROR;
switch (chd->codecintf[rawmap[0]]->compression) switch (chd->codecintf[rawmap[0]]->compression)
{ {
case CHD_CODEC_CD_LZMA: case CHD_CODEC_CD_LZMA:
@ -2189,13 +2245,12 @@ static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *des
return CHDERR_NONE; return CHDERR_NONE;
case COMPRESSION_NONE: case COMPRESSION_NONE:
if (core_fseek(chd->file, blockoffs, SEEK_SET) != 0) err = read_uncompressed(chd, blockoffs, blocklen, dest);
return CHDERR_READ_ERROR; if (err != CHDERR_NONE)
if (core_fread(chd->file, dest, chd->header.hunkbytes) != chd->header.hunkbytes) return err;
return CHDERR_READ_ERROR;
#ifdef VERIFY_BLOCK_CRC #ifdef VERIFY_BLOCK_CRC
if (crc16(dest, chd->header.hunkbytes) != blockcrc) if (crc16(dest, chd->header.hunkbytes) != blockcrc)
return CHDERR_DECOMPRESSION_ERROR; return CHDERR_DECOMPRESSION_ERROR;
#endif #endif
return CHDERR_NONE; return CHDERR_NONE;

View File

@ -348,8 +348,11 @@ struct _chd_verify_result
/* open an existing CHD file */ /* open an existing CHD file */
chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **chd); chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **chd);
chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd); chd_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 */ /* close a CHD file */
void chd_close(chd_file *chd); void chd_close(chd_file *chd);