1 
2 #include "chdtypes.h"
3 
4 #include "chd.h"
5 #include "hashing.h"
6 #include "chdcdrom.h"
7 #include "coretmpl.h"
8 #include "bitstream.h"
9 #include "huffman.h"
10 
11 // standard metadata formats
12 const char *HARD_DISK_METADATA_FORMAT = "CYLS:%d,HEADS:%d,SECS:%d,BPS:%d";
13 const char *CDROM_TRACK_METADATA_FORMAT = "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d";
14 const char *CDROM_TRACK_METADATA2_FORMAT = "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d";
15 const char *GDROM_TRACK_METADATA_FORMAT = "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PAD:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d";
16 const char *AV_METADATA_FORMAT = "FPS:%d.%06d WIDTH:%d HEIGHT:%d INTERLACED:%d CHANNELS:%d SAMPLERATE:%d";
17 
18 static const UINT32 METADATA_HEADER_SIZE = 16;			// metadata header size
19 
20 static const UINT8 V34_MAP_ENTRY_FLAG_TYPE_MASK	= 0x0f;		// what type of hunk
21 static const UINT8 V34_MAP_ENTRY_FLAG_NO_CRC = 0x10;		// no CRC is present
22 
23 
24 
25 // V3-V4 entry types
26 enum
27 {
28 	V34_MAP_ENTRY_TYPE_INVALID = 0,				// invalid type
29 	V34_MAP_ENTRY_TYPE_COMPRESSED = 1,			// standard compression
30 	V34_MAP_ENTRY_TYPE_UNCOMPRESSED = 2,		// uncompressed data
31 	V34_MAP_ENTRY_TYPE_MINI = 3,				// mini: use offset as raw data
32 	V34_MAP_ENTRY_TYPE_SELF_HUNK = 4,			// same as another hunk in this file
33 	V34_MAP_ENTRY_TYPE_PARENT_HUNK = 5,			// same as a hunk in the parent file
34 	V34_MAP_ENTRY_TYPE_2ND_COMPRESSED = 6		// compressed with secondary algorithm (usually FLAC CDDA)
35 };
36 
37 // V5 compression types
38 enum
39 {
40 	// these types are live when running
41 	COMPRESSION_TYPE_0 = 0,						// codec #0
42 	COMPRESSION_TYPE_1 = 1,						// codec #1
43 	COMPRESSION_TYPE_2 = 2,						// codec #2
44 	COMPRESSION_TYPE_3 = 3,						// codec #3
45 	COMPRESSION_NONE = 4,						// no compression; implicit length = hunkbytes
46 	COMPRESSION_SELF = 5,						// same as another block in this chd
47 	COMPRESSION_PARENT = 6,						// same as a hunk's worth of units in the parent chd
48 
49 	// these additional pseudo-types are used for compressed encodings:
50 	COMPRESSION_RLE_SMALL,						// start of small RLE run (4-bit length)
51 	COMPRESSION_RLE_LARGE,						// start of large RLE run (8-bit length)
52 	COMPRESSION_SELF_0,							// same as the last COMPRESSION_SELF block
53 	COMPRESSION_SELF_1,							// same as the last COMPRESSION_SELF block + 1
54 	COMPRESSION_PARENT_SELF,					// same block in the parent
55 	COMPRESSION_PARENT_0,						// same as the last COMPRESSION_PARENT block
56 	COMPRESSION_PARENT_1						// same as the last COMPRESSION_PARENT block + 1
57 };
58 
59 
60 //**************************************************************************
61 //  TYPE DEFINITIONS
62 //**************************************************************************
63 
64 // ======================> metadata_entry
65 
66 // description of where a metadata entry lives within the file
67 struct chd_file::metadata_entry
68 {
69 	UINT64					offset;			// offset within the file of the header
70 	UINT64					next;			// offset within the file of the next header
71 	UINT64					prev;			// offset within the file of the previous header
72 	UINT32					length;			// length of the metadata
73 	UINT32					metatag;		// metadata tag
74 	UINT8					flags;			// flag bits
75 };
76 
77 
78 // ======================> metadata_hash
79 
80 struct chd_file::metadata_hash
81 {
82 	UINT8					tag[4];			// tag of the metadata in big-endian
83 	sha1_t					sha1;			// hash data
84 };
85 
86 
87 //-------------------------------------------------
88 //  be_read - extract a big-endian number from
89 //  a byte buffer
90 //-------------------------------------------------
91 
be_read(const UINT8 * base,int numbytes)92 inline UINT64 chd_file::be_read(const UINT8 *base, int numbytes)
93 {
94 	UINT64 result = 0;
95 	while (numbytes--)
96 		result = (result << 8) | *base++;
97 	return result;
98 }
99 
100 //-------------------------------------------------
101 //  be_write - write a big-endian number to a byte
102 //  buffer
103 //-------------------------------------------------
104 
be_write(UINT8 * base,UINT64 value,int numbytes)105 inline void chd_file::be_write(UINT8 *base, UINT64 value, int numbytes)
106 {
107 	base += numbytes;
108 	while (numbytes--)
109 	{
110 		*--base = value;
111 		value >>= 8;
112 	}
113 }
114 
115 //-------------------------------------------------
116 //  be_read_sha1 - fetch a sha1_t from a data
117 //  stream in bigendian order
118 //-------------------------------------------------
119 
be_read_sha1(const UINT8 * base)120 inline sha1_t chd_file::be_read_sha1(const UINT8 *base)
121 {
122 	sha1_t result;
123 	memcpy(&result.m_raw[0], base, sizeof(result.m_raw));
124 	return result;
125 }
126 
127 //-------------------------------------------------
128 //  file_read - read from the file at the given
129 //  offset; on failure throw an error
130 //-------------------------------------------------
131 
file_read(UINT64 offset,void * dest,UINT32 length)132 inline void chd_file::file_read(UINT64 offset, void *dest, UINT32 length)
133 {
134 	// no file = failure
135 	if (m_file == NULL)
136 		throw CHDERR_NOT_OPEN;
137 
138 	// seek and read
139 	zfile_fseek(m_file, offset, SEEK_SET);
140 	UINT32 count = zfile_fread(dest, 1, length, m_file);
141 	if (count != length)
142 		throw CHDERR_READ_ERROR;
143 }
144 
145 //-------------------------------------------------
146 //  hunk_info - return information about this
147 //  hunk
148 //-------------------------------------------------
149 
hunk_info(UINT32 hunknum,chd_codec_type & compressor,UINT32 & compbytes)150 chd_error chd_file::hunk_info(UINT32 hunknum, chd_codec_type &compressor, UINT32 &compbytes)
151 {
152 	// error if invalid
153 	if (hunknum >= m_hunkcount)
154 		return CHDERR_HUNK_OUT_OF_RANGE;
155 
156 	// get the map pointer
157 	UINT8 *rawmap;
158 	switch (m_version)
159 	{
160 		// v3/v4 map entries
161 		case 3:
162 		case 4:
163 			rawmap = m_rawmap + 16 * hunknum;
164 			switch (rawmap[15] & V34_MAP_ENTRY_FLAG_TYPE_MASK)
165 			{
166 				case V34_MAP_ENTRY_TYPE_COMPRESSED:
167 					compressor = CHD_CODEC_ZLIB;
168 					compbytes = be_read(&rawmap[12], 2) + (rawmap[14] << 16);
169 					break;
170 
171 				case V34_MAP_ENTRY_TYPE_UNCOMPRESSED:
172 					compressor = CHD_CODEC_NONE;
173 					compbytes = m_hunkbytes;
174 					break;
175 
176 				case V34_MAP_ENTRY_TYPE_MINI:
177 					compressor = CHD_CODEC_MINI;
178 					compbytes = 0;
179 					break;
180 
181 				case V34_MAP_ENTRY_TYPE_SELF_HUNK:
182 					compressor = CHD_CODEC_SELF;
183 					compbytes = 0;
184 					break;
185 
186 				case V34_MAP_ENTRY_TYPE_PARENT_HUNK:
187 					compressor = CHD_CODEC_PARENT;
188 					compbytes = 0;
189 					break;
190 			}
191 			break;
192 
193 		// v5 map entries
194 		case 5:
195 			rawmap = m_rawmap + m_mapentrybytes * hunknum;
196 
197 			// uncompressed case
198 			if (!compressed())
199 			{
200 				if (be_read(&rawmap[0], 4) == 0)
201 				{
202 					compressor = CHD_CODEC_PARENT;
203 					compbytes = 0;
204 				}
205 				else
206 				{
207 					compressor = CHD_CODEC_NONE;
208 					compbytes = m_hunkbytes;
209 				}
210 				break;
211 			}
212 
213 			// compressed case
214 			switch (rawmap[0])
215 			{
216 				case COMPRESSION_TYPE_0:
217 				case COMPRESSION_TYPE_1:
218 				case COMPRESSION_TYPE_2:
219 				case COMPRESSION_TYPE_3:
220 					compressor = m_compression[rawmap[0]];
221 					compbytes = be_read(&rawmap[1], 3);
222 					break;
223 
224 				case COMPRESSION_NONE:
225 					compressor = CHD_CODEC_NONE;
226 					compbytes = m_hunkbytes;
227 					break;
228 
229 				case COMPRESSION_SELF:
230 					compressor = CHD_CODEC_SELF;
231 					compbytes = 0;
232 					break;
233 
234 				case COMPRESSION_PARENT:
235 					compressor = CHD_CODEC_PARENT;
236 					compbytes = 0;
237 					break;
238 			}
239 			break;
240 	}
241 	return CHDERR_NONE;
242 }
243 
244 //-------------------------------------------------
245 //  open - open an existing file for read or
246 //  read/write
247 //-------------------------------------------------
248 
open(struct zfile * file,bool writeable,chd_file * parent)249 chd_error chd_file::open(struct zfile *file, bool writeable, chd_file *parent)
250 {
251 	// make sure we don't already have a file open
252 	if (m_file != NULL)
253 		return CHDERR_ALREADY_OPEN;
254 
255 	// open the file
256 	m_file = file;
257 	m_owns_file = false;
258 	m_parent = parent;
259 	return open_common(writeable);
260 }
261 
262 //-------------------------------------------------
263 //  close - close a CHD file for access
264 //-------------------------------------------------
265 
close()266 void chd_file::close()
267 {
268 	// reset file characteristics
269 	if (m_owns_file && m_file != NULL)
270 		zfile_fclose(m_file);
271 	m_file = NULL;
272 	m_owns_file = false;
273 	m_allow_reads = false;
274 	m_allow_writes = false;
275 
276 	// reset core parameters from the header
277 	m_version = HEADER_VERSION;
278 	m_logicalbytes = 0;
279 	m_mapoffset = 0;
280 	m_metaoffset = 0;
281 	m_hunkbytes = 0;
282 	m_hunkcount = 0;
283 	m_unitbytes = 0;
284 	m_unitcount = 0;
285 	memset(m_compression, 0, sizeof(m_compression));
286 	m_parent = NULL;
287 	m_parent_missing = false;
288 
289 	// reset key offsets within the header
290 	m_mapoffset_offset = 0;
291 	m_metaoffset_offset = 0;
292 	m_sha1_offset = 0;
293 	m_rawsha1_offset = 0;
294 	m_parentsha1_offset = 0;
295 
296 	// reset map information
297 	m_mapentrybytes = 0;
298 	m_rawmap.reset();
299 
300 	// reset compression management
301 	for (int decompnum = 0; decompnum < ARRAY_LENGTH(m_decompressor); decompnum++)
302 	{
303 		delete m_decompressor[decompnum];
304 		m_decompressor[decompnum] = NULL;
305 	}
306 	m_compressed.reset();
307 
308 	// reset caching
309 	m_cache.reset();
310 	m_cachehunk = ~0;
311 }
312 
313 
314 //-------------------------------------------------
315 //  read - read a single hunk from the CHD file
316 //-------------------------------------------------
317 
read_hunk(UINT32 hunknum,void * buffer)318 chd_error chd_file::read_hunk(UINT32 hunknum, void *buffer)
319 {
320 	// wrap this for clean reporting
321 	try
322 	{
323 		// punt if no file
324 		if (m_file == NULL)
325 			throw CHDERR_NOT_OPEN;
326 
327 		// return an error if out of range
328 		if (hunknum >= m_hunkcount)
329 			throw CHDERR_HUNK_OUT_OF_RANGE;
330 
331 		// get a pointer to the map entry
332 		UINT64 blockoffs;
333 		UINT32 blocklen;
334 		UINT32 blockcrc;
335 		UINT8 *rawmap;
336 		UINT8 *dest = reinterpret_cast<UINT8 *>(buffer);
337 		switch (m_version)
338 		{
339 			// v3/v4 map entries
340 			case 3:
341 			case 4:
342 				rawmap = m_rawmap + 16 * hunknum;
343 				blockoffs = be_read(&rawmap[0], 8);
344 				blockcrc = be_read(&rawmap[8], 4);
345 				switch (rawmap[15] & V34_MAP_ENTRY_FLAG_TYPE_MASK)
346 				{
347 					case V34_MAP_ENTRY_TYPE_COMPRESSED:
348 						blocklen = be_read(&rawmap[12], 2) + (rawmap[14] << 16);
349 						file_read(blockoffs, m_compressed, blocklen);
350 						m_decompressor[0]->decompress(m_compressed, blocklen, dest, m_hunkbytes);
351 						if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && dest != NULL && crc32_creator::simple(dest, m_hunkbytes) != blockcrc)
352 							throw CHDERR_DECOMPRESSION_ERROR;
353 						return CHDERR_NONE;
354 
355 					case V34_MAP_ENTRY_TYPE_UNCOMPRESSED:
356 						file_read(blockoffs, dest, m_hunkbytes);
357 						if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && crc32_creator::simple(dest, m_hunkbytes) != blockcrc)
358 							throw CHDERR_DECOMPRESSION_ERROR;
359 						return CHDERR_NONE;
360 
361 					case V34_MAP_ENTRY_TYPE_MINI:
362 						be_write(dest, blockoffs, 8);
363 						for (UINT32 bytes = 8; bytes < m_hunkbytes; bytes++)
364 							dest[bytes] = dest[bytes - 8];
365 						if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && crc32_creator::simple(dest, m_hunkbytes) != blockcrc)
366 							throw CHDERR_DECOMPRESSION_ERROR;
367 						return CHDERR_NONE;
368 
369 					case V34_MAP_ENTRY_TYPE_SELF_HUNK:
370 						return read_hunk(blockoffs, dest);
371 
372 					case V34_MAP_ENTRY_TYPE_PARENT_HUNK:
373 						if (m_parent_missing)
374 							throw CHDERR_REQUIRES_PARENT;
375 						return m_parent->read_hunk(blockoffs, dest);
376 				}
377 				break;
378 
379 			// v5 map entries
380 			case 5:
381 				rawmap = m_rawmap + m_mapentrybytes * hunknum;
382 
383 				// uncompressed case
384 				if (!compressed())
385 				{
386 					blockoffs = UINT64(be_read(rawmap, 4)) * UINT64(m_hunkbytes);
387 					if (blockoffs != 0)
388 						file_read(blockoffs, dest, m_hunkbytes);
389 					else if (m_parent_missing)
390 						throw CHDERR_REQUIRES_PARENT;
391 					else if (m_parent != NULL)
392 						m_parent->read_hunk(hunknum, dest);
393 					else
394 						memset(dest, 0, m_hunkbytes);
395 					return CHDERR_NONE;
396 				}
397 
398 				// compressed case
399 				blocklen = be_read(&rawmap[1], 3);
400 				blockoffs = be_read(&rawmap[4], 6);
401 				blockcrc = be_read(&rawmap[10], 2);
402 				switch (rawmap[0])
403 				{
404 					case COMPRESSION_TYPE_0:
405 					case COMPRESSION_TYPE_1:
406 					case COMPRESSION_TYPE_2:
407 					case COMPRESSION_TYPE_3:
408 						file_read(blockoffs, m_compressed, blocklen);
409 						m_decompressor[rawmap[0]]->decompress(m_compressed, blocklen, dest, m_hunkbytes);
410 						if (!m_decompressor[rawmap[0]]->lossy() && dest != NULL && crc16_creator::simple(dest, m_hunkbytes) != blockcrc)
411 							throw CHDERR_DECOMPRESSION_ERROR;
412 						if (m_decompressor[rawmap[0]]->lossy() && crc16_creator::simple(m_compressed, blocklen) != blockcrc)
413 							throw CHDERR_DECOMPRESSION_ERROR;
414 						return CHDERR_NONE;
415 
416 					case COMPRESSION_NONE:
417 						file_read(blockoffs, dest, m_hunkbytes);
418 						if (crc16_creator::simple(dest, m_hunkbytes) != blockcrc)
419 							throw CHDERR_DECOMPRESSION_ERROR;
420 						return CHDERR_NONE;
421 
422 					case COMPRESSION_SELF:
423 						return read_hunk(blockoffs, dest);
424 
425 					case COMPRESSION_PARENT:
426 						if (m_parent_missing)
427 							throw CHDERR_REQUIRES_PARENT;
428 						return m_parent->read_bytes(UINT64(blockoffs) * UINT64(m_parent->unit_bytes()), dest, m_hunkbytes);
429 				}
430 				break;
431 		}
432 
433 		// if we get here, something was wrong
434 		throw CHDERR_READ_ERROR;
435 	}
436 
437 	// just return errors
438 	catch (chd_error &err)
439 	{
440 		return err;
441 	}
442 }
443 
444 //-------------------------------------------------
445 //  read_bytes - read from the CHD at a byte level,
446 //  using the cache to handle partial hunks
447 //-------------------------------------------------
448 
read_bytes(UINT64 offset,void * buffer,UINT32 bytes)449 chd_error chd_file::read_bytes(UINT64 offset, void *buffer, UINT32 bytes)
450 {
451 	// iterate over hunks
452 	UINT32 first_hunk = offset / m_hunkbytes;
453 	UINT32 last_hunk = (offset + bytes - 1) / m_hunkbytes;
454 	UINT8 *dest = reinterpret_cast<UINT8 *>(buffer);
455 	for (UINT32 curhunk = first_hunk; curhunk <= last_hunk; curhunk++)
456 	{
457 		// determine start/end boundaries
458 		UINT32 startoffs = (curhunk == first_hunk) ? (offset % m_hunkbytes) : 0;
459 		UINT32 endoffs = (curhunk == last_hunk) ? ((offset + bytes - 1) % m_hunkbytes) : (m_hunkbytes - 1);
460 
461 		// if it's a full block, just read directly from disk unless it's the cached hunk
462 		chd_error err = CHDERR_NONE;
463 		if (startoffs == 0 && endoffs == m_hunkbytes - 1 && curhunk != m_cachehunk)
464 			err = read_hunk(curhunk, dest);
465 
466 		// otherwise, read from the cache
467 		else
468 		{
469 			if (curhunk != m_cachehunk)
470 			{
471 				err = read_hunk(curhunk, m_cache);
472 				if (err != CHDERR_NONE)
473 					return err;
474 				m_cachehunk = curhunk;
475 			}
476 			memcpy(dest, &m_cache[startoffs], endoffs + 1 - startoffs);
477 		}
478 
479 		// handle errors and advance
480 		if (err != CHDERR_NONE)
481 			return err;
482 		dest += endoffs + 1 - startoffs;
483 	}
484 	return CHDERR_NONE;
485 }
486 
487 
488 //-------------------------------------------------
489 //  read_metadata - read the indexed metadata
490 //  of the given type
491 //-------------------------------------------------
492 
read_metadata(chd_metadata_tag searchtag,UINT32 searchindex,astring & output)493 chd_error chd_file::read_metadata(chd_metadata_tag searchtag, UINT32 searchindex, astring &output)
494 {
495 	// wrap this for clean reporting
496 	try
497 	{
498 		// if we didn't find it, just return
499 		metadata_entry metaentry;
500 		if (!metadata_find(searchtag, searchindex, metaentry))
501 			throw CHDERR_METADATA_NOT_FOUND;
502 
503 		// read the metadata
504 		// TODO: how to properly allocate a dynamic char buffer?
505 		char* metabuf = new char[metaentry.length+1];
506 		memset(metabuf, 0x00, metaentry.length+1);
507 		file_read(metaentry.offset + METADATA_HEADER_SIZE, metabuf, metaentry.length);
508 		output.cpy(metabuf);
509 		delete[] metabuf;
510 		return CHDERR_NONE;
511 	}
512 
513 	// just return errors
514 	catch (chd_error &err)
515 	{
516 		return err;
517 	}
518 }
519 
read_metadata(chd_metadata_tag searchtag,UINT32 searchindex,dynamic_buffer & output)520 chd_error chd_file::read_metadata(chd_metadata_tag searchtag, UINT32 searchindex, dynamic_buffer &output)
521 {
522 	// wrap this for clean reporting
523 	try
524 	{
525 		// if we didn't find it, just return
526 		metadata_entry metaentry;
527 		if (!metadata_find(searchtag, searchindex, metaentry))
528 			throw CHDERR_METADATA_NOT_FOUND;
529 
530 		// read the metadata
531 		output.resize(metaentry.length);
532 		file_read(metaentry.offset + METADATA_HEADER_SIZE, output, metaentry.length);
533 		return CHDERR_NONE;
534 	}
535 
536 	// just return errors
537 	catch (chd_error &err)
538 	{
539 		return err;
540 	}
541 }
542 
read_metadata(chd_metadata_tag searchtag,UINT32 searchindex,void * output,UINT32 outputlen,UINT32 & resultlen)543 chd_error chd_file::read_metadata(chd_metadata_tag searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 &resultlen)
544 {
545 	// wrap this for clean reporting
546 	try
547 	{
548 		// if we didn't find it, just return
549 		metadata_entry metaentry;
550 		if (!metadata_find(searchtag, searchindex, metaentry))
551 			throw CHDERR_METADATA_NOT_FOUND;
552 
553 		// read the metadata
554 		resultlen = metaentry.length;
555 		file_read(metaentry.offset + METADATA_HEADER_SIZE, output, MIN(outputlen, resultlen));
556 		return CHDERR_NONE;
557 	}
558 
559 	// just return errors
560 	catch (chd_error &err)
561 	{
562 		return err;
563 	}
564 }
565 
read_metadata(chd_metadata_tag searchtag,UINT32 searchindex,dynamic_buffer & output,chd_metadata_tag & resulttag,UINT8 & resultflags)566 chd_error chd_file::read_metadata(chd_metadata_tag searchtag, UINT32 searchindex, dynamic_buffer &output, chd_metadata_tag &resulttag, UINT8 &resultflags)
567 {
568 	// wrap this for clean reporting
569 	try
570 	{
571 		// if we didn't find it, just return
572 		metadata_entry metaentry;
573 		if (!metadata_find(searchtag, searchindex, metaentry))
574 			throw CHDERR_METADATA_NOT_FOUND;
575 
576 		// read the metadata
577 		output.resize(metaentry.length);
578 		file_read(metaentry.offset + METADATA_HEADER_SIZE, output, metaentry.length);
579 		resulttag = metaentry.metatag;
580 		resultflags = metaentry.flags;
581 		return CHDERR_NONE;
582 	}
583 
584 	// just return errors
585 	catch (chd_error &err)
586 	{
587 		return err;
588 	}
589 }
590 
591 
592 //-------------------------------------------------
593 //  guess_unitbytes - for older CHD formats, take
594 //  a guess at the bytes/unit based on metadata
595 //-------------------------------------------------
596 
guess_unitbytes()597 UINT32 chd_file::guess_unitbytes()
598 {
599 	// look for hard disk metadata; if found, then the unit size == sector size
600 	astring metadata;
601 	int i0, i1, i2, i3;
602 	if (read_metadata(HARD_DISK_METADATA_TAG, 0, metadata) == CHDERR_NONE && sscanf(metadata, HARD_DISK_METADATA_FORMAT, &i0, &i1, &i2, &i3) == 4)
603 		return i3;
604 
605 	// look for CD-ROM metadata; if found, then the unit size == CD frame size
606 	if (read_metadata(CDROM_OLD_METADATA_TAG, 0, metadata) == CHDERR_NONE ||
607 		read_metadata(CDROM_TRACK_METADATA_TAG, 0, metadata) == CHDERR_NONE ||
608 		read_metadata(CDROM_TRACK_METADATA2_TAG, 0, metadata) == CHDERR_NONE ||
609 		read_metadata(GDROM_TRACK_METADATA_TAG, 0, metadata) == CHDERR_NONE)
610 		return CD_FRAME_SIZE;
611 
612 	// otherwise, just map 1:1 with the hunk size
613 	return m_hunkbytes;
614 }
615 
616 
617 //-------------------------------------------------
618 //  parse_v3_header - parse the header from a v3
619 //  file and configure core parameters
620 //-------------------------------------------------
621 
parse_v3_header(UINT8 * rawheader,sha1_t & parentsha1)622 void chd_file::parse_v3_header(UINT8 *rawheader, sha1_t &parentsha1)
623 {
624 	// verify header length
625 	if (be_read(&rawheader[8], 4) != V3_HEADER_SIZE)
626 		throw CHDERR_INVALID_FILE;
627 
628 	// extract core info
629 	m_logicalbytes = be_read(&rawheader[28], 8);
630 	m_mapoffset = 120;
631 	m_metaoffset = be_read(&rawheader[36], 8);
632 	m_hunkbytes = be_read(&rawheader[76], 4);
633 	m_hunkcount = be_read(&rawheader[24], 4);
634 
635 	// extract parent SHA-1
636 	UINT32 flags = be_read(&rawheader[16], 4);
637 	m_allow_writes = (flags & 2) == 0;
638 
639 	// determine compression
640 	switch (be_read(&rawheader[20], 4))
641 	{
642 		case 0:	m_compression[0] = CHD_CODEC_NONE;		break;
643 		case 1:	m_compression[0] = CHD_CODEC_ZLIB;		break;
644 		case 2:	m_compression[0] = CHD_CODEC_ZLIB;		break;
645 		case 3:	m_compression[0] = CHD_CODEC_AVHUFF;	break;
646 		default: throw CHDERR_UNKNOWN_COMPRESSION;
647 	}
648 	m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC_NONE;
649 
650 	// describe the format
651 	m_mapoffset_offset = 0;
652 	m_metaoffset_offset = 36;
653 	m_sha1_offset = 80;
654 	m_rawsha1_offset = 0;
655 	m_parentsha1_offset = 100;
656 
657 	// determine properties of map entries
658 	m_mapentrybytes = 16;
659 
660 	// extract parent SHA-1
661 	if (flags & 1)
662 		parentsha1 = be_read_sha1(&rawheader[m_parentsha1_offset]);
663 
664 	// guess at the units based on snooping the metadata
665 	m_unitbytes = guess_unitbytes();
666 	m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes;
667 }
668 
669 
670 //-------------------------------------------------
671 //  parse_v4_header - parse the header from a v4
672 //  file and configure core parameters
673 //-------------------------------------------------
674 
parse_v4_header(UINT8 * rawheader,sha1_t & parentsha1)675 void chd_file::parse_v4_header(UINT8 *rawheader, sha1_t &parentsha1)
676 {
677 	// verify header length
678 	if (be_read(&rawheader[8], 4) != V4_HEADER_SIZE)
679 		throw CHDERR_INVALID_FILE;
680 
681 	// extract core info
682 	m_logicalbytes = be_read(&rawheader[28], 8);
683 	m_mapoffset = 108;
684 	m_metaoffset = be_read(&rawheader[36], 8);
685 	m_hunkbytes = be_read(&rawheader[44], 4);
686 	m_hunkcount = be_read(&rawheader[24], 4);
687 
688 	// extract parent SHA-1
689 	UINT32 flags = be_read(&rawheader[16], 4);
690 	m_allow_writes = (flags & 2) == 0;
691 
692 	// determine compression
693 	switch (be_read(&rawheader[20], 4))
694 	{
695 		case 0:	m_compression[0] = CHD_CODEC_NONE;		break;
696 		case 1:	m_compression[0] = CHD_CODEC_ZLIB;		break;
697 		case 2:	m_compression[0] = CHD_CODEC_ZLIB;		break;
698 		case 3:	m_compression[0] = CHD_CODEC_AVHUFF;	break;
699 		default: throw CHDERR_UNKNOWN_COMPRESSION;
700 	}
701 	m_compression[1] = m_compression[2] = m_compression[3] = CHD_CODEC_NONE;
702 
703 	// describe the format
704 	m_mapoffset_offset = 0;
705 	m_metaoffset_offset = 36;
706 	m_sha1_offset = 48;
707 	m_rawsha1_offset = 88;
708 	m_parentsha1_offset = 68;
709 
710 	// determine properties of map entries
711 	m_mapentrybytes = 16;
712 
713 	// extract parent SHA-1
714 	if (flags & 1)
715 		parentsha1 = be_read_sha1(&rawheader[m_parentsha1_offset]);
716 
717 	// guess at the units based on snooping the metadata
718 	m_unitbytes = guess_unitbytes();
719 	m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes;
720 }
721 
722 
723 //-------------------------------------------------
724 //  parse_v5_header - read the header from a v5
725 //  file and configure core parameters
726 //-------------------------------------------------
727 
parse_v5_header(UINT8 * rawheader,sha1_t & parentsha1)728 void chd_file::parse_v5_header(UINT8 *rawheader, sha1_t &parentsha1)
729 {
730 	// verify header length
731 	if (be_read(&rawheader[8], 4) != V5_HEADER_SIZE)
732 		throw CHDERR_INVALID_FILE;
733 
734 	// extract core info
735 	m_logicalbytes = be_read(&rawheader[32], 8);
736 	m_mapoffset = be_read(&rawheader[40], 8);
737 	m_metaoffset = be_read(&rawheader[48], 8);
738 	m_hunkbytes = be_read(&rawheader[56], 4);
739 	m_hunkcount = (m_logicalbytes + m_hunkbytes - 1) / m_hunkbytes;
740 	m_unitbytes = be_read(&rawheader[60], 4);
741 	m_unitcount = (m_logicalbytes + m_unitbytes - 1) / m_unitbytes;
742 
743 	// determine compression
744 	m_compression[0] = be_read(&rawheader[16], 4);
745 	m_compression[1] = be_read(&rawheader[20], 4);
746 	m_compression[2] = be_read(&rawheader[24], 4);
747 	m_compression[3] = be_read(&rawheader[28], 4);
748 
749 	m_allow_writes = !compressed();
750 
751 	// describe the format
752 	m_mapoffset_offset = 40;
753 	m_metaoffset_offset = 48;
754 	m_sha1_offset = 84;
755 	m_rawsha1_offset = 64;
756 	m_parentsha1_offset = 104;
757 
758 	// determine properties of map entries
759 	m_mapentrybytes = compressed() ? 12 : 4;
760 
761 	// extract parent SHA-1
762 	parentsha1 = be_read_sha1(&rawheader[m_parentsha1_offset]);
763 }
764 
765 
766 //-------------------------------------------------
767 //  open_common - common path when opening an
768 //  existing CHD file for input
769 //-------------------------------------------------
770 
open_common(bool writeable)771 chd_error chd_file::open_common(bool writeable)
772 {
773 	// wrap in try for proper error handling
774 	try
775 	{
776 		// reads are always permitted
777 		m_allow_reads = true;
778 
779 		// read the raw header
780 		UINT8 rawheader[MAX_HEADER_SIZE];
781 		file_read(0, rawheader, sizeof(rawheader));
782 
783 		// verify the signature
784 		if (memcmp(rawheader, "MComprHD", 8) != 0)
785 			throw CHDERR_INVALID_FILE;
786 
787 		// only allow writes to the most recent version
788 		m_version = be_read(&rawheader[12], 4);
789 		if (writeable && m_version < HEADER_VERSION)
790 			throw CHDERR_UNSUPPORTED_VERSION;
791 
792 		// read the header if we support it
793 		sha1_t parentsha1 = sha1_t::null;
794 		switch (m_version)
795 		{
796 			case 3:		parse_v3_header(rawheader, parentsha1);	break;
797 			case 4:		parse_v4_header(rawheader, parentsha1);	break;
798 			case 5:		parse_v5_header(rawheader, parentsha1);	break;
799 			default:	throw CHDERR_UNSUPPORTED_VERSION;
800 		}
801 
802 		if (writeable && !m_allow_writes)
803 			throw CHDERR_FILE_NOT_WRITEABLE;
804 
805 		// make sure we have a parent if we need one (and don't if we don't)
806 		if (parentsha1 != sha1_t::null)
807 		{
808 			if (m_parent == NULL)
809 				m_parent_missing = true;
810 			else if (m_parent->sha1() != parentsha1)
811 				throw CHDERR_INVALID_PARENT;
812 		}
813 		else if (m_parent != NULL)
814 			throw CHDERR_INVALID_PARAMETER;
815 
816 		// finish opening the file
817 		create_open_common();
818 		return CHDERR_NONE;
819 	}
820 
821 	// handle errors by closing ourself
822 	catch (chd_error &err)
823 	{
824 		close();
825 		return err;
826 	}
827 }
828 
829 //-------------------------------------------------
830 //  create_open_common - common code for handling
831 //  creation and opening of a file
832 //-------------------------------------------------
833 
create_open_common()834 void chd_file::create_open_common()
835 {
836 	// verify the compression types and initialize the codecs
837 	for (int decompnum = 0; decompnum < ARRAY_LENGTH(m_compression); decompnum++)
838 	{
839 		m_decompressor[decompnum] = chd_codec_list::new_decompressor(m_compression[decompnum], *this);
840 		if (m_decompressor[decompnum] == NULL && m_compression[decompnum] != 0)
841 			throw CHDERR_UNKNOWN_COMPRESSION;
842 	}
843 
844 	// read the map; v5+ compressed drives need to read and decompress their map
845 	m_rawmap.resize(m_hunkcount * m_mapentrybytes);
846 	if (m_version >= 5 && compressed())
847 		decompress_v5_map();
848 	else
849 		file_read(m_mapoffset, m_rawmap, m_rawmap.count());
850 
851 	// allocate the temporary compressed buffer and a buffer for caching
852 	m_compressed.resize(m_hunkbytes);
853 	m_cache.resize(m_hunkbytes);
854 }
855 
856 
857 //-------------------------------------------------
858 //  metadata_find - find a metadata entry
859 //-------------------------------------------------
860 
metadata_find(chd_metadata_tag metatag,INT32 metaindex,metadata_entry & metaentry,bool resume)861 bool chd_file::metadata_find(chd_metadata_tag metatag, INT32 metaindex, metadata_entry &metaentry, bool resume)
862 {
863 	// start at the beginning unless we're resuming a previous search
864 	if (!resume)
865 	{
866 		metaentry.offset = m_metaoffset;
867 		metaentry.prev = 0;
868 	}
869 	else
870 	{
871 		metaentry.prev = metaentry.offset;
872 		metaentry.offset = metaentry.next;
873 	}
874 
875 	// loop until we run out of options
876 	while (metaentry.offset != 0)
877 	{
878 		// read the raw header
879 		UINT8 raw_meta_header[METADATA_HEADER_SIZE];
880 		file_read(metaentry.offset, raw_meta_header, sizeof(raw_meta_header));
881 
882 		// extract the data
883 		metaentry.metatag = be_read(&raw_meta_header[0], 4);
884 		metaentry.flags = raw_meta_header[4];
885 		metaentry.length = be_read(&raw_meta_header[5], 3);
886 		metaentry.next = be_read(&raw_meta_header[8], 8);
887 
888 		// if we got a match, proceed
889 		if (metatag == CHDMETATAG_WILDCARD || metaentry.metatag == metatag)
890 			if (metaindex-- == 0)
891 				return true;
892 
893 		// no match, fetch the next link
894 		metaentry.prev = metaentry.offset;
895 		metaentry.offset = metaentry.next;
896 	}
897 
898 	// if we get here, we didn't find it
899 	return false;
900 }
901 
902 
903 //-------------------------------------------------
904 //  decompress_v5_map - decompress the v5 map
905 //-------------------------------------------------
906 
decompress_v5_map()907 void chd_file::decompress_v5_map()
908 {
909 	// if no offset, we haven't written it yet
910 	if (m_mapoffset == 0)
911 	{
912 		memset(m_rawmap, 0xff, m_rawmap.count());
913 		return;
914 	}
915 
916 	// read the reader
917 	UINT8 rawbuf[16];
918 	file_read(m_mapoffset, rawbuf, sizeof(rawbuf));
919 	UINT32 mapbytes = be_read(&rawbuf[0], 4);
920 	UINT64 firstoffs = be_read(&rawbuf[4], 6);
921 	UINT16 mapcrc = be_read(&rawbuf[10], 2);
922 	UINT8 lengthbits = rawbuf[12];
923 	UINT8 selfbits = rawbuf[13];
924 	UINT8 parentbits = rawbuf[14];
925 
926 	// now read the map
927 	dynamic_buffer compressed(mapbytes);
928 	file_read(m_mapoffset + 16, compressed, mapbytes);
929 	bitstream_in bitbuf(compressed, compressed.count());
930 
931 	// first decode the compression types
932 	huffman_decoder<16, 8> decoder;
933 	huffman_error err = decoder.import_tree_rle(bitbuf);
934 	if (err != HUFFERR_NONE)
935 		throw CHDERR_DECOMPRESSION_ERROR;
936 	UINT8 lastcomp = 0;
937 	int repcount = 0;
938 	for (int hunknum = 0; hunknum < m_hunkcount; hunknum++)
939 	{
940 		UINT8 *rawmap = &m_rawmap[hunknum * 12];
941 		if (repcount > 0)
942 			rawmap[0] = lastcomp, repcount--;
943 		else
944 		{
945 			UINT8 val = decoder.decode_one(bitbuf);
946 			if (val == COMPRESSION_RLE_SMALL)
947 				rawmap[0] = lastcomp, repcount = 2 + decoder.decode_one(bitbuf);
948 			else if (val == COMPRESSION_RLE_LARGE)
949 				rawmap[0] = lastcomp, repcount = 2 + 16 + (decoder.decode_one(bitbuf) << 4), repcount += decoder.decode_one(bitbuf);
950 			else
951 				rawmap[0] = lastcomp = val;
952 		}
953 	}
954 
955 	// then iterate through the hunks and extract the needed data
956 	UINT64 curoffset = firstoffs;
957 	UINT32 last_self = 0;
958 	UINT64 last_parent = 0;
959 	for (int hunknum = 0; hunknum < m_hunkcount; hunknum++)
960 	{
961 		UINT8 *rawmap = &m_rawmap[hunknum * 12];
962 		UINT64 offset = curoffset;
963 		UINT32 length = 0;
964 		UINT16 crc = 0;
965 		switch (rawmap[0])
966 		{
967 			// base types
968 			case COMPRESSION_TYPE_0:
969 			case COMPRESSION_TYPE_1:
970 			case COMPRESSION_TYPE_2:
971 			case COMPRESSION_TYPE_3:
972 				curoffset += length = bitbuf.read(lengthbits);
973 				crc = bitbuf.read(16);
974 				break;
975 
976 			case COMPRESSION_NONE:
977 				curoffset += length = m_hunkbytes;
978 				crc = bitbuf.read(16);
979 				break;
980 
981 			case COMPRESSION_SELF:
982 				last_self = offset = bitbuf.read(selfbits);
983 				break;
984 
985 			case COMPRESSION_PARENT:
986 				offset = bitbuf.read(parentbits);
987 				last_parent = offset;
988 				break;
989 
990 			// pseudo-types; convert into base types
991 			case COMPRESSION_SELF_1:
992 				last_self++;
993 			case COMPRESSION_SELF_0:
994 				rawmap[0] = COMPRESSION_SELF;
995 				offset = last_self;
996 				break;
997 
998 			case COMPRESSION_PARENT_SELF:
999 				rawmap[0] = COMPRESSION_PARENT;
1000 				last_parent = offset = (UINT64(hunknum) * UINT64(m_hunkbytes)) / m_unitbytes;
1001 				break;
1002 
1003 			case COMPRESSION_PARENT_1:
1004 				last_parent += m_hunkbytes / m_unitbytes;
1005 			case COMPRESSION_PARENT_0:
1006 				rawmap[0] = COMPRESSION_PARENT;
1007 				offset = last_parent;
1008 				break;
1009 		}
1010 		be_write(&rawmap[1], length, 3);
1011 		be_write(&rawmap[4], offset, 6);
1012 		be_write(&rawmap[10], crc, 2);
1013 	}
1014 
1015 	// verify the final CRC
1016 	if (crc16_creator::simple(m_rawmap, m_hunkcount * 12) != mapcrc)
1017 		throw CHDERR_DECOMPRESSION_ERROR;
1018 }
1019 
1020 //-------------------------------------------------
1021 //  sha1 - return our SHA1 value
1022 //-------------------------------------------------
1023 
sha1()1024 sha1_t chd_file::sha1()
1025 {
1026 	try
1027 	{
1028 		// read the big-endian version
1029 		UINT8 rawbuf[sizeof(sha1_t)];
1030 		file_read(m_sha1_offset, rawbuf, sizeof(rawbuf));
1031 		return be_read_sha1(rawbuf);
1032 	}
1033 	catch (chd_error &)
1034 	{
1035 		// on failure, return NULL
1036 		return sha1_t::null;
1037 	}
1038 }
1039 
1040 
1041 //-------------------------------------------------
1042 //  raw_sha1 - return our raw SHA1 value
1043 //-------------------------------------------------
1044 
raw_sha1()1045 sha1_t chd_file::raw_sha1()
1046 {
1047 	try
1048 	{
1049 		// determine offset within the file for data-only
1050 		if (m_rawsha1_offset == 0)
1051 			throw CHDERR_UNSUPPORTED_VERSION;
1052 
1053 		// read the big-endian version
1054 		UINT8 rawbuf[sizeof(sha1_t)];
1055 		file_read(m_rawsha1_offset, rawbuf, sizeof(rawbuf));
1056 		return be_read_sha1(rawbuf);
1057 	}
1058 	catch (chd_error &)
1059 	{
1060 		// on failure, return NULL
1061 		return sha1_t::null;
1062 	}
1063 }
1064 
1065 
1066 //-------------------------------------------------
1067 //  parent_sha1 - return our parent's SHA1 value
1068 //-------------------------------------------------
1069 
parent_sha1()1070 sha1_t chd_file::parent_sha1()
1071 {
1072 	try
1073 	{
1074 		// determine offset within the file
1075 		if (m_parentsha1_offset == 0)
1076 			throw CHDERR_UNSUPPORTED_VERSION;
1077 
1078 		// read the big-endian version
1079 		UINT8 rawbuf[sizeof(sha1_t)];
1080 		file_read(m_parentsha1_offset, rawbuf, sizeof(rawbuf));
1081 		return be_read_sha1(rawbuf);
1082 	}
1083 	catch (chd_error &)
1084 	{
1085 		// on failure, return NULL
1086 		return sha1_t::null;
1087 	}
1088 }
1089 
1090 //**************************************************************************
1091 //  CHD FILE MANAGEMENT
1092 //**************************************************************************
1093 
1094 //-------------------------------------------------
1095 //  chd_file - constructor
1096 //-------------------------------------------------
1097 
chd_file()1098 chd_file::chd_file()
1099 	: m_file(NULL),
1100       m_owns_file(false)
1101 {
1102 	// reset state
1103 	memset(m_decompressor, 0, sizeof(m_decompressor));
1104 	close();
1105 }
1106 
1107 
1108 //-------------------------------------------------
1109 //  ~chd_file - destructor
1110 //-------------------------------------------------
1111 
~chd_file()1112 chd_file::~chd_file()
1113 {
1114 	// close any open files
1115 	close();
1116 }
1117