Sync to latest upstream
[pcsx_rearmed.git] / deps / libchdr / chd.c
CommitLineData
ce188d4d 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***************************************************************************/
ce188d4d 39
9c659ffe 40#include <stddef.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <time.h>
ce188d4d 45#include "chd.h"
46#include "cdrom.h"
ce188d4d 47#include "flac.h"
9c659ffe 48#include "huffman.h"
ce188d4d 49#include "LzmaEnc.h"
50#include "LzmaDec.h"
9c659ffe 51#include "md5.h"
52#include "sha1.h"
53#include "zlib.h"
ce188d4d 54
55#define TRUE 1
56#define FALSE 0
57
58#define MAX(x, y) (((x) > (y)) ? (x) : (y))
59#define MIN(x, y) (((x) < (y)) ? (x) : (y))
60
61#define SHA1_DIGEST_SIZE 20
62
ce188d4d 63/***************************************************************************
64 DEBUGGING
65***************************************************************************/
66
67#define PRINTF_MAX_HUNK (0)
68
ce188d4d 69/***************************************************************************
70 CONSTANTS
71***************************************************************************/
72
73#define MAP_STACK_ENTRIES 512 /* max number of entries to use on the stack */
74#define MAP_ENTRY_SIZE 16 /* V3 and later */
75#define OLD_MAP_ENTRY_SIZE 8 /* V1-V2 */
76#define METADATA_HEADER_SIZE 16 /* metadata header size */
77#define CRCMAP_HASH_SIZE 4095 /* number of CRC hashtable entries */
78
79#define MAP_ENTRY_FLAG_TYPE_MASK 0x0f /* what type of hunk */
80#define MAP_ENTRY_FLAG_NO_CRC 0x10 /* no CRC is present */
81
82#define CHD_V1_SECTOR_SIZE 512 /* size of a "sector" in the V1 header */
83
84#define COOKIE_VALUE 0xbaadf00d
85#define MAX_ZLIB_ALLOCS 64
86
87#define END_OF_LIST_COOKIE "EndOfListCookie"
88
89#define NO_MATCH (~0)
90
91static const uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 };
92
9c659ffe 93/* V3-V4 entry types */
ce188d4d 94enum
95{
9c659ffe 96 V34_MAP_ENTRY_TYPE_INVALID = 0, /* invalid type */
97 V34_MAP_ENTRY_TYPE_COMPRESSED = 1, /* standard compression */
98 V34_MAP_ENTRY_TYPE_UNCOMPRESSED = 2, /* uncompressed data */
99 V34_MAP_ENTRY_TYPE_MINI = 3, /* mini: use offset as raw data */
100 V34_MAP_ENTRY_TYPE_SELF_HUNK = 4, /* same as another hunk in this file */
101 V34_MAP_ENTRY_TYPE_PARENT_HUNK = 5, /* same as a hunk in the parent file */
102 V34_MAP_ENTRY_TYPE_2ND_COMPRESSED = 6 /* compressed with secondary algorithm (usually FLAC CDDA) */
ce188d4d 103};
104
9c659ffe 105/* V5 compression types */
ce188d4d 106enum
107{
9c659ffe 108 /* codec #0
109 * these types are live when running */
ce188d4d 110 COMPRESSION_TYPE_0 = 0,
9c659ffe 111 /* codec #1 */
ce188d4d 112 COMPRESSION_TYPE_1 = 1,
9c659ffe 113 /* codec #2 */
ce188d4d 114 COMPRESSION_TYPE_2 = 2,
9c659ffe 115 /* codec #3 */
ce188d4d 116 COMPRESSION_TYPE_3 = 3,
9c659ffe 117 /* no compression; implicit length = hunkbytes */
ce188d4d 118 COMPRESSION_NONE = 4,
9c659ffe 119 /* same as another block in this chd */
ce188d4d 120 COMPRESSION_SELF = 5,
9c659ffe 121 /* same as a hunk's worth of units in the parent chd */
ce188d4d 122 COMPRESSION_PARENT = 6,
123
9c659ffe 124 /* start of small RLE run (4-bit length)
125 * these additional pseudo-types are used for compressed encodings: */
ce188d4d 126 COMPRESSION_RLE_SMALL,
9c659ffe 127 /* start of large RLE run (8-bit length) */
ce188d4d 128 COMPRESSION_RLE_LARGE,
9c659ffe 129 /* same as the last COMPRESSION_SELF block */
ce188d4d 130 COMPRESSION_SELF_0,
9c659ffe 131 /* same as the last COMPRESSION_SELF block + 1 */
ce188d4d 132 COMPRESSION_SELF_1,
9c659ffe 133 /* same block in the parent */
ce188d4d 134 COMPRESSION_PARENT_SELF,
9c659ffe 135 /* same as the last COMPRESSION_PARENT block */
ce188d4d 136 COMPRESSION_PARENT_0,
9c659ffe 137 /* same as the last COMPRESSION_PARENT block + 1 */
ce188d4d 138 COMPRESSION_PARENT_1
139};
140
ce188d4d 141/***************************************************************************
142 MACROS
143***************************************************************************/
144
145#define EARLY_EXIT(x) do { (void)(x); goto cleanup; } while (0)
146
ce188d4d 147/***************************************************************************
148 TYPE DEFINITIONS
149***************************************************************************/
150
151/* interface to a codec */
152typedef struct _codec_interface codec_interface;
153struct _codec_interface
154{
155 UINT32 compression; /* type of compression */
156 const char *compname; /* name of the algorithm */
157 UINT8 lossy; /* is this a lossy algorithm? */
158 chd_error (*init)(void *codec, UINT32 hunkbytes); /* codec initialize */
159 void (*free)(void *codec); /* codec free */
160 chd_error (*decompress)(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); /* decompress data */
161 chd_error (*config)(void *codec, int param, void *config); /* configure */
162};
163
ce188d4d 164/* a single map entry */
165typedef struct _map_entry map_entry;
166struct _map_entry
167{
168 UINT64 offset; /* offset within the file of the data */
169 UINT32 crc; /* 32-bit CRC of the data */
170 UINT32 length; /* length of the data */
171 UINT8 flags; /* misc flags */
172};
173
ce188d4d 174/* simple linked-list of hunks used for our CRC map */
175typedef struct _crcmap_entry crcmap_entry;
176struct _crcmap_entry
177{
178 UINT32 hunknum; /* hunk number */
179 crcmap_entry * next; /* next entry in list */
180};
181
ce188d4d 182/* a single metadata entry */
183typedef struct _metadata_entry metadata_entry;
184struct _metadata_entry
185{
186 UINT64 offset; /* offset within the file of the header */
187 UINT64 next; /* offset within the file of the next header */
188 UINT64 prev; /* offset within the file of the previous header */
189 UINT32 length; /* length of the metadata */
190 UINT32 metatag; /* metadata tag */
191 UINT8 flags; /* flag bits */
192};
193
194/* codec-private data for the ZLIB codec */
195
196typedef struct _zlib_allocator zlib_allocator;
197struct _zlib_allocator
198{
199 UINT32 * allocptr[MAX_ZLIB_ALLOCS];
200};
201
202typedef struct _zlib_codec_data zlib_codec_data;
203struct _zlib_codec_data
204{
205 z_stream inflater;
206 zlib_allocator allocator;
207};
208
209/* codec-private data for the LZMA codec */
210#define MAX_LZMA_ALLOCS 64
211
212typedef struct _lzma_allocator lzma_allocator;
213struct _lzma_allocator
214{
215 void *(*Alloc)(void *p, size_t size);
216 void (*Free)(void *p, void *address); /* address can be 0 */
217 void (*FreeSz)(void *p, void *address, size_t size); /* address can be 0 */
218 uint32_t* allocptr[MAX_LZMA_ALLOCS];
219};
220
221typedef struct _lzma_codec_data lzma_codec_data;
9c659ffe 222struct _lzma_codec_data
ce188d4d 223{
224 CLzmaDec decoder;
225 lzma_allocator allocator;
226};
227
228/* codec-private data for the CDZL codec */
229typedef struct _cdzl_codec_data cdzl_codec_data;
230struct _cdzl_codec_data {
9c659ffe 231 /* internal state */
ce188d4d 232 zlib_codec_data base_decompressor;
233 zlib_codec_data subcode_decompressor;
234 uint8_t* buffer;
235};
236
237/* codec-private data for the CDLZ codec */
238typedef struct _cdlz_codec_data cdlz_codec_data;
239struct _cdlz_codec_data {
9c659ffe 240 /* internal state */
ce188d4d 241 lzma_codec_data base_decompressor;
242 zlib_codec_data subcode_decompressor;
243 uint8_t* buffer;
244};
245
246/* codec-private data for the CDFL codec */
247typedef struct _cdfl_codec_data cdfl_codec_data;
248struct _cdfl_codec_data {
9c659ffe 249 /* internal state */
ce188d4d 250 int swap_endian;
251 flac_decoder decoder;
252 z_stream inflater;
253 zlib_allocator allocator;
254 uint8_t* buffer;
255};
256
257/* internal representation of an open CHD file */
258struct _chd_file
259{
260 UINT32 cookie; /* cookie, should equal COOKIE_VALUE */
261
262 core_file * file; /* handle to the open core file */
263 UINT8 owns_file; /* flag indicating if this file should be closed on chd_close() */
264 chd_header header; /* header, extracted from file */
265
266 chd_file * parent; /* pointer to parent file, or NULL */
267
268 map_entry * map; /* array of map entries */
269
270 UINT8 * cache; /* hunk cache pointer */
271 UINT32 cachehunk; /* index of currently cached hunk */
272
273 UINT8 * compare; /* hunk compare pointer */
274 UINT32 comparehunk; /* index of current compare data */
275
276 UINT8 * compressed; /* pointer to buffer for compressed data */
277 const codec_interface * codecintf[4]; /* interface to the codec */
278
279 zlib_codec_data zlib_codec_data; /* zlib codec data */
280 cdzl_codec_data cdzl_codec_data; /* cdzl codec data */
281 cdlz_codec_data cdlz_codec_data; /* cdlz codec data */
282 cdfl_codec_data cdfl_codec_data; /* cdfl codec data */
283
284 crcmap_entry * crcmap; /* CRC map entries */
285 crcmap_entry * crcfree; /* free list CRC entries */
286 crcmap_entry ** crctable; /* table of CRC entries */
287
288 UINT32 maxhunk; /* maximum hunk accessed */
289
290 UINT8 compressing; /* are we compressing? */
291 MD5_CTX compmd5; /* running MD5 during compression */
292 SHA1_CTX compsha1; /* running SHA1 during compression */
293 UINT32 comphunk; /* next hunk we will compress */
294
295 UINT8 verifying; /* are we verifying? */
296 MD5_CTX vermd5; /* running MD5 during verification */
297 SHA1_CTX versha1; /* running SHA1 during verification */
298 UINT32 verhunk; /* next hunk we will verify */
299
300 UINT32 async_hunknum; /* hunk index for asynchronous operations */
301 void * async_buffer; /* buffer pointer for asynchronous operations */
302
9c659ffe 303 UINT8 * file_cache; /* cache of underlying file */
ce188d4d 304};
305
ce188d4d 306/* a single metadata hash entry */
307typedef struct _metadata_hash metadata_hash;
308struct _metadata_hash
309{
310 UINT8 tag[4]; /* tag of the metadata in big-endian */
311 UINT8 sha1[CHD_SHA1_BYTES]; /* hash */
312};
313
ce188d4d 314/***************************************************************************
315 GLOBAL VARIABLES
316***************************************************************************/
317
318static const UINT8 nullmd5[CHD_MD5_BYTES] = { 0 };
319static const UINT8 nullsha1[CHD_SHA1_BYTES] = { 0 };
320
ce188d4d 321/***************************************************************************
322 PROTOTYPES
323***************************************************************************/
324
325/* internal header operations */
326static chd_error header_validate(const chd_header *header);
9c659ffe 327static chd_error header_read(chd_file *chd, chd_header *header);
ce188d4d 328
329/* internal hunk read/write */
330static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum);
331static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest);
332
333/* internal map access */
334static chd_error map_read(chd_file *chd);
335
336/* metadata management */
337static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry);
338
ce188d4d 339/* zlib compression codec */
340static chd_error zlib_codec_init(void *codec, uint32_t hunkbytes);
341static void zlib_codec_free(void *codec);
342static chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
343static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size);
344static void zlib_fast_free(voidpf opaque, voidpf address);
345
346/* lzma compression codec */
347static chd_error lzma_codec_init(void *codec, uint32_t hunkbytes);
348static void lzma_codec_free(void *codec);
349static chd_error lzma_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
350
351/* cdzl compression codec */
352static chd_error cdzl_codec_init(void* codec, uint32_t hunkbytes);
353static void cdzl_codec_free(void* codec);
354static chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
355
356/* cdlz compression codec */
357static chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes);
358static void cdlz_codec_free(void* codec);
359static chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
360
361/* cdfl compression codec */
362static chd_error cdfl_codec_init(void* codec, uint32_t hunkbytes);
363static void cdfl_codec_free(void* codec);
364static chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
365
9c659ffe 366/***************************************************************************
367 * LZMA ALLOCATOR HELPER
368 ***************************************************************************
369 */
ce188d4d 370
371void *lzma_fast_alloc(void *p, size_t size);
372void lzma_fast_free(void *p, void *address);
373
9c659ffe 374/*-------------------------------------------------
375 * lzma_allocator_init
376 *-------------------------------------------------
377 */
ce188d4d 378
379void lzma_allocator_init(void* p)
380{
381 lzma_allocator *codec = (lzma_allocator *)(p);
382
9c659ffe 383 /* reset pointer list */
ce188d4d 384 memset(codec->allocptr, 0, sizeof(codec->allocptr));
385 codec->Alloc = lzma_fast_alloc;
386 codec->Free = lzma_fast_free;
387}
388
9c659ffe 389/*-------------------------------------------------
390 * lzma_allocator_free
391 *-------------------------------------------------
392 */
ce188d4d 393
394void lzma_allocator_free(void* p )
395{
ce188d4d 396 lzma_allocator *codec = (lzma_allocator *)(p);
397
9c659ffe 398 /* free our memory */
399 for (int i = 0 ; i < MAX_LZMA_ALLOCS ; i++)
ce188d4d 400 {
401 if (codec->allocptr[i] != NULL)
402 free(codec->allocptr[i]);
403 }
404}
405
9c659ffe 406/*-------------------------------------------------
407 * lzma_fast_alloc - fast malloc for lzma, which
408 * allocates and frees memory frequently
409 *-------------------------------------------------
410 */
ce188d4d 411
412void *lzma_fast_alloc(void *p, size_t size)
413{
ce188d4d 414 lzma_allocator *codec = (lzma_allocator *)(p);
415
9c659ffe 416 /* compute the size, rounding to the nearest 1k */
ce188d4d 417 size = (size + 0x3ff) & ~0x3ff;
418
9c659ffe 419 /* reuse a hunk if we can */
420 for (int scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
ce188d4d 421 {
422 uint32_t *ptr = codec->allocptr[scan];
423 if (ptr != NULL && size == *ptr)
424 {
9c659ffe 425 /* set the low bit of the size so we don't match next time */
ce188d4d 426 *ptr |= 1;
427 return ptr + 1;
428 }
429 }
430
9c659ffe 431 /* alloc a new one and put it into the list */
432 uint32_t *addr = (uint32_t *)malloc(sizeof(uint8_t) * size + sizeof(uintptr_t));
ce188d4d 433 if (addr==NULL)
434 return NULL;
9c659ffe 435 for (int scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
ce188d4d 436 {
437 if (codec->allocptr[scan] == NULL)
438 {
439 codec->allocptr[scan] = addr;
440 break;
441 }
442 }
443
9c659ffe 444 /* set the low bit of the size so we don't match next time */
ce188d4d 445 *addr = size | 1;
9c659ffe 446 return addr + (sizeof(uint32_t) == sizeof(uintptr_t) ? 1 : 2);
ce188d4d 447}
448
9c659ffe 449/*-------------------------------------------------
450 * lzma_fast_free - fast free for lzma, which
451 * allocates and frees memory frequently
452 *-------------------------------------------------
453 */
ce188d4d 454
455void lzma_fast_free(void *p, void *address)
456{
ce188d4d 457 if (address == NULL)
458 return;
459
9c659ffe 460 lzma_allocator *codec = (lzma_allocator *)(p);
ce188d4d 461
9c659ffe 462 /* find the hunk */
463 uint32_t *ptr = (uint32_t *)(address) - 1;
464 for (int scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
ce188d4d 465 {
466 if (ptr == codec->allocptr[scan])
467 {
9c659ffe 468 /* clear the low bit of the size to allow matches */
ce188d4d 469 *ptr &= ~1;
470 return;
471 }
472 }
473}
474
9c659ffe 475/***************************************************************************
476 * LZMA DECOMPRESSOR
477 ***************************************************************************
478 */
ce188d4d 479
9c659ffe 480/*-------------------------------------------------
481 * lzma_codec_init - constructor
482 *-------------------------------------------------
483 */
ce188d4d 484
485chd_error lzma_codec_init(void* codec, uint32_t hunkbytes)
486{
ce188d4d 487 lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;
488
9c659ffe 489 /* construct the decoder */
ce188d4d 490 LzmaDec_Construct(&lzma_codec->decoder);
491
9c659ffe 492 /* FIXME: this code is written in a way that makes it impossible to safely upgrade the LZMA SDK
493 * This code assumes that the current version of the encoder imposes the same requirements on the
494 * decoder as the encoder used to produce the file. This is not necessarily true. The format
495 * needs to be changed so the encoder properties are written to the file.
ce188d4d 496
9c659ffe 497 * configure the properties like the compressor did */
498 CLzmaEncProps encoder_props;
ce188d4d 499 LzmaEncProps_Init(&encoder_props);
500 encoder_props.level = 9;
501 encoder_props.reduceSize = hunkbytes;
502 LzmaEncProps_Normalize(&encoder_props);
503
9c659ffe 504 /* convert to decoder properties */
505 lzma_allocator* alloc = &lzma_codec->allocator;
ce188d4d 506 lzma_allocator_init(alloc);
9c659ffe 507 CLzmaEncHandle enc = LzmaEnc_Create((ISzAlloc*)alloc);
ce188d4d 508 if (!enc)
509 return CHDERR_DECOMPRESSION_ERROR;
510 if (LzmaEnc_SetProps(enc, &encoder_props) != SZ_OK)
511 {
512 LzmaEnc_Destroy(enc, (ISzAlloc*)&alloc, (ISzAlloc*)&alloc);
513 return CHDERR_DECOMPRESSION_ERROR;
514 }
9c659ffe 515 Byte decoder_props[LZMA_PROPS_SIZE];
516 SizeT props_size = sizeof(decoder_props);
ce188d4d 517 if (LzmaEnc_WriteProperties(enc, decoder_props, &props_size) != SZ_OK)
518 {
519 LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc);
520 return CHDERR_DECOMPRESSION_ERROR;
521 }
522 LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc);
523
9c659ffe 524 /* do memory allocations */
ce188d4d 525 if (LzmaDec_Allocate(&lzma_codec->decoder, decoder_props, LZMA_PROPS_SIZE, (ISzAlloc*)alloc) != SZ_OK)
526 return CHDERR_DECOMPRESSION_ERROR;
9c659ffe 527
528 /* Okay */
ce188d4d 529 return CHDERR_NONE;
530}
531
9c659ffe 532/*-------------------------------------------------
533 * lzma_codec_free
534 *-------------------------------------------------
535 */
ce188d4d 536
537void lzma_codec_free(void* codec)
538{
539 lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;
540
9c659ffe 541 /* free memory */
ce188d4d 542 LzmaDec_Free(&lzma_codec->decoder, (ISzAlloc*)&lzma_codec->allocator);
9c659ffe 543 lzma_allocator_free(&lzma_codec->allocator);
ce188d4d 544}
545
9c659ffe 546/*-------------------------------------------------
547 * decompress - decompress data using the LZMA
548 * codec
549 *-------------------------------------------------
550 */
ce188d4d 551
552chd_error lzma_codec_decompress(void* codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
553{
9c659ffe 554 /* initialize */
ce188d4d 555 lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;
556 LzmaDec_Init(&lzma_codec->decoder);
557
9c659ffe 558 /* decode */
559 SizeT consumedlen = complen;
560 SizeT decodedlen = destlen;
561 ELzmaStatus status;
562 SRes res = LzmaDec_DecodeToBuf(&lzma_codec->decoder, dest, &decodedlen, src, &consumedlen, LZMA_FINISH_END, &status);
ce188d4d 563 if ((res != SZ_OK && res != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) || consumedlen != complen || decodedlen != destlen)
564 return CHDERR_DECOMPRESSION_ERROR;
565 return CHDERR_NONE;
566}
567
9c659ffe 568/* cdlz */
ce188d4d 569chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes)
570{
571 cdlz_codec_data* cdlz = (cdlz_codec_data*) codec;
572
9c659ffe 573 /* allocate buffer */
ce188d4d 574 cdlz->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
9c659ffe 575
576 /* make sure the CHD's hunk size is an even multiple of the frame size */
ce188d4d 577 lzma_codec_init(&cdlz->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
578 zlib_codec_init(&cdlz->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA);
579
580 if (hunkbytes % CD_FRAME_SIZE != 0)
581 return CHDERR_CODEC_ERROR;
582
583 return CHDERR_NONE;
584}
585
586void cdlz_codec_free(void* codec)
587{
9c659ffe 588 cdlz_codec_data* cdlz = (cdlz_codec_data*) codec;
589 free(cdlz->buffer);
590 lzma_codec_free(&cdlz->base_decompressor);
591 zlib_codec_free(&cdlz->subcode_decompressor);
ce188d4d 592}
593
594chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
595{
9c659ffe 596 uint8_t *sector;
ce188d4d 597 cdlz_codec_data* cdlz = (cdlz_codec_data*)codec;
598
9c659ffe 599 /* determine header bytes */
ce188d4d 600 uint32_t frames = destlen / CD_FRAME_SIZE;
601 uint32_t complen_bytes = (destlen < 65536) ? 2 : 3;
602 uint32_t ecc_bytes = (frames + 7) / 8;
603 uint32_t header_bytes = ecc_bytes + complen_bytes;
604
9c659ffe 605 /* extract compressed length of base */
ce188d4d 606 uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1];
607 if (complen_bytes > 2)
608 complen_base = (complen_base << 8) | src[ecc_bytes + 2];
609
9c659ffe 610 /* reset and decode */
ce188d4d 611 lzma_codec_decompress(&cdlz->base_decompressor, &src[header_bytes], complen_base, &cdlz->buffer[0], frames * CD_MAX_SECTOR_DATA);
612 zlib_codec_decompress(&cdlz->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdlz->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);
613
9c659ffe 614 /* reassemble the data */
615 for (uint32_t framenum = 0; framenum < frames; framenum++)
ce188d4d 616 {
ce188d4d 617 memcpy(&dest[framenum * CD_FRAME_SIZE], &cdlz->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
618 memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdlz->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA);
619
9c659ffe 620 /* reconstitute the ECC data and sync header */
621 sector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE];
ce188d4d 622 if ((src[framenum / 8] & (1 << (framenum % 8))) != 0)
623 {
624 memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header));
625 ecc_generate(sector);
626 }
627 }
628 return CHDERR_NONE;
629}
630
9c659ffe 631/* cdzl */
ce188d4d 632
633chd_error cdzl_codec_init(void *codec, uint32_t hunkbytes)
634{
635 cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;
636
9c659ffe 637 /* make sure the CHD's hunk size is an even multiple of the frame size */
ce188d4d 638 zlib_codec_init(&cdzl->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
639 zlib_codec_init(&cdzl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA);
640
641 cdzl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
642 if (hunkbytes % CD_FRAME_SIZE != 0)
643 return CHDERR_CODEC_ERROR;
644
645 return CHDERR_NONE;
646}
647
648void cdzl_codec_free(void *codec)
649{
9c659ffe 650 cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;
651 zlib_codec_free(&cdzl->base_decompressor);
652 zlib_codec_free(&cdzl->subcode_decompressor);
653 free(cdzl->buffer);
ce188d4d 654}
655
656chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
657{
9c659ffe 658 uint8_t *sector;
ce188d4d 659 cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;
9c659ffe 660
661 /* determine header bytes */
ce188d4d 662 uint32_t frames = destlen / CD_FRAME_SIZE;
663 uint32_t complen_bytes = (destlen < 65536) ? 2 : 3;
664 uint32_t ecc_bytes = (frames + 7) / 8;
665 uint32_t header_bytes = ecc_bytes + complen_bytes;
666
9c659ffe 667 /* extract compressed length of base */
ce188d4d 668 uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1];
669 if (complen_bytes > 2)
670 complen_base = (complen_base << 8) | src[ecc_bytes + 2];
671
9c659ffe 672 /* reset and decode */
ce188d4d 673 zlib_codec_decompress(&cdzl->base_decompressor, &src[header_bytes], complen_base, &cdzl->buffer[0], frames * CD_MAX_SECTOR_DATA);
674 zlib_codec_decompress(&cdzl->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdzl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);
675
9c659ffe 676 /* reassemble the data */
677 for (uint32_t framenum = 0; framenum < frames; framenum++)
ce188d4d 678 {
ce188d4d 679 memcpy(&dest[framenum * CD_FRAME_SIZE], &cdzl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
680 memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdzl->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA);
681
9c659ffe 682 /* reconstitute the ECC data and sync header */
683 sector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE];
ce188d4d 684 if ((src[framenum / 8] & (1 << (framenum % 8))) != 0)
685 {
686 memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header));
687 ecc_generate(sector);
688 }
689 }
690 return CHDERR_NONE;
691}
692
9c659ffe 693/***************************************************************************
694 * CD FLAC DECOMPRESSOR
695 ***************************************************************************
696 */
ce188d4d 697
9c659ffe 698/*------------------------------------------------------
699 * cdfl_codec_blocksize - return the optimal block size
700 *------------------------------------------------------
701 */
ce188d4d 702
703static uint32_t cdfl_codec_blocksize(uint32_t bytes)
704{
9c659ffe 705 /* determine FLAC block size, which must be 16-65535
706 * clamp to 2k since that's supposed to be the sweet spot */
ce188d4d 707 uint32_t hunkbytes = bytes / 4;
708 while (hunkbytes > 2048)
709 hunkbytes /= 2;
710 return hunkbytes;
711}
712
713chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes)
714{
ce188d4d 715 cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;
716
717 cdfl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
718
9c659ffe 719 /* make sure the CHD's hunk size is an even multiple of the frame size */
ce188d4d 720 if (hunkbytes % CD_FRAME_SIZE != 0)
721 return CHDERR_CODEC_ERROR;
722
9c659ffe 723 /* determine whether we want native or swapped samples */
724 uint16_t native_endian = 0;
ce188d4d 725 *(uint8_t *)(&native_endian) = 1;
726 cdfl->swap_endian = (native_endian & 1);
727
9c659ffe 728 /* init the inflater */
729 cdfl->inflater.next_in = (Bytef *)cdfl; /* bogus, but that's ok */
ce188d4d 730 cdfl->inflater.avail_in = 0;
9c659ffe 731#if 0
732 cdfl->allocator.install(cdfl->inflater);
733#endif
ce188d4d 734 cdfl->inflater.zalloc = zlib_fast_alloc;
735 cdfl->inflater.zfree = zlib_fast_free;
736 cdfl->inflater.opaque = &cdfl->allocator;
9c659ffe 737 int zerr = inflateInit2(&cdfl->inflater, -MAX_WBITS);
ce188d4d 738
9c659ffe 739 /* convert errors */
ce188d4d 740 if (zerr == Z_MEM_ERROR)
741 return CHDERR_OUT_OF_MEMORY;
742 else if (zerr != Z_OK)
743 return CHDERR_CODEC_ERROR;
744
9c659ffe 745 /* flac decoder init */
ce188d4d 746 flac_decoder_init(&cdfl->decoder);
ce188d4d 747 return CHDERR_NONE;
748}
749
750void cdfl_codec_free(void *codec)
751{
752 cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;
9c659ffe 753 free(cdfl->buffer);
ce188d4d 754 inflateEnd(&cdfl->inflater);
9c659ffe 755 flac_decoder_free(&cdfl->decoder);
ce188d4d 756}
757
758chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
759{
ce188d4d 760 cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;
761
9c659ffe 762 /* reset and decode */
ce188d4d 763 uint32_t frames = destlen / CD_FRAME_SIZE;
9c659ffe 764
ce188d4d 765 if (!flac_decoder_reset(&cdfl->decoder, 44100, 2, cdfl_codec_blocksize(frames * CD_MAX_SECTOR_DATA), src, complen))
766 return CHDERR_DECOMPRESSION_ERROR;
9c659ffe 767 uint8_t *buffer = &cdfl->buffer[0];
ce188d4d 768 if (!flac_decoder_decode_interleaved(&cdfl->decoder, (int16_t *)(buffer), frames * CD_MAX_SECTOR_DATA/4, cdfl->swap_endian))
769 return CHDERR_DECOMPRESSION_ERROR;
770
9c659ffe 771 /* inflate the subcode data */
772 uint32_t offset = flac_decoder_finish(&cdfl->decoder);
ce188d4d 773 cdfl->inflater.next_in = (Bytef *)(src + offset);
774 cdfl->inflater.avail_in = complen - offset;
775 cdfl->inflater.total_in = 0;
776 cdfl->inflater.next_out = &cdfl->buffer[frames * CD_MAX_SECTOR_DATA];
777 cdfl->inflater.avail_out = frames * CD_MAX_SUBCODE_DATA;
778 cdfl->inflater.total_out = 0;
9c659ffe 779 int zerr = inflateReset(&cdfl->inflater);
ce188d4d 780 if (zerr != Z_OK)
781 return CHDERR_DECOMPRESSION_ERROR;
782
9c659ffe 783 /* do it */
ce188d4d 784 zerr = inflate(&cdfl->inflater, Z_FINISH);
785 if (zerr != Z_STREAM_END)
786 return CHDERR_DECOMPRESSION_ERROR;
787 if (cdfl->inflater.total_out != frames * CD_MAX_SUBCODE_DATA)
788 return CHDERR_DECOMPRESSION_ERROR;
789
9c659ffe 790 /* reassemble the data */
791 for (uint32_t framenum = 0; framenum < frames; framenum++)
ce188d4d 792 {
793 memcpy(&dest[framenum * CD_FRAME_SIZE], &cdfl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
794 memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdfl->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA);
795 }
796
797 return CHDERR_NONE;
798}
799/***************************************************************************
800 CODEC INTERFACES
801***************************************************************************/
802
ce188d4d 803static const codec_interface codec_interfaces[] =
804{
805 /* "none" or no compression */
806 {
807 CHDCOMPRESSION_NONE,
808 "none",
809 FALSE,
810 NULL,
811 NULL,
812 NULL,
813 NULL
814 },
815
816 /* standard zlib compression */
817 {
818 CHDCOMPRESSION_ZLIB,
819 "zlib",
820 FALSE,
821 zlib_codec_init,
822 zlib_codec_free,
823 zlib_codec_decompress,
824 NULL
825 },
826
827 /* zlib+ compression */
828 {
829 CHDCOMPRESSION_ZLIB_PLUS,
830 "zlib+",
831 FALSE,
832 zlib_codec_init,
833 zlib_codec_free,
834 zlib_codec_decompress,
835 NULL
836 },
837
9c659ffe 838 /* V5 zlib compression */
839 {
840 CHD_CODEC_ZLIB,
841 "zlib (Deflate)",
842 FALSE,
843 zlib_codec_init,
844 zlib_codec_free,
845 zlib_codec_decompress,
846 NULL
847 },
848
ce188d4d 849 /* V5 CD zlib compression */
850 {
851 CHD_CODEC_CD_ZLIB,
852 "cdzl (CD Deflate)",
853 FALSE,
854 cdzl_codec_init,
855 cdzl_codec_free,
856 cdzl_codec_decompress,
857 NULL
9c659ffe 858 },
ce188d4d 859
860 /* V5 CD lzma compression */
861 {
862 CHD_CODEC_CD_LZMA,
863 "cdlz (CD LZMA)",
864 FALSE,
865 cdlz_codec_init,
866 cdlz_codec_free,
867 cdlz_codec_decompress,
868 NULL
9c659ffe 869 },
ce188d4d 870
871 /* V5 CD flac compression */
872 {
873 CHD_CODEC_CD_FLAC,
874 "cdfl (CD FLAC)",
875 FALSE,
876 cdfl_codec_init,
877 cdfl_codec_free,
878 cdfl_codec_decompress,
879 NULL
9c659ffe 880 },
ce188d4d 881};
882
883/***************************************************************************
884 INLINE FUNCTIONS
885***************************************************************************/
886
887/*-------------------------------------------------
888 get_bigendian_uint64 - fetch a UINT64 from
889 the data stream in bigendian order
890-------------------------------------------------*/
891
892static inline UINT64 get_bigendian_uint64(const UINT8 *base)
893{
894 return ((UINT64)base[0] << 56) | ((UINT64)base[1] << 48) | ((UINT64)base[2] << 40) | ((UINT64)base[3] << 32) |
895 ((UINT64)base[4] << 24) | ((UINT64)base[5] << 16) | ((UINT64)base[6] << 8) | (UINT64)base[7];
896}
897
ce188d4d 898/*-------------------------------------------------
899 put_bigendian_uint64 - write a UINT64 to
900 the data stream in bigendian order
901-------------------------------------------------*/
902
903static inline void put_bigendian_uint64(UINT8 *base, UINT64 value)
904{
905 base[0] = value >> 56;
906 base[1] = value >> 48;
907 base[2] = value >> 40;
908 base[3] = value >> 32;
909 base[4] = value >> 24;
910 base[5] = value >> 16;
911 base[6] = value >> 8;
912 base[7] = value;
913}
914
915/*-------------------------------------------------
916 get_bigendian_uint48 - fetch a UINT48 from
917 the data stream in bigendian order
918-------------------------------------------------*/
919
920static inline UINT64 get_bigendian_uint48(const UINT8 *base)
921{
922 return ((UINT64)base[0] << 40) | ((UINT64)base[1] << 32) |
923 ((UINT64)base[2] << 24) | ((UINT64)base[3] << 16) | ((UINT64)base[4] << 8) | (UINT64)base[5];
924}
925
926/*-------------------------------------------------
927 put_bigendian_uint48 - write a UINT48 to
928 the data stream in bigendian order
929-------------------------------------------------*/
930
931static inline void put_bigendian_uint48(UINT8 *base, UINT64 value)
932{
9c659ffe 933 value &= 0xffffffffffff;
ce188d4d 934 base[0] = value >> 40;
935 base[1] = value >> 32;
936 base[2] = value >> 24;
937 base[3] = value >> 16;
938 base[4] = value >> 8;
939 base[5] = value;
940}
941/*-------------------------------------------------
942 get_bigendian_uint32 - fetch a UINT32 from
943 the data stream in bigendian order
944-------------------------------------------------*/
945
946static inline UINT32 get_bigendian_uint32(const UINT8 *base)
947{
948 return (base[0] << 24) | (base[1] << 16) | (base[2] << 8) | base[3];
949}
950
ce188d4d 951/*-------------------------------------------------
952 put_bigendian_uint32 - write a UINT32 to
953 the data stream in bigendian order
954-------------------------------------------------*/
955
9c659ffe 956static inline void put_bigendian_uint32(UINT8 *base, UINT32 value)
ce188d4d 957{
9c659ffe 958 base[0] = value >> 24;
959 base[1] = value >> 16;
960 base[2] = value >> 8;
961 base[3] = value;
ce188d4d 962}
963
ce188d4d 964/*-------------------------------------------------
965 put_bigendian_uint24 - write a UINT24 to
966 the data stream in bigendian order
967-------------------------------------------------*/
968
9c659ffe 969static inline void put_bigendian_uint24(UINT8 *base, UINT32 value)
ce188d4d 970{
971 value &= 0xffffff;
972 base[0] = value >> 16;
973 base[1] = value >> 8;
974 base[2] = value;
975}
976
977/*-------------------------------------------------
978 get_bigendian_uint24 - fetch a UINT24 from
979 the data stream in bigendian order
980-------------------------------------------------*/
981
982static inline UINT32 get_bigendian_uint24(const UINT8 *base)
983{
984 return (base[0] << 16) | (base[1] << 8) | base[2];
985}
986
987/*-------------------------------------------------
988 get_bigendian_uint16 - fetch a UINT16 from
989 the data stream in bigendian order
990-------------------------------------------------*/
991
992static inline UINT16 get_bigendian_uint16(const UINT8 *base)
993{
994 return (base[0] << 8) | base[1];
995}
996
ce188d4d 997/*-------------------------------------------------
998 put_bigendian_uint16 - write a UINT16 to
999 the data stream in bigendian order
1000-------------------------------------------------*/
1001
1002static inline void put_bigendian_uint16(UINT8 *base, UINT16 value)
1003{
1004 base[0] = value >> 8;
1005 base[1] = value;
1006}
1007
ce188d4d 1008/*-------------------------------------------------
1009 map_extract - extract a single map
1010 entry from the datastream
1011-------------------------------------------------*/
1012
1013static inline void map_extract(const UINT8 *base, map_entry *entry)
1014{
1015 entry->offset = get_bigendian_uint64(&base[0]);
1016 entry->crc = get_bigendian_uint32(&base[8]);
1017 entry->length = get_bigendian_uint16(&base[12]) | (base[14] << 16);
1018 entry->flags = base[15];
1019}
1020
ce188d4d 1021/*-------------------------------------------------
1022 map_assemble - write a single map
1023 entry to the datastream
1024-------------------------------------------------*/
1025
1026static inline void map_assemble(UINT8 *base, map_entry *entry)
1027{
1028 put_bigendian_uint64(&base[0], entry->offset);
1029 put_bigendian_uint32(&base[8], entry->crc);
1030 put_bigendian_uint16(&base[12], entry->length);
1031 base[14] = entry->length >> 16;
1032 base[15] = entry->flags;
1033}
1034
1035/*-------------------------------------------------
1036 map_size_v5 - calculate CHDv5 map size
1037-------------------------------------------------*/
1038static inline int map_size_v5(chd_header* header)
1039{
1040 return header->hunkcount * header->mapentrybytes;
1041}
1042
ce188d4d 1043/*-------------------------------------------------
1044 crc16 - calculate CRC16 (from hashing.cpp)
1045-------------------------------------------------*/
1046uint16_t crc16(const void *data, uint32_t length)
1047{
1048 uint16_t crc = 0xffff;
1049
1050 static const uint16_t s_table[256] =
1051 {
1052 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
1053 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
1054 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
1055 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
1056 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
1057 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
1058 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
1059 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
1060 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
1061 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
1062 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
1063 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
1064 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
1065 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
1066 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
1067 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
1068 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
1069 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
1070 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
1071 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
1072 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
1073 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
1074 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
1075 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
1076 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
1077 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
1078 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
1079 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
1080 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
1081 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
1082 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
1083 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
1084 };
1085
1086 const uint8_t *src = (uint8_t*)data;
1087
9c659ffe 1088 /* fetch the current value into a local and rip through the source data */
ce188d4d 1089 while (length-- != 0)
1090 crc = (crc << 8) ^ s_table[(crc >> 8) ^ *src++];
1091 return crc;
1092}
1093
9c659ffe 1094/*-------------------------------------------------
1095 compressed - test if CHD file is compressed
1096+-------------------------------------------------*/
1097
1098static inline int compressed(chd_header* header) {
1099 return header->compression[0] != CHD_CODEC_NONE;
1100}
1101
ce188d4d 1102/*-------------------------------------------------
1103 decompress_v5_map - decompress the v5 map
1104-------------------------------------------------*/
1105
1106static chd_error decompress_v5_map(chd_file* chd, chd_header* header)
1107{
9c659ffe 1108 int rawmapsize = map_size_v5(header);
ce188d4d 1109
9c659ffe 1110 if (!compressed(header))
ce188d4d 1111 {
9c659ffe 1112 header->rawmap = (uint8_t*)malloc(rawmapsize);
1113 core_fseek(chd->file, header->mapoffset, SEEK_SET);
1114 core_fread(chd->file, header->rawmap, rawmapsize);
1115 return CHDERR_NONE;
ce188d4d 1116 }
1117
9c659ffe 1118 /* read the reader */
1119 uint8_t rawbuf[16];
ce188d4d 1120 core_fseek(chd->file, header->mapoffset, SEEK_SET);
1121 core_fread(chd->file, rawbuf, sizeof(rawbuf));
9c659ffe 1122 uint32_t const mapbytes = get_bigendian_uint32(&rawbuf[0]);
1123 uint64_t const firstoffs = get_bigendian_uint48(&rawbuf[4]);
1124 uint16_t const mapcrc = get_bigendian_uint16(&rawbuf[10]);
1125 uint8_t const lengthbits = rawbuf[12];
1126 uint8_t const selfbits = rawbuf[13];
1127 uint8_t const parentbits = rawbuf[14];
1128
1129 /* now read the map */
1130 uint8_t* compressed = (uint8_t*)malloc(sizeof(uint8_t) * mapbytes);
ce188d4d 1131 core_fseek(chd->file, header->mapoffset + 16, SEEK_SET);
1132 core_fread(chd->file, compressed, mapbytes);
9c659ffe 1133 struct bitstream* bitbuf = create_bitstream(compressed, sizeof(uint8_t) * mapbytes);
1134 header->rawmap = (uint8_t*)malloc(rawmapsize);
ce188d4d 1135
9c659ffe 1136 /* first decode the compression types */
1137 struct huffman_decoder* decoder = create_huffman_decoder(16, 8);
1138 enum huffman_error err = huffman_import_tree_rle(decoder, bitbuf);
ce188d4d 1139 if (err != HUFFERR_NONE)
1140 return CHDERR_DECOMPRESSION_ERROR;
9c659ffe 1141 uint8_t lastcomp = 0;
1142 int repcount = 0;
1143 for (int hunknum = 0; hunknum < header->hunkcount; hunknum++)
ce188d4d 1144 {
1145 uint8_t *rawmap = header->rawmap + (hunknum * 12);
1146 if (repcount > 0)
1147 rawmap[0] = lastcomp, repcount--;
1148 else
1149 {
1150 uint8_t val = huffman_decode_one(decoder, bitbuf);
1151 if (val == COMPRESSION_RLE_SMALL)
1152 rawmap[0] = lastcomp, repcount = 2 + huffman_decode_one(decoder, bitbuf);
1153 else if (val == COMPRESSION_RLE_LARGE)
1154 rawmap[0] = lastcomp, repcount = 2 + 16 + (huffman_decode_one(decoder, bitbuf) << 4), repcount += huffman_decode_one(decoder, bitbuf);
1155 else
1156 rawmap[0] = lastcomp = val;
1157 }
1158 }
1159
9c659ffe 1160 /* then iterate through the hunks and extract the needed data */
1161 uint64_t curoffset = firstoffs;
1162 uint32_t last_self = 0;
1163 uint64_t last_parent = 0;
1164 for (int hunknum = 0; hunknum < header->hunkcount; hunknum++)
ce188d4d 1165 {
1166 uint8_t *rawmap = header->rawmap + (hunknum * 12);
1167 uint64_t offset = curoffset;
1168 uint32_t length = 0;
1169 uint16_t crc = 0;
1170 switch (rawmap[0])
1171 {
9c659ffe 1172 /* base types */
ce188d4d 1173 case COMPRESSION_TYPE_0:
1174 case COMPRESSION_TYPE_1:
1175 case COMPRESSION_TYPE_2:
1176 case COMPRESSION_TYPE_3:
1177 curoffset += length = bitstream_read(bitbuf, lengthbits);
1178 crc = bitstream_read(bitbuf, 16);
1179 break;
1180
1181 case COMPRESSION_NONE:
1182 curoffset += length = header->hunkbytes;
1183 crc = bitstream_read(bitbuf, 16);
1184 break;
1185
1186 case COMPRESSION_SELF:
1187 last_self = offset = bitstream_read(bitbuf, selfbits);
1188 break;
1189
1190 case COMPRESSION_PARENT:
1191 offset = bitstream_read(bitbuf, parentbits);
1192 last_parent = offset;
1193 break;
1194
9c659ffe 1195 /* pseudo-types; convert into base types */
ce188d4d 1196 case COMPRESSION_SELF_1:
1197 last_self++;
1198 case COMPRESSION_SELF_0:
1199 rawmap[0] = COMPRESSION_SELF;
1200 offset = last_self;
1201 break;
1202
1203 case COMPRESSION_PARENT_SELF:
1204 rawmap[0] = COMPRESSION_PARENT;
1205 last_parent = offset = ( ((uint64_t)hunknum) * ((uint64_t)header->hunkbytes) ) / header->unitbytes;
1206 break;
1207
1208 case COMPRESSION_PARENT_1:
1209 last_parent += header->hunkbytes / header->unitbytes;
1210 case COMPRESSION_PARENT_0:
1211 rawmap[0] = COMPRESSION_PARENT;
1212 offset = last_parent;
1213 break;
1214 }
9c659ffe 1215 /* UINT24 length */
ce188d4d 1216 put_bigendian_uint24(&rawmap[1], length);
1217
9c659ffe 1218 /* UINT48 offset */
ce188d4d 1219 put_bigendian_uint48(&rawmap[4], offset);
1220
9c659ffe 1221 /* crc16 */
ce188d4d 1222 put_bigendian_uint16(&rawmap[10], crc);
1223 }
1224
9c659ffe 1225 free(compressed);
1226 free(bitbuf);
1227 free(decoder->lookup);
1228 free(decoder->huffnode);
1229 free(decoder);
1230
1231 /* verify the final CRC */
ce188d4d 1232 if (crc16(&header->rawmap[0], header->hunkcount * 12) != mapcrc)
1233 return CHDERR_DECOMPRESSION_ERROR;
1234
1235 return CHDERR_NONE;
1236}
1237
1238/*-------------------------------------------------
1239 map_extract_old - extract a single map
1240 entry in old format from the datastream
1241-------------------------------------------------*/
1242
1243static inline void map_extract_old(const UINT8 *base, map_entry *entry, UINT32 hunkbytes)
1244{
1245 entry->offset = get_bigendian_uint64(&base[0]);
1246 entry->crc = 0;
1247 entry->length = entry->offset >> 44;
1248 entry->flags = MAP_ENTRY_FLAG_NO_CRC | ((entry->length == hunkbytes) ? V34_MAP_ENTRY_TYPE_UNCOMPRESSED : V34_MAP_ENTRY_TYPE_COMPRESSED);
1249#ifdef __MWERKS__
1250 entry->offset = entry->offset & 0x00000FFFFFFFFFFFLL;
1251#else
1252 entry->offset = (entry->offset << 20) >> 20;
1253#endif
1254}
1255
ce188d4d 1256/***************************************************************************
1257 CHD FILE MANAGEMENT
1258***************************************************************************/
1259
ce188d4d 1260/*-------------------------------------------------
1261 chd_open_file - open a CHD file for access
1262-------------------------------------------------*/
1263
1264chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **chd)
1265{
1266 chd_file *newchd = NULL;
1267 chd_error err;
1268 int intfnum;
1269
1270 /* verify parameters */
1271 if (file == NULL)
1272 EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
1273
1274 /* punt if invalid parent */
1275 if (parent != NULL && parent->cookie != COOKIE_VALUE)
1276 EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
1277
1278 /* allocate memory for the final result */
9c659ffe 1279 newchd = (chd_file *)malloc(sizeof(**chd));
ce188d4d 1280 if (newchd == NULL)
1281 EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
9c659ffe 1282 memset(newchd, 0, sizeof(*newchd));
ce188d4d 1283 newchd->cookie = COOKIE_VALUE;
1284 newchd->parent = parent;
1285 newchd->file = file;
1286
1287 /* now attempt to read the header */
9c659ffe 1288 err = header_read(newchd, &newchd->header);
ce188d4d 1289 if (err != CHDERR_NONE)
1290 EARLY_EXIT(err);
1291
1292 /* validate the header */
1293 err = header_validate(&newchd->header);
1294 if (err != CHDERR_NONE)
1295 EARLY_EXIT(err);
1296
1297 /* make sure we don't open a read-only file writeable */
1298 if (mode == CHD_OPEN_READWRITE && !(newchd->header.flags & CHDFLAGS_IS_WRITEABLE))
1299 EARLY_EXIT(err = CHDERR_FILE_NOT_WRITEABLE);
1300
1301 /* also, never open an older version writeable */
1302 if (mode == CHD_OPEN_READWRITE && newchd->header.version < CHD_HEADER_VERSION)
1303 EARLY_EXIT(err = CHDERR_UNSUPPORTED_VERSION);
1304
1305 /* if we need a parent, make sure we have one */
1306 if (parent == NULL && (newchd->header.flags & CHDFLAGS_HAS_PARENT))
1307 EARLY_EXIT(err = CHDERR_REQUIRES_PARENT);
1308
1309 /* make sure we have a valid parent */
1310 if (parent != NULL)
1311 {
1312 /* check MD5 if it isn't empty */
1313 if (memcmp(nullmd5, newchd->header.parentmd5, sizeof(newchd->header.parentmd5)) != 0 &&
1314 memcmp(nullmd5, newchd->parent->header.md5, sizeof(newchd->parent->header.md5)) != 0 &&
1315 memcmp(newchd->parent->header.md5, newchd->header.parentmd5, sizeof(newchd->header.parentmd5)) != 0)
1316 EARLY_EXIT(err = CHDERR_INVALID_PARENT);
1317
1318 /* check SHA1 if it isn't empty */
1319 if (memcmp(nullsha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0 &&
1320 memcmp(nullsha1, newchd->parent->header.sha1, sizeof(newchd->parent->header.sha1)) != 0 &&
1321 memcmp(newchd->parent->header.sha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0)
1322 EARLY_EXIT(err = CHDERR_INVALID_PARENT);
1323 }
1324
1325 /* now read the hunk map */
1326 if (newchd->header.version < 5)
1327 {
1328 err = map_read(newchd);
ce188d4d 1329 }
9c659ffe 1330 else
ce188d4d 1331 {
1332 err = decompress_v5_map(newchd, &(newchd->header));
1333 }
9c659ffe 1334 if (err != CHDERR_NONE)
1335 EARLY_EXIT(err);
1336
ce188d4d 1337
1338 /* allocate and init the hunk cache */
1339 newchd->cache = (UINT8 *)malloc(newchd->header.hunkbytes);
1340 newchd->compare = (UINT8 *)malloc(newchd->header.hunkbytes);
1341 if (newchd->cache == NULL || newchd->compare == NULL)
1342 EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
1343 newchd->cachehunk = ~0;
1344 newchd->comparehunk = ~0;
1345
1346 /* allocate the temporary compressed buffer */
1347 newchd->compressed = (UINT8 *)malloc(newchd->header.hunkbytes);
1348 if (newchd->compressed == NULL)
1349 EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
1350
1351 /* find the codec interface */
1352 if (newchd->header.version < 5)
1353 {
1354 for (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++)
9c659ffe 1355 {
ce188d4d 1356 if (codec_interfaces[intfnum].compression == newchd->header.compression[0])
1357 {
1358 newchd->codecintf[0] = &codec_interfaces[intfnum];
1359 break;
1360 }
9c659ffe 1361 }
1362
ce188d4d 1363 if (intfnum == ARRAY_LENGTH(codec_interfaces))
1364 EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);
1365
1366 /* initialize the codec */
1367 if (newchd->codecintf[0]->init != NULL)
9c659ffe 1368 {
ce188d4d 1369 err = (*newchd->codecintf[0]->init)(&newchd->zlib_codec_data, newchd->header.hunkbytes);
9c659ffe 1370 if (err != CHDERR_NONE)
1371 EARLY_EXIT(err);
1372 }
ce188d4d 1373 }
1374 else
1375 {
9c659ffe 1376 /* verify the compression types and initialize the codecs */
1377 for (int decompnum = 0; decompnum < ARRAY_LENGTH(newchd->header.compression); decompnum++)
ce188d4d 1378 {
9c659ffe 1379 for (int i = 0 ; i < ARRAY_LENGTH(codec_interfaces) ; i++)
ce188d4d 1380 {
1381 if (codec_interfaces[i].compression == newchd->header.compression[decompnum])
1382 {
1383 newchd->codecintf[decompnum] = &codec_interfaces[i];
9c659ffe 1384 break;
ce188d4d 1385 }
1386 }
9c659ffe 1387
1388 if (newchd->codecintf[decompnum] == NULL && newchd->header.compression[decompnum] != 0)
1389 EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);
1390
1391 /* initialize the codec */
1392 if (newchd->codecintf[decompnum]->init != NULL)
1393 {
1394 void* codec = NULL;
1395 switch (newchd->header.compression[decompnum])
1396 {
1397 case CHD_CODEC_ZLIB:
1398 codec = &newchd->zlib_codec_data;
1399 break;
1400
1401 case CHD_CODEC_CD_ZLIB:
1402 codec = &newchd->cdzl_codec_data;
1403 break;
1404
1405 case CHD_CODEC_CD_LZMA:
1406 codec = &newchd->cdlz_codec_data;
1407 break;
1408
1409 case CHD_CODEC_CD_FLAC:
1410 codec = &newchd->cdfl_codec_data;
1411 break;
1412 }
1413
1414 if (codec == NULL)
1415 EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);
1416
1417 err = (*newchd->codecintf[decompnum]->init)(codec, newchd->header.hunkbytes);
1418 if (err != CHDERR_NONE)
1419 EARLY_EXIT(err);
1420 }
ce188d4d 1421 }
1422 }
1423
ce188d4d 1424 /* all done */
1425 *chd = newchd;
1426 return CHDERR_NONE;
1427
1428cleanup:
1429 if (newchd != NULL)
1430 chd_close(newchd);
1431 return err;
1432}
1433
9c659ffe 1434/*-------------------------------------------------
1435 chd_precache - precache underlying file in
1436 memory
1437-------------------------------------------------*/
1438
1439chd_error chd_precache(chd_file *chd)
1440{
1441 ssize_t size, count;
1442
1443 if (chd->file_cache == NULL)
1444 {
1445 core_fseek(chd->file, 0, SEEK_END);
1446 size = core_ftell(chd->file);
1447 if (size <= 0)
1448 return CHDERR_INVALID_DATA;
1449 chd->file_cache = malloc(size);
1450 if (chd->file_cache == NULL)
1451 return CHDERR_OUT_OF_MEMORY;
1452 core_fseek(chd->file, 0, SEEK_SET);
1453 count = core_fread(chd->file, chd->file_cache, size);
1454 if (count != size)
1455 {
1456 free(chd->file_cache);
1457 chd->file_cache = NULL;
1458 return CHDERR_READ_ERROR;
1459 }
1460 }
1461
1462 return CHDERR_NONE;
1463}
1464
ce188d4d 1465/*-------------------------------------------------
1466 chd_open - open a CHD file by
1467 filename
1468-------------------------------------------------*/
1469
1470chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd)
1471{
1472 chd_error err;
1473 core_file *file = NULL;
1474 UINT32 openflags;
1475
1476 /* choose the proper mode */
1477 switch(mode)
1478 {
1479 case CHD_OPEN_READ:
1480 break;
1481
1482 default:
1483 err = CHDERR_INVALID_PARAMETER;
1484 goto cleanup;
1485 }
1486
1487 /* open the file */
1488 file = core_fopen(filename);
1489 if (file == 0)
1490 {
1491 err = CHDERR_FILE_NOT_FOUND;
1492 goto cleanup;
1493 }
1494
1495 /* now open the CHD */
1496 err = chd_open_file(file, mode, parent, chd);
1497 if (err != CHDERR_NONE)
1498 goto cleanup;
1499
1500 /* we now own this file */
1501 (*chd)->owns_file = TRUE;
1502
1503cleanup:
1504 if ((err != CHDERR_NONE) && (file != NULL))
1505 core_fclose(file);
1506 return err;
1507}
1508
ce188d4d 1509/*-------------------------------------------------
1510 chd_close - close a CHD file for access
1511-------------------------------------------------*/
1512
1513void chd_close(chd_file *chd)
1514{
1515 /* punt if NULL or invalid */
1516 if (chd == NULL || chd->cookie != COOKIE_VALUE)
1517 return;
1518
1519 /* deinit the codec */
1520 if (chd->header.version < 5)
1521 {
9c659ffe 1522 if (chd->codecintf[0] != NULL && chd->codecintf[0]->free != NULL)
1523 (*chd->codecintf[0]->free)(&chd->zlib_codec_data);
ce188d4d 1524 }
1525 else
1526 {
9c659ffe 1527 /* Free the codecs */
1528 for (int i = 0 ; i < ARRAY_LENGTH(chd->codecintf); i++)
ce188d4d 1529 {
1530 void* codec = NULL;
9c659ffe 1531
1532 if (chd->codecintf[i] == NULL)
1533 continue;
1534
ce188d4d 1535 switch (chd->codecintf[i]->compression)
1536 {
1537 case CHD_CODEC_CD_LZMA:
1538 codec = &chd->cdlz_codec_data;
1539 break;
1540
9c659ffe 1541 case CHD_CODEC_ZLIB:
1542 codec = &chd->zlib_codec_data;
1543 break;
1544
ce188d4d 1545 case CHD_CODEC_CD_ZLIB:
1546 codec = &chd->cdzl_codec_data;
1547 break;
1548
1549 case CHD_CODEC_CD_FLAC:
1550 codec = &chd->cdfl_codec_data;
1551 break;
9c659ffe 1552 }
1553
ce188d4d 1554 if (codec)
1555 {
1556 (*chd->codecintf[i]->free)(codec);
1557 }
1558 }
1559
9c659ffe 1560 /* Free the raw map */
ce188d4d 1561 if (chd->header.rawmap != NULL)
1562 free(chd->header.rawmap);
1563 }
1564
1565 /* free the compressed data buffer */
1566 if (chd->compressed != NULL)
1567 free(chd->compressed);
1568
1569 /* free the hunk cache and compare data */
1570 if (chd->compare != NULL)
1571 free(chd->compare);
1572 if (chd->cache != NULL)
1573 free(chd->cache);
1574
1575 /* free the hunk map */
1576 if (chd->map != NULL)
1577 free(chd->map);
1578
1579 /* free the CRC table */
1580 if (chd->crctable != NULL)
1581 free(chd->crctable);
1582
1583 /* free the CRC map */
1584 if (chd->crcmap != NULL)
1585 free(chd->crcmap);
1586
1587 /* close the file */
1588 if (chd->owns_file && chd->file != NULL)
1589 core_fclose(chd->file);
1590
1591 if (PRINTF_MAX_HUNK) printf("Max hunk = %d/%d\n", chd->maxhunk, chd->header.totalhunks);
1592
1593 if (chd->file_cache)
1594 free(chd->file_cache);
1595
1596 /* free our memory */
1597 free(chd);
1598}
1599
ce188d4d 1600/*-------------------------------------------------
1601 chd_core_file - return the associated
1602 core_file
1603-------------------------------------------------*/
1604
1605core_file *chd_core_file(chd_file *chd)
1606{
1607 return chd->file;
1608}
1609
ce188d4d 1610/*-------------------------------------------------
1611 chd_error_string - return an error string for
1612 the given CHD error
1613-------------------------------------------------*/
1614
1615const char *chd_error_string(chd_error err)
1616{
1617 switch (err)
1618 {
1619 case CHDERR_NONE: return "no error";
1620 case CHDERR_NO_INTERFACE: return "no drive interface";
1621 case CHDERR_OUT_OF_MEMORY: return "out of memory";
1622 case CHDERR_INVALID_FILE: return "invalid file";
1623 case CHDERR_INVALID_PARAMETER: return "invalid parameter";
1624 case CHDERR_INVALID_DATA: return "invalid data";
1625 case CHDERR_FILE_NOT_FOUND: return "file not found";
1626 case CHDERR_REQUIRES_PARENT: return "requires parent";
1627 case CHDERR_FILE_NOT_WRITEABLE: return "file not writeable";
1628 case CHDERR_READ_ERROR: return "read error";
1629 case CHDERR_WRITE_ERROR: return "write error";
1630 case CHDERR_CODEC_ERROR: return "codec error";
1631 case CHDERR_INVALID_PARENT: return "invalid parent";
1632 case CHDERR_HUNK_OUT_OF_RANGE: return "hunk out of range";
1633 case CHDERR_DECOMPRESSION_ERROR: return "decompression error";
1634 case CHDERR_COMPRESSION_ERROR: return "compression error";
1635 case CHDERR_CANT_CREATE_FILE: return "can't create file";
1636 case CHDERR_CANT_VERIFY: return "can't verify file";
1637 case CHDERR_NOT_SUPPORTED: return "operation not supported";
1638 case CHDERR_METADATA_NOT_FOUND: return "can't find metadata";
1639 case CHDERR_INVALID_METADATA_SIZE: return "invalid metadata size";
1640 case CHDERR_UNSUPPORTED_VERSION: return "unsupported CHD version";
1641 case CHDERR_VERIFY_INCOMPLETE: return "incomplete verify";
1642 case CHDERR_INVALID_METADATA: return "invalid metadata";
1643 case CHDERR_INVALID_STATE: return "invalid state";
1644 case CHDERR_OPERATION_PENDING: return "operation pending";
1645 case CHDERR_NO_ASYNC_OPERATION: return "no async operation in progress";
1646 case CHDERR_UNSUPPORTED_FORMAT: return "unsupported format";
1647 default: return "undocumented error";
1648 }
1649}
1650
ce188d4d 1651/***************************************************************************
1652 CHD HEADER MANAGEMENT
1653***************************************************************************/
1654
1655/*-------------------------------------------------
1656 chd_get_header - return a pointer to the
1657 extracted header data
1658-------------------------------------------------*/
1659
1660const chd_header *chd_get_header(chd_file *chd)
1661{
1662 /* punt if NULL or invalid */
1663 if (chd == NULL || chd->cookie != COOKIE_VALUE)
1664 return NULL;
1665
1666 return &chd->header;
1667}
1668
ce188d4d 1669/***************************************************************************
1670 CORE DATA READ/WRITE
1671***************************************************************************/
1672
1673/*-------------------------------------------------
1674 chd_read - read a single hunk from the CHD
1675 file
1676-------------------------------------------------*/
1677
1678chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer)
1679{
1680 /* punt if NULL or invalid */
1681 if (chd == NULL || chd->cookie != COOKIE_VALUE)
1682 return CHDERR_INVALID_PARAMETER;
1683
1684 /* if we're past the end, fail */
1685 if (hunknum >= chd->header.totalhunks)
1686 return CHDERR_HUNK_OUT_OF_RANGE;
1687
1688 /* perform the read */
1689 return hunk_read_into_memory(chd, hunknum, (UINT8 *)buffer);
1690}
1691
ce188d4d 1692/***************************************************************************
1693 METADATA MANAGEMENT
1694***************************************************************************/
1695
1696/*-------------------------------------------------
1697 chd_get_metadata - get the indexed metadata
1698 of the given type
1699-------------------------------------------------*/
1700
1701chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 *resultlen, UINT32 *resulttag, UINT8 *resultflags)
1702{
1703 metadata_entry metaentry;
1704 chd_error err;
1705 UINT32 count;
1706
1707 /* if we didn't find it, just return */
1708 err = metadata_find_entry(chd, searchtag, searchindex, &metaentry);
1709 if (err != CHDERR_NONE)
1710 {
1711 /* unless we're an old version and they are requesting hard disk metadata */
1712 if (chd->header.version < 3 && (searchtag == HARD_DISK_METADATA_TAG || searchtag == CHDMETATAG_WILDCARD) && searchindex == 0)
1713 {
1714 char faux_metadata[256];
1715 UINT32 faux_length;
1716
1717 /* fill in the faux metadata */
1718 sprintf(faux_metadata, HARD_DISK_METADATA_FORMAT, chd->header.obsolete_cylinders, chd->header.obsolete_heads, chd->header.obsolete_sectors, chd->header.hunkbytes / chd->header.obsolete_hunksize);
1719 faux_length = (UINT32)strlen(faux_metadata) + 1;
1720
1721 /* copy the metadata itself */
1722 memcpy(output, faux_metadata, MIN(outputlen, faux_length));
1723
1724 /* return the length of the data and the tag */
1725 if (resultlen != NULL)
1726 *resultlen = faux_length;
1727 if (resulttag != NULL)
1728 *resulttag = HARD_DISK_METADATA_TAG;
1729 return CHDERR_NONE;
1730 }
1731 return err;
1732 }
1733
1734 /* read the metadata */
1735 outputlen = MIN(outputlen, metaentry.length);
1736 core_fseek(chd->file, metaentry.offset + METADATA_HEADER_SIZE, SEEK_SET);
1737 count = core_fread(chd->file, output, outputlen);
1738 if (count != outputlen)
1739 return CHDERR_READ_ERROR;
1740
1741 /* return the length of the data and the tag */
1742 if (resultlen != NULL)
1743 *resultlen = metaentry.length;
1744 if (resulttag != NULL)
1745 *resulttag = metaentry.metatag;
1746 if (resultflags != NULL)
1747 *resultflags = metaentry.flags;
1748 return CHDERR_NONE;
1749}
1750
ce188d4d 1751/***************************************************************************
1752 CODEC INTERFACES
1753***************************************************************************/
1754
1755/*-------------------------------------------------
1756 chd_codec_config - set internal codec
1757 parameters
1758-------------------------------------------------*/
1759
1760chd_error chd_codec_config(chd_file *chd, int param, void *config)
1761{
ce188d4d 1762 return CHDERR_INVALID_PARAMETER;
1763}
1764
ce188d4d 1765/*-------------------------------------------------
1766 chd_get_codec_name - get the name of a
1767 particular codec
1768-------------------------------------------------*/
1769
1770const char *chd_get_codec_name(UINT32 codec)
1771{
1772 return "Unknown";
1773}
1774
ce188d4d 1775/***************************************************************************
1776 INTERNAL HEADER OPERATIONS
1777***************************************************************************/
1778
1779/*-------------------------------------------------
1780 header_validate - check the validity of a
1781 CHD header
1782-------------------------------------------------*/
1783
1784static chd_error header_validate(const chd_header *header)
1785{
1786 int intfnum;
9c659ffe 1787
ce188d4d 1788 /* require a valid version */
1789 if (header->version == 0 || header->version > CHD_HEADER_VERSION)
1790 return CHDERR_UNSUPPORTED_VERSION;
9c659ffe 1791
ce188d4d 1792 /* require a valid length */
1793 if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) ||
1794 (header->version == 2 && header->length != CHD_V2_HEADER_SIZE) ||
1795 (header->version == 3 && header->length != CHD_V3_HEADER_SIZE) ||
1796 (header->version == 4 && header->length != CHD_V4_HEADER_SIZE) ||
1797 (header->version == 5 && header->length != CHD_V5_HEADER_SIZE))
1798 return CHDERR_INVALID_PARAMETER;
9c659ffe 1799
ce188d4d 1800 /* Do not validate v5 header */
1801 if (header->version <= 4)
1802 {
1803 /* require valid flags */
1804 if (header->flags & CHDFLAGS_UNDEFINED)
1805 return CHDERR_INVALID_PARAMETER;
1806
1807 /* require a supported compression mechanism */
1808 for (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++)
1809 if (codec_interfaces[intfnum].compression == header->compression[0])
1810 break;
1811
1812 if (intfnum == ARRAY_LENGTH(codec_interfaces))
1813 return CHDERR_INVALID_PARAMETER;
1814
1815 /* require a valid hunksize */
1816 if (header->hunkbytes == 0 || header->hunkbytes >= 65536 * 256)
1817 return CHDERR_INVALID_PARAMETER;
1818
1819 /* require a valid hunk count */
1820 if (header->totalhunks == 0)
1821 return CHDERR_INVALID_PARAMETER;
1822
1823 /* require a valid MD5 and/or SHA1 if we're using a parent */
1824 if ((header->flags & CHDFLAGS_HAS_PARENT) && memcmp(header->parentmd5, nullmd5, sizeof(nullmd5)) == 0 && memcmp(header->parentsha1, nullsha1, sizeof(nullsha1)) == 0)
1825 return CHDERR_INVALID_PARAMETER;
1826
1827 /* if we're V3 or later, the obsolete fields must be 0 */
1828 if (header->version >= 3 &&
1829 (header->obsolete_cylinders != 0 || header->obsolete_sectors != 0 ||
1830 header->obsolete_heads != 0 || header->obsolete_hunksize != 0))
1831 return CHDERR_INVALID_PARAMETER;
1832
1833 /* if we're pre-V3, the obsolete fields must NOT be 0 */
1834 if (header->version < 3 &&
1835 (header->obsolete_cylinders == 0 || header->obsolete_sectors == 0 ||
1836 header->obsolete_heads == 0 || header->obsolete_hunksize == 0))
1837 return CHDERR_INVALID_PARAMETER;
1838 }
1839
1840 return CHDERR_NONE;
1841}
1842
9c659ffe 1843/*-------------------------------------------------
1844 header_guess_unitbytes - for older CHD formats,
1845 guess at the bytes/unit based on metadata
1846-------------------------------------------------*/
1847
1848static UINT32 header_guess_unitbytes(chd_file *chd)
1849{
1850 /* look for hard disk metadata; if found, then the unit size == sector size */
1851 char metadata[512];
1852 int i0, i1, i2, i3;
1853 if (chd_get_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE &&
1854 sscanf(metadata, HARD_DISK_METADATA_FORMAT, &i0, &i1, &i2, &i3) == 4)
1855 return i3;
1856
1857 /* look for CD-ROM metadata; if found, then the unit size == CD frame size */
1858 if (chd_get_metadata(chd, CDROM_OLD_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
1859 chd_get_metadata(chd, CDROM_TRACK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
1860 chd_get_metadata(chd, CDROM_TRACK_METADATA2_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
1861 chd_get_metadata(chd, GDROM_OLD_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
1862 chd_get_metadata(chd, GDROM_TRACK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE)
1863 return CD_FRAME_SIZE;
1864
1865 /* otherwise, just map 1:1 with the hunk size */
1866 return chd->header.hunkbytes;
1867}
ce188d4d 1868
1869/*-------------------------------------------------
1870 header_read - read a CHD header into the
1871 internal data structure
1872-------------------------------------------------*/
1873
9c659ffe 1874static chd_error header_read(chd_file *chd, chd_header *header)
ce188d4d 1875{
1876 UINT8 rawheader[CHD_MAX_HEADER_SIZE];
1877 UINT32 count;
1878
1879 /* punt if NULL */
1880 if (header == NULL)
1881 return CHDERR_INVALID_PARAMETER;
1882
1883 /* punt if invalid file */
9c659ffe 1884 if (chd->file == NULL)
ce188d4d 1885 return CHDERR_INVALID_FILE;
1886
1887 /* seek and read */
9c659ffe 1888 core_fseek(chd->file, 0, SEEK_SET);
1889 count = core_fread(chd->file, rawheader, sizeof(rawheader));
ce188d4d 1890 if (count != sizeof(rawheader))
1891 return CHDERR_READ_ERROR;
1892
1893 /* verify the tag */
1894 if (strncmp((char *)rawheader, "MComprHD", 8) != 0)
1895 return CHDERR_INVALID_DATA;
1896
1897 /* extract the direct data */
1898 memset(header, 0, sizeof(*header));
1899 header->length = get_bigendian_uint32(&rawheader[8]);
1900 header->version = get_bigendian_uint32(&rawheader[12]);
1901
1902 /* make sure it's a version we understand */
1903 if (header->version == 0 || header->version > CHD_HEADER_VERSION)
1904 return CHDERR_UNSUPPORTED_VERSION;
1905
1906 /* make sure the length is expected */
1907 if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) ||
1908 (header->version == 2 && header->length != CHD_V2_HEADER_SIZE) ||
1909 (header->version == 3 && header->length != CHD_V3_HEADER_SIZE) ||
1910 (header->version == 4 && header->length != CHD_V4_HEADER_SIZE) ||
1911 (header->version == 5 && header->length != CHD_V5_HEADER_SIZE))
9c659ffe 1912
ce188d4d 1913 return CHDERR_INVALID_DATA;
1914
1915 /* extract the common data */
1916 header->flags = get_bigendian_uint32(&rawheader[16]);
1917 header->compression[0] = get_bigendian_uint32(&rawheader[20]);
9c659ffe 1918 header->compression[1] = CHD_CODEC_NONE;
1919 header->compression[2] = CHD_CODEC_NONE;
1920 header->compression[3] = CHD_CODEC_NONE;
ce188d4d 1921
1922 /* extract the V1/V2-specific data */
1923 if (header->version < 3)
1924 {
1925 int seclen = (header->version == 1) ? CHD_V1_SECTOR_SIZE : get_bigendian_uint32(&rawheader[76]);
1926 header->obsolete_hunksize = get_bigendian_uint32(&rawheader[24]);
1927 header->totalhunks = get_bigendian_uint32(&rawheader[28]);
1928 header->obsolete_cylinders = get_bigendian_uint32(&rawheader[32]);
1929 header->obsolete_heads = get_bigendian_uint32(&rawheader[36]);
1930 header->obsolete_sectors = get_bigendian_uint32(&rawheader[40]);
1931 memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES);
1932 memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES);
1933 header->logicalbytes = (UINT64)header->obsolete_cylinders * (UINT64)header->obsolete_heads * (UINT64)header->obsolete_sectors * (UINT64)seclen;
1934 header->hunkbytes = seclen * header->obsolete_hunksize;
9c659ffe 1935 header->unitbytes = header_guess_unitbytes(chd);
1936 header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
ce188d4d 1937 header->metaoffset = 0;
1938 }
1939
1940 /* extract the V3-specific data */
1941 else if (header->version == 3)
1942 {
1943 header->totalhunks = get_bigendian_uint32(&rawheader[24]);
1944 header->logicalbytes = get_bigendian_uint64(&rawheader[28]);
1945 header->metaoffset = get_bigendian_uint64(&rawheader[36]);
1946 memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES);
1947 memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES);
1948 header->hunkbytes = get_bigendian_uint32(&rawheader[76]);
9c659ffe 1949 header->unitbytes = header_guess_unitbytes(chd);
1950 header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
ce188d4d 1951 memcpy(header->sha1, &rawheader[80], CHD_SHA1_BYTES);
1952 memcpy(header->parentsha1, &rawheader[100], CHD_SHA1_BYTES);
1953 }
1954
1955 /* extract the V4-specific data */
1956 else if (header->version == 4)
1957 {
1958 header->totalhunks = get_bigendian_uint32(&rawheader[24]);
1959 header->logicalbytes = get_bigendian_uint64(&rawheader[28]);
1960 header->metaoffset = get_bigendian_uint64(&rawheader[36]);
1961 header->hunkbytes = get_bigendian_uint32(&rawheader[44]);
9c659ffe 1962 header->unitbytes = header_guess_unitbytes(chd);
1963 header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
ce188d4d 1964 memcpy(header->sha1, &rawheader[48], CHD_SHA1_BYTES);
1965 memcpy(header->parentsha1, &rawheader[68], CHD_SHA1_BYTES);
1966 memcpy(header->rawsha1, &rawheader[88], CHD_SHA1_BYTES);
1967 }
1968
1969 /* extract the V5-specific data */
1970 else if (header->version == 5)
1971 {
1972 /* TODO */
9c659ffe 1973 header->compression[0] = get_bigendian_uint32(&rawheader[16]);
1974 header->compression[1] = get_bigendian_uint32(&rawheader[20]);
1975 header->compression[2] = get_bigendian_uint32(&rawheader[24]);
1976 header->compression[3] = get_bigendian_uint32(&rawheader[28]);
1977 header->logicalbytes = get_bigendian_uint64(&rawheader[32]);
1978 header->mapoffset = get_bigendian_uint64(&rawheader[40]);
1979 header->metaoffset = get_bigendian_uint64(&rawheader[48]);
1980 header->hunkbytes = get_bigendian_uint32(&rawheader[56]);
1981 header->hunkcount = (header->logicalbytes + header->hunkbytes - 1) / header->hunkbytes;
1982 header->unitbytes = get_bigendian_uint32(&rawheader[60]);
1983 header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
ce188d4d 1984 memcpy(header->sha1, &rawheader[84], CHD_SHA1_BYTES);
1985 memcpy(header->parentsha1, &rawheader[104], CHD_SHA1_BYTES);
1986 memcpy(header->rawsha1, &rawheader[64], CHD_SHA1_BYTES);
1987
9c659ffe 1988 /* determine properties of map entries */
1989 header->mapentrybytes = compressed(header) ? 12 : 4;
ce188d4d 1990
9c659ffe 1991 /* hack */
ce188d4d 1992 header->totalhunks = header->hunkcount;
1993 }
1994
1995 /* Unknown version */
9c659ffe 1996 else
ce188d4d 1997 {
1998 /* TODO */
1999 }
2000
2001 /* guess it worked */
2002 return CHDERR_NONE;
2003}
2004
ce188d4d 2005/***************************************************************************
2006 INTERNAL HUNK READ/WRITE
2007***************************************************************************/
2008
2009/*-------------------------------------------------
9c659ffe 2010 hunk_read_compressed - read a compressed
2011 hunk
ce188d4d 2012-------------------------------------------------*/
2013
9c659ffe 2014static UINT8* hunk_read_compressed(chd_file *chd, UINT64 offset, size_t size)
ce188d4d 2015{
2016 ssize_t bytes;
2017 if (chd->file_cache != NULL)
2018 {
2019 return chd->file_cache + offset;
2020 }
2021 else
2022 {
2023 core_fseek(chd->file, offset, SEEK_SET);
2024 bytes = core_fread(chd->file, chd->compressed, size);
2025 if (bytes != size)
2026 return NULL;
2027 return chd->compressed;
2028 }
2029}
2030
9c659ffe 2031/*-------------------------------------------------
2032 hunk_read_uncompressed - read an uncompressed
2033 hunk
2034-------------------------------------------------*/
2035
2036static chd_error hunk_read_uncompressed(chd_file *chd, UINT64 offset, size_t size, UINT8 *dest)
ce188d4d 2037{
2038 ssize_t bytes;
2039 if (chd->file_cache != NULL)
2040 {
2041 memcpy(dest, chd->file_cache + offset, size);
2042 }
2043 else
2044 {
2045 core_fseek(chd->file, offset, SEEK_SET);
2046 bytes = core_fread(chd->file, dest, size);
2047 if (bytes != size)
2048 return CHDERR_READ_ERROR;
2049 }
2050 return CHDERR_NONE;
2051}
2052
9c659ffe 2053/*-------------------------------------------------
2054 hunk_read_into_cache - read a hunk into
2055 the CHD's hunk cache
2056-------------------------------------------------*/
2057
2058static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum)
2059{
2060 chd_error err;
2061
2062 /* track the max */
2063 if (hunknum > chd->maxhunk)
2064 chd->maxhunk = hunknum;
2065
2066 /* if we're already in the cache, we're done */
2067 if (chd->cachehunk == hunknum)
2068 return CHDERR_NONE;
2069 chd->cachehunk = ~0;
2070
2071 /* otherwise, read the data */
2072 err = hunk_read_into_memory(chd, hunknum, chd->cache);
2073 if (err != CHDERR_NONE)
2074 return err;
2075
2076 /* mark the hunk successfully cached in */
2077 chd->cachehunk = hunknum;
2078 return CHDERR_NONE;
2079}
2080
ce188d4d 2081/*-------------------------------------------------
2082 hunk_read_into_memory - read a hunk into
2083 memory at the given location
2084-------------------------------------------------*/
2085
2086static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest)
2087{
2088 chd_error err;
2089
9c659ffe 2090 /* punt if no file */
ce188d4d 2091 if (chd->file == NULL)
2092 return CHDERR_INVALID_FILE;
2093
2094 /* return an error if out of range */
2095 if (hunknum >= chd->header.totalhunks)
2096 return CHDERR_HUNK_OUT_OF_RANGE;
2097
2098 if (chd->header.version < 5)
2099 {
2100 map_entry *entry = &chd->map[hunknum];
2101 UINT32 bytes;
9c659ffe 2102 UINT8* compressed_bytes;
ce188d4d 2103
2104 /* switch off the entry type */
2105 switch (entry->flags & MAP_ENTRY_FLAG_TYPE_MASK)
2106 {
2107 /* compressed data */
2108 case V34_MAP_ENTRY_TYPE_COMPRESSED:
9c659ffe 2109
2110 /* read it into the decompression buffer */
2111 compressed_bytes = hunk_read_compressed(chd, entry->offset, entry->length);
2112 if (compressed_bytes == NULL)
2113 return CHDERR_READ_ERROR;
2114
2115 /* now decompress using the codec */
2116 err = CHDERR_NONE;
2117 void* codec = &chd->zlib_codec_data;
2118 if (chd->codecintf[0]->decompress != NULL)
2119 err = (*chd->codecintf[0]->decompress)(codec, compressed_bytes, entry->length, dest, chd->header.hunkbytes);
2120 if (err != CHDERR_NONE)
2121 return err;
ce188d4d 2122 break;
2123
2124 /* uncompressed data */
2125 case V34_MAP_ENTRY_TYPE_UNCOMPRESSED:
9c659ffe 2126 err = hunk_read_uncompressed(chd, entry->offset, chd->header.hunkbytes, dest);
ce188d4d 2127 if (err != CHDERR_NONE)
2128 return err;
2129 break;
2130
2131 /* mini-compressed data */
2132 case V34_MAP_ENTRY_TYPE_MINI:
2133 put_bigendian_uint64(&dest[0], entry->offset);
2134 for (bytes = 8; bytes < chd->header.hunkbytes; bytes++)
2135 dest[bytes] = dest[bytes - 8];
2136 break;
2137
2138 /* self-referenced data */
2139 case V34_MAP_ENTRY_TYPE_SELF_HUNK:
2140 if (chd->cachehunk == entry->offset && dest == chd->cache)
2141 break;
2142 return hunk_read_into_memory(chd, entry->offset, dest);
2143
2144 /* parent-referenced data */
2145 case V34_MAP_ENTRY_TYPE_PARENT_HUNK:
2146 err = hunk_read_into_memory(chd->parent, entry->offset, dest);
2147 if (err != CHDERR_NONE)
2148 return err;
2149 break;
2150 }
2151 return CHDERR_NONE;
2152 }
2153 else
2154 {
9c659ffe 2155 /* get a pointer to the map entry */
ce188d4d 2156 uint64_t blockoffs;
2157 uint32_t blocklen;
2158 uint16_t blockcrc;
ce188d4d 2159 uint8_t *rawmap = &chd->header.rawmap[chd->header.mapentrybytes * hunknum];
9c659ffe 2160 UINT8* compressed_bytes;
ce188d4d 2161
9c659ffe 2162 /* uncompressed case */
2163 if (!compressed(&chd->header))
ce188d4d 2164 {
9c659ffe 2165 blockoffs = (uint64_t)get_bigendian_uint32(rawmap) * (uint64_t)chd->header.hunkbytes;
2166 if (blockoffs != 0) {
2167 core_fseek(chd->file, blockoffs, SEEK_SET);
2168 core_fread(chd->file, dest, chd->header.hunkbytes);
2169 /* TODO
ce188d4d 2170 else if (m_parent_missing)
9c659ffe 2171 throw CHDERR_REQUIRES_PARENT; */
2172 } else if (chd->parent) {
2173 err = hunk_read_into_memory(chd->parent, hunknum, dest);
2174 if (err != CHDERR_NONE)
2175 return err;
2176 } else {
2177 memset(dest, 0, chd->header.hunkbytes);
2178 }
2179 }
ce188d4d 2180
9c659ffe 2181 /* compressed case */
ce188d4d 2182 blocklen = get_bigendian_uint24(&rawmap[1]);
2183 blockoffs = get_bigendian_uint48(&rawmap[4]);
2184 blockcrc = get_bigendian_uint16(&rawmap[10]);
9c659ffe 2185 void* codec = NULL;
ce188d4d 2186 switch (rawmap[0])
2187 {
2188 case COMPRESSION_TYPE_0:
2189 case COMPRESSION_TYPE_1:
2190 case COMPRESSION_TYPE_2:
2191 case COMPRESSION_TYPE_3:
9c659ffe 2192 compressed_bytes = hunk_read_compressed(chd, blockoffs, blocklen);
2193 if (compressed_bytes == NULL)
ce188d4d 2194 return CHDERR_READ_ERROR;
2195 switch (chd->codecintf[rawmap[0]]->compression)
2196 {
2197 case CHD_CODEC_CD_LZMA:
2198 codec = &chd->cdlz_codec_data;
2199 break;
2200
9c659ffe 2201 case CHD_CODEC_ZLIB:
2202 codec = &chd->zlib_codec_data;
2203 break;
2204
ce188d4d 2205 case CHD_CODEC_CD_ZLIB:
2206 codec = &chd->cdzl_codec_data;
2207 break;
2208
2209 case CHD_CODEC_CD_FLAC:
2210 codec = &chd->cdfl_codec_data;
2211 break;
2212 }
2213 if (codec==NULL)
2214 return CHDERR_DECOMPRESSION_ERROR;
9c659ffe 2215 chd->codecintf[rawmap[0]]->decompress(codec, compressed_bytes, blocklen, dest, chd->header.hunkbytes);
ce188d4d 2216 if (dest != NULL && crc16(dest, chd->header.hunkbytes) != blockcrc)
2217 return CHDERR_DECOMPRESSION_ERROR;
2218 return CHDERR_NONE;
2219
2220 case COMPRESSION_NONE:
9c659ffe 2221 err = hunk_read_uncompressed(chd, blockoffs, blocklen, dest);
ce188d4d 2222 if (err != CHDERR_NONE)
2223 return err;
2224 if (crc16(dest, chd->header.hunkbytes) != blockcrc)
2225 return CHDERR_DECOMPRESSION_ERROR;
2226 return CHDERR_NONE;
2227
2228 case COMPRESSION_SELF:
2229 return hunk_read_into_memory(chd, blockoffs, dest);
2230
2231 case COMPRESSION_PARENT:
9c659ffe 2232#if 0
2233 /* TODO */
2234 if (m_parent_missing)
2235 return CHDERR_REQUIRES_PARENT;
2236 return m_parent->read_bytes(uint64_t(blockoffs) * uint64_t(m_parent->unit_bytes()), dest, m_hunkbytes);
2237#endif
ce188d4d 2238 return CHDERR_DECOMPRESSION_ERROR;
2239 }
2240 return CHDERR_NONE;
2241 }
2242
9c659ffe 2243 /* We should not reach this code */
ce188d4d 2244 return CHDERR_DECOMPRESSION_ERROR;
2245}
2246
ce188d4d 2247/***************************************************************************
2248 INTERNAL MAP ACCESS
2249***************************************************************************/
2250
2251/*-------------------------------------------------
2252 map_read - read the initial sector map
2253-------------------------------------------------*/
2254
2255static chd_error map_read(chd_file *chd)
2256{
2257 UINT32 entrysize = (chd->header.version < 3) ? OLD_MAP_ENTRY_SIZE : MAP_ENTRY_SIZE;
2258 UINT8 raw_map_entries[MAP_STACK_ENTRIES * MAP_ENTRY_SIZE];
2259 UINT64 fileoffset, maxoffset = 0;
2260 UINT8 cookie[MAP_ENTRY_SIZE];
2261 UINT32 count;
2262 chd_error err;
2263 int i;
2264
2265 /* first allocate memory */
2266 chd->map = (map_entry *)malloc(sizeof(chd->map[0]) * chd->header.totalhunks);
2267 if (!chd->map)
2268 return CHDERR_OUT_OF_MEMORY;
2269
2270 /* read the map entries in in chunks and extract to the map list */
2271 fileoffset = chd->header.length;
2272 for (i = 0; i < chd->header.totalhunks; i += MAP_STACK_ENTRIES)
2273 {
2274 /* compute how many entries this time */
2275 int entries = chd->header.totalhunks - i, j;
2276 if (entries > MAP_STACK_ENTRIES)
2277 entries = MAP_STACK_ENTRIES;
2278
2279 /* read that many */
2280 core_fseek(chd->file, fileoffset, SEEK_SET);
2281 count = core_fread(chd->file, raw_map_entries, entries * entrysize);
2282 if (count != entries * entrysize)
2283 {
2284 err = CHDERR_READ_ERROR;
2285 goto cleanup;
2286 }
2287 fileoffset += entries * entrysize;
2288
2289 /* process that many */
2290 if (entrysize == MAP_ENTRY_SIZE)
2291 {
2292 for (j = 0; j < entries; j++)
2293 map_extract(&raw_map_entries[j * MAP_ENTRY_SIZE], &chd->map[i + j]);
2294 }
2295 else
2296 {
2297 for (j = 0; j < entries; j++)
2298 map_extract_old(&raw_map_entries[j * OLD_MAP_ENTRY_SIZE], &chd->map[i + j], chd->header.hunkbytes);
2299 }
2300
2301 /* track the maximum offset */
2302 for (j = 0; j < entries; j++)
2303 if ((chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == V34_MAP_ENTRY_TYPE_COMPRESSED ||
2304 (chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == V34_MAP_ENTRY_TYPE_UNCOMPRESSED)
2305 maxoffset = MAX(maxoffset, chd->map[i + j].offset + chd->map[i + j].length);
2306 }
2307
2308 /* verify the cookie */
2309 core_fseek(chd->file, fileoffset, SEEK_SET);
2310 count = core_fread(chd->file, &cookie, entrysize);
2311 if (count != entrysize || memcmp(&cookie, END_OF_LIST_COOKIE, entrysize))
2312 {
2313 err = CHDERR_INVALID_FILE;
2314 goto cleanup;
2315 }
2316
2317 /* verify the length */
2318 if (maxoffset > core_fsize(chd->file))
2319 {
2320 err = CHDERR_INVALID_FILE;
2321 goto cleanup;
2322 }
2323 return CHDERR_NONE;
2324
2325cleanup:
2326 if (chd->map)
2327 free(chd->map);
2328 chd->map = NULL;
2329 return err;
2330}
2331
ce188d4d 2332/***************************************************************************
2333 INTERNAL METADATA ACCESS
2334***************************************************************************/
2335
2336/*-------------------------------------------------
2337 metadata_find_entry - find a metadata entry
2338-------------------------------------------------*/
2339
2340static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry)
2341{
2342 /* start at the beginning */
2343 metaentry->offset = chd->header.metaoffset;
2344 metaentry->prev = 0;
2345
2346 /* loop until we run out of options */
2347 while (metaentry->offset != 0)
2348 {
2349 UINT8 raw_meta_header[METADATA_HEADER_SIZE];
2350 UINT32 count;
2351
2352 /* read the raw header */
2353 core_fseek(chd->file, metaentry->offset, SEEK_SET);
2354 count = core_fread(chd->file, raw_meta_header, sizeof(raw_meta_header));
2355 if (count != sizeof(raw_meta_header))
2356 break;
2357
2358 /* extract the data */
2359 metaentry->metatag = get_bigendian_uint32(&raw_meta_header[0]);
2360 metaentry->length = get_bigendian_uint32(&raw_meta_header[4]);
2361 metaentry->next = get_bigendian_uint64(&raw_meta_header[8]);
2362
2363 /* flags are encoded in the high byte of length */
2364 metaentry->flags = metaentry->length >> 24;
2365 metaentry->length &= 0x00ffffff;
2366
2367 /* if we got a match, proceed */
2368 if (metatag == CHDMETATAG_WILDCARD || metaentry->metatag == metatag)
2369 if (metaindex-- == 0)
2370 return CHDERR_NONE;
2371
2372 /* no match, fetch the next link */
2373 metaentry->prev = metaentry->offset;
2374 metaentry->offset = metaentry->next;
2375 }
2376
2377 /* if we get here, we didn't find it */
2378 return CHDERR_METADATA_NOT_FOUND;
2379}
2380
ce188d4d 2381/***************************************************************************
2382 ZLIB COMPRESSION CODEC
2383***************************************************************************/
2384
2385/*-------------------------------------------------
2386 zlib_codec_init - initialize the ZLIB codec
2387-------------------------------------------------*/
2388
2389static chd_error zlib_codec_init(void *codec, uint32_t hunkbytes)
2390{
2391 zlib_codec_data *data = (zlib_codec_data*)codec;
2392 chd_error err;
2393 int zerr;
2394
2395 /* clear the buffers */
2396 memset(data, 0, sizeof(zlib_codec_data));
2397
2398 /* init the inflater first */
2399 data->inflater.next_in = (Bytef *)data; /* bogus, but that's ok */
2400 data->inflater.avail_in = 0;
2401 data->inflater.zalloc = zlib_fast_alloc;
2402 data->inflater.zfree = zlib_fast_free;
2403 data->inflater.opaque = &data->allocator;
2404 zerr = inflateInit2(&data->inflater, -MAX_WBITS);
2405
2406 /* convert errors */
2407 if (zerr == Z_MEM_ERROR)
2408 err = CHDERR_OUT_OF_MEMORY;
2409 else if (zerr != Z_OK)
2410 err = CHDERR_CODEC_ERROR;
2411 else
2412 err = CHDERR_NONE;
2413
2414 /* handle an error */
2415 if (err != CHDERR_NONE)
2416 free(data);
2417
2418 return err;
2419}
2420
ce188d4d 2421/*-------------------------------------------------
2422 zlib_codec_free - free data for the ZLIB
2423 codec
2424-------------------------------------------------*/
2425
2426static void zlib_codec_free(void *codec)
2427{
2428 zlib_codec_data *data = (zlib_codec_data *)codec;
2429
2430 /* deinit the streams */
2431 if (data != NULL)
2432 {
2433 int i;
ce188d4d 2434
2435 inflateEnd(&data->inflater);
2436
2437 /* free our fast memory */
9c659ffe 2438 zlib_allocator alloc = data->allocator;
ce188d4d 2439 for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
2440 if (alloc.allocptr[i])
2441 free(alloc.allocptr[i]);
2442 }
2443}
2444
ce188d4d 2445/*-------------------------------------------------
2446 zlib_codec_decompress - decomrpess data using
2447 the ZLIB codec
2448-------------------------------------------------*/
2449
2450static chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
2451{
2452 zlib_codec_data *data = (zlib_codec_data *)codec;
2453 int zerr;
2454
2455 /* reset the decompressor */
2456 data->inflater.next_in = (Bytef *)src;
2457 data->inflater.avail_in = complen;
2458 data->inflater.total_in = 0;
2459 data->inflater.next_out = (Bytef *)dest;
2460 data->inflater.avail_out = destlen;
2461 data->inflater.total_out = 0;
2462 zerr = inflateReset(&data->inflater);
2463 if (zerr != Z_OK)
2464 return CHDERR_DECOMPRESSION_ERROR;
2465
2466 /* do it */
2467 zerr = inflate(&data->inflater, Z_FINISH);
2468 if (data->inflater.total_out != destlen)
2469 return CHDERR_DECOMPRESSION_ERROR;
2470
2471 return CHDERR_NONE;
2472}
2473
ce188d4d 2474/*-------------------------------------------------
2475 zlib_fast_alloc - fast malloc for ZLIB, which
2476 allocates and frees memory frequently
2477-------------------------------------------------*/
2478
2479static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
2480{
2481 zlib_allocator *alloc = (zlib_allocator *)opaque;
2482 UINT32 *ptr;
2483 int i;
2484
2485 /* compute the size, rounding to the nearest 1k */
2486 size = (size * items + 0x3ff) & ~0x3ff;
2487
2488 /* reuse a hunk if we can */
2489 for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
2490 {
2491 ptr = alloc->allocptr[i];
2492 if (ptr && size == *ptr)
2493 {
2494 /* set the low bit of the size so we don't match next time */
2495 *ptr |= 1;
2496 return ptr + 1;
2497 }
2498 }
2499
2500 /* alloc a new one */
9c659ffe 2501 ptr = (UINT32 *)malloc(size + sizeof(uintptr_t));
ce188d4d 2502 if (!ptr)
2503 return NULL;
2504
2505 /* put it into the list */
2506 for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
2507 if (!alloc->allocptr[i])
2508 {
2509 alloc->allocptr[i] = ptr;
2510 break;
2511 }
2512
2513 /* set the low bit of the size so we don't match next time */
2514 *ptr = size | 1;
9c659ffe 2515 return ptr + (sizeof(uint32_t) == sizeof(uintptr_t) ? 1 : 2);
ce188d4d 2516}
2517
ce188d4d 2518/*-------------------------------------------------
2519 zlib_fast_free - fast free for ZLIB, which
2520 allocates and frees memory frequently
2521-------------------------------------------------*/
2522
2523static void zlib_fast_free(voidpf opaque, voidpf address)
2524{
2525 zlib_allocator *alloc = (zlib_allocator *)opaque;
9c659ffe 2526 UINT32 *ptr = (UINT32 *)address - (sizeof(uint32_t) == sizeof(uintptr_t) ? 1 : 2);
ce188d4d 2527 int i;
2528
2529 /* find the hunk */
2530 for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
2531 if (ptr == alloc->allocptr[i])
2532 {
2533 /* clear the low bit of the size to allow matches */
2534 *ptr &= ~1;
2535 return;
2536 }
2537}