2017-05-19 20:28:49 +01:00
|
|
|
// /***************************************************************************
|
2016-10-08 04:29:04 +01:00
|
|
|
// The Disc Image Chef
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Filename : CloneCD.cs
|
|
|
|
|
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
|
|
|
//
|
2017-12-19 03:50:57 +00:00
|
|
|
// Component : Disc image plugins.
|
2016-10-08 04:29:04 +01:00
|
|
|
//
|
|
|
|
|
// --[ Description ] ----------------------------------------------------------
|
|
|
|
|
//
|
2017-12-19 03:50:57 +00:00
|
|
|
// Manages CloneCD disc images.
|
2016-10-08 04:29:04 +01:00
|
|
|
//
|
|
|
|
|
// --[ 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/>.
|
|
|
|
|
//
|
|
|
|
|
// ----------------------------------------------------------------------------
|
2017-12-19 03:50:57 +00:00
|
|
|
// Copyright © 2011-2018 Natalia Portillo
|
2016-10-08 04:29:04 +01:00
|
|
|
// ****************************************************************************/
|
2017-12-19 19:33:46 +00:00
|
|
|
|
2016-10-08 04:29:04 +01:00
|
|
|
using System;
|
2016-10-08 04:29:33 +01:00
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text.RegularExpressions;
|
2017-12-21 14:30:38 +00:00
|
|
|
using DiscImageChef.Checksums;
|
2016-10-08 04:29:33 +01:00
|
|
|
using DiscImageChef.CommonTypes;
|
|
|
|
|
using DiscImageChef.Console;
|
|
|
|
|
using DiscImageChef.Decoders.CD;
|
|
|
|
|
using DiscImageChef.Filters;
|
|
|
|
|
|
2016-10-08 04:29:04 +01:00
|
|
|
namespace DiscImageChef.DiscImages
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
public class CloneCd : ImagePlugin
|
2016-10-08 04:29:04 +01:00
|
|
|
{
|
2017-12-19 20:33:03 +00:00
|
|
|
#region Parsing regexs
|
2017-12-20 17:15:26 +00:00
|
|
|
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*)+)";
|
2017-12-19 20:33:03 +00:00
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
Filter imageFilter;
|
|
|
|
|
Filter dataFilter;
|
|
|
|
|
Filter subFilter;
|
|
|
|
|
StreamReader cueStream;
|
|
|
|
|
byte[] fulltoc;
|
|
|
|
|
bool scrambled;
|
|
|
|
|
string catalog;
|
2017-12-21 14:30:38 +00:00
|
|
|
List<Session> sessions;
|
2017-12-19 20:33:03 +00:00
|
|
|
List<Partition> partitions;
|
|
|
|
|
List<Track> tracks;
|
|
|
|
|
Stream dataStream;
|
|
|
|
|
Stream subStream;
|
|
|
|
|
Dictionary<uint, ulong> offsetmap;
|
|
|
|
|
byte[] cdtext;
|
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
public CloneCd()
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
|
|
|
|
Name = "CloneCD";
|
2017-12-20 17:15:26 +00:00
|
|
|
PluginUuid = new Guid("EE9C2975-2E79-427A-8EE9-F86F19165784");
|
2017-12-19 20:33:03 +00:00
|
|
|
ImageInfo = new ImageInfo();
|
2017-12-20 17:15:26 +00:00
|
|
|
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;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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());
|
|
|
|
|
|
|
|
|
|
string _line = cueStream.ReadLine();
|
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
Regex hdr = new Regex(CCD_IDENTIFIER);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
Match hdm;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
2017-12-21 14:41:38 +00:00
|
|
|
hdm = hdr.Match(_line ?? throw new InvalidOperationException());
|
2017-12-19 20:33:03 +00:00
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
return hdm.Success;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
Regex ccdIdRegex = new Regex(CCD_IDENTIFIER);
|
|
|
|
|
Regex discIdRegex = new Regex(DISC_IDENTIFIER);
|
|
|
|
|
Regex sessIdRegex = new Regex(SESSION_IDENTIFIER);
|
|
|
|
|
Regex entryIdRegex = new Regex(ENTRY_IDENTIFIER);
|
|
|
|
|
Regex trackIdRegex = new Regex(TRACK_IDENTIFIER);
|
|
|
|
|
Regex cdtIdRegex = new Regex(CDTEXT_IDENTIFIER);
|
|
|
|
|
Regex ccdVerRegex = new Regex(CCD_VERSION);
|
|
|
|
|
Regex discEntRegex = new Regex(DISC_ENTRIES);
|
|
|
|
|
Regex discSessRegex = new Regex(DISC_SESSIONS);
|
|
|
|
|
Regex discScrRegex = new Regex(DISC_SCRAMBLED);
|
|
|
|
|
Regex cdtLenRegex = new Regex(CDTEXT_LENGTH);
|
|
|
|
|
Regex discCatRegex = new Regex(DISC_CATALOG);
|
|
|
|
|
Regex sessPregRegex = new Regex(SESSION_PREGAP);
|
|
|
|
|
Regex sessSubcRegex = new Regex(SESSION_SUBCHANNEL);
|
|
|
|
|
Regex entSessRegex = new Regex(ENTRY_SESSION);
|
|
|
|
|
Regex entPointRegex = new Regex(ENTRY_POINT);
|
|
|
|
|
Regex entAdrRegex = new Regex(ENTRY_ADR);
|
|
|
|
|
Regex entCtrlRegex = new Regex(ENTRY_CONTROL);
|
|
|
|
|
Regex entTnoRegex = new Regex(ENTRY_TRACKNO);
|
|
|
|
|
Regex entAMinRegex = new Regex(ENTRY_AMIN);
|
|
|
|
|
Regex entASecRegex = new Regex(ENTRY_ASEC);
|
|
|
|
|
Regex entAFrameRegex = new Regex(ENTRY_AFRAME);
|
|
|
|
|
Regex entAlbaRegex = new Regex(ENTRY_ALBA);
|
|
|
|
|
Regex entZeroRegex = new Regex(ENTRY_ZERO);
|
|
|
|
|
Regex entPMinRegex = new Regex(ENTRY_PMIN);
|
|
|
|
|
Regex entPSecRegex = new Regex(ENTRY_PSEC);
|
|
|
|
|
Regex entPFrameRegex = new Regex(ENTRY_PFRAME);
|
|
|
|
|
Regex entPlbaRegex = new Regex(ENTRY_PLBA);
|
|
|
|
|
Regex cdtEntsRegex = new Regex(CDTEXT_ENTRIES);
|
|
|
|
|
Regex cdtEntRegex = new Regex(CDTEXT_ENTRY);
|
|
|
|
|
|
|
|
|
|
Match ccdIdMatch;
|
|
|
|
|
Match discIdMatch;
|
|
|
|
|
Match sessIdMatch;
|
|
|
|
|
Match entryIdMatch;
|
|
|
|
|
Match trackIdMatch;
|
|
|
|
|
Match cdtIdMatch;
|
|
|
|
|
Match ccdVerMatch;
|
|
|
|
|
Match discEntMatch;
|
|
|
|
|
Match discSessMatch;
|
|
|
|
|
Match discScrMatch;
|
|
|
|
|
Match cdtLenMatch;
|
|
|
|
|
Match discCatMatch;
|
|
|
|
|
Match sessPregMatch;
|
|
|
|
|
Match sessSubcMatch;
|
|
|
|
|
Match entSessMatch;
|
|
|
|
|
Match entPointMatch;
|
|
|
|
|
Match entAdrMatch;
|
|
|
|
|
Match entCtrlMatch;
|
|
|
|
|
Match entTnoMatch;
|
|
|
|
|
Match entAMinMatch;
|
|
|
|
|
Match entASecMatch;
|
|
|
|
|
Match entAFrameMatch;
|
|
|
|
|
Match entAlbaMatch;
|
|
|
|
|
Match entZeroMatch;
|
|
|
|
|
Match entPMinMatch;
|
|
|
|
|
Match entPSecMatch;
|
|
|
|
|
Match entPFrameMatch;
|
|
|
|
|
Match entPlbaMatch;
|
|
|
|
|
Match cdtEntsMatch;
|
|
|
|
|
Match cdtEntMatch;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
bool inCcd = false;
|
|
|
|
|
bool inDisk = false;
|
|
|
|
|
bool inSession = false;
|
|
|
|
|
bool inEntry = false;
|
|
|
|
|
bool inTrack = false;
|
2017-12-20 17:15:26 +00:00
|
|
|
bool inCdText = false;
|
2017-12-19 20:33:03 +00:00
|
|
|
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();
|
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
ccdIdMatch = ccdIdRegex.Match(_line);
|
|
|
|
|
discIdMatch = discIdRegex.Match(_line);
|
|
|
|
|
sessIdMatch = sessIdRegex.Match(_line);
|
|
|
|
|
entryIdMatch = entryIdRegex.Match(_line);
|
|
|
|
|
trackIdMatch = trackIdRegex.Match(_line);
|
|
|
|
|
cdtIdMatch = cdtIdRegex.Match(_line);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
// [CloneCD]
|
2017-12-20 17:15:26 +00:00
|
|
|
if(ccdIdMatch.Success)
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
if(inDisk || inSession || inEntry || inTrack || inCdText)
|
2017-12-19 20:33:03 +00:00
|
|
|
throw new
|
2017-12-21 17:58:51 +00:00
|
|
|
FeatureUnsupportedImageException($"Found [CloneCD] out of order in line {line}");
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
inCcd = true;
|
|
|
|
|
inDisk = false;
|
|
|
|
|
inSession = false;
|
|
|
|
|
inEntry = false;
|
|
|
|
|
inTrack = false;
|
2017-12-20 17:15:26 +00:00
|
|
|
inCdText = false;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
else if(discIdMatch.Success || sessIdMatch.Success || entryIdMatch.Success ||
|
|
|
|
|
trackIdMatch.Success || cdtIdMatch.Success)
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
|
|
|
|
if(inEntry)
|
|
|
|
|
{
|
|
|
|
|
entries.Add(currentEntry);
|
|
|
|
|
currentEntry = new FullTOC.TrackDataDescriptor();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inCcd = false;
|
2017-12-20 17:15:26 +00:00
|
|
|
inDisk = discIdMatch.Success;
|
|
|
|
|
inSession = sessIdMatch.Success;
|
|
|
|
|
inEntry = entryIdMatch.Success;
|
|
|
|
|
inTrack = trackIdMatch.Success;
|
|
|
|
|
inCdText = cdtIdMatch.Success;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if(inCcd)
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
ccdVerMatch = ccdVerRegex.Match(_line);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
2017-12-21 06:06:19 +00:00
|
|
|
if(!ccdVerMatch.Success) continue;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
2017-12-21 06:06:19 +00:00
|
|
|
DicConsole.DebugWriteLine("CloneCD plugin", "Found Version at line {0}", line);
|
|
|
|
|
|
|
|
|
|
ImageInfo.ImageVersion = ccdVerMatch.Groups["value"].Value;
|
|
|
|
|
if(ImageInfo.ImageVersion != "2" && ImageInfo.ImageVersion != "3")
|
|
|
|
|
DicConsole
|
|
|
|
|
.ErrorWriteLine("(CloneCD plugin): Warning! Unknown CCD image version {0}, may not work!",
|
|
|
|
|
ImageInfo.ImageVersion);
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
else if(inDisk)
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
discEntMatch = discEntRegex.Match(_line);
|
|
|
|
|
discSessMatch = discSessRegex.Match(_line);
|
|
|
|
|
discScrMatch = discScrRegex.Match(_line);
|
|
|
|
|
cdtLenMatch = cdtLenRegex.Match(_line);
|
|
|
|
|
discCatMatch = discCatRegex.Match(_line);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
2017-12-20 23:07:46 +00:00
|
|
|
if(discEntMatch.Success) DicConsole.DebugWriteLine("CloneCD plugin", "Found TocEntries at line {0}", line);
|
|
|
|
|
else if(discSessMatch.Success) DicConsole.DebugWriteLine("CloneCD plugin", "Found Sessions at line {0}", line);
|
2017-12-20 17:15:26 +00:00
|
|
|
else if(discScrMatch.Success)
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
|
|
|
|
DicConsole.DebugWriteLine("CloneCD plugin", "Found DataTracksScrambled at line {0}",
|
|
|
|
|
line);
|
2017-12-20 17:15:26 +00:00
|
|
|
scrambled |= discScrMatch.Groups["value"].Value == "1";
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
2017-12-20 23:07:46 +00:00
|
|
|
else if(cdtLenMatch.Success) DicConsole.DebugWriteLine("CloneCD plugin", "Found CDTextLength at line {0}", line);
|
2017-12-20 17:15:26 +00:00
|
|
|
else if(discCatMatch.Success)
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
|
|
|
|
DicConsole.DebugWriteLine("CloneCD plugin", "Found Catalog at line {0}", line);
|
2017-12-20 17:15:26 +00:00
|
|
|
catalog = discCatMatch.Groups["value"].Value;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// TODO: Do not suppose here entries come sorted
|
2017-12-20 17:15:26 +00:00
|
|
|
else if(inCdText)
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
cdtEntsMatch = cdtEntsRegex.Match(_line);
|
|
|
|
|
cdtEntMatch = cdtEntRegex.Match(_line);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
2017-12-20 23:07:46 +00:00
|
|
|
if(cdtEntsMatch.Success) DicConsole.DebugWriteLine("CloneCD plugin", "Found CD-Text Entries at line {0}", line);
|
2017-12-20 17:15:26 +00:00
|
|
|
else if(cdtEntMatch.Success)
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
|
|
|
|
DicConsole.DebugWriteLine("CloneCD plugin", "Found CD-Text Entry at line {0}", line);
|
2017-12-21 14:30:38 +00:00
|
|
|
string[] bytes = cdtEntMatch.Groups["value"].Value.Split(new[] {' '},
|
2017-12-19 20:33:03 +00:00
|
|
|
StringSplitOptions
|
|
|
|
|
.RemoveEmptyEntries);
|
|
|
|
|
foreach(string byt in bytes) cdtMs.WriteByte(Convert.ToByte(byt, 16));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Is this useful?
|
|
|
|
|
else if(inSession)
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sessPregMatch = sessPregRegex.Match(_line);
|
|
|
|
|
sessSubcMatch = sessSubcRegex.Match(_line);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
2017-12-20 23:07:46 +00:00
|
|
|
if(sessPregMatch.Success) DicConsole.DebugWriteLine("CloneCD plugin", "Found PreGapMode at line {0}", line);
|
|
|
|
|
else if(sessSubcMatch.Success) DicConsole.DebugWriteLine("CloneCD plugin", "Found PreGapSubC at line {0}", line);
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
else if(inEntry)
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
entSessMatch = entSessRegex.Match(_line);
|
|
|
|
|
entPointMatch = entPointRegex.Match(_line);
|
|
|
|
|
entAdrMatch = entAdrRegex.Match(_line);
|
|
|
|
|
entCtrlMatch = entCtrlRegex.Match(_line);
|
|
|
|
|
entTnoMatch = entTnoRegex.Match(_line);
|
|
|
|
|
entAMinMatch = entAMinRegex.Match(_line);
|
|
|
|
|
entASecMatch = entASecRegex.Match(_line);
|
|
|
|
|
entAFrameMatch = entAFrameRegex.Match(_line);
|
|
|
|
|
entAlbaMatch = entAlbaRegex.Match(_line);
|
|
|
|
|
entZeroMatch = entZeroRegex.Match(_line);
|
|
|
|
|
entPMinMatch = entPMinRegex.Match(_line);
|
|
|
|
|
entPSecMatch = entPSecRegex.Match(_line);
|
|
|
|
|
entPFrameMatch = entPFrameRegex.Match(_line);
|
|
|
|
|
entPlbaMatch = entPlbaRegex.Match(_line);
|
|
|
|
|
|
|
|
|
|
if(entSessMatch.Success)
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
|
|
|
|
DicConsole.DebugWriteLine("CloneCD plugin", "Found Session at line {0}", line);
|
2017-12-20 17:15:26 +00:00
|
|
|
currentEntry.SessionNumber = Convert.ToByte(entSessMatch.Groups["value"].Value, 10);
|
2017-12-19 20:33:03 +00:00
|
|
|
if(currentEntry.SessionNumber < minSession) minSession = currentEntry.SessionNumber;
|
|
|
|
|
if(currentEntry.SessionNumber > maxSession) maxSession = currentEntry.SessionNumber;
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
else if(entPointMatch.Success)
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
|
|
|
|
DicConsole.DebugWriteLine("CloneCD plugin", "Found Point at line {0}", line);
|
2017-12-20 17:15:26 +00:00
|
|
|
currentEntry.POINT = Convert.ToByte(entPointMatch.Groups["value"].Value, 16);
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
else if(entAdrMatch.Success)
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
|
|
|
|
DicConsole.DebugWriteLine("CloneCD plugin", "Found ADR at line {0}", line);
|
2017-12-20 17:15:26 +00:00
|
|
|
currentEntry.ADR = Convert.ToByte(entAdrMatch.Groups["value"].Value, 16);
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
else if(entCtrlMatch.Success)
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
|
|
|
|
DicConsole.DebugWriteLine("CloneCD plugin", "Found Control at line {0}", line);
|
2017-12-20 17:15:26 +00:00
|
|
|
currentEntry.CONTROL = Convert.ToByte(entCtrlMatch.Groups["value"].Value, 16);
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
else if(entTnoMatch.Success)
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
|
|
|
|
DicConsole.DebugWriteLine("CloneCD plugin", "Found TrackNo at line {0}", line);
|
2017-12-20 17:15:26 +00:00
|
|
|
currentEntry.TNO = Convert.ToByte(entTnoMatch.Groups["value"].Value, 10);
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
else if(entAMinMatch.Success)
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
|
|
|
|
DicConsole.DebugWriteLine("CloneCD plugin", "Found AMin at line {0}", line);
|
2017-12-20 17:15:26 +00:00
|
|
|
currentEntry.Min = Convert.ToByte(entAMinMatch.Groups["value"].Value, 10);
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
else if(entASecMatch.Success)
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
|
|
|
|
DicConsole.DebugWriteLine("CloneCD plugin", "Found ASec at line {0}", line);
|
2017-12-20 17:15:26 +00:00
|
|
|
currentEntry.Sec = Convert.ToByte(entASecMatch.Groups["value"].Value, 10);
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
else if(entAFrameMatch.Success)
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
|
|
|
|
DicConsole.DebugWriteLine("CloneCD plugin", "Found AFrame at line {0}", line);
|
2017-12-20 17:15:26 +00:00
|
|
|
currentEntry.Frame = Convert.ToByte(entAFrameMatch.Groups["value"].Value, 10);
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
2017-12-20 23:07:46 +00:00
|
|
|
else if(entAlbaMatch.Success) DicConsole.DebugWriteLine("CloneCD plugin", "Found ALBA at line {0}", line);
|
2017-12-20 17:15:26 +00:00
|
|
|
else if(entZeroMatch.Success)
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
|
|
|
|
DicConsole.DebugWriteLine("CloneCD plugin", "Found Zero at line {0}", line);
|
2017-12-20 17:15:26 +00:00
|
|
|
currentEntry.Zero = Convert.ToByte(entZeroMatch.Groups["value"].Value, 10);
|
2017-12-19 20:33:03 +00:00
|
|
|
currentEntry.HOUR = (byte)((currentEntry.Zero & 0xF0) >> 4);
|
|
|
|
|
currentEntry.PHOUR = (byte)(currentEntry.Zero & 0x0F);
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
else if(entPMinMatch.Success)
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
|
|
|
|
DicConsole.DebugWriteLine("CloneCD plugin", "Found PMin at line {0}", line);
|
2017-12-20 17:15:26 +00:00
|
|
|
currentEntry.PMIN = Convert.ToByte(entPMinMatch.Groups["value"].Value, 10);
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
else if(entPSecMatch.Success)
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
|
|
|
|
DicConsole.DebugWriteLine("CloneCD plugin", "Found PSec at line {0}", line);
|
2017-12-20 17:15:26 +00:00
|
|
|
currentEntry.PSEC = Convert.ToByte(entPSecMatch.Groups["value"].Value, 10);
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
else if(entPFrameMatch.Success)
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
|
|
|
|
DicConsole.DebugWriteLine("CloneCD plugin", "Found PFrame at line {0}", line);
|
2017-12-20 17:15:26 +00:00
|
|
|
currentEntry.PFRAME = Convert.ToByte(entPFrameMatch.Groups["value"].Value, 10);
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
2017-12-20 23:07:46 +00:00
|
|
|
else if(entPlbaMatch.Success) DicConsole.DebugWriteLine("CloneCD plugin", "Found PLBA at line {0}", line);
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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();
|
2017-12-20 17:15:26 +00:00
|
|
|
ImageInfo.ReadableMediaTags.Add(MediaTagType.CD_FullTOC);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
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;
|
2017-12-20 17:15:26 +00:00
|
|
|
ulong leadOutStart = 0;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
dataStream = dataFilter.GetDataForkStream();
|
|
|
|
|
if(subFilter != null) subStream = subFilter.GetDataForkStream();
|
|
|
|
|
|
|
|
|
|
foreach(FullTOC.TrackDataDescriptor descriptor in entries)
|
|
|
|
|
{
|
|
|
|
|
if(descriptor.SessionNumber > curSessionNo)
|
|
|
|
|
{
|
|
|
|
|
curSessionNo = descriptor.SessionNumber;
|
|
|
|
|
if(!firstTrackInSession)
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
currentTrack.TrackEndSector = leadOutStart - 1;
|
2017-12-19 20:33:03 +00:00
|
|
|
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:
|
2017-12-20 17:15:26 +00:00
|
|
|
leadOutStart = GetLba(descriptor.PHOUR, descriptor.PMIN, descriptor.PSEC,
|
2017-12-19 20:33:03 +00:00
|
|
|
descriptor.PFRAME);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if(descriptor.POINT >= 0x01 && descriptor.POINT <= 0x63)
|
|
|
|
|
{
|
|
|
|
|
if(!firstTrackInSession)
|
|
|
|
|
{
|
|
|
|
|
currentTrack.TrackEndSector =
|
2017-12-20 17:15:26 +00:00
|
|
|
GetLba(descriptor.PHOUR, descriptor.PMIN, descriptor.PSEC,
|
2017-12-19 20:33:03 +00:00
|
|
|
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 =
|
2017-12-20 17:15:26 +00:00
|
|
|
GetLba(descriptor.PHOUR, descriptor.PMIN, descriptor.PSEC,
|
2017-12-19 20:33:03 +00:00
|
|
|
descriptor.PFRAME);
|
|
|
|
|
currentTrack.TrackFileOffset = currentTrack.TrackStartSector * 2352;
|
|
|
|
|
currentTrack.TrackSession = descriptor.SessionNumber;
|
|
|
|
|
|
|
|
|
|
// Need to check exact data type later
|
2017-12-22 02:04:18 +00:00
|
|
|
if((TocControl)(descriptor.CONTROL & 0x0D) == TocControl.DataTrack ||
|
|
|
|
|
(TocControl)(descriptor.CONTROL & 0x0D) == TocControl.DataTrackIncremental)
|
2017-12-19 20:33:03 +00:00
|
|
|
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;
|
2017-12-20 17:15:26 +00:00
|
|
|
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
|
|
|
|
|
.CdSectorEccP))
|
|
|
|
|
ImageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorEccP);
|
|
|
|
|
if(!ImageInfo.ReadableSectorTags.Contains(SectorTagType
|
|
|
|
|
.CdSectorEccQ))
|
|
|
|
|
ImageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorEccQ);
|
|
|
|
|
if(!ImageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorEdc)
|
|
|
|
|
) ImageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorEdc);
|
|
|
|
|
if(ImageInfo.SectorSize < 2048) ImageInfo.SectorSize = 2048;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
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;
|
2017-12-20 17:15:26 +00:00
|
|
|
currentTrack.TrackType = TrackType.CdMode2Form2;
|
|
|
|
|
if(!ImageInfo.ReadableSectorTags.Contains(SectorTagType
|
|
|
|
|
.CdSectorSync)
|
2017-12-19 20:33:03 +00:00
|
|
|
)
|
2017-12-20 17:15:26 +00:00
|
|
|
ImageInfo.ReadableSectorTags.Add(SectorTagType
|
|
|
|
|
.CdSectorSync);
|
|
|
|
|
if(!ImageInfo.ReadableSectorTags.Contains(SectorTagType
|
|
|
|
|
.CdSectorHeader)
|
2017-12-19 20:33:03 +00:00
|
|
|
)
|
2017-12-20 17:15:26 +00:00
|
|
|
ImageInfo.ReadableSectorTags.Add(SectorTagType
|
|
|
|
|
.CdSectorHeader);
|
|
|
|
|
if(!ImageInfo.ReadableSectorTags.Contains(SectorTagType
|
|
|
|
|
.CdSectorSubHeader)
|
2017-12-19 20:33:03 +00:00
|
|
|
)
|
2017-12-20 17:15:26 +00:00
|
|
|
ImageInfo.ReadableSectorTags.Add(SectorTagType
|
|
|
|
|
.CdSectorSubHeader);
|
|
|
|
|
if(!ImageInfo.ReadableSectorTags.Contains(SectorTagType
|
|
|
|
|
.CdSectorEdc))
|
|
|
|
|
ImageInfo.ReadableSectorTags.Add(SectorTagType
|
|
|
|
|
.CdSectorEdc);
|
|
|
|
|
if(ImageInfo.SectorSize < 2324) ImageInfo.SectorSize = 2324;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
currentTrack.TrackBytesPerSector = 2048;
|
2017-12-20 17:15:26 +00:00
|
|
|
currentTrack.TrackType = TrackType.CdMode2Form1;
|
|
|
|
|
if(!ImageInfo.ReadableSectorTags.Contains(SectorTagType
|
|
|
|
|
.CdSectorSync)
|
2017-12-19 20:33:03 +00:00
|
|
|
)
|
2017-12-20 17:15:26 +00:00
|
|
|
ImageInfo.ReadableSectorTags.Add(SectorTagType
|
|
|
|
|
.CdSectorSync);
|
|
|
|
|
if(!ImageInfo.ReadableSectorTags.Contains(SectorTagType
|
|
|
|
|
.CdSectorHeader)
|
2017-12-19 20:33:03 +00:00
|
|
|
)
|
2017-12-20 17:15:26 +00:00
|
|
|
ImageInfo.ReadableSectorTags.Add(SectorTagType
|
|
|
|
|
.CdSectorHeader);
|
|
|
|
|
if(!ImageInfo.ReadableSectorTags.Contains(SectorTagType
|
|
|
|
|
.CdSectorSubHeader)
|
2017-12-19 20:33:03 +00:00
|
|
|
)
|
2017-12-20 17:15:26 +00:00
|
|
|
ImageInfo.ReadableSectorTags.Add(SectorTagType
|
|
|
|
|
.CdSectorSubHeader);
|
|
|
|
|
if(!ImageInfo.ReadableSectorTags.Contains(SectorTagType
|
|
|
|
|
.CdSectorEcc))
|
|
|
|
|
ImageInfo.ReadableSectorTags.Add(SectorTagType
|
|
|
|
|
.CdSectorEcc);
|
|
|
|
|
if(!ImageInfo.ReadableSectorTags.Contains(SectorTagType
|
|
|
|
|
.CdSectorEccP)
|
2017-12-19 20:33:03 +00:00
|
|
|
)
|
2017-12-20 17:15:26 +00:00
|
|
|
ImageInfo.ReadableSectorTags.Add(SectorTagType
|
|
|
|
|
.CdSectorEccP);
|
|
|
|
|
if(!ImageInfo.ReadableSectorTags.Contains(SectorTagType
|
|
|
|
|
.CdSectorEccQ)
|
2017-12-19 20:33:03 +00:00
|
|
|
)
|
2017-12-20 17:15:26 +00:00
|
|
|
ImageInfo.ReadableSectorTags.Add(SectorTagType
|
|
|
|
|
.CdSectorEccQ);
|
|
|
|
|
if(!ImageInfo.ReadableSectorTags.Contains(SectorTagType
|
|
|
|
|
.CdSectorEdc))
|
|
|
|
|
ImageInfo.ReadableSectorTags.Add(SectorTagType
|
|
|
|
|
.CdSectorEdc);
|
|
|
|
|
if(ImageInfo.SectorSize < 2048) ImageInfo.SectorSize = 2048;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
currentTrack.TrackBytesPerSector = 2336;
|
2017-12-20 17:15:26 +00:00
|
|
|
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;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
else { if(ImageInfo.SectorSize < 2352) ImageInfo.SectorSize = 2352; }
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case 5:
|
|
|
|
|
switch(descriptor.POINT)
|
|
|
|
|
{
|
|
|
|
|
case 0xC0:
|
|
|
|
|
if(descriptor.PMIN == 97)
|
|
|
|
|
{
|
|
|
|
|
int type = descriptor.PFRAME % 10;
|
|
|
|
|
int frm = descriptor.PFRAME - type;
|
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
ImageInfo.MediaManufacturer = ATIP.ManufacturerFromATIP(descriptor.PSEC, frm);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
if(ImageInfo.MediaManufacturer != "")
|
2017-12-19 20:33:03 +00:00
|
|
|
DicConsole.DebugWriteLine("CloneCD plugin", "Disc manufactured by: {0}",
|
2017-12-20 17:15:26 +00:00
|
|
|
ImageInfo.MediaManufacturer);
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
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);
|
2017-12-21 17:58:51 +00:00
|
|
|
ImageInfo.MediaSerialNumber = $"{id & 0x00FFFFFF:X6}";
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!firstTrackInSession)
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
currentTrack.TrackEndSector = leadOutStart - 1;
|
2017-12-19 20:33:03 +00:00
|
|
|
tracks.Add(currentTrack);
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
if(subFilter != null && !ImageInfo.ReadableSectorTags.Contains(SectorTagType.CdSectorSubchannel))
|
|
|
|
|
ImageInfo.ReadableSectorTags.Add(SectorTagType.CdSectorSubchannel);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
2017-12-21 14:30:38 +00:00
|
|
|
sessions = new List<Session>();
|
|
|
|
|
Session currentSession = new Session();
|
2017-12-19 20:33:03 +00:00
|
|
|
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);
|
2017-12-21 14:30:38 +00:00
|
|
|
currentSession = new Session();
|
2017-12-19 20:33:03 +00:00
|
|
|
currentSession.EndTrack = uint.MinValue;
|
|
|
|
|
currentSession.StartTrack = uint.MaxValue;
|
|
|
|
|
currentSession.SessionSequence = track.TrackSession;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Partition partition = new Partition();
|
|
|
|
|
partition.Description = track.TrackDescription;
|
2017-12-20 17:26:28 +00:00
|
|
|
partition.Size = (track.TrackEndSector - track.TrackStartSector + 1) *
|
2017-12-19 20:33:03 +00:00
|
|
|
(ulong)track.TrackRawBytesPerSector;
|
2017-12-20 17:26:28 +00:00
|
|
|
partition.Length = track.TrackEndSector - track.TrackStartSector + 1;
|
2017-12-20 17:15:26 +00:00
|
|
|
ImageInfo.Sectors += partition.Length;
|
2017-12-19 20:33:03 +00:00
|
|
|
partition.Sequence = track.TrackSequence;
|
|
|
|
|
partition.Offset = track.TrackFileOffset;
|
|
|
|
|
partition.Start = track.TrackStartSector;
|
|
|
|
|
partition.Type = 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)
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
case TrackType.CdMode2Form1:
|
|
|
|
|
case TrackType.CdMode2Form2:
|
|
|
|
|
case TrackType.CdMode2Formless:
|
2017-12-19 20:33:03 +00:00
|
|
|
mode2 = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: Check format
|
|
|
|
|
cdtext = cdtMs.ToArray();
|
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
if(!data && !firstdata) ImageInfo.MediaType = MediaType.CDDA;
|
|
|
|
|
else if(firstaudio && data && sessions.Count > 1 && mode2) ImageInfo.MediaType = MediaType.CDPLUS;
|
2017-12-20 17:26:28 +00:00
|
|
|
else if(firstdata && audio || mode2) ImageInfo.MediaType = MediaType.CDROMXA;
|
2017-12-20 17:15:26 +00:00
|
|
|
else if(!audio) ImageInfo.MediaType = MediaType.CDROM;
|
|
|
|
|
else ImageInfo.MediaType = MediaType.CD;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
ImageInfo.ImageApplication = "CloneCD";
|
|
|
|
|
ImageInfo.ImageSize = (ulong)imageFilter.GetDataForkLength();
|
|
|
|
|
ImageInfo.ImageCreationTime = imageFilter.GetCreationTime();
|
|
|
|
|
ImageInfo.ImageLastModificationTime = imageFilter.GetLastWriteTime();
|
|
|
|
|
ImageInfo.XmlMediaType = XmlMediaType.OpticalDisc;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
static ulong GetLba(int hour, int minute, int second, int frame)
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:26:28 +00:00
|
|
|
return (ulong)(hour * 60 * 60 * 75 + minute * 60 * 75 + second * 75 + frame - 150);
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override bool ImageHasPartitions()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.ImageHasPartitions;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override ulong GetImageSize()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.ImageSize;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override ulong GetSectors()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.Sectors;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override uint GetSectorSize()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.SectorSize;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2017-12-21 07:08:26 +00:00
|
|
|
foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from _track in tracks where _track.TrackSequence == kvp.Key where sectorAddress <= _track.TrackEndSector select kvp) return ReadSectors(sectorAddress - kvp.Value, length, kvp.Key);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
2017-12-21 17:58:51 +00:00
|
|
|
throw new ArgumentOutOfRangeException(nameof(sectorAddress), $"Sector address {sectorAddress} not found");
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag)
|
|
|
|
|
{
|
2017-12-21 07:08:26 +00:00
|
|
|
foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from _track in tracks where _track.TrackSequence == kvp.Key where sectorAddress <= _track.TrackEndSector select kvp) return ReadSectorsTag(sectorAddress - kvp.Value, length, kvp.Key, tag);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
2017-12-21 17:58:51 +00:00
|
|
|
throw new ArgumentOutOfRangeException(nameof(sectorAddress), $"Sector address {sectorAddress} not found");
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override byte[] ReadSectors(ulong sectorAddress, uint length, uint track)
|
|
|
|
|
{
|
|
|
|
|
Track _track = new Track();
|
|
|
|
|
|
|
|
|
|
_track.TrackSequence = 0;
|
|
|
|
|
|
2017-12-21 07:08:26 +00:00
|
|
|
foreach(Track __track in tracks.Where(__track => __track.TrackSequence == track)) {
|
|
|
|
|
_track = __track;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
if(_track.TrackSequence == 0)
|
|
|
|
|
throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image");
|
|
|
|
|
|
2017-12-20 17:26:28 +00:00
|
|
|
if(length + sectorAddress - 1 > _track.TrackEndSector)
|
2017-12-19 20:33:03 +00:00
|
|
|
throw new ArgumentOutOfRangeException(nameof(length),
|
|
|
|
|
string
|
|
|
|
|
.Format("Requested more sectors ({0} {2}) than present in track ({1}), won't cross tracks",
|
|
|
|
|
length + sectorAddress, _track.TrackEndSector,
|
|
|
|
|
sectorAddress));
|
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
uint sectorOffset;
|
|
|
|
|
uint sectorSize;
|
|
|
|
|
uint sectorSkip;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
switch(_track.TrackType)
|
|
|
|
|
{
|
|
|
|
|
case TrackType.Audio:
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 0;
|
|
|
|
|
sectorSize = 2352;
|
|
|
|
|
sectorSkip = 0;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
case TrackType.CdMode1:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 16;
|
|
|
|
|
sectorSize = 2048;
|
|
|
|
|
sectorSkip = 288;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
case TrackType.CdMode2Formless:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 16;
|
|
|
|
|
sectorSize = 2336;
|
|
|
|
|
sectorSkip = 0;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
case TrackType.CdMode2Form1:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 24;
|
|
|
|
|
sectorSize = 2048;
|
|
|
|
|
sectorSkip = 280;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
case TrackType.CdMode2Form2:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 24;
|
|
|
|
|
sectorSize = 2324;
|
|
|
|
|
sectorSkip = 4;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: throw new FeatureSupportedButNotImplementedImageException("Unsupported track type");
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
byte[] buffer = new byte[sectorSize * length];
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
dataStream.Seek((long)(_track.TrackFileOffset + sectorAddress * 2352), SeekOrigin.Begin);
|
2017-12-20 17:15:26 +00:00
|
|
|
if(sectorOffset == 0 && sectorSkip == 0) dataStream.Read(buffer, 0, buffer.Length);
|
2017-12-19 20:33:03 +00:00
|
|
|
else
|
|
|
|
|
for(int i = 0; i < length; i++)
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
byte[] sector = new byte[sectorSize];
|
|
|
|
|
dataStream.Seek(sectorOffset, SeekOrigin.Current);
|
2017-12-19 20:33:03 +00:00
|
|
|
dataStream.Read(sector, 0, sector.Length);
|
2017-12-20 17:15:26 +00:00
|
|
|
dataStream.Seek(sectorSkip, SeekOrigin.Current);
|
|
|
|
|
Array.Copy(sector, 0, buffer, i * sectorSize, sectorSize);
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: Flags
|
|
|
|
|
public override byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag)
|
|
|
|
|
{
|
|
|
|
|
Track _track = new Track();
|
|
|
|
|
|
|
|
|
|
_track.TrackSequence = 0;
|
|
|
|
|
|
2017-12-21 07:08:26 +00:00
|
|
|
foreach(Track __track in tracks.Where(__track => __track.TrackSequence == track)) {
|
|
|
|
|
_track = __track;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
if(_track.TrackSequence == 0)
|
|
|
|
|
throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image");
|
|
|
|
|
|
2017-12-20 17:26:28 +00:00
|
|
|
if(length + sectorAddress - 1 > _track.TrackEndSector)
|
2017-12-19 20:33:03 +00:00
|
|
|
throw new ArgumentOutOfRangeException(nameof(length),
|
2017-12-21 17:58:51 +00:00
|
|
|
$"Requested more sectors ({length + sectorAddress}) than present in track ({_track.TrackEndSector}), won't cross tracks");
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
if(_track.TrackType == TrackType.Data)
|
|
|
|
|
throw new ArgumentException("Unsupported tag requested", nameof(tag));
|
|
|
|
|
|
|
|
|
|
byte[] buffer;
|
|
|
|
|
|
|
|
|
|
switch(tag)
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
case SectorTagType.CdSectorEcc:
|
|
|
|
|
case SectorTagType.CdSectorEccP:
|
|
|
|
|
case SectorTagType.CdSectorEccQ:
|
|
|
|
|
case SectorTagType.CdSectorEdc:
|
|
|
|
|
case SectorTagType.CdSectorHeader:
|
|
|
|
|
case SectorTagType.CdSectorSubHeader:
|
|
|
|
|
case SectorTagType.CdSectorSync: break;
|
|
|
|
|
case SectorTagType.CdSectorSubchannel:
|
2017-12-19 20:33:03 +00:00
|
|
|
buffer = new byte[96 * length];
|
|
|
|
|
subStream.Seek((long)(_track.TrackSubchannelOffset + sectorAddress * 96), SeekOrigin.Begin);
|
|
|
|
|
subStream.Read(buffer, 0, buffer.Length);
|
|
|
|
|
return buffer;
|
|
|
|
|
default: throw new ArgumentException("Unsupported tag requested", nameof(tag));
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
uint sectorOffset;
|
|
|
|
|
uint sectorSize;
|
|
|
|
|
uint sectorSkip;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
switch(_track.TrackType)
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
case TrackType.CdMode1:
|
2017-12-19 20:33:03 +00:00
|
|
|
switch(tag)
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
case SectorTagType.CdSectorSync:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 0;
|
|
|
|
|
sectorSize = 12;
|
|
|
|
|
sectorSkip = 2340;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
case SectorTagType.CdSectorHeader:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 12;
|
|
|
|
|
sectorSize = 4;
|
|
|
|
|
sectorSkip = 2336;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
case SectorTagType.CdSectorSubHeader:
|
2017-12-19 20:33:03 +00:00
|
|
|
throw new ArgumentException("Unsupported tag requested for this track", nameof(tag));
|
2017-12-20 17:15:26 +00:00
|
|
|
case SectorTagType.CdSectorEcc:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 2076;
|
|
|
|
|
sectorSize = 276;
|
|
|
|
|
sectorSkip = 0;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
case SectorTagType.CdSectorEccP:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 2076;
|
|
|
|
|
sectorSize = 172;
|
|
|
|
|
sectorSkip = 104;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
case SectorTagType.CdSectorEccQ:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 2248;
|
|
|
|
|
sectorSize = 104;
|
|
|
|
|
sectorSkip = 0;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
case SectorTagType.CdSectorEdc:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 2064;
|
|
|
|
|
sectorSize = 4;
|
|
|
|
|
sectorSkip = 284;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: throw new ArgumentException("Unsupported tag requested", nameof(tag));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
2017-12-20 17:15:26 +00:00
|
|
|
case TrackType.CdMode2Formless:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
|
|
|
|
switch(tag)
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
case SectorTagType.CdSectorSync:
|
|
|
|
|
case SectorTagType.CdSectorHeader:
|
|
|
|
|
case SectorTagType.CdSectorEcc:
|
|
|
|
|
case SectorTagType.CdSectorEccP:
|
|
|
|
|
case SectorTagType.CdSectorEccQ:
|
2017-12-19 20:33:03 +00:00
|
|
|
throw new ArgumentException("Unsupported tag requested for this track", nameof(tag));
|
2017-12-20 17:15:26 +00:00
|
|
|
case SectorTagType.CdSectorSubHeader:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 0;
|
|
|
|
|
sectorSize = 8;
|
|
|
|
|
sectorSkip = 2328;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
case SectorTagType.CdSectorEdc:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 2332;
|
|
|
|
|
sectorSize = 4;
|
|
|
|
|
sectorSkip = 0;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: throw new ArgumentException("Unsupported tag requested", nameof(tag));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
case TrackType.CdMode2Form1:
|
2017-12-19 20:33:03 +00:00
|
|
|
switch(tag)
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
case SectorTagType.CdSectorSync:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 0;
|
|
|
|
|
sectorSize = 12;
|
|
|
|
|
sectorSkip = 2340;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
case SectorTagType.CdSectorHeader:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 12;
|
|
|
|
|
sectorSize = 4;
|
|
|
|
|
sectorSkip = 2336;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
case SectorTagType.CdSectorSubHeader:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 16;
|
|
|
|
|
sectorSize = 8;
|
|
|
|
|
sectorSkip = 2328;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
case SectorTagType.CdSectorEcc:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 2076;
|
|
|
|
|
sectorSize = 276;
|
|
|
|
|
sectorSkip = 0;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
case SectorTagType.CdSectorEccP:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 2076;
|
|
|
|
|
sectorSize = 172;
|
|
|
|
|
sectorSkip = 104;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
case SectorTagType.CdSectorEccQ:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 2248;
|
|
|
|
|
sectorSize = 104;
|
|
|
|
|
sectorSkip = 0;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
case SectorTagType.CdSectorEdc:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 2072;
|
|
|
|
|
sectorSize = 4;
|
|
|
|
|
sectorSkip = 276;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: throw new ArgumentException("Unsupported tag requested", nameof(tag));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
2017-12-20 17:15:26 +00:00
|
|
|
case TrackType.CdMode2Form2:
|
2017-12-19 20:33:03 +00:00
|
|
|
switch(tag)
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
case SectorTagType.CdSectorSync:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 0;
|
|
|
|
|
sectorSize = 12;
|
|
|
|
|
sectorSkip = 2340;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
case SectorTagType.CdSectorHeader:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 12;
|
|
|
|
|
sectorSize = 4;
|
|
|
|
|
sectorSkip = 2336;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
case SectorTagType.CdSectorSubHeader:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 16;
|
|
|
|
|
sectorSize = 8;
|
|
|
|
|
sectorSkip = 2328;
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2017-12-20 17:15:26 +00:00
|
|
|
case SectorTagType.CdSectorEdc:
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
sectorOffset = 2348;
|
|
|
|
|
sectorSize = 4;
|
|
|
|
|
sectorSkip = 0;
|
2017-12-19 20:33:03 +00:00
|
|
|
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");
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
buffer = new byte[sectorSize * length];
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
dataStream.Seek((long)(_track.TrackFileOffset + sectorAddress * 2352), SeekOrigin.Begin);
|
2017-12-20 17:15:26 +00:00
|
|
|
if(sectorOffset == 0 && sectorSkip == 0) dataStream.Read(buffer, 0, buffer.Length);
|
2017-12-19 20:33:03 +00:00
|
|
|
else
|
|
|
|
|
for(int i = 0; i < length; i++)
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
byte[] sector = new byte[sectorSize];
|
|
|
|
|
dataStream.Seek(sectorOffset, SeekOrigin.Current);
|
2017-12-19 20:33:03 +00:00
|
|
|
dataStream.Read(sector, 0, sector.Length);
|
2017-12-20 17:15:26 +00:00
|
|
|
dataStream.Seek(sectorSkip, SeekOrigin.Current);
|
|
|
|
|
Array.Copy(sector, 0, buffer, i * sectorSize, sectorSize);
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2017-12-21 07:08:26 +00:00
|
|
|
foreach(KeyValuePair<uint, ulong> kvp in from kvp in offsetmap where sectorAddress >= kvp.Value from track in tracks where track.TrackSequence == kvp.Key where sectorAddress - kvp.Value < track.TrackEndSector - track.TrackStartSector + 1 select kvp) return ReadSectorsLong(sectorAddress - kvp.Value, length, kvp.Key);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
2017-12-21 17:58:51 +00:00
|
|
|
throw new ArgumentOutOfRangeException(nameof(sectorAddress), $"Sector address {sectorAddress} not found");
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track)
|
|
|
|
|
{
|
|
|
|
|
Track _track = new Track();
|
|
|
|
|
|
|
|
|
|
_track.TrackSequence = 0;
|
|
|
|
|
|
2017-12-21 07:08:26 +00:00
|
|
|
foreach(Track __track in tracks.Where(__track => __track.TrackSequence == track)) {
|
|
|
|
|
_track = __track;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
if(_track.TrackSequence == 0)
|
|
|
|
|
throw new ArgumentOutOfRangeException(nameof(track), "Track does not exist in disc image");
|
|
|
|
|
|
2017-12-20 17:26:28 +00:00
|
|
|
if(length + sectorAddress - 1 > _track.TrackEndSector)
|
2017-12-19 20:33:03 +00:00
|
|
|
throw new ArgumentOutOfRangeException(nameof(length),
|
2017-12-21 17:58:51 +00:00
|
|
|
$"Requested more sectors ({length + sectorAddress}) than present in track ({_track.TrackEndSector}), won't cross tracks");
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.ImageVersion;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string GetImageApplication()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.ImageApplication;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string GetImageApplicationVersion()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.ImageApplicationVersion;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string GetImageCreator()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.ImageCreator;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override DateTime GetImageCreationTime()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.ImageCreationTime;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override DateTime GetImageLastModificationTime()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.ImageLastModificationTime;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string GetImageName()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.ImageName;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string GetImageComments()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.ImageComments;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string GetMediaManufacturer()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.MediaManufacturer;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string GetMediaModel()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.MediaModel;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string GetMediaSerialNumber()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.DriveSerialNumber;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string GetMediaBarcode()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.MediaBarcode;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string GetMediaPartNumber()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.MediaPartNumber;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override MediaType GetMediaType()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.MediaType;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override int GetMediaSequence()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.MediaSequence;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override int GetLastDiskSequence()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.LastMediaSequence;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string GetDriveManufacturer()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.DriveManufacturer;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string GetDriveModel()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.DriveModel;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string GetDriveSerialNumber()
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
return ImageInfo.DriveSerialNumber;
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override List<Partition> GetPartitions()
|
|
|
|
|
{
|
|
|
|
|
return partitions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override List<Track> GetTracks()
|
|
|
|
|
{
|
|
|
|
|
return tracks;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-21 14:30:38 +00:00
|
|
|
public override List<Track> GetSessionTracks(Session session)
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
2017-12-20 23:07:46 +00:00
|
|
|
if(sessions.Contains(session)) return GetSessionTracks(session.SessionSequence);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
throw new ImageNotSupportedException("Session does not exist in disc image");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override List<Track> GetSessionTracks(ushort session)
|
|
|
|
|
{
|
2017-12-21 14:30:38 +00:00
|
|
|
return tracks.Where(_track => _track.TrackSession == session).ToList();
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
2017-12-21 14:30:38 +00:00
|
|
|
public override List<Session> GetSessions()
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
|
|
|
|
return sessions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override bool? VerifySector(ulong sectorAddress)
|
|
|
|
|
{
|
|
|
|
|
byte[] buffer = ReadSectorLong(sectorAddress);
|
2017-12-21 14:30:38 +00:00
|
|
|
return CdChecksums.CheckCdSector(buffer);
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override bool? VerifySector(ulong sectorAddress, uint track)
|
|
|
|
|
{
|
|
|
|
|
byte[] buffer = ReadSectorLong(sectorAddress, track);
|
2017-12-21 14:30:38 +00:00
|
|
|
return CdChecksums.CheckCdSector(buffer);
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
public override bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> failingLbas,
|
|
|
|
|
out List<ulong> unknownLbas)
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
|
|
|
|
byte[] buffer = ReadSectorsLong(sectorAddress, length);
|
|
|
|
|
int bps = (int)(buffer.Length / length);
|
|
|
|
|
byte[] sector = new byte[bps];
|
2017-12-20 17:15:26 +00:00
|
|
|
failingLbas = new List<ulong>();
|
|
|
|
|
unknownLbas = new List<ulong>();
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
for(int i = 0; i < length; i++)
|
|
|
|
|
{
|
|
|
|
|
Array.Copy(buffer, i * bps, sector, 0, bps);
|
2017-12-21 14:30:38 +00:00
|
|
|
bool? sectorStatus = CdChecksums.CheckCdSector(sector);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
switch(sectorStatus)
|
|
|
|
|
{
|
|
|
|
|
case null:
|
2017-12-20 17:15:26 +00:00
|
|
|
unknownLbas.Add((ulong)i + sectorAddress);
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
case false:
|
2017-12-20 17:15:26 +00:00
|
|
|
failingLbas.Add((ulong)i + sectorAddress);
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
if(unknownLbas.Count > 0) return null;
|
|
|
|
|
if(failingLbas.Count > 0) return false;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
public override bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> failingLbas,
|
|
|
|
|
out List<ulong> unknownLbas)
|
2017-12-19 20:33:03 +00:00
|
|
|
{
|
|
|
|
|
byte[] buffer = ReadSectorsLong(sectorAddress, length, track);
|
|
|
|
|
int bps = (int)(buffer.Length / length);
|
|
|
|
|
byte[] sector = new byte[bps];
|
2017-12-20 17:15:26 +00:00
|
|
|
failingLbas = new List<ulong>();
|
|
|
|
|
unknownLbas = new List<ulong>();
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
for(int i = 0; i < length; i++)
|
|
|
|
|
{
|
|
|
|
|
Array.Copy(buffer, i * bps, sector, 0, bps);
|
2017-12-21 14:30:38 +00:00
|
|
|
bool? sectorStatus = CdChecksums.CheckCdSector(sector);
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
switch(sectorStatus)
|
|
|
|
|
{
|
|
|
|
|
case null:
|
2017-12-20 17:15:26 +00:00
|
|
|
unknownLbas.Add((ulong)i + sectorAddress);
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
case false:
|
2017-12-20 17:15:26 +00:00
|
|
|
failingLbas.Add((ulong)i + sectorAddress);
|
2017-12-19 20:33:03 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
if(unknownLbas.Count > 0) return null;
|
|
|
|
|
if(failingLbas.Count > 0) return false;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override bool? VerifyMediaImage()
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|