1 /***************************************************************************
5 MAME Compressed Hunks of Data file format
7 ****************************************************************************
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are
16 * Redistributions of source code must retain the above copyright
17 notice, this list of conditions and the following disclaimer.
18 * Redistributions in binary form must reproduce the above copyright
19 notice, this list of conditions and the following disclaimer in
20 the documentation and/or other materials provided with the
22 * Neither the name 'MAME' nor the names of its contributors may be
23 used to endorse or promote products derived from this software
24 without specific prior written permission.
26 THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
27 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29 DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
30 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
34 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
35 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 POSSIBILITY OF SUCH DAMAGE.
38 ***************************************************************************/
45 #include <libchdr/chd.h>
46 #include <libchdr/minmax.h>
47 #include <libchdr/cdrom.h>
48 #include <libchdr/huffman.h>
51 #include <libchdr/flac.h>
55 #include <libchdr/lzma.h>
59 #include <libchdr/libchdr_zlib.h>
62 #include <retro_inline.h>
63 #include <streams/file_stream.h>
68 /***************************************************************************
70 ***************************************************************************/
72 #define PRINTF_MAX_HUNK (0)
74 /***************************************************************************
76 ***************************************************************************/
78 #define MAP_STACK_ENTRIES 512 /* max number of entries to use on the stack */
79 #define MAP_ENTRY_SIZE 16 /* V3 and later */
80 #define OLD_MAP_ENTRY_SIZE 8 /* V1-V2 */
81 #define METADATA_HEADER_SIZE 16 /* metadata header size */
83 #define CRCMAP_HASH_SIZE 4095 /* number of CRC hashtable entries */
85 #define MAP_ENTRY_FLAG_TYPE_MASK 0x0f /* what type of hunk */
86 #define MAP_ENTRY_FLAG_NO_CRC 0x10 /* no CRC is present */
88 #define CHD_V1_SECTOR_SIZE 512 /* size of a "sector" in the V1 header */
90 #define COOKIE_VALUE 0xbaadf00d
92 #define END_OF_LIST_COOKIE "EndOfListCookie"
96 #ifdef WANT_RAW_DATA_SECTOR
97 const uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 };
100 /* V3-V4 entry types */
103 V34_MAP_ENTRY_TYPE_INVALID = 0, /* invalid type */
104 V34_MAP_ENTRY_TYPE_COMPRESSED = 1, /* standard compression */
105 V34_MAP_ENTRY_TYPE_UNCOMPRESSED = 2, /* uncompressed data */
106 V34_MAP_ENTRY_TYPE_MINI = 3, /* mini: use offset as raw data */
107 V34_MAP_ENTRY_TYPE_SELF_HUNK = 4, /* same as another hunk in this file */
108 V34_MAP_ENTRY_TYPE_PARENT_HUNK = 5, /* same as a hunk in the parent file */
109 V34_MAP_ENTRY_TYPE_2ND_COMPRESSED = 6 /* compressed with secondary algorithm (usually FLAC CDDA) */
112 /* V5 compression types */
116 * these types are live when running */
117 COMPRESSION_TYPE_0 = 0,
119 COMPRESSION_TYPE_1 = 1,
121 COMPRESSION_TYPE_2 = 2,
123 COMPRESSION_TYPE_3 = 3,
124 /* no compression; implicit length = hunkbytes */
125 COMPRESSION_NONE = 4,
126 /* same as another block in this chd */
127 COMPRESSION_SELF = 5,
128 /* same as a hunk's worth of units in the parent chd */
129 COMPRESSION_PARENT = 6,
131 /* start of small RLE run (4-bit length)
132 * these additional pseudo-types are used for compressed encodings: */
133 COMPRESSION_RLE_SMALL,
134 /* start of large RLE run (8-bit length) */
135 COMPRESSION_RLE_LARGE,
136 /* same as the last COMPRESSION_SELF block */
138 /* same as the last COMPRESSION_SELF block + 1 */
140 /* same block in the parent */
141 COMPRESSION_PARENT_SELF,
142 /* same as the last COMPRESSION_PARENT block */
143 COMPRESSION_PARENT_0,
144 /* same as the last COMPRESSION_PARENT block + 1 */
148 /***************************************************************************
150 ***************************************************************************/
152 #define EARLY_EXIT(x) do { (void)(x); goto cleanup; } while (0)
154 /***************************************************************************
156 ***************************************************************************/
158 /* interface to a codec */
159 typedef struct _codec_interface codec_interface;
160 struct _codec_interface
162 UINT32 compression; /* type of compression */
163 const char *compname; /* name of the algorithm */
164 UINT8 lossy; /* is this a lossy algorithm? */
165 chd_error (*init)(void *codec, UINT32 hunkbytes); /* codec initialize */
166 void (*free)(void *codec); /* codec free */
167 chd_error (*decompress)(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); /* decompress data */
168 chd_error (*config)(void *codec, int param, void *config); /* configure */
171 /* a single map entry */
172 typedef struct _map_entry map_entry;
175 UINT64 offset; /* offset within the file of the data */
176 UINT32 crc; /* 32-bit CRC of the data */
177 UINT32 length; /* length of the data */
178 UINT8 flags; /* misc flags */
181 /* a single metadata entry */
182 typedef struct _metadata_entry metadata_entry;
183 struct _metadata_entry
185 UINT64 offset; /* offset within the file of the header */
186 UINT64 next; /* offset within the file of the next header */
187 UINT64 prev; /* offset within the file of the previous header */
188 UINT32 length; /* length of the metadata */
189 UINT32 metatag; /* metadata tag */
190 UINT8 flags; /* flag bits */
193 /* internal representation of an open CHD file */
196 UINT32 cookie; /* cookie, should equal COOKIE_VALUE */
198 RFILE * file; /* handle to the open core file */
199 UINT8 owns_file; /* flag indicating if this file should be closed on chd_close() */
200 chd_header header; /* header, extracted from file */
202 chd_file * parent; /* pointer to parent file, or NULL */
204 map_entry * map; /* array of map entries */
206 #ifdef NEED_CACHE_HUNK
207 UINT8 * cache; /* hunk cache pointer */
208 UINT32 cachehunk; /* index of currently cached hunk */
210 UINT8 * compare; /* hunk compare pointer */
211 UINT32 comparehunk; /* index of current compare data */
214 UINT8 * compressed; /* pointer to buffer for compressed data */
215 const codec_interface * codecintf[4]; /* interface to the codec */
218 zlib_codec_data zlib_codec_data; /* zlib codec data */
219 cdzl_codec_data cdzl_codec_data; /* cdzl codec data */
222 cdlz_codec_data cdlz_codec_data; /* cdlz codec data */
225 cdfl_codec_data cdfl_codec_data; /* cdfl codec data */
228 #ifdef NEED_CACHE_HUNK
229 UINT32 maxhunk; /* maximum hunk accessed */
231 UINT8 * file_cache; /* cache of underlying file */
234 /***************************************************************************
236 ***************************************************************************/
238 static const UINT8 nullmd5[CHD_MD5_BYTES] = { 0 };
239 static const UINT8 nullsha1[CHD_SHA1_BYTES] = { 0 };
241 /***************************************************************************
243 ***************************************************************************/
245 /* internal header operations */
246 static chd_error header_validate(const chd_header *header);
247 static chd_error header_read(chd_file *chd, chd_header *header);
249 /* internal hunk read/write */
250 #ifdef NEED_CACHE_HUNK
251 static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum);
253 static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest);
255 /* internal map access */
256 static chd_error map_read(chd_file *chd);
258 /* metadata management */
259 static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry);
261 /***************************************************************************
263 ***************************************************************************/
265 static const codec_interface codec_interfaces[] =
267 /* "none" or no compression */
279 /* standard zlib compression */
286 zlib_codec_decompress,
290 /* zlib+ compression */
292 CHDCOMPRESSION_ZLIB_PLUS,
297 zlib_codec_decompress,
301 /* V5 zlib compression */
308 zlib_codec_decompress,
312 /* V5 CD zlib compression */
319 cdzl_codec_decompress,
325 /* V5 CD lzma compression */
332 cdlz_codec_decompress,
338 /* V5 CD flac compression */
345 cdfl_codec_decompress,
351 /***************************************************************************
353 ***************************************************************************/
355 /*-------------------------------------------------
356 get_bigendian_uint64 - fetch a UINT64 from
357 the data stream in bigendian order
358 -------------------------------------------------*/
360 static INLINE UINT64 get_bigendian_uint64(const UINT8 *base)
362 return ((UINT64)base[0] << 56) | ((UINT64)base[1] << 48) | ((UINT64)base[2] << 40) | ((UINT64)base[3] << 32) |
363 ((UINT64)base[4] << 24) | ((UINT64)base[5] << 16) | ((UINT64)base[6] << 8) | (UINT64)base[7];
366 /*-------------------------------------------------
367 put_bigendian_uint64 - write a UINT64 to
368 the data stream in bigendian order
369 -------------------------------------------------*/
371 static INLINE void put_bigendian_uint64(UINT8 *base, UINT64 value)
373 base[0] = value >> 56;
374 base[1] = value >> 48;
375 base[2] = value >> 40;
376 base[3] = value >> 32;
377 base[4] = value >> 24;
378 base[5] = value >> 16;
379 base[6] = value >> 8;
383 /*-------------------------------------------------
384 get_bigendian_uint48 - fetch a UINT48 from
385 the data stream in bigendian order
386 -------------------------------------------------*/
388 static INLINE UINT64 get_bigendian_uint48(const UINT8 *base)
390 return ((UINT64)base[0] << 40) | ((UINT64)base[1] << 32) |
391 ((UINT64)base[2] << 24) | ((UINT64)base[3] << 16) | ((UINT64)base[4] << 8) | (UINT64)base[5];
394 /*-------------------------------------------------
395 put_bigendian_uint48 - write a UINT48 to
396 the data stream in bigendian order
397 -------------------------------------------------*/
399 static INLINE void put_bigendian_uint48(UINT8 *base, UINT64 value)
401 value &= 0xffffffffffff;
402 base[0] = value >> 40;
403 base[1] = value >> 32;
404 base[2] = value >> 24;
405 base[3] = value >> 16;
406 base[4] = value >> 8;
409 /*-------------------------------------------------
410 get_bigendian_uint32 - fetch a UINT32 from
411 the data stream in bigendian order
412 -------------------------------------------------*/
414 static INLINE UINT32 get_bigendian_uint32(const UINT8 *base)
416 return (base[0] << 24) | (base[1] << 16) | (base[2] << 8) | base[3];
419 /*-------------------------------------------------
420 put_bigendian_uint32 - write a UINT32 to
421 the data stream in bigendian order
422 -------------------------------------------------*/
425 static INLINE void put_bigendian_uint32(UINT8 *base, UINT32 value)
427 base[0] = value >> 24;
428 base[1] = value >> 16;
429 base[2] = value >> 8;
434 /*-------------------------------------------------
435 put_bigendian_uint24 - write a UINT24 to
436 the data stream in bigendian order
437 -------------------------------------------------*/
439 static INLINE void put_bigendian_uint24(UINT8 *base, UINT32 value)
442 base[0] = value >> 16;
443 base[1] = value >> 8;
447 /*-------------------------------------------------
448 get_bigendian_uint24 - fetch a UINT24 from
449 the data stream in bigendian order
450 -------------------------------------------------*/
452 static INLINE UINT32 get_bigendian_uint24(const UINT8 *base)
454 return (base[0] << 16) | (base[1] << 8) | base[2];
457 /*-------------------------------------------------
458 get_bigendian_uint16 - fetch a UINT16 from
459 the data stream in bigendian order
460 -------------------------------------------------*/
462 static INLINE UINT16 get_bigendian_uint16(const UINT8 *base)
464 return (base[0] << 8) | base[1];
467 /*-------------------------------------------------
468 put_bigendian_uint16 - write a UINT16 to
469 the data stream in bigendian order
470 -------------------------------------------------*/
472 static INLINE void put_bigendian_uint16(UINT8 *base, UINT16 value)
474 base[0] = value >> 8;
478 /*-------------------------------------------------
479 map_extract - extract a single map
480 entry from the datastream
481 -------------------------------------------------*/
483 static INLINE void map_extract(const UINT8 *base, map_entry *entry)
485 entry->offset = get_bigendian_uint64(&base[0]);
486 entry->crc = get_bigendian_uint32(&base[8]);
487 entry->length = get_bigendian_uint16(&base[12]) | (base[14] << 16);
488 entry->flags = base[15];
491 /*-------------------------------------------------
492 map_assemble - write a single map
493 entry to the datastream
494 -------------------------------------------------*/
497 static INLINE void map_assemble(UINT8 *base, map_entry *entry)
499 put_bigendian_uint64(&base[0], entry->offset);
500 put_bigendian_uint32(&base[8], entry->crc);
501 put_bigendian_uint16(&base[12], entry->length);
502 base[14] = entry->length >> 16;
503 base[15] = entry->flags;
507 /*-------------------------------------------------
508 map_size_v5 - calculate CHDv5 map size
509 -------------------------------------------------*/
510 static INLINE int map_size_v5(chd_header* header)
512 return header->hunkcount * header->mapentrybytes;
515 /*-------------------------------------------------
516 crc16 - calculate CRC16 (from hashing.cpp)
517 -------------------------------------------------*/
518 uint16_t crc16(const void *data, uint32_t length)
520 uint16_t crc = 0xffff;
522 static const uint16_t s_table[256] =
524 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
525 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
526 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
527 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
528 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
529 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
530 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
531 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
532 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
533 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
534 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
535 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
536 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
537 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
538 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
539 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
540 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
541 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
542 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
543 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
544 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
545 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
546 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
547 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
548 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
549 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
550 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
551 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
552 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
553 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
554 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
555 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
558 const uint8_t *src = (uint8_t*)data;
560 /* fetch the current value into a local and rip through the source data */
561 while (length-- != 0)
562 crc = (crc << 8) ^ s_table[(crc >> 8) ^ *src++];
566 /*-------------------------------------------------
567 decompress_v5_map - decompress the v5 map
568 -------------------------------------------------*/
570 static chd_error decompress_v5_map(chd_file* chd, chd_header* header)
576 uint32_t last_self = 0;
577 uint64_t last_parent = 0;
578 uint8_t lastcomp = 0;
579 int hunknum, repcount = 0;
580 enum huffman_error err;
581 uint8_t lengthbits, selfbits, parentbits;
583 struct bitstream* bitbuf;
584 struct huffman_decoder* decoder;
586 if (header->mapoffset == 0)
589 memset(header->rawmap, 0xff,map_size_v5(header));
591 return CHDERR_READ_ERROR;
594 /* read the reader */
595 filestream_seek(chd->file, header->mapoffset, SEEK_SET);
596 filestream_read(chd->file, rawbuf, sizeof(rawbuf));
597 mapbytes = get_bigendian_uint32(&rawbuf[0]);
598 firstoffs = get_bigendian_uint48(&rawbuf[4]);
599 mapcrc = get_bigendian_uint16(&rawbuf[10]);
600 lengthbits = rawbuf[12];
601 selfbits = rawbuf[13];
602 parentbits = rawbuf[14];
604 /* now read the map */
605 compressed = (uint8_t*)malloc(sizeof(uint8_t) * mapbytes);
606 if (compressed == NULL)
607 return CHDERR_OUT_OF_MEMORY;
609 filestream_seek(chd->file, header->mapoffset + 16, SEEK_SET);
610 filestream_read(chd->file, compressed, mapbytes);
611 bitbuf = create_bitstream(compressed, sizeof(uint8_t) * mapbytes);
615 return CHDERR_OUT_OF_MEMORY;
618 header->rawmap = (uint8_t*)malloc(sizeof(uint8_t) * map_size_v5(header));
619 if (header->rawmap == NULL)
623 return CHDERR_OUT_OF_MEMORY;
626 /* first decode the compression types */
627 decoder = create_huffman_decoder(16, 8);
632 return CHDERR_OUT_OF_MEMORY;
635 err = huffman_import_tree_rle(decoder, bitbuf);
636 if (err != HUFFERR_NONE)
640 delete_huffman_decoder(decoder);
641 return CHDERR_DECOMPRESSION_ERROR;
644 for (hunknum = 0; hunknum < (int)header->hunkcount; hunknum++)
646 uint8_t *rawmap = header->rawmap + (hunknum * 12);
649 rawmap[0] = lastcomp;
654 uint8_t val = huffman_decode_one(decoder, bitbuf);
655 if (val == COMPRESSION_RLE_SMALL)
657 rawmap[0] = lastcomp;
658 repcount = 2 + huffman_decode_one(decoder, bitbuf);
660 else if (val == COMPRESSION_RLE_LARGE)
662 rawmap[0] = lastcomp;
663 repcount = 2 + 16 + (huffman_decode_one(decoder, bitbuf) << 4);
664 repcount += huffman_decode_one(decoder, bitbuf);
667 rawmap[0] = lastcomp = val;
671 /* then iterate through the hunks and extract the needed data */
672 curoffset = firstoffs;
673 for (hunknum = 0; hunknum < (int)header->hunkcount; hunknum++)
675 uint8_t *rawmap = header->rawmap + (hunknum * 12);
676 uint64_t offset = curoffset;
682 case COMPRESSION_TYPE_0:
683 case COMPRESSION_TYPE_1:
684 case COMPRESSION_TYPE_2:
685 case COMPRESSION_TYPE_3:
686 curoffset += length = bitstream_read(bitbuf, lengthbits);
687 crc = bitstream_read(bitbuf, 16);
690 case COMPRESSION_NONE:
691 curoffset += length = header->hunkbytes;
692 crc = bitstream_read(bitbuf, 16);
695 case COMPRESSION_SELF:
696 last_self = offset = bitstream_read(bitbuf, selfbits);
699 case COMPRESSION_PARENT:
700 offset = bitstream_read(bitbuf, parentbits);
701 last_parent = offset;
704 /* pseudo-types; convert into base types */
705 case COMPRESSION_SELF_1:
707 case COMPRESSION_SELF_0:
708 rawmap[0] = COMPRESSION_SELF;
712 case COMPRESSION_PARENT_SELF:
713 rawmap[0] = COMPRESSION_PARENT;
714 last_parent = offset = ( ((uint64_t)hunknum) * ((uint64_t)header->hunkbytes) ) / header->unitbytes;
717 case COMPRESSION_PARENT_1:
718 last_parent += header->hunkbytes / header->unitbytes;
719 case COMPRESSION_PARENT_0:
720 rawmap[0] = COMPRESSION_PARENT;
721 offset = last_parent;
725 put_bigendian_uint24(&rawmap[1], length);
728 put_bigendian_uint48(&rawmap[4], offset);
731 put_bigendian_uint16(&rawmap[10], crc);
737 delete_huffman_decoder(decoder);
739 /* verify the final CRC */
740 if (crc16(&header->rawmap[0], header->hunkcount * 12) != mapcrc)
741 return CHDERR_DECOMPRESSION_ERROR;
746 /*-------------------------------------------------
747 map_extract_old - extract a single map
748 entry in old format from the datastream
749 -------------------------------------------------*/
751 static INLINE void map_extract_old(const UINT8 *base, map_entry *entry, UINT32 hunkbytes)
753 entry->offset = get_bigendian_uint64(&base[0]);
755 entry->length = entry->offset >> 44;
756 entry->flags = MAP_ENTRY_FLAG_NO_CRC | ((entry->length == hunkbytes) ? V34_MAP_ENTRY_TYPE_UNCOMPRESSED : V34_MAP_ENTRY_TYPE_COMPRESSED);
758 entry->offset = entry->offset & 0x00000FFFFFFFFFFFLL;
760 entry->offset = (entry->offset << 20) >> 20;
764 /***************************************************************************
766 ***************************************************************************/
768 /*-------------------------------------------------
769 chd_open_file - open a CHD file for access
770 -------------------------------------------------*/
772 chd_error chd_open_file(RFILE *file, int mode, chd_file *parent, chd_file **chd)
774 chd_file *newchd = NULL;
778 /* verify parameters */
780 EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
782 /* punt if invalid parent */
783 if (parent != NULL && parent->cookie != COOKIE_VALUE)
784 EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
786 /* allocate memory for the final result */
787 newchd = (chd_file *)malloc(sizeof(**chd));
789 EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
790 memset(newchd, 0, sizeof(*newchd));
791 newchd->cookie = COOKIE_VALUE;
792 newchd->parent = parent;
795 /* now attempt to read the header */
796 err = header_read(newchd, &newchd->header);
797 if (err != CHDERR_NONE)
800 /* validate the header */
801 err = header_validate(&newchd->header);
802 if (err != CHDERR_NONE)
805 /* make sure we don't open a read-only file writeable */
806 if (mode == CHD_OPEN_READWRITE && !(newchd->header.flags & CHDFLAGS_IS_WRITEABLE))
807 EARLY_EXIT(err = CHDERR_FILE_NOT_WRITEABLE);
809 /* also, never open an older version writeable */
810 if (mode == CHD_OPEN_READWRITE && newchd->header.version < CHD_HEADER_VERSION)
811 EARLY_EXIT(err = CHDERR_UNSUPPORTED_VERSION);
813 /* if we need a parent, make sure we have one */
814 if (parent == NULL && (newchd->header.flags & CHDFLAGS_HAS_PARENT))
815 EARLY_EXIT(err = CHDERR_REQUIRES_PARENT);
817 /* make sure we have a valid parent */
820 /* check MD5 if it isn't empty */
821 if (memcmp(nullmd5, newchd->header.parentmd5, sizeof(newchd->header.parentmd5)) != 0 &&
822 memcmp(nullmd5, newchd->parent->header.md5, sizeof(newchd->parent->header.md5)) != 0 &&
823 memcmp(newchd->parent->header.md5, newchd->header.parentmd5, sizeof(newchd->header.parentmd5)) != 0)
824 EARLY_EXIT(err = CHDERR_INVALID_PARENT);
826 /* check SHA1 if it isn't empty */
827 if (memcmp(nullsha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0 &&
828 memcmp(nullsha1, newchd->parent->header.sha1, sizeof(newchd->parent->header.sha1)) != 0 &&
829 memcmp(newchd->parent->header.sha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0)
830 EARLY_EXIT(err = CHDERR_INVALID_PARENT);
833 /* now read the hunk map */
834 if (newchd->header.version < 5)
836 err = map_read(newchd);
840 err = decompress_v5_map(newchd, &(newchd->header));
842 if (err != CHDERR_NONE)
845 #ifdef NEED_CACHE_HUNK
846 /* allocate and init the hunk cache */
847 newchd->cache = (UINT8 *)malloc(newchd->header.hunkbytes);
848 newchd->compare = (UINT8 *)malloc(newchd->header.hunkbytes);
849 if (newchd->cache == NULL || newchd->compare == NULL)
850 EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
851 newchd->cachehunk = ~0;
852 newchd->comparehunk = ~0;
855 /* allocate the temporary compressed buffer */
856 newchd->compressed = (UINT8 *)malloc(newchd->header.hunkbytes);
857 if (newchd->compressed == NULL)
858 EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
860 /* find the codec interface */
861 if (newchd->header.version < 5)
863 for (intfnum = 0; intfnum < (int)ARRAY_SIZE(codec_interfaces); intfnum++)
864 if (codec_interfaces[intfnum].compression == newchd->header.compression[0])
866 newchd->codecintf[0] = &codec_interfaces[intfnum];
869 if (intfnum == ARRAY_SIZE(codec_interfaces))
870 EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);
873 /* initialize the codec */
874 if (newchd->codecintf[0]->init != NULL)
876 err = (*newchd->codecintf[0]->init)(&newchd->zlib_codec_data, newchd->header.hunkbytes);
884 /* verify the compression types and initialize the codecs */
885 for (decompnum = 0; decompnum < (int)ARRAY_SIZE(newchd->header.compression); decompnum++)
887 for (i = 0 ; i < (int)ARRAY_SIZE(codec_interfaces); i++)
889 if (codec_interfaces[i].compression == newchd->header.compression[decompnum])
891 newchd->codecintf[decompnum] = &codec_interfaces[i];
892 if (newchd->codecintf[decompnum] == NULL && newchd->header.compression[decompnum] != 0)
894 err = CHDERR_UNSUPPORTED_FORMAT;
898 /* initialize the codec */
899 if (newchd->codecintf[decompnum]->init != NULL)
902 switch (newchd->header.compression[decompnum])
906 codec = &newchd->zlib_codec_data;
910 case CHD_CODEC_CD_ZLIB:
912 codec = &newchd->cdzl_codec_data;
916 case CHD_CODEC_CD_LZMA:
918 codec = &newchd->cdlz_codec_data;
922 case CHD_CODEC_CD_FLAC:
924 codec = &newchd->cdfl_codec_data;
930 err = (*newchd->codecintf[decompnum]->init)(codec, newchd->header.hunkbytes);
942 if (err != CHDERR_NONE)
956 /*-------------------------------------------------
957 chd_precache - precache underlying file in
959 -------------------------------------------------*/
961 chd_error chd_precache(chd_file *chd)
965 if (!chd->file_cache)
967 filestream_seek(chd->file, 0, SEEK_END);
968 size = filestream_tell(chd->file);
970 return CHDERR_INVALID_DATA;
971 chd->file_cache = (UINT8*)malloc(size);
972 if (chd->file_cache == NULL)
973 return CHDERR_OUT_OF_MEMORY;
974 filestream_seek(chd->file, 0, SEEK_SET);
975 count = filestream_read(chd->file, chd->file_cache, size);
978 free(chd->file_cache);
979 chd->file_cache = NULL;
980 return CHDERR_READ_ERROR;
988 /*-------------------------------------------------
989 chd_open - open a CHD file by
991 -------------------------------------------------*/
993 chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd)
998 /* choose the proper mode */
1005 err = CHDERR_INVALID_PARAMETER;
1010 file = filestream_open(filename,
1011 RETRO_VFS_FILE_ACCESS_READ,
1012 RETRO_VFS_FILE_ACCESS_HINT_NONE);
1016 err = CHDERR_FILE_NOT_FOUND;
1020 /* now open the CHD */
1021 err = chd_open_file(file, mode, parent, chd);
1022 if (err != CHDERR_NONE)
1025 /* we now own this file */
1026 (*chd)->owns_file = TRUE;
1029 if ((err != CHDERR_NONE) && (file != NULL))
1030 filestream_close(file);
1034 /*-------------------------------------------------
1035 chd_close - close a CHD file for access
1036 -------------------------------------------------*/
1038 void chd_close(chd_file *chd)
1040 /* punt if NULL or invalid */
1041 if (chd == NULL || chd->cookie != COOKIE_VALUE)
1044 /* deinit the codec */
1045 if (chd->header.version < 5)
1048 if (chd->codecintf[0] != NULL && chd->codecintf[0]->free != NULL)
1049 (*chd->codecintf[0]->free)(&chd->zlib_codec_data);
1055 /* Free the codecs */
1056 for (i = 0 ; i < 4 ; i++)
1059 if (!chd->codecintf[i])
1062 switch (chd->codecintf[i]->compression)
1064 case CHD_CODEC_CD_LZMA:
1066 codec = &chd->cdlz_codec_data;
1070 case CHD_CODEC_ZLIB:
1072 codec = &chd->zlib_codec_data;
1076 case CHD_CODEC_CD_ZLIB:
1078 codec = &chd->cdzl_codec_data;
1082 case CHD_CODEC_CD_FLAC:
1084 codec = &chd->cdfl_codec_data;
1089 (*chd->codecintf[i]->free)(codec);
1092 /* Free the raw map */
1093 if (chd->header.rawmap != NULL)
1094 free(chd->header.rawmap);
1097 /* free the compressed data buffer */
1098 if (chd->compressed != NULL)
1099 free(chd->compressed);
1101 #ifdef NEED_CACHE_HUNK
1102 /* free the hunk cache and compare data */
1103 if (chd->compare != NULL)
1105 if (chd->cache != NULL)
1109 /* free the hunk map */
1110 if (chd->map != NULL)
1113 /* close the file */
1114 if (chd->owns_file && chd->file != NULL)
1115 filestream_close(chd->file);
1117 #ifdef NEED_CACHE_HUNK
1118 if (PRINTF_MAX_HUNK) printf("Max hunk = %d/%d\n", chd->maxhunk, chd->header.totalhunks);
1121 if (chd->file_cache)
1122 free(chd->file_cache);
1124 /* free our memory */
1128 /*-------------------------------------------------
1129 chd_core_file - return the associated
1131 -------------------------------------------------*/
1133 RFILE *chd_core_file(chd_file *chd)
1138 /*-------------------------------------------------
1139 chd_error_string - return an error string for
1141 -------------------------------------------------*/
1143 const char *chd_error_string(chd_error err)
1147 case CHDERR_NONE: return "no error";
1148 case CHDERR_NO_INTERFACE: return "no drive interface";
1149 case CHDERR_OUT_OF_MEMORY: return "out of memory";
1150 case CHDERR_INVALID_FILE: return "invalid file";
1151 case CHDERR_INVALID_PARAMETER: return "invalid parameter";
1152 case CHDERR_INVALID_DATA: return "invalid data";
1153 case CHDERR_FILE_NOT_FOUND: return "file not found";
1154 case CHDERR_REQUIRES_PARENT: return "requires parent";
1155 case CHDERR_FILE_NOT_WRITEABLE: return "file not writeable";
1156 case CHDERR_READ_ERROR: return "read error";
1157 case CHDERR_WRITE_ERROR: return "write error";
1158 case CHDERR_CODEC_ERROR: return "codec error";
1159 case CHDERR_INVALID_PARENT: return "invalid parent";
1160 case CHDERR_HUNK_OUT_OF_RANGE: return "hunk out of range";
1161 case CHDERR_DECOMPRESSION_ERROR: return "decompression error";
1162 case CHDERR_COMPRESSION_ERROR: return "compression error";
1163 case CHDERR_CANT_CREATE_FILE: return "can't create file";
1164 case CHDERR_CANT_VERIFY: return "can't verify file";
1165 case CHDERR_NOT_SUPPORTED: return "operation not supported";
1166 case CHDERR_METADATA_NOT_FOUND: return "can't find metadata";
1167 case CHDERR_INVALID_METADATA_SIZE: return "invalid metadata size";
1168 case CHDERR_UNSUPPORTED_VERSION: return "unsupported CHD version";
1169 case CHDERR_VERIFY_INCOMPLETE: return "incomplete verify";
1170 case CHDERR_INVALID_METADATA: return "invalid metadata";
1171 case CHDERR_INVALID_STATE: return "invalid state";
1172 case CHDERR_OPERATION_PENDING: return "operation pending";
1173 case CHDERR_NO_ASYNC_OPERATION: return "no async operation in progress";
1174 case CHDERR_UNSUPPORTED_FORMAT: return "unsupported format";
1175 default: return "undocumented error";
1179 /***************************************************************************
1180 CHD HEADER MANAGEMENT
1181 ***************************************************************************/
1183 /*-------------------------------------------------
1184 chd_get_header - return a pointer to the
1185 extracted header data
1186 -------------------------------------------------*/
1188 const chd_header *chd_get_header(chd_file *chd)
1190 /* punt if NULL or invalid */
1191 if (chd == NULL || chd->cookie != COOKIE_VALUE)
1194 return &chd->header;
1197 /***************************************************************************
1198 CORE DATA READ/WRITE
1199 ***************************************************************************/
1201 /*-------------------------------------------------
1202 chd_read - read a single hunk from the CHD
1204 -------------------------------------------------*/
1206 chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer)
1208 /* punt if NULL or invalid */
1209 if (chd == NULL || chd->cookie != COOKIE_VALUE)
1210 return CHDERR_INVALID_PARAMETER;
1212 /* perform the read */
1213 return hunk_read_into_memory(chd, hunknum, (UINT8 *)buffer);
1216 /***************************************************************************
1218 ***************************************************************************/
1220 /*-------------------------------------------------
1221 chd_get_metadata - get the indexed metadata
1223 -------------------------------------------------*/
1225 chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 *resultlen, UINT32 *resulttag, UINT8 *resultflags)
1227 metadata_entry metaentry;
1231 /* if we didn't find it, just return */
1232 err = metadata_find_entry(chd, searchtag, searchindex, &metaentry);
1233 if (err != CHDERR_NONE)
1235 /* unless we're an old version and they are requesting hard disk metadata */
1236 if (chd->header.version < 3 && (searchtag == HARD_DISK_METADATA_TAG || searchtag == CHDMETATAG_WILDCARD) && searchindex == 0)
1238 char faux_metadata[256];
1241 /* fill in the faux metadata */
1242 snprintf(faux_metadata,
1243 sizeof(faux_metadata),
1244 HARD_DISK_METADATA_FORMAT,
1245 chd->header.obsolete_cylinders,
1246 chd->header.obsolete_heads,
1247 chd->header.obsolete_sectors,
1248 chd->header.hunkbytes / chd->header.obsolete_hunksize);
1249 faux_length = (UINT32)strlen(faux_metadata) + 1;
1251 /* copy the metadata itself */
1252 memcpy(output, faux_metadata, MIN(outputlen, faux_length));
1254 /* return the length of the data and the tag */
1255 if (resultlen != NULL)
1256 *resultlen = faux_length;
1257 if (resulttag != NULL)
1258 *resulttag = HARD_DISK_METADATA_TAG;
1264 /* read the metadata */
1265 outputlen = MIN(outputlen, metaentry.length);
1266 filestream_seek(chd->file, metaentry.offset + METADATA_HEADER_SIZE, SEEK_SET);
1267 count = filestream_read(chd->file, output, outputlen);
1268 if (count != outputlen)
1269 return CHDERR_READ_ERROR;
1271 /* return the length of the data and the tag */
1272 if (resultlen != NULL)
1273 *resultlen = metaentry.length;
1274 if (resulttag != NULL)
1275 *resulttag = metaentry.metatag;
1276 if (resultflags != NULL)
1277 *resultflags = metaentry.flags;
1281 /***************************************************************************
1283 ***************************************************************************/
1285 /*-------------------------------------------------
1286 chd_codec_config - set internal codec
1288 -------------------------------------------------*/
1290 chd_error chd_codec_config(chd_file *chd, int param, void *config)
1292 return CHDERR_INVALID_PARAMETER;
1295 /*-------------------------------------------------
1296 chd_get_codec_name - get the name of a
1298 -------------------------------------------------*/
1300 const char *chd_get_codec_name(UINT32 codec)
1305 /***************************************************************************
1306 INTERNAL HEADER OPERATIONS
1307 ***************************************************************************/
1309 /*-------------------------------------------------
1310 header_validate - check the validity of a
1312 -------------------------------------------------*/
1314 static chd_error header_validate(const chd_header *header)
1318 /* require a valid version */
1319 if (header->version == 0 || header->version > CHD_HEADER_VERSION)
1320 return CHDERR_UNSUPPORTED_VERSION;
1322 /* require a valid length */
1323 if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) ||
1324 (header->version == 2 && header->length != CHD_V2_HEADER_SIZE) ||
1325 (header->version == 3 && header->length != CHD_V3_HEADER_SIZE) ||
1326 (header->version == 4 && header->length != CHD_V4_HEADER_SIZE) ||
1327 (header->version == 5 && header->length != CHD_V5_HEADER_SIZE))
1328 return CHDERR_INVALID_PARAMETER;
1330 /* Do not validate v5 header */
1331 if (header->version <= 4)
1333 /* require valid flags */
1334 if (header->flags & CHDFLAGS_UNDEFINED)
1335 return CHDERR_INVALID_PARAMETER;
1337 /* require a supported compression mechanism */
1338 for (intfnum = 0; intfnum < (int)ARRAY_SIZE(codec_interfaces); intfnum++)
1339 if (codec_interfaces[intfnum].compression == header->compression[0])
1342 if (intfnum == ARRAY_SIZE(codec_interfaces))
1343 return CHDERR_INVALID_PARAMETER;
1345 /* require a valid hunksize */
1346 if (header->hunkbytes == 0 || header->hunkbytes >= 65536 * 256)
1347 return CHDERR_INVALID_PARAMETER;
1349 /* require a valid hunk count */
1350 if (header->totalhunks == 0)
1351 return CHDERR_INVALID_PARAMETER;
1353 /* require a valid MD5 and/or SHA1 if we're using a parent */
1354 if ((header->flags & CHDFLAGS_HAS_PARENT) && memcmp(header->parentmd5, nullmd5, sizeof(nullmd5)) == 0 && memcmp(header->parentsha1, nullsha1, sizeof(nullsha1)) == 0)
1355 return CHDERR_INVALID_PARAMETER;
1357 /* if we're V3 or later, the obsolete fields must be 0 */
1358 if (header->version >= 3 &&
1359 (header->obsolete_cylinders != 0 || header->obsolete_sectors != 0 ||
1360 header->obsolete_heads != 0 || header->obsolete_hunksize != 0))
1361 return CHDERR_INVALID_PARAMETER;
1363 /* if we're pre-V3, the obsolete fields must NOT be 0 */
1364 if (header->version < 3 &&
1365 (header->obsolete_cylinders == 0 || header->obsolete_sectors == 0 ||
1366 header->obsolete_heads == 0 || header->obsolete_hunksize == 0))
1367 return CHDERR_INVALID_PARAMETER;
1373 /*-------------------------------------------------
1374 header_guess_unitbytes - for older CHD formats,
1375 guess at the bytes/unit based on metadata
1376 -------------------------------------------------*/
1378 static UINT32 header_guess_unitbytes(chd_file *chd)
1380 /* look for hard disk metadata; if found, then the unit size == sector size */
1382 unsigned int i0, i1, i2, i3;
1383 if (chd_get_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE &&
1384 sscanf(metadata, HARD_DISK_METADATA_FORMAT, &i0, &i1, &i2, &i3) == 4)
1387 /* look for CD-ROM metadata; if found, then the unit size == CD frame size */
1388 if (chd_get_metadata(chd, CDROM_OLD_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
1389 chd_get_metadata(chd, CDROM_TRACK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
1390 chd_get_metadata(chd, CDROM_TRACK_METADATA2_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
1391 chd_get_metadata(chd, GDROM_OLD_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
1392 chd_get_metadata(chd, GDROM_TRACK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE)
1393 return CD_FRAME_SIZE;
1395 /* otherwise, just map 1:1 with the hunk size */
1396 return chd->header.hunkbytes;
1399 /*-------------------------------------------------
1400 header_read - read a CHD header into the
1401 internal data structure
1402 -------------------------------------------------*/
1404 static chd_error header_read(chd_file *chd, chd_header *header)
1406 UINT8 rawheader[CHD_MAX_HEADER_SIZE];
1411 return CHDERR_INVALID_PARAMETER;
1413 /* punt if invalid file */
1414 if (chd->file == NULL)
1415 return CHDERR_INVALID_FILE;
1418 filestream_seek(chd->file, 0, SEEK_SET);
1419 count = filestream_read(chd->file, rawheader, sizeof(rawheader));
1420 if (count != sizeof(rawheader))
1421 return CHDERR_READ_ERROR;
1423 /* verify the tag */
1424 if (strncmp((char *)rawheader, "MComprHD", 8) != 0)
1425 return CHDERR_INVALID_DATA;
1427 /* extract the direct data */
1428 memset(header, 0, sizeof(*header));
1429 header->length = get_bigendian_uint32(&rawheader[8]);
1430 header->version = get_bigendian_uint32(&rawheader[12]);
1432 /* make sure it's a version we understand */
1433 if (header->version == 0 || header->version > CHD_HEADER_VERSION)
1434 return CHDERR_UNSUPPORTED_VERSION;
1436 /* make sure the length is expected */
1437 if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) ||
1438 (header->version == 2 && header->length != CHD_V2_HEADER_SIZE) ||
1439 (header->version == 3 && header->length != CHD_V3_HEADER_SIZE) ||
1440 (header->version == 4 && header->length != CHD_V4_HEADER_SIZE) ||
1441 (header->version == 5 && header->length != CHD_V5_HEADER_SIZE))
1443 return CHDERR_INVALID_DATA;
1445 /* extract the common data */
1446 header->flags = get_bigendian_uint32(&rawheader[16]);
1447 header->compression[0] = get_bigendian_uint32(&rawheader[20]);
1449 /* extract the V1/V2-specific data */
1450 if (header->version < 3)
1452 int seclen = (header->version == 1) ? CHD_V1_SECTOR_SIZE : get_bigendian_uint32(&rawheader[76]);
1453 header->obsolete_hunksize = get_bigendian_uint32(&rawheader[24]);
1454 header->totalhunks = get_bigendian_uint32(&rawheader[28]);
1455 header->obsolete_cylinders = get_bigendian_uint32(&rawheader[32]);
1456 header->obsolete_heads = get_bigendian_uint32(&rawheader[36]);
1457 header->obsolete_sectors = get_bigendian_uint32(&rawheader[40]);
1458 memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES);
1459 memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES);
1460 header->logicalbytes = (UINT64)header->obsolete_cylinders * (UINT64)header->obsolete_heads * (UINT64)header->obsolete_sectors * (UINT64)seclen;
1461 header->hunkbytes = seclen * header->obsolete_hunksize;
1462 header->unitbytes = header_guess_unitbytes(chd);
1463 header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
1464 header->metaoffset = 0;
1467 /* extract the V3-specific data */
1468 else if (header->version == 3)
1470 header->totalhunks = get_bigendian_uint32(&rawheader[24]);
1471 header->logicalbytes = get_bigendian_uint64(&rawheader[28]);
1472 header->metaoffset = get_bigendian_uint64(&rawheader[36]);
1473 memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES);
1474 memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES);
1475 header->hunkbytes = get_bigendian_uint32(&rawheader[76]);
1476 header->unitbytes = header_guess_unitbytes(chd);
1477 header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
1478 memcpy(header->sha1, &rawheader[80], CHD_SHA1_BYTES);
1479 memcpy(header->parentsha1, &rawheader[100], CHD_SHA1_BYTES);
1482 /* extract the V4-specific data */
1483 else if (header->version == 4)
1485 header->totalhunks = get_bigendian_uint32(&rawheader[24]);
1486 header->logicalbytes = get_bigendian_uint64(&rawheader[28]);
1487 header->metaoffset = get_bigendian_uint64(&rawheader[36]);
1488 header->hunkbytes = get_bigendian_uint32(&rawheader[44]);
1489 header->unitbytes = header_guess_unitbytes(chd);
1490 header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
1491 memcpy(header->sha1, &rawheader[48], CHD_SHA1_BYTES);
1492 memcpy(header->parentsha1, &rawheader[68], CHD_SHA1_BYTES);
1493 memcpy(header->rawsha1, &rawheader[88], CHD_SHA1_BYTES);
1496 /* extract the V5-specific data */
1497 else if (header->version == 5)
1500 header->compression[0] = get_bigendian_uint32(&rawheader[16]);
1501 header->compression[1] = get_bigendian_uint32(&rawheader[20]);
1502 header->compression[2] = get_bigendian_uint32(&rawheader[24]);
1503 header->compression[3] = get_bigendian_uint32(&rawheader[28]);
1504 header->logicalbytes = get_bigendian_uint64(&rawheader[32]);
1505 header->mapoffset = get_bigendian_uint64(&rawheader[40]);
1506 header->metaoffset = get_bigendian_uint64(&rawheader[48]);
1507 header->hunkbytes = get_bigendian_uint32(&rawheader[56]);
1508 header->hunkcount = (UINT32)((header->logicalbytes + header->hunkbytes - 1) / header->hunkbytes);
1509 header->unitbytes = get_bigendian_uint32(&rawheader[60]);
1510 header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
1511 memcpy(header->sha1, &rawheader[84], CHD_SHA1_BYTES);
1512 memcpy(header->parentsha1, &rawheader[104], CHD_SHA1_BYTES);
1513 memcpy(header->rawsha1, &rawheader[64], CHD_SHA1_BYTES);
1515 /* determine properties of map entries */
1516 header->mapentrybytes = 12; /* TODO compressed() ? 12 : 4; */
1519 header->totalhunks = header->hunkcount;
1522 /* Unknown version */
1528 /* guess it worked */
1532 /***************************************************************************
1533 INTERNAL HUNK READ/WRITE
1534 ***************************************************************************/
1536 #ifdef NEED_CACHE_HUNK
1537 /*-------------------------------------------------
1538 hunk_read_into_cache - read a hunk into
1539 the CHD's hunk cache
1540 -------------------------------------------------*/
1542 static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum)
1547 if (hunknum > chd->maxhunk)
1548 chd->maxhunk = hunknum;
1550 /* if we're already in the cache, we're done */
1551 if (chd->cachehunk == hunknum)
1553 chd->cachehunk = ~0;
1555 /* otherwise, read the data */
1556 err = hunk_read_into_memory(chd, hunknum, chd->cache);
1557 if (err != CHDERR_NONE)
1560 /* mark the hunk successfully cached in */
1561 chd->cachehunk = hunknum;
1566 /*-------------------------------------------------
1567 hunk_read_compressed - read a compressed
1569 -------------------------------------------------*/
1571 static UINT8* hunk_read_compressed(chd_file *chd, UINT64 offset, size_t size)
1574 if (chd->file_cache)
1575 return chd->file_cache + offset;
1576 filestream_seek(chd->file, offset, SEEK_SET);
1577 bytes = filestream_read(chd->file, chd->compressed, size);
1578 if (bytes != (int64_t)size)
1580 return chd->compressed;
1583 /*-------------------------------------------------
1584 hunk_read_uncompressed - read an uncompressed
1586 -------------------------------------------------*/
1588 static chd_error hunk_read_uncompressed(chd_file *chd, UINT64 offset, size_t size, UINT8 *dest)
1591 if (chd->file_cache)
1593 memcpy(dest, chd->file_cache + offset, size);
1596 filestream_seek(chd->file, offset, SEEK_SET);
1597 bytes = filestream_read(chd->file, dest, size);
1598 if (bytes != (int64_t)size)
1599 return CHDERR_READ_ERROR;
1603 /*-------------------------------------------------
1604 hunk_read_into_memory - read a hunk into
1605 memory at the given location
1606 -------------------------------------------------*/
1608 static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest)
1612 /* punt if no file */
1613 if (chd->file == NULL)
1614 return CHDERR_INVALID_FILE;
1616 /* return an error if out of range */
1617 if (hunknum >= chd->header.totalhunks)
1618 return CHDERR_HUNK_OUT_OF_RANGE;
1621 return CHDERR_INVALID_PARAMETER;
1623 if (chd->header.version < 5)
1625 map_entry *entry = &chd->map[hunknum];
1627 UINT8* compressed_bytes;
1629 /* switch off the entry type */
1630 switch (entry->flags & MAP_ENTRY_FLAG_TYPE_MASK)
1632 /* compressed data */
1633 case V34_MAP_ENTRY_TYPE_COMPRESSED:
1635 /* read it into the decompression buffer */
1638 compressed_bytes = hunk_read_compressed(chd, entry->offset,
1640 if (compressed_bytes == NULL)
1641 return CHDERR_READ_ERROR;
1644 /* now decompress using the codec */
1646 codec = &chd->zlib_codec_data;
1647 if (chd->codecintf[0]->decompress != NULL)
1648 err = (*chd->codecintf[0]->decompress)(codec, compressed_bytes, entry->length, dest, chd->header.hunkbytes);
1649 if (err != CHDERR_NONE)
1655 /* uncompressed data */
1656 case V34_MAP_ENTRY_TYPE_UNCOMPRESSED:
1657 err = hunk_read_uncompressed(chd, entry->offset, chd->header.hunkbytes, dest);
1658 if (err != CHDERR_NONE)
1662 /* mini-compressed data */
1663 case V34_MAP_ENTRY_TYPE_MINI:
1664 put_bigendian_uint64(&dest[0], entry->offset);
1665 for (bytes = 8; bytes < chd->header.hunkbytes; bytes++)
1666 dest[bytes] = dest[bytes - 8];
1669 /* self-referenced data */
1670 case V34_MAP_ENTRY_TYPE_SELF_HUNK:
1671 #ifdef NEED_CACHE_HUNK
1672 if (chd->cachehunk == entry->offset && dest == chd->cache)
1675 return hunk_read_into_memory(chd, (UINT32)entry->offset, dest);
1677 /* parent-referenced data */
1678 case V34_MAP_ENTRY_TYPE_PARENT_HUNK:
1679 err = hunk_read_into_memory(chd->parent, (UINT32)entry->offset, dest);
1680 if (err != CHDERR_NONE)
1689 /* get a pointer to the map entry */
1692 #ifdef VERIFY_BLOCK_CRC
1695 uint8_t *rawmap = &chd->header.rawmap[chd->header.mapentrybytes * hunknum];
1696 UINT8 *compressed_bytes;
1699 /* uncompressed case - TODO */
1702 blockoffs = uint64_t(be_read(rawmap, 4)) * uint64_t(m_hunkbytes);
1704 file_read(blockoffs, dest, m_hunkbytes);
1705 else if (m_parent_missing)
1706 throw CHDERR_REQUIRES_PARENT;
1707 else if (m_parent != nullptr)
1708 m_parent->read_hunk(hunknum, dest);
1710 memset(dest, 0, m_hunkbytes);
1715 /* compressed case */
1716 blocklen = get_bigendian_uint24(&rawmap[1]);
1717 blockoffs = get_bigendian_uint48(&rawmap[4]);
1718 #ifdef VERIFY_BLOCK_CRC
1719 blockcrc = get_bigendian_uint16(&rawmap[10]);
1723 case COMPRESSION_TYPE_0:
1724 case COMPRESSION_TYPE_1:
1725 case COMPRESSION_TYPE_2:
1726 case COMPRESSION_TYPE_3:
1727 compressed_bytes = hunk_read_compressed(chd, blockoffs, blocklen);
1728 if (compressed_bytes == NULL)
1729 return CHDERR_READ_ERROR;
1730 if (!chd->codecintf[rawmap[0]])
1731 return CHDERR_UNSUPPORTED_FORMAT;
1732 switch (chd->codecintf[rawmap[0]]->compression)
1734 case CHD_CODEC_CD_LZMA:
1736 codec = &chd->cdlz_codec_data;
1740 case CHD_CODEC_ZLIB:
1742 codec = &chd->zlib_codec_data;
1746 case CHD_CODEC_CD_ZLIB:
1748 codec = &chd->cdzl_codec_data;
1752 case CHD_CODEC_CD_FLAC:
1754 codec = &chd->cdfl_codec_data;
1759 return CHDERR_CODEC_ERROR;
1760 err = (*chd->codecintf[rawmap[0]]->decompress)(codec, compressed_bytes, blocklen, dest, chd->header.hunkbytes);
1761 if (err != CHDERR_NONE)
1763 #ifdef VERIFY_BLOCK_CRC
1764 if (crc16(dest, chd->header.hunkbytes) != blockcrc)
1765 return CHDERR_DECOMPRESSION_ERROR;
1769 case COMPRESSION_NONE:
1770 err = hunk_read_uncompressed(chd, blockoffs, blocklen, dest);
1771 if (err != CHDERR_NONE)
1773 #ifdef VERIFY_BLOCK_CRC
1774 if (crc16(dest, chd->header.hunkbytes) != blockcrc)
1775 return CHDERR_DECOMPRESSION_ERROR;
1779 case COMPRESSION_SELF:
1780 return hunk_read_into_memory(chd, (UINT32)blockoffs, dest);
1782 case COMPRESSION_PARENT:
1785 if (m_parent_missing)
1786 return CHDERR_REQUIRES_PARENT;
1787 return m_parent->read_bytes(uint64_t(blockoffs) * uint64_t(m_parent->unit_bytes()), dest, m_hunkbytes);
1789 return CHDERR_DECOMPRESSION_ERROR;
1794 /* We should not reach this code */
1795 return CHDERR_DECOMPRESSION_ERROR;
1798 /***************************************************************************
1800 ***************************************************************************/
1802 static size_t core_fsize(RFILE *f)
1804 int64_t rv, p = filestream_tell(f);
1805 filestream_seek(f, 0, SEEK_END);
1806 rv = filestream_tell(f);
1807 filestream_seek(f, p, SEEK_SET);
1811 /*-------------------------------------------------
1812 map_read - read the initial sector map
1813 -------------------------------------------------*/
1815 static chd_error map_read(chd_file *chd)
1817 UINT32 entrysize = (chd->header.version < 3) ? OLD_MAP_ENTRY_SIZE : MAP_ENTRY_SIZE;
1818 UINT8 raw_map_entries[MAP_STACK_ENTRIES * MAP_ENTRY_SIZE];
1819 UINT64 fileoffset, maxoffset = 0;
1820 UINT8 cookie[MAP_ENTRY_SIZE];
1825 /* first allocate memory */
1826 chd->map = (map_entry *)malloc(sizeof(chd->map[0]) * chd->header.totalhunks);
1828 return CHDERR_OUT_OF_MEMORY;
1830 /* read the map entries in in chunks and extract to the map list */
1831 fileoffset = chd->header.length;
1832 for (i = 0; i < (int)chd->header.totalhunks; i += MAP_STACK_ENTRIES)
1834 /* compute how many entries this time */
1835 int entries = chd->header.totalhunks - i, j;
1836 if (entries > MAP_STACK_ENTRIES)
1837 entries = MAP_STACK_ENTRIES;
1839 /* read that many */
1840 filestream_seek(chd->file, fileoffset, SEEK_SET);
1841 count = filestream_read(chd->file, raw_map_entries, entries * entrysize);
1842 if (count != entries * entrysize)
1844 err = CHDERR_READ_ERROR;
1847 fileoffset += entries * entrysize;
1849 /* process that many */
1850 if (entrysize == MAP_ENTRY_SIZE)
1852 for (j = 0; j < entries; j++)
1853 map_extract(&raw_map_entries[j * MAP_ENTRY_SIZE], &chd->map[i + j]);
1857 for (j = 0; j < entries; j++)
1858 map_extract_old(&raw_map_entries[j * OLD_MAP_ENTRY_SIZE], &chd->map[i + j], chd->header.hunkbytes);
1861 /* track the maximum offset */
1862 for (j = 0; j < entries; j++)
1863 if ((chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == V34_MAP_ENTRY_TYPE_COMPRESSED ||
1864 (chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == V34_MAP_ENTRY_TYPE_UNCOMPRESSED)
1865 maxoffset = MAX(maxoffset, chd->map[i + j].offset + chd->map[i + j].length);
1868 /* verify the cookie */
1869 filestream_seek(chd->file, fileoffset, SEEK_SET);
1870 count = filestream_read(chd->file, &cookie, entrysize);
1871 if (count != entrysize || memcmp(&cookie, END_OF_LIST_COOKIE, entrysize))
1873 err = CHDERR_INVALID_FILE;
1877 /* verify the length */
1878 if (maxoffset > core_fsize(chd->file))
1880 err = CHDERR_INVALID_FILE;
1892 /***************************************************************************
1893 INTERNAL METADATA ACCESS
1894 ***************************************************************************/
1896 /*-------------------------------------------------
1897 metadata_find_entry - find a metadata entry
1898 -------------------------------------------------*/
1900 static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry)
1902 /* start at the beginning */
1903 metaentry->offset = chd->header.metaoffset;
1904 metaentry->prev = 0;
1906 /* loop until we run out of options */
1907 while (metaentry->offset != 0)
1909 UINT8 raw_meta_header[METADATA_HEADER_SIZE];
1912 /* read the raw header */
1913 filestream_seek(chd->file, metaentry->offset, SEEK_SET);
1914 count = filestream_read(chd->file, raw_meta_header, sizeof(raw_meta_header));
1915 if (count != sizeof(raw_meta_header))
1918 /* extract the data */
1919 metaentry->metatag = get_bigendian_uint32(&raw_meta_header[0]);
1920 metaentry->length = get_bigendian_uint32(&raw_meta_header[4]);
1921 metaentry->next = get_bigendian_uint64(&raw_meta_header[8]);
1923 /* flags are encoded in the high byte of length */
1924 metaentry->flags = metaentry->length >> 24;
1925 metaentry->length &= 0x00ffffff;
1927 /* if we got a match, proceed */
1928 if (metatag == CHDMETATAG_WILDCARD || metaentry->metatag == metatag)
1929 if (metaindex-- == 0)
1932 /* no match, fetch the next link */
1933 metaentry->prev = metaentry->offset;
1934 metaentry->offset = metaentry->next;
1937 /* if we get here, we didn't find it */
1938 return CHDERR_METADATA_NOT_FOUND;