cdrom: fix a copy-paste mistake
[pcsx_rearmed.git] / deps / libretro-common / formats / libchdr / libchdr_chd.c
CommitLineData
3719602c
PC
1/***************************************************************************
2
3 chd.c
4
5 MAME Compressed Hunks of Data file format
6
7****************************************************************************
8
9 Copyright Aaron Giles
10 All rights reserved.
11
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are
14 met:
15
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
21 distribution.
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.
25
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.
37
38***************************************************************************/
39
40#include <stddef.h>
41#include <stdint.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <libchdr/chd.h>
46#include <libchdr/minmax.h>
47#include <libchdr/cdrom.h>
48#include <libchdr/huffman.h>
49
50#ifdef HAVE_FLAC
51#include <libchdr/flac.h>
52#endif
53
54#ifdef HAVE_7ZIP
55#include <libchdr/lzma.h>
56#endif
57
58#ifdef HAVE_ZLIB
59#include <libchdr/libchdr_zlib.h>
60#endif
61
62#include <retro_inline.h>
63#include <streams/file_stream.h>
64
65#define TRUE 1
66#define FALSE 0
67
68/***************************************************************************
69 DEBUGGING
70***************************************************************************/
71
72#define PRINTF_MAX_HUNK (0)
73
74/***************************************************************************
75 CONSTANTS
76***************************************************************************/
77
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 */
82
83#define CRCMAP_HASH_SIZE 4095 /* number of CRC hashtable entries */
84
85#define MAP_ENTRY_FLAG_TYPE_MASK 0x0f /* what type of hunk */
86#define MAP_ENTRY_FLAG_NO_CRC 0x10 /* no CRC is present */
87
88#define CHD_V1_SECTOR_SIZE 512 /* size of a "sector" in the V1 header */
89
90#define COOKIE_VALUE 0xbaadf00d
91
92#define END_OF_LIST_COOKIE "EndOfListCookie"
93
94#define NO_MATCH (~0)
95
96#ifdef WANT_RAW_DATA_SECTOR
97const uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 };
98#endif
99
100/* V3-V4 entry types */
101enum
102{
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) */
110};
111
112/* V5 compression types */
113enum
114{
115 /* codec #0
116 * these types are live when running */
117 COMPRESSION_TYPE_0 = 0,
118 /* codec #1 */
119 COMPRESSION_TYPE_1 = 1,
120 /* codec #2 */
121 COMPRESSION_TYPE_2 = 2,
122 /* codec #3 */
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,
130
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 */
137 COMPRESSION_SELF_0,
138 /* same as the last COMPRESSION_SELF block + 1 */
139 COMPRESSION_SELF_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 */
145 COMPRESSION_PARENT_1
146};
147
148/***************************************************************************
149 MACROS
150***************************************************************************/
151
152#define EARLY_EXIT(x) do { (void)(x); goto cleanup; } while (0)
153
154/***************************************************************************
155 TYPE DEFINITIONS
156***************************************************************************/
157
158/* interface to a codec */
159typedef struct _codec_interface codec_interface;
160struct _codec_interface
161{
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 */
169};
170
171/* a single map entry */
172typedef struct _map_entry map_entry;
173struct _map_entry
174{
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 */
179};
180
181/* a single metadata entry */
182typedef struct _metadata_entry metadata_entry;
183struct _metadata_entry
184{
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 */
191};
192
193/* internal representation of an open CHD file */
194struct _chd_file
195{
196 UINT32 cookie; /* cookie, should equal COOKIE_VALUE */
197
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 */
201
202 chd_file * parent; /* pointer to parent file, or NULL */
203
204 map_entry * map; /* array of map entries */
205
206#ifdef NEED_CACHE_HUNK
207 UINT8 * cache; /* hunk cache pointer */
208 UINT32 cachehunk; /* index of currently cached hunk */
209
210 UINT8 * compare; /* hunk compare pointer */
211 UINT32 comparehunk; /* index of current compare data */
212#endif
213
214 UINT8 * compressed; /* pointer to buffer for compressed data */
215 const codec_interface * codecintf[4]; /* interface to the codec */
216
217#ifdef HAVE_ZLIB
218 zlib_codec_data zlib_codec_data; /* zlib codec data */
219 cdzl_codec_data cdzl_codec_data; /* cdzl codec data */
220#endif
221#ifdef HAVE_7ZIP
222 cdlz_codec_data cdlz_codec_data; /* cdlz codec data */
223#endif
224#ifdef HAVE_FLAC
225 cdfl_codec_data cdfl_codec_data; /* cdfl codec data */
226#endif
227
228#ifdef NEED_CACHE_HUNK
229 UINT32 maxhunk; /* maximum hunk accessed */
230#endif
231 UINT8 * file_cache; /* cache of underlying file */
232};
233
234/***************************************************************************
235 GLOBAL VARIABLES
236***************************************************************************/
237
238static const UINT8 nullmd5[CHD_MD5_BYTES] = { 0 };
239static const UINT8 nullsha1[CHD_SHA1_BYTES] = { 0 };
240
241/***************************************************************************
242 PROTOTYPES
243***************************************************************************/
244
245/* internal header operations */
246static chd_error header_validate(const chd_header *header);
247static chd_error header_read(chd_file *chd, chd_header *header);
248
249/* internal hunk read/write */
250#ifdef NEED_CACHE_HUNK
251static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum);
252#endif
253static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest);
254
255/* internal map access */
256static chd_error map_read(chd_file *chd);
257
258/* metadata management */
259static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry);
260
261/***************************************************************************
262 CODEC INTERFACES
263***************************************************************************/
264
265static const codec_interface codec_interfaces[] =
266{
267 /* "none" or no compression */
268 {
269 CHDCOMPRESSION_NONE,
270 "none",
271 FALSE,
272 NULL,
273 NULL,
274 NULL,
275 NULL
276 },
277
278#ifdef HAVE_ZLIB
279 /* standard zlib compression */
280 {
281 CHDCOMPRESSION_ZLIB,
282 "zlib",
283 FALSE,
284 zlib_codec_init,
285 zlib_codec_free,
286 zlib_codec_decompress,
287 NULL
288 },
289
290 /* zlib+ compression */
291 {
292 CHDCOMPRESSION_ZLIB_PLUS,
293 "zlib+",
294 FALSE,
295 zlib_codec_init,
296 zlib_codec_free,
297 zlib_codec_decompress,
298 NULL
299 },
300
301 /* V5 zlib compression */
302 {
303 CHD_CODEC_ZLIB,
304 "zlib (Deflate)",
305 FALSE,
306 zlib_codec_init,
307 zlib_codec_free,
308 zlib_codec_decompress,
309 NULL
310 },
311
312 /* V5 CD zlib compression */
313 {
314 CHD_CODEC_CD_ZLIB,
315 "cdzl (CD Deflate)",
316 FALSE,
317 cdzl_codec_init,
318 cdzl_codec_free,
319 cdzl_codec_decompress,
320 NULL
321 },
322#endif
323
324#ifdef HAVE_7ZIP
325 /* V5 CD lzma compression */
326 {
327 CHD_CODEC_CD_LZMA,
328 "cdlz (CD LZMA)",
329 FALSE,
330 cdlz_codec_init,
331 cdlz_codec_free,
332 cdlz_codec_decompress,
333 NULL
334 },
335#endif
336
337#ifdef HAVE_FLAC
338 /* V5 CD flac compression */
339 {
340 CHD_CODEC_CD_FLAC,
341 "cdfl (CD FLAC)",
342 FALSE,
343 cdfl_codec_init,
344 cdfl_codec_free,
345 cdfl_codec_decompress,
346 NULL
347 },
348#endif
349};
350
351/***************************************************************************
352 INLINE FUNCTIONS
353***************************************************************************/
354
355/*-------------------------------------------------
356 get_bigendian_uint64 - fetch a UINT64 from
357 the data stream in bigendian order
358-------------------------------------------------*/
359
360static INLINE UINT64 get_bigendian_uint64(const UINT8 *base)
361{
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];
364}
365
366/*-------------------------------------------------
367 put_bigendian_uint64 - write a UINT64 to
368 the data stream in bigendian order
369-------------------------------------------------*/
370
371static INLINE void put_bigendian_uint64(UINT8 *base, UINT64 value)
372{
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;
380 base[7] = value;
381}
382
383/*-------------------------------------------------
384 get_bigendian_uint48 - fetch a UINT48 from
385 the data stream in bigendian order
386-------------------------------------------------*/
387
388static INLINE UINT64 get_bigendian_uint48(const UINT8 *base)
389{
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];
392}
393
394/*-------------------------------------------------
395 put_bigendian_uint48 - write a UINT48 to
396 the data stream in bigendian order
397-------------------------------------------------*/
398
399static INLINE void put_bigendian_uint48(UINT8 *base, UINT64 value)
400{
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;
407 base[5] = value;
408}
409/*-------------------------------------------------
410 get_bigendian_uint32 - fetch a UINT32 from
411 the data stream in bigendian order
412-------------------------------------------------*/
413
414static INLINE UINT32 get_bigendian_uint32(const UINT8 *base)
415{
416 return (base[0] << 24) | (base[1] << 16) | (base[2] << 8) | base[3];
417}
418
419/*-------------------------------------------------
420 put_bigendian_uint32 - write a UINT32 to
421 the data stream in bigendian order
422-------------------------------------------------*/
423
424#if 0
425static INLINE void put_bigendian_uint32(UINT8 *base, UINT32 value)
426{
427 base[0] = value >> 24;
428 base[1] = value >> 16;
429 base[2] = value >> 8;
430 base[3] = value;
431}
432#endif
433
434/*-------------------------------------------------
435 put_bigendian_uint24 - write a UINT24 to
436 the data stream in bigendian order
437-------------------------------------------------*/
438
439static INLINE void put_bigendian_uint24(UINT8 *base, UINT32 value)
440{
441 value &= 0xffffff;
442 base[0] = value >> 16;
443 base[1] = value >> 8;
444 base[2] = value;
445}
446
447/*-------------------------------------------------
448 get_bigendian_uint24 - fetch a UINT24 from
449 the data stream in bigendian order
450-------------------------------------------------*/
451
452static INLINE UINT32 get_bigendian_uint24(const UINT8 *base)
453{
454 return (base[0] << 16) | (base[1] << 8) | base[2];
455}
456
457/*-------------------------------------------------
458 get_bigendian_uint16 - fetch a UINT16 from
459 the data stream in bigendian order
460-------------------------------------------------*/
461
462static INLINE UINT16 get_bigendian_uint16(const UINT8 *base)
463{
464 return (base[0] << 8) | base[1];
465}
466
467/*-------------------------------------------------
468 put_bigendian_uint16 - write a UINT16 to
469 the data stream in bigendian order
470-------------------------------------------------*/
471
472static INLINE void put_bigendian_uint16(UINT8 *base, UINT16 value)
473{
474 base[0] = value >> 8;
475 base[1] = value;
476}
477
478/*-------------------------------------------------
479 map_extract - extract a single map
480 entry from the datastream
481-------------------------------------------------*/
482
483static INLINE void map_extract(const UINT8 *base, map_entry *entry)
484{
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];
489}
490
491/*-------------------------------------------------
492 map_assemble - write a single map
493 entry to the datastream
494-------------------------------------------------*/
495
496#if 0
497static INLINE void map_assemble(UINT8 *base, map_entry *entry)
498{
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;
504}
505#endif
506
507/*-------------------------------------------------
508 map_size_v5 - calculate CHDv5 map size
509-------------------------------------------------*/
510static INLINE int map_size_v5(chd_header* header)
511{
512 return header->hunkcount * header->mapentrybytes;
513}
514
515/*-------------------------------------------------
516 crc16 - calculate CRC16 (from hashing.cpp)
517-------------------------------------------------*/
518uint16_t crc16(const void *data, uint32_t length)
519{
520 uint16_t crc = 0xffff;
521
522 static const uint16_t s_table[256] =
523 {
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
556 };
557
558 const uint8_t *src = (uint8_t*)data;
559
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++];
563 return crc;
564}
565
566/*-------------------------------------------------
567 decompress_v5_map - decompress the v5 map
568-------------------------------------------------*/
569
570static chd_error decompress_v5_map(chd_file* chd, chd_header* header)
571{
572 uint8_t rawbuf[16];
573 uint16_t mapcrc;
574 uint32_t mapbytes;
575 uint64_t firstoffs;
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;
582 uint8_t* compressed;
583 struct bitstream* bitbuf;
584 struct huffman_decoder* decoder;
585 uint64_t curoffset;
586 if (header->mapoffset == 0)
587 {
588#if 0
589 memset(header->rawmap, 0xff,map_size_v5(header));
590#endif
591 return CHDERR_READ_ERROR;
592 }
593
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];
603
604 /* now read the map */
605 compressed = (uint8_t*)malloc(sizeof(uint8_t) * mapbytes);
606 if (compressed == NULL)
607 return CHDERR_OUT_OF_MEMORY;
608
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);
612 if (bitbuf == NULL)
613 {
614 free(compressed);
615 return CHDERR_OUT_OF_MEMORY;
616 }
617
618 header->rawmap = (uint8_t*)malloc(sizeof(uint8_t) * map_size_v5(header));
619 if (header->rawmap == NULL)
620 {
621 free(compressed);
622 free(bitbuf);
623 return CHDERR_OUT_OF_MEMORY;
624 }
625
626 /* first decode the compression types */
627 decoder = create_huffman_decoder(16, 8);
628 if (decoder == NULL)
629 {
630 free(compressed);
631 free(bitbuf);
632 return CHDERR_OUT_OF_MEMORY;
633 }
634
635 err = huffman_import_tree_rle(decoder, bitbuf);
636 if (err != HUFFERR_NONE)
637 {
638 free(compressed);
639 free(bitbuf);
640 delete_huffman_decoder(decoder);
641 return CHDERR_DECOMPRESSION_ERROR;
642 }
643
644 for (hunknum = 0; hunknum < (int)header->hunkcount; hunknum++)
645 {
646 uint8_t *rawmap = header->rawmap + (hunknum * 12);
647 if (repcount > 0)
648 {
649 rawmap[0] = lastcomp;
650 repcount--;
651 }
652 else
653 {
654 uint8_t val = huffman_decode_one(decoder, bitbuf);
655 if (val == COMPRESSION_RLE_SMALL)
656 {
657 rawmap[0] = lastcomp;
658 repcount = 2 + huffman_decode_one(decoder, bitbuf);
659 }
660 else if (val == COMPRESSION_RLE_LARGE)
661 {
662 rawmap[0] = lastcomp;
663 repcount = 2 + 16 + (huffman_decode_one(decoder, bitbuf) << 4);
664 repcount += huffman_decode_one(decoder, bitbuf);
665 }
666 else
667 rawmap[0] = lastcomp = val;
668 }
669 }
670
671 /* then iterate through the hunks and extract the needed data */
672 curoffset = firstoffs;
673 for (hunknum = 0; hunknum < (int)header->hunkcount; hunknum++)
674 {
675 uint8_t *rawmap = header->rawmap + (hunknum * 12);
676 uint64_t offset = curoffset;
677 uint32_t length = 0;
678 uint16_t crc = 0;
679 switch (rawmap[0])
680 {
681 /* base types */
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);
688 break;
689
690 case COMPRESSION_NONE:
691 curoffset += length = header->hunkbytes;
692 crc = bitstream_read(bitbuf, 16);
693 break;
694
695 case COMPRESSION_SELF:
696 last_self = offset = bitstream_read(bitbuf, selfbits);
697 break;
698
699 case COMPRESSION_PARENT:
700 offset = bitstream_read(bitbuf, parentbits);
701 last_parent = offset;
702 break;
703
704 /* pseudo-types; convert into base types */
705 case COMPRESSION_SELF_1:
706 last_self++;
707 case COMPRESSION_SELF_0:
708 rawmap[0] = COMPRESSION_SELF;
709 offset = last_self;
710 break;
711
712 case COMPRESSION_PARENT_SELF:
713 rawmap[0] = COMPRESSION_PARENT;
714 last_parent = offset = ( ((uint64_t)hunknum) * ((uint64_t)header->hunkbytes) ) / header->unitbytes;
715 break;
716
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;
722 break;
723 }
724 /* UINT24 length */
725 put_bigendian_uint24(&rawmap[1], length);
726
727 /* UINT48 offset */
728 put_bigendian_uint48(&rawmap[4], offset);
729
730 /* crc16 */
731 put_bigendian_uint16(&rawmap[10], crc);
732 }
733
734 /* free memory */
735 free(compressed);
736 free(bitbuf);
737 delete_huffman_decoder(decoder);
738
739 /* verify the final CRC */
740 if (crc16(&header->rawmap[0], header->hunkcount * 12) != mapcrc)
741 return CHDERR_DECOMPRESSION_ERROR;
742
743 return CHDERR_NONE;
744}
745
746/*-------------------------------------------------
747 map_extract_old - extract a single map
748 entry in old format from the datastream
749-------------------------------------------------*/
750
751static INLINE void map_extract_old(const UINT8 *base, map_entry *entry, UINT32 hunkbytes)
752{
753 entry->offset = get_bigendian_uint64(&base[0]);
754 entry->crc = 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);
757#ifdef __MWERKS__
758 entry->offset = entry->offset & 0x00000FFFFFFFFFFFLL;
759#else
760 entry->offset = (entry->offset << 20) >> 20;
761#endif
762}
763
764/***************************************************************************
765 CHD FILE MANAGEMENT
766***************************************************************************/
767
768/*-------------------------------------------------
769 chd_open_file - open a CHD file for access
770-------------------------------------------------*/
771
772chd_error chd_open_file(RFILE *file, int mode, chd_file *parent, chd_file **chd)
773{
774 chd_file *newchd = NULL;
775 chd_error err;
776 int intfnum;
777
778 /* verify parameters */
779 if (file == NULL)
780 EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
781
782 /* punt if invalid parent */
783 if (parent != NULL && parent->cookie != COOKIE_VALUE)
784 EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
785
786 /* allocate memory for the final result */
787 newchd = (chd_file *)malloc(sizeof(**chd));
788 if (newchd == NULL)
789 EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
790 memset(newchd, 0, sizeof(*newchd));
791 newchd->cookie = COOKIE_VALUE;
792 newchd->parent = parent;
793 newchd->file = file;
794
795 /* now attempt to read the header */
796 err = header_read(newchd, &newchd->header);
797 if (err != CHDERR_NONE)
798 EARLY_EXIT(err);
799
800 /* validate the header */
801 err = header_validate(&newchd->header);
802 if (err != CHDERR_NONE)
803 EARLY_EXIT(err);
804
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);
808
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);
812
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);
816
817 /* make sure we have a valid parent */
818 if (parent != NULL)
819 {
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);
825
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);
831 }
832
833 /* now read the hunk map */
834 if (newchd->header.version < 5)
835 {
836 err = map_read(newchd);
837 }
838 else
839 {
840 err = decompress_v5_map(newchd, &(newchd->header));
841 }
842 if (err != CHDERR_NONE)
843 EARLY_EXIT(err);
844
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;
853#endif
854
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);
859
860 /* find the codec interface */
861 if (newchd->header.version < 5)
862 {
863 for (intfnum = 0; intfnum < (int)ARRAY_SIZE(codec_interfaces); intfnum++)
864 if (codec_interfaces[intfnum].compression == newchd->header.compression[0])
865 {
866 newchd->codecintf[0] = &codec_interfaces[intfnum];
867 break;
868 }
869 if (intfnum == ARRAY_SIZE(codec_interfaces))
870 EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);
871
872#ifdef HAVE_ZLIB
873 /* initialize the codec */
874 if (newchd->codecintf[0]->init != NULL)
875 {
876 err = (*newchd->codecintf[0]->init)(&newchd->zlib_codec_data, newchd->header.hunkbytes);
877 (void)err;
878 }
879#endif
880 }
881 else
882 {
883 int i, decompnum;
884 /* verify the compression types and initialize the codecs */
885 for (decompnum = 0; decompnum < (int)ARRAY_SIZE(newchd->header.compression); decompnum++)
886 {
887 for (i = 0 ; i < (int)ARRAY_SIZE(codec_interfaces); i++)
888 {
889 if (codec_interfaces[i].compression == newchd->header.compression[decompnum])
890 {
891 newchd->codecintf[decompnum] = &codec_interfaces[i];
892 if (newchd->codecintf[decompnum] == NULL && newchd->header.compression[decompnum] != 0)
893 {
894 err = CHDERR_UNSUPPORTED_FORMAT;
895 (void)err;
896 }
897
898 /* initialize the codec */
899 if (newchd->codecintf[decompnum]->init != NULL)
900 {
901 void* codec = NULL;
902 switch (newchd->header.compression[decompnum])
903 {
904 case CHD_CODEC_ZLIB:
905#ifdef HAVE_ZLIB
906 codec = &newchd->zlib_codec_data;
907#endif
908 break;
909
910 case CHD_CODEC_CD_ZLIB:
911#ifdef HAVE_ZLIB
912 codec = &newchd->cdzl_codec_data;
913#endif
914 break;
915
916 case CHD_CODEC_CD_LZMA:
917#ifdef HAVE_7ZIP
918 codec = &newchd->cdlz_codec_data;
919#endif
920 break;
921
922 case CHD_CODEC_CD_FLAC:
923#ifdef HAVE_FLAC
924 codec = &newchd->cdfl_codec_data;
925#endif
926 break;
927 }
928 if (codec != NULL)
929 {
930 err = (*newchd->codecintf[decompnum]->init)(codec, newchd->header.hunkbytes);
931 (void)err;
932 }
933 }
934
935 }
936 }
937 }
938 }
939
940#if 0
941 /* HACK */
942 if (err != CHDERR_NONE)
943 EARLY_EXIT(err);
944#endif
945
946 /* all done */
947 *chd = newchd;
948 return CHDERR_NONE;
949
950cleanup:
951 if (newchd != NULL)
952 chd_close(newchd);
953 return err;
954}
955
956/*-------------------------------------------------
957 chd_precache - precache underlying file in
958 memory
959-------------------------------------------------*/
960
961chd_error chd_precache(chd_file *chd)
962{
963 int64_t size, count;
964
965 if (!chd->file_cache)
966 {
967 filestream_seek(chd->file, 0, SEEK_END);
968 size = filestream_tell(chd->file);
969 if (size <= 0)
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);
976 if (count != size)
977 {
978 free(chd->file_cache);
979 chd->file_cache = NULL;
980 return CHDERR_READ_ERROR;
981 }
982 }
983
984 return CHDERR_NONE;
985}
986
987
988/*-------------------------------------------------
989 chd_open - open a CHD file by
990 filename
991-------------------------------------------------*/
992
993chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd)
994{
995 chd_error err;
996 RFILE *file = NULL;
997
998 /* choose the proper mode */
999 switch(mode)
1000 {
1001 case CHD_OPEN_READ:
1002 break;
1003
1004 default:
1005 err = CHDERR_INVALID_PARAMETER;
1006 goto cleanup;
1007 }
1008
1009 /* open the file */
1010 file = filestream_open(filename,
1011 RETRO_VFS_FILE_ACCESS_READ,
1012 RETRO_VFS_FILE_ACCESS_HINT_NONE);
1013
1014 if (!file)
1015 {
1016 err = CHDERR_FILE_NOT_FOUND;
1017 goto cleanup;
1018 }
1019
1020 /* now open the CHD */
1021 err = chd_open_file(file, mode, parent, chd);
1022 if (err != CHDERR_NONE)
1023 goto cleanup;
1024
1025 /* we now own this file */
1026 (*chd)->owns_file = TRUE;
1027
1028cleanup:
1029 if ((err != CHDERR_NONE) && (file != NULL))
1030 filestream_close(file);
1031 return err;
1032}
1033
1034/*-------------------------------------------------
1035 chd_close - close a CHD file for access
1036-------------------------------------------------*/
1037
1038void chd_close(chd_file *chd)
1039{
1040 /* punt if NULL or invalid */
1041 if (chd == NULL || chd->cookie != COOKIE_VALUE)
1042 return;
1043
1044 /* deinit the codec */
1045 if (chd->header.version < 5)
1046 {
1047#ifdef HAVE_ZLIB
1048 if (chd->codecintf[0] != NULL && chd->codecintf[0]->free != NULL)
1049 (*chd->codecintf[0]->free)(&chd->zlib_codec_data);
1050#endif
1051 }
1052 else
1053 {
1054 int i;
1055 /* Free the codecs */
1056 for (i = 0 ; i < 4 ; i++)
1057 {
1058 void* codec = NULL;
1059 if (!chd->codecintf[i])
1060 continue;
1061
1062 switch (chd->codecintf[i]->compression)
1063 {
1064 case CHD_CODEC_CD_LZMA:
1065#ifdef HAVE_7ZIP
1066 codec = &chd->cdlz_codec_data;
1067#endif
1068 break;
1069
1070 case CHD_CODEC_ZLIB:
1071#ifdef HAVE_ZLIB
1072 codec = &chd->zlib_codec_data;
1073#endif
1074 break;
1075
1076 case CHD_CODEC_CD_ZLIB:
1077#ifdef HAVE_ZLIB
1078 codec = &chd->cdzl_codec_data;
1079#endif
1080 break;
1081
1082 case CHD_CODEC_CD_FLAC:
1083#ifdef HAVE_FLAC
1084 codec = &chd->cdfl_codec_data;
1085#endif
1086 break;
1087 }
1088 if (codec)
1089 (*chd->codecintf[i]->free)(codec);
1090 }
1091
1092 /* Free the raw map */
1093 if (chd->header.rawmap != NULL)
1094 free(chd->header.rawmap);
1095 }
1096
1097 /* free the compressed data buffer */
1098 if (chd->compressed != NULL)
1099 free(chd->compressed);
1100
1101#ifdef NEED_CACHE_HUNK
1102 /* free the hunk cache and compare data */
1103 if (chd->compare != NULL)
1104 free(chd->compare);
1105 if (chd->cache != NULL)
1106 free(chd->cache);
1107#endif
1108
1109 /* free the hunk map */
1110 if (chd->map != NULL)
1111 free(chd->map);
1112
1113 /* close the file */
1114 if (chd->owns_file && chd->file != NULL)
1115 filestream_close(chd->file);
1116
1117#ifdef NEED_CACHE_HUNK
1118 if (PRINTF_MAX_HUNK) printf("Max hunk = %d/%d\n", chd->maxhunk, chd->header.totalhunks);
1119#endif
1120
1121 if (chd->file_cache)
1122 free(chd->file_cache);
1123
1124 /* free our memory */
1125 free(chd);
1126}
1127
1128/*-------------------------------------------------
1129 chd_core_file - return the associated
1130 core_file
1131-------------------------------------------------*/
1132
1133RFILE *chd_core_file(chd_file *chd)
1134{
1135 return chd->file;
1136}
1137
1138/*-------------------------------------------------
1139 chd_error_string - return an error string for
1140 the given CHD error
1141-------------------------------------------------*/
1142
1143const char *chd_error_string(chd_error err)
1144{
1145 switch (err)
1146 {
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";
1176 }
1177}
1178
1179/***************************************************************************
1180 CHD HEADER MANAGEMENT
1181***************************************************************************/
1182
1183/*-------------------------------------------------
1184 chd_get_header - return a pointer to the
1185 extracted header data
1186-------------------------------------------------*/
1187
1188const chd_header *chd_get_header(chd_file *chd)
1189{
1190 /* punt if NULL or invalid */
1191 if (chd == NULL || chd->cookie != COOKIE_VALUE)
1192 return NULL;
1193
1194 return &chd->header;
1195}
1196
1197/***************************************************************************
1198 CORE DATA READ/WRITE
1199***************************************************************************/
1200
1201/*-------------------------------------------------
1202 chd_read - read a single hunk from the CHD
1203 file
1204-------------------------------------------------*/
1205
1206chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer)
1207{
1208 /* punt if NULL or invalid */
1209 if (chd == NULL || chd->cookie != COOKIE_VALUE)
1210 return CHDERR_INVALID_PARAMETER;
1211
1212 /* perform the read */
1213 return hunk_read_into_memory(chd, hunknum, (UINT8 *)buffer);
1214}
1215
1216/***************************************************************************
1217 METADATA MANAGEMENT
1218***************************************************************************/
1219
1220/*-------------------------------------------------
1221 chd_get_metadata - get the indexed metadata
1222 of the given type
1223-------------------------------------------------*/
1224
1225chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 *resultlen, UINT32 *resulttag, UINT8 *resultflags)
1226{
1227 metadata_entry metaentry;
1228 chd_error err;
1229 int64_t count;
1230
1231 /* if we didn't find it, just return */
1232 err = metadata_find_entry(chd, searchtag, searchindex, &metaentry);
1233 if (err != CHDERR_NONE)
1234 {
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)
1237 {
1238 char faux_metadata[256];
1239 UINT32 faux_length;
1240
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;
1250
1251 /* copy the metadata itself */
1252 memcpy(output, faux_metadata, MIN(outputlen, faux_length));
1253
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;
1259 return CHDERR_NONE;
1260 }
1261 return err;
1262 }
1263
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;
1270
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;
1278 return CHDERR_NONE;
1279}
1280
1281/***************************************************************************
1282 CODEC INTERFACES
1283***************************************************************************/
1284
1285/*-------------------------------------------------
1286 chd_codec_config - set internal codec
1287 parameters
1288-------------------------------------------------*/
1289
1290chd_error chd_codec_config(chd_file *chd, int param, void *config)
1291{
1292 return CHDERR_INVALID_PARAMETER;
1293}
1294
1295/*-------------------------------------------------
1296 chd_get_codec_name - get the name of a
1297 particular codec
1298-------------------------------------------------*/
1299
1300const char *chd_get_codec_name(UINT32 codec)
1301{
1302 return "Unknown";
1303}
1304
1305/***************************************************************************
1306 INTERNAL HEADER OPERATIONS
1307***************************************************************************/
1308
1309/*-------------------------------------------------
1310 header_validate - check the validity of a
1311 CHD header
1312-------------------------------------------------*/
1313
1314static chd_error header_validate(const chd_header *header)
1315{
1316 int intfnum;
1317
1318 /* require a valid version */
1319 if (header->version == 0 || header->version > CHD_HEADER_VERSION)
1320 return CHDERR_UNSUPPORTED_VERSION;
1321
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;
1329
1330 /* Do not validate v5 header */
1331 if (header->version <= 4)
1332 {
1333 /* require valid flags */
1334 if (header->flags & CHDFLAGS_UNDEFINED)
1335 return CHDERR_INVALID_PARAMETER;
1336
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])
1340 break;
1341
1342 if (intfnum == ARRAY_SIZE(codec_interfaces))
1343 return CHDERR_INVALID_PARAMETER;
1344
1345 /* require a valid hunksize */
1346 if (header->hunkbytes == 0 || header->hunkbytes >= 65536 * 256)
1347 return CHDERR_INVALID_PARAMETER;
1348
1349 /* require a valid hunk count */
1350 if (header->totalhunks == 0)
1351 return CHDERR_INVALID_PARAMETER;
1352
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;
1356
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;
1362
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;
1368 }
1369
1370 return CHDERR_NONE;
1371}
1372
1373/*-------------------------------------------------
1374 header_guess_unitbytes - for older CHD formats,
1375 guess at the bytes/unit based on metadata
1376-------------------------------------------------*/
1377
1378static UINT32 header_guess_unitbytes(chd_file *chd)
1379{
1380 /* look for hard disk metadata; if found, then the unit size == sector size */
1381 char metadata[512];
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)
1385 return i3;
1386
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;
1394
1395 /* otherwise, just map 1:1 with the hunk size */
1396 return chd->header.hunkbytes;
1397}
1398
1399/*-------------------------------------------------
1400 header_read - read a CHD header into the
1401 internal data structure
1402-------------------------------------------------*/
1403
1404static chd_error header_read(chd_file *chd, chd_header *header)
1405{
1406 UINT8 rawheader[CHD_MAX_HEADER_SIZE];
1407 int64_t count;
1408
1409 /* punt if NULL */
1410 if (header == NULL)
1411 return CHDERR_INVALID_PARAMETER;
1412
1413 /* punt if invalid file */
1414 if (chd->file == NULL)
1415 return CHDERR_INVALID_FILE;
1416
1417 /* seek and read */
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;
1422
1423 /* verify the tag */
1424 if (strncmp((char *)rawheader, "MComprHD", 8) != 0)
1425 return CHDERR_INVALID_DATA;
1426
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]);
1431
1432 /* make sure it's a version we understand */
1433 if (header->version == 0 || header->version > CHD_HEADER_VERSION)
1434 return CHDERR_UNSUPPORTED_VERSION;
1435
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))
1442
1443 return CHDERR_INVALID_DATA;
1444
1445 /* extract the common data */
1446 header->flags = get_bigendian_uint32(&rawheader[16]);
1447 header->compression[0] = get_bigendian_uint32(&rawheader[20]);
1448
1449 /* extract the V1/V2-specific data */
1450 if (header->version < 3)
1451 {
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;
1465 }
1466
1467 /* extract the V3-specific data */
1468 else if (header->version == 3)
1469 {
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);
1480 }
1481
1482 /* extract the V4-specific data */
1483 else if (header->version == 4)
1484 {
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);
1494 }
1495
1496 /* extract the V5-specific data */
1497 else if (header->version == 5)
1498 {
1499 /* TODO */
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);
1514
1515 /* determine properties of map entries */
1516 header->mapentrybytes = 12; /* TODO compressed() ? 12 : 4; */
1517
1518 /* hack */
1519 header->totalhunks = header->hunkcount;
1520 }
1521
1522 /* Unknown version */
1523 else
1524 {
1525 /* TODO */
1526 }
1527
1528 /* guess it worked */
1529 return CHDERR_NONE;
1530}
1531
1532/***************************************************************************
1533 INTERNAL HUNK READ/WRITE
1534***************************************************************************/
1535
1536#ifdef NEED_CACHE_HUNK
1537/*-------------------------------------------------
1538 hunk_read_into_cache - read a hunk into
1539 the CHD's hunk cache
1540-------------------------------------------------*/
1541
1542static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum)
1543{
1544 chd_error err;
1545
1546 /* track the max */
1547 if (hunknum > chd->maxhunk)
1548 chd->maxhunk = hunknum;
1549
1550 /* if we're already in the cache, we're done */
1551 if (chd->cachehunk == hunknum)
1552 return CHDERR_NONE;
1553 chd->cachehunk = ~0;
1554
1555 /* otherwise, read the data */
1556 err = hunk_read_into_memory(chd, hunknum, chd->cache);
1557 if (err != CHDERR_NONE)
1558 return err;
1559
1560 /* mark the hunk successfully cached in */
1561 chd->cachehunk = hunknum;
1562 return CHDERR_NONE;
1563}
1564#endif
1565
1566/*-------------------------------------------------
1567 hunk_read_compressed - read a compressed
1568 hunk
1569-------------------------------------------------*/
1570
1571static UINT8* hunk_read_compressed(chd_file *chd, UINT64 offset, size_t size)
1572{
1573 int64_t bytes;
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)
1579 return NULL;
1580 return chd->compressed;
1581}
1582
1583/*-------------------------------------------------
1584 hunk_read_uncompressed - read an uncompressed
1585 hunk
1586-------------------------------------------------*/
1587
1588static chd_error hunk_read_uncompressed(chd_file *chd, UINT64 offset, size_t size, UINT8 *dest)
1589{
1590 int64_t bytes;
1591 if (chd->file_cache)
1592 {
1593 memcpy(dest, chd->file_cache + offset, size);
1594 return CHDERR_NONE;
1595 }
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;
1600 return CHDERR_NONE;
1601}
1602
1603/*-------------------------------------------------
1604 hunk_read_into_memory - read a hunk into
1605 memory at the given location
1606-------------------------------------------------*/
1607
1608static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest)
1609{
1610 chd_error err;
1611
1612 /* punt if no file */
1613 if (chd->file == NULL)
1614 return CHDERR_INVALID_FILE;
1615
1616 /* return an error if out of range */
1617 if (hunknum >= chd->header.totalhunks)
1618 return CHDERR_HUNK_OUT_OF_RANGE;
1619
1620 if (dest == NULL)
1621 return CHDERR_INVALID_PARAMETER;
1622
1623 if (chd->header.version < 5)
1624 {
1625 map_entry *entry = &chd->map[hunknum];
1626 UINT32 bytes;
1627 UINT8* compressed_bytes;
1628
1629 /* switch off the entry type */
1630 switch (entry->flags & MAP_ENTRY_FLAG_TYPE_MASK)
1631 {
1632 /* compressed data */
1633 case V34_MAP_ENTRY_TYPE_COMPRESSED:
1634 {
1635 /* read it into the decompression buffer */
1636
1637 void *codec;
1638 compressed_bytes = hunk_read_compressed(chd, entry->offset,
1639 entry->length);
1640 if (compressed_bytes == NULL)
1641 return CHDERR_READ_ERROR;
1642
1643#ifdef HAVE_ZLIB
1644 /* now decompress using the codec */
1645 err = CHDERR_NONE;
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)
1650 return err;
1651#endif
1652 }
1653 break;
1654
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)
1659 return err;
1660 break;
1661
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];
1667 break;
1668
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)
1673 break;
1674#endif
1675 return hunk_read_into_memory(chd, (UINT32)entry->offset, dest);
1676
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)
1681 return err;
1682 break;
1683 }
1684 return CHDERR_NONE;
1685 }
1686 else
1687 {
1688 void* codec = NULL;
1689 /* get a pointer to the map entry */
1690 uint64_t blockoffs;
1691 uint32_t blocklen;
1692#ifdef VERIFY_BLOCK_CRC
1693 uint16_t blockcrc;
1694#endif
1695 uint8_t *rawmap = &chd->header.rawmap[chd->header.mapentrybytes * hunknum];
1696 UINT8 *compressed_bytes;
1697
1698#if 0
1699 /* uncompressed case - TODO */
1700 if (!compressed())
1701 {
1702 blockoffs = uint64_t(be_read(rawmap, 4)) * uint64_t(m_hunkbytes);
1703 if (blockoffs != 0)
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);
1709 else
1710 memset(dest, 0, m_hunkbytes);
1711 return CHDERR_NONE;
1712 }
1713#endif
1714
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]);
1720#endif
1721 switch (rawmap[0])
1722 {
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)
1733 {
1734 case CHD_CODEC_CD_LZMA:
1735#ifdef HAVE_7ZIP
1736 codec = &chd->cdlz_codec_data;
1737#endif
1738 break;
1739
1740 case CHD_CODEC_ZLIB:
1741#ifdef HAVE_ZLIB
1742 codec = &chd->zlib_codec_data;
1743#endif
1744 break;
1745
1746 case CHD_CODEC_CD_ZLIB:
1747#ifdef HAVE_ZLIB
1748 codec = &chd->cdzl_codec_data;
1749#endif
1750 break;
1751
1752 case CHD_CODEC_CD_FLAC:
1753#ifdef HAVE_FLAC
1754 codec = &chd->cdfl_codec_data;
1755#endif
1756 break;
1757 }
1758 if (codec==NULL)
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)
1762 return err;
1763#ifdef VERIFY_BLOCK_CRC
1764 if (crc16(dest, chd->header.hunkbytes) != blockcrc)
1765 return CHDERR_DECOMPRESSION_ERROR;
1766#endif
1767 return CHDERR_NONE;
1768
1769 case COMPRESSION_NONE:
1770 err = hunk_read_uncompressed(chd, blockoffs, blocklen, dest);
1771 if (err != CHDERR_NONE)
1772 return err;
1773#ifdef VERIFY_BLOCK_CRC
1774 if (crc16(dest, chd->header.hunkbytes) != blockcrc)
1775 return CHDERR_DECOMPRESSION_ERROR;
1776#endif
1777 return CHDERR_NONE;
1778
1779 case COMPRESSION_SELF:
1780 return hunk_read_into_memory(chd, (UINT32)blockoffs, dest);
1781
1782 case COMPRESSION_PARENT:
1783#if 0
1784 /* TODO */
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);
1788#endif
1789 return CHDERR_DECOMPRESSION_ERROR;
1790 }
1791 return CHDERR_NONE;
1792 }
1793
1794 /* We should not reach this code */
1795 return CHDERR_DECOMPRESSION_ERROR;
1796}
1797
1798/***************************************************************************
1799 INTERNAL MAP ACCESS
1800***************************************************************************/
1801
1802static size_t core_fsize(RFILE *f)
1803{
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);
1808 return rv;
1809}
1810
1811/*-------------------------------------------------
1812 map_read - read the initial sector map
1813-------------------------------------------------*/
1814
1815static chd_error map_read(chd_file *chd)
1816{
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];
1821 int64_t count;
1822 chd_error err;
1823 int i;
1824
1825 /* first allocate memory */
1826 chd->map = (map_entry *)malloc(sizeof(chd->map[0]) * chd->header.totalhunks);
1827 if (!chd->map)
1828 return CHDERR_OUT_OF_MEMORY;
1829
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)
1833 {
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;
1838
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)
1843 {
1844 err = CHDERR_READ_ERROR;
1845 goto cleanup;
1846 }
1847 fileoffset += entries * entrysize;
1848
1849 /* process that many */
1850 if (entrysize == MAP_ENTRY_SIZE)
1851 {
1852 for (j = 0; j < entries; j++)
1853 map_extract(&raw_map_entries[j * MAP_ENTRY_SIZE], &chd->map[i + j]);
1854 }
1855 else
1856 {
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);
1859 }
1860
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);
1866 }
1867
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))
1872 {
1873 err = CHDERR_INVALID_FILE;
1874 goto cleanup;
1875 }
1876
1877 /* verify the length */
1878 if (maxoffset > core_fsize(chd->file))
1879 {
1880 err = CHDERR_INVALID_FILE;
1881 goto cleanup;
1882 }
1883 return CHDERR_NONE;
1884
1885cleanup:
1886 if (chd->map)
1887 free(chd->map);
1888 chd->map = NULL;
1889 return err;
1890}
1891
1892/***************************************************************************
1893 INTERNAL METADATA ACCESS
1894***************************************************************************/
1895
1896/*-------------------------------------------------
1897 metadata_find_entry - find a metadata entry
1898-------------------------------------------------*/
1899
1900static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry)
1901{
1902 /* start at the beginning */
1903 metaentry->offset = chd->header.metaoffset;
1904 metaentry->prev = 0;
1905
1906 /* loop until we run out of options */
1907 while (metaentry->offset != 0)
1908 {
1909 UINT8 raw_meta_header[METADATA_HEADER_SIZE];
1910 int64_t count;
1911
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))
1916 break;
1917
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]);
1922
1923 /* flags are encoded in the high byte of length */
1924 metaentry->flags = metaentry->length >> 24;
1925 metaentry->length &= 0x00ffffff;
1926
1927 /* if we got a match, proceed */
1928 if (metatag == CHDMETATAG_WILDCARD || metaentry->metatag == metatag)
1929 if (metaindex-- == 0)
1930 return CHDERR_NONE;
1931
1932 /* no match, fetch the next link */
1933 metaentry->prev = metaentry->offset;
1934 metaentry->offset = metaentry->next;
1935 }
1936
1937 /* if we get here, we didn't find it */
1938 return CHDERR_METADATA_NOT_FOUND;
1939}