From 3eb1f14701d0612a9cf2bfb232fd27b0221a9d1f Mon Sep 17 00:00:00 2001 From: "R. Belmont" Date: Fri, 18 Apr 2014 02:05:33 +0000 Subject: [PATCH] chd updates: [MetalliC] - Bugfixed byte order for GD-ROM audio tracks so FLAC compression is effective - Fixed uninitialized struct on MSVC (and possibly other) builds nw: this will change the SHA1s of every GD-ROM CHD in MAME; a patch to reflect that is pending (the old images still work, they just take a little more space than is necessary). "chdman copy" suffices to upgrade; no downloading is necessary. --- src/lib/util/cdrom.c | 45 +++++++++++++++++++++++---------- src/lib/util/cdrom.h | 1 + src/lib/util/chd.c | 1 + src/lib/util/chd.h | 3 ++- src/lib/util/chdcd.c | 2 ++ src/tools/chdman.c | 60 ++++++++++++++++++++++++++++++++++++++++---- 6 files changed, 93 insertions(+), 19 deletions(-) diff --git a/src/lib/util/cdrom.c b/src/lib/util/cdrom.c index e2419ea1a0b..2d2dbddb006 100644 --- a/src/lib/util/cdrom.c +++ b/src/lib/util/cdrom.c @@ -142,6 +142,7 @@ cdrom_file *cdrom_open(const char *inputfile) file = new cdrom_file(); if (file == NULL) return NULL; + memset(file, 0, sizeof(cdrom_file)); /* setup the CDROM module and get the disc info */ chd_error err = chdcd_parse_toc(inputfile, file->cdtoc, file->track_info); @@ -239,6 +240,7 @@ cdrom_file *cdrom_open(chd_file *chd) file = new cdrom_file(); if (file == NULL) return NULL; + memset(file, 0, sizeof(cdrom_file)); /* fill in the data */ file->chd = chd; @@ -330,32 +332,44 @@ void cdrom_close(cdrom_file *file) chd_error read_partial_sector(cdrom_file *file, void *dest, UINT32 lbasector, UINT32 chdsector, UINT32 tracknum, UINT32 startoffs, UINT32 length) { + chd_error result = CHDERR_NONE; + bool needswap = false; + // if this is pregap info that isn't actually in the file, just return blank data if ((file->cdtoc.tracks[tracknum].pgdatasize == 0) && (lbasector < (file->cdtoc.tracks[tracknum].logframeofs + file->cdtoc.tracks[tracknum].pregap))) { // printf("PG missing sector: LBA %d, trklog %d\n", lbasector, file->cdtoc.tracks[tracknum].logframeofs); memset(dest, 0, length); - return CHDERR_NONE; + return result; } // if a CHD, just read if (file->chd != NULL) - return file->chd->read_bytes(UINT64(chdsector) * UINT64(CD_FRAME_SIZE) + startoffs, dest, length); + { + result = file->chd->read_bytes(UINT64(chdsector) * UINT64(CD_FRAME_SIZE) + startoffs, dest, length); + /* swap CDDA in the case of LE GDROMs */ + if ((file->cdtoc.flags & CD_FLAG_GDROMLE) && (file->cdtoc.tracks[tracknum].trktype == CD_TRACK_AUDIO)) + needswap = true; + } + else + { + // else read from the appropriate file + core_file *srcfile = file->fhandle[tracknum]; - // else read from the appropriate file - core_file *srcfile = file->fhandle[tracknum]; + UINT64 sourcefileoffset = file->track_info.track[tracknum].offset; + int bytespersector = file->cdtoc.tracks[tracknum].datasize + file->cdtoc.tracks[tracknum].subsize; - UINT64 sourcefileoffset = file->track_info.track[tracknum].offset; - int bytespersector = file->cdtoc.tracks[tracknum].datasize + file->cdtoc.tracks[tracknum].subsize; + sourcefileoffset += chdsector * bytespersector + startoffs; - sourcefileoffset += chdsector * bytespersector + startoffs; + // printf("Reading sector %d from track %d at offset %lld\n", chdsector, tracknum, sourcefileoffset); -// printf("Reading sector %d from track %d at offset %lld\n", chdsector, tracknum, sourcefileoffset); + core_fseek(srcfile, sourcefileoffset, SEEK_SET); + core_fread(srcfile, dest, length); - core_fseek(srcfile, sourcefileoffset, SEEK_SET); - core_fread(srcfile, dest, length); + needswap = file->track_info.track[tracknum].swap; + } - if (file->track_info.track[tracknum].swap) + if (needswap) { UINT8 *buffer = (UINT8 *)dest - startoffs; for (int swapindex = startoffs; swapindex < 2352; swapindex += 2 ) @@ -365,7 +379,7 @@ chd_error read_partial_sector(cdrom_file *file, void *dest, UINT32 lbasector, UI buffer[ swapindex + 1 ] = swaptemp; } } - return CHDERR_NONE; + return result; } @@ -839,7 +853,12 @@ chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc) } else { - err = chd->read_metadata(GDROM_TRACK_METADATA_TAG, toc->numtrks, metadata); + err = chd->read_metadata(GDROM_OLD_METADATA_TAG, toc->numtrks, metadata); + if (err == CHDERR_NONE) + /* legacy GDROM track was detected */ + toc->flags |= CD_FLAG_GDROMLE; + else + err = chd->read_metadata(GDROM_TRACK_METADATA_TAG, toc->numtrks, metadata); if (err == CHDERR_NONE) { diff --git a/src/lib/util/cdrom.h b/src/lib/util/cdrom.h index 68538f6a298..426bcf36a36 100644 --- a/src/lib/util/cdrom.h +++ b/src/lib/util/cdrom.h @@ -56,6 +56,7 @@ enum }; #define CD_FLAG_GDROM 0x00000001 // disc is a GD-ROM, all tracks should be stored with GD-ROM metadata +#define CD_FLAG_GDROMLE 0x00000002 // legacy GD-ROM, with little-endian CDDA data /*************************************************************************** TYPE DEFINITIONS diff --git a/src/lib/util/chd.c b/src/lib/util/chd.c index 68332479312..7a32f2262d5 100644 --- a/src/lib/util/chd.c +++ b/src/lib/util/chd.c @@ -1412,6 +1412,7 @@ UINT32 chd_file::guess_unitbytes() if (read_metadata(CDROM_OLD_METADATA_TAG, 0, metadata) == CHDERR_NONE || read_metadata(CDROM_TRACK_METADATA_TAG, 0, metadata) == CHDERR_NONE || read_metadata(CDROM_TRACK_METADATA2_TAG, 0, metadata) == CHDERR_NONE || + read_metadata(GDROM_OLD_METADATA_TAG, 0, metadata) == CHDERR_NONE || read_metadata(GDROM_TRACK_METADATA_TAG, 0, metadata) == CHDERR_NONE) return CD_FRAME_SIZE; diff --git a/src/lib/util/chd.h b/src/lib/util/chd.h index cc0f493cc0b..9beb674cc47 100644 --- a/src/lib/util/chd.h +++ b/src/lib/util/chd.h @@ -225,7 +225,8 @@ const chd_metadata_tag CDROM_TRACK_METADATA_TAG = CHD_MAKE_TAG('C','H','T','R'); extern const char *CDROM_TRACK_METADATA_FORMAT; const chd_metadata_tag CDROM_TRACK_METADATA2_TAG = CHD_MAKE_TAG('C','H','T','2'); extern const char *CDROM_TRACK_METADATA2_FORMAT; -const chd_metadata_tag GDROM_TRACK_METADATA_TAG = CHD_MAKE_TAG('C','H','G','T'); +const chd_metadata_tag GDROM_OLD_METADATA_TAG = CHD_MAKE_TAG('C','H','G','T'); +const chd_metadata_tag GDROM_TRACK_METADATA_TAG = CHD_MAKE_TAG('C', 'H', 'G', 'D'); extern const char *GDROM_TRACK_METADATA_FORMAT; // standard A/V metadata diff --git a/src/lib/util/chdcd.c b/src/lib/util/chdcd.c index 9059d65aacb..8690cc65ffa 100644 --- a/src/lib/util/chdcd.c +++ b/src/lib/util/chdcd.c @@ -634,6 +634,7 @@ static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_ outtoc.tracks[trknum].datasize = 0; outtoc.tracks[trknum].subtype = CD_SUB_NONE; outtoc.tracks[trknum].subsize = 0; + outtoc.tracks[trknum].pgsub = CD_SUB_NONE; tok=strtok(NULL," "); outtoc.tracks[trknum].physframeofs=atoi(tok); @@ -658,6 +659,7 @@ static chd_error chdcd_parse_gdi(const char *tocfname, cdrom_toc &outtoc, chdcd_ { outtoc.tracks[trknum].trktype=CD_TRACK_AUDIO; outtoc.tracks[trknum].datasize=2352; + outinfo.track[trknum].swap = true; } astring name; diff --git a/src/tools/chdman.c b/src/tools/chdman.c index 5c1068c8099..1fe97a68f3c 100644 --- a/src/tools/chdman.c +++ b/src/tools/chdman.c @@ -215,7 +215,8 @@ class chd_chdfile_compressor : public chd_file_compressor public: // construction/destruction chd_chdfile_compressor(chd_file &file, UINT64 offset = 0, UINT64 maxoffset = ~0) - : m_file(file), + : m_toc(NULL), + m_file(file), m_offset(offset), m_maxoffset(MIN(maxoffset, file.logical_bytes())) { } @@ -230,9 +231,46 @@ public: chd_error err = m_file.read_bytes(offset, dest, length); if (err != CHDERR_NONE) throw err; + + // if we have TOC - detect audio sectors and swap data + if (m_toc) + { + assert(offset % CD_FRAME_SIZE == 0); + assert(length % CD_FRAME_SIZE == 0); + + int startlba = offset / CD_FRAME_SIZE; + int lenlba = length / CD_FRAME_SIZE; + UINT8 *_dest = reinterpret_cast(dest); + + for (int chdlba = 0; chdlba < lenlba; chdlba++) + { + // find current frame's track number + int tracknum = m_toc->numtrks; + for (int track = 0; track < m_toc->numtrks; track++) + if ((chdlba + startlba) < m_toc->tracks[track + 1].chdframeofs) + { + tracknum = track; + break; + } + // is it audio ? + if (m_toc->tracks[tracknum].trktype != CD_TRACK_AUDIO) + continue; + // byteswap if yes + int dataoffset = chdlba * CD_FRAME_SIZE; + for (UINT32 swapindex = dataoffset; swapindex < (dataoffset + CD_MAX_SECTOR_DATA); swapindex += 2) + { + UINT8 temp = _dest[swapindex]; + _dest[swapindex] = _dest[swapindex + 1]; + _dest[swapindex + 1] = temp; + } + } + } + return length; } +const cdrom_toc * m_toc; + private: // internal state chd_file & m_file; @@ -2042,8 +2080,10 @@ static void do_copy(parameters_t ¶ms) memcpy(compression, s_default_ld_compression, sizeof(compression)); else if (input_chd.read_metadata(CDROM_OLD_METADATA_TAG, 0, metadata) == CHDERR_NONE || input_chd.read_metadata(CDROM_TRACK_METADATA_TAG, 0, metadata) == CHDERR_NONE || - input_chd.read_metadata(CDROM_TRACK_METADATA2_TAG, 0, metadata) == CHDERR_NONE) - memcpy(compression, s_default_cd_compression, sizeof(compression)); + input_chd.read_metadata(CDROM_TRACK_METADATA2_TAG, 0, metadata) == CHDERR_NONE || + input_chd.read_metadata(GDROM_OLD_METADATA_TAG, 0, metadata) == CHDERR_NONE || + input_chd.read_metadata(GDROM_TRACK_METADATA_TAG, 0, metadata) == CHDERR_NONE) + memcpy(compression, s_default_cd_compression, sizeof(compression)); else memcpy(compression, s_default_raw_compression, sizeof(compression)); } @@ -2087,6 +2127,7 @@ static void do_copy(parameters_t ¶ms) UINT8 metaflags; UINT32 index = 0; bool redo_cd = false; + bool cdda_swap = false; for (err = input_chd.read_metadata(CHDMETATAG_WILDCARD, index++, metadata, metatag, metaflags); err == CHDERR_NONE; err = input_chd.read_metadata(CHDMETATAG_WILDCARD, index++, metadata, metatag, metaflags)) { // if this is an old CD-CHD tag, note that we want to re-do it @@ -2095,6 +2136,12 @@ static void do_copy(parameters_t ¶ms) redo_cd = true; continue; } + // if this is old GD tag we want re-do it and swap CDDA + if (metatag == GDROM_OLD_METADATA_TAG) + { + cdda_swap = redo_cd = true; + continue; + } // otherwise, clone it err = chd->write_metadata(metatag, CHDMETAINDEX_APPEND, metadata, metaflags); @@ -2112,6 +2159,8 @@ static void do_copy(parameters_t ¶ms) err = cdrom_write_metadata(chd, toc); if (err != CHDERR_NONE) report_error(1, "Error writing upgraded CD metadata: %s", chd_file::error_string(err)); + if (cdda_swap) + chd->m_toc = toc; } // compress it generically @@ -2354,8 +2403,9 @@ static void do_extract_cd(parameters_t ¶ms) // read the data cdrom_read_data(cdrom, cdrom_get_track_start_phys(cdrom, tracknum) + frame, &buffer[bufferoffs], trackinfo.trktype, true); - // for CDRWin, audio tracks must be reversed - if ((mode == MODE_CUEBIN) && (trackinfo.trktype == CD_TRACK_AUDIO)) + // for CDRWin and GDI audio tracks must be reversed + // in the case of GDI and CHD version < 5 we assuming source CHD image is GDROM so audio tracks is already reversed + if (((mode == MODE_GDI && input_chd.version() > 4) || (mode == MODE_CUEBIN)) && (trackinfo.trktype == CD_TRACK_AUDIO)) for (int swapindex = 0; swapindex < trackinfo.datasize; swapindex += 2) { UINT8 swaptemp = buffer[bufferoffs + swapindex];