diff options
author | 2022-04-01 11:36:41 +0200 | |
---|---|---|
committer | 2022-04-01 11:36:55 +0200 | |
commit | e4564eb99a5513e4044eecc070cbb09cb689a657 (patch) | |
tree | add3668153b17485e30ba415f0ba8b7feef25acc /src/lib/util/cdrom.h | |
parent | e818533b167a24207e1cbfcee04524b215d001ef (diff) |
cdrom_file: classify. Could use more internal work, but it's a step
Diffstat (limited to 'src/lib/util/cdrom.h')
-rw-r--r-- | src/lib/util/cdrom.h | 412 |
1 files changed, 245 insertions, 167 deletions
diff --git a/src/lib/util/cdrom.h b/src/lib/util/cdrom.h index 1847a1db83a..ee26472d2e7 100644 --- a/src/lib/util/cdrom.h +++ b/src/lib/util/cdrom.h @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Aaron Giles +// copyright-holders:Aaron Giles,R. Belmont /*************************************************************************** cdrom.h @@ -13,175 +13,253 @@ #pragma once #include "chd.h" - +#include "corefile.h" #include "osdcore.h" - - -/*************************************************************************** - CONSTANTS -***************************************************************************/ - -// tracks are padded to a multiple of this many frames -const uint32_t CD_TRACK_PADDING = 4; - -#define CD_MAX_TRACKS (99) /* AFAIK the theoretical limit */ -#define CD_MAX_SECTOR_DATA (2352) -#define CD_MAX_SUBCODE_DATA (96) - -#define CD_FRAME_SIZE (CD_MAX_SECTOR_DATA + CD_MAX_SUBCODE_DATA) -#define CD_FRAMES_PER_HUNK (8) - -#define CD_METADATA_WORDS (1+(CD_MAX_TRACKS * 6)) - -enum -{ - CD_TRACK_MODE1 = 0, /* mode 1 2048 bytes/sector */ - CD_TRACK_MODE1_RAW, /* mode 1 2352 bytes/sector */ - CD_TRACK_MODE2, /* mode 2 2336 bytes/sector */ - CD_TRACK_MODE2_FORM1, /* mode 2 2048 bytes/sector */ - CD_TRACK_MODE2_FORM2, /* mode 2 2324 bytes/sector */ - CD_TRACK_MODE2_FORM_MIX, /* mode 2 2336 bytes/sector */ - CD_TRACK_MODE2_RAW, /* mode 2 2352 bytes / sector */ - CD_TRACK_AUDIO, /* redbook audio track 2352 bytes/sector (588 samples) */ - - CD_TRACK_RAW_DONTCARE /* special flag for cdrom_read_data: just return me whatever is there */ -}; - -enum -{ - CD_SUB_NORMAL = 0, /* "cooked" 96 bytes per sector */ - CD_SUB_RAW, /* raw uninterleaved 96 bytes per sector */ - CD_SUB_NONE /* no subcode data stored */ -}; - -#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 -***************************************************************************/ - -struct cdrom_file; - -struct cdrom_track_info -{ - /* fields used by CHDMAN and in MAME */ - uint32_t trktype; /* track type */ - uint32_t subtype; /* subcode data type */ - uint32_t datasize; /* size of data in each sector of this track */ - uint32_t subsize; /* size of subchannel data in each sector of this track */ - uint32_t frames; /* number of frames in this track */ - uint32_t extraframes; /* number of "spillage" frames in this track */ - uint32_t pregap; /* number of pregap frames */ - uint32_t postgap; /* number of postgap frames */ - uint32_t pgtype; /* type of sectors in pregap */ - uint32_t pgsub; /* type of subchannel data in pregap */ - uint32_t pgdatasize; /* size of data in each sector of the pregap */ - uint32_t pgsubsize; /* size of subchannel data in each sector of the pregap */ - - /* fields used in CHDMAN only */ - uint32_t padframes; /* number of frames of padding to add to the end of the track; needed for GDI */ - uint32_t splitframes; /* number of frames to read from the next file; needed for Redump split-bin GDI */ - - /* fields used in MAME/MESS only */ - uint32_t logframeofs; /* logical frame of actual track data - offset by pregap size if pregap not physically present */ - uint32_t physframeofs; /* physical frame of actual track data in CHD data */ - uint32_t chdframeofs; /* frame number this track starts at on the CHD */ - uint32_t logframes; /* number of frames from logframeofs until end of track data */ - - /* fields used in multi-cue GDI */ - uint32_t multicuearea; -}; - - -struct cdrom_toc -{ - uint32_t numtrks; /* number of tracks */ - uint32_t flags; /* see FLAG_ above */ - cdrom_track_info tracks[CD_MAX_TRACKS]; -}; - - - -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ - -/* base functionality */ -cdrom_file *cdrom_open(chd_file *chd); -void cdrom_close(cdrom_file *file); - -cdrom_file *cdrom_open(const char *inputfile); - -/* core read access */ -uint32_t cdrom_read_data(cdrom_file *file, uint32_t lbasector, void *buffer, uint32_t datatype, bool phys=false); -uint32_t cdrom_read_subcode(cdrom_file *file, uint32_t lbasector, void *buffer, bool phys=false); - -/* handy utilities */ -uint32_t cdrom_get_track(cdrom_file *file, uint32_t frame); -uint32_t cdrom_get_track_start(cdrom_file *file, uint32_t track); -uint32_t cdrom_get_track_start_phys(cdrom_file *file, uint32_t track); -chd_file *cdrom_get_chd(cdrom_file *file); - -/* TOC utilities */ -int cdrom_get_last_track(cdrom_file *file); -int cdrom_get_adr_control(cdrom_file *file, int track); -int cdrom_get_track_type(cdrom_file *file, int track); -const cdrom_toc *cdrom_get_toc(cdrom_file *file); - -/* extra utilities */ -void cdrom_convert_type_string_to_track_info(const char *typestring, cdrom_track_info *info); -void cdrom_convert_type_string_to_pregap_info(const char *typestring, cdrom_track_info *info); -void cdrom_convert_subtype_string_to_track_info(const char *typestring, cdrom_track_info *info); -void cdrom_convert_subtype_string_to_pregap_info(const char *typestring, cdrom_track_info *info); -const char *cdrom_get_type_string(uint32_t trktype); -const char *cdrom_get_subtype_string(uint32_t subtype); -std::error_condition cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc); -std::error_condition cdrom_write_metadata(chd_file *chd, const cdrom_toc *toc); - -// ECC utilities -bool ecc_verify(const uint8_t *sector); -void ecc_generate(uint8_t *sector); -void ecc_clear(uint8_t *sector); - - - -/*************************************************************************** - INLINE FUNCTIONS -***************************************************************************/ - -static inline uint32_t msf_to_lba(uint32_t msf) -{ - return ( ((msf&0x00ff0000)>>16) * 60 * 75) + (((msf&0x0000ff00)>>8) * 75) + ((msf&0x000000ff)>>0); -} - -static inline uint32_t lba_to_msf(uint32_t lba) -{ - uint8_t m, s, f; - - m = lba / (60 * 75); - lba -= m * (60 * 75); - s = lba / 75; - f = lba % 75; - - return ((m / 10) << 20) | ((m % 10) << 16) | +class cdrom_file { +public: + // tracks are padded to a multiple of this many frames + static constexpr uint32_t TRACK_PADDING = 4; + + static constexpr uint32_t MAX_TRACKS = 99; /* AFAIK the theoretical limit */ + static constexpr uint32_t MAX_SECTOR_DATA = 2352; + static constexpr uint32_t MAX_SUBCODE_DATA = 96; + + static constexpr uint32_t FRAME_SIZE = MAX_SECTOR_DATA + MAX_SUBCODE_DATA; + static constexpr uint32_t FRAMES_PER_HUNK = 8; + + static constexpr uint32_t METADATA_WORDS = 1 + MAX_TRACKS * 6; + + enum + { + CD_TRACK_MODE1 = 0, /* mode 1 2048 bytes/sector */ + CD_TRACK_MODE1_RAW, /* mode 1 2352 bytes/sector */ + CD_TRACK_MODE2, /* mode 2 2336 bytes/sector */ + CD_TRACK_MODE2_FORM1, /* mode 2 2048 bytes/sector */ + CD_TRACK_MODE2_FORM2, /* mode 2 2324 bytes/sector */ + CD_TRACK_MODE2_FORM_MIX, /* mode 2 2336 bytes/sector */ + CD_TRACK_MODE2_RAW, /* mode 2 2352 bytes / sector */ + CD_TRACK_AUDIO, /* redbook audio track 2352 bytes/sector (588 samples) */ + + CD_TRACK_RAW_DONTCARE /* special flag for cdrom_read_data: just return me whatever is there */ + }; + + enum + { + CD_SUB_NORMAL = 0, /* "cooked" 96 bytes per sector */ + CD_SUB_RAW, /* raw uninterleaved 96 bytes per sector */ + CD_SUB_NONE /* no subcode data stored */ + }; + + enum + { + CD_FLAG_GDROM = 0x00000001, // disc is a GD-ROM, all tracks should be stored with GD-ROM metadata + CD_FLAG_GDROMLE = 0x00000002 // legacy GD-ROM, with little-endian CDDA data + }; + + struct track_info + { + /* fields used by CHDMAN and in MAME */ + uint32_t trktype; /* track type */ + uint32_t subtype; /* subcode data type */ + uint32_t datasize; /* size of data in each sector of this track */ + uint32_t subsize; /* size of subchannel data in each sector of this track */ + uint32_t frames; /* number of frames in this track */ + uint32_t extraframes; /* number of "spillage" frames in this track */ + uint32_t pregap; /* number of pregap frames */ + uint32_t postgap; /* number of postgap frames */ + uint32_t pgtype; /* type of sectors in pregap */ + uint32_t pgsub; /* type of subchannel data in pregap */ + uint32_t pgdatasize; /* size of data in each sector of the pregap */ + uint32_t pgsubsize; /* size of subchannel data in each sector of the pregap */ + + /* fields used in CHDMAN only */ + uint32_t padframes; /* number of frames of padding to add to the end of the track; needed for GDI */ + uint32_t splitframes; /* number of frames to read from the next file; needed for Redump split-bin GDI */ + + /* fields used in MAME/MESS only */ + uint32_t logframeofs; /* logical frame of actual track data - offset by pregap size if pregap not physically present */ + uint32_t physframeofs; /* physical frame of actual track data in CHD data */ + uint32_t chdframeofs; /* frame number this track starts at on the CHD */ + uint32_t logframes; /* number of frames from logframeofs until end of track data */ + + /* fields used in multi-cue GDI */ + uint32_t multicuearea; + }; + + + struct toc + { + uint32_t numtrks; /* number of tracks */ + uint32_t flags; /* see FLAG_ above */ + track_info tracks[MAX_TRACKS]; + }; + + struct track_input_entry + { + track_input_entry() { reset(); } + void reset() { fname.clear(); offset = idx0offs = idx1offs = 0; swap = false; } + + std::string fname; // filename for each track + uint32_t offset; // offset in the data file for each track + bool swap; // data needs to be byte swapped + uint32_t idx0offs; + uint32_t idx1offs; + }; + + struct track_input_info + { + void reset() { for (auto & elem : track) elem.reset(); } + + track_input_entry track[MAX_TRACKS]; + }; + + + cdrom_file(chd_file *chd); + cdrom_file(const char *inputfile); + ~cdrom_file(); + + + /* core read access */ + bool read_data(uint32_t lbasector, void *buffer, uint32_t datatype, bool phys=false); + bool read_subcode(uint32_t lbasector, void *buffer, bool phys=false); + + /* handy utilities */ + uint32_t get_track(uint32_t frame) const; + uint32_t get_track_start(uint32_t track) const {return cdtoc.tracks[track == 0xaa ? cdtoc.numtrks : track].logframeofs; } + uint32_t get_track_start_phys(uint32_t track) const { return cdtoc.tracks[track == 0xaa ? cdtoc.numtrks : track].physframeofs; } + chd_file *get_chd() const { return chd; } + + /* TOC utilities */ + static std::error_condition parse_nero(const char *tocfname, toc &outtoc, track_input_info &outinfo); + static std::error_condition parse_iso(const char *tocfname, toc &outtoc, track_input_info &outinfo); + static std::error_condition parse_gdi(const char *tocfname, toc &outtoc, track_input_info &outinfo); + static std::error_condition parse_cue(const char *tocfname, toc &outtoc, track_input_info &outinfo); + static bool is_gdicue(const char *tocfname); + static std::error_condition parse_gdicue(const char *tocfname, toc &outtoc, track_input_info &outinfo); + static std::error_condition parse_toc(const char *tocfname, toc &outtoc, track_input_info &outinfo); + int get_last_track() const { return cdtoc.numtrks; } + int get_adr_control(int track) const { return track == 0xaa || cdtoc.tracks[track].trktype == CD_TRACK_AUDIO ? 0x10 : 0x14; } + int get_track_type(int track) const { return cdtoc.tracks[track].trktype; } + const toc &get_toc() const { return cdtoc; } + + /* extra utilities */ + static void convert_type_string_to_track_info(const char *typestring, track_info *info); + static void convert_type_string_to_pregap_info(const char *typestring, track_info *info); + static void convert_subtype_string_to_track_info(const char *typestring, track_info *info); + static void convert_subtype_string_to_pregap_info(const char *typestring, track_info *info); + static const char *get_type_string(uint32_t trktype); + static const char *get_subtype_string(uint32_t subtype); + static std::error_condition parse_metadata(chd_file *chd, toc &toc); + static std::error_condition write_metadata(chd_file *chd, const toc &toc); + + // ECC utilities + static bool ecc_verify(const uint8_t *sector); + static void ecc_generate(uint8_t *sector); + static void ecc_clear(uint8_t *sector); + + + + static inline uint32_t msf_to_lba(uint32_t msf) + { + return ( ((msf&0x00ff0000)>>16) * 60 * 75) + (((msf&0x0000ff00)>>8) * 75) + ((msf&0x000000ff)>>0); + } + + static inline uint32_t lba_to_msf(uint32_t lba) + { + uint8_t m, s, f; + + m = lba / (60 * 75); + lba -= m * (60 * 75); + s = lba / 75; + f = lba % 75; + + return ((m / 10) << 20) | ((m % 10) << 16) | ((s / 10) << 12) | ((s % 10) << 8) | ((f / 10) << 4) | ((f % 10) << 0); -} - -// segacd needs it like this.. investigate -// Angelo also says PCE tracks often start playing at the -// wrong address.. related? -static inline uint32_t lba_to_msf_alt(int lba) -{ - uint32_t ret = 0; - - ret |= ((lba / (60 * 75))&0xff)<<16; - ret |= (((lba / 75) % 60)&0xff)<<8; - ret |= ((lba % 75)&0xff)<<0; - - return ret; -} + } + + // segacd needs it like this.. investigate + // Angelo also says PCE tracks often start playing at the + // wrong address.. related? + static inline uint32_t lba_to_msf_alt(int lba) + { + uint32_t ret = 0; + + ret |= ((lba / (60 * 75))&0xff)<<16; + ret |= (((lba / 75) % 60)&0xff)<<8; + ret |= ((lba % 75)&0xff)<<0; + + return ret; + } + +private: + enum gdi_area { + SINGLE_DENSITY, + HIGH_DENSITY + }; + + enum gdi_pattern { + TYPE_UNKNOWN = 0, + TYPE_I, + TYPE_II, + TYPE_III, + TYPE_III_SPLIT + }; + + /** @brief offset within sector. */ + static constexpr int SYNC_OFFSET = 0x000; + /** @brief 12 bytes. */ + static constexpr int SYNC_NUM_BYTES = 12; + + /** @brief offset within sector. */ + static constexpr int MODE_OFFSET = 0x00f; + + /** @brief offset within sector. */ + static constexpr int ECC_P_OFFSET = 0x81c; + /** @brief 2 lots of 86. */ + static constexpr int ECC_P_NUM_BYTES = 86; + /** @brief 24 bytes each. */ + static constexpr int ECC_P_COMP = 24; + + /** @brief The ECC q offset. */ + static constexpr int ECC_Q_OFFSET = ECC_P_OFFSET + 2 * ECC_P_NUM_BYTES; + /** @brief 2 lots of 52. */ + static constexpr int ECC_Q_NUM_BYTES = 52; + /** @brief 43 bytes each. */ + static constexpr int ECC_Q_COMP = 43; + + // ECC tables + static const uint8_t ecclow[256]; + static const uint8_t ecchigh[256]; + static const uint16_t poffsets[ECC_P_NUM_BYTES][ECC_P_COMP]; + static const uint16_t qoffsets[ECC_Q_NUM_BYTES][ECC_Q_COMP]; + + /** @brief The chd. */ + chd_file * chd; /* CHD file */ + /** @brief The cdtoc. */ + toc cdtoc; /* TOC for the CD */ + /** @brief Information describing the track. */ + track_input_info cdtrack_info; /* track info */ + /** @brief The fhandle[ CD maximum tracks]. */ + util::core_file::ptr fhandle[MAX_TRACKS];/* file handle */ + + inline uint32_t physical_to_chd_lba(uint32_t physlba, uint32_t &tracknum) const; + inline uint32_t logical_to_chd_lba(uint32_t physlba, uint32_t &tracknum) const; + + static void get_info_from_type_string(const char *typestring, uint32_t *trktype, uint32_t *datasize); + static uint8_t ecc_source_byte(const uint8_t *sector, uint32_t offset); + static void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, uint8_t &val1, uint8_t &val2); + std::error_condition read_partial_sector(void *dest, uint32_t lbasector, uint32_t chdsector, uint32_t tracknum, uint32_t startoffs, uint32_t length, bool phys=false); + + static std::string get_file_path(std::string &path); + static uint64_t get_file_size(const char *filename); + static int tokenize( const char *linebuffer, int i, int linebuffersize, char *token, int tokensize ); + static int msf_to_frames( char *token ); + static uint32_t parse_wav_sample(const char *filename, uint32_t *dataoffs); + static uint16_t read_uint16(FILE *infile); + static uint32_t read_uint32(FILE *infile); + static uint64_t read_uint64(FILE *infile); +}; #endif // MAME_LIB_UTIL_CDROM_H |