git subrepo pull (merge) --force deps/libchdr
[pcsx_rearmed.git] / deps / libchdr / src / libchdr_chd.c
CommitLineData
b24e7fce 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 <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <time.h>
45
46#include <libchdr/chd.h>
47#include <libchdr/cdrom.h>
48#include <libchdr/flac.h>
49#include <libchdr/huffman.h>
648db22b 50#include <zstd.h>
b24e7fce 51
52#include "LzmaEnc.h"
53#include "LzmaDec.h"
9e052883 54#if defined(__PS3__) || defined(__PSL1GHT__)
55#define __MACTYPES__
56#endif
648db22b 57#include <zlib.h>
b24e7fce 58
59#undef TRUE
60#undef FALSE
61#define TRUE 1
62#define FALSE 0
63
64#undef MAX
65#undef MIN
66#define MAX(x, y) (((x) > (y)) ? (x) : (y))
67#define MIN(x, y) (((x) < (y)) ? (x) : (y))
68
69#define SHA1_DIGEST_SIZE 20
70
71/***************************************************************************
72 DEBUGGING
73***************************************************************************/
74
75#define PRINTF_MAX_HUNK (0)
76
77/***************************************************************************
78 CONSTANTS
79***************************************************************************/
80
81#define MAP_STACK_ENTRIES 512 /* max number of entries to use on the stack */
82#define MAP_ENTRY_SIZE 16 /* V3 and later */
83#define OLD_MAP_ENTRY_SIZE 8 /* V1-V2 */
84#define METADATA_HEADER_SIZE 16 /* metadata header size */
85
86#define MAP_ENTRY_FLAG_TYPE_MASK 0x0f /* what type of hunk */
87#define MAP_ENTRY_FLAG_NO_CRC 0x10 /* no CRC is present */
88
89#define CHD_V1_SECTOR_SIZE 512 /* size of a "sector" in the V1 header */
90
91#define COOKIE_VALUE 0xbaadf00d
92#define MAX_ZLIB_ALLOCS 64
93
94#define END_OF_LIST_COOKIE "EndOfListCookie"
95
96#define NO_MATCH (~0)
97
98#ifdef WANT_RAW_DATA_SECTOR
99static const uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 };
100#endif
101
102/* V3-V4 entry types */
103enum
104{
105 V34_MAP_ENTRY_TYPE_INVALID = 0, /* invalid type */
106 V34_MAP_ENTRY_TYPE_COMPRESSED = 1, /* standard compression */
107 V34_MAP_ENTRY_TYPE_UNCOMPRESSED = 2, /* uncompressed data */
108 V34_MAP_ENTRY_TYPE_MINI = 3, /* mini: use offset as raw data */
109 V34_MAP_ENTRY_TYPE_SELF_HUNK = 4, /* same as another hunk in this file */
110 V34_MAP_ENTRY_TYPE_PARENT_HUNK = 5, /* same as a hunk in the parent file */
111 V34_MAP_ENTRY_TYPE_2ND_COMPRESSED = 6 /* compressed with secondary algorithm (usually FLAC CDDA) */
112};
113
114/* V5 compression types */
115enum
116{
117 /* codec #0
118 * these types are live when running */
119 COMPRESSION_TYPE_0 = 0,
120 /* codec #1 */
121 COMPRESSION_TYPE_1 = 1,
122 /* codec #2 */
123 COMPRESSION_TYPE_2 = 2,
124 /* codec #3 */
125 COMPRESSION_TYPE_3 = 3,
126 /* no compression; implicit length = hunkbytes */
127 COMPRESSION_NONE = 4,
128 /* same as another block in this chd */
129 COMPRESSION_SELF = 5,
130 /* same as a hunk's worth of units in the parent chd */
131 COMPRESSION_PARENT = 6,
132
133 /* start of small RLE run (4-bit length)
134 * these additional pseudo-types are used for compressed encodings: */
135 COMPRESSION_RLE_SMALL,
136 /* start of large RLE run (8-bit length) */
137 COMPRESSION_RLE_LARGE,
138 /* same as the last COMPRESSION_SELF block */
139 COMPRESSION_SELF_0,
140 /* same as the last COMPRESSION_SELF block + 1 */
141 COMPRESSION_SELF_1,
142 /* same block in the parent */
143 COMPRESSION_PARENT_SELF,
144 /* same as the last COMPRESSION_PARENT block */
145 COMPRESSION_PARENT_0,
146 /* same as the last COMPRESSION_PARENT block + 1 */
147 COMPRESSION_PARENT_1
148};
149
150/***************************************************************************
151 MACROS
152***************************************************************************/
153
154#define EARLY_EXIT(x) do { (void)(x); goto cleanup; } while (0)
155
156/***************************************************************************
157 TYPE DEFINITIONS
158***************************************************************************/
159
160/* interface to a codec */
161typedef struct _codec_interface codec_interface;
162struct _codec_interface
163{
164 UINT32 compression; /* type of compression */
165 const char *compname; /* name of the algorithm */
166 UINT8 lossy; /* is this a lossy algorithm? */
167 chd_error (*init)(void *codec, UINT32 hunkbytes); /* codec initialize */
168 void (*free)(void *codec); /* codec free */
169 chd_error (*decompress)(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); /* decompress data */
170 chd_error (*config)(void *codec, int param, void *config); /* configure */
171};
172
173/* a single map entry */
174typedef struct _map_entry map_entry;
175struct _map_entry
176{
177 UINT64 offset; /* offset within the file of the data */
178 UINT32 crc; /* 32-bit CRC of the data */
179 UINT32 length; /* length of the data */
180 UINT8 flags; /* misc flags */
181};
182
183/* a single metadata entry */
184typedef struct _metadata_entry metadata_entry;
185struct _metadata_entry
186{
187 UINT64 offset; /* offset within the file of the header */
188 UINT64 next; /* offset within the file of the next header */
189 UINT64 prev; /* offset within the file of the previous header */
190 UINT32 length; /* length of the metadata */
191 UINT32 metatag; /* metadata tag */
192 UINT8 flags; /* flag bits */
193};
194
195/* codec-private data for the ZLIB codec */
196
197typedef struct _zlib_allocator zlib_allocator;
198struct _zlib_allocator
199{
200 UINT32 * allocptr[MAX_ZLIB_ALLOCS];
201 UINT32 * allocptr2[MAX_ZLIB_ALLOCS];
202};
203
204typedef struct _zlib_codec_data zlib_codec_data;
205struct _zlib_codec_data
206{
207 z_stream inflater;
208 zlib_allocator allocator;
209};
210
211/* codec-private data for the LZMA codec */
212#define MAX_LZMA_ALLOCS 64
213
214typedef struct _lzma_allocator lzma_allocator;
215struct _lzma_allocator
216{
217 void *(*Alloc)(void *p, size_t size);
218 void (*Free)(void *p, void *address); /* address can be 0 */
219 void (*FreeSz)(void *p, void *address, size_t size); /* address can be 0 */
220 uint32_t* allocptr[MAX_LZMA_ALLOCS];
221 uint32_t* allocptr2[MAX_LZMA_ALLOCS];
222};
223
224typedef struct _lzma_codec_data lzma_codec_data;
225struct _lzma_codec_data
226{
227 CLzmaDec decoder;
228 lzma_allocator allocator;
229};
230
9e052883 231typedef struct _huff_codec_data huff_codec_data;
232struct _huff_codec_data
233{
234 struct huffman_decoder* decoder;
235};
236
648db22b 237typedef struct _zstd_codec_data zstd_codec_data;
238struct _zstd_codec_data
239{
240 ZSTD_DStream *dstream;
241};
242
b24e7fce 243/* codec-private data for the CDZL codec */
244typedef struct _cdzl_codec_data cdzl_codec_data;
245struct _cdzl_codec_data {
246 /* internal state */
247 zlib_codec_data base_decompressor;
248#ifdef WANT_SUBCODE
249 zlib_codec_data subcode_decompressor;
250#endif
251 uint8_t* buffer;
252};
253
254/* codec-private data for the CDLZ codec */
255typedef struct _cdlz_codec_data cdlz_codec_data;
256struct _cdlz_codec_data {
257 /* internal state */
258 lzma_codec_data base_decompressor;
259#ifdef WANT_SUBCODE
260 zlib_codec_data subcode_decompressor;
261#endif
262 uint8_t* buffer;
263};
264
9e052883 265/* codec-private data for the FLAC codec */
266typedef struct _flac_codec_data flac_codec_data;
267struct _flac_codec_data {
268 /* internal state */
269 int native_endian;
270 flac_decoder decoder;
271};
272
b24e7fce 273/* codec-private data for the CDFL codec */
274typedef struct _cdfl_codec_data cdfl_codec_data;
275struct _cdfl_codec_data {
276 /* internal state */
277 int swap_endian;
278 flac_decoder decoder;
279#ifdef WANT_SUBCODE
280 zlib_codec_data subcode_decompressor;
281#endif
282 uint8_t* buffer;
283};
284
648db22b 285typedef struct _cdzs_codec_data cdzs_codec_data;
286struct _cdzs_codec_data
287{
288 zstd_codec_data base_decompressor;
289#ifdef WANT_SUBCODE
290 zstd_codec_data subcode_decompressor;
291#endif
292 uint8_t* buffer;
293};
294
b24e7fce 295/* internal representation of an open CHD file */
296struct _chd_file
297{
298 UINT32 cookie; /* cookie, should equal COOKIE_VALUE */
299
300 core_file * file; /* handle to the open core file */
b24e7fce 301 chd_header header; /* header, extracted from file */
302
303 chd_file * parent; /* pointer to parent file, or NULL */
304
305 map_entry * map; /* array of map entries */
306
307#ifdef NEED_CACHE_HUNK
308 UINT8 * cache; /* hunk cache pointer */
309 UINT32 cachehunk; /* index of currently cached hunk */
310
311 UINT8 * compare; /* hunk compare pointer */
312 UINT32 comparehunk; /* index of current compare data */
313#endif
314
315 UINT8 * compressed; /* pointer to buffer for compressed data */
316 const codec_interface * codecintf[4]; /* interface to the codec */
317
318 zlib_codec_data zlib_codec_data; /* zlib codec data */
9e052883 319 lzma_codec_data lzma_codec_data; /* lzma codec data */
320 huff_codec_data huff_codec_data; /* huff codec data */
321 flac_codec_data flac_codec_data; /* flac codec data */
648db22b 322 zstd_codec_data zstd_codec_data; /* zstd codec data */
b24e7fce 323 cdzl_codec_data cdzl_codec_data; /* cdzl codec data */
324 cdlz_codec_data cdlz_codec_data; /* cdlz codec data */
325 cdfl_codec_data cdfl_codec_data; /* cdfl codec data */
648db22b 326 cdzs_codec_data cdzs_codec_data; /* cdzs codec data */
b24e7fce 327
328#ifdef NEED_CACHE_HUNK
329 UINT32 maxhunk; /* maximum hunk accessed */
330#endif
331
332 UINT8 * file_cache; /* cache of underlying file */
333};
334
335
336/***************************************************************************
337 GLOBAL VARIABLES
338***************************************************************************/
339
340static const UINT8 nullmd5[CHD_MD5_BYTES] = { 0 };
341static const UINT8 nullsha1[CHD_SHA1_BYTES] = { 0 };
342
343/***************************************************************************
344 PROTOTYPES
345***************************************************************************/
346
9e052883 347/* core_file wrappers over stdio */
348static core_file *core_stdio_fopen(char const *path);
349static UINT64 core_stdio_fsize(core_file *file);
350static size_t core_stdio_fread(void *ptr, size_t size, size_t nmemb, core_file *file);
351static int core_stdio_fclose(core_file *file);
352static int core_stdio_fclose_nonowner(core_file *file); // alternate fclose used by chd_open_file
353static int core_stdio_fseek(core_file* file, INT64 offset, int whence);
354
b24e7fce 355/* internal header operations */
356static chd_error header_validate(const chd_header *header);
357static chd_error header_read(chd_file *chd, chd_header *header);
358
359/* internal hunk read/write */
360#ifdef NEED_CACHE_HUNK
361static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum);
362#endif
363static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest);
364
365/* internal map access */
366static chd_error map_read(chd_file *chd);
367
368/* metadata management */
369static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry);
370
371/* zlib compression codec */
372static chd_error zlib_codec_init(void *codec, uint32_t hunkbytes);
373static void zlib_codec_free(void *codec);
374static chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
375static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size);
376static void zlib_fast_free(voidpf opaque, voidpf address);
377static void zlib_allocator_free(voidpf opaque);
378
379/* lzma compression codec */
380static chd_error lzma_codec_init(void *codec, uint32_t hunkbytes);
381static void lzma_codec_free(void *codec);
382static chd_error lzma_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
383
9e052883 384/* huff compression codec */
385static chd_error huff_codec_init(void *codec, uint32_t hunkbytes);
386static void huff_codec_free(void *codec);
387static chd_error huff_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
388
389/* flac compression codec */
390static chd_error flac_codec_init(void *codec, uint32_t hunkbytes);
391static void flac_codec_free(void *codec);
392static chd_error flac_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
393
648db22b 394/* zstd compression codec */
395static chd_error zstd_codec_init(void *codec, uint32_t hunkbytes);
396static void zstd_codec_free(void *codec);
397static chd_error zstd_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
398
399
b24e7fce 400/* cdzl compression codec */
401static chd_error cdzl_codec_init(void* codec, uint32_t hunkbytes);
402static void cdzl_codec_free(void* codec);
403static chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
404
405/* cdlz compression codec */
406static chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes);
407static void cdlz_codec_free(void* codec);
408static chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
409
410/* cdfl compression codec */
411static chd_error cdfl_codec_init(void* codec, uint32_t hunkbytes);
412static void cdfl_codec_free(void* codec);
413static chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
414
648db22b 415/* cdzs compression codec */
416static chd_error cdzs_codec_init(void *codec, uint32_t hunkbytes);
417static void cdzs_codec_free(void *codec);
418static chd_error cdzs_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
419
b24e7fce 420/***************************************************************************
421 * LZMA ALLOCATOR HELPER
422 ***************************************************************************
423 */
424
425static void *lzma_fast_alloc(void *p, size_t size);
426static void lzma_fast_free(void *p, void *address);
427
428/*-------------------------------------------------
429 * lzma_allocator_init
430 *-------------------------------------------------
431 */
432
433static void lzma_allocator_init(void* p)
434{
435 lzma_allocator *codec = (lzma_allocator *)(p);
436
437 /* reset pointer list */
438 memset(codec->allocptr, 0, sizeof(codec->allocptr));
439 memset(codec->allocptr2, 0, sizeof(codec->allocptr2));
440 codec->Alloc = lzma_fast_alloc;
441 codec->Free = lzma_fast_free;
442}
443
444/*-------------------------------------------------
445 * lzma_allocator_free
446 *-------------------------------------------------
447 */
448
449static void lzma_allocator_free(void* p )
450{
451 int i;
452 lzma_allocator *codec = (lzma_allocator *)(p);
453
454 /* free our memory */
455 for (i = 0 ; i < MAX_LZMA_ALLOCS ; i++)
456 {
457 if (codec->allocptr[i] != NULL)
458 free(codec->allocptr[i]);
459 }
460}
461
462/*-------------------------------------------------
463 * lzma_fast_alloc - fast malloc for lzma, which
464 * allocates and frees memory frequently
465 *-------------------------------------------------
466 */
467
468/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */
469#define LZMA_MIN_ALIGNMENT_BITS 512
470#define LZMA_MIN_ALIGNMENT_BYTES (LZMA_MIN_ALIGNMENT_BITS / 8)
471
472static void *lzma_fast_alloc(void *p, size_t size)
473{
474 int scan;
475 uint32_t *addr = NULL;
476 lzma_allocator *codec = (lzma_allocator *)(p);
477 uintptr_t vaddr = 0;
478
479 /* compute the size, rounding to the nearest 1k */
480 size = (size + 0x3ff) & ~0x3ff;
481
482 /* reuse a hunk if we can */
483 for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
484 {
485 uint32_t *ptr = codec->allocptr[scan];
486 if (ptr != NULL && size == *ptr)
487 {
488 /* set the low bit of the size so we don't match next time */
489 *ptr |= 1;
490
491 /* return aligned address of the block */
492 return codec->allocptr2[scan];
493 }
494 }
495
496 /* alloc a new one and put it into the list */
497 addr = (uint32_t *)malloc(size + sizeof(uint32_t) + LZMA_MIN_ALIGNMENT_BYTES);
498 if (addr==NULL)
499 return NULL;
500 for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
501 {
502 if (codec->allocptr[scan] == NULL)
503 {
504 /* store block address */
505 codec->allocptr[scan] = addr;
506
507 /* compute aligned address, store it */
508 vaddr = (uintptr_t)addr;
509 vaddr = (vaddr + sizeof(uint32_t) + (LZMA_MIN_ALIGNMENT_BYTES-1)) & (~(LZMA_MIN_ALIGNMENT_BYTES-1));
510 codec->allocptr2[scan] = (uint32_t*)vaddr;
511 break;
512 }
513 }
514
515 /* set the low bit of the size so we don't match next time */
516 *addr = size | 1;
517
518 /* return aligned address */
519 return (void*)vaddr;
520}
521
522/*-------------------------------------------------
523 * lzma_fast_free - fast free for lzma, which
524 * allocates and frees memory frequently
525 *-------------------------------------------------
526 */
527
528static void lzma_fast_free(void *p, void *address)
529{
530 int scan;
531 uint32_t *ptr = NULL;
532 lzma_allocator *codec = NULL;
533
534 if (address == NULL)
535 return;
536
537 codec = (lzma_allocator *)(p);
538
539 /* find the hunk */
540 ptr = (uint32_t *)address;
541 for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
542 {
543 if (ptr == codec->allocptr2[scan])
544 {
545 /* clear the low bit of the size to allow matches */
546 *codec->allocptr[scan] &= ~1;
547 return;
548 }
549 }
550}
551
552/***************************************************************************
553 * LZMA DECOMPRESSOR
554 ***************************************************************************
555 */
556
557/*-------------------------------------------------
558 * lzma_codec_init - constructor
559 *-------------------------------------------------
560 */
561
562static chd_error lzma_codec_init(void* codec, uint32_t hunkbytes)
563{
564 CLzmaEncHandle enc;
565 CLzmaEncProps encoder_props;
566 Byte decoder_props[LZMA_PROPS_SIZE];
567 SizeT props_size;
568 lzma_allocator* alloc;
569 lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;
570
571 /* construct the decoder */
572 LzmaDec_Construct(&lzma_codec->decoder);
573
574 /* FIXME: this code is written in a way that makes it impossible to safely upgrade the LZMA SDK
575 * This code assumes that the current version of the encoder imposes the same requirements on the
576 * decoder as the encoder used to produce the file. This is not necessarily true. The format
577 * needs to be changed so the encoder properties are written to the file.
578
579 * configure the properties like the compressor did */
580 LzmaEncProps_Init(&encoder_props);
581 encoder_props.level = 9;
582 encoder_props.reduceSize = hunkbytes;
583 LzmaEncProps_Normalize(&encoder_props);
584
585 /* convert to decoder properties */
586 alloc = &lzma_codec->allocator;
587 lzma_allocator_init(alloc);
588 enc = LzmaEnc_Create((ISzAlloc*)alloc);
589 if (!enc)
590 return CHDERR_DECOMPRESSION_ERROR;
591 if (LzmaEnc_SetProps(enc, &encoder_props) != SZ_OK)
592 {
593 LzmaEnc_Destroy(enc, (ISzAlloc*)&alloc, (ISzAlloc*)&alloc);
594 return CHDERR_DECOMPRESSION_ERROR;
595 }
596 props_size = sizeof(decoder_props);
597 if (LzmaEnc_WriteProperties(enc, decoder_props, &props_size) != SZ_OK)
598 {
599 LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc);
600 return CHDERR_DECOMPRESSION_ERROR;
601 }
602 LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc);
603
604 /* do memory allocations */
605 if (LzmaDec_Allocate(&lzma_codec->decoder, decoder_props, LZMA_PROPS_SIZE, (ISzAlloc*)alloc) != SZ_OK)
606 return CHDERR_DECOMPRESSION_ERROR;
607
608 /* Okay */
609 return CHDERR_NONE;
610}
611
612/*-------------------------------------------------
613 * lzma_codec_free
614 *-------------------------------------------------
615 */
616
617static void lzma_codec_free(void* codec)
618{
619 lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;
620
621 /* free memory */
622 LzmaDec_Free(&lzma_codec->decoder, (ISzAlloc*)&lzma_codec->allocator);
623 lzma_allocator_free(&lzma_codec->allocator);
624}
625
626/*-------------------------------------------------
627 * decompress - decompress data using the LZMA
628 * codec
629 *-------------------------------------------------
630 */
631
632static chd_error lzma_codec_decompress(void* codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
633{
634 ELzmaStatus status;
635 SRes res;
636 SizeT consumedlen, decodedlen;
637 /* initialize */
638 lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;
639 LzmaDec_Init(&lzma_codec->decoder);
640
641 /* decode */
642 consumedlen = complen;
643 decodedlen = destlen;
644 res = LzmaDec_DecodeToBuf(&lzma_codec->decoder, dest, &decodedlen, src, &consumedlen, LZMA_FINISH_END, &status);
645 if ((res != SZ_OK && res != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) || consumedlen != complen || decodedlen != destlen)
646 return CHDERR_DECOMPRESSION_ERROR;
647 return CHDERR_NONE;
648}
649
650/* cdlz */
651static chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes)
652{
653 chd_error ret;
654 cdlz_codec_data* cdlz = (cdlz_codec_data*) codec;
655
656 /* allocate buffer */
657 cdlz->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
658 if (cdlz->buffer == NULL)
659 return CHDERR_OUT_OF_MEMORY;
660
661 /* make sure the CHD's hunk size is an even multiple of the frame size */
662 ret = lzma_codec_init(&cdlz->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
663 if (ret != CHDERR_NONE)
664 return ret;
665
666#ifdef WANT_SUBCODE
667 ret = zlib_codec_init(&cdlz->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA);
668 if (ret != CHDERR_NONE)
669 return ret;
670#endif
671
672 if (hunkbytes % CD_FRAME_SIZE != 0)
673 return CHDERR_CODEC_ERROR;
674
675 return CHDERR_NONE;
676}
677
678static void cdlz_codec_free(void* codec)
679{
680 cdlz_codec_data* cdlz = (cdlz_codec_data*) codec;
681 free(cdlz->buffer);
682 lzma_codec_free(&cdlz->base_decompressor);
683#ifdef WANT_SUBCODE
684 zlib_codec_free(&cdlz->subcode_decompressor);
685#endif
686}
687
688static chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
689{
690 uint32_t framenum;
691 cdlz_codec_data* cdlz = (cdlz_codec_data*)codec;
692
693 /* determine header bytes */
694 uint32_t frames = destlen / CD_FRAME_SIZE;
695 uint32_t complen_bytes = (destlen < 65536) ? 2 : 3;
696 uint32_t ecc_bytes = (frames + 7) / 8;
697 uint32_t header_bytes = ecc_bytes + complen_bytes;
698
699 /* extract compressed length of base */
700 uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1];
701 if (complen_bytes > 2)
702 complen_base = (complen_base << 8) | src[ecc_bytes + 2];
703
704 /* reset and decode */
705 lzma_codec_decompress(&cdlz->base_decompressor, &src[header_bytes], complen_base, &cdlz->buffer[0], frames * CD_MAX_SECTOR_DATA);
706#ifdef WANT_SUBCODE
707 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);
708#endif
709
710 /* reassemble the data */
711 for (framenum = 0; framenum < frames; framenum++)
712 {
713 uint8_t *sector;
714
715 memcpy(&dest[framenum * CD_FRAME_SIZE], &cdlz->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
716#ifdef WANT_SUBCODE
717 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);
718#endif
719
720#ifdef WANT_RAW_DATA_SECTOR
721 /* reconstitute the ECC data and sync header */
722 sector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE];
723 if ((src[framenum / 8] & (1 << (framenum % 8))) != 0)
724 {
725 memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header));
726 ecc_generate(sector);
727 }
728#endif
729 }
730 return CHDERR_NONE;
731}
732
733/* cdzl */
734
735static chd_error cdzl_codec_init(void *codec, uint32_t hunkbytes)
736{
737 chd_error ret;
738 cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;
739
740 /* make sure the CHD's hunk size is an even multiple of the frame size */
741 if (hunkbytes % CD_FRAME_SIZE != 0)
742 return CHDERR_CODEC_ERROR;
743
744 cdzl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
745 if (cdzl->buffer == NULL)
746 return CHDERR_OUT_OF_MEMORY;
747
748 ret = zlib_codec_init(&cdzl->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
749 if (ret != CHDERR_NONE)
750 return ret;
751
752#ifdef WANT_SUBCODE
753 ret = zlib_codec_init(&cdzl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA);
754 if (ret != CHDERR_NONE)
755 return ret;
756#endif
757
758 return CHDERR_NONE;
759}
760
761static void cdzl_codec_free(void *codec)
762{
763 cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;
764 zlib_codec_free(&cdzl->base_decompressor);
765#ifdef WANT_SUBCODE
766 zlib_codec_free(&cdzl->subcode_decompressor);
767#endif
768 free(cdzl->buffer);
769}
770
771static chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
772{
773 uint32_t framenum;
774 cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;
775
776 /* determine header bytes */
777 uint32_t frames = destlen / CD_FRAME_SIZE;
778 uint32_t complen_bytes = (destlen < 65536) ? 2 : 3;
779 uint32_t ecc_bytes = (frames + 7) / 8;
780 uint32_t header_bytes = ecc_bytes + complen_bytes;
781
782 /* extract compressed length of base */
783 uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1];
784 if (complen_bytes > 2)
785 complen_base = (complen_base << 8) | src[ecc_bytes + 2];
786
787 /* reset and decode */
788 zlib_codec_decompress(&cdzl->base_decompressor, &src[header_bytes], complen_base, &cdzl->buffer[0], frames * CD_MAX_SECTOR_DATA);
789#ifdef WANT_SUBCODE
790 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);
791#endif
792
793 /* reassemble the data */
794 for (framenum = 0; framenum < frames; framenum++)
795 {
796 uint8_t *sector;
797
798 memcpy(&dest[framenum * CD_FRAME_SIZE], &cdzl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
799#ifdef WANT_SUBCODE
800 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);
801#endif
802
803#ifdef WANT_RAW_DATA_SECTOR
804 /* reconstitute the ECC data and sync header */
805 sector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE];
806 if ((src[framenum / 8] & (1 << (framenum % 8))) != 0)
807 {
808 memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header));
809 ecc_generate(sector);
810 }
811#endif
812 }
813 return CHDERR_NONE;
814}
815
9e052883 816/***************************************************************************
817 * HUFFMAN DECOMPRESSOR
818 ***************************************************************************
819 */
820
821static chd_error huff_codec_init(void* codec, uint32_t hunkbytes)
822{
823 huff_codec_data* huff_codec = (huff_codec_data*) codec;
824 huff_codec->decoder = create_huffman_decoder(256, 16);
825 return CHDERR_NONE;
826}
827
828static void huff_codec_free(void *codec)
829{
830 huff_codec_data* huff_codec = (huff_codec_data*) codec;
831 delete_huffman_decoder(huff_codec->decoder);
832}
833
834static chd_error huff_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
835{
836 huff_codec_data* huff_codec = (huff_codec_data*) codec;
837 struct bitstream* bitbuf = create_bitstream(src, complen);
838
839 // first import the tree
840 enum huffman_error err = huffman_import_tree_huffman(huff_codec->decoder, bitbuf);
841 if (err != HUFFERR_NONE)
842 {
843 free(bitbuf);
648db22b 844 return CHDERR_DECOMPRESSION_ERROR;
9e052883 845 }
846
847 // then decode the data
648db22b 848 uint32_t cur;
849 for (cur = 0; cur < destlen; cur++)
9e052883 850 dest[cur] = huffman_decode_one(huff_codec->decoder, bitbuf);
851 bitstream_flush(bitbuf);
852 chd_error result = bitstream_overflow(bitbuf) ? CHDERR_DECOMPRESSION_ERROR : CHDERR_NONE;
853
854 free(bitbuf);
855 return result;
856}
857
b24e7fce 858/***************************************************************************
859 * CD FLAC DECOMPRESSOR
860 ***************************************************************************
861 */
862
863/*------------------------------------------------------
9e052883 864 * flac_codec_blocksize - return the optimal block size
b24e7fce 865 *------------------------------------------------------
866 */
867
9e052883 868static uint32_t flac_codec_blocksize(uint32_t bytes)
b24e7fce 869{
870 /* determine FLAC block size, which must be 16-65535
871 * clamp to 2k since that's supposed to be the sweet spot */
9e052883 872 uint32_t blocksize = bytes / 4;
873 while (blocksize > 2048)
874 blocksize /= 2;
875 return blocksize;
876}
877
878static chd_error flac_codec_init(void *codec, uint32_t hunkbytes)
879{
880 uint16_t native_endian = 0;
881 flac_codec_data *flac = (flac_codec_data*)codec;
882
883 /* make sure the CHD's hunk size is an even multiple of the sample size */
884 if (hunkbytes % 4 != 0)
885 return CHDERR_CODEC_ERROR;
886
887 /* determine whether we want native or swapped samples */
888 *(uint8_t *)(&native_endian) = 1;
889 flac->native_endian = (native_endian & 1);
890
891 /* flac decoder init */
892 if (flac_decoder_init(&flac->decoder))
893 return CHDERR_OUT_OF_MEMORY;
894
895 return CHDERR_NONE;
896}
897
898static void flac_codec_free(void *codec)
899{
900 flac_codec_data *flac = (flac_codec_data*)codec;
901 flac_decoder_free(&flac->decoder);
902}
903
904static chd_error flac_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
905{
906 flac_codec_data *flac = (flac_codec_data*)codec;
907 int swap_endian;
908
909 if (src[0] == 'L')
910 swap_endian = !flac->native_endian;
911 else if (src[0] == 'B')
912 swap_endian = flac->native_endian;
913 else
914 return CHDERR_DECOMPRESSION_ERROR;
915
916 if (!flac_decoder_reset(&flac->decoder, 44100, 2, flac_codec_blocksize(destlen), src + 1, complen - 1))
917 return CHDERR_DECOMPRESSION_ERROR;
918 if (!flac_decoder_decode_interleaved(&flac->decoder, (int16_t *)(dest), destlen/4, swap_endian))
919 return CHDERR_DECOMPRESSION_ERROR;
920 flac_decoder_finish(&flac->decoder);
921
922 return CHDERR_NONE;
923}
924
925static uint32_t cdfl_codec_blocksize(uint32_t bytes)
926{
927 // for CDs it seems that CD_MAX_SECTOR_DATA is the right target
928 uint32_t blocksize = bytes / 4;
929 while (blocksize > CD_MAX_SECTOR_DATA)
930 blocksize /= 2;
931 return blocksize;
b24e7fce 932}
933
934static chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes)
935{
936#ifdef WANT_SUBCODE
937 chd_error ret;
938#endif
939 uint16_t native_endian = 0;
940 cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;
941
942 /* make sure the CHD's hunk size is an even multiple of the frame size */
943 if (hunkbytes % CD_FRAME_SIZE != 0)
944 return CHDERR_CODEC_ERROR;
945
946 cdfl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
947 if (cdfl->buffer == NULL)
948 return CHDERR_OUT_OF_MEMORY;
949
950 /* determine whether we want native or swapped samples */
951 *(uint8_t *)(&native_endian) = 1;
952 cdfl->swap_endian = (native_endian & 1);
953
954#ifdef WANT_SUBCODE
955 /* init zlib inflater */
956 ret = zlib_codec_init(&cdfl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
957 if (ret != CHDERR_NONE)
958 return ret;
959#endif
960
961 /* flac decoder init */
962 if (flac_decoder_init(&cdfl->decoder))
963 return CHDERR_OUT_OF_MEMORY;
964
965 return CHDERR_NONE;
966}
967
968static void cdfl_codec_free(void *codec)
969{
970 cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;
971 flac_decoder_free(&cdfl->decoder);
972#ifdef WANT_SUBCODE
973 zlib_codec_free(&cdfl->subcode_decompressor);
974#endif
975 if (cdfl->buffer)
976 free(cdfl->buffer);
977}
978
979static chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
980{
981 uint32_t framenum;
982 uint8_t *buffer;
983#ifdef WANT_SUBCODE
984 uint32_t offset;
985 chd_error ret;
986#endif
987 cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;
988
989 /* reset and decode */
990 uint32_t frames = destlen / CD_FRAME_SIZE;
991
992 if (!flac_decoder_reset(&cdfl->decoder, 44100, 2, cdfl_codec_blocksize(frames * CD_MAX_SECTOR_DATA), src, complen))
993 return CHDERR_DECOMPRESSION_ERROR;
994 buffer = &cdfl->buffer[0];
995 if (!flac_decoder_decode_interleaved(&cdfl->decoder, (int16_t *)(buffer), frames * CD_MAX_SECTOR_DATA/4, cdfl->swap_endian))
996 return CHDERR_DECOMPRESSION_ERROR;
997
998#ifdef WANT_SUBCODE
999 /* inflate the subcode data */
1000 offset = flac_decoder_finish(&cdfl->decoder);
1001 ret = zlib_codec_decompress(&cdfl->subcode_decompressor, src + offset, complen - offset, &cdfl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);
1002 if (ret != CHDERR_NONE)
1003 return ret;
1004#else
1005 flac_decoder_finish(&cdfl->decoder);
1006#endif
1007
1008 /* reassemble the data */
1009 for (framenum = 0; framenum < frames; framenum++)
1010 {
1011 memcpy(&dest[framenum * CD_FRAME_SIZE], &cdfl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
1012#ifdef WANT_SUBCODE
1013 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);
1014#endif
1015 }
1016
1017 return CHDERR_NONE;
1018}
648db22b 1019
1020
1021/***************************************************************************
1022 * ZSTD DECOMPRESSOR
1023 ***************************************************************************
1024 */
1025
1026/*-------------------------------------------------
1027 * zstd_codec_init - constructor
1028 *-------------------------------------------------
1029 */
1030
1031static chd_error zstd_codec_init(void* codec, uint32_t hunkbytes)
1032{
1033 zstd_codec_data* zstd_codec = (zstd_codec_data*) codec;
1034
1035 zstd_codec->dstream = ZSTD_createDStream();
1036 if (!zstd_codec->dstream) {
1037 printf("NO DSTREAM CREATED!\n");
1038 return CHDERR_DECOMPRESSION_ERROR;
1039 }
1040 return CHDERR_NONE;
1041}
1042
1043/*-------------------------------------------------
1044 * zstd_codec_free
1045 *-------------------------------------------------
1046 */
1047
1048static void zstd_codec_free(void* codec)
1049{
1050 zstd_codec_data* zstd_codec = (zstd_codec_data*) codec;
1051
1052 ZSTD_freeDStream(zstd_codec->dstream);
1053}
1054
1055/*-------------------------------------------------
1056 * decompress - decompress data using the ZSTD
1057 * codec
1058 *-------------------------------------------------
1059 */
1060static chd_error zstd_codec_decompress(void* codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
1061{
1062 /* initialize */
1063 zstd_codec_data* zstd_codec = (zstd_codec_data*) codec;
1064 //reset decompressor
1065 size_t zstd_res = ZSTD_initDStream(zstd_codec->dstream);
1066 if (ZSTD_isError(zstd_res))
1067 {
1068 printf("INITI DSTREAM FAILED!\n");
1069 return CHDERR_DECOMPRESSION_ERROR;
1070 }
1071
1072 ZSTD_inBuffer input = {src, complen, 0};
1073 ZSTD_outBuffer output = {dest, destlen, 0 };
1074
1075 while ((input.pos < input.size) && (output.pos < output.size))
1076 {
1077 zstd_res = ZSTD_decompressStream(zstd_codec->dstream, &output, &input);
1078 if (ZSTD_isError(zstd_res))
1079 {
1080 printf("DECOMPRESSION ERROR IN LOOP\n");
1081 return CHDERR_DECOMPRESSION_ERROR;
1082 }
1083 }
1084 if (output.pos != output.size)
1085 {
1086 printf("OUTPUT DOESN'T MATCH!\n");
1087 return CHDERR_DECOMPRESSION_ERROR;
1088 }
1089 return CHDERR_NONE;
1090
1091}
1092
1093/* cdzs */
1094static chd_error cdzs_codec_init(void* codec, uint32_t hunkbytes)
1095{
1096 chd_error ret;
1097 cdzs_codec_data* cdzs = (cdzs_codec_data*) codec;
1098
1099 /* allocate buffer */
1100 cdzs->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
1101 if (cdzs->buffer == NULL)
1102 return CHDERR_OUT_OF_MEMORY;
1103
1104 /* make sure the CHD's hunk size is an even multiple of the frame size */
1105 ret = zstd_codec_init(&cdzs->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
1106 if (ret != CHDERR_NONE)
1107 return ret;
1108
1109#ifdef WANT_SUBCODE
1110 ret = zstd_codec_init(&cdzs->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA);
1111 if (ret != CHDERR_NONE)
1112 return ret;
1113#endif
1114
1115 if (hunkbytes % CD_FRAME_SIZE != 0)
1116 return CHDERR_CODEC_ERROR;
1117
1118 return CHDERR_NONE;
1119}
1120
1121static void cdzs_codec_free(void* codec)
1122{
1123 cdzs_codec_data* cdzs = (cdzs_codec_data*) codec;
1124 free(cdzs->buffer);
1125 zstd_codec_free(&cdzs->base_decompressor);
1126#ifdef WANT_SUBCODE
1127 zstd_codec_free(&cdzs->subcode_decompressor);
1128#endif
1129}
1130
1131static chd_error cdzs_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
1132{
1133 uint32_t framenum;
1134 cdzs_codec_data* cdzs = (cdzs_codec_data*)codec;
1135
1136 /* determine header bytes */
1137 uint32_t frames = destlen / CD_FRAME_SIZE;
1138 uint32_t complen_bytes = (destlen < 65536) ? 2 : 3;
1139 uint32_t ecc_bytes = (frames + 7) / 8;
1140 uint32_t header_bytes = ecc_bytes + complen_bytes;
1141
1142 /* extract compressed length of base */
1143 uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1];
1144 if (complen_bytes > 2)
1145 complen_base = (complen_base << 8) | src[ecc_bytes + 2];
1146
1147 /* reset and decode */
1148 zstd_codec_decompress(&cdzs->base_decompressor, &src[header_bytes], complen_base, &cdzs->buffer[0], frames * CD_MAX_SECTOR_DATA);
1149#ifdef WANT_SUBCODE
1150 zstd_codec_decompress(&cdzs->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdzs->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);
1151#endif
1152
1153 /* reassemble the data */
1154 for (framenum = 0; framenum < frames; framenum++)
1155 {
1156 uint8_t *sector;
1157
1158 memcpy(&dest[framenum * CD_FRAME_SIZE], &cdzs->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
1159#ifdef WANT_SUBCODE
1160 memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdzs->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA);
1161#endif
1162
1163#ifdef WANT_RAW_DATA_SECTOR
1164 /* reconstitute the ECC data and sync header */
1165 sector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE];
1166 if ((src[framenum / 8] & (1 << (framenum % 8))) != 0)
1167 {
1168 memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header));
1169 ecc_generate(sector);
1170 }
1171#endif
1172 }
1173 return CHDERR_NONE;
1174}
1175
b24e7fce 1176/***************************************************************************
1177 CODEC INTERFACES
1178***************************************************************************/
1179
1180static const codec_interface codec_interfaces[] =
1181{
1182 /* "none" or no compression */
1183 {
1184 CHDCOMPRESSION_NONE,
1185 "none",
1186 FALSE,
1187 NULL,
1188 NULL,
1189 NULL,
1190 NULL
1191 },
1192
1193 /* standard zlib compression */
1194 {
1195 CHDCOMPRESSION_ZLIB,
1196 "zlib",
1197 FALSE,
1198 zlib_codec_init,
1199 zlib_codec_free,
1200 zlib_codec_decompress,
1201 NULL
1202 },
1203
1204 /* zlib+ compression */
1205 {
1206 CHDCOMPRESSION_ZLIB_PLUS,
1207 "zlib+",
1208 FALSE,
1209 zlib_codec_init,
1210 zlib_codec_free,
1211 zlib_codec_decompress,
1212 NULL
1213 },
1214
1215 /* V5 zlib compression */
1216 {
1217 CHD_CODEC_ZLIB,
1218 "zlib (Deflate)",
1219 FALSE,
1220 zlib_codec_init,
1221 zlib_codec_free,
1222 zlib_codec_decompress,
1223 NULL
1224 },
1225
9e052883 1226 /* V5 lzma compression */
1227 {
1228 CHD_CODEC_LZMA,
1229 "lzma (LZMA)",
1230 FALSE,
1231 lzma_codec_init,
1232 lzma_codec_free,
1233 lzma_codec_decompress,
1234 NULL
1235 },
1236
1237 /* V5 huffman compression */
1238 {
1239 CHD_CODEC_HUFFMAN,
1240 "Huffman",
1241 FALSE,
1242 huff_codec_init,
1243 huff_codec_free,
1244 huff_codec_decompress,
1245 NULL
1246 },
1247
1248 /* V5 flac compression */
1249 {
1250 CHD_CODEC_FLAC,
1251 "flac (FLAC)",
1252 FALSE,
1253 flac_codec_init,
1254 flac_codec_free,
1255 flac_codec_decompress,
1256 NULL
1257 },
648db22b 1258 /* V5 zstd compression */
1259 {
1260 CHD_CODEC_ZSTD,
1261 "ZStandard",
1262 FALSE,
1263 zstd_codec_init,
1264 zstd_codec_free,
1265 zstd_codec_decompress,
1266 NULL
1267 },
9e052883 1268
b24e7fce 1269 /* V5 CD zlib compression */
1270 {
1271 CHD_CODEC_CD_ZLIB,
1272 "cdzl (CD Deflate)",
1273 FALSE,
1274 cdzl_codec_init,
1275 cdzl_codec_free,
1276 cdzl_codec_decompress,
1277 NULL
1278 },
1279
1280 /* V5 CD lzma compression */
1281 {
1282 CHD_CODEC_CD_LZMA,
1283 "cdlz (CD LZMA)",
1284 FALSE,
1285 cdlz_codec_init,
1286 cdlz_codec_free,
1287 cdlz_codec_decompress,
1288 NULL
1289 },
1290
1291 /* V5 CD flac compression */
1292 {
1293 CHD_CODEC_CD_FLAC,
1294 "cdfl (CD FLAC)",
1295 FALSE,
1296 cdfl_codec_init,
1297 cdfl_codec_free,
1298 cdfl_codec_decompress,
1299 NULL
1300 },
648db22b 1301 /* V5 CD zstd compression */
1302 {
1303 CHD_CODEC_CD_ZSTD,
1304 "cdzs (CD ZStandard)",
1305 FALSE,
1306 cdzs_codec_init,
1307 cdzs_codec_free,
1308 cdzs_codec_decompress,
1309 NULL
1310 }
1311
b24e7fce 1312};
1313
1314/***************************************************************************
1315 INLINE FUNCTIONS
1316***************************************************************************/
1317
1318/*-------------------------------------------------
1319 get_bigendian_uint64 - fetch a UINT64 from
1320 the data stream in bigendian order
1321-------------------------------------------------*/
1322
1323static inline UINT64 get_bigendian_uint64(const UINT8 *base)
1324{
1325 return ((UINT64)base[0] << 56) | ((UINT64)base[1] << 48) | ((UINT64)base[2] << 40) | ((UINT64)base[3] << 32) |
1326 ((UINT64)base[4] << 24) | ((UINT64)base[5] << 16) | ((UINT64)base[6] << 8) | (UINT64)base[7];
1327}
1328
1329/*-------------------------------------------------
1330 put_bigendian_uint64 - write a UINT64 to
1331 the data stream in bigendian order
1332-------------------------------------------------*/
1333
1334static inline void put_bigendian_uint64(UINT8 *base, UINT64 value)
1335{
1336 base[0] = value >> 56;
1337 base[1] = value >> 48;
1338 base[2] = value >> 40;
1339 base[3] = value >> 32;
1340 base[4] = value >> 24;
1341 base[5] = value >> 16;
1342 base[6] = value >> 8;
1343 base[7] = value;
1344}
1345
1346/*-------------------------------------------------
1347 get_bigendian_uint48 - fetch a UINT48 from
1348 the data stream in bigendian order
1349-------------------------------------------------*/
1350
1351static inline UINT64 get_bigendian_uint48(const UINT8 *base)
1352{
1353 return ((UINT64)base[0] << 40) | ((UINT64)base[1] << 32) |
1354 ((UINT64)base[2] << 24) | ((UINT64)base[3] << 16) | ((UINT64)base[4] << 8) | (UINT64)base[5];
1355}
1356
1357/*-------------------------------------------------
1358 put_bigendian_uint48 - write a UINT48 to
1359 the data stream in bigendian order
1360-------------------------------------------------*/
1361
1362static inline void put_bigendian_uint48(UINT8 *base, UINT64 value)
1363{
1364 value &= 0xffffffffffff;
1365 base[0] = value >> 40;
1366 base[1] = value >> 32;
1367 base[2] = value >> 24;
1368 base[3] = value >> 16;
1369 base[4] = value >> 8;
1370 base[5] = value;
1371}
1372/*-------------------------------------------------
1373 get_bigendian_uint32 - fetch a UINT32 from
1374 the data stream in bigendian order
1375-------------------------------------------------*/
1376
1377static inline UINT32 get_bigendian_uint32(const UINT8 *base)
1378{
1379 return (base[0] << 24) | (base[1] << 16) | (base[2] << 8) | base[3];
1380}
1381
1382/*-------------------------------------------------
1383 put_bigendian_uint32 - write a UINT32 to
1384 the data stream in bigendian order
1385-------------------------------------------------*/
1386
1387static inline void put_bigendian_uint32(UINT8 *base, UINT32 value)
1388{
1389 base[0] = value >> 24;
1390 base[1] = value >> 16;
1391 base[2] = value >> 8;
1392 base[3] = value;
1393}
1394
1395/*-------------------------------------------------
1396 put_bigendian_uint24 - write a UINT24 to
1397 the data stream in bigendian order
1398-------------------------------------------------*/
1399
1400static inline void put_bigendian_uint24(UINT8 *base, UINT32 value)
1401{
1402 value &= 0xffffff;
1403 base[0] = value >> 16;
1404 base[1] = value >> 8;
1405 base[2] = value;
1406}
1407
1408/*-------------------------------------------------
1409 get_bigendian_uint24 - fetch a UINT24 from
1410 the data stream in bigendian order
1411-------------------------------------------------*/
1412
1413static inline UINT32 get_bigendian_uint24(const UINT8 *base)
1414{
1415 return (base[0] << 16) | (base[1] << 8) | base[2];
1416}
1417
1418/*-------------------------------------------------
1419 get_bigendian_uint16 - fetch a UINT16 from
1420 the data stream in bigendian order
1421-------------------------------------------------*/
1422
1423static inline UINT16 get_bigendian_uint16(const UINT8 *base)
1424{
1425 return (base[0] << 8) | base[1];
1426}
1427
1428/*-------------------------------------------------
1429 put_bigendian_uint16 - write a UINT16 to
1430 the data stream in bigendian order
1431-------------------------------------------------*/
1432
1433static inline void put_bigendian_uint16(UINT8 *base, UINT16 value)
1434{
1435 base[0] = value >> 8;
1436 base[1] = value;
1437}
1438
1439/*-------------------------------------------------
1440 map_extract - extract a single map
1441 entry from the datastream
1442-------------------------------------------------*/
1443
1444static inline void map_extract(const UINT8 *base, map_entry *entry)
1445{
1446 entry->offset = get_bigendian_uint64(&base[0]);
1447 entry->crc = get_bigendian_uint32(&base[8]);
1448 entry->length = get_bigendian_uint16(&base[12]) | (base[14] << 16);
1449 entry->flags = base[15];
1450}
1451
1452/*-------------------------------------------------
1453 map_assemble - write a single map
1454 entry to the datastream
1455-------------------------------------------------*/
1456
1457static inline void map_assemble(UINT8 *base, map_entry *entry)
1458{
1459 put_bigendian_uint64(&base[0], entry->offset);
1460 put_bigendian_uint32(&base[8], entry->crc);
1461 put_bigendian_uint16(&base[12], entry->length);
1462 base[14] = entry->length >> 16;
1463 base[15] = entry->flags;
1464}
1465
1466/*-------------------------------------------------
1467 map_size_v5 - calculate CHDv5 map size
1468-------------------------------------------------*/
1469static inline int map_size_v5(chd_header* header)
1470{
1471 return header->hunkcount * header->mapentrybytes;
1472}
1473
1474/*-------------------------------------------------
1475 crc16 - calculate CRC16 (from hashing.cpp)
1476-------------------------------------------------*/
1477uint16_t crc16(const void *data, uint32_t length)
1478{
1479 uint16_t crc = 0xffff;
1480
1481 static const uint16_t s_table[256] =
1482 {
1483 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
1484 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
1485 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
1486 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
1487 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
1488 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
1489 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
1490 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
1491 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
1492 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
1493 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
1494 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
1495 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
1496 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
1497 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
1498 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
1499 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
1500 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
1501 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
1502 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
1503 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
1504 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
1505 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
1506 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
1507 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
1508 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
1509 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
1510 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
1511 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
1512 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
1513 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
1514 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
1515 };
1516
1517 const uint8_t *src = (uint8_t*)data;
1518
1519 /* fetch the current value into a local and rip through the source data */
1520 while (length-- != 0)
1521 crc = (crc << 8) ^ s_table[(crc >> 8) ^ *src++];
1522 return crc;
1523}
1524
1525/*-------------------------------------------------
1526 compressed - test if CHD file is compressed
1527+-------------------------------------------------*/
1528static inline int chd_compressed(chd_header* header) {
1529 return header->compression[0] != CHD_CODEC_NONE;
1530}
1531
1532/*-------------------------------------------------
1533 decompress_v5_map - decompress the v5 map
1534-------------------------------------------------*/
1535
1536static chd_error decompress_v5_map(chd_file* chd, chd_header* header)
1537{
1538 int result = 0;
9e052883 1539 uint32_t hunknum;
b24e7fce 1540 int repcount = 0;
1541 uint8_t lastcomp = 0;
1542 uint32_t last_self = 0;
1543 uint64_t last_parent = 0;
1544 struct bitstream* bitbuf;
1545 uint32_t mapbytes;
1546 uint64_t firstoffs;
1547 uint16_t mapcrc;
1548 uint8_t lengthbits;
1549 uint8_t selfbits;
1550 uint8_t parentbits;
1551 uint8_t *compressed_ptr;
1552 uint8_t rawbuf[16];
1553 struct huffman_decoder* decoder;
1554 enum huffman_error err;
1555 uint64_t curoffset;
1556 int rawmapsize = map_size_v5(header);
1557
1558 if (!chd_compressed(header))
1559 {
1560 header->rawmap = (uint8_t*)malloc(rawmapsize);
9e052883 1561 if (header->rawmap == NULL)
1562 return CHDERR_OUT_OF_MEMORY;
b24e7fce 1563 core_fseek(chd->file, header->mapoffset, SEEK_SET);
1564 result = core_fread(chd->file, header->rawmap, rawmapsize);
1565 return CHDERR_NONE;
1566 }
1567
1568 /* read the reader */
1569 core_fseek(chd->file, header->mapoffset, SEEK_SET);
1570 result = core_fread(chd->file, rawbuf, sizeof(rawbuf));
1571 mapbytes = get_bigendian_uint32(&rawbuf[0]);
1572 firstoffs = get_bigendian_uint48(&rawbuf[4]);
1573 mapcrc = get_bigendian_uint16(&rawbuf[10]);
1574 lengthbits = rawbuf[12];
1575 selfbits = rawbuf[13];
1576 parentbits = rawbuf[14];
1577
1578 /* now read the map */
1579 compressed_ptr = (uint8_t*)malloc(sizeof(uint8_t) * mapbytes);
9e052883 1580 if (compressed_ptr == NULL)
1581 return CHDERR_OUT_OF_MEMORY;
b24e7fce 1582 core_fseek(chd->file, header->mapoffset + 16, SEEK_SET);
1583 result = core_fread(chd->file, compressed_ptr, mapbytes);
1584 bitbuf = create_bitstream(compressed_ptr, sizeof(uint8_t) * mapbytes);
1585 header->rawmap = (uint8_t*)malloc(rawmapsize);
9e052883 1586 if (header->rawmap == NULL)
1587 {
1588 free(compressed_ptr);
1589 free(bitbuf);
1590 return CHDERR_OUT_OF_MEMORY;
1591 }
b24e7fce 1592
1593 /* first decode the compression types */
1594 decoder = create_huffman_decoder(16, 8);
1595 if (decoder == NULL)
1596 {
1597 free(compressed_ptr);
1598 free(bitbuf);
1599 return CHDERR_OUT_OF_MEMORY;
1600 }
1601
1602 err = huffman_import_tree_rle(decoder, bitbuf);
1603 if (err != HUFFERR_NONE)
1604 {
1605 free(compressed_ptr);
1606 free(bitbuf);
1607 delete_huffman_decoder(decoder);
1608 return CHDERR_DECOMPRESSION_ERROR;
1609 }
1610
1611 for (hunknum = 0; hunknum < header->hunkcount; hunknum++)
1612 {
1613 uint8_t *rawmap = header->rawmap + (hunknum * 12);
1614 if (repcount > 0)
1615 rawmap[0] = lastcomp, repcount--;
1616 else
1617 {
1618 uint8_t val = huffman_decode_one(decoder, bitbuf);
1619 if (val == COMPRESSION_RLE_SMALL)
1620 rawmap[0] = lastcomp, repcount = 2 + huffman_decode_one(decoder, bitbuf);
1621 else if (val == COMPRESSION_RLE_LARGE)
1622 rawmap[0] = lastcomp, repcount = 2 + 16 + (huffman_decode_one(decoder, bitbuf) << 4), repcount += huffman_decode_one(decoder, bitbuf);
1623 else
1624 rawmap[0] = lastcomp = val;
1625 }
1626 }
1627
1628 /* then iterate through the hunks and extract the needed data */
1629 curoffset = firstoffs;
1630 for (hunknum = 0; hunknum < header->hunkcount; hunknum++)
1631 {
1632 uint8_t *rawmap = header->rawmap + (hunknum * 12);
1633 uint64_t offset = curoffset;
1634 uint32_t length = 0;
1635 uint16_t crc = 0;
1636 switch (rawmap[0])
1637 {
1638 /* base types */
1639 case COMPRESSION_TYPE_0:
1640 case COMPRESSION_TYPE_1:
1641 case COMPRESSION_TYPE_2:
1642 case COMPRESSION_TYPE_3:
1643 curoffset += length = bitstream_read(bitbuf, lengthbits);
1644 crc = bitstream_read(bitbuf, 16);
1645 break;
1646
1647 case COMPRESSION_NONE:
1648 curoffset += length = header->hunkbytes;
1649 crc = bitstream_read(bitbuf, 16);
1650 break;
1651
1652 case COMPRESSION_SELF:
1653 last_self = offset = bitstream_read(bitbuf, selfbits);
1654 break;
1655
1656 case COMPRESSION_PARENT:
1657 offset = bitstream_read(bitbuf, parentbits);
1658 last_parent = offset;
1659 break;
1660
1661 /* pseudo-types; convert into base types */
1662 case COMPRESSION_SELF_1:
1663 last_self++;
1664 case COMPRESSION_SELF_0:
1665 rawmap[0] = COMPRESSION_SELF;
1666 offset = last_self;
1667 break;
1668
1669 case COMPRESSION_PARENT_SELF:
1670 rawmap[0] = COMPRESSION_PARENT;
1671 last_parent = offset = ( ((uint64_t)hunknum) * ((uint64_t)header->hunkbytes) ) / header->unitbytes;
1672 break;
1673
1674 case COMPRESSION_PARENT_1:
1675 last_parent += header->hunkbytes / header->unitbytes;
1676 case COMPRESSION_PARENT_0:
1677 rawmap[0] = COMPRESSION_PARENT;
1678 offset = last_parent;
1679 break;
1680 }
1681 /* UINT24 length */
1682 put_bigendian_uint24(&rawmap[1], length);
1683
1684 /* UINT48 offset */
1685 put_bigendian_uint48(&rawmap[4], offset);
1686
1687 /* crc16 */
1688 put_bigendian_uint16(&rawmap[10], crc);
1689 }
1690
1691 /* free memory */
1692 free(compressed_ptr);
1693 free(bitbuf);
1694 delete_huffman_decoder(decoder);
1695
1696 /* verify the final CRC */
1697 if (crc16(&header->rawmap[0], header->hunkcount * 12) != mapcrc)
1698 return CHDERR_DECOMPRESSION_ERROR;
1699
1700 return CHDERR_NONE;
1701}
1702
1703/*-------------------------------------------------
1704 map_extract_old - extract a single map
1705 entry in old format from the datastream
1706-------------------------------------------------*/
1707
1708static inline void map_extract_old(const UINT8 *base, map_entry *entry, UINT32 hunkbytes)
1709{
1710 entry->offset = get_bigendian_uint64(&base[0]);
1711 entry->crc = 0;
1712 entry->length = entry->offset >> 44;
1713 entry->flags = MAP_ENTRY_FLAG_NO_CRC | ((entry->length == hunkbytes) ? V34_MAP_ENTRY_TYPE_UNCOMPRESSED : V34_MAP_ENTRY_TYPE_COMPRESSED);
1714#ifdef __MWERKS__
1715 entry->offset = entry->offset & 0x00000FFFFFFFFFFFLL;
1716#else
1717 entry->offset = (entry->offset << 20) >> 20;
1718#endif
1719}
1720
1721/***************************************************************************
1722 CHD FILE MANAGEMENT
1723***************************************************************************/
1724
1725/*-------------------------------------------------
1726 chd_open_file - open a CHD file for access
1727-------------------------------------------------*/
1728
9e052883 1729CHD_EXPORT chd_error chd_open_file(FILE *file, int mode, chd_file *parent, chd_file **chd) {
1730 core_file *stream = malloc(sizeof(core_file));
1731 if (!stream)
1732 return CHDERR_OUT_OF_MEMORY;
1733 stream->argp = file;
1734 stream->fsize = core_stdio_fsize;
1735 stream->fread = core_stdio_fread;
1736 stream->fclose = core_stdio_fclose_nonowner;
1737 stream->fseek = core_stdio_fseek;
1738
1739 return chd_open_core_file(stream, mode, parent, chd);
1740}
1741
1742/*-------------------------------------------------
1743 chd_open_core_file - open a CHD file for access
1744-------------------------------------------------*/
1745
1746CHD_EXPORT chd_error chd_open_core_file(core_file *file, int mode, chd_file *parent, chd_file **chd)
b24e7fce 1747{
1748 chd_file *newchd = NULL;
1749 chd_error err;
1750 int intfnum;
1751
1752 /* verify parameters */
1753 if (file == NULL)
1754 EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
1755
1756 /* punt if invalid parent */
1757 if (parent != NULL && parent->cookie != COOKIE_VALUE)
1758 EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
1759
1760 /* allocate memory for the final result */
1761 newchd = (chd_file *)malloc(sizeof(**chd));
1762 if (newchd == NULL)
1763 EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
1764 memset(newchd, 0, sizeof(*newchd));
1765 newchd->cookie = COOKIE_VALUE;
1766 newchd->parent = parent;
1767 newchd->file = file;
1768
1769 /* now attempt to read the header */
1770 err = header_read(newchd, &newchd->header);
1771 if (err != CHDERR_NONE)
1772 EARLY_EXIT(err);
1773
1774 /* validate the header */
1775 err = header_validate(&newchd->header);
1776 if (err != CHDERR_NONE)
1777 EARLY_EXIT(err);
1778
1779 /* make sure we don't open a read-only file writeable */
1780 if (mode == CHD_OPEN_READWRITE && !(newchd->header.flags & CHDFLAGS_IS_WRITEABLE))
1781 EARLY_EXIT(err = CHDERR_FILE_NOT_WRITEABLE);
1782
1783 /* also, never open an older version writeable */
1784 if (mode == CHD_OPEN_READWRITE && newchd->header.version < CHD_HEADER_VERSION)
1785 EARLY_EXIT(err = CHDERR_UNSUPPORTED_VERSION);
1786
1787 /* if we need a parent, make sure we have one */
1788 if (parent == NULL)
1789 {
1790 /* Detect parent requirement for versions below 5 */
1791 if (newchd->header.version < 5 && newchd->header.flags & CHDFLAGS_HAS_PARENT)
1792 EARLY_EXIT(err = CHDERR_REQUIRES_PARENT);
1793 /* Detection for version 5 and above - if parentsha1 != 0, we have a parent */
1794 else if (newchd->header.version >= 5 && memcmp(nullsha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0)
1795 EARLY_EXIT(err = CHDERR_REQUIRES_PARENT);
1796 }
1797
1798 /* make sure we have a valid parent */
1799 if (parent != NULL)
1800 {
1801 /* check MD5 if it isn't empty */
1802 if (memcmp(nullmd5, newchd->header.parentmd5, sizeof(newchd->header.parentmd5)) != 0 &&
1803 memcmp(nullmd5, newchd->parent->header.md5, sizeof(newchd->parent->header.md5)) != 0 &&
1804 memcmp(newchd->parent->header.md5, newchd->header.parentmd5, sizeof(newchd->header.parentmd5)) != 0)
1805 EARLY_EXIT(err = CHDERR_INVALID_PARENT);
1806
1807 /* check SHA1 if it isn't empty */
1808 if (memcmp(nullsha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0 &&
1809 memcmp(nullsha1, newchd->parent->header.sha1, sizeof(newchd->parent->header.sha1)) != 0 &&
1810 memcmp(newchd->parent->header.sha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0)
1811 EARLY_EXIT(err = CHDERR_INVALID_PARENT);
1812 }
1813
1814 /* now read the hunk map */
1815 if (newchd->header.version < 5)
1816 {
1817 err = map_read(newchd);
1818 if (err != CHDERR_NONE)
1819 EARLY_EXIT(err);
1820 }
1821 else
1822 {
1823 err = decompress_v5_map(newchd, &(newchd->header));
1824 }
1825 if (err != CHDERR_NONE)
1826 EARLY_EXIT(err);
1827
1828#ifdef NEED_CACHE_HUNK
1829 /* allocate and init the hunk cache */
1830 newchd->cache = (UINT8 *)malloc(newchd->header.hunkbytes);
1831 newchd->compare = (UINT8 *)malloc(newchd->header.hunkbytes);
1832 if (newchd->cache == NULL || newchd->compare == NULL)
1833 EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
1834 newchd->cachehunk = ~0;
1835 newchd->comparehunk = ~0;
1836#endif
1837
1838 /* allocate the temporary compressed buffer */
1839 newchd->compressed = (UINT8 *)malloc(newchd->header.hunkbytes);
1840 if (newchd->compressed == NULL)
1841 EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
1842
1843 /* find the codec interface */
1844 if (newchd->header.version < 5)
1845 {
1846 for (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++)
1847 {
1848 if (codec_interfaces[intfnum].compression == newchd->header.compression[0])
1849 {
1850 newchd->codecintf[0] = &codec_interfaces[intfnum];
1851 break;
1852 }
1853 }
1854
1855 if (intfnum == ARRAY_LENGTH(codec_interfaces))
1856 EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);
1857
1858 /* initialize the codec */
1859 if (newchd->codecintf[0]->init != NULL)
1860 {
1861 err = (*newchd->codecintf[0]->init)(&newchd->zlib_codec_data, newchd->header.hunkbytes);
1862 if (err != CHDERR_NONE)
1863 EARLY_EXIT(err);
1864 }
1865 }
1866 else
1867 {
1868 int decompnum;
1869 /* verify the compression types and initialize the codecs */
1870 for (decompnum = 0; decompnum < ARRAY_LENGTH(newchd->header.compression); decompnum++)
1871 {
1872 int i;
1873 for (i = 0 ; i < ARRAY_LENGTH(codec_interfaces) ; i++)
1874 {
1875 if (codec_interfaces[i].compression == newchd->header.compression[decompnum])
1876 {
1877 newchd->codecintf[decompnum] = &codec_interfaces[i];
1878 break;
1879 }
1880 }
1881
1882 if (newchd->codecintf[decompnum] == NULL && newchd->header.compression[decompnum] != 0)
1883 EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);
1884
1885 /* initialize the codec */
1886 if (newchd->codecintf[decompnum]->init != NULL)
1887 {
1888 void* codec = NULL;
1889 switch (newchd->header.compression[decompnum])
1890 {
1891 case CHD_CODEC_ZLIB:
1892 codec = &newchd->zlib_codec_data;
1893 break;
1894
9e052883 1895 case CHD_CODEC_LZMA:
1896 codec = &newchd->lzma_codec_data;
1897 break;
1898
1899 case CHD_CODEC_HUFFMAN:
1900 codec = &newchd->huff_codec_data;
1901 break;
1902
1903 case CHD_CODEC_FLAC:
1904 codec = &newchd->flac_codec_data;
1905 break;
1906
648db22b 1907 case CHD_CODEC_ZSTD:
1908 codec = &newchd->zstd_codec_data;
1909 break;
1910
b24e7fce 1911 case CHD_CODEC_CD_ZLIB:
1912 codec = &newchd->cdzl_codec_data;
1913 break;
1914
1915 case CHD_CODEC_CD_LZMA:
1916 codec = &newchd->cdlz_codec_data;
1917 break;
1918
1919 case CHD_CODEC_CD_FLAC:
1920 codec = &newchd->cdfl_codec_data;
1921 break;
648db22b 1922
1923 case CHD_CODEC_CD_ZSTD:
1924 codec = &newchd->cdzs_codec_data;
1925 break;
b24e7fce 1926 }
1927
1928 if (codec == NULL)
1929 EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);
1930
1931 err = (*newchd->codecintf[decompnum]->init)(codec, newchd->header.hunkbytes);
1932 if (err != CHDERR_NONE)
1933 EARLY_EXIT(err);
1934 }
1935 }
1936 }
1937
1938 /* all done */
1939 *chd = newchd;
1940 return CHDERR_NONE;
1941
1942cleanup:
1943 if (newchd != NULL)
1944 chd_close(newchd);
1945 return err;
1946}
1947
1948/*-------------------------------------------------
1949 chd_precache - precache underlying file in
1950 memory
1951-------------------------------------------------*/
1952
1953CHD_EXPORT chd_error chd_precache(chd_file *chd)
1954{
9e052883 1955 INT64 count;
1956 UINT64 size;
b24e7fce 1957
1958 if (chd->file_cache == NULL)
1959 {
9e052883 1960 size = core_fsize(chd->file);
1961 if ((INT64)size <= 0)
b24e7fce 1962 return CHDERR_INVALID_DATA;
1963 chd->file_cache = malloc(size);
1964 if (chd->file_cache == NULL)
1965 return CHDERR_OUT_OF_MEMORY;
1966 core_fseek(chd->file, 0, SEEK_SET);
1967 count = core_fread(chd->file, chd->file_cache, size);
1968 if (count != size)
1969 {
1970 free(chd->file_cache);
1971 chd->file_cache = NULL;
1972 return CHDERR_READ_ERROR;
1973 }
1974 }
1975
1976 return CHDERR_NONE;
1977}
1978
1979/*-------------------------------------------------
1980 chd_open - open a CHD file by
1981 filename
1982-------------------------------------------------*/
1983
1984CHD_EXPORT chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd)
1985{
1986 chd_error err;
1987 core_file *file = NULL;
1988
9e052883 1989 if (filename == NULL)
1990 {
1991 err = CHDERR_INVALID_PARAMETER;
1992 goto cleanup;
1993 }
1994
b24e7fce 1995 /* choose the proper mode */
1996 switch(mode)
1997 {
1998 case CHD_OPEN_READ:
1999 break;
2000
2001 default:
2002 err = CHDERR_INVALID_PARAMETER;
2003 goto cleanup;
2004 }
2005
2006 /* open the file */
9e052883 2007 file = core_stdio_fopen(filename);
b24e7fce 2008 if (file == 0)
2009 {
2010 err = CHDERR_FILE_NOT_FOUND;
2011 goto cleanup;
2012 }
2013
2014 /* now open the CHD */
9e052883 2015 return chd_open_core_file(file, mode, parent, chd);
b24e7fce 2016
2017cleanup:
2018 if ((err != CHDERR_NONE) && (file != NULL))
2019 core_fclose(file);
2020 return err;
2021}
2022
2023/*-------------------------------------------------
2024 chd_close - close a CHD file for access
2025-------------------------------------------------*/
2026
2027CHD_EXPORT void chd_close(chd_file *chd)
2028{
2029 /* punt if NULL or invalid */
2030 if (chd == NULL || chd->cookie != COOKIE_VALUE)
2031 return;
2032
2033 /* deinit the codec */
2034 if (chd->header.version < 5)
2035 {
2036 if (chd->codecintf[0] != NULL && chd->codecintf[0]->free != NULL)
2037 (*chd->codecintf[0]->free)(&chd->zlib_codec_data);
2038 }
2039 else
2040 {
2041 int i;
2042 /* Free the codecs */
2043 for (i = 0 ; i < ARRAY_LENGTH(chd->codecintf); i++)
2044 {
2045 void* codec = NULL;
2046
2047 if (chd->codecintf[i] == NULL)
2048 continue;
2049
2050 switch (chd->codecintf[i]->compression)
2051 {
b24e7fce 2052 case CHD_CODEC_ZLIB:
2053 codec = &chd->zlib_codec_data;
2054 break;
2055
9e052883 2056 case CHD_CODEC_LZMA:
2057 codec = &chd->lzma_codec_data;
2058 break;
2059
2060 case CHD_CODEC_HUFFMAN:
2061 codec = &chd->huff_codec_data;
2062 break;
2063
2064 case CHD_CODEC_FLAC:
2065 codec = &chd->flac_codec_data;
2066 break;
2067
648db22b 2068 case CHD_CODEC_ZSTD:
2069 codec = &chd->zstd_codec_data;
2070 break;
2071
b24e7fce 2072 case CHD_CODEC_CD_ZLIB:
2073 codec = &chd->cdzl_codec_data;
2074 break;
2075
9e052883 2076 case CHD_CODEC_CD_LZMA:
2077 codec = &chd->cdlz_codec_data;
2078 break;
2079
b24e7fce 2080 case CHD_CODEC_CD_FLAC:
2081 codec = &chd->cdfl_codec_data;
2082 break;
648db22b 2083
2084 case CHD_CODEC_CD_ZSTD:
2085 codec = &chd->cdzs_codec_data;
2086 break;
b24e7fce 2087 }
2088
2089 if (codec)
2090 {
2091 (*chd->codecintf[i]->free)(codec);
2092 }
2093 }
2094
2095 /* Free the raw map */
2096 if (chd->header.rawmap != NULL)
2097 free(chd->header.rawmap);
2098 }
2099
2100 /* free the compressed data buffer */
2101 if (chd->compressed != NULL)
2102 free(chd->compressed);
2103
2104#ifdef NEED_CACHE_HUNK
2105 /* free the hunk cache and compare data */
2106 if (chd->compare != NULL)
2107 free(chd->compare);
2108 if (chd->cache != NULL)
2109 free(chd->cache);
2110#endif
2111
2112 /* free the hunk map */
2113 if (chd->map != NULL)
2114 free(chd->map);
2115
2116 /* close the file */
9e052883 2117 if (chd->file != NULL)
b24e7fce 2118 core_fclose(chd->file);
2119
2120#ifdef NEED_CACHE_HUNK
2121 if (PRINTF_MAX_HUNK) printf("Max hunk = %d/%d\n", chd->maxhunk, chd->header.totalhunks);
2122#endif
2123 if (chd->file_cache)
2124 free(chd->file_cache);
2125
2126 if (chd->parent)
2127 chd_close(chd->parent);
2128
2129 /* free our memory */
2130 free(chd);
2131}
2132
2133/*-------------------------------------------------
2134 chd_core_file - return the associated
2135 core_file
2136-------------------------------------------------*/
2137
2138CHD_EXPORT core_file *chd_core_file(chd_file *chd)
2139{
2140 return chd->file;
2141}
2142
2143/*-------------------------------------------------
2144 chd_error_string - return an error string for
2145 the given CHD error
2146-------------------------------------------------*/
2147
2148CHD_EXPORT const char *chd_error_string(chd_error err)
2149{
2150 switch (err)
2151 {
2152 case CHDERR_NONE: return "no error";
2153 case CHDERR_NO_INTERFACE: return "no drive interface";
2154 case CHDERR_OUT_OF_MEMORY: return "out of memory";
2155 case CHDERR_INVALID_FILE: return "invalid file";
2156 case CHDERR_INVALID_PARAMETER: return "invalid parameter";
2157 case CHDERR_INVALID_DATA: return "invalid data";
2158 case CHDERR_FILE_NOT_FOUND: return "file not found";
2159 case CHDERR_REQUIRES_PARENT: return "requires parent";
2160 case CHDERR_FILE_NOT_WRITEABLE: return "file not writeable";
2161 case CHDERR_READ_ERROR: return "read error";
2162 case CHDERR_WRITE_ERROR: return "write error";
2163 case CHDERR_CODEC_ERROR: return "codec error";
2164 case CHDERR_INVALID_PARENT: return "invalid parent";
2165 case CHDERR_HUNK_OUT_OF_RANGE: return "hunk out of range";
2166 case CHDERR_DECOMPRESSION_ERROR: return "decompression error";
2167 case CHDERR_COMPRESSION_ERROR: return "compression error";
2168 case CHDERR_CANT_CREATE_FILE: return "can't create file";
2169 case CHDERR_CANT_VERIFY: return "can't verify file";
2170 case CHDERR_NOT_SUPPORTED: return "operation not supported";
2171 case CHDERR_METADATA_NOT_FOUND: return "can't find metadata";
2172 case CHDERR_INVALID_METADATA_SIZE: return "invalid metadata size";
2173 case CHDERR_UNSUPPORTED_VERSION: return "unsupported CHD version";
2174 case CHDERR_VERIFY_INCOMPLETE: return "incomplete verify";
2175 case CHDERR_INVALID_METADATA: return "invalid metadata";
2176 case CHDERR_INVALID_STATE: return "invalid state";
2177 case CHDERR_OPERATION_PENDING: return "operation pending";
2178 case CHDERR_NO_ASYNC_OPERATION: return "no async operation in progress";
2179 case CHDERR_UNSUPPORTED_FORMAT: return "unsupported format";
2180 default: return "undocumented error";
2181 }
2182}
2183
2184/***************************************************************************
2185 CHD HEADER MANAGEMENT
2186***************************************************************************/
2187
2188/*-------------------------------------------------
2189 chd_get_header - return a pointer to the
2190 extracted header data
2191-------------------------------------------------*/
2192
2193CHD_EXPORT const chd_header *chd_get_header(chd_file *chd)
2194{
2195 /* punt if NULL or invalid */
2196 if (chd == NULL || chd->cookie != COOKIE_VALUE)
2197 return NULL;
2198
2199 return &chd->header;
2200}
2201
2202/*-------------------------------------------------
2203 chd_read_header - read CHD header data
2204 from file into the pointed struct
2205-------------------------------------------------*/
2206CHD_EXPORT chd_error chd_read_header(const char *filename, chd_header *header)
2207{
2208 chd_error err = CHDERR_NONE;
2209 chd_file chd;
2210
2211 /* punt if NULL */
2212 if (filename == NULL || header == NULL)
2213 EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
2214
2215 /* open the file */
9e052883 2216 chd.file = core_stdio_fopen(filename);
b24e7fce 2217 if (chd.file == NULL)
2218 EARLY_EXIT(err = CHDERR_FILE_NOT_FOUND);
2219
2220 /* attempt to read the header */
2221 err = header_read(&chd, header);
2222 if (err != CHDERR_NONE)
2223 EARLY_EXIT(err);
2224
2225 /* validate the header */
2226 err = header_validate(header);
2227 if (err != CHDERR_NONE)
2228 EARLY_EXIT(err);
2229
2230cleanup:
2231 if (chd.file != NULL)
2232 core_fclose(chd.file);
2233
2234 return err;
2235}
2236
2237/***************************************************************************
2238 CORE DATA READ/WRITE
2239***************************************************************************/
2240
2241/*-------------------------------------------------
2242 chd_read - read a single hunk from the CHD
2243 file
2244-------------------------------------------------*/
2245
2246CHD_EXPORT chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer)
2247{
2248 /* punt if NULL or invalid */
2249 if (chd == NULL || chd->cookie != COOKIE_VALUE)
2250 return CHDERR_INVALID_PARAMETER;
2251
2252 /* if we're past the end, fail */
2253 if (hunknum >= chd->header.totalhunks)
2254 return CHDERR_HUNK_OUT_OF_RANGE;
2255
2256 /* perform the read */
2257 return hunk_read_into_memory(chd, hunknum, (UINT8 *)buffer);
2258}
2259
2260/***************************************************************************
2261 METADATA MANAGEMENT
2262***************************************************************************/
2263
2264/*-------------------------------------------------
2265 chd_get_metadata - get the indexed metadata
2266 of the given type
2267-------------------------------------------------*/
2268
2269CHD_EXPORT chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 *resultlen, UINT32 *resulttag, UINT8 *resultflags)
2270{
2271 metadata_entry metaentry;
2272 chd_error err;
2273 UINT32 count;
2274
2275 /* if we didn't find it, just return */
2276 err = metadata_find_entry(chd, searchtag, searchindex, &metaentry);
2277 if (err != CHDERR_NONE)
2278 {
2279 /* unless we're an old version and they are requesting hard disk metadata */
2280 if (chd->header.version < 3 && (searchtag == HARD_DISK_METADATA_TAG || searchtag == CHDMETATAG_WILDCARD) && searchindex == 0)
2281 {
2282 char faux_metadata[256];
2283 UINT32 faux_length;
2284
2285 /* fill in the faux metadata */
2286 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);
2287 faux_length = (UINT32)strlen(faux_metadata) + 1;
2288
2289 /* copy the metadata itself */
2290 memcpy(output, faux_metadata, MIN(outputlen, faux_length));
2291
2292 /* return the length of the data and the tag */
2293 if (resultlen != NULL)
2294 *resultlen = faux_length;
2295 if (resulttag != NULL)
2296 *resulttag = HARD_DISK_METADATA_TAG;
2297 return CHDERR_NONE;
2298 }
2299 return err;
2300 }
2301
2302 /* read the metadata */
2303 outputlen = MIN(outputlen, metaentry.length);
2304 core_fseek(chd->file, metaentry.offset + METADATA_HEADER_SIZE, SEEK_SET);
2305 count = core_fread(chd->file, output, outputlen);
2306 if (count != outputlen)
2307 return CHDERR_READ_ERROR;
2308
2309 /* return the length of the data and the tag */
2310 if (resultlen != NULL)
2311 *resultlen = metaentry.length;
2312 if (resulttag != NULL)
2313 *resulttag = metaentry.metatag;
2314 if (resultflags != NULL)
2315 *resultflags = metaentry.flags;
2316 return CHDERR_NONE;
2317}
2318
2319/***************************************************************************
2320 CODEC INTERFACES
2321***************************************************************************/
2322
2323/*-------------------------------------------------
2324 chd_codec_config - set internal codec
2325 parameters
2326-------------------------------------------------*/
2327
2328CHD_EXPORT chd_error chd_codec_config(chd_file *chd, int param, void *config)
2329{
2330 return CHDERR_INVALID_PARAMETER;
2331}
2332
2333/*-------------------------------------------------
2334 chd_get_codec_name - get the name of a
2335 particular codec
2336-------------------------------------------------*/
2337
2338CHD_EXPORT const char *chd_get_codec_name(UINT32 codec)
2339{
2340 return "Unknown";
2341}
2342
2343/***************************************************************************
2344 INTERNAL HEADER OPERATIONS
2345***************************************************************************/
2346
2347/*-------------------------------------------------
2348 header_validate - check the validity of a
2349 CHD header
2350-------------------------------------------------*/
2351
2352static chd_error header_validate(const chd_header *header)
2353{
2354 int intfnum;
2355
2356 /* require a valid version */
2357 if (header->version == 0 || header->version > CHD_HEADER_VERSION)
2358 return CHDERR_UNSUPPORTED_VERSION;
2359
2360 /* require a valid length */
2361 if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) ||
2362 (header->version == 2 && header->length != CHD_V2_HEADER_SIZE) ||
2363 (header->version == 3 && header->length != CHD_V3_HEADER_SIZE) ||
2364 (header->version == 4 && header->length != CHD_V4_HEADER_SIZE) ||
2365 (header->version == 5 && header->length != CHD_V5_HEADER_SIZE))
2366 return CHDERR_INVALID_PARAMETER;
2367
2368 /* Do not validate v5 header */
2369 if (header->version <= 4)
2370 {
2371 /* require valid flags */
2372 if (header->flags & CHDFLAGS_UNDEFINED)
2373 return CHDERR_INVALID_PARAMETER;
2374
2375 /* require a supported compression mechanism */
2376 for (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++)
2377 if (codec_interfaces[intfnum].compression == header->compression[0])
2378 break;
2379
2380 if (intfnum == ARRAY_LENGTH(codec_interfaces))
2381 return CHDERR_INVALID_PARAMETER;
2382
2383 /* require a valid hunksize */
2384 if (header->hunkbytes == 0 || header->hunkbytes >= 65536 * 256)
2385 return CHDERR_INVALID_PARAMETER;
2386
2387 /* require a valid hunk count */
2388 if (header->totalhunks == 0)
2389 return CHDERR_INVALID_PARAMETER;
2390
2391 /* require a valid MD5 and/or SHA1 if we're using a parent */
2392 if ((header->flags & CHDFLAGS_HAS_PARENT) && memcmp(header->parentmd5, nullmd5, sizeof(nullmd5)) == 0 && memcmp(header->parentsha1, nullsha1, sizeof(nullsha1)) == 0)
2393 return CHDERR_INVALID_PARAMETER;
2394
2395 /* if we're V3 or later, the obsolete fields must be 0 */
2396 if (header->version >= 3 &&
2397 (header->obsolete_cylinders != 0 || header->obsolete_sectors != 0 ||
2398 header->obsolete_heads != 0 || header->obsolete_hunksize != 0))
2399 return CHDERR_INVALID_PARAMETER;
2400
2401 /* if we're pre-V3, the obsolete fields must NOT be 0 */
2402 if (header->version < 3 &&
2403 (header->obsolete_cylinders == 0 || header->obsolete_sectors == 0 ||
2404 header->obsolete_heads == 0 || header->obsolete_hunksize == 0))
2405 return CHDERR_INVALID_PARAMETER;
2406 }
2407
2408 return CHDERR_NONE;
2409}
2410
2411/*-------------------------------------------------
2412 header_guess_unitbytes - for older CHD formats,
2413 guess at the bytes/unit based on metadata
2414-------------------------------------------------*/
2415
2416static UINT32 header_guess_unitbytes(chd_file *chd)
2417{
2418 /* look for hard disk metadata; if found, then the unit size == sector size */
2419 char metadata[512];
2420 int i0, i1, i2, i3;
2421 if (chd_get_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE &&
2422 sscanf(metadata, HARD_DISK_METADATA_FORMAT, &i0, &i1, &i2, &i3) == 4)
2423 return i3;
2424
2425 /* look for CD-ROM metadata; if found, then the unit size == CD frame size */
2426 if (chd_get_metadata(chd, CDROM_OLD_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
2427 chd_get_metadata(chd, CDROM_TRACK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
2428 chd_get_metadata(chd, CDROM_TRACK_METADATA2_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
2429 chd_get_metadata(chd, GDROM_OLD_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
2430 chd_get_metadata(chd, GDROM_TRACK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE)
2431 return CD_FRAME_SIZE;
2432
2433 /* otherwise, just map 1:1 with the hunk size */
2434 return chd->header.hunkbytes;
2435}
2436
2437/*-------------------------------------------------
2438 header_read - read a CHD header into the
2439 internal data structure
2440-------------------------------------------------*/
2441
2442static chd_error header_read(chd_file *chd, chd_header *header)
2443{
2444 UINT8 rawheader[CHD_MAX_HEADER_SIZE];
2445 UINT32 count;
2446
2447 /* punt if NULL */
2448 if (header == NULL)
2449 return CHDERR_INVALID_PARAMETER;
2450
2451 /* punt if invalid file */
2452 if (chd->file == NULL)
2453 return CHDERR_INVALID_FILE;
2454
2455 /* seek and read */
2456 core_fseek(chd->file, 0, SEEK_SET);
2457 count = core_fread(chd->file, rawheader, sizeof(rawheader));
2458 if (count != sizeof(rawheader))
2459 return CHDERR_READ_ERROR;
2460
2461 /* verify the tag */
2462 if (strncmp((char *)rawheader, "MComprHD", 8) != 0)
2463 return CHDERR_INVALID_DATA;
2464
2465 /* extract the direct data */
2466 memset(header, 0, sizeof(*header));
2467 header->length = get_bigendian_uint32(&rawheader[8]);
2468 header->version = get_bigendian_uint32(&rawheader[12]);
2469
2470 /* make sure it's a version we understand */
2471 if (header->version == 0 || header->version > CHD_HEADER_VERSION)
2472 return CHDERR_UNSUPPORTED_VERSION;
2473
2474 /* make sure the length is expected */
2475 if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) ||
2476 (header->version == 2 && header->length != CHD_V2_HEADER_SIZE) ||
2477 (header->version == 3 && header->length != CHD_V3_HEADER_SIZE) ||
2478 (header->version == 4 && header->length != CHD_V4_HEADER_SIZE) ||
2479 (header->version == 5 && header->length != CHD_V5_HEADER_SIZE))
2480
2481 return CHDERR_INVALID_DATA;
2482
2483 /* extract the common data */
2484 header->flags = get_bigendian_uint32(&rawheader[16]);
2485 header->compression[0] = get_bigendian_uint32(&rawheader[20]);
2486 header->compression[1] = CHD_CODEC_NONE;
2487 header->compression[2] = CHD_CODEC_NONE;
2488 header->compression[3] = CHD_CODEC_NONE;
2489
2490 /* extract the V1/V2-specific data */
2491 if (header->version < 3)
2492 {
2493 int seclen = (header->version == 1) ? CHD_V1_SECTOR_SIZE : get_bigendian_uint32(&rawheader[76]);
2494 header->obsolete_hunksize = get_bigendian_uint32(&rawheader[24]);
2495 header->totalhunks = get_bigendian_uint32(&rawheader[28]);
2496 header->obsolete_cylinders = get_bigendian_uint32(&rawheader[32]);
2497 header->obsolete_heads = get_bigendian_uint32(&rawheader[36]);
2498 header->obsolete_sectors = get_bigendian_uint32(&rawheader[40]);
2499 memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES);
2500 memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES);
2501 header->logicalbytes = (UINT64)header->obsolete_cylinders * (UINT64)header->obsolete_heads * (UINT64)header->obsolete_sectors * (UINT64)seclen;
2502 header->hunkbytes = seclen * header->obsolete_hunksize;
2503 header->unitbytes = header_guess_unitbytes(chd);
9e052883 2504 if (header->unitbytes == 0)
2505 return CHDERR_INVALID_DATA;
b24e7fce 2506 header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
2507 header->metaoffset = 0;
2508 }
2509
2510 /* extract the V3-specific data */
2511 else if (header->version == 3)
2512 {
2513 header->totalhunks = get_bigendian_uint32(&rawheader[24]);
2514 header->logicalbytes = get_bigendian_uint64(&rawheader[28]);
2515 header->metaoffset = get_bigendian_uint64(&rawheader[36]);
2516 memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES);
2517 memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES);
2518 header->hunkbytes = get_bigendian_uint32(&rawheader[76]);
2519 header->unitbytes = header_guess_unitbytes(chd);
9e052883 2520 if (header->unitbytes == 0)
2521 return CHDERR_INVALID_DATA;
b24e7fce 2522 header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
2523 memcpy(header->sha1, &rawheader[80], CHD_SHA1_BYTES);
2524 memcpy(header->parentsha1, &rawheader[100], CHD_SHA1_BYTES);
2525 }
2526
2527 /* extract the V4-specific data */
2528 else if (header->version == 4)
2529 {
2530 header->totalhunks = get_bigendian_uint32(&rawheader[24]);
2531 header->logicalbytes = get_bigendian_uint64(&rawheader[28]);
2532 header->metaoffset = get_bigendian_uint64(&rawheader[36]);
2533 header->hunkbytes = get_bigendian_uint32(&rawheader[44]);
2534 header->unitbytes = header_guess_unitbytes(chd);
9e052883 2535 if (header->unitbytes == 0)
2536 return CHDERR_INVALID_DATA;
b24e7fce 2537 header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
2538 memcpy(header->sha1, &rawheader[48], CHD_SHA1_BYTES);
2539 memcpy(header->parentsha1, &rawheader[68], CHD_SHA1_BYTES);
2540 memcpy(header->rawsha1, &rawheader[88], CHD_SHA1_BYTES);
2541 }
2542
2543 /* extract the V5-specific data */
2544 else if (header->version == 5)
2545 {
2546 /* TODO */
2547 header->compression[0] = get_bigendian_uint32(&rawheader[16]);
2548 header->compression[1] = get_bigendian_uint32(&rawheader[20]);
2549 header->compression[2] = get_bigendian_uint32(&rawheader[24]);
2550 header->compression[3] = get_bigendian_uint32(&rawheader[28]);
2551 header->logicalbytes = get_bigendian_uint64(&rawheader[32]);
2552 header->mapoffset = get_bigendian_uint64(&rawheader[40]);
2553 header->metaoffset = get_bigendian_uint64(&rawheader[48]);
2554 header->hunkbytes = get_bigendian_uint32(&rawheader[56]);
9e052883 2555 if (header->hunkbytes == 0)
2556 return CHDERR_INVALID_DATA;
b24e7fce 2557 header->hunkcount = (header->logicalbytes + header->hunkbytes - 1) / header->hunkbytes;
2558 header->unitbytes = get_bigendian_uint32(&rawheader[60]);
9e052883 2559 if (header->unitbytes == 0)
2560 return CHDERR_INVALID_DATA;
b24e7fce 2561 header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
2562 memcpy(header->sha1, &rawheader[84], CHD_SHA1_BYTES);
2563 memcpy(header->parentsha1, &rawheader[104], CHD_SHA1_BYTES);
2564 memcpy(header->rawsha1, &rawheader[64], CHD_SHA1_BYTES);
2565
2566 /* determine properties of map entries */
2567 header->mapentrybytes = chd_compressed(header) ? 12 : 4;
2568
2569 /* hack */
2570 header->totalhunks = header->hunkcount;
2571 }
2572
2573 /* Unknown version */
2574 else
2575 {
2576 /* TODO */
2577 }
2578
2579 /* guess it worked */
2580 return CHDERR_NONE;
2581}
2582
2583/***************************************************************************
2584 INTERNAL HUNK READ/WRITE
2585***************************************************************************/
2586
2587/*-------------------------------------------------
2588 hunk_read_compressed - read a compressed
2589 hunk
2590-------------------------------------------------*/
2591
2592static UINT8* hunk_read_compressed(chd_file *chd, UINT64 offset, size_t size)
2593{
2594#ifdef _MSC_VER
2595 size_t bytes;
2596#else
2597 ssize_t bytes;
2598#endif
2599 if (chd->file_cache != NULL)
2600 {
2601 return chd->file_cache + offset;
2602 }
2603 else
2604 {
2605 core_fseek(chd->file, offset, SEEK_SET);
2606 bytes = core_fread(chd->file, chd->compressed, size);
2607 if (bytes != size)
2608 return NULL;
2609 return chd->compressed;
2610 }
2611}
2612
2613/*-------------------------------------------------
2614 hunk_read_uncompressed - read an uncompressed
2615 hunk
2616-------------------------------------------------*/
2617
2618static chd_error hunk_read_uncompressed(chd_file *chd, UINT64 offset, size_t size, UINT8 *dest)
2619{
2620#ifdef _MSC_VER
2621 size_t bytes;
2622#else
2623 ssize_t bytes;
2624#endif
2625 if (chd->file_cache != NULL)
2626 {
2627 memcpy(dest, chd->file_cache + offset, size);
2628 }
2629 else
2630 {
2631 core_fseek(chd->file, offset, SEEK_SET);
2632 bytes = core_fread(chd->file, dest, size);
2633 if (bytes != size)
2634 return CHDERR_READ_ERROR;
2635 }
2636 return CHDERR_NONE;
2637}
2638
2639#ifdef NEED_CACHE_HUNK
2640/*-------------------------------------------------
2641 hunk_read_into_cache - read a hunk into
2642 the CHD's hunk cache
2643-------------------------------------------------*/
2644
2645static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum)
2646{
2647 chd_error err;
2648
2649 /* track the max */
2650 if (hunknum > chd->maxhunk)
2651 chd->maxhunk = hunknum;
2652
2653 /* if we're already in the cache, we're done */
2654 if (chd->cachehunk == hunknum)
2655 return CHDERR_NONE;
2656 chd->cachehunk = ~0;
2657
2658 /* otherwise, read the data */
2659 err = hunk_read_into_memory(chd, hunknum, chd->cache);
2660 if (err != CHDERR_NONE)
2661 return err;
2662
2663 /* mark the hunk successfully cached in */
2664 chd->cachehunk = hunknum;
2665 return CHDERR_NONE;
2666}
2667#endif
2668
2669/*-------------------------------------------------
2670 hunk_read_into_memory - read a hunk into
2671 memory at the given location
2672-------------------------------------------------*/
2673
2674static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest)
2675{
2676 chd_error err;
2677
2678 /* punt if no file */
2679 if (chd->file == NULL)
2680 return CHDERR_INVALID_FILE;
2681
2682 /* return an error if out of range */
2683 if (hunknum >= chd->header.totalhunks)
2684 return CHDERR_HUNK_OUT_OF_RANGE;
2685
2686 if (dest == NULL)
2687 return CHDERR_INVALID_PARAMETER;
2688
2689 if (chd->header.version < 5)
2690 {
2691 map_entry *entry = &chd->map[hunknum];
2692 UINT32 bytes;
2693 UINT8* compressed_bytes;
2694
2695 /* switch off the entry type */
2696 switch (entry->flags & MAP_ENTRY_FLAG_TYPE_MASK)
2697 {
2698 /* compressed data */
2699 case V34_MAP_ENTRY_TYPE_COMPRESSED:
2700 {
2701 void *codec = NULL;
2702
2703 /* read it into the decompression buffer */
2704 compressed_bytes = hunk_read_compressed(chd, entry->offset, entry->length);
2705 if (compressed_bytes == NULL)
648db22b 2706 {
b24e7fce 2707 return CHDERR_READ_ERROR;
648db22b 2708 }
b24e7fce 2709
2710 /* now decompress using the codec */
2711 err = CHDERR_NONE;
2712 codec = &chd->zlib_codec_data;
2713 if (chd->codecintf[0]->decompress != NULL)
2714 err = (*chd->codecintf[0]->decompress)(codec, compressed_bytes, entry->length, dest, chd->header.hunkbytes);
2715 if (err != CHDERR_NONE)
2716 return err;
2717 break;
2718 }
2719
2720 /* uncompressed data */
2721 case V34_MAP_ENTRY_TYPE_UNCOMPRESSED:
2722 err = hunk_read_uncompressed(chd, entry->offset, chd->header.hunkbytes, dest);
2723 if (err != CHDERR_NONE)
2724 return err;
2725 break;
2726
2727 /* mini-compressed data */
2728 case V34_MAP_ENTRY_TYPE_MINI:
2729 put_bigendian_uint64(&dest[0], entry->offset);
2730 for (bytes = 8; bytes < chd->header.hunkbytes; bytes++)
2731 dest[bytes] = dest[bytes - 8];
2732 break;
2733
2734 /* self-referenced data */
2735 case V34_MAP_ENTRY_TYPE_SELF_HUNK:
2736#ifdef NEED_CACHE_HUNK
2737 if (chd->cachehunk == entry->offset && dest == chd->cache)
2738 break;
2739#endif
2740 return hunk_read_into_memory(chd, entry->offset, dest);
2741
2742 /* parent-referenced data */
2743 case V34_MAP_ENTRY_TYPE_PARENT_HUNK:
2744 err = hunk_read_into_memory(chd->parent, entry->offset, dest);
2745 if (err != CHDERR_NONE)
2746 return err;
2747 break;
2748 }
2749 return CHDERR_NONE;
2750 }
2751 else
2752 {
2753 void* codec = NULL;
2754 /* get a pointer to the map entry */
2755 uint64_t blockoffs;
2756 uint32_t blocklen;
2757#ifdef VERIFY_BLOCK_CRC
2758 uint16_t blockcrc;
2759#endif
2760 uint8_t *rawmap = &chd->header.rawmap[chd->header.mapentrybytes * hunknum];
2761 UINT8* compressed_bytes;
2762
2763 /* uncompressed case */
2764 if (!chd_compressed(&chd->header))
2765 {
2766 blockoffs = (uint64_t)get_bigendian_uint32(rawmap) * (uint64_t)chd->header.hunkbytes;
2767 if (blockoffs != 0) {
2768 core_fseek(chd->file, blockoffs, SEEK_SET);
2769 int result = core_fread(chd->file, dest, chd->header.hunkbytes);
2770 /* TODO
2771 else if (m_parent_missing)
2772 throw CHDERR_REQUIRES_PARENT; */
2773 } else if (chd->parent) {
2774 err = hunk_read_into_memory(chd->parent, hunknum, dest);
2775 if (err != CHDERR_NONE)
2776 return err;
2777 } else {
2778 memset(dest, 0, chd->header.hunkbytes);
2779 }
2780
2781 return CHDERR_NONE;
2782 }
2783
2784 /* compressed case */
2785 blocklen = get_bigendian_uint24(&rawmap[1]);
2786 blockoffs = get_bigendian_uint48(&rawmap[4]);
2787#ifdef VERIFY_BLOCK_CRC
2788 blockcrc = get_bigendian_uint16(&rawmap[10]);
2789#endif
2790 codec = NULL;
2791 switch (rawmap[0])
2792 {
2793 case COMPRESSION_TYPE_0:
2794 case COMPRESSION_TYPE_1:
2795 case COMPRESSION_TYPE_2:
2796 case COMPRESSION_TYPE_3:
2797 compressed_bytes = hunk_read_compressed(chd, blockoffs, blocklen);
2798 if (compressed_bytes == NULL)
2799 return CHDERR_READ_ERROR;
2800 switch (chd->codecintf[rawmap[0]]->compression)
2801 {
b24e7fce 2802 case CHD_CODEC_ZLIB:
2803 codec = &chd->zlib_codec_data;
2804 break;
2805
9e052883 2806 case CHD_CODEC_LZMA:
2807 codec = &chd->lzma_codec_data;
2808 break;
2809
2810 case CHD_CODEC_HUFFMAN:
2811 codec = &chd->huff_codec_data;
2812 break;
2813
2814 case CHD_CODEC_FLAC:
2815 codec = &chd->flac_codec_data;
2816 break;
2817
648db22b 2818 case CHD_CODEC_ZSTD:
2819 codec = &chd->zstd_codec_data;
2820 break;
2821
b24e7fce 2822 case CHD_CODEC_CD_ZLIB:
2823 codec = &chd->cdzl_codec_data;
2824 break;
2825
9e052883 2826 case CHD_CODEC_CD_LZMA:
2827 codec = &chd->cdlz_codec_data;
2828 break;
2829
b24e7fce 2830 case CHD_CODEC_CD_FLAC:
2831 codec = &chd->cdfl_codec_data;
2832 break;
648db22b 2833
2834 case CHD_CODEC_CD_ZSTD:
2835 codec = &chd->cdzs_codec_data;
2836 break;
b24e7fce 2837 }
2838 if (codec==NULL)
2839 return CHDERR_CODEC_ERROR;
2840 err = chd->codecintf[rawmap[0]]->decompress(codec, compressed_bytes, blocklen, dest, chd->header.hunkbytes);
2841 if (err != CHDERR_NONE)
2842 return err;
2843#ifdef VERIFY_BLOCK_CRC
2844 if (crc16(dest, chd->header.hunkbytes) != blockcrc)
2845 return CHDERR_DECOMPRESSION_ERROR;
2846#endif
2847 return CHDERR_NONE;
2848
2849 case COMPRESSION_NONE:
2850 err = hunk_read_uncompressed(chd, blockoffs, blocklen, dest);
2851 if (err != CHDERR_NONE)
2852 return err;
2853#ifdef VERIFY_BLOCK_CRC
2854 if (crc16(dest, chd->header.hunkbytes) != blockcrc)
2855 return CHDERR_DECOMPRESSION_ERROR;
2856#endif
2857 return CHDERR_NONE;
2858
2859 case COMPRESSION_SELF:
2860 return hunk_read_into_memory(chd, blockoffs, dest);
2861
2862 case COMPRESSION_PARENT:
2863 if (chd->parent == NULL)
2864 return CHDERR_REQUIRES_PARENT;
2865 UINT8 units_in_hunk = chd->header.hunkbytes / chd->header.unitbytes;
2866
2867 /* blockoffs is aligned to units_in_hunk */
2868 if (blockoffs % units_in_hunk == 0) {
2869 return hunk_read_into_memory(chd->parent, blockoffs / units_in_hunk, dest);
2870 /* blockoffs is not aligned to units_in_hunk */
2871 } else {
2872 UINT32 unit_in_hunk = blockoffs % units_in_hunk;
2873 UINT8 *buf = malloc(chd->header.hunkbytes);
2874 /* Read first half of hunk which contains blockoffs */
2875 err = hunk_read_into_memory(chd->parent, blockoffs / units_in_hunk, buf);
2876 if (err != CHDERR_NONE) {
2877 free(buf);
2878 return err;
2879 }
2880 memcpy(dest, buf + unit_in_hunk * chd->header.unitbytes, (units_in_hunk - unit_in_hunk) * chd->header.unitbytes);
2881 /* Read second half of hunk which contains blockoffs */
2882 err = hunk_read_into_memory(chd->parent, (blockoffs / units_in_hunk) + 1, buf);
2883 if (err != CHDERR_NONE) {
2884 free(buf);
2885 return err;
2886 }
2887 memcpy(dest + (units_in_hunk - unit_in_hunk) * chd->header.unitbytes, buf, unit_in_hunk * chd->header.unitbytes);
2888 free(buf);
2889 }
2890 }
2891 return CHDERR_NONE;
2892 }
2893
2894 /* We should not reach this code */
2895 return CHDERR_DECOMPRESSION_ERROR;
2896}
2897
2898/***************************************************************************
2899 INTERNAL MAP ACCESS
2900***************************************************************************/
2901
2902/*-------------------------------------------------
2903 map_read - read the initial sector map
2904-------------------------------------------------*/
2905
2906static chd_error map_read(chd_file *chd)
2907{
2908 UINT32 entrysize = (chd->header.version < 3) ? OLD_MAP_ENTRY_SIZE : MAP_ENTRY_SIZE;
2909 UINT8 raw_map_entries[MAP_STACK_ENTRIES * MAP_ENTRY_SIZE];
2910 UINT64 fileoffset, maxoffset = 0;
2911 UINT8 cookie[MAP_ENTRY_SIZE];
2912 UINT32 count;
2913 chd_error err;
9e052883 2914 UINT32 i;
b24e7fce 2915
2916 /* first allocate memory */
2917 chd->map = (map_entry *)malloc(sizeof(chd->map[0]) * chd->header.totalhunks);
2918 if (!chd->map)
2919 return CHDERR_OUT_OF_MEMORY;
2920
2921 /* read the map entries in in chunks and extract to the map list */
2922 fileoffset = chd->header.length;
2923 for (i = 0; i < chd->header.totalhunks; i += MAP_STACK_ENTRIES)
2924 {
2925 /* compute how many entries this time */
2926 int entries = chd->header.totalhunks - i, j;
2927 if (entries > MAP_STACK_ENTRIES)
2928 entries = MAP_STACK_ENTRIES;
2929
2930 /* read that many */
2931 core_fseek(chd->file, fileoffset, SEEK_SET);
2932 count = core_fread(chd->file, raw_map_entries, entries * entrysize);
2933 if (count != entries * entrysize)
2934 {
2935 err = CHDERR_READ_ERROR;
2936 goto cleanup;
2937 }
2938 fileoffset += entries * entrysize;
2939
2940 /* process that many */
2941 if (entrysize == MAP_ENTRY_SIZE)
2942 {
2943 for (j = 0; j < entries; j++)
2944 map_extract(&raw_map_entries[j * MAP_ENTRY_SIZE], &chd->map[i + j]);
2945 }
2946 else
2947 {
2948 for (j = 0; j < entries; j++)
2949 map_extract_old(&raw_map_entries[j * OLD_MAP_ENTRY_SIZE], &chd->map[i + j], chd->header.hunkbytes);
2950 }
2951
2952 /* track the maximum offset */
2953 for (j = 0; j < entries; j++)
2954 if ((chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == V34_MAP_ENTRY_TYPE_COMPRESSED ||
2955 (chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == V34_MAP_ENTRY_TYPE_UNCOMPRESSED)
2956 maxoffset = MAX(maxoffset, chd->map[i + j].offset + chd->map[i + j].length);
2957 }
2958
2959 /* verify the cookie */
2960 core_fseek(chd->file, fileoffset, SEEK_SET);
2961 count = core_fread(chd->file, &cookie, entrysize);
2962 if (count != entrysize || memcmp(&cookie, END_OF_LIST_COOKIE, entrysize))
2963 {
2964 err = CHDERR_INVALID_FILE;
2965 goto cleanup;
2966 }
2967
2968 /* verify the length */
2969 if (maxoffset > core_fsize(chd->file))
2970 {
2971 err = CHDERR_INVALID_FILE;
2972 goto cleanup;
2973 }
2974 return CHDERR_NONE;
2975
2976cleanup:
2977 if (chd->map)
2978 free(chd->map);
2979 chd->map = NULL;
2980 return err;
2981}
2982
2983/***************************************************************************
2984 INTERNAL METADATA ACCESS
2985***************************************************************************/
2986
2987/*-------------------------------------------------
2988 metadata_find_entry - find a metadata entry
2989-------------------------------------------------*/
2990
2991static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry)
2992{
2993 /* start at the beginning */
2994 metaentry->offset = chd->header.metaoffset;
2995 metaentry->prev = 0;
2996
2997 /* loop until we run out of options */
2998 while (metaentry->offset != 0)
2999 {
3000 UINT8 raw_meta_header[METADATA_HEADER_SIZE];
3001 UINT32 count;
3002
3003 /* read the raw header */
3004 core_fseek(chd->file, metaentry->offset, SEEK_SET);
3005 count = core_fread(chd->file, raw_meta_header, sizeof(raw_meta_header));
3006 if (count != sizeof(raw_meta_header))
3007 break;
3008
3009 /* extract the data */
3010 metaentry->metatag = get_bigendian_uint32(&raw_meta_header[0]);
3011 metaentry->length = get_bigendian_uint32(&raw_meta_header[4]);
3012 metaentry->next = get_bigendian_uint64(&raw_meta_header[8]);
3013
3014 /* flags are encoded in the high byte of length */
3015 metaentry->flags = metaentry->length >> 24;
3016 metaentry->length &= 0x00ffffff;
3017
3018 /* if we got a match, proceed */
3019 if (metatag == CHDMETATAG_WILDCARD || metaentry->metatag == metatag)
3020 if (metaindex-- == 0)
3021 return CHDERR_NONE;
3022
3023 /* no match, fetch the next link */
3024 metaentry->prev = metaentry->offset;
3025 metaentry->offset = metaentry->next;
3026 }
3027
3028 /* if we get here, we didn't find it */
3029 return CHDERR_METADATA_NOT_FOUND;
3030}
3031
3032/***************************************************************************
3033 ZLIB COMPRESSION CODEC
3034***************************************************************************/
3035
3036/*-------------------------------------------------
3037 zlib_codec_init - initialize the ZLIB codec
3038-------------------------------------------------*/
3039
3040static chd_error zlib_codec_init(void *codec, uint32_t hunkbytes)
3041{
3042 int zerr;
3043 chd_error err;
3044 zlib_codec_data *data = (zlib_codec_data*)codec;
3045
3046 /* clear the buffers */
3047 memset(data, 0, sizeof(zlib_codec_data));
3048
3049 /* init the inflater first */
3050 data->inflater.next_in = (Bytef *)data; /* bogus, but that's ok */
3051 data->inflater.avail_in = 0;
3052 data->inflater.zalloc = zlib_fast_alloc;
3053 data->inflater.zfree = zlib_fast_free;
3054 data->inflater.opaque = &data->allocator;
3055 zerr = inflateInit2(&data->inflater, -MAX_WBITS);
3056
3057 /* convert errors */
3058 if (zerr == Z_MEM_ERROR)
3059 err = CHDERR_OUT_OF_MEMORY;
3060 else if (zerr != Z_OK)
3061 err = CHDERR_CODEC_ERROR;
3062 else
3063 err = CHDERR_NONE;
3064
b24e7fce 3065 return err;
3066}
3067
3068/*-------------------------------------------------
3069 zlib_codec_free - free data for the ZLIB
3070 codec
3071-------------------------------------------------*/
3072
3073static void zlib_codec_free(void *codec)
3074{
3075 zlib_codec_data *data = (zlib_codec_data *)codec;
3076
3077 /* deinit the streams */
3078 if (data != NULL)
3079 {
b24e7fce 3080 inflateEnd(&data->inflater);
3081
3082 /* free our fast memory */
3083 zlib_allocator_free(&data->allocator);
3084 }
3085}
3086
3087/*-------------------------------------------------
3088 zlib_codec_decompress - decompress data using
3089 the ZLIB codec
3090-------------------------------------------------*/
3091
3092static chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
3093{
3094 zlib_codec_data *data = (zlib_codec_data *)codec;
3095 int zerr;
3096
3097 /* reset the decompressor */
3098 data->inflater.next_in = (Bytef *)src;
3099 data->inflater.avail_in = complen;
3100 data->inflater.total_in = 0;
3101 data->inflater.next_out = (Bytef *)dest;
3102 data->inflater.avail_out = destlen;
3103 data->inflater.total_out = 0;
3104 zerr = inflateReset(&data->inflater);
3105 if (zerr != Z_OK)
3106 return CHDERR_DECOMPRESSION_ERROR;
3107
3108 /* do it */
3109 zerr = inflate(&data->inflater, Z_FINISH);
3110 if (data->inflater.total_out != destlen)
3111 return CHDERR_DECOMPRESSION_ERROR;
3112
3113 return CHDERR_NONE;
3114}
3115
3116/*-------------------------------------------------
3117 zlib_fast_alloc - fast malloc for ZLIB, which
3118 allocates and frees memory frequently
3119-------------------------------------------------*/
3120
3121/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */
3122#define ZLIB_MIN_ALIGNMENT_BITS 512
3123#define ZLIB_MIN_ALIGNMENT_BYTES (ZLIB_MIN_ALIGNMENT_BITS / 8)
3124
3125static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
3126{
3127 zlib_allocator *alloc = (zlib_allocator *)opaque;
3128 uintptr_t paddr = 0;
3129 UINT32 *ptr;
3130 int i;
3131
3132 /* compute the size, rounding to the nearest 1k */
3133 size = (size * items + 0x3ff) & ~0x3ff;
3134
3135 /* reuse a hunk if we can */
3136 for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
3137 {
3138 ptr = alloc->allocptr[i];
3139 if (ptr && size == *ptr)
3140 {
3141 /* set the low bit of the size so we don't match next time */
3142 *ptr |= 1;
3143
3144 /* return aligned block address */
3145 return (voidpf)(alloc->allocptr2[i]);
3146 }
3147 }
3148
3149 /* alloc a new one */
3150 ptr = (UINT32 *)malloc(size + sizeof(UINT32) + ZLIB_MIN_ALIGNMENT_BYTES);
3151 if (!ptr)
3152 return NULL;
3153
3154 /* put it into the list */
3155 for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
3156 if (!alloc->allocptr[i])
3157 {
3158 alloc->allocptr[i] = ptr;
3159 paddr = (((uintptr_t)ptr) + sizeof(UINT32) + (ZLIB_MIN_ALIGNMENT_BYTES-1)) & (~(ZLIB_MIN_ALIGNMENT_BYTES-1));
3160 alloc->allocptr2[i] = (uint32_t*)paddr;
3161 break;
3162 }
3163
3164 /* set the low bit of the size so we don't match next time */
3165 *ptr = size | 1;
3166
3167 /* return aligned block address */
3168 return (voidpf)paddr;
3169}
3170
3171/*-------------------------------------------------
3172 zlib_fast_free - fast free for ZLIB, which
3173 allocates and frees memory frequently
3174-------------------------------------------------*/
3175
3176static void zlib_fast_free(voidpf opaque, voidpf address)
3177{
3178 zlib_allocator *alloc = (zlib_allocator *)opaque;
3179 UINT32 *ptr = (UINT32 *)address;
3180 int i;
3181
3182 /* find the hunk */
3183 for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
3184 if (ptr == alloc->allocptr2[i])
3185 {
3186 /* clear the low bit of the size to allow matches */
3187 *(alloc->allocptr[i]) &= ~1;
3188 return;
3189 }
3190}
3191
3192/*-------------------------------------------------
3193 zlib_allocator_free
3194-------------------------------------------------*/
3195static void zlib_allocator_free(voidpf opaque)
3196{
3197 zlib_allocator *alloc = (zlib_allocator *)opaque;
3198 int i;
3199
3200 for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
3201 if (alloc->allocptr[i])
3202 free(alloc->allocptr[i]);
3203}
9e052883 3204
3205/*-------------------------------------------------
3206 core_stdio_fopen - core_file wrapper over fopen
3207-------------------------------------------------*/
3208static core_file *core_stdio_fopen(char const *path) {
3209 core_file *file = malloc(sizeof(core_file));
3210 if (!file)
3211 return NULL;
3212 if (!(file->argp = fopen(path, "rb"))) {
3213 free(file);
3214 return NULL;
3215 }
3216 file->fsize = core_stdio_fsize;
3217 file->fread = core_stdio_fread;
3218 file->fclose = core_stdio_fclose;
3219 file->fseek = core_stdio_fseek;
3220 return file;
3221}
3222
3223/*-------------------------------------------------
3224 core_stdio_fsize - core_file function for
3225 getting file size with stdio
3226-------------------------------------------------*/
3227static UINT64 core_stdio_fsize(core_file *file) {
3228#if defined USE_LIBRETRO_VFS
3229 #define core_stdio_fseek_impl fseek
3230 #define core_stdio_ftell_impl ftell
3231#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WIN64__)
3232 #define core_stdio_fseek_impl _fseeki64
3233 #define core_stdio_ftell_impl _ftelli64
3234#elif defined(_LARGEFILE_SOURCE) && defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64
3235 #define core_stdio_fseek_impl fseeko64
3236 #define core_stdio_ftell_impl ftello64
3237#elif defined(__PS3__) && !defined(__PSL1GHT__) || defined(__SWITCH__) || defined(__vita__)
3238 #define core_stdio_fseek_impl(x,y,z) fseek(x,(off_t)y,z)
3239 #define core_stdio_ftell_impl(x) (off_t)ftell(x)
3240#else
3241 #define core_stdio_fseek_impl fseeko
3242 #define core_stdio_ftell_impl ftello
3243#endif
3244 FILE *fp;
3245 UINT64 p, rv;
3246 fp = (FILE*)file->argp;
3247
3248 p = core_stdio_ftell_impl(fp);
3249 core_stdio_fseek_impl(fp, 0, SEEK_END);
3250 rv = core_stdio_ftell_impl(fp);
3251 core_stdio_fseek_impl(fp, p, SEEK_SET);
3252 return rv;
3253}
3254
3255/*-------------------------------------------------
3256 core_stdio_fread - core_file wrapper over fread
3257-------------------------------------------------*/
3258static size_t core_stdio_fread(void *ptr, size_t size, size_t nmemb, core_file *file) {
3259 return fread(ptr, size, nmemb, (FILE*)file->argp);
3260}
3261
3262/*-------------------------------------------------
3263 core_stdio_fclose - core_file wrapper over fclose
3264-------------------------------------------------*/
3265static int core_stdio_fclose(core_file *file) {
3266 int err = fclose((FILE*)file->argp);
3267 if (err == 0)
3268 free(file);
3269 return err;
3270}
3271
3272/*-------------------------------------------------
3273 core_stdio_fclose_nonowner - don't call fclose because
3274 we don't own the underlying file, but do free the
3275 core_file because libchdr did allocate that itself.
3276-------------------------------------------------*/
3277static int core_stdio_fclose_nonowner(core_file *file) {
3278 free(file);
3279 return 0;
3280}
3281
3282/*-------------------------------------------------
3283 core_stdio_fseek - core_file wrapper over fclose
3284-------------------------------------------------*/
3285static int core_stdio_fseek(core_file* file, INT64 offset, int whence) {
3286 return core_stdio_fseek_impl((FILE*)file->argp, offset, whence);
3287}