Files
Aaru.Server/DiscImageChef.DiscImages/CloneCD.cs

1543 lines
48 KiB
C#

// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : CloneCD.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Component
//
// --[ Description ] ----------------------------------------------------------
//
// Description
//
// --[ 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 <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2017 Natalia Portillo
// ****************************************************************************/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using DiscImageChef.CommonTypes;
using DiscImageChef.Console;
using DiscImageChef.Decoders.CD;
using DiscImageChef.Filters;
using DiscImageChef.ImagePlugins;
namespace DiscImageChef.DiscImages
{
public class CloneCD : ImagePlugin
{
#region Parsing regexs
const string CCD_Identifier = "^\\s*\\[CloneCD\\]";
const string Disc_Identifier = "^\\s*\\[Disc\\]";
const string Session_Identifier = "^\\s*\\[Session\\s*(?<number>\\d+)\\]";
const string Entry_Identifier = "^\\s*\\[Entry\\s*(?<number>\\d+)\\]";
const string Track_Identifier = "^\\s*\\[TRACK\\s*(?<number>\\d+)\\]";
const string CDText_Identifier = "^\\s*\\[CDText\\]";
const string CCD_Version = "^\\s*Version\\s*=\\s*(?<value>\\d+)";
const string Disc_Entries = "^\\s*TocEntries\\s*=\\s*(?<value>\\d+)";
const string Disc_Sessions = "^\\s*Sessions\\s*=\\s*(?<value>\\d+)";
const string Disc_Scrambled = "^\\s*DataTracksScrambled\\s*=\\s*(?<value>\\d+)";
const string CDText_Length = "^\\s*CDTextLength\\s*=\\s*(?<value>\\d+)";
const string Disc_Catalog = "^\\s*CATALOG\\s*=\\s*(?<value>\\w+)";
const string Session_Pregap = "^\\s*PreGapMode\\s*=\\s*(?<value>\\d+)";
const string Session_Subchannel = "^\\s*PreGapSubC\\s*=\\s*(?<value>\\d+)";
const string Entry_Session = "^\\s*Session\\s*=\\s*(?<value>\\d+)";
const string Entry_Point = "^\\s*Point\\s*=\\s*(?<value>[\\w+]+)";
const string Entry_ADR = "^\\s*ADR\\s*=\\s*(?<value>\\w+)";
const string Entry_Control = "^\\s*Control\\s*=\\s*(?<value>\\w+)";
const string Entry_TrackNo = "^\\s*TrackNo\\s*=\\s*(?<value>\\d+)";
const string Entry_AMin = "^\\s*AMin\\s*=\\s*(?<value>\\d+)";
const string Entry_ASec = "^\\s*ASec\\s*=\\s*(?<value>\\d+)";
const string Entry_AFrame = "^\\s*AFrame\\s*=\\s*(?<value>\\d+)";
const string Entry_ALBA = "^\\s*ALBA\\s*=\\s*(?<value>-?\\d+)";
const string Entry_Zero = "^\\s*Zero\\s*=\\s*(?<value>\\d+)";
const string Entry_PMin = "^\\s*PMin\\s*=\\s*(?<value>\\d+)";
const string Entry_PSec = "^\\s*PSec\\s*=\\s*(?<value>\\d+)";
const string Entry_PFrame = "^\\s*PFrame\\s*=\\s*(?<value>\\d+)";
const string Entry_PLBA ="^\\s*PLBA\\s*=\\s*(?<value>\\d+)";
const string CDText_Entries = "^\\s*Entries\\s*=\\s*(?<value>\\d+)";
const string CDText_Entry = "^\\s*Entry\\s*(?<number>\\d+)\\s*=\\s*(?<value>([0-9a-fA-F]+\\s*)+)";
#endregion
Filter imageFilter;
Filter dataFilter;
Filter subFilter;
StreamReader cueStream;
byte[] fulltoc;
bool scrambled;
string catalog;
List<ImagePlugins.Session> sessions;
List<Partition> partitions;
List<Track> tracks;
Stream dataStream;
Stream subStream;
Dictionary<uint, ulong> offsetmap;
byte[] cdtext;
public CloneCD()
{
Name = "CloneCD";
PluginUUID = new Guid("EE9C2975-2E79-427A-8EE9-F86F19165784");
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;
}
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
foreach(byte b in testArray)
{
if(b < 0x20 && b != 0x0A && b != 0x0D && b != 0x00)
return false;
}
cueStream = new StreamReader(this.imageFilter.GetDataForkStream());
string _line = cueStream.ReadLine();
Regex Hdr = new Regex(CCD_Identifier);
Match Hdm;
Hdm = Hdr.Match(_line);
return Hdm.Success;
}
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;
Regex CCD_IdRegex = new Regex(CCD_Identifier);
Regex Disc_IdRegex = new Regex(Disc_Identifier);
Regex Sess_IdRegex = new Regex(Session_Identifier);
Regex Entry_IdRegex = new Regex(Entry_Identifier);
Regex Track_IdRegex = new Regex(Track_Identifier);
Regex CDT_IdRegex = new Regex(CDText_Identifier);
Regex CCD_VerRegex = new Regex(CCD_Version);
Regex Disc_EntRegex = new Regex(Disc_Entries);
Regex Disc_SessRegex = new Regex(Disc_Sessions);
Regex Disc_ScrRegex = new Regex(Disc_Scrambled);
Regex CDT_LenRegex = new Regex(CDText_Length);
Regex Disc_CatRegex = new Regex(Disc_Catalog);
Regex Sess_PregRegex = new Regex(Session_Pregap);
Regex Sess_SubcRegex = new Regex(Session_Subchannel);
Regex Ent_SessRegex = new Regex(Entry_Session);
Regex Ent_PointRegex = new Regex(Entry_Point);
Regex Ent_ADRRegex = new Regex(Entry_ADR);
Regex Ent_CtrlRegex = new Regex(Entry_Control);
Regex Ent_TNORegex = new Regex(Entry_TrackNo);
Regex Ent_AMinRegex = new Regex(Entry_AMin);
Regex Ent_ASecRegex = new Regex(Entry_ASec);
Regex Ent_AFrameRegex = new Regex(Entry_AFrame);
Regex Ent_ALBARegex = new Regex(Entry_ALBA);
Regex Ent_ZeroRegex = new Regex(Entry_Zero);
Regex Ent_PMinRegex = new Regex(Entry_PMin);
Regex Ent_PSecRegex = new Regex(Entry_PSec);
Regex Ent_PFrameRegex = new Regex(Entry_PFrame);
Regex Ent_PLBARegex = new Regex(Entry_PLBA);
Regex CDT_EntsRegex = new Regex(CDText_Entries);
Regex CDT_EntRegex = new Regex(CDText_Entry);
Match CCD_IdMatch;
Match Disc_IdMatch;
Match Sess_IdMatch;
Match Entry_IdMatch;
Match Track_IdMatch;
Match CDT_IdMatch;
Match CCD_VerMatch;
Match Disc_EntMatch;
Match Disc_SessMatch;
Match Disc_ScrMatch;
Match CDT_LenMatch;
Match Disc_CatMatch;
Match Sess_PregMatch;
Match Sess_SubcMatch;
Match Ent_SessMatch;
Match Ent_PointMatch;
Match Ent_ADRMatch;
Match Ent_CtrlMatch;
Match Ent_TNOMatch;
Match Ent_AMinMatch;
Match Ent_ASecMatch;
Match Ent_AFrameMatch;
Match Ent_ALBAMatch;
Match Ent_ZeroMatch;
Match Ent_PMinMatch;
Match Ent_PSecMatch;
Match Ent_PFrameMatch;
Match Ent_PLBAMatch;
Match CDT_EntsMatch;
Match CDT_EntMatch;
bool inCcd = false;
bool inDisk = false;
bool inSession = false;
bool inEntry = false;
bool inTrack = false;
bool inCDText = false;
MemoryStream cdtMs = new MemoryStream();
int minSession = int.MaxValue;
int maxSession = int.MinValue;
FullTOC.TrackDataDescriptor currentEntry = new FullTOC.TrackDataDescriptor();
List<FullTOC.TrackDataDescriptor> entries = new List<FullTOC.TrackDataDescriptor>();
scrambled = false;
catalog = null;
while(cueStream.Peek() >= 0)
{
line++;
string _line = cueStream.ReadLine();
CCD_IdMatch = CCD_IdRegex.Match(_line);
Disc_IdMatch = Disc_IdRegex.Match(_line);
Sess_IdMatch = Sess_IdRegex.Match(_line);
Entry_IdMatch = Entry_IdRegex.Match(_line);
Track_IdMatch = Track_IdRegex.Match(_line);
CDT_IdMatch = CDT_IdRegex.Match(_line);
// [CloneCD]
if(CCD_IdMatch.Success)
{
if(inDisk || inSession || inEntry || inTrack || inCDText)
throw new FeatureUnsupportedImageException(string.Format("Found [CloneCD] out of order in line {0}", line));
inCcd = true;
inDisk = false;
inSession = false;
inEntry = false;
inTrack = false;
inCDText = false;
}
else if(Disc_IdMatch.Success || Sess_IdMatch.Success || Entry_IdMatch.Success || Track_IdMatch.Success || CDT_IdMatch.Success)
{
if(inEntry)
{
entries.Add(currentEntry);
currentEntry = new FullTOC.TrackDataDescriptor();
}
inCcd = false;
inDisk = Disc_IdMatch.Success;
inSession = Sess_IdMatch.Success;
inEntry = Entry_IdMatch.Success;
inTrack = Track_IdMatch.Success;
inCDText = CDT_IdMatch.Success;
}
else
{
if(inCcd)
{
CCD_VerMatch = CCD_VerRegex.Match(_line);
if(CCD_VerMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found Version at line {0}", line);
ImageInfo.imageVersion = CCD_VerMatch.Groups["value"].Value;
if(ImageInfo.imageVersion != "2")
DicConsole.ErrorWriteLine("(CloneCD plugin): Warning! Unknown CCD image version {0}, may not work!", ImageInfo.imageVersion);
}
}
else if(inDisk)
{
Disc_EntMatch = Disc_EntRegex.Match(_line);
Disc_SessMatch = Disc_SessRegex.Match(_line);
Disc_ScrMatch = Disc_ScrRegex.Match(_line);
CDT_LenMatch = CDT_LenRegex.Match(_line);
Disc_CatMatch = Disc_CatRegex.Match(_line);
if(Disc_EntMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found TocEntries at line {0}", line);
}
else if(Disc_SessMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found Sessions at line {0}", line);
}
else if(Disc_ScrMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found DataTracksScrambled at line {0}", line);
scrambled |= Disc_ScrMatch.Groups["value"].Value == "1";
}
else if(CDT_LenMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found CDTextLength at line {0}", line);
}
else if(Disc_CatMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found Catalog at line {0}", line);
catalog = Disc_CatMatch.Groups["value"].Value;
}
}
// TODO: Do not suppose here entries come sorted
else if(inCDText)
{
CDT_EntsMatch = CDT_EntsRegex.Match(_line);
CDT_EntMatch = CDT_EntRegex.Match(_line);
if(CDT_EntsMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found CD-Text Entries at line {0}", line);
}
else if(CDT_EntMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found CD-Text Entry at line {0}", line);
string[] bytes = CDT_EntMatch.Groups["value"].Value.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
foreach(string byt in bytes)
cdtMs.WriteByte(Convert.ToByte(byt, 16));
}
}
// Is this useful?
else if(inSession)
{
Sess_PregMatch = Sess_PregRegex.Match(_line);
Sess_SubcMatch = Sess_SubcRegex.Match(_line);
if(Sess_PregMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found PreGapMode at line {0}", line);
}
else if(Sess_SubcMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found PreGapSubC at line {0}", line);
}
}
else if(inEntry)
{
Ent_SessMatch = Ent_SessRegex.Match(_line);
Ent_PointMatch = Ent_PointRegex.Match(_line);
Ent_ADRMatch = Ent_ADRRegex.Match(_line);
Ent_CtrlMatch = Ent_CtrlRegex.Match(_line);
Ent_TNOMatch = Ent_TNORegex.Match(_line);
Ent_AMinMatch = Ent_AMinRegex.Match(_line);
Ent_ASecMatch = Ent_ASecRegex.Match(_line);
Ent_AFrameMatch = Ent_AFrameRegex.Match(_line);
Ent_ALBAMatch = Ent_ALBARegex.Match(_line);
Ent_ZeroMatch = Ent_ZeroRegex.Match(_line);
Ent_PMinMatch = Ent_PMinRegex.Match(_line);
Ent_PSecMatch = Ent_PSecRegex.Match(_line);
Ent_PFrameMatch = Ent_PFrameRegex.Match(_line);
Ent_PLBAMatch = Ent_PLBARegex.Match(_line);
if(Ent_SessMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found Session at line {0}", line);
currentEntry.SessionNumber = Convert.ToByte(Ent_SessMatch.Groups["value"].Value, 10);
if(currentEntry.SessionNumber < minSession)
minSession = currentEntry.SessionNumber;
if(currentEntry.SessionNumber > maxSession)
maxSession = currentEntry.SessionNumber;
}
else if(Ent_PointMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found Point at line {0}", line);
currentEntry.POINT = Convert.ToByte(Ent_PointMatch.Groups["value"].Value, 16);
}
else if(Ent_ADRMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found ADR at line {0}", line);
currentEntry.ADR = Convert.ToByte(Ent_ADRMatch.Groups["value"].Value, 16);
}
else if(Ent_CtrlMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found Control at line {0}", line);
currentEntry.CONTROL = Convert.ToByte(Ent_CtrlMatch.Groups["value"].Value, 16);
}
else if(Ent_TNOMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found TrackNo at line {0}", line);
currentEntry.TNO = Convert.ToByte(Ent_TNOMatch.Groups["value"].Value, 10);
}
else if(Ent_AMinMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found AMin at line {0}", line);
currentEntry.Min = Convert.ToByte(Ent_AMinMatch.Groups["value"].Value, 10);
}
else if(Ent_ASecMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found ASec at line {0}", line);
currentEntry.Sec = Convert.ToByte(Ent_ASecMatch.Groups["value"].Value, 10);
}
else if(Ent_AFrameMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found AFrame at line {0}", line);
currentEntry.Frame = Convert.ToByte(Ent_AFrameMatch.Groups["value"].Value, 10);
}
else if(Ent_ALBAMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found ALBA at line {0}", line);
}
else if(Ent_ZeroMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found Zero at line {0}", line);
currentEntry.Zero = Convert.ToByte(Ent_ZeroMatch.Groups["value"].Value, 10);
currentEntry.HOUR = (byte)((currentEntry.Zero & 0xF0) >> 4);
currentEntry.PHOUR = (byte)(currentEntry.Zero & 0x0F);
}
else if(Ent_PMinMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found PMin at line {0}", line);
currentEntry.PMIN = Convert.ToByte(Ent_PMinMatch.Groups["value"].Value, 10);
}
else if(Ent_PSecMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found PSec at line {0}", line);
currentEntry.PSEC = Convert.ToByte(Ent_PSecMatch.Groups["value"].Value, 10);
}
else if(Ent_PFrameMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found PFrame at line {0}", line);
currentEntry.PFRAME = Convert.ToByte(Ent_PFrameMatch.Groups["value"].Value, 10);
}
else if(Ent_PLBAMatch.Success)
{
DicConsole.DebugWriteLine("CloneCD plugin", "Found PLBA at line {0}", line);
}
}
}
}
if(inEntry)
entries.Add(currentEntry);
if(entries.Count == 0)
throw new FeatureUnsupportedImageException("Did not find any track.");
FullTOC.CDFullTOC toc;
toc.TrackDescriptors = entries.ToArray();
toc.LastCompleteSession = (byte)maxSession;
toc.FirstCompleteSession = (byte)minSession;
toc.DataLength = (ushort)(entries.Count * 11 + 2);
MemoryStream tocMs = new MemoryStream();
tocMs.Write(BigEndianBitConverter.GetBytes(toc.DataLength), 0, 2);
tocMs.WriteByte(toc.FirstCompleteSession);
tocMs.WriteByte(toc.LastCompleteSession);
foreach(FullTOC.TrackDataDescriptor descriptor in toc.TrackDescriptors)
{
tocMs.WriteByte(descriptor.SessionNumber);
tocMs.WriteByte((byte)((descriptor.ADR << 4) + descriptor.CONTROL));
tocMs.WriteByte(descriptor.TNO);
tocMs.WriteByte(descriptor.POINT);
tocMs.WriteByte(descriptor.Min);
tocMs.WriteByte(descriptor.Sec);
tocMs.WriteByte(descriptor.Frame);
tocMs.WriteByte(descriptor.Zero);
tocMs.WriteByte(descriptor.PMIN);
tocMs.WriteByte(descriptor.PSEC);
tocMs.WriteByte(descriptor.PFRAME);
}
fulltoc = tocMs.ToArray();
ImageInfo.readableMediaTags.Add(MediaTagType.CD_FullTOC);
DicConsole.DebugWriteLine("CloneCD plugin", "{0}", FullTOC.Prettify(toc));
string dataFile = Path.GetFileNameWithoutExtension(imageFilter.GetBasePath()) + ".img";
string subFile = Path.GetFileNameWithoutExtension(imageFilter.GetBasePath()) + ".sub";
FiltersList filtersList = new FiltersList();
dataFilter = filtersList.GetFilter(dataFile);
if(dataFilter == null)
throw new Exception("Cannot open data file");
filtersList = new FiltersList();
subFilter = filtersList.GetFilter(subFile);
int curSessionNo = 0;
Track currentTrack = new Track();
bool firstTrackInSession = true;
tracks = new List<Track>();
byte discType;
ulong LeadOutStart = 0;
dataStream = dataFilter.GetDataForkStream();
if(subFilter != null)
subStream = subFilter.GetDataForkStream();
foreach(FullTOC.TrackDataDescriptor descriptor in entries)
{
if(descriptor.SessionNumber > curSessionNo)
{
curSessionNo = descriptor.SessionNumber;
if(!firstTrackInSession)
{
currentTrack.TrackEndSector = LeadOutStart - 1;
tracks.Add(currentTrack);
}
firstTrackInSession = true;
}
switch(descriptor.ADR)
{
case 1:
case 4:
switch(descriptor.POINT)
{
case 0xA0:
discType = descriptor.PSEC;
DicConsole.DebugWriteLine("CloneCD plugin", "Disc Type: {0}", discType);
break;
case 0xA2:
LeadOutStart = GetLBA(descriptor.PHOUR, descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME);
break;
default:
if(descriptor.POINT >= 0x01 && descriptor.POINT <= 0x63)
{
if(!firstTrackInSession)
{
currentTrack.TrackEndSector = GetLBA(descriptor.PHOUR, descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME) - 1;
tracks.Add(currentTrack);
}
else
firstTrackInSession = false;
currentTrack = new Track();
currentTrack.TrackBytesPerSector = 2352;
currentTrack.TrackFile = dataFilter.GetFilename();
currentTrack.TrackFileType = scrambled ? "SCRAMBLED" : "BINARY";
currentTrack.TrackFilter = dataFilter;
currentTrack.TrackRawBytesPerSector = 2352;
currentTrack.TrackSequence = descriptor.POINT;
currentTrack.TrackStartSector = GetLBA(descriptor.PHOUR, descriptor.PMIN, descriptor.PSEC, descriptor.PFRAME);
currentTrack.TrackFileOffset = currentTrack.TrackStartSector * 2352;
currentTrack.TrackSession = descriptor.SessionNumber;
// Need to check exact data type later
if((TOC_CONTROL)(descriptor.CONTROL & 0x0D) == TOC_CONTROL.DataTrack ||
(TOC_CONTROL)(descriptor.CONTROL & 0x0D) == TOC_CONTROL.DataTrackIncremental)
currentTrack.TrackType = TrackType.Data;
else
currentTrack.TrackType = TrackType.Audio;
if(subFilter != null)
{
currentTrack.TrackSubchannelFile = subFilter.GetFilename();
currentTrack.TrackSubchannelFilter = subFilter;
currentTrack.TrackSubchannelOffset = currentTrack.TrackStartSector * 96;
currentTrack.TrackSubchannelType = TrackSubchannelType.Raw;
}
else
currentTrack.TrackSubchannelType = TrackSubchannelType.None;
if(currentTrack.TrackType == TrackType.Data)
{
byte[] syncTest = new byte[12];
byte[] sectTest = new byte[2352];
dataStream.Seek((long)currentTrack.TrackFileOffset, SeekOrigin.Begin);
dataStream.Read(sectTest, 0, 2352);
Array.Copy(sectTest, 0, syncTest, 0, 12);
if(Sector.SyncMark.SequenceEqual(syncTest))
{
if(scrambled)
sectTest = Sector.Scramble(sectTest);
if(sectTest[15] == 1)
{
currentTrack.TrackBytesPerSector = 2048;
currentTrack.TrackType = TrackType.CDMode1;
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.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);
if(ImageInfo.sectorSize < 2048)
ImageInfo.sectorSize = 2048;
}
else if(sectTest[15] == 2)
{
byte[] subHdr1 = new byte[4];
byte[] subHdr2 = new byte[4];
byte[] empHdr = new byte[4];
Array.Copy(sectTest, 16, subHdr1, 0, 4);
Array.Copy(sectTest, 20, subHdr2, 0, 4);
if(subHdr1.SequenceEqual(subHdr2) && !empHdr.SequenceEqual(subHdr1))
{
if((subHdr1[2] & 0x20) == 0x20)
{
currentTrack.TrackBytesPerSector = 2324;
currentTrack.TrackType = TrackType.CDMode2Form2;
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);
if(ImageInfo.sectorSize < 2324)
ImageInfo.sectorSize = 2324;
}
else
{
currentTrack.TrackBytesPerSector = 2048;
currentTrack.TrackType = TrackType.CDMode2Form1;
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);
if(ImageInfo.sectorSize < 2048)
ImageInfo.sectorSize = 2048;
}
}
else
{
currentTrack.TrackBytesPerSector = 2336;
currentTrack.TrackType = TrackType.CDMode2Formless;
if(!ImageInfo.readableSectorTags.Contains(SectorTagType.CDSectorSync))
ImageInfo.readableSectorTags.Add(SectorTagType.CDSectorSync);
if(!ImageInfo.readableSectorTags.Contains(SectorTagType.CDSectorHeader))
ImageInfo.readableSectorTags.Add(SectorTagType.CDSectorHeader);
if(ImageInfo.sectorSize < 2336)
ImageInfo.sectorSize = 2336;
}
}
}
}
else
{
if(ImageInfo.sectorSize < 2352)
ImageInfo.sectorSize = 2352;
}
}
break;
}
break;
case 5:
switch(descriptor.POINT)
{
case 0xC0:
if(descriptor.PMIN == 97)
{
int type = descriptor.PFRAME % 10;
int frm = descriptor.PFRAME - type;
ImageInfo.mediaManufacturer = ATIP.ManufacturerFromATIP(descriptor.PSEC, frm);
if(ImageInfo.mediaManufacturer != "")
DicConsole.DebugWriteLine("CloneCD plugin", "Disc manufactured by: {0}", ImageInfo.mediaManufacturer);
}
break;
}
break;
case 6:
{
uint id = (uint)((descriptor.Min << 16) + (descriptor.Sec << 8) + descriptor.Frame);
DicConsole.DebugWriteLine("CloneCD plugin", "Disc ID: {0:X6}", id & 0x00FFFFFF);
ImageInfo.mediaSerialNumber = string.Format("{0:X6}", id & 0x00FFFFFF);
break;
}
}
}
if(!firstTrackInSession)
{
currentTrack.TrackEndSector = LeadOutStart - 1;
tracks.Add(currentTrack);
}
if(subFilter != null && !ImageInfo.readableSectorTags.Contains(SectorTagType.CDSectorSubchannel))
ImageInfo.readableSectorTags.Add(SectorTagType.CDSectorSubchannel);
sessions = new List<ImagePlugins.Session>();
ImagePlugins.Session currentSession = new ImagePlugins.Session();
currentSession.EndTrack = uint.MinValue;
currentSession.StartTrack = uint.MaxValue;
currentSession.SessionSequence = 1;
partitions = new List<Partition>();
offsetmap = new Dictionary<uint, ulong>();
foreach(Track track in tracks)
{
if(track.TrackSession == currentSession.SessionSequence)
{
if(track.TrackSequence > currentSession.EndTrack)
{
currentSession.EndSector = track.TrackEndSector;
currentSession.EndTrack = track.TrackSequence;
}
if(track.TrackSequence < currentSession.StartTrack)
{
currentSession.StartSector = track.TrackStartSector;
currentSession.StartTrack = track.TrackSequence;
}
}
else
{
sessions.Add(currentSession);
currentSession = new ImagePlugins.Session();
currentSession.EndTrack = uint.MinValue;
currentSession.StartTrack = uint.MaxValue;
currentSession.SessionSequence = track.TrackSession;
}
Partition partition = new Partition();
partition.PartitionDescription = track.TrackDescription;
partition.PartitionLength = (track.TrackEndSector - track.TrackStartSector) * (ulong)track.TrackRawBytesPerSector;
partition.PartitionSectors = (track.TrackEndSector - track.TrackStartSector);
ImageInfo.sectors += partition.PartitionSectors;
partition.PartitionSequence = track.TrackSequence;
partition.PartitionStart = track.TrackFileOffset;
partition.PartitionStartSector = track.TrackStartSector;
partition.PartitionType = track.TrackType.ToString();
partitions.Add(partition);
offsetmap.Add(track.TrackSequence, track.TrackStartSector);
}
bool data = false;
bool mode2 = false;
bool firstaudio = false;
bool firstdata = false;
bool audio = false;
for(int i = 0; i < tracks.Count; i++)
{
// First track is audio
firstaudio |= i == 0 && tracks[i].TrackType == TrackType.Audio;
// First track is data
firstdata |= i == 0 && tracks[i].TrackType != TrackType.Audio;
// Any non first track is data
data |= i != 0 && tracks[i].TrackType != TrackType.Audio;
// Any non first track is audio
audio |= i != 0 && tracks[i].TrackType == TrackType.Audio;
switch(tracks[i].TrackType)
{
case TrackType.CDMode2Form1:
case TrackType.CDMode2Form2:
case TrackType.CDMode2Formless:
mode2 = true;
break;
}
}
// TODO: Check format
cdtext = cdtMs.ToArray();
if(!data && !firstdata)
ImageInfo.mediaType = MediaType.CDDA;
else if(firstaudio && data && sessions.Count > 1 && mode2)
ImageInfo.mediaType = MediaType.CDPLUS;
else if((firstdata && audio) || mode2)
ImageInfo.mediaType = MediaType.CDROMXA;
else if(!audio)
ImageInfo.mediaType = MediaType.CDROM;
else
ImageInfo.mediaType = MediaType.CD;
ImageInfo.imageApplication = "CloneCD";
ImageInfo.imageSize = (ulong)imageFilter.GetDataForkLength();
ImageInfo.imageCreationTime = imageFilter.GetCreationTime();
ImageInfo.imageLastModificationTime = imageFilter.GetLastWriteTime();
ImageInfo.xmlMediaType = XmlMediaType.OpticalDisc;
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;
}
}
static ulong GetLBA(int hour, int minute, int second, int frame)
{
return (ulong)((hour * 60 * 60 * 75) + (minute * 60 * 75) + (second * 75) + frame - 150);
}
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_FullTOC:
{
return fulltoc;
}
case MediaTagType.CD_TEXT:
{
if(cdtext != null && cdtext.Length > 0)
return cdtext;
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(Track _track in tracks)
{
if(_track.TrackSequence == kvp.Key)
{
if(sectorAddress < _track.TrackEndSector)
return ReadSectors((sectorAddress - kvp.Value), length, kvp.Key);
}
}
}
}
throw new ArgumentOutOfRangeException(nameof(sectorAddress), string.Format("Sector address {0} not found", sectorAddress));
}
public override byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag)
{
foreach(KeyValuePair<uint, ulong> kvp in offsetmap)
{
if(sectorAddress >= kvp.Value)
{
foreach(Track _track in tracks)
{
if(_track.TrackSequence == kvp.Key)
{
if(sectorAddress < _track.TrackEndSector)
return ReadSectorsTag((sectorAddress - kvp.Value), length, kvp.Key, tag);
}
}
}
}
throw new ArgumentOutOfRangeException(nameof(sectorAddress), string.Format("Sector address {0} not found", sectorAddress));
}
public override byte[] ReadSectors(ulong sectorAddress, uint length, uint track)
{
Track _track = new Track();
_track.TrackSequence = 0;
foreach(Track __track in tracks)
{
if(__track.TrackSequence == track)
{
_track = __track;
break;
}
}
if(_track.TrackSequence == 0)
throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image");
if(length + sectorAddress > (_track.TrackEndSector))
throw new ArgumentOutOfRangeException(nameof(length), string.Format("Requested more sectors ({0}) than present in track ({1}), won't cross tracks", length + sectorAddress, _track.TrackEndSector));
uint sector_offset;
uint sector_size;
uint sector_skip;
switch(_track.TrackType)
{
case TrackType.Audio:
{
sector_offset = 0;
sector_size = 2352;
sector_skip = 0;
break;
}
case TrackType.CDMode1:
{
sector_offset = 16;
sector_size = 2048;
sector_skip = 288;
break;
}
case TrackType.CDMode2Formless:
{
sector_offset = 16;
sector_size = 2336;
sector_skip = 0;
break;
}
case TrackType.CDMode2Form1:
{
sector_offset = 24;
sector_size = 2048;
sector_skip = 280;
break;
}
case TrackType.CDMode2Form2:
{
sector_offset = 24;
sector_size = 2324;
sector_skip = 4;
break;
}
default:
throw new FeatureSupportedButNotImplementedImageException("Unsupported track type");
}
byte[] buffer = new byte[sector_size * length];
dataStream.Seek((long)(_track.TrackFileOffset + sectorAddress * 2352), SeekOrigin.Begin);
if(sector_offset == 0 && sector_skip == 0)
dataStream.Read(buffer, 0, buffer.Length);
else
{
for(int i = 0; i < length; i++)
{
byte[] sector = new byte[sector_size];
dataStream.Seek(sector_offset, SeekOrigin.Current);
dataStream.Read(sector, 0, sector.Length);
dataStream.Seek(sector_skip, SeekOrigin.Current);
Array.Copy(sector, 0, buffer, i * sector_size, sector_size);
}
}
return buffer;
}
// TODO: Flags
public override byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag)
{
Track _track = new Track();
_track.TrackSequence = 0;
foreach(Track __track in tracks)
{
if(__track.TrackSequence == track)
{
_track = __track;
break;
}
}
if(_track.TrackSequence == 0)
throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image");
if(length + sectorAddress > (_track.TrackEndSector))
throw new ArgumentOutOfRangeException(nameof(length), string.Format("Requested more sectors ({0}) than present in track ({1}), won't cross tracks", length + sectorAddress, _track.TrackEndSector));
if(_track.TrackType == TrackType.Data)
throw new ArgumentException("Unsupported tag requested", nameof(tag));
byte[] buffer;
switch(tag)
{
case SectorTagType.CDSectorECC:
case SectorTagType.CDSectorECC_P:
case SectorTagType.CDSectorECC_Q:
case SectorTagType.CDSectorEDC:
case SectorTagType.CDSectorHeader:
case SectorTagType.CDSectorSubHeader:
case SectorTagType.CDSectorSync:
break;
case SectorTagType.CDSectorSubchannel:
buffer = new byte[96 * length];
subStream.Seek((long)(_track.TrackSubchannelOffset + sectorAddress * 96), SeekOrigin.Begin);
subStream.Read(buffer, 0, buffer.Length);
break;
default:
throw new ArgumentException("Unsupported tag requested", nameof(tag));
}
uint sector_offset;
uint sector_size;
uint sector_skip;
switch(_track.TrackType)
{
case TrackType.CDMode1:
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.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 TrackType.CDMode2Formless:
{
switch(tag)
{
case SectorTagType.CDSectorSync:
case SectorTagType.CDSectorHeader:
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 TrackType.CDMode2Form1:
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.CDSectorSubHeader:
{
sector_offset = 16;
sector_size = 8;
sector_skip = 2328;
break;
}
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 = 2072;
sector_size = 4;
sector_skip = 276;
break;
}
default:
throw new ArgumentException("Unsupported tag requested", nameof(tag));
}
break;
case TrackType.CDMode2Form2:
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.CDSectorSubHeader:
{
sector_offset = 16;
sector_size = 8;
sector_skip = 2328;
break;
}
case SectorTagType.CDSectorEDC:
{
sector_offset = 2348;
sector_size = 4;
sector_skip = 0;
break;
}
default:
throw new ArgumentException("Unsupported tag requested", nameof(tag));
}
break;
case TrackType.Audio:
{
throw new ArgumentException("Unsupported tag requested", nameof(tag));
}
default:
throw new FeatureSupportedButNotImplementedImageException("Unsupported track type");
}
buffer = new byte[sector_size * length];
dataStream.Seek((long)(_track.TrackFileOffset + sectorAddress * 2352), SeekOrigin.Begin);
if(sector_offset == 0 && sector_skip == 0)
dataStream.Read(buffer, 0, buffer.Length);
else
{
for(int i = 0; i < length; i++)
{
byte[] sector = new byte[sector_size];
dataStream.Seek(sector_offset, SeekOrigin.Current);
dataStream.Read(sector, 0, sector.Length);
dataStream.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(Track track in tracks)
{
if(track.TrackSequence == kvp.Key)
{
if((sectorAddress - kvp.Value) < (track.TrackEndSector - track.TrackStartSector))
return ReadSectorsLong((sectorAddress - kvp.Value), length, kvp.Key);
}
}
}
}
throw new ArgumentOutOfRangeException(nameof(sectorAddress), string.Format("Sector address {0} not found", sectorAddress));
}
public override byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track)
{
Track _track = new Track();
_track.TrackSequence = 0;
foreach(Track __track in tracks)
{
if(__track.TrackSequence == track)
{
_track = __track;
break;
}
}
if(_track.TrackSequence == 0)
throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image");
if(length + sectorAddress > (_track.TrackEndSector))
throw new ArgumentOutOfRangeException(nameof(length), string.Format("Requested more sectors ({0}) than present in track ({1}), won't cross tracks", length + sectorAddress, _track.TrackEndSector));
byte[] buffer = new byte[2352 * length];
dataStream.Seek((long)(_track.TrackFileOffset + sectorAddress * 2352), SeekOrigin.Begin);
dataStream.Read(buffer, 0, buffer.Length);
return buffer;
}
public override string GetImageFormat()
{
return "CloneCD";
}
public override string GetImageVersion()
{
return ImageInfo.imageVersion;
}
public override string GetImageApplication()
{
return ImageInfo.imageApplication;
}
public override string GetImageApplicationVersion()
{
return ImageInfo.imageApplicationVersion;
}
public override string GetImageCreator()
{
return ImageInfo.imageCreator;
}
public override DateTime GetImageCreationTime()
{
return ImageInfo.imageCreationTime;
}
public override DateTime GetImageLastModificationTime()
{
return ImageInfo.imageLastModificationTime;
}
public override string GetImageName()
{
return ImageInfo.imageName;
}
public override string GetImageComments()
{
return ImageInfo.imageComments;
}
public override string GetMediaManufacturer()
{
return ImageInfo.mediaManufacturer;
}
public override string GetMediaModel()
{
return ImageInfo.mediaModel;
}
public override string GetMediaSerialNumber()
{
return ImageInfo.driveSerialNumber;
}
public override string GetMediaBarcode()
{
return ImageInfo.mediaBarcode;
}
public override string GetMediaPartNumber()
{
return ImageInfo.mediaPartNumber;
}
public override MediaType GetMediaType()
{
return ImageInfo.mediaType;
}
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 List<Partition> GetPartitions()
{
return partitions;
}
public override List<Track> GetTracks()
{
return tracks;
}
public override List<Track> GetSessionTracks(ImagePlugins.Session session)
{
if(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(Track _track in tracks)
{
if(_track.TrackSession == session)
_tracks.Add(_track);
}
return _tracks;
}
public override List<ImagePlugins.Session> GetSessions()
{
return 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;
}
}
}