// /*************************************************************************** // The Disc Image Chef // ---------------------------------------------------------------------------- // // Filename : CDRWin.cs // Author(s) : Natalia Portillo // // Component : Disc image plugins. // // --[ Description ] ---------------------------------------------------------- // // Manages CDRWin cuesheets (cue/bin). // // --[ License ] -------------------------------------------------------------- // // This library is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; either version 2.1 of the // License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, see . // // ---------------------------------------------------------------------------- // Copyright © 2011-2017 Natalia Portillo // ****************************************************************************/ // TODO: Implement track flags using System; using System.IO; using System.Text; using System.Text.RegularExpressions; using System.Collections.Generic; using DiscImageChef.Console; using DiscImageChef.CommonTypes; using DiscImageChef.Filters; namespace DiscImageChef.ImagePlugins { public class CDRWin : ImagePlugin { #region Internal structures struct CDRWinTrackFile { /// Track # public uint sequence; /// Filter of file containing track public Filter datafilter; /// Offset of track start in file public ulong offset; /// Type of file public string filetype; } struct CDRWinTrack { /// Track # public uint sequence; /// Track title (from CD-Text) public string title; /// Track genre (from CD-Text) public string genre; /// Track arranger (from CD-Text) public string arranger; /// Track composer (from CD-Text) public string composer; /// Track performer (from CD-Text) public string performer; /// Track song writer (from CD-Text) public string songwriter; /// Track ISRC public string isrc; /// File struct for this track public CDRWinTrackFile trackfile; /// Indexes on this track public Dictionary indexes; /// Track pre-gap in sectors public ulong pregap; /// Track post-gap in sectors public ulong postgap; /// Digical Copy Permitted public bool flag_dcp; /// Track is quadraphonic public bool flag_4ch; /// Track has preemphasis public bool flag_pre; /// Track has SCMS public bool flag_scms; /// Bytes per sector public ushort bps; /// Sectors in track public ulong sectors; /// Track type public string tracktype; /// Track session public ushort session; } #endregion struct CDRWinDisc { /// Disk title (from CD-Text) public string title; /// Disk genre (from CD-Text) public string genre; /// Disk arranger (from CD-Text) public string arranger; /// Disk composer (from CD-Text) public string composer; /// Disk performer (from CD-Text) public string performer; /// Disk song writer (from CD-Text) public string songwriter; /// Media catalog number public string mcn; /// Disk type public MediaType disktype; /// Disk type string public string disktypestr; /// Disk CDDB ID public string disk_id; /// Disk UPC/EAN public string barcode; /// Sessions public List sessions; /// Tracks public List tracks; /// Disk comment public string comment; /// File containing CD-Text public string cdtextfile; } #region Internal consts // Type for FILE entity /// Data as-is in little-endian const string CDRWinDiskTypeLittleEndian = "BINARY"; /// Data as-is in big-endian const string CDRWinDiskTypeBigEndian = "MOTOROLA"; /// Audio in Apple AIF file const string CDRWinDiskTypeAIFF = "AIFF"; /// Audio in Microsoft WAV file const string CDRWinDiskTypeRIFF = "WAVE"; /// Audio in MP3 file const string CDRWinDiskTypeMP3 = "MP3"; // Type for TRACK entity /// Audio track, 2352 bytes/sector const string CDRWinTrackTypeAudio = "AUDIO"; /// CD+G track, 2448 bytes/sector (audio+subchannel) const string CDRWinTrackTypeCDG = "CDG"; /// Mode 1 track, cooked, 2048 bytes/sector const string CDRWinTrackTypeMode1 = "MODE1/2048"; /// Mode 1 track, raw, 2352 bytes/sector const string CDRWinTrackTypeMode1Raw = "MODE1/2352"; /// Mode 2 form 1 track, cooked, 2048 bytes/sector const string CDRWinTrackTypeMode2Form1 = "MODE2/2048"; /// Mode 2 form 2 track, cooked, 2324 bytes/sector const string CDRWinTrackTypeMode2Form2 = "MODE2/2324"; /// Mode 2 formless track, cooked, 2336 bytes/sector const string CDRWinTrackTypeMode2Formless = "MODE2/2336"; /// Mode 2 track, raw, 2352 bytes/sector const string CDRWinTrackTypeMode2Raw = "MODE2/2352"; /// CD-i track, cooked, 2336 bytes/sector const string CDRWinTrackTypeCDI = "CDI/2336"; /// CD-i track, raw, 2352 bytes/sector const string CDRWinTrackTypeCDIRaw = "CDI/2352"; // Type for REM ORIGINAL MEDIA-TYPE entity /// DiskType.CD const string CDRWinDiskTypeCD = "CD"; /// DiskType.CDRW const string CDRWinDiskTypeCDRW = "CD-RW"; /// DiskType.CDMRW const string CDRWinDiskTypeCDMRW = "CD-MRW"; /// DiskType.CDMRW const string CDRWinDiskTypeCDMRW2 = "CD-(MRW)"; /// DiskType.DVDROM const string CDRWinDiskTypeDVD = "DVD"; /// DiskType.DVDPRW const string CDRWinDiskTypeDVDPMRW = "DVD+MRW"; /// DiskType.DVDPRW const string CDRWinDiskTypeDVDPMRW2 = "DVD+(MRW)"; /// DiskType.DVDPRWDL const string CDRWinDiskTypeDVDPMRWDL = "DVD+MRW DL"; /// DiskType.DVDPRWDL const string CDRWinDiskTypeDVDPMRWDL2 = "DVD+(MRW) DL"; /// DiskType.DVDPR const string CDRWinDiskTypeDVDPR = "DVD+R"; /// DiskType.DVDPRDL const string CDRWinDiskTypeDVDPRDL = "DVD+R DL"; /// DiskType.DVDPRW const string CDRWinDiskTypeDVDPRW = "DVD+RW"; /// DiskType.DVDPRWDL const string CDRWinDiskTypeDVDPRWDL = "DVD+RW DL"; /// DiskType.DVDPR const string CDRWinDiskTypeDVDPVR = "DVD+VR"; /// DiskType.DVDRAM const string CDRWinDiskTypeDVDRAM = "DVD-RAM"; /// DiskType.DVDR const string CDRWinDiskTypeDVDR = "DVD-R"; /// DiskType.DVDRDL const string CDRWinDiskTypeDVDRDL = "DVD-R DL"; /// DiskType.DVDRW const string CDRWinDiskTypeDVDRW = "DVD-RW"; /// DiskType.DVDRWDL const string CDRWinDiskTypeDVDRWDL = "DVD-RW DL"; /// DiskType.DVDR const string CDRWinDiskTypeDVDVR = "DVD-VR"; /// DiskType.DVDRW const string CDRWinDiskTypeDVDRW2 = "DVDRW"; /// DiskType.HDDVDROM const string CDRWinDiskTypeHDDVD = "HD DVD"; /// DiskType.HDDVDRAM const string CDRWinDiskTypeHDDVDRAM = "HD DVD-RAM"; /// DiskType.HDDVDR const string CDRWinDiskTypeHDDVDR = "HD DVD-R"; /// DiskType.HDDVDR const string CDRWinDiskTypeHDDVDRDL = "HD DVD-R DL"; /// DiskType.HDDVDRW const string CDRWinDiskTypeHDDVDRW = "HD DVD-RW"; /// DiskType.HDDVDRW const string CDRWinDiskTypeHDDVDRWDL = "HD DVD-RW DL"; /// DiskType.BDROM const string CDRWinDiskTypeBD = "BD"; /// DiskType.BDR const string CDRWinDiskTypeBDR = "BD-R"; /// DiskType.BDRE const string CDRWinDiskTypeBDRE = "BD-RE"; /// DiskType.BDR const string CDRWinDiskTypeBDRDL = "BD-R DL"; /// DiskType.BDRE const string CDRWinDiskTypeBDREDL = "BD-RE DL"; #endregion #region Internal variables Filter imageFilter; StreamReader cueStream; Stream imageStream; /// Dictionary, index is track #, value is TrackFile Dictionary offsetmap; CDRWinDisc discimage; List partitions; #endregion #region Parsing regexs const string SessionRegEx = "\\bREM\\s+SESSION\\s+(?\\d+).*$"; const string DiskTypeRegEx = "\\bREM\\s+ORIGINAL MEDIA-TYPE:\\s+(?.+)$"; const string LeadOutRegEx = "\\bREM\\s+LEAD-OUT\\s+(?[\\d]+:[\\d]+:[\\d]+)$"; // Not checked const string LBARegEx = "\\bREM MSF:\\s+(?[\\d]+:[\\d]+:[\\d]+)\\s+=\\s+LBA:\\s+(?[\\d]+)$"; const string DiskIDRegEx = "\\bDISC_ID\\s+(?[\\da-f]{8})$"; const string BarCodeRegEx = "\\bUPC_EAN\\s+(?[\\d]{12,13})$"; const string CommentRegEx = "\\bREM\\s+(?.+)$"; const string CDTextRegEx = "\\bCDTEXTFILE\\s+(?.+)$"; const string MCNRegEx = "\\bCATALOG\\s+(?\\d{13})$"; const string TitleRegEx = "\\bTITLE\\s+(?.+)$"; const string GenreRegEx = "\\bGENRE\\s+(?<genre>.+)$"; const string ArrangerRegEx = "\\bARRANGER\\s+(?<arranger>.+)$"; const string ComposerRegEx = "\\bCOMPOSER\\s+(?<composer>.+)$"; const string PerformerRegEx = "\\bPERFORMER\\s+(?<performer>.+)$"; const string SongWriterRegEx = "\\bSONGWRITER\\s+(?<songwriter>.+)$"; const string FileRegEx = "\\bFILE\\s+(?<filename>.+)\\s+(?<type>\\S+)$"; const string TrackRegEx = "\\bTRACK\\s+(?<number>\\d+)\\s+(?<type>\\S+)$"; const string ISRCRegEx = "\\bISRC\\s+(?<isrc>\\w{12})$"; const string IndexRegEx = "\\bINDEX\\s+(?<index>\\d+)\\s+(?<msf>[\\d]+:[\\d]+:[\\d]+)$"; const string PregapRegEx = "\\bPREGAP\\s+(?<msf>[\\d]+:[\\d]+:[\\d]+)$"; const string PostgapRegex = "\\bPOSTGAP\\s+(?<msf>[\\d]+:[\\d]+:[\\d]+)$"; const string FlagsRegEx = "\\bFLAGS\\s+(((?<dcp>DCP)|(?<quad>4CH)|(?<pre>PRE)|(?<scms>SCMS))\\s*)+$"; #endregion #region Methods public CDRWin() { Name = "CDRWin cuesheet"; PluginUUID = new Guid("664568B2-15D4-4E64-8A7A-20BDA8B8386F"); ImageInfo = new ImageInfo(); ImageInfo.readableSectorTags = new List<SectorTagType>(); ImageInfo.readableMediaTags = new List<MediaTagType>(); ImageInfo.imageHasPartitions = true; ImageInfo.imageHasSessions = true; ImageInfo.imageVersion = null; ImageInfo.imageApplicationVersion = null; ImageInfo.imageName = null; ImageInfo.imageCreator = null; ImageInfo.mediaManufacturer = null; ImageInfo.mediaModel = null; ImageInfo.mediaPartNumber = null; ImageInfo.mediaSequence = 0; ImageInfo.lastMediaSequence = 0; ImageInfo.driveManufacturer = null; ImageInfo.driveModel = null; ImageInfo.driveSerialNumber = null; ImageInfo.driveFirmwareRevision = null; } // Due to .cue format, this method must parse whole file, ignoring errors (those will be thrown by OpenImage()). public override bool IdentifyImage(Filter imageFilter) { this.imageFilter = imageFilter; try { imageFilter.GetDataForkStream().Seek(0, SeekOrigin.Begin); byte[] testArray = new byte[512]; imageFilter.GetDataForkStream().Read(testArray, 0, 512); imageFilter.GetDataForkStream().Seek(0, SeekOrigin.Begin); // Check for unexpected control characters that shouldn't be present in a text file and can crash this plugin bool twoConsecutiveNulls = false; for(int i = 0; i < 512; i++) { if(i >= imageFilter.GetDataForkStream().Length) break; if(testArray[i] == 0) { if(twoConsecutiveNulls) return false; twoConsecutiveNulls = true; } else twoConsecutiveNulls = false; if(testArray[i] < 0x20 && testArray[i] != 0x0A && testArray[i] != 0x0D && testArray[i] != 0x00) return false; } cueStream = new StreamReader(this.imageFilter.GetDataForkStream()); int line = 0; while(cueStream.Peek() >= 0) { line++; string _line = cueStream.ReadLine(); Regex Sr = new Regex(SessionRegEx); Regex Rr = new Regex(CommentRegEx); Regex Cr = new Regex(MCNRegEx); Regex Fr = new Regex(FileRegEx); Regex Tr = new Regex(CDTextRegEx); Match Sm; Match Rm; Match Cm; Match Fm; Match Tm; // First line must be SESSION, REM, CATALOG, FILE or CDTEXTFILE. Sm = Sr.Match(_line); Rm = Rr.Match(_line); Cm = Cr.Match(_line); Fm = Fr.Match(_line); Tm = Tr.Match(_line); if(!Sm.Success && !Rm.Success && !Cm.Success && !Fm.Success && !Tm.Success) return false; return true; } return false; } catch(Exception ex) { DicConsole.ErrorWriteLine("Exception trying to identify image file {0}", this.imageFilter); DicConsole.ErrorWriteLine("Exception: {0}", ex.Message); DicConsole.ErrorWriteLine("Stack trace: {0}", ex.StackTrace); return false; } } public override bool OpenImage(Filter imageFilter) { if(imageFilter == null) return false; this.imageFilter = imageFilter; try { imageFilter.GetDataForkStream().Seek(0, SeekOrigin.Begin); cueStream = new StreamReader(imageFilter.GetDataForkStream()); int line = 0; bool intrack = false; byte currentsession = 1; // Initialize all RegExs Regex RegexSession = new Regex(SessionRegEx); Regex RegexDiskType = new Regex(DiskTypeRegEx); Regex RegexLeadOut = new Regex(LeadOutRegEx); Regex RegexLBA = new Regex(LBARegEx); Regex RegexDiskID = new Regex(DiskIDRegEx); Regex RegexBarCode = new Regex(BarCodeRegEx); Regex RegexComment = new Regex(CommentRegEx); Regex RegexCDText = new Regex(CDTextRegEx); Regex RegexMCN = new Regex(MCNRegEx); Regex RegexTitle = new Regex(TitleRegEx); Regex RegexGenre = new Regex(GenreRegEx); Regex RegexArranger = new Regex(ArrangerRegEx); Regex RegexComposer = new Regex(ComposerRegEx); Regex RegexPerformer = new Regex(PerformerRegEx); Regex RegexSongWriter = new Regex(SongWriterRegEx); Regex RegexFile = new Regex(FileRegEx); Regex RegexTrack = new Regex(TrackRegEx); Regex RegexISRC = new Regex(ISRCRegEx); Regex RegexIndex = new Regex(IndexRegEx); Regex RegexPregap = new Regex(PregapRegEx); Regex RegexPostgap = new Regex(PostgapRegex); Regex RegexFlags = new Regex(FlagsRegEx); // Initialize all RegEx matches Match MatchSession; Match MatchDiskType; Match MatchLeadOut; Match MatchLBA; Match MatchDiskID; Match MatchBarCode; Match MatchComment; Match MatchCDText; Match MatchMCN; Match MatchTitle; Match MatchGenre; Match MatchArranger; Match MatchComposer; Match MatchPerformer; Match MatchSongWriter; Match MatchFile; Match MatchTrack; Match MatchISRC; Match MatchIndex; Match MatchPregap; Match MatchPostgap; Match MatchFlags; // Initialize disc discimage = new CDRWinDisc(); discimage.sessions = new List<Session>(); discimage.tracks = new List<CDRWinTrack>(); discimage.comment = ""; CDRWinTrack currenttrack = new CDRWinTrack(); currenttrack.indexes = new Dictionary<int, ulong>(); CDRWinTrackFile currentfile = new CDRWinTrackFile(); ulong currentfileoffsetsector = 0; CDRWinTrack[] cuetracks; int track_count = 0; while(cueStream.Peek() >= 0) { line++; string _line = cueStream.ReadLine(); MatchTrack = RegexTrack.Match(_line); if(MatchTrack.Success) { uint track_seq = uint.Parse(MatchTrack.Groups[1].Value); if(track_count + 1 != track_seq) throw new FeatureUnsupportedImageException(string.Format("Found TRACK {0} out of order in line {1}", track_seq, line)); track_count++; } } if(track_count == 0) throw new FeatureUnsupportedImageException("No tracks found"); cuetracks = new CDRWinTrack[track_count]; line = 0; imageFilter.GetDataForkStream().Seek(0, SeekOrigin.Begin); cueStream = new StreamReader(imageFilter.GetDataForkStream()); FiltersList filtersList = new FiltersList(); while(cueStream.Peek() >= 0) { line++; string _line = cueStream.ReadLine(); MatchSession = RegexSession.Match(_line); MatchDiskType = RegexDiskType.Match(_line); MatchComment = RegexComment.Match(_line); MatchLBA = RegexLBA.Match(_line); // Unhandled, just ignored MatchLeadOut = RegexLeadOut.Match(_line); // Unhandled, just ignored if(MatchDiskType.Success && !intrack) { DicConsole.DebugWriteLine("CDRWin plugin", "Found REM ORIGINAL MEDIA TYPE at line {0}", line); discimage.disktypestr = MatchDiskType.Groups[1].Value; } else if(MatchDiskType.Success && intrack) { throw new FeatureUnsupportedImageException(string.Format("Found REM ORIGINAL MEDIA TYPE field after a track in line {0}", line)); } else if(MatchSession.Success) { DicConsole.DebugWriteLine("CDRWin plugin", "Found REM SESSION at line {0}", line); currentsession = byte.Parse(MatchSession.Groups[1].Value); // What happens between sessions } else if(MatchLBA.Success) { DicConsole.DebugWriteLine("CDRWin plugin", "Found REM MSF at line {0}", line); // Just ignored } else if(MatchLeadOut.Success) { DicConsole.DebugWriteLine("CDRWin plugin", "Found REM LEAD-OUT at line {0}", line); // Just ignored } else if(MatchComment.Success) { DicConsole.DebugWriteLine("CDRWin plugin", "Found REM at line {0}", line); if(discimage.comment == "") discimage.comment = MatchComment.Groups[1].Value; // First comment else discimage.comment += Environment.NewLine + MatchComment.Groups[1].Value; // Append new comments as new lines } else { MatchTrack = RegexTrack.Match(_line); MatchTitle = RegexTitle.Match(_line); MatchSongWriter = RegexSongWriter.Match(_line); MatchPregap = RegexPregap.Match(_line); MatchPostgap = RegexPostgap.Match(_line); MatchPerformer = RegexPerformer.Match(_line); MatchMCN = RegexMCN.Match(_line); MatchISRC = RegexISRC.Match(_line); MatchIndex = RegexIndex.Match(_line); MatchGenre = RegexGenre.Match(_line); MatchFlags = RegexFlags.Match(_line); MatchFile = RegexFile.Match(_line); MatchDiskID = RegexDiskID.Match(_line); MatchComposer = RegexComposer.Match(_line); MatchCDText = RegexCDText.Match(_line); MatchBarCode = RegexBarCode.Match(_line); MatchArranger = RegexArranger.Match(_line); if(MatchArranger.Success) { DicConsole.DebugWriteLine("CDRWin plugin", "Found ARRANGER at line {0}", line); if(intrack) currenttrack.arranger = MatchArranger.Groups[1].Value; else discimage.arranger = MatchArranger.Groups[1].Value; } else if(MatchBarCode.Success) { DicConsole.DebugWriteLine("CDRWin plugin", "Found UPC_EAN at line {0}", line); if(!intrack) discimage.barcode = MatchBarCode.Groups[1].Value; else throw new FeatureUnsupportedImageException(string.Format("Found barcode field in incorrect place at line {0}", line)); } else if(MatchCDText.Success) { DicConsole.DebugWriteLine("CDRWin plugin", "Found CDTEXTFILE at line {0}", line); if(!intrack) discimage.cdtextfile = MatchCDText.Groups[1].Value; else throw new FeatureUnsupportedImageException(string.Format("Found CD-Text file field in incorrect place at line {0}", line)); } else if(MatchComposer.Success) { DicConsole.DebugWriteLine("CDRWin plugin", "Found COMPOSER at line {0}", line); if(intrack) currenttrack.arranger = MatchComposer.Groups[1].Value; else discimage.arranger = MatchComposer.Groups[1].Value; } else if(MatchDiskID.Success) { DicConsole.DebugWriteLine("CDRWin plugin", "Found DISC_ID at line {0}", line); if(!intrack) discimage.disk_id = MatchDiskID.Groups[1].Value; else throw new FeatureUnsupportedImageException(string.Format("Found CDDB ID field in incorrect place at line {0}", line)); } else if(MatchFile.Success) { DicConsole.DebugWriteLine("CDRWin plugin", "Found FILE at line {0}", line); if(currenttrack.sequence != 0) { currentfile.sequence = currenttrack.sequence; currenttrack.trackfile = currentfile; currenttrack.sectors = ((ulong)currentfile.datafilter.GetLength() - currentfile.offset) / CDRWinTrackTypeToBytesPerSector(currenttrack.tracktype); cuetracks[currenttrack.sequence - 1] = currenttrack; intrack = false; currenttrack = new CDRWinTrack(); currentfile = new CDRWinTrackFile(); filtersList = new FiltersList(); } //currentfile = new CDRWinTrackFile(); string datafile = MatchFile.Groups[1].Value; currentfile.filetype = MatchFile.Groups[2].Value; // Check if file path is quoted if(datafile[0] == '"' && datafile[datafile.Length - 1] == '"') { datafile = datafile.Substring(1, datafile.Length - 2); // Unquote it } currentfile.datafilter = filtersList.GetFilter(datafile); // Check if file exists if(currentfile.datafilter == null) { if(datafile[0] == '/' || (datafile[0] == '/' && datafile[1] == '.')) // UNIX absolute path { Regex unixpath = new Regex("^(.+)/([^/]+)$"); Match unixpathmatch = unixpath.Match(datafile); if(unixpathmatch.Success) { currentfile.datafilter = filtersList.GetFilter(unixpathmatch.Groups[1].Value); if(currentfile.datafilter == null) { string path = imageFilter.GetParentFolder() + Path.PathSeparator + unixpathmatch.Groups[1].Value; currentfile.datafilter = filtersList.GetFilter(path); if(currentfile.datafilter == null) throw new FeatureUnsupportedImageException(string.Format("File \"{0}\" not found.", MatchFile.Groups[1].Value)); } } else throw new FeatureUnsupportedImageException(string.Format("File \"{0}\" not found.", MatchFile.Groups[1].Value)); } else if((datafile[1] == ':' && datafile[2] == '\\') || (datafile[0] == '\\' && datafile[1] == '\\') || ((datafile[0] == '.' && datafile[1] == '\\'))) // Windows absolute path { Regex winpath = new Regex("^(?:[a-zA-Z]\\:(\\\\|\\/)|file\\:\\/\\/|\\\\\\\\|\\.(\\/|\\\\))([^\\\\\\/\\:\\*\\?\\<\\>\\\"\\|]+(\\\\|\\/){0,1})+$"); Match winpathmatch = winpath.Match(datafile); if(winpathmatch.Success) { currentfile.datafilter = filtersList.GetFilter(winpathmatch.Groups[1].Value); if(currentfile.datafilter == null) { string path = imageFilter.GetParentFolder() + Path.PathSeparator + winpathmatch.Groups[1].Value; currentfile.datafilter = filtersList.GetFilter(path); if(currentfile.datafilter == null) throw new FeatureUnsupportedImageException(string.Format("File \"{0}\" not found.", MatchFile.Groups[1].Value)); } } else throw new FeatureUnsupportedImageException(string.Format("File \"{0}\" not found.", MatchFile.Groups[1].Value)); } else { string path = imageFilter.GetParentFolder() + Path.PathSeparator + datafile; currentfile.datafilter = filtersList.GetFilter(path); if(currentfile.datafilter == null) throw new FeatureUnsupportedImageException(string.Format("File \"{0}\" not found.", MatchFile.Groups[1].Value)); } } // File does exist, process it DicConsole.DebugWriteLine("CDRWin plugin", "File \"{0}\" found", currentfile.datafilter.GetFilename()); switch(currentfile.filetype) { case CDRWinDiskTypeLittleEndian: break; case CDRWinDiskTypeBigEndian: case CDRWinDiskTypeAIFF: case CDRWinDiskTypeRIFF: case CDRWinDiskTypeMP3: throw new FeatureSupportedButNotImplementedImageException(string.Format("Unsupported file type {0}", currentfile.filetype)); default: throw new FeatureUnsupportedImageException(string.Format("Unknown file type {0}", currentfile.filetype)); } currentfile.offset = 0; currentfile.sequence = 0; } else if(MatchFlags.Success) { DicConsole.DebugWriteLine("CDRWin plugin", "Found FLAGS at line {0}", line); if(!intrack) throw new FeatureUnsupportedImageException(string.Format("Found FLAGS field in incorrect place at line {0}", line)); currenttrack.flag_dcp |= MatchFile.Groups["dcp"].Value == "DCP"; currenttrack.flag_4ch |= MatchFile.Groups["quad"].Value == "4CH"; currenttrack.flag_pre |= MatchFile.Groups["pre"].Value == "PRE"; currenttrack.flag_scms |= MatchFile.Groups["scms"].Value == "SCMS"; } else if(MatchGenre.Success) { DicConsole.DebugWriteLine("CDRWin plugin", "Found GENRE at line {0}", line); if(intrack) currenttrack.genre = MatchGenre.Groups[1].Value; else discimage.genre = MatchGenre.Groups[1].Value; } else if(MatchIndex.Success) { DicConsole.DebugWriteLine("CDRWin plugin", "Found INDEX at line {0}", line); if(!intrack) throw new FeatureUnsupportedImageException(string.Format("Found INDEX before a track {0}", line)); else { int index = int.Parse(MatchIndex.Groups[1].Value); ulong offset = CDRWinMSFToLBA(MatchIndex.Groups[2].Value); if((index != 0 && index != 1) && currenttrack.indexes.Count == 0) throw new FeatureUnsupportedImageException(string.Format("Found INDEX {0} before INDEX 00 or INDEX 01", index)); if((index == 0 || (index == 1 && !currenttrack.indexes.ContainsKey(0)))) { if((int)(currenttrack.sequence - 2) >= 0 && offset > 1) { cuetracks[currenttrack.sequence - 2].sectors = offset - currentfileoffsetsector; currentfile.offset += cuetracks[currenttrack.sequence - 2].sectors * cuetracks[currenttrack.sequence - 2].bps; DicConsole.DebugWriteLine("CDRWin plugin", "Sets currentfile.offset to {0} at line 553", currentfile.offset); DicConsole.DebugWriteLine("CDRWin plugin", "cuetracks[currenttrack.sequence-2].sectors = {0}", cuetracks[currenttrack.sequence - 2].sectors); DicConsole.DebugWriteLine("CDRWin plugin", "cuetracks[currenttrack.sequence-2].bps = {0}", cuetracks[currenttrack.sequence - 2].bps); } } if((index == 0 || (index == 1 && !currenttrack.indexes.ContainsKey(0))) && currenttrack.sequence == 1) { DicConsole.DebugWriteLine("CDRWin plugin", "Sets currentfile.offset to {0} at line 559", offset * currenttrack.bps); currentfile.offset = offset * currenttrack.bps; } currentfileoffsetsector = offset; currenttrack.indexes.Add(index, offset); } } else if(MatchISRC.Success) { DicConsole.DebugWriteLine("CDRWin plugin", "Found ISRC at line {0}", line); if(!intrack) throw new FeatureUnsupportedImageException(string.Format("Found ISRC before a track {0}", line)); currenttrack.isrc = MatchISRC.Groups[1].Value; } else if(MatchMCN.Success) { DicConsole.DebugWriteLine("CDRWin plugin", "Found CATALOG at line {0}", line); if(!intrack) discimage.mcn = MatchMCN.Groups[1].Value; else throw new FeatureUnsupportedImageException(string.Format("Found CATALOG field in incorrect place at line {0}", line)); } else if(MatchPerformer.Success) { DicConsole.DebugWriteLine("CDRWin plugin", "Found PERFORMER at line {0}", line); if(intrack) currenttrack.performer = MatchPerformer.Groups[1].Value; else discimage.performer = MatchPerformer.Groups[1].Value; } else if(MatchPostgap.Success) { DicConsole.DebugWriteLine("CDRWin plugin", "Found POSTGAP at line {0}", line); if(intrack) { currenttrack.postgap = CDRWinMSFToLBA(MatchPostgap.Groups[1].Value); } else throw new FeatureUnsupportedImageException(string.Format("Found POSTGAP field before a track at line {0}", line)); } else if(MatchPregap.Success) { DicConsole.DebugWriteLine("CDRWin plugin", "Found PREGAP at line {0}", line); if(intrack) { currenttrack.pregap = CDRWinMSFToLBA(MatchPregap.Groups[1].Value); } else throw new FeatureUnsupportedImageException(string.Format("Found PREGAP field before a track at line {0}", line)); } else if(MatchSongWriter.Success) { DicConsole.DebugWriteLine("CDRWin plugin", "Found SONGWRITER at line {0}", line); if(intrack) currenttrack.songwriter = MatchSongWriter.Groups[1].Value; else discimage.songwriter = MatchSongWriter.Groups[1].Value; } else if(MatchTitle.Success) { DicConsole.DebugWriteLine("CDRWin plugin", "Found TITLE at line {0}", line); if(intrack) currenttrack.title = MatchTitle.Groups[1].Value; else discimage.title = MatchTitle.Groups[1].Value; } else if(MatchTrack.Success) { DicConsole.DebugWriteLine("CDRWin plugin", "Found TRACK at line {0}", line); if(currentfile.datafilter == null) throw new FeatureUnsupportedImageException(string.Format("Found TRACK field before a file is defined at line {0}", line)); if(intrack) { if(currenttrack.indexes.ContainsKey(0) && currenttrack.pregap == 0) { currenttrack.indexes.TryGetValue(0, out currenttrack.pregap); } currentfile.sequence = currenttrack.sequence; currenttrack.trackfile = currentfile; cuetracks[currenttrack.sequence - 1] = currenttrack; } currenttrack = new CDRWinTrack(); currenttrack.indexes = new Dictionary<int, ulong>(); currenttrack.sequence = uint.Parse(MatchTrack.Groups[1].Value); DicConsole.DebugWriteLine("CDRWin plugin", "Setting currenttrack.sequence to {0}", currenttrack.sequence); currentfile.sequence = currenttrack.sequence; currenttrack.bps = CDRWinTrackTypeToBytesPerSector(MatchTrack.Groups[2].Value); currenttrack.tracktype = MatchTrack.Groups[2].Value; currenttrack.session = currentsession; intrack = true; } else if(_line == "") // Empty line, ignore it { } else // Non-empty unknown field { throw new FeatureUnsupportedImageException(string.Format("Found unknown field defined at line {0}: \"{1}\"", line, _line)); } } } if(currenttrack.sequence != 0) { currentfile.sequence = currenttrack.sequence; currenttrack.trackfile = currentfile; currenttrack.sectors = ((ulong)currentfile.datafilter.GetLength() - currentfile.offset) / CDRWinTrackTypeToBytesPerSector(currenttrack.tracktype); cuetracks[currenttrack.sequence - 1] = currenttrack; } Session[] _sessions = new Session[currentsession]; for(int s = 1; s <= _sessions.Length; s++) { _sessions[s - 1].SessionSequence = 1; if(s > 1) _sessions[s - 1].StartSector = _sessions[s - 2].EndSector + 1; else _sessions[s - 1].StartSector = 0; ulong session_sectors = 0; int last_session_track = 0; for(int i = 0; i < cuetracks.Length; i++) { if(cuetracks[i].session == s) { session_sectors += cuetracks[i].sectors; if(i > last_session_track) last_session_track = i; } } _sessions[s - 1].EndTrack = cuetracks[last_session_track].sequence; _sessions[s - 1].EndSector = session_sectors - 1; } for(int s = 1; s <= _sessions.Length; s++) discimage.sessions.Add(_sessions[s - 1]); for(int t = 1; t <= cuetracks.Length; t++) discimage.tracks.Add(cuetracks[t - 1]); discimage.disktype = CDRWinIsoBusterDiscTypeToMediaType(discimage.disktypestr); if(discimage.disktype == MediaType.Unknown || discimage.disktype == MediaType.CD) { bool data = false; bool cdg = false; bool cdi = false; bool mode2 = false; bool firstaudio = false; bool firstdata = false; bool audio = false; for(int i = 0; i < discimage.tracks.Count; i++) { // First track is audio firstaudio |= i == 0 && discimage.tracks[i].tracktype == CDRWinTrackTypeAudio; // First track is data firstdata |= i == 0 && discimage.tracks[i].tracktype != CDRWinTrackTypeAudio; // Any non first track is data data |= i != 0 && discimage.tracks[i].tracktype != CDRWinTrackTypeAudio; // Any non first track is audio audio |= i != 0 && discimage.tracks[i].tracktype == CDRWinTrackTypeAudio; switch(discimage.tracks[i].tracktype) { case CDRWinTrackTypeCDG: cdg = true; break; case CDRWinTrackTypeCDI: case CDRWinTrackTypeCDIRaw: cdi = true; break; case CDRWinTrackTypeMode2Form1: case CDRWinTrackTypeMode2Form2: case CDRWinTrackTypeMode2Formless: case CDRWinTrackTypeMode2Raw: mode2 = true; break; } } if(!data && !firstdata) discimage.disktype = MediaType.CDDA; else if(cdg) discimage.disktype = MediaType.CDG; else if(cdi) discimage.disktype = MediaType.CDI; else if(firstaudio && data && discimage.sessions.Count > 1 && mode2) discimage.disktype = MediaType.CDPLUS; else if((firstdata && audio) || mode2) discimage.disktype = MediaType.CDROMXA; else if(!audio) discimage.disktype = MediaType.CDROM; else discimage.disktype = MediaType.CD; } // DEBUG information DicConsole.DebugWriteLine("CDRWin plugin", "Disc image parsing results"); DicConsole.DebugWriteLine("CDRWin plugin", "Disc CD-TEXT:"); if(discimage.arranger == null) DicConsole.DebugWriteLine("CDRWin plugin", "\tArranger is not set."); else DicConsole.DebugWriteLine("CDRWin plugin", "\tArranger: {0}", discimage.arranger); if(discimage.composer == null) DicConsole.DebugWriteLine("CDRWin plugin", "\tComposer is not set."); else DicConsole.DebugWriteLine("CDRWin plugin", "\tComposer: {0}", discimage.composer); if(discimage.genre == null) DicConsole.DebugWriteLine("CDRWin plugin", "\tGenre is not set."); else DicConsole.DebugWriteLine("CDRWin plugin", "\tGenre: {0}", discimage.genre); if(discimage.performer == null) DicConsole.DebugWriteLine("CDRWin plugin", "\tPerformer is not set."); else DicConsole.DebugWriteLine("CDRWin plugin", "\tPerformer: {0}", discimage.performer); if(discimage.songwriter == null) DicConsole.DebugWriteLine("CDRWin plugin", "\tSongwriter is not set."); else DicConsole.DebugWriteLine("CDRWin plugin", "\tSongwriter: {0}", discimage.songwriter); if(discimage.title == null) DicConsole.DebugWriteLine("CDRWin plugin", "\tTitle is not set."); else DicConsole.DebugWriteLine("CDRWin plugin", "\tTitle: {0}", discimage.title); if(discimage.cdtextfile == null) DicConsole.DebugWriteLine("CDRWin plugin", "\tCD-TEXT binary file not set."); else DicConsole.DebugWriteLine("CDRWin plugin", "\tCD-TEXT binary file: {0}", discimage.cdtextfile); DicConsole.DebugWriteLine("CDRWin plugin", "Disc information:"); if(discimage.disktypestr == null) DicConsole.DebugWriteLine("CDRWin plugin", "\tISOBuster disc type not set."); else DicConsole.DebugWriteLine("CDRWin plugin", "\tISOBuster disc type: {0}", discimage.disktypestr); DicConsole.DebugWriteLine("CDRWin plugin", "\tGuessed disk type: {0}", discimage.disktype); if(discimage.barcode == null) DicConsole.DebugWriteLine("CDRWin plugin", "\tBarcode not set."); else DicConsole.DebugWriteLine("CDRWin plugin", "\tBarcode: {0}", discimage.barcode); if(discimage.disk_id == null) DicConsole.DebugWriteLine("CDRWin plugin", "\tDisc ID not set."); else DicConsole.DebugWriteLine("CDRWin plugin", "\tDisc ID: {0}", discimage.disk_id); if(discimage.mcn == null) DicConsole.DebugWriteLine("CDRWin plugin", "\tMCN not set."); else DicConsole.DebugWriteLine("CDRWin plugin", "\tMCN: {0}", discimage.mcn); if(discimage.comment == null) DicConsole.DebugWriteLine("CDRWin plugin", "\tComment not set."); else DicConsole.DebugWriteLine("CDRWin plugin", "\tComment: \"{0}\"", discimage.comment); DicConsole.DebugWriteLine("CDRWin plugin", "Session information:"); DicConsole.DebugWriteLine("CDRWin plugin", "\tDisc contains {0} sessions", discimage.sessions.Count); for(int i = 0; i < discimage.sessions.Count; i++) { DicConsole.DebugWriteLine("CDRWin plugin", "\tSession {0} information:", i + 1); DicConsole.DebugWriteLine("CDRWin plugin", "\t\tStarting track: {0}", discimage.sessions[i].StartTrack); DicConsole.DebugWriteLine("CDRWin plugin", "\t\tStarting sector: {0}", discimage.sessions[i].StartSector); DicConsole.DebugWriteLine("CDRWin plugin", "\t\tEnding track: {0}", discimage.sessions[i].EndTrack); DicConsole.DebugWriteLine("CDRWin plugin", "\t\tEnding sector: {0}", discimage.sessions[i].EndSector); } DicConsole.DebugWriteLine("CDRWin plugin", "Track information:"); DicConsole.DebugWriteLine("CDRWin plugin", "\tDisc contains {0} tracks", discimage.tracks.Count); for(int i = 0; i < discimage.tracks.Count; i++) { DicConsole.DebugWriteLine("CDRWin plugin", "\tTrack {0} information:", discimage.tracks[i].sequence); DicConsole.DebugWriteLine("CDRWin plugin", "\t\t{0} bytes per sector", discimage.tracks[i].bps); DicConsole.DebugWriteLine("CDRWin plugin", "\t\tPregap: {0} sectors", discimage.tracks[i].pregap); DicConsole.DebugWriteLine("CDRWin plugin", "\t\tData: {0} sectors", discimage.tracks[i].sectors); DicConsole.DebugWriteLine("CDRWin plugin", "\t\tPostgap: {0} sectors", discimage.tracks[i].postgap); if(discimage.tracks[i].flag_4ch) DicConsole.DebugWriteLine("CDRWin plugin", "\t\tTrack is flagged as quadraphonic"); if(discimage.tracks[i].flag_dcp) DicConsole.DebugWriteLine("CDRWin plugin", "\t\tTrack allows digital copy"); if(discimage.tracks[i].flag_pre) DicConsole.DebugWriteLine("CDRWin plugin", "\t\tTrack has pre-emphasis applied"); if(discimage.tracks[i].flag_scms) DicConsole.DebugWriteLine("CDRWin plugin", "\t\tTrack has SCMS"); DicConsole.DebugWriteLine("CDRWin plugin", "\t\tTrack resides in file {0}, type defined as {1}, starting at byte {2}", discimage.tracks[i].trackfile.datafilter.GetFilename(), discimage.tracks[i].trackfile.filetype, discimage.tracks[i].trackfile.offset); DicConsole.DebugWriteLine("CDRWin plugin", "\t\tIndexes:"); foreach(KeyValuePair<int, ulong> kvp in discimage.tracks[i].indexes) DicConsole.DebugWriteLine("CDRWin plugin", "\t\t\tIndex {0} starts at sector {1}", kvp.Key, kvp.Value); if(discimage.tracks[i].isrc == null) DicConsole.DebugWriteLine("CDRWin plugin", "\t\tISRC is not set."); else DicConsole.DebugWriteLine("CDRWin plugin", "\t\tISRC: {0}", discimage.tracks[i].isrc); if(discimage.tracks[i].arranger == null) DicConsole.DebugWriteLine("CDRWin plugin", "\t\tArranger is not set."); else DicConsole.DebugWriteLine("CDRWin plugin", "\t\tArranger: {0}", discimage.tracks[i].arranger); if(discimage.tracks[i].composer == null) DicConsole.DebugWriteLine("CDRWin plugin", "\t\tComposer is not set."); else DicConsole.DebugWriteLine("CDRWin plugin", "\t\tComposer: {0}", discimage.tracks[i].composer); if(discimage.tracks[i].genre == null) DicConsole.DebugWriteLine("CDRWin plugin", "\t\tGenre is not set."); else DicConsole.DebugWriteLine("CDRWin plugin", "\t\tGenre: {0}", discimage.tracks[i].genre); if(discimage.tracks[i].performer == null) DicConsole.DebugWriteLine("CDRWin plugin", "\t\tPerformer is not set."); else DicConsole.DebugWriteLine("CDRWin plugin", "\t\tPerformer: {0}", discimage.tracks[i].performer); if(discimage.tracks[i].songwriter == null) DicConsole.DebugWriteLine("CDRWin plugin", "\t\tSongwriter is not set."); else DicConsole.DebugWriteLine("CDRWin plugin", "\t\tSongwriter: {0}", discimage.tracks[i].songwriter); if(discimage.tracks[i].title == null) DicConsole.DebugWriteLine("CDRWin plugin", "\t\tTitle is not set."); else DicConsole.DebugWriteLine("CDRWin plugin", "\t\tTitle: {0}", discimage.tracks[i].title); } DicConsole.DebugWriteLine("CDRWin plugin", "Building offset map"); partitions = new List<Partition>(); ulong byte_offset = 0; ulong sector_offset = 0; ulong partitionSequence = 0; ulong index_zero_offset = 0; ulong index_one_offset = 0; bool index_zero = false; offsetmap = new Dictionary<uint, ulong>(); for(int i = 0; i < discimage.tracks.Count; i++) { ulong index0_len = 0; if(discimage.tracks[i].sequence == 1 && i != 0) throw new ImageNotSupportedException("Unordered tracks"); Partition partition = new Partition(); /*if(discimage.tracks[i].pregap > 0) { partition.PartitionDescription = string.Format("Track {0} pregap.", discimage.tracks[i].sequence); partition.PartitionName = discimage.tracks[i].title; partition.PartitionStartSector = sector_offset; partition.PartitionLength = discimage.tracks[i].pregap * discimage.tracks[i].bps; partition.PartitionSectors = discimage.tracks[i].pregap; partition.PartitionSequence = partitionSequence; partition.PartitionStart = byte_offset; partition.PartitionType = discimage.tracks[i].tracktype; sector_offset += partition.PartitionSectors; byte_offset += partition.PartitionLength; partitionSequence++; if(!offsetmap.ContainsKey(discimage.tracks[i].sequence)) offsetmap.Add(discimage.tracks[i].sequence, partition.PartitionStartSector); else { ulong old_start; offsetmap.TryGetValue(discimage.tracks[i].sequence, out old_start); if(partition.PartitionStartSector < old_start) { offsetmap.Remove(discimage.tracks[i].sequence); offsetmap.Add(discimage.tracks[i].sequence, partition.PartitionStartSector); } } partitions.Add(partition); partition = new Partition(); }*/ index_zero |= discimage.tracks[i].indexes.TryGetValue(0, out index_zero_offset); if(!discimage.tracks[i].indexes.TryGetValue(1, out index_one_offset)) throw new ImageNotSupportedException(string.Format("Track {0} lacks index 01", discimage.tracks[i].sequence)); /*if(index_zero && index_one_offset > index_zero_offset) { partition.PartitionDescription = string.Format("Track {0} index 00.", discimage.tracks[i].sequence); partition.PartitionName = discimage.tracks[i].title; partition.PartitionStartSector = sector_offset; partition.PartitionLength = (index_one_offset - index_zero_offset) * discimage.tracks[i].bps; partition.PartitionSectors = index_one_offset - index_zero_offset; partition.PartitionSequence = partitionSequence; partition.PartitionStart = byte_offset; partition.PartitionType = discimage.tracks[i].tracktype; sector_offset += partition.PartitionSectors; byte_offset += partition.PartitionLength; index0_len = partition.PartitionSectors; partitionSequence++; if(!offsetmap.ContainsKey(discimage.tracks[i].sequence)) offsetmap.Add(discimage.tracks[i].sequence, partition.PartitionStartSector); else { ulong old_start; offsetmap.TryGetValue(discimage.tracks[i].sequence, out old_start); if(partition.PartitionStartSector < old_start) { offsetmap.Remove(discimage.tracks[i].sequence); offsetmap.Add(discimage.tracks[i].sequence, partition.PartitionStartSector); } } partitions.Add(partition); partition = new Partition(); }*/ // Index 01 partition.Description = string.Format("Track {0}.", discimage.tracks[i].sequence); partition.Name = discimage.tracks[i].title; partition.Start = sector_offset; partition.Size = (discimage.tracks[i].sectors - index0_len) * discimage.tracks[i].bps; partition.Length = (discimage.tracks[i].sectors - index0_len); partition.Sequence = partitionSequence; partition.Offset = byte_offset; partition.Type = discimage.tracks[i].tracktype; sector_offset += partition.Length; byte_offset += partition.Size; partitionSequence++; if(!offsetmap.ContainsKey(discimage.tracks[i].sequence)) offsetmap.Add(discimage.tracks[i].sequence, partition.Start); else { ulong old_start; offsetmap.TryGetValue(discimage.tracks[i].sequence, out old_start); if(partition.Start < old_start) { offsetmap.Remove(discimage.tracks[i].sequence); offsetmap.Add(discimage.tracks[i].sequence, partition.Start); } } partitions.Add(partition); partition = new Partition(); } // Print offset map DicConsole.DebugWriteLine("CDRWin plugin", "printing partition map"); foreach(Partition partition in partitions) { DicConsole.DebugWriteLine("CDRWin plugin", "Partition sequence: {0}", partition.Sequence); DicConsole.DebugWriteLine("CDRWin plugin", "\tPartition name: {0}", partition.Name); DicConsole.DebugWriteLine("CDRWin plugin", "\tPartition description: {0}", partition.Description); DicConsole.DebugWriteLine("CDRWin plugin", "\tPartition type: {0}", partition.Type); DicConsole.DebugWriteLine("CDRWin plugin", "\tPartition starting sector: {0}", partition.Start); DicConsole.DebugWriteLine("CDRWin plugin", "\tPartition sectors: {0}", partition.Length); DicConsole.DebugWriteLine("CDRWin plugin", "\tPartition starting offset: {0}", partition.Offset); DicConsole.DebugWriteLine("CDRWin plugin", "\tPartition size in bytes: {0}", partition.Size); } foreach(CDRWinTrack track in discimage.tracks) ImageInfo.imageSize += track.bps * track.sectors; foreach(CDRWinTrack track in discimage.tracks) ImageInfo.sectors += track.sectors; if(discimage.disktype == MediaType.CDG || discimage.disktype == MediaType.CDEG || discimage.disktype == MediaType.CDMIDI) ImageInfo.sectorSize = 2448; // CD+G subchannels ARE user data, as CD+G are useless without them else if(discimage.disktype != MediaType.CDROMXA && discimage.disktype != MediaType.CDDA && discimage.disktype != MediaType.CDI && discimage.disktype != MediaType.CDPLUS) ImageInfo.sectorSize = 2048; // Only data tracks else ImageInfo.sectorSize = 2352; // All others if(discimage.mcn != null) ImageInfo.readableMediaTags.Add(MediaTagType.CD_MCN); if(discimage.cdtextfile != null) ImageInfo.readableMediaTags.Add(MediaTagType.CD_TEXT); // Detect ISOBuster extensions if(discimage.disktypestr != null || discimage.comment.ToLower().Contains("isobuster") || discimage.sessions.Count > 1) ImageInfo.imageApplication = "ISOBuster"; else ImageInfo.imageApplication = "CDRWin"; ImageInfo.imageCreationTime = imageFilter.GetCreationTime(); ImageInfo.imageLastModificationTime = imageFilter.GetLastWriteTime(); ImageInfo.imageComments = discimage.comment; ImageInfo.mediaSerialNumber = discimage.mcn; ImageInfo.mediaBarcode = discimage.barcode; ImageInfo.mediaType = discimage.disktype; ImageInfo.readableSectorTags.Add(SectorTagType.CDTrackFlags); foreach(CDRWinTrack track in discimage.tracks) { switch(track.tracktype) { case CDRWinTrackTypeAudio: { if(!ImageInfo.readableSectorTags.Contains(SectorTagType.CDTrackISRC)) ImageInfo.readableSectorTags.Add(SectorTagType.CDTrackISRC); break; } case CDRWinTrackTypeCDG: { if(!ImageInfo.readableSectorTags.Contains(SectorTagType.CDTrackISRC)) ImageInfo.readableSectorTags.Add(SectorTagType.CDTrackISRC); if(!ImageInfo.readableSectorTags.Contains(SectorTagType.CDSectorSubchannel)) ImageInfo.readableSectorTags.Add(SectorTagType.CDSectorSubchannel); break; } case CDRWinTrackTypeMode2Formless: case CDRWinTrackTypeCDI: { if(!ImageInfo.readableSectorTags.Contains(SectorTagType.CDSectorSubHeader)) ImageInfo.readableSectorTags.Add(SectorTagType.CDSectorSubHeader); if(!ImageInfo.readableSectorTags.Contains(SectorTagType.CDSectorEDC)) ImageInfo.readableSectorTags.Add(SectorTagType.CDSectorEDC); break; } case CDRWinTrackTypeMode2Raw: case CDRWinTrackTypeCDIRaw: { if(!ImageInfo.readableSectorTags.Contains(SectorTagType.CDSectorSync)) ImageInfo.readableSectorTags.Add(SectorTagType.CDSectorSync); if(!ImageInfo.readableSectorTags.Contains(SectorTagType.CDSectorHeader)) ImageInfo.readableSectorTags.Add(SectorTagType.CDSectorHeader); if(!ImageInfo.readableSectorTags.Contains(SectorTagType.CDSectorSubHeader)) ImageInfo.readableSectorTags.Add(SectorTagType.CDSectorSubHeader); if(!ImageInfo.readableSectorTags.Contains(SectorTagType.CDSectorEDC)) ImageInfo.readableSectorTags.Add(SectorTagType.CDSectorEDC); break; } case CDRWinTrackTypeMode1Raw: { if(!ImageInfo.readableSectorTags.Contains(SectorTagType.CDSectorSync)) ImageInfo.readableSectorTags.Add(SectorTagType.CDSectorSync); if(!ImageInfo.readableSectorTags.Contains(SectorTagType.CDSectorHeader)) ImageInfo.readableSectorTags.Add(SectorTagType.CDSectorHeader); if(!ImageInfo.readableSectorTags.Contains(SectorTagType.CDSectorSubHeader)) ImageInfo.readableSectorTags.Add(SectorTagType.CDSectorSubHeader); if(!ImageInfo.readableSectorTags.Contains(SectorTagType.CDSectorECC)) ImageInfo.readableSectorTags.Add(SectorTagType.CDSectorECC); if(!ImageInfo.readableSectorTags.Contains(SectorTagType.CDSectorECC_P)) ImageInfo.readableSectorTags.Add(SectorTagType.CDSectorECC_P); if(!ImageInfo.readableSectorTags.Contains(SectorTagType.CDSectorECC_Q)) ImageInfo.readableSectorTags.Add(SectorTagType.CDSectorECC_Q); if(!ImageInfo.readableSectorTags.Contains(SectorTagType.CDSectorEDC)) ImageInfo.readableSectorTags.Add(SectorTagType.CDSectorEDC); break; } } } ImageInfo.xmlMediaType = XmlMediaType.OpticalDisc; DicConsole.VerboseWriteLine("CDRWIN image describes a disc of type {0}", ImageInfo.mediaType); if(!string.IsNullOrEmpty(ImageInfo.imageComments)) DicConsole.VerboseWriteLine("CDRWIN comments: {0}", ImageInfo.imageComments); return true; } catch(Exception ex) { DicConsole.ErrorWriteLine("Exception trying to identify image file {0}", imageFilter.GetFilename()); DicConsole.ErrorWriteLine("Exception: {0}", ex.Message); DicConsole.ErrorWriteLine("Stack trace: {0}", ex.StackTrace); return false; } } public override bool ImageHasPartitions() { return ImageInfo.imageHasPartitions; } public override ulong GetImageSize() { return ImageInfo.imageSize; } public override ulong GetSectors() { return ImageInfo.sectors; } public override uint GetSectorSize() { return ImageInfo.sectorSize; } public override byte[] ReadDiskTag(MediaTagType tag) { switch(tag) { case MediaTagType.CD_MCN: { if(discimage.mcn != null) { return Encoding.ASCII.GetBytes(discimage.mcn); } throw new FeatureNotPresentImageException("Image does not contain MCN information."); } case MediaTagType.CD_TEXT: { if(discimage.cdtextfile != null) // TODO: Check that binary text file exists, open it, read it, send it to caller. throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); throw new FeatureNotPresentImageException("Image does not contain CD-TEXT information."); } default: throw new FeatureSupportedButNotImplementedImageException("Feature not supported by image format"); } } public override byte[] ReadSector(ulong sectorAddress) { return ReadSectors(sectorAddress, 1); } public override byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag) { return ReadSectorsTag(sectorAddress, 1, tag); } public override byte[] ReadSector(ulong sectorAddress, uint track) { return ReadSectors(sectorAddress, 1, track); } public override byte[] ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag) { return ReadSectorsTag(sectorAddress, 1, track, tag); } public override byte[] ReadSectors(ulong sectorAddress, uint length) { foreach(KeyValuePair<uint, ulong> kvp in offsetmap) { if(sectorAddress >= kvp.Value) { foreach(CDRWinTrack cdrwin_track in discimage.tracks) { if(cdrwin_track.sequence == kvp.Key) { if((sectorAddress - kvp.Value) < cdrwin_track.sectors) return ReadSectors((sectorAddress - kvp.Value), length, kvp.Key); } } } } throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found"); } public override byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag) { foreach(KeyValuePair<uint, ulong> kvp in offsetmap) { if(sectorAddress >= kvp.Value) { foreach(CDRWinTrack cdrwin_track in discimage.tracks) { if(cdrwin_track.sequence == kvp.Key) { if((sectorAddress - kvp.Value) < cdrwin_track.sectors) return ReadSectorsTag((sectorAddress - kvp.Value), length, kvp.Key, tag); } } } } throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found"); } public override byte[] ReadSectors(ulong sectorAddress, uint length, uint track) { CDRWinTrack _track = new CDRWinTrack(); _track.sequence = 0; foreach(CDRWinTrack cdrwin_track in discimage.tracks) { if(cdrwin_track.sequence == track) { _track = cdrwin_track; break; } } if(_track.sequence == 0) throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image"); if(length > _track.sectors) throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than present in track, won't cross tracks"); uint sector_offset; uint sector_size; uint sector_skip; switch(_track.tracktype) { case CDRWinTrackTypeMode1: case CDRWinTrackTypeMode2Form1: { sector_offset = 0; sector_size = 2048; sector_skip = 0; break; } case CDRWinTrackTypeMode2Form2: { sector_offset = 0; sector_size = 2324; sector_skip = 0; break; } case CDRWinTrackTypeMode2Formless: case CDRWinTrackTypeCDI: { sector_offset = 0; sector_size = 2336; sector_skip = 0; break; } case CDRWinTrackTypeAudio: { sector_offset = 0; sector_size = 2352; sector_skip = 0; break; } case CDRWinTrackTypeMode1Raw: { sector_offset = 16; sector_size = 2048; sector_skip = 288; break; } case CDRWinTrackTypeMode2Raw: { sector_offset = 16; sector_size = 2336; sector_skip = 0; break; } case CDRWinTrackTypeCDIRaw: { sector_offset = 16; sector_size = 2336; sector_skip = 0; break; } case CDRWinTrackTypeCDG: { sector_offset = 0; sector_size = 2352; sector_skip = 96; break; } default: throw new FeatureSupportedButNotImplementedImageException("Unsupported track type"); } byte[] buffer = new byte[sector_size * length]; imageStream = _track.trackfile.datafilter.GetDataForkStream(); BinaryReader br = new BinaryReader(imageStream); br.BaseStream.Seek((long)_track.trackfile.offset + (long)(sectorAddress * (sector_offset + sector_size + sector_skip)), SeekOrigin.Begin); if(sector_offset == 0 && sector_skip == 0) buffer = br.ReadBytes((int)(sector_size * length)); else { for(int i = 0; i < length; i++) { byte[] sector; br.BaseStream.Seek(sector_offset, SeekOrigin.Current); sector = br.ReadBytes((int)sector_size); br.BaseStream.Seek(sector_skip, SeekOrigin.Current); Array.Copy(sector, 0, buffer, i * sector_size, sector_size); } } return buffer; } public override byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag) { CDRWinTrack _track = new CDRWinTrack(); _track.sequence = 0; foreach(CDRWinTrack cdrwin_track in discimage.tracks) { if(cdrwin_track.sequence == track) { _track = cdrwin_track; break; } } if(_track.sequence == 0) throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image"); if(length > _track.sectors) throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than present in track, won't cross tracks"); uint sector_offset; uint sector_size; uint sector_skip; switch(tag) { case SectorTagType.CDSectorECC: case SectorTagType.CDSectorECC_P: case SectorTagType.CDSectorECC_Q: case SectorTagType.CDSectorEDC: case SectorTagType.CDSectorHeader: case SectorTagType.CDSectorSubchannel: case SectorTagType.CDSectorSubHeader: case SectorTagType.CDSectorSync: break; case SectorTagType.CDTrackFlags: { byte[] flags = new byte[1]; if(_track.tracktype != CDRWinTrackTypeAudio && _track.tracktype != CDRWinTrackTypeCDG) flags[0] += 0x40; if(_track.flag_dcp) flags[0] += 0x20; if(_track.flag_pre) flags[0] += 0x10; if(_track.flag_4ch) flags[0] += 0x80; return flags; } case SectorTagType.CDTrackISRC: return Encoding.UTF8.GetBytes(_track.isrc); case SectorTagType.CDTrackText: throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); default: throw new ArgumentException("Unsupported tag requested", nameof(tag)); } switch(_track.tracktype) { case CDRWinTrackTypeMode1: case CDRWinTrackTypeMode2Form1: case CDRWinTrackTypeMode2Form2: throw new ArgumentException("No tags in image for requested track", nameof(tag)); case CDRWinTrackTypeMode2Formless: case CDRWinTrackTypeCDI: { switch(tag) { case SectorTagType.CDSectorSync: case SectorTagType.CDSectorHeader: case SectorTagType.CDSectorSubchannel: case SectorTagType.CDSectorECC: case SectorTagType.CDSectorECC_P: case SectorTagType.CDSectorECC_Q: throw new ArgumentException("Unsupported tag requested for this track", nameof(tag)); case SectorTagType.CDSectorSubHeader: { sector_offset = 0; sector_size = 8; sector_skip = 2328; break; } case SectorTagType.CDSectorEDC: { sector_offset = 2332; sector_size = 4; sector_skip = 0; break; } default: throw new ArgumentException("Unsupported tag requested", nameof(tag)); } break; } case CDRWinTrackTypeAudio: throw new ArgumentException("There are no tags on audio tracks", nameof(tag)); case CDRWinTrackTypeMode1Raw: { switch(tag) { case SectorTagType.CDSectorSync: { sector_offset = 0; sector_size = 12; sector_skip = 2340; break; } case SectorTagType.CDSectorHeader: { sector_offset = 12; sector_size = 4; sector_skip = 2336; break; } case SectorTagType.CDSectorSubchannel: case SectorTagType.CDSectorSubHeader: throw new ArgumentException("Unsupported tag requested for this track", nameof(tag)); case SectorTagType.CDSectorECC: { sector_offset = 2076; sector_size = 276; sector_skip = 0; break; } case SectorTagType.CDSectorECC_P: { sector_offset = 2076; sector_size = 172; sector_skip = 104; break; } case SectorTagType.CDSectorECC_Q: { sector_offset = 2248; sector_size = 104; sector_skip = 0; break; } case SectorTagType.CDSectorEDC: { sector_offset = 2064; sector_size = 4; sector_skip = 284; break; } default: throw new ArgumentException("Unsupported tag requested", nameof(tag)); } break; } case CDRWinTrackTypeMode2Raw: // Requires reading sector case CDRWinTrackTypeCDIRaw: throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented"); case CDRWinTrackTypeCDG: { if(tag != SectorTagType.CDSectorSubchannel) throw new ArgumentException("Unsupported tag requested for this track", nameof(tag)); sector_offset = 2352; sector_size = 96; sector_skip = 0; break; } default: throw new FeatureSupportedButNotImplementedImageException("Unsupported track type"); } byte[] buffer = new byte[sector_size * length]; imageStream = _track.trackfile.datafilter.GetDataForkStream(); BinaryReader br = new BinaryReader(imageStream); br.BaseStream.Seek((long)_track.trackfile.offset + (long)(sectorAddress * (sector_offset + sector_size + sector_skip)), SeekOrigin.Begin); if(sector_offset == 0 && sector_skip == 0) buffer = br.ReadBytes((int)(sector_size * length)); else { for(int i = 0; i < length; i++) { byte[] sector; br.BaseStream.Seek(sector_offset, SeekOrigin.Current); sector = br.ReadBytes((int)sector_size); br.BaseStream.Seek(sector_skip, SeekOrigin.Current); Array.Copy(sector, 0, buffer, i * sector_size, sector_size); } } return buffer; } public override byte[] ReadSectorLong(ulong sectorAddress) { return ReadSectorsLong(sectorAddress, 1); } public override byte[] ReadSectorLong(ulong sectorAddress, uint track) { return ReadSectorsLong(sectorAddress, 1, track); } public override byte[] ReadSectorsLong(ulong sectorAddress, uint length) { foreach(KeyValuePair<uint, ulong> kvp in offsetmap) { if(sectorAddress >= kvp.Value) { foreach(CDRWinTrack cdrwin_track in discimage.tracks) { if(cdrwin_track.sequence == kvp.Key) { if((sectorAddress - kvp.Value) < cdrwin_track.sectors) return ReadSectorsLong((sectorAddress - kvp.Value), length, kvp.Key); } } } } throw new ArgumentOutOfRangeException(nameof(sectorAddress), "Sector address not found"); } public override byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track) { CDRWinTrack _track = new CDRWinTrack(); _track.sequence = 0; foreach(CDRWinTrack cdrwin_track in discimage.tracks) { if(cdrwin_track.sequence == track) { _track = cdrwin_track; break; } } if(_track.sequence == 0) throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image"); if(length > _track.sectors) throw new ArgumentOutOfRangeException(nameof(length), "Requested more sectors than present in track, won't cross tracks"); uint sector_offset; uint sector_size; uint sector_skip; switch(_track.tracktype) { case CDRWinTrackTypeMode1: case CDRWinTrackTypeMode2Form1: { sector_offset = 0; sector_size = 2048; sector_skip = 0; break; } case CDRWinTrackTypeMode2Form2: { sector_offset = 0; sector_size = 2324; sector_skip = 0; break; } case CDRWinTrackTypeMode2Formless: case CDRWinTrackTypeCDI: { sector_offset = 0; sector_size = 2336; sector_skip = 0; break; } case CDRWinTrackTypeMode1Raw: case CDRWinTrackTypeMode2Raw: case CDRWinTrackTypeCDIRaw: case CDRWinTrackTypeAudio: { sector_offset = 0; sector_size = 2352; sector_skip = 0; break; } case CDRWinTrackTypeCDG: { sector_offset = 0; sector_size = 2448; sector_skip = 0; break; } default: throw new FeatureSupportedButNotImplementedImageException("Unsupported track type"); } byte[] buffer = new byte[sector_size * length]; imageStream = _track.trackfile.datafilter.GetDataForkStream(); BinaryReader br = new BinaryReader(imageStream); br.BaseStream.Seek((long)_track.trackfile.offset + (long)(sectorAddress * (sector_offset + sector_size + sector_skip)), SeekOrigin.Begin); if(sector_offset == 0 && sector_skip == 0) buffer = br.ReadBytes((int)(sector_size * length)); else { for(int i = 0; i < length; i++) { byte[] sector; br.BaseStream.Seek(sector_offset, SeekOrigin.Current); sector = br.ReadBytes((int)sector_size); br.BaseStream.Seek(sector_skip, SeekOrigin.Current); Array.Copy(sector, 0, buffer, i * sector_size, sector_size); } } return buffer; } public override string GetImageFormat() { return "CDRWin CUESheet"; } public override string GetImageVersion() { return ImageInfo.imageVersion; } public override string GetImageApplication() { return ImageInfo.imageApplication; } public override string GetImageApplicationVersion() { return ImageInfo.imageApplicationVersion; } public override DateTime GetImageCreationTime() { return ImageInfo.imageCreationTime; } public override DateTime GetImageLastModificationTime() { return ImageInfo.imageLastModificationTime; } public override string GetImageComments() { return ImageInfo.imageComments; } public override string GetMediaSerialNumber() { return ImageInfo.mediaSerialNumber; } public override string GetMediaBarcode() { return ImageInfo.mediaBarcode; } public override MediaType GetMediaType() { return ImageInfo.mediaType; } public override List<Partition> GetPartitions() { return partitions; } public override List<Track> GetTracks() { List<Track> tracks = new List<Track>(); ulong previousStartSector = 0; foreach(CDRWinTrack cdr_track in discimage.tracks) { Track _track = new Track(); _track.Indexes = cdr_track.indexes; _track.TrackDescription = cdr_track.title; if(!cdr_track.indexes.TryGetValue(0, out _track.TrackStartSector)) cdr_track.indexes.TryGetValue(1, out _track.TrackStartSector); _track.TrackStartSector = previousStartSector; _track.TrackEndSector = _track.TrackStartSector + cdr_track.sectors - 1; _track.TrackPregap = cdr_track.pregap; _track.TrackSession = cdr_track.session; _track.TrackSequence = cdr_track.sequence; _track.TrackType = CDRWinTrackTypeToTrackType(cdr_track.tracktype); _track.TrackFile = cdr_track.trackfile.datafilter.GetFilename(); _track.TrackFilter = cdr_track.trackfile.datafilter; _track.TrackFileOffset = cdr_track.trackfile.offset; _track.TrackFileType = cdr_track.trackfile.filetype; _track.TrackRawBytesPerSector = cdr_track.bps; _track.TrackBytesPerSector = CDRWinTrackTypeToCookedBytesPerSector(cdr_track.tracktype); if(cdr_track.bps == 2448) { _track.TrackSubchannelFilter = cdr_track.trackfile.datafilter; _track.TrackSubchannelFile = cdr_track.trackfile.datafilter.GetFilename(); _track.TrackSubchannelOffset = cdr_track.trackfile.offset; _track.TrackSubchannelType = TrackSubchannelType.RawInterleaved; } else _track.TrackSubchannelType = TrackSubchannelType.None; tracks.Add(_track); previousStartSector = _track.TrackEndSector + 1; } return tracks; } public override List<Track> GetSessionTracks(Session session) { if(discimage.sessions.Contains(session)) { return GetSessionTracks(session.SessionSequence); } throw new ImageNotSupportedException("Session does not exist in disc image"); } public override List<Track> GetSessionTracks(ushort session) { List<Track> tracks = new List<Track>(); foreach(CDRWinTrack cdr_track in discimage.tracks) { if(cdr_track.session == session) { Track _track = new Track(); _track.Indexes = cdr_track.indexes; _track.TrackDescription = cdr_track.title; if(!cdr_track.indexes.TryGetValue(0, out _track.TrackStartSector)) cdr_track.indexes.TryGetValue(1, out _track.TrackStartSector); _track.TrackEndSector = _track.TrackStartSector + cdr_track.sectors - 1; _track.TrackPregap = cdr_track.pregap; _track.TrackSession = cdr_track.session; _track.TrackSequence = cdr_track.sequence; _track.TrackType = CDRWinTrackTypeToTrackType(cdr_track.tracktype); _track.TrackFile = cdr_track.trackfile.datafilter.GetFilename(); _track.TrackFilter = cdr_track.trackfile.datafilter; _track.TrackFileOffset = cdr_track.trackfile.offset; _track.TrackFileType = cdr_track.trackfile.filetype; _track.TrackRawBytesPerSector = cdr_track.bps; _track.TrackBytesPerSector = CDRWinTrackTypeToCookedBytesPerSector(cdr_track.tracktype); if(cdr_track.bps == 2448) { _track.TrackSubchannelFilter = cdr_track.trackfile.datafilter; _track.TrackSubchannelFile = cdr_track.trackfile.datafilter.GetFilename(); _track.TrackSubchannelOffset = cdr_track.trackfile.offset; _track.TrackSubchannelType = TrackSubchannelType.RawInterleaved; } else _track.TrackSubchannelType = TrackSubchannelType.None; tracks.Add(_track); } } return tracks; } public override List<Session> GetSessions() { return discimage.sessions; } public override bool? VerifySector(ulong sectorAddress) { byte[] buffer = ReadSectorLong(sectorAddress); return Checksums.CDChecksums.CheckCDSector(buffer); } public override bool? VerifySector(ulong sectorAddress, uint track) { byte[] buffer = ReadSectorLong(sectorAddress, track); return Checksums.CDChecksums.CheckCDSector(buffer); } public override bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> FailingLBAs, out List<ulong> UnknownLBAs) { byte[] buffer = ReadSectorsLong(sectorAddress, length); int bps = (int)(buffer.Length / length); byte[] sector = new byte[bps]; FailingLBAs = new List<ulong>(); UnknownLBAs = new List<ulong>(); for(int i = 0; i < length; i++) { Array.Copy(buffer, i * bps, sector, 0, bps); bool? sectorStatus = Checksums.CDChecksums.CheckCDSector(sector); switch(sectorStatus) { case null: UnknownLBAs.Add((ulong)i + sectorAddress); break; case false: FailingLBAs.Add((ulong)i + sectorAddress); break; } } if(UnknownLBAs.Count > 0) return null; if(FailingLBAs.Count > 0) return false; return true; } public override bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> FailingLBAs, out List<ulong> UnknownLBAs) { byte[] buffer = ReadSectorsLong(sectorAddress, length, track); int bps = (int)(buffer.Length / length); byte[] sector = new byte[bps]; FailingLBAs = new List<ulong>(); UnknownLBAs = new List<ulong>(); for(int i = 0; i < length; i++) { Array.Copy(buffer, i * bps, sector, 0, bps); bool? sectorStatus = Checksums.CDChecksums.CheckCDSector(sector); switch(sectorStatus) { case null: UnknownLBAs.Add((ulong)i + sectorAddress); break; case false: FailingLBAs.Add((ulong)i + sectorAddress); break; } } if(UnknownLBAs.Count > 0) return null; if(FailingLBAs.Count > 0) return false; return true; } public override bool? VerifyMediaImage() { return null; } #endregion #region Private methods static ulong CDRWinMSFToLBA(string MSF) { string[] MSFElements; ulong minute, second, frame, sectors; MSFElements = MSF.Split(':'); minute = ulong.Parse(MSFElements[0]); second = ulong.Parse(MSFElements[1]); frame = ulong.Parse(MSFElements[2]); sectors = (minute * 60 * 75) + (second * 75) + frame; return sectors; } static ushort CDRWinTrackTypeToBytesPerSector(string trackType) { switch(trackType) { case CDRWinTrackTypeMode1: case CDRWinTrackTypeMode2Form1: return 2048; case CDRWinTrackTypeMode2Form2: return 2324; case CDRWinTrackTypeMode2Formless: case CDRWinTrackTypeCDI: return 2336; case CDRWinTrackTypeAudio: case CDRWinTrackTypeMode1Raw: case CDRWinTrackTypeMode2Raw: case CDRWinTrackTypeCDIRaw: return 2352; case CDRWinTrackTypeCDG: return 2448; default: return 0; } } static ushort CDRWinTrackTypeToCookedBytesPerSector(string trackType) { switch(trackType) { case CDRWinTrackTypeMode1: case CDRWinTrackTypeMode2Form1: case CDRWinTrackTypeMode1Raw: return 2048; case CDRWinTrackTypeMode2Form2: return 2324; case CDRWinTrackTypeMode2Formless: case CDRWinTrackTypeCDI: case CDRWinTrackTypeMode2Raw: case CDRWinTrackTypeCDIRaw: return 2336; case CDRWinTrackTypeAudio: return 2352; case CDRWinTrackTypeCDG: return 2448; default: return 0; } } static TrackType CDRWinTrackTypeToTrackType(string trackType) { switch(trackType) { case CDRWinTrackTypeMode1: case CDRWinTrackTypeMode1Raw: return TrackType.CDMode1; case CDRWinTrackTypeMode2Form1: return TrackType.CDMode2Form1; case CDRWinTrackTypeMode2Form2: return TrackType.CDMode2Form2; case CDRWinTrackTypeCDIRaw: case CDRWinTrackTypeCDI: case CDRWinTrackTypeMode2Raw: case CDRWinTrackTypeMode2Formless: return TrackType.CDMode2Formless; case CDRWinTrackTypeAudio: case CDRWinTrackTypeCDG: return TrackType.Audio; default: return TrackType.Data; } } static MediaType CDRWinIsoBusterDiscTypeToMediaType(string discType) { switch(discType) { case CDRWinDiskTypeCD: return MediaType.CD; case CDRWinDiskTypeCDRW: case CDRWinDiskTypeCDMRW: case CDRWinDiskTypeCDMRW2: return MediaType.CDRW; case CDRWinDiskTypeDVD: return MediaType.DVDROM; case CDRWinDiskTypeDVDPRW: case CDRWinDiskTypeDVDPMRW: case CDRWinDiskTypeDVDPMRW2: return MediaType.DVDPRW; case CDRWinDiskTypeDVDPRWDL: case CDRWinDiskTypeDVDPMRWDL: case CDRWinDiskTypeDVDPMRWDL2: return MediaType.DVDPRWDL; case CDRWinDiskTypeDVDPR: case CDRWinDiskTypeDVDPVR: return MediaType.DVDPR; case CDRWinDiskTypeDVDPRDL: return MediaType.DVDPRDL; case CDRWinDiskTypeDVDRAM: return MediaType.DVDRAM; case CDRWinDiskTypeDVDVR: case CDRWinDiskTypeDVDR: return MediaType.DVDR; case CDRWinDiskTypeDVDRDL: return MediaType.DVDRDL; case CDRWinDiskTypeDVDRW: case CDRWinDiskTypeDVDRWDL: case CDRWinDiskTypeDVDRW2: return MediaType.DVDRW; case CDRWinDiskTypeHDDVD: return MediaType.HDDVDROM; case CDRWinDiskTypeHDDVDRAM: return MediaType.HDDVDRAM; case CDRWinDiskTypeHDDVDR: case CDRWinDiskTypeHDDVDRDL: return MediaType.HDDVDR; case CDRWinDiskTypeHDDVDRW: case CDRWinDiskTypeHDDVDRWDL: return MediaType.HDDVDRW; case CDRWinDiskTypeBD: return MediaType.BDROM; case CDRWinDiskTypeBDR: case CDRWinDiskTypeBDRDL: return MediaType.BDR; case CDRWinDiskTypeBDRE: case CDRWinDiskTypeBDREDL: return MediaType.BDRE; default: return MediaType.Unknown; } } #endregion #region Unsupported features public override int GetMediaSequence() { return ImageInfo.mediaSequence; } public override int GetLastDiskSequence() { return ImageInfo.lastMediaSequence; } public override string GetDriveManufacturer() { return ImageInfo.driveManufacturer; } public override string GetDriveModel() { return ImageInfo.driveModel; } public override string GetDriveSerialNumber() { return ImageInfo.driveSerialNumber; } public override string GetMediaPartNumber() { return ImageInfo.mediaPartNumber; } public override string GetMediaManufacturer() { return ImageInfo.mediaManufacturer; } public override string GetMediaModel() { return ImageInfo.mediaModel; } public override string GetImageName() { return ImageInfo.imageName; } public override string GetImageCreator() { return ImageInfo.imageCreator; } #endregion } }