2016-10-08 04:29:04 +01:00
// /***************************************************************************
// 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-2016 Natalia Portillo
// ****************************************************************************/
using System ;
2016-10-08 04:29:33 +01:00
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 ;
2016-10-08 04:29:04 +01:00
namespace DiscImageChef.DiscImages
{
2016-10-08 04:29:33 +01:00
public class CloneCD : ImagePlugin
2016-10-08 04:29:04 +01:00
{
2016-10-08 04:29:33 +01:00
#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" ;
2016-10-10 02:05:49 +01:00
PluginUUID = new Guid ( "EE9C2975-2E79-427A-8EE9-F86F19165784" ) ;
2016-10-08 04:29:33 +01:00
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 )
{
2017-05-16 07:26:05 +01:00
if ( b < 0x20 & & b ! = 0x0A & & b ! = 0x0D & & b ! = 0x00 )
2016-10-08 04:29:33 +01:00
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 ] ;
2016-10-10 02:05:49 +01:00
subStream . Seek ( ( long ) ( _track . TrackSubchannelOffset + sectorAddress * 96 ) , SeekOrigin . Begin ) ;
subStream . Read ( buffer , 0 , buffer . Length ) ;
2016-10-08 04:29:33 +01:00
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 ;
}
}
2016-10-08 04:29:04 +01:00
}