chd 0.1.1

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