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