summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/util/cdrom.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/util/cdrom.h')
-rw-r--r--src/lib/util/cdrom.h414
1 files changed, 248 insertions, 166 deletions
diff --git a/src/lib/util/cdrom.h b/src/lib/util/cdrom.h
index 50b762d5009..9bf80190a7c 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
@@ -7,176 +7,258 @@
Generic MAME cd-rom implementation
***************************************************************************/
-
-#ifndef MAME_UTIL_CDROM_H
-#define MAME_UTIL_CDROM_H
+#ifndef MAME_LIB_UTIL_CDROM_H
+#define MAME_LIB_UTIL_CDROM_H
#pragma once
-#include "osdcore.h"
#include "chd.h"
+#include "ioprocs.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 */
-
- /* 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 */
-};
-
-
-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);
-chd_error cdrom_parse_metadata(chd_file *chd, cdrom_toc *toc);
-chd_error 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 from the next file to add to the end of the current track after padding; 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 + 1];
+ };
+
+ 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(std::string_view 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; }
+
+ /* TOC utilities */
+ static std::error_condition parse_nero(std::string_view tocfname, toc &outtoc, track_input_info &outinfo);
+ static std::error_condition parse_iso(std::string_view tocfname, toc &outtoc, track_input_info &outinfo);
+ static std::error_condition parse_gdi(std::string_view tocfname, toc &outtoc, track_input_info &outinfo);
+ static std::error_condition parse_cue(std::string_view tocfname, toc &outtoc, track_input_info &outinfo);
+ static bool is_gdicue(std::string_view tocfname);
+ static std::error_condition parse_toc(std::string_view 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);
+ bool is_gdrom() const { return cdtoc.flags & (CD_FLAG_GDROM|CD_FLAG_GDROMLE); }
+
+ // 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::random_read::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);
+
+ static std::string get_file_path(std::string &path);
+ static uint64_t get_file_size(std::string_view 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(std::string_view 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_UTIL_CDROM_H
+#endif // MAME_LIB_UTIL_CDROM_H