Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support to extractcd for GDROM .cue/.bin #7717

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
f0e2bbd
refactoring for GDROM .cue/.bin extract
nathanhand Dec 28, 2020
40d4dc0
initial support for GDROM .cue/.bin extract
nathanhand Dec 28, 2020
867460d
successful extract GDROM Type I
nathanhand Dec 28, 2020
d0d9d03
successful extract GDROM Type II
nathanhand Dec 28, 2020
15ed072
successful extract GDROM Type III
nathanhand Dec 29, 2020
b77029d
added EDC support, required for TYPE_III GDROM
nathanhand Jan 27, 2021
9faaf32
use constexpr to resolve at compile time
nathanhand Jan 29, 2021
eb23b45
added technical details for the EDC polynomial
nathanhand Jan 29, 2021
e79599f
lowercase hex values to match existing style
nathanhand Jan 29, 2021
38a7fd7
gdrom classifications dont belong in cdrom.h or cdrom.cpp
nathanhand Jan 29, 2021
e8d8825
more information on the CRC polynomial
nathanhand Jan 29, 2021
82a9b11
resolve conflict with upstream master
nathanhand Jan 29, 2021
0780c51
Merge branch 'master' into extract_gdrom_cue
Jan 29, 2021
f57a477
use std::string same as upstream master
nathanhand Jan 29, 2021
2f5b224
Merge branch 'extract_gdrom_cue' of https://github.com/nhand42/mame i…
nathanhand Jan 29, 2021
dde21b1
generate CRC lookup table for EDC at runtime
nathanhand Jan 30, 2021
b08d627
use bit shifts rather than casts to avoid endian issues
nathanhand Jan 30, 2021
0d4bb49
gdrom should be internal to the CHD code
nathanhand Jan 30, 2021
2e90c84
control the scope of table
nathanhand Feb 2, 2021
d55e9bf
init at compile time to avoid separate init func
nathanhand Feb 3, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions scripts/src/lib.lua
Expand Up @@ -37,6 +37,8 @@ project "utils"
MAME_DIR .. "src/lib/util/bitmap.h",
MAME_DIR .. "src/lib/util/cdrom.cpp",
MAME_DIR .. "src/lib/util/cdrom.h",
MAME_DIR .. "src/lib/util/gdrom.cpp",
MAME_DIR .. "src/lib/util/gdrom.h",
MAME_DIR .. "src/lib/util/chd.cpp",
MAME_DIR .. "src/lib/util/chd.h",
MAME_DIR .. "src/lib/util/chdcd.cpp",
Expand Down
138 changes: 129 additions & 9 deletions src/lib/util/cdrom.cpp
Expand Up @@ -73,26 +73,29 @@ void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2);
***************************************************************************/

/** @brief offset within sector. */
const int SYNC_OFFSET = 0x000;
constexpr int SYNC_OFFSET = 0x000;
/** @brief 12 bytes. */
const int SYNC_NUM_BYTES = 12;
constexpr int SYNC_NUM_BYTES = 12;

/** @brief offset within sector. */
const int MODE_OFFSET = 0x00f;
constexpr int MODE_OFFSET = 0x00f;

/** @brief EDC offsets */
constexpr int EDC_MODE1_OFFSET = 16+2048;

/** @brief offset within sector. */
const int ECC_P_OFFSET = 0x81c;
constexpr int ECC_P_OFFSET = 0x81c;
/** @brief 2 lots of 86. */
const int ECC_P_NUM_BYTES = 86;
constexpr int ECC_P_NUM_BYTES = 86;
/** @brief 24 bytes each. */
const int ECC_P_COMP = 24;
constexpr int ECC_P_COMP = 24;

/** @brief The ECC q offset. */
const int ECC_Q_OFFSET = ECC_P_OFFSET + 2 * ECC_P_NUM_BYTES;
constexpr int ECC_Q_OFFSET = ECC_P_OFFSET + 2 * ECC_P_NUM_BYTES;
/** @brief 2 lots of 52. */
const int ECC_Q_NUM_BYTES = 52;
constexpr int ECC_Q_NUM_BYTES = 52;
/** @brief 43 bytes each. */
const int ECC_Q_COMP = 43;
constexpr int ECC_Q_COMP = 43;



Expand Down Expand Up @@ -1552,6 +1555,96 @@ static const uint16_t qoffsets[ECC_Q_NUM_BYTES][ECC_Q_COMP] =
};


/**
* @brief -------------------------------------------------
* EDC_crctable - each value represents a CRC used
* in calculating the EDC for MODE1 sectors. the
* CRC polynomial is from ECMA 130 section 14.3
*
* P(X) = (X^16 + x^15 + x^2 + 1) * (x^16 + x^2 + x + 1)
*
* where least significant parity bit (x^0) is the
* most significant bit of the checksum. it can
* be regenerated using these poly parameters into
* Rocksoft Model CRC Algorithm
*
* Width : 4 bytes
* Poly : 0x8001801BL
* Reverse : TRUE
*
* credit to cdrtools for the EDC table, code and
* technical details.
* -------------------------------------------------.
*/

static const uint32_t EDC_crctable[256] =
{
0x00000000, 0x90910101, 0x91210201, 0x01b00300,
0x92410401, 0x02d00500, 0x03600600, 0x93f10701,
0x94810801, 0x04100900, 0x05a00a00, 0x95310b01,
0x06c00c00, 0x96510d01, 0x97e10e01, 0x07700f00,
0x99011001, 0x09901100, 0x08201200, 0x98b11301,
0x0b401400, 0x9bd11501, 0x9a611601, 0x0af01700,
0x0d801800, 0x9d111901, 0x9ca11a01, 0x0c301b00,
0x9fc11c01, 0x0f501d00, 0x0ee01e00, 0x9e711f01,
0x82012001, 0x12902100, 0x13202200, 0x83b12301,
0x10402400, 0x80d12501, 0x81612601, 0x11f02700,
0x16802800, 0x86112901, 0x87a12a01, 0x17302b00,
0x84c12c01, 0x14502d00, 0x15e02e00, 0x85712f01,
0x1b003000, 0x8b913101, 0x8a213201, 0x1ab03300,
0x89413401, 0x19d03500, 0x18603600, 0x88f13701,
0x8f813801, 0x1f103900, 0x1ea03a00, 0x8e313b01,
0x1dc03c00, 0x8d513d01, 0x8ce13e01, 0x1c703f00,
0xb4014001, 0x24904100, 0x25204200, 0xb5b14301,
0x26404400, 0xb6d14501, 0xb7614601, 0x27f04700,
0x20804800, 0xb0114901, 0xb1a14a01, 0x21304b00,
0xb2c14c01, 0x22504d00, 0x23e04e00, 0xb3714f01,
0x2d005000, 0xbd915101, 0xbc215201, 0x2cb05300,
0xbf415401, 0x2fd05500, 0x2e605600, 0xbef15701,
0xb9815801, 0x29105900, 0x28a05a00, 0xb8315b01,
0x2bc05c00, 0xbb515d01, 0xbae15e01, 0x2a705f00,
0x36006000, 0xa6916101, 0xa7216201, 0x37b06300,
0xa4416401, 0x34d06500, 0x35606600, 0xa5f16701,
0xa2816801, 0x32106900, 0x33a06a00, 0xa3316b01,
0x30c06c00, 0xa0516d01, 0xa1e16e01, 0x31706f00,
0xaf017001, 0x3f907100, 0x3e207200, 0xaeb17301,
0x3d407400, 0xadd17501, 0xac617601, 0x3cf07700,
0x3b807800, 0xab117901, 0xaaa17a01, 0x3a307b00,
0xa9c17c01, 0x39507d00, 0x38e07e00, 0xa8717f01,
0xd8018001, 0x48908100, 0x49208200, 0xd9b18301,
0x4a408400, 0xdad18501, 0xdb618601, 0x4bf08700,
0x4c808800, 0xdc118901, 0xdda18a01, 0x4d308b00,
0xdec18c01, 0x4e508d00, 0x4fe08e00, 0xdf718f01,
0x41009000, 0xd1919101, 0xd0219201, 0x40b09300,
0xd3419401, 0x43d09500, 0x42609600, 0xd2f19701,
0xd5819801, 0x45109900, 0x44a09a00, 0xd4319b01,
0x47c09c00, 0xd7519d01, 0xd6e19e01, 0x46709f00,
0x5a00a000, 0xca91a101, 0xcb21a201, 0x5bb0a300,
0xc841a401, 0x58d0a500, 0x5960a600, 0xc9f1a701,
0xce81a801, 0x5e10a900, 0x5fa0aa00, 0xcf31ab01,
0x5cc0ac00, 0xcc51ad01, 0xcde1ae01, 0x5d70af00,
0xc301b001, 0x5390b100, 0x5220b200, 0xc2b1b301,
0x5140b400, 0xc1d1b501, 0xc061b601, 0x50f0b700,
0x5780b800, 0xc711b901, 0xc6a1ba01, 0x5630bb00,
0xc5c1bc01, 0x5550bd00, 0x54e0be00, 0xc471bf01,
0x6c00c000, 0xfc91c101, 0xfd21c201, 0x6db0c300,
0xfe41c401, 0x6ed0c500, 0x6f60c600, 0xfff1c701,
0xf881c801, 0x6810c900, 0x69a0ca00, 0xf931cb01,
0x6ac0cc00, 0xfa51cd01, 0xfbe1ce01, 0x6b70cf00,
0xf501d001, 0x6590d100, 0x6420d200, 0xf4b1d301,
0x6740d400, 0xf7d1d501, 0xf661d601, 0x66f0d700,
0x6180d800, 0xf111d901, 0xf0a1da01, 0x6030db00,
0xf3c1dc01, 0x6350dd00, 0x62e0de00, 0xf271df01,
0xee01e001, 0x7e90e100, 0x7f20e200, 0xefb1e301,
0x7c40e400, 0xecd1e501, 0xed61e601, 0x7df0e700,
0x7a80e800, 0xea11e901, 0xeba1ea01, 0x7b30eb00,
0xe8c1ec01, 0x7850ed00, 0x79e0ee00, 0xe971ef01,
0x7700f000, 0xe791f101, 0xe621f201, 0x76b0f300,
0xe541f401, 0x75d0f500, 0x7460f600, 0xe4f1f701,
0xe381f801, 0x7310f900, 0x72a0fa00, 0xe231fb01,
0x71c0fc00, 0xe151fd01, 0xe0e1fe01, 0x7070ff00,
};

//-------------------------------------------------
// ecc_source_byte - return data from the sector
// at the given offset, masking anything
Expand Down Expand Up @@ -1625,6 +1718,33 @@ bool ecc_verify(const uint8_t *sector)
return true;
}

/**
* @fn void edc_generate(uint8_t *sector)
*
* @brief -------------------------------------------------
* edc_generate - generate the EDC checksum for a sector, overwriting any
* existing checksum, code is only valid for MODE1 sectors
* -------------------------------------------------.
*
* @param [in,out] sector If non-null, the sector.
*/
void edc_generate(uint8_t *sector)
{
uint32_t result = 0;
for (int byte = 0; byte < EDC_MODE1_OFFSET; byte += 4)
{
result = EDC_crctable[(result ^ sector[byte+0]) & 0xffL] ^ (result >> 8);
result = EDC_crctable[(result ^ sector[byte+1]) & 0xffL] ^ (result >> 8);
result = EDC_crctable[(result ^ sector[byte+2]) & 0xffL] ^ (result >> 8);
result = EDC_crctable[(result ^ sector[byte+3]) & 0xffL] ^ (result >> 8);
}

sector[EDC_MODE1_OFFSET+0] = ((uint8_t *) &result)[0];
sector[EDC_MODE1_OFFSET+1] = ((uint8_t *) &result)[1];
sector[EDC_MODE1_OFFSET+2] = ((uint8_t *) &result)[2];
sector[EDC_MODE1_OFFSET+3] = ((uint8_t *) &result)[3];
This conversation was marked as resolved.
Show resolved Hide resolved
}

/**
* @fn void ecc_generate(uint8_t *sector)
*
Expand Down
4 changes: 4 additions & 0 deletions src/lib/util/cdrom.h
Expand Up @@ -58,6 +58,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
***************************************************************************/
Expand Down Expand Up @@ -144,6 +145,9 @@ bool ecc_verify(const uint8_t *sector);
void ecc_generate(uint8_t *sector);
void ecc_clear(uint8_t *sector);

// EDC utilities
void edc_generate(uint8_t *sector);



/***************************************************************************
Expand Down
47 changes: 6 additions & 41 deletions src/lib/util/chdcd.cpp
Expand Up @@ -15,6 +15,7 @@
#include "chdcd.h"
#include "corefile.h"
#include "corestr.h"
#include "gdrom.h"



Expand All @@ -37,19 +38,6 @@
#define TOKENIZE i = tokenize( linebuffer, i, sizeof(linebuffer), token, sizeof(token) );


enum gdi_area {
SINGLE_DENSITY,
HIGH_DENSITY
};

enum gdi_pattern {
TYPE_UNKNOWN = 0,
TYPE_I,
TYPE_II,
TYPE_III,
TYPE_III_SPLIT
};


/***************************************************************************
GLOBAL VARIABLES
Expand Down Expand Up @@ -1226,8 +1214,7 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac
std::string lastfname;
uint32_t wavlen, wavoffs;
std::string path = std::string(tocfname);
enum gdi_area current_area = SINGLE_DENSITY;
enum gdi_pattern disc_pattern = TYPE_UNKNOWN;
enum gdrom_area current_area = GDROM_SINGLE_DENSITY;

infile = fopen(tocfname, "rt");
path = get_file_path(path);
Expand Down Expand Up @@ -1256,14 +1243,14 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac
/* single-density area starts LBA = 0 */
if (!strncmp(linebuffer, "REM SINGLE-DENSITY AREA", 23))
{
current_area = SINGLE_DENSITY;
current_area = GDROM_SINGLE_DENSITY;
continue;
}

/* high-density area starts LBA = 45000 */
if (!strncmp(linebuffer, "REM HIGH-DENSITY AREA", 21))
{
current_area = HIGH_DENSITY;
current_area = GDROM_HIGH_DENSITY;
continue;
}

Expand Down Expand Up @@ -1518,28 +1505,6 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac
}
}

/*
* Dreamcast patterns are identified by track types and number of tracks
*/
if (outtoc.numtrks > 4 && outtoc.tracks[outtoc.numtrks-1].pgtype == CD_TRACK_MODE1_RAW)
{
if (outtoc.tracks[outtoc.numtrks-2].pgtype == CD_TRACK_AUDIO)
disc_pattern = TYPE_III_SPLIT;
else
disc_pattern = TYPE_III;
}
else if (outtoc.numtrks > 3)
{
if (outtoc.tracks[outtoc.numtrks-1].pgtype == CD_TRACK_AUDIO)
disc_pattern = TYPE_II;
else
disc_pattern = TYPE_III;
}
else if (outtoc.numtrks == 3)
{
disc_pattern = TYPE_I;
}

/*
* Strip pregaps from Redump tracks and adjust the LBA offset to match TOSEC layout
*/
Expand Down Expand Up @@ -1582,7 +1547,7 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac
/*
* Special handling for TYPE_III_SPLIT, pregap in last track contains 75 frames audio and 150 frames data
*/
if (disc_pattern == TYPE_III_SPLIT)
if (gdrom_identify_pattern(&outtoc) == GDROM_TYPE_III_SPLIT)
{
assert(outtoc.tracks[outtoc.numtrks-1].pregap == 225);

Expand All @@ -1602,7 +1567,7 @@ chd_error chdcd_parse_gdicue(const char *tocfname, cdrom_toc &outtoc, chdcd_trac
*/
for (trknum = 1; trknum < outtoc.numtrks; trknum++)
{
if (outtoc.tracks[trknum].multicuearea == HIGH_DENSITY && outtoc.tracks[trknum-1].multicuearea == SINGLE_DENSITY)
if (outtoc.tracks[trknum].multicuearea == GDROM_HIGH_DENSITY && outtoc.tracks[trknum-1].multicuearea == GDROM_SINGLE_DENSITY)
{
outtoc.tracks[trknum].physframeofs = 45000;
int dif=outtoc.tracks[trknum].physframeofs-(outtoc.tracks[trknum-1].frames+outtoc.tracks[trknum-1].physframeofs);
Expand Down
51 changes: 51 additions & 0 deletions src/lib/util/gdrom.cpp
@@ -0,0 +1,51 @@
// license:BSD-3-Clause
/***************************************************************************

gdrom.cpp

GDROM routines

***************************************************************************/


#include "cdrom.h"
#include "gdrom.h"


/*---------------------------------------------------------------------------------------
gdrom_identify_pattern - Dreamcast has well-known standardised GDROM patterns
----------------------------------------------------------------------------------------*/

/**
* Dreamcast GDROM patterns are identified by track types and number of tracks
*
* Pattern I - (SD) DATA + AUDIO, (HD) DATA
* Pattern II - (SD) DATA + AUDIO, (HD) DATA + ... + AUDIO
* Pattern III - (SD) DATA + AUDIO, (HD) DATA + ... + DATA
*
* And a III variant when two HD DATA tracks are split by one or more AUDIO tracks.
*/

enum gdrom_pattern gdrom_identify_pattern(const cdrom_toc *toc)
{
if (toc->numtrks > 4 && toc->tracks[toc->numtrks-1].trktype == CD_TRACK_MODE1_RAW)
{
if (toc->tracks[toc->numtrks-2].trktype == CD_TRACK_AUDIO)
return GDROM_TYPE_III_SPLIT;
else
return GDROM_TYPE_III;
}
else if (toc->numtrks > 3)
{
if (toc->tracks[toc->numtrks-1].trktype == CD_TRACK_AUDIO)
return GDROM_TYPE_II;
else
return GDROM_TYPE_III;
}
else if (toc->numtrks == 3)
{
return GDROM_TYPE_I;
}

return GDROM_TYPE_UNKNOWN;
}
41 changes: 41 additions & 0 deletions src/lib/util/gdrom.h
@@ -0,0 +1,41 @@
// license:BSD-3-Clause
/***************************************************************************

gdrom.h

Definitions used in GDROM routines

***************************************************************************/

#ifndef MAME_UTIL_GDROM_H
#define MAME_UTIL_GDROM_H

#pragma once

/***************************************************************************
CONSTANTS
***************************************************************************/

enum gdrom_area
{
GDROM_SINGLE_DENSITY = 0,
GDROM_HIGH_DENSITY
};

enum gdrom_pattern
{
GDROM_TYPE_UNKNOWN = 0,
GDROM_TYPE_I,
GDROM_TYPE_II,
GDROM_TYPE_III,
GDROM_TYPE_III_SPLIT
};

/***************************************************************************
FUNCTION PROTOTYPES
***************************************************************************/

/* GDROM utilities */
enum gdrom_pattern gdrom_identify_pattern(const cdrom_toc *toc);

#endif // MAME_UTIL_GDROM_H