\\d+)\\s*\\{";
+ const string ClosureRegEx = "^\\s*\\}";
+ const string LanguageMapRegEx = "^\\s*LANGUAGE_MAP\\s*\\{";
+ const string LanguageMappingRegEx = "^\\s*(?\\d+)\\s?\\:\\s?(?\\d+|\\w+)";
+
+ #endregion
+
+ #region Public methods
+
+ public CDRDAO()
+ {
+ Name = "CDRDAO tocfile";
+ PluginUUID = new Guid("04D7BA12-1BE8-44D4-97A4-1B48A505463E");
+ imagePath = "";
+ ImageInfo = new ImageInfo();
+ ImageInfo.readableSectorTags = new List();
+ ImageInfo.readableDiskTags = new List();
+ ImageInfo.imageHasPartitions = true;
+ ImageInfo.imageHasSessions = true;
+ ImageInfo.imageVersion = null;
+ ImageInfo.imageApplicationVersion = null;
+ ImageInfo.imageName = null;
+ ImageInfo.imageCreator = null;
+ ImageInfo.diskManufacturer = null;
+ ImageInfo.diskModel = null;
+ ImageInfo.diskPartNumber = null;
+ ImageInfo.diskSequence = 0;
+ ImageInfo.lastDiskSequence = 0;
+ ImageInfo.driveManufacturer = null;
+ ImageInfo.driveModel = null;
+ ImageInfo.driveSerialNumber = null;
+ }
+
+ #endregion Public methods
+
+ public override bool IdentifyImage(string imagePath)
+ {
+ this.imagePath = imagePath;
+
+ try
+ {
+ tocStream = new StreamReader(this.imagePath);
+ string _line = tocStream.ReadLine();
+
+ Regex Dr = new Regex(DiskTypeRegEx);
+ Match Dm;
+
+ Dm = Dr.Match(_line);
+
+ return Dm.Success;
+ }
+ catch (Exception ex)
+ {
+ DicConsole.ErrorWriteLine("Exception trying to identify image file {0}", this.imagePath);
+ DicConsole.ErrorWriteLine("Exception: {0}", ex.Message);
+ DicConsole.ErrorWriteLine("Stack trace: {0}", ex.StackTrace);
+ return false;
+ }
+ }
+
+ #region Not implemented methods
+
+ public override bool OpenImage(string imagePath)
+ {
+ if (imagePath == null)
+ return false;
+ if (imagePath == "")
+ return false;
+
+ this.imagePath = imagePath;
+
+ try
+ {
+ tocStream = new StreamReader(imagePath);
+ int line = 0;
+ bool intrack = false;
+
+ // Initialize all RegExs
+ Regex RegexComment = new Regex(CommentRegEx);
+ Regex RegexDiskType = new Regex(DiskTypeRegEx);
+ Regex RegexMCN = new Regex(MCNRegEx);
+ Regex RegexTrack = new Regex(TrackRegEx);
+ Regex RegexCopy = new Regex(CopyRegEx);
+ Regex RegexEmphasis = new Regex(EmphasisRegEx);
+ Regex RegexStereo = new Regex(StereoRegEx);
+ Regex RegexISRC = new Regex(ISRCRegEx);
+ Regex RegexIndex = new Regex(IndexRegEx);
+ Regex RegexPregap = new Regex(PregapRegEx);
+ Regex RegexZeroPregap = new Regex(ZeroPregapRegEx);
+ Regex RegexZeroData = new Regex(ZeroDataRegEx);
+ Regex RegexZeroAudio = new Regex(ZeroAudioRegEx);
+ Regex RegexAudioFile = new Regex(AudioFileRegEx);
+ Regex RegexFile = new Regex(FileRegEx);
+ Regex RegexTitle = new Regex(TitleRegEx);
+ Regex RegexPerformer = new Regex(PerformerRegEx);
+ Regex RegexSongwriter = new Regex(SongwriterRegEx);
+ Regex RegexComposer = new Regex(ComposerRegEx);
+ Regex RegexArranger = new Regex(ArrangerRegEx);
+ Regex RegexMessage = new Regex(MessageRegEx);
+ Regex RegexDiscID = new Regex(DiscIDRegEx);
+ Regex RegexUPC = new Regex(UPCRegEx);
+ Regex RegexCDText = new Regex(CDTextRegEx);
+ Regex RegexLanguage = new Regex(LanguageRegEx);
+ Regex RegexClosure = new Regex(ClosureRegEx);
+ Regex RegexLanguageMap = new Regex(LanguageMapRegEx);
+ Regex RegexLanguageMapping = new Regex(LanguageMappingRegEx);
+
+ // Initialize all RegEx matches
+ Match MatchComment;
+ Match MatchDiskType;
+ Match MatchMCN;
+ Match MatchTrack;
+ Match MatchCopy;
+ Match MatchEmphasis;
+ Match MatchStereo;
+ Match MatchISRC;
+ Match MatchIndex;
+ Match MatchPregap;
+ Match MatchZeroPregap;
+ Match MatchZeroData;
+ Match MatchZeroAudio;
+ Match MatchAudioFile;
+ Match MatchFile;
+ Match MatchTitle;
+ Match MatchPerformer;
+ Match MatchSongwriter;
+ Match MatchComposer;
+ Match MatchArranger;
+ Match MatchMessage;
+ Match MatchDiscID;
+ Match MatchUPC;
+ Match MatchCDText;
+ Match MatchLanguage;
+ Match MatchClosure;
+ Match MatchLanguageMap;
+ Match MatchLanguageMapping;
+
+ // Initialize disc
+ discimage = new CDRDAODisc();
+ discimage.tracks = new List();
+ discimage.comment = "";
+
+ CDRDAOTrack currenttrack = new CDRDAOTrack();
+ uint currentTrackNumber = 0;
+ currenttrack.indexes = new Dictionary();
+ currenttrack.pregap = 0;
+ ulong currentSector = 0;
+ int nextindex = 2;
+ StringBuilder commentBuilder = new StringBuilder();
+
+ tocStream = new StreamReader(this.imagePath);
+ string _line = tocStream.ReadLine();
+
+ MatchDiskType = RegexDiskType.Match(_line);
+
+ if (!MatchDiskType.Success)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Not a CDRDAO TOC or TOC type not in first line.");
+ return false;
+ }
+
+ tocStream.Close();
+ tocStream = new StreamReader(this.imagePath);
+
+ while (tocStream.Peek() >= 0)
+ {
+ line++;
+ _line = tocStream.ReadLine();
+
+ MatchComment = RegexComment.Match(_line);
+ MatchDiskType = RegexDiskType.Match(_line);
+ MatchMCN = RegexMCN.Match(_line);
+ MatchTrack = RegexTrack.Match(_line);
+ MatchCopy = RegexCopy.Match(_line);
+ MatchEmphasis = RegexEmphasis.Match(_line);
+ MatchStereo = RegexStereo.Match(_line);
+ MatchISRC = RegexISRC.Match(_line);
+ MatchIndex = RegexIndex.Match(_line);
+ MatchPregap = RegexPregap.Match(_line);
+ MatchZeroPregap = RegexZeroPregap.Match(_line);
+ MatchZeroData = RegexZeroData.Match(_line);
+ MatchZeroAudio = RegexZeroAudio.Match(_line);
+ MatchAudioFile = RegexAudioFile.Match(_line);
+ MatchFile = RegexFile.Match(_line);
+ MatchTitle = RegexTitle.Match(_line);
+ MatchPerformer = RegexPerformer.Match(_line);
+ MatchSongwriter = RegexSongwriter.Match(_line);
+ MatchComposer = RegexComposer.Match(_line);
+ MatchArranger = RegexArranger.Match(_line);
+ MatchMessage = RegexMessage.Match(_line);
+ MatchDiscID = RegexDiscID.Match(_line);
+ MatchUPC = RegexUPC.Match(_line);
+ MatchCDText = RegexCDText.Match(_line);
+ MatchLanguage = RegexLanguage.Match(_line);
+ MatchClosure = RegexClosure.Match(_line);
+ MatchLanguageMap = RegexLanguageMap.Match(_line);
+ MatchLanguageMapping = RegexLanguageMapping.Match(_line);
+
+ if (MatchComment.Success)
+ {
+ // Ignore "// Track X" comments
+ if (!MatchComment.Groups["comment"].Value.StartsWith(" Track ", StringComparison.Ordinal))
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found comment \"{1}\" at line {0}", line, MatchComment.Groups["comment"].Value.Trim());
+ commentBuilder.AppendLine(MatchComment.Groups["comment"].Value.Trim());
+ }
+ }
+ else if (MatchDiskType.Success)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found {1} at line {0}", line, MatchDiskType.Groups["type"].Value);
+ discimage.disktypestr = MatchDiskType.Groups["type"].Value;
+ switch (MatchDiskType.Groups["type"].Value)
+ {
+ case "CD_DA":
+ discimage.disktype = DiskType.CDDA;
+ break;
+ case "CD_ROM":
+ discimage.disktype = DiskType.CDROM;
+ break;
+ case "CD_ROM_XA":
+ discimage.disktype = DiskType.CDROMXA;
+ break;
+ case "CD_I":
+ discimage.disktype = DiskType.CDI;
+ break;
+ default:
+ discimage.disktype = DiskType.CD;
+ break;
+ }
+ }
+ else if (MatchMCN.Success)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found CATALOG \"{1}\" at line {0}", line, MatchMCN.Groups["catalog"].Value);
+ discimage.mcn = MatchMCN.Groups["catalog"].Value;
+ }
+ else if (MatchTrack.Success)
+ {
+ if (MatchTrack.Groups["subchan"].Value == "")
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found TRACK type \"{1}\" with no subchannel at line {0}", line, MatchTrack.Groups["type"].Value);
+ else
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found TRACK type \"{1}\" subchannel {2} at line {0}", line, MatchTrack.Groups["type"].Value, MatchTrack.Groups["subchan"].Value);
+
+ if (intrack)
+ {
+ currentSector += currenttrack.sectors;
+ if(currenttrack.pregap != currenttrack.sectors && !currenttrack.indexes.ContainsKey(1))
+ currenttrack.indexes.Add(1, currenttrack.startSector + currenttrack.pregap);
+ discimage.tracks.Add(currenttrack);
+ currenttrack = new CDRDAOTrack();
+ currenttrack.indexes = new Dictionary();
+ currenttrack.pregap = 0;
+ nextindex = 2;
+ }
+ currentTrackNumber++;
+ intrack = true;
+
+ switch (MatchTrack.Groups["type"].Value)
+ {
+ case "AUDIO":
+ case "MODE1_RAW":
+ case "MODE2_RAW":
+ currenttrack.bps = 2352;
+ break;
+ case "MODE1":
+ case "MODE2_FORM1":
+ currenttrack.bps = 2048;
+ break;
+ case "MODE2_FORM2":
+ currenttrack.bps = 2324;
+ break;
+ case "MODE2":
+ case "MODE2_FORM_MIX":
+ currenttrack.bps = 2336;
+ break;
+ default:
+ throw new NotSupportedException(String.Format("Track mode {0} is unsupported", MatchTrack.Groups["type"].Value));
+ }
+
+ switch (MatchTrack.Groups["subchan"].Value)
+ {
+ case "":
+ break;
+ case "RW":
+ currenttrack.packedsubchannel = true;
+ goto case "RW_RAW";
+ case "RW_RAW":
+ currenttrack.bps += 96;
+ currenttrack.subchannel = true;
+ break;
+ default:
+ throw new NotSupportedException(String.Format("Track subchannel mode {0} is unsupported", MatchTrack.Groups["subchan"].Value));
+ }
+
+ currenttrack.tracktype = MatchTrack.Groups["type"].Value;
+
+ currenttrack.sequence = currentTrackNumber;
+ currenttrack.startSector = currentSector;
+ }
+ else if (MatchCopy.Success)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found {1} COPY at line {0}", line, MatchCopy.Groups["no"].Value);
+ currenttrack.flag_dcp |= intrack && MatchCopy.Groups["no"].Value == "";
+ }
+ else if (MatchEmphasis.Success)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found {1} PRE_EMPHASIS at line {0}", line, MatchEmphasis.Groups["no"].Value);
+ currenttrack.flag_pre |= intrack && MatchCopy.Groups["no"].Value == "";
+ }
+ else if (MatchStereo.Success)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found {1}_CHANNEL_AUDIO at line {0}", line, MatchStereo.Groups["num"].Value);
+ currenttrack.flag_4ch |= intrack && MatchCopy.Groups["num"].Value == "FOUR";
+ }
+ else if (MatchISRC.Success)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found ISRC \"{1}\" at line {0}", line, MatchISRC.Groups["isrc"].Value);
+ if (intrack)
+ currenttrack.isrc = MatchISRC.Groups["isrc"].Value;
+ }
+ else if (MatchIndex.Success)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found INDEX \"{1}\" at line {0}", line, MatchIndex.Groups["address"].Value);
+
+ string[] lengthString = MatchFile.Groups["length"].Value.Split(new char[] { ':' });
+ ulong nextIndexPos = ulong.Parse(lengthString[0]) * 60 * 75 + ulong.Parse(lengthString[1]) * 75 + ulong.Parse(lengthString[2]);
+ currenttrack.indexes.Add(nextindex, nextIndexPos + currenttrack.pregap + currenttrack.startSector);
+ }
+ else if (MatchPregap.Success)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found START \"{1}\" at line {0}", line, MatchPregap.Groups["address"].Value);
+
+ currenttrack.indexes.Add(0, currenttrack.startSector);
+ if(MatchPregap.Groups["address"].Value != "")
+ {
+ string[] lengthString = MatchPregap.Groups["address"].Value.Split(new char[] { ':' });
+ currenttrack.pregap = ulong.Parse(lengthString[0]) * 60 * 75 + ulong.Parse(lengthString[1]) * 75 + ulong.Parse(lengthString[2]);
+ }
+ else
+ currenttrack.pregap = currenttrack.sectors;
+ }
+ else if (MatchZeroPregap.Success)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found PREGAP \"{1}\" at line {0}", line, MatchZeroPregap.Groups["length"].Value);
+ currenttrack.indexes.Add(0, currenttrack.startSector);
+ string[] lengthString = MatchZeroPregap.Groups["length"].Value.Split(new char[] { ':' });
+ currenttrack.pregap = ulong.Parse(lengthString[0]) * 60 * 75 + ulong.Parse(lengthString[1]) * 75 + ulong.Parse(lengthString[2]);
+ }
+ else if (MatchZeroData.Success)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found ZERO \"{1}\" at line {0}", line, MatchZeroData.Groups["length"].Value);
+ // Seems can be ignored as the data is still in the image
+ }
+ else if (MatchZeroAudio.Success)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found SILENCE \"{1}\" at line {0}", line, MatchZeroAudio.Groups["length"].Value);
+ // Seems can be ignored as the data is still in the image
+ }
+ else if (MatchAudioFile.Success)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found AUDIOFILE \"{1}\" at line {0}", line, MatchAudioFile.Groups["filename"].Value);
+
+ currenttrack.trackfile = new CDRDAOTrackFile();
+ currenttrack.trackfile.datafile = MatchAudioFile.Groups["filename"].Value;
+ currenttrack.trackfile.offset = MatchAudioFile.Groups["base_offset"].Value != "" ? ulong.Parse(MatchAudioFile.Groups["base_offset"].Value) : 0;
+
+ currenttrack.trackfile.filetype = "BINARY";
+ currenttrack.trackfile.sequence = currentTrackNumber;
+
+ ulong startSectors = 0;
+
+ if (MatchFile.Groups["start"].Value != "")
+ {
+ string[] startString = MatchAudioFile.Groups["start"].Value.Split(new char[] { ':' });
+ startSectors = ulong.Parse(startString[0]) * 60 * 75 + ulong.Parse(startString[1]) * 75 + ulong.Parse(startString[2]);
+ }
+
+ currenttrack.trackfile.offset += (startSectors * currenttrack.bps);
+
+ if (MatchFile.Groups["length"].Value != "")
+ {
+ string[] lengthString = MatchAudioFile.Groups["length"].Value.Split(new char[] { ':' });
+ currenttrack.sectors = ulong.Parse(lengthString[0]) * 60 * 75 + ulong.Parse(lengthString[1]) * 75 + ulong.Parse(lengthString[2]);
+ }
+ else
+ {
+ FileInfo pfi = new FileInfo(currenttrack.trackfile.datafile);
+ currenttrack.sectors = ((ulong)pfi.Length - currenttrack.trackfile.offset) / currenttrack.bps;
+ }
+ }
+ else if (MatchFile.Success)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found DATAFILE \"{1}\" at line {0}", line, MatchFile.Groups["filename"].Value);
+
+ currenttrack.trackfile = new CDRDAOTrackFile();
+ currenttrack.trackfile.datafile = MatchFile.Groups["filename"].Value;
+ currenttrack.trackfile.offset = MatchFile.Groups["base_offset"].Value != "" ? ulong.Parse(MatchFile.Groups["base_offset"].Value) : 0;
+
+ currenttrack.trackfile.filetype = "BINARY";
+ currenttrack.trackfile.sequence = currentTrackNumber;
+ if (MatchFile.Groups["length"].Value != "")
+ {
+ string[] lengthString = MatchFile.Groups["length"].Value.Split(new char[] { ':' });
+ currenttrack.sectors = ulong.Parse(lengthString[0]) * 60 * 75 + ulong.Parse(lengthString[1]) * 75 + ulong.Parse(lengthString[2]);
+ }
+ else
+ {
+ FileInfo pfi = new FileInfo(currenttrack.trackfile.datafile);
+ currenttrack.sectors = ((ulong)pfi.Length - currenttrack.trackfile.offset) / currenttrack.bps;
+ }
+ }
+ else if (MatchTitle.Success)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found TITLE \"{1}\" at line {0}", line, MatchTitle.Groups["title"].Value);
+ if (intrack)
+ currenttrack.title = MatchTitle.Groups["title"].Value;
+ else
+ discimage.title = MatchTitle.Groups["title"].Value;
+ }
+ else if (MatchPerformer.Success)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found PERFORMER \"{1}\" at line {0}", line, MatchPerformer.Groups["performer"].Value);
+ if (intrack)
+ currenttrack.performer = MatchPerformer.Groups["performer"].Value;
+ else
+ discimage.performer = MatchPerformer.Groups["performer"].Value;
+ }
+ else if (MatchSongwriter.Success)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found SONGWRITER \"{1}\" at line {0}", line, MatchSongwriter.Groups["songwriter"].Value);
+ if (intrack)
+ currenttrack.songwriter = MatchSongwriter.Groups["songwriter"].Value;
+ else
+ discimage.songwriter = MatchSongwriter.Groups["songwriter"].Value;
+ }
+ else if (MatchComposer.Success)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found COMPOSER \"{1}\" at line {0}", line, MatchComposer.Groups["composer"].Value);
+ if (intrack)
+ currenttrack.composer = MatchComposer.Groups["composer"].Value;
+ else
+ discimage.composer = MatchComposer.Groups["composer"].Value;
+ }
+ else if (MatchArranger.Success)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found ARRANGER \"{1}\" at line {0}", line, MatchArranger.Groups["arranger"].Value);
+ if (intrack)
+ currenttrack.arranger = MatchArranger.Groups["arranger"].Value;
+ else
+ discimage.arranger = MatchArranger.Groups["arranger"].Value;
+ }
+ else if (MatchMessage.Success)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found MESSAGE \"{1}\" at line {0}", line, MatchMessage.Groups["message"].Value);
+ if (intrack)
+ currenttrack.message = MatchMessage.Groups["message"].Value;
+ else
+ discimage.message = MatchMessage.Groups["message"].Value;
+ }
+ else if (MatchDiscID.Success)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found DISC_ID \"{1}\" at line {0}", line, MatchDiscID.Groups["discid"].Value);
+ if (!intrack)
+ discimage.disk_id = MatchDiscID.Groups["discid"].Value;
+ }
+ else if (MatchUPC.Success)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Found UPC_EAN \"{1}\" at line {0}", line, MatchUPC.Groups["catalog"].Value);
+ if (!intrack)
+ discimage.barcode = MatchUPC.Groups["catalog"].Value;
+ }
+ // Ignored fields
+ else if (MatchCDText.Success || MatchLanguage.Success || MatchClosure.Success ||
+ MatchLanguageMap.Success || MatchLanguageMapping.Success)
+ {
+
+ }
+ else if (_line == "") // Empty line, ignore it
+ {
+
+ }
+ // TODO: Regex CD-TEXT SIZE_INFO
+ /*
+ else // Non-empty unknown field
+ {
+ throw new FeatureUnsupportedImageException(String.Format("Found unknown field defined at line {0}: \"{1}\"", line, _line));
+ }
+ */
+ }
+
+ if (currenttrack.sequence != 0)
+ {
+ if(currenttrack.pregap != currenttrack.sectors && !currenttrack.indexes.ContainsKey(1))
+ currenttrack.indexes.Add(1, currenttrack.startSector + currenttrack.pregap);
+
+ discimage.tracks.Add(currenttrack);
+ }
+
+ discimage.comment = commentBuilder.ToString();
+
+ // DEBUG information
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Disc image parsing results");
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Disc CD-TEXT:");
+ if (discimage.arranger == null)
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tArranger is not set.");
+ else
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tArranger: {0}", discimage.arranger);
+ if (discimage.composer == null)
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tComposer is not set.");
+ else
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tComposer: {0}", discimage.composer);
+ if (discimage.performer == null)
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tPerformer is not set.");
+ else
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tPerformer: {0}", discimage.performer);
+ if (discimage.songwriter == null)
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tSongwriter is not set.");
+ else
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tSongwriter: {0}", discimage.songwriter);
+ if (discimage.title == null)
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tTitle is not set.");
+ else
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tTitle: {0}", discimage.title);
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Disc information:");
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tGuessed disk type: {0}", discimage.disktype);
+ if (discimage.barcode == null)
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tBarcode not set.");
+ else
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tBarcode: {0}", discimage.barcode);
+ if (discimage.disk_id == null)
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tDisc ID not set.");
+ else
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tDisc ID: {0}", discimage.disk_id);
+ if (discimage.mcn == null)
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tMCN not set.");
+ else
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tMCN: {0}", discimage.mcn);
+ if (string.IsNullOrEmpty(discimage.comment))
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tComment not set.");
+ else
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tComment: \"{0}\"", discimage.comment);
+
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Track information:");
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tDisc contains {0} tracks", discimage.tracks.Count);
+ for (int i = 0; i < discimage.tracks.Count; i++)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tTrack {0} information:", discimage.tracks[i].sequence);
+
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\t\t{0} bytes per sector", discimage.tracks[i].bps);
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\t\tPregap: {0} sectors", discimage.tracks[i].pregap);
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\t\tData: {0} sectors starting at sector {1}", discimage.tracks[i].sectors, discimage.tracks[i].startSector);
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\t\tPostgap: {0} sectors", discimage.tracks[i].postgap);
+
+ if (discimage.tracks[i].flag_4ch)
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\t\tTrack is flagged as quadraphonic");
+ if (discimage.tracks[i].flag_dcp)
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\t\tTrack allows digital copy");
+ if (discimage.tracks[i].flag_pre)
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\t\tTrack has pre-emphasis applied");
+
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\t\tTrack resides in file {0}, type defined as {1}, starting at byte {2}",
+ discimage.tracks[i].trackfile.datafile, discimage.tracks[i].trackfile.filetype, discimage.tracks[i].trackfile.offset);
+
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\t\tIndexes:");
+ foreach (KeyValuePair kvp in discimage.tracks[i].indexes)
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\t\t\tIndex {0} starts at sector {1}", kvp.Key, kvp.Value);
+
+ if (discimage.tracks[i].isrc == null)
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\t\tISRC is not set.");
+ else
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\t\tISRC: {0}", discimage.tracks[i].isrc);
+
+ if (discimage.tracks[i].arranger == null)
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\t\tArranger is not set.");
+ else
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\t\tArranger: {0}", discimage.tracks[i].arranger);
+ if (discimage.tracks[i].composer == null)
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\t\tComposer is not set.");
+ else
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\t\tComposer: {0}", discimage.tracks[i].composer);
+ if (discimage.tracks[i].performer == null)
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\t\tPerformer is not set.");
+ else
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\t\tPerformer: {0}", discimage.tracks[i].performer);
+ if (discimage.tracks[i].songwriter == null)
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\t\tSongwriter is not set.");
+ else
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\t\tSongwriter: {0}", discimage.tracks[i].songwriter);
+ if (discimage.tracks[i].title == null)
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\t\tTitle is not set.");
+ else
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\t\tTitle: {0}", discimage.tracks[i].title);
+ }
+
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Building offset map");
+
+ partitions = new List();
+ offsetmap = new Dictionary();
+
+ ulong byte_offset = 0;
+ ulong partitionSequence = 0;
+ 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();
+
+ // Index 01
+ partition.PartitionDescription = String.Format("Track {0}.", discimage.tracks[i].sequence);
+ partition.PartitionName = discimage.tracks[i].title;
+ partition.PartitionStartSector = discimage.tracks[i].startSector;
+ partition.PartitionLength = (discimage.tracks[i].sectors - index0_len) * discimage.tracks[i].bps;
+ partition.PartitionSectors = (discimage.tracks[i].sectors - index0_len);
+ partition.PartitionSequence = partitionSequence;
+ partition.PartitionStart = byte_offset;
+ partition.PartitionType = discimage.tracks[i].tracktype;
+
+ 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();
+ }
+
+ // Print partition map
+ DicConsole.DebugWriteLine("CDRDAO plugin", "printing partition map");
+ foreach (Partition partition in partitions)
+ {
+ DicConsole.DebugWriteLine("CDRDAO plugin", "Partition sequence: {0}", partition.PartitionSequence);
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tPartition name: {0}", partition.PartitionName);
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tPartition description: {0}", partition.PartitionDescription);
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tPartition type: {0}", partition.PartitionType);
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tPartition starting sector: {0}", partition.PartitionStartSector);
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tPartition sectors: {0}", partition.PartitionSectors);
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tPartition starting offset: {0}", partition.PartitionStart);
+ DicConsole.DebugWriteLine("CDRDAO plugin", "\tPartition size in bytes: {0}", partition.PartitionLength);
+ }
+
+ foreach (CDRDAOTrack track in discimage.tracks)
+ {
+ ImageInfo.imageSize += track.bps * track.sectors;
+ ImageInfo.sectors += track.sectors;
+ }
+
+ if (discimage.disktype == DiskType.CDG || discimage.disktype == DiskType.CDEG || discimage.disktype == DiskType.CDMIDI)
+ ImageInfo.sectorSize = 2448; // CD+G subchannels ARE user data, as CD+G are useless without them
+ else if (discimage.disktype != DiskType.CDROMXA && discimage.disktype != DiskType.CDDA && discimage.disktype != DiskType.CDI && discimage.disktype != DiskType.CDPLUS)
+ ImageInfo.sectorSize = 2048; // Only data tracks
+ else
+ ImageInfo.sectorSize = 2352; // All others
+
+ if (discimage.mcn != null)
+ ImageInfo.readableDiskTags.Add(DiskTagType.CD_MCN);
+
+ ImageInfo.imageApplication = "CDRDAO";
+
+ FileInfo fi = new FileInfo(discimage.tracks[0].trackfile.datafile);
+
+ ImageInfo.imageCreationTime = fi.CreationTimeUtc;
+ ImageInfo.imageLastModificationTime = fi.LastWriteTimeUtc;
+
+ ImageInfo.imageComments = discimage.comment;
+ ImageInfo.diskSerialNumber = discimage.mcn;
+ ImageInfo.diskBarcode = discimage.barcode;
+ ImageInfo.diskType = discimage.disktype;
+
+ ImageInfo.readableSectorTags.Add(SectorTagType.CDTrackFlags);
+
+ foreach (CDRDAOTrack track in discimage.tracks)
+ {
+ if (track.subchannel)
+ {
+ if (!ImageInfo.readableSectorTags.Contains(SectorTagType.CDSectorSubchannel))
+ ImageInfo.readableSectorTags.Add(SectorTagType.CDSectorSubchannel);
+ }
+
+ switch (track.tracktype)
+ {
+ case CDRDAOTrackTypeAudio:
+ {
+ if (!ImageInfo.readableSectorTags.Contains(SectorTagType.CDTrackISRC))
+ ImageInfo.readableSectorTags.Add(SectorTagType.CDTrackISRC);
+ break;
+ }
+ case CDRDAOTrackTypeMode2:
+ case CDRDAOTrackTypeMode2Mix:
+ {
+ if (!ImageInfo.readableSectorTags.Contains(SectorTagType.CDSectorSubHeader))
+ ImageInfo.readableSectorTags.Add(SectorTagType.CDSectorSubHeader);
+ if (!ImageInfo.readableSectorTags.Contains(SectorTagType.CDSectorEDC))
+ ImageInfo.readableSectorTags.Add(SectorTagType.CDSectorEDC);
+ break;
+ }
+ case CDRDAOTrackTypeMode2Raw:
+ {
+ 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 CDRDAOTrackTypeMode1Raw:
+ {
+ 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;
+
+ return true;
+ }
+ catch (Exception ex)
+ {
+ DicConsole.ErrorWriteLine("Exception trying to identify image file {0}", imagePath);
+ DicConsole.ErrorWriteLine("Exception: {0}", ex.Message);
+ DicConsole.ErrorWriteLine("Stack trace: {0}", ex.StackTrace);
+ return false;
+ }
+ }
+
+ public override bool ImageHasPartitions()
+ {
+ return ImageInfo.imageHasPartitions;
+ }
+
+ public override UInt64 GetImageSize()
+ {
+ return ImageInfo.imageSize;
+ }
+
+ public override UInt64 GetSectors()
+ {
+ return ImageInfo.sectors;
+ }
+
+ public override UInt32 GetSectorSize()
+ {
+ return ImageInfo.sectorSize;
+ }
+
+ public override byte[] ReadDiskTag(DiskTagType tag)
+ {
+ switch (tag)
+ {
+ case DiskTagType.CD_MCN:
+ {
+ if (discimage.mcn != null)
+ {
+ return Encoding.ASCII.GetBytes(discimage.mcn);
+ }
+ throw new FeatureNotPresentImageException("Image does not contain MCN information.");
+ }
+ default:
+ throw new FeatureSupportedButNotImplementedImageException("Feature not supported by image format");
+ }
+ }
+
+ public override byte[] ReadSector(UInt64 sectorAddress)
+ {
+ return ReadSectors(sectorAddress, 1);
+ }
+
+ public override byte[] ReadSectorTag(UInt64 sectorAddress, SectorTagType tag)
+ {
+ return ReadSectorsTag(sectorAddress, 1, tag);
+ }
+
+ public override byte[] ReadSector(UInt64 sectorAddress, UInt32 track)
+ {
+ return ReadSectors(sectorAddress, 1, track);
+ }
+
+ public override byte[] ReadSectorTag(UInt64 sectorAddress, UInt32 track, SectorTagType tag)
+ {
+ return ReadSectorsTag(sectorAddress, 1, track, tag);
+ }
+
+ public override byte[] ReadSectors(UInt64 sectorAddress, UInt32 length)
+ {
+ foreach (KeyValuePair kvp in offsetmap)
+ {
+ if (sectorAddress >= kvp.Value)
+ {
+ foreach (CDRDAOTrack cdrdao_track in discimage.tracks)
+ {
+ if (cdrdao_track.sequence == kvp.Key)
+ {
+ if ((sectorAddress - kvp.Value) < cdrdao_track.sectors)
+ return ReadSectors((sectorAddress - kvp.Value), length, kvp.Key);
+ }
+ }
+ }
+ }
+
+ throw new ArgumentOutOfRangeException("sectorAddress", String.Format("Sector address {0} not found", sectorAddress));
+ }
+
+ public override byte[] ReadSectorsTag(UInt64 sectorAddress, UInt32 length, SectorTagType tag)
+ {
+ foreach (KeyValuePair kvp in offsetmap)
+ {
+ if (sectorAddress >= kvp.Value)
+ {
+ foreach (CDRDAOTrack cdrdao_track in discimage.tracks)
+ {
+ if (cdrdao_track.sequence == kvp.Key)
+ {
+ if ((sectorAddress - kvp.Value) < cdrdao_track.sectors)
+ return ReadSectorsTag((sectorAddress - kvp.Value), length, kvp.Key, tag);
+ }
+ }
+ }
+ }
+
+ throw new ArgumentOutOfRangeException("sectorAddress", String.Format("Sector address {0} not found", sectorAddress));
+ }
+
+ public override byte[] ReadSectors(UInt64 sectorAddress, UInt32 length, UInt32 track)
+ {
+ CDRDAOTrack _track = new CDRDAOTrack();
+
+ _track.sequence = 0;
+
+ foreach (CDRDAOTrack cdrdao_track in discimage.tracks)
+ {
+ if (cdrdao_track.sequence == track)
+ {
+ _track = cdrdao_track;
+ break;
+ }
+ }
+
+ if (_track.sequence == 0)
+ throw new ArgumentOutOfRangeException("track", "Track does not exist in disc image");
+
+ if (length > _track.sectors)
+ throw new ArgumentOutOfRangeException("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 CDRDAOTrackTypeMode1:
+ case CDRDAOTrackTypeMode2Form1:
+ {
+ sector_offset = 0;
+ sector_size = 2048;
+ sector_skip = 0;
+ break;
+ }
+ case CDRDAOTrackTypeMode2Form2:
+ {
+ sector_offset = 0;
+ sector_size = 2324;
+ sector_skip = 0;
+ break;
+ }
+ case CDRDAOTrackTypeMode2:
+ case CDRDAOTrackTypeMode2Mix:
+ {
+ sector_offset = 0;
+ sector_size = 2336;
+ sector_skip = 0;
+ break;
+ }
+ case CDRDAOTrackTypeAudio:
+ {
+ sector_offset = 0;
+ sector_size = 2352;
+ sector_skip = 0;
+ break;
+ }
+ case CDRDAOTrackTypeMode1Raw:
+ {
+ sector_offset = 16;
+ sector_size = 2048;
+ sector_skip = 288;
+ break;
+ }
+ case CDRDAOTrackTypeMode2Raw:
+ {
+ sector_offset = 16;
+ sector_size = 2336;
+ sector_skip = 0;
+ break;
+ }
+ default:
+ throw new FeatureSupportedButNotImplementedImageException("Unsupported track type");
+ }
+
+ if (_track.subchannel)
+ sector_skip += 96;
+
+ byte[] buffer = new byte[sector_size * length];
+
+ imageStream = new FileStream(_track.trackfile.datafile, FileMode.Open, FileAccess.Read);
+ using (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(UInt64 sectorAddress, UInt32 length, UInt32 track, SectorTagType tag)
+ {
+ CDRDAOTrack _track = new CDRDAOTrack();
+
+ _track.sequence = 0;
+
+ foreach (CDRDAOTrack cdrdao_track in discimage.tracks)
+ {
+ if (cdrdao_track.sequence == track)
+ {
+ _track = cdrdao_track;
+ break;
+ }
+ }
+
+ if (_track.sequence == 0)
+ throw new ArgumentOutOfRangeException("track", "Track does not exist in disc image");
+
+ if (length > _track.sectors)
+ throw new ArgumentOutOfRangeException("length", "Requested more sectors than present in track, won't cross tracks");
+
+ uint sector_offset;
+ uint sector_size;
+ uint sector_skip = 0;
+
+ if (!_track.subchannel && tag == SectorTagType.CDSectorSubchannel)
+ throw new ArgumentException("No tags in image for requested track", "tag");
+
+ 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 != CDRDAOTrackTypeAudio)
+ 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);
+ default:
+ throw new ArgumentException("Unsupported tag requested", "tag");
+ }
+
+ switch (_track.tracktype)
+ {
+ case CDRDAOTrackTypeMode1:
+ case CDRDAOTrackTypeMode2Form1:
+ if (tag == SectorTagType.CDSectorSubchannel)
+ {
+ sector_offset = 2048;
+ sector_size = 96;
+ break;
+ }
+ throw new ArgumentException("No tags in image for requested track", "tag");
+ case CDRDAOTrackTypeMode2Form2:
+ case CDRDAOTrackTypeMode2Mix:
+ if (tag == SectorTagType.CDSectorSubchannel)
+ {
+ sector_offset = 2336;
+ sector_size = 96;
+ break;
+ }
+ throw new ArgumentException("No tags in image for requested track", "tag");
+ case CDRDAOTrackTypeAudio:
+ if (tag == SectorTagType.CDSectorSubchannel)
+ {
+ sector_offset = 2352;
+ sector_size = 96;
+ break;
+ }
+ throw new ArgumentException("No tags in image for requested track", "tag");
+ case CDRDAOTrackTypeMode1Raw:
+ {
+ 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:
+ {
+ sector_offset = 2352;
+ sector_size = 96;
+ break;
+ }
+ case SectorTagType.CDSectorSubHeader:
+ throw new ArgumentException("Unsupported tag requested for this track", "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", "tag");
+ }
+ break;
+ }
+ case CDRDAOTrackTypeMode2Raw: // Requires reading sector
+ if(tag == SectorTagType.CDSectorSubchannel)
+ {
+ sector_offset = 2352;
+ sector_size = 96;
+ break;
+ }
+ throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented");
+ default:
+ throw new FeatureSupportedButNotImplementedImageException("Unsupported track type");
+ }
+
+ byte[] buffer = new byte[sector_size * length];
+
+ imageStream = new FileStream(_track.trackfile.datafile, FileMode.Open, FileAccess.Read);
+ using (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(UInt64 sectorAddress)
+ {
+ return ReadSectorsLong(sectorAddress, 1);
+ }
+
+ public override byte[] ReadSectorLong(UInt64 sectorAddress, UInt32 track)
+ {
+ return ReadSectorsLong(sectorAddress, 1, track);
+ }
+
+ public override byte[] ReadSectorsLong(UInt64 sectorAddress, UInt32 length)
+ {
+ foreach (KeyValuePair kvp in offsetmap)
+ {
+ if (sectorAddress >= kvp.Value)
+ {
+ foreach (CDRDAOTrack cdrdao_track in discimage.tracks)
+ {
+ if (cdrdao_track.sequence == kvp.Key)
+ {
+ if ((sectorAddress - kvp.Value) < cdrdao_track.sectors)
+ return ReadSectorsLong((sectorAddress - kvp.Value), length, kvp.Key);
+ }
+ }
+ }
+ }
+
+ throw new ArgumentOutOfRangeException("sectorAddress", "Sector address not found");
+ }
+
+ public override byte[] ReadSectorsLong(UInt64 sectorAddress, UInt32 length, UInt32 track)
+ {
+ CDRDAOTrack _track = new CDRDAOTrack();
+
+ _track.sequence = 0;
+
+ foreach (CDRDAOTrack cdrdao_track in discimage.tracks)
+ {
+ if (cdrdao_track.sequence == track)
+ {
+ _track = cdrdao_track;
+ break;
+ }
+ }
+
+ if (_track.sequence == 0)
+ throw new ArgumentOutOfRangeException("track", "Track does not exist in disc image");
+
+ if (length > _track.sectors)
+ throw new ArgumentOutOfRangeException("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 CDRDAOTrackTypeMode1:
+ case CDRDAOTrackTypeMode2Form1:
+ {
+ sector_offset = 0;
+ sector_size = 2048;
+ sector_skip = 0;
+ break;
+ }
+ case CDRDAOTrackTypeMode2Form2:
+ {
+ sector_offset = 0;
+ sector_size = 2324;
+ sector_skip = 0;
+ break;
+ }
+ case CDRDAOTrackTypeMode2:
+ case CDRDAOTrackTypeMode2Mix:
+ {
+ sector_offset = 0;
+ sector_size = 2336;
+ sector_skip = 0;
+ break;
+ }
+ case CDRDAOTrackTypeMode1Raw:
+ case CDRDAOTrackTypeMode2Raw:
+ case CDRDAOTrackTypeAudio:
+ {
+ sector_offset = 0;
+ sector_size = 2352;
+ sector_skip = 0;
+ break;
+ }
+ default:
+ throw new FeatureSupportedButNotImplementedImageException("Unsupported track type");
+ }
+
+ if (_track.subchannel)
+ sector_skip += 96;
+
+ byte[] buffer = new byte[sector_size * length];
+
+ imageStream = new FileStream(_track.trackfile.datafile, FileMode.Open, FileAccess.Read);
+ 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 "CDRDAO tocfile";
+ }
+
+ 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 GetDiskSerialNumber()
+ {
+ return ImageInfo.diskSerialNumber;
+ }
+
+ public override string GetDiskBarcode()
+ {
+ return ImageInfo.diskBarcode;
+ }
+
+ public override DiskType GetDiskType()
+ {
+ return ImageInfo.diskType;
+ }
+
+ public override List GetPartitions()
+ {
+ return partitions;
+ }
+
+ public override List