update libchdr
[pcsx_rearmed.git] / deps / libretro-common / formats / libchdr / libchdr_chd.c
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
97 const 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 */
101 enum
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 */
113 enum
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 */
159 typedef struct _codec_interface codec_interface;
160 struct _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 */
172 typedef struct _map_entry map_entry;
173 struct _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 */
182 typedef struct _metadata_entry metadata_entry;
183 struct _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 */
194 struct _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
238 static const UINT8 nullmd5[CHD_MD5_BYTES] = { 0 };
239 static const UINT8 nullsha1[CHD_SHA1_BYTES] = { 0 };
240
241 /***************************************************************************
242     PROTOTYPES
243 ***************************************************************************/
244
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);
248
249 /* internal hunk read/write */
250 #ifdef NEED_CACHE_HUNK
251 static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum);
252 #endif
253 static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest);
254
255 /* internal map access */
256 static chd_error map_read(chd_file *chd);
257
258 /* metadata management */
259 static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry);
260
261 /***************************************************************************
262     CODEC INTERFACES
263 ***************************************************************************/
264
265 static 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
360 static 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
371 static 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
388 static 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
399 static 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
414 static 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
425 static 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
439 static 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
452 static 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
462 static 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
472 static 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
483 static 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
497 static 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 -------------------------------------------------*/
510 static 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 -------------------------------------------------*/
518 uint16_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
570 static 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
751 static 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
772 chd_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
950 cleanup:
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
961 chd_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
993 chd_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
1028 cleanup:
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
1038 void 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
1133 RFILE *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
1143 const 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
1188 const 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
1206 chd_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
1225 chd_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
1290 chd_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
1300 const 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
1314 static 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
1378 static 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
1404 static 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
1542 static 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
1571 static 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
1588 static 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
1608 static 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
1802 static 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
1815 static 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
1885 cleanup:
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
1900 static 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 }