2017-05-19 20:28:49 +01:00
// /***************************************************************************
2015-12-25 20:47:40 +00:00
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : GDI.cs
2016-07-28 18:13:49 +01:00
// Author(s) : Natalia Portillo <claunia@claunia.com>
2015-12-25 20:47:40 +00:00
//
2016-07-28 18:13:49 +01:00
// Component : Disc image plugins.
2015-12-25 20:47:40 +00:00
//
// --[ Description ] ----------------------------------------------------------
//
2016-07-28 18:13:49 +01:00
// Manages Dreamcast GDI disc images.
2015-12-25 20:47:40 +00:00
//
// --[ License ] --------------------------------------------------------------
//
2016-07-28 18:13:49 +01:00
// 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
2015-12-25 20:47:40 +00:00
// License, or (at your option) any later version.
//
2016-07-28 18:13:49 +01:00
// 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.
2015-12-25 20:47:40 +00:00
//
2016-07-28 18:13:49 +01:00
// 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/>.
2015-12-25 20:47:40 +00:00
//
// ----------------------------------------------------------------------------
2017-12-19 03:50:57 +00:00
// Copyright © 2011-2018 Natalia Portillo
2015-12-25 20:47:40 +00:00
// ****************************************************************************/
2016-07-28 18:13:49 +01:00
2015-12-25 20:47:40 +00:00
using System ;
using System.Collections.Generic ;
using System.IO ;
2017-12-21 07:08:26 +00:00
using System.Linq ;
2015-12-25 20:47:40 +00:00
using System.Text.RegularExpressions ;
2017-12-21 14:30:38 +00:00
using DiscImageChef.Checksums ;
2015-12-25 20:47:40 +00:00
using DiscImageChef.CommonTypes ;
2017-12-19 19:33:46 +00:00
using DiscImageChef.Console ;
2016-09-05 17:37:31 +01:00
using DiscImageChef.Filters ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
namespace DiscImageChef.DiscImages
2015-12-25 20:47:40 +00:00
{
2017-12-19 20:33:03 +00:00
// TODO: There seems no be no clear definition on how to treat pregaps that are not included in the file, so this is just appending it to start of track
// TODO: This format doesn't support to specify pregaps that are included in the file (like Redump ones)
2017-12-26 06:05:12 +00:00
public class Gdi : IMediaImage
2015-12-25 20:47:40 +00:00
{
2017-12-24 00:12:31 +00:00
const string REGEX_TRACK =
2017-12-26 02:51:10 +00:00
@"\s?(?<track>\d+)\s+(?<start>\d+)\s(?<flags>\d)\s(?<type>2352|2048)\s(?<filename>.+)\s(?<offset>\d+)$" ;
2015-12-25 20:47:40 +00:00
2017-12-24 00:12:31 +00:00
ulong densitySeparationSectors ;
GdiDisc discimage ;
2015-12-25 20:47:40 +00:00
StreamReader gdiStream ;
2017-12-26 06:05:12 +00:00
ImageInfo imageInfo ;
2016-09-05 17:37:31 +01:00
Stream imageStream ;
2015-12-25 20:47:40 +00:00
/// <summary>Dictionary, index is track #, value is track number, or 0 if a TOC</summary>
2016-07-28 22:25:26 +01:00
Dictionary < uint , ulong > offsetmap ;
2015-12-25 20:47:40 +00:00
List < Partition > partitions ;
2017-12-20 17:15:26 +00:00
public Gdi ( )
2015-12-25 20:47:40 +00:00
{
2017-12-26 06:05:12 +00:00
imageInfo = new ImageInfo
2017-12-22 06:55:04 +00:00
{
ReadableSectorTags = new List < SectorTagType > ( ) ,
ReadableMediaTags = new List < MediaTagType > ( ) ,
2017-12-26 02:51:10 +00:00
HasPartitions = true ,
HasSessions = true ,
Version = null ,
ApplicationVersion = null ,
MediaTitle = null ,
Creator = null ,
2017-12-22 06:55:04 +00:00
MediaManufacturer = null ,
MediaModel = null ,
MediaPartNumber = null ,
MediaSequence = 0 ,
LastMediaSequence = 0 ,
DriveManufacturer = null ,
DriveModel = null ,
DriveSerialNumber = null ,
DriveFirmwareRevision = null
} ;
2015-12-25 20:47:40 +00:00
}
2017-12-26 06:05:12 +00:00
public virtual string Name = > "Dreamcast GDI image" ;
public virtual Guid Id = > new Guid ( "281ECBF2-D2A7-414C-8497-1A33F6DCB2DD" ) ;
public virtual ImageInfo Info = > imageInfo ;
2017-12-26 02:51:10 +00:00
2017-12-26 06:05:12 +00:00
public virtual string ImageFormat = > "Dreamcast GDI image" ;
2017-12-26 02:51:10 +00:00
2017-12-26 06:05:12 +00:00
public virtual List < Partition > Partitions = > partitions ;
public virtual List < Track > Tracks
2017-12-26 02:51:10 +00:00
{
get
{
List < Track > tracks = new List < Track > ( ) ;
foreach ( GdiTrack gdiTrack in discimage . Tracks )
{
Track track = new Track
{
Indexes = new Dictionary < int , ulong > ( ) ,
TrackDescription = null ,
TrackStartSector = gdiTrack . StartSector ,
TrackPregap = gdiTrack . Pregap ,
TrackSession = ( ushort ) ( gdiTrack . HighDensity ? 2 : 1 ) ,
TrackSequence = gdiTrack . Sequence ,
TrackType = gdiTrack . Tracktype ,
TrackFilter = gdiTrack . Trackfilter ,
TrackFile = gdiTrack . Trackfile ,
TrackFileOffset = ( ulong ) gdiTrack . Offset ,
TrackFileType = "BINARY" ,
TrackRawBytesPerSector = gdiTrack . Bps ,
TrackBytesPerSector = gdiTrack . Tracktype = = TrackType . Data ? 2048 : 2352 ,
TrackSubchannelType = TrackSubchannelType . None
} ;
track . TrackEndSector = track . TrackStartSector + gdiTrack . Sectors - 1 ;
tracks . Add ( track ) ;
}
return tracks ;
}
}
2017-12-26 06:05:12 +00:00
public virtual List < Session > Sessions = > discimage . Sessions ;
2017-12-26 02:51:10 +00:00
2015-12-25 20:47:40 +00:00
// Due to .gdi format, this method must parse whole file, ignoring errors (those will be thrown by OpenImage()).
2017-12-26 06:05:12 +00:00
public virtual bool IdentifyImage ( IFilter imageFilter )
2015-12-25 20:47:40 +00:00
{
try
{
2017-12-19 20:33:03 +00:00
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 ;
}
gdiStream = new StreamReader ( imageFilter . GetDataForkStream ( ) ) ;
2017-12-22 06:55:04 +00:00
int lineNumber = 0 ;
2015-12-25 20:47:40 +00:00
int tracksFound = 0 ;
int tracks = 0 ;
2016-04-19 02:11:47 +01:00
while ( gdiStream . Peek ( ) > = 0 )
2015-12-25 20:47:40 +00:00
{
2017-12-22 06:55:04 +00:00
lineNumber + + ;
string line = gdiStream . ReadLine ( ) ;
2015-12-25 20:47:40 +00:00
2017-12-22 06:55:04 +00:00
if ( lineNumber = = 1 ) { if ( ! int . TryParse ( line , out tracks ) ) return false ; }
2015-12-25 20:47:40 +00:00
else
{
2017-12-24 00:12:31 +00:00
Regex regexTrack = new Regex ( REGEX_TRACK ) ;
2015-12-25 20:47:40 +00:00
2017-12-22 06:55:04 +00:00
Match trackMatch = regexTrack . Match ( line ? ? throw new InvalidOperationException ( ) ) ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
if ( ! trackMatch . Success ) return false ;
2015-12-25 20:47:40 +00:00
tracksFound + + ;
}
}
2017-12-19 20:33:03 +00:00
if ( tracks = = 0 ) return false ;
2015-12-25 20:47:40 +00:00
return tracks = = tracksFound ;
}
2016-04-19 02:11:47 +01:00
catch ( Exception ex )
2015-12-25 20:47:40 +00:00
{
2016-09-05 17:37:31 +01:00
DicConsole . ErrorWriteLine ( "Exception trying to identify image file {0}" , imageFilter . GetBasePath ( ) ) ;
2015-12-25 20:47:40 +00:00
DicConsole . ErrorWriteLine ( "Exception: {0}" , ex . Message ) ;
DicConsole . ErrorWriteLine ( "Stack trace: {0}" , ex . StackTrace ) ;
return false ;
}
}
2017-12-26 06:05:12 +00:00
public virtual bool OpenImage ( IFilter imageFilter )
2015-12-25 20:47:40 +00:00
{
2017-12-19 20:33:03 +00:00
if ( imageFilter = = null ) return false ;
2015-12-25 20:47:40 +00:00
try
{
2016-09-05 17:37:31 +01:00
imageFilter . GetDataForkStream ( ) . Seek ( 0 , SeekOrigin . Begin ) ;
gdiStream = new StreamReader ( imageFilter . GetDataForkStream ( ) ) ;
2017-12-22 06:55:04 +00:00
int lineNumber = 0 ;
2015-12-25 20:47:40 +00:00
bool highDensity = false ;
// Initialize all RegExs
2017-12-24 00:12:31 +00:00
Regex regexTrack = new Regex ( REGEX_TRACK ) ;
2015-12-25 20:47:40 +00:00
// Initialize all RegEx matches
// Initialize disc
2017-12-22 06:55:04 +00:00
discimage = new GdiDisc { Sessions = new List < Session > ( ) , Tracks = new List < GdiTrack > ( ) } ;
2015-12-25 20:47:40 +00:00
ulong currentStart = 0 ;
offsetmap = new Dictionary < uint , ulong > ( ) ;
densitySeparationSectors = 0 ;
2016-04-19 02:11:47 +01:00
while ( gdiStream . Peek ( ) > = 0 )
2015-12-25 20:47:40 +00:00
{
2017-12-22 06:55:04 +00:00
lineNumber + + ;
string line = gdiStream . ReadLine ( ) ;
2015-12-25 20:47:40 +00:00
2017-12-22 06:55:04 +00:00
if ( lineNumber = = 1 )
2015-12-25 20:47:40 +00:00
{
2017-12-22 06:55:04 +00:00
if ( ! int . TryParse ( line , out _ ) )
2015-12-25 20:47:40 +00:00
throw new ImageNotSupportedException ( "Not a correct Dreamcast GDI image" ) ;
}
else
{
2017-12-22 06:55:04 +00:00
Match trackMatch = regexTrack . Match ( line ? ? throw new InvalidOperationException ( ) ) ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
if ( ! trackMatch . Success )
2017-12-22 06:55:04 +00:00
throw new ImageNotSupportedException ( $"Unknown line \" { line } \ " at line {lineNumber}" ) ;
2015-12-25 20:47:40 +00:00
2017-12-19 20:33:03 +00:00
DicConsole . DebugWriteLine ( "GDI plugin" ,
"Found track {0} starts at {1} flags {2} type {3} file {4} offset {5} at line {6}" ,
2017-12-20 17:15:26 +00:00
trackMatch . Groups [ "track" ] . Value , trackMatch . Groups [ "start" ] . Value ,
trackMatch . Groups [ "flags" ] . Value , trackMatch . Groups [ "type" ] . Value ,
trackMatch . Groups [ "filename" ] . Value ,
2017-12-22 06:55:04 +00:00
trackMatch . Groups [ "offset" ] . Value , lineNumber ) ;
FiltersList filtersList = new FiltersList ( ) ;
GdiTrack currentTrack = new GdiTrack
{
Bps = ushort . Parse ( trackMatch . Groups [ "type" ] . Value ) ,
Flags = ( byte ) ( byte . Parse ( trackMatch . Groups [ "flags" ] . Value ) * 0x10 ) ,
Offset = long . Parse ( trackMatch . Groups [ "offset" ] . Value ) ,
Sequence = uint . Parse ( trackMatch . Groups [ "track" ] . Value ) ,
StartSector = ulong . Parse ( trackMatch . Groups [ "start" ] . Value ) ,
Trackfilter =
filtersList . GetFilter ( Path . Combine ( imageFilter . GetParentFolder ( ) ,
trackMatch . Groups [ "filename" ] . Value
. Replace ( "\\\"" , "\"" ) . Trim ( '"' ) ) )
} ;
2017-12-20 17:15:26 +00:00
currentTrack . Trackfile = currentTrack . Trackfilter . GetFilename ( ) ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:26:28 +00:00
if ( currentTrack . StartSector - currentStart > 0 )
2017-12-20 17:15:26 +00:00
if ( currentTrack . StartSector = = 45000 )
2015-12-25 20:47:40 +00:00
{
highDensity = true ;
offsetmap . Add ( 0 , currentStart ) ;
2017-12-20 17:26:28 +00:00
densitySeparationSectors = currentTrack . StartSector - currentStart ;
2017-12-20 17:15:26 +00:00
currentStart = currentTrack . StartSector ;
2015-12-25 20:47:40 +00:00
}
else
{
2017-12-20 17:26:28 +00:00
currentTrack . Pregap = currentTrack . StartSector - currentStart ;
currentTrack . StartSector - = currentTrack . StartSector - currentStart ;
2015-12-25 20:47:40 +00:00
}
2017-12-24 00:12:31 +00:00
if ( ( currentTrack . Trackfilter . GetDataForkLength ( ) - currentTrack . Offset ) % currentTrack . Bps ! = 0 )
throw new ImageNotSupportedException ( "Track size not a multiple of sector size" ) ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
currentTrack . Sectors =
( ulong ) ( ( currentTrack . Trackfilter . GetDataForkLength ( ) - currentTrack . Offset ) /
currentTrack . Bps ) ;
currentTrack . Sectors + = currentTrack . Pregap ;
currentStart + = currentTrack . Sectors ;
currentTrack . HighDensity = highDensity ;
2015-12-25 20:47:40 +00:00
2017-12-24 00:12:31 +00:00
currentTrack . Tracktype =
( currentTrack . Flags & 0x40 ) = = 0x40 ? TrackType . CdMode1 : TrackType . Audio ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
discimage . Tracks . Add ( currentTrack ) ;
2015-12-25 20:47:40 +00:00
}
}
2017-12-22 06:55:04 +00:00
Session [ ] sessions = new Session [ 2 ] ;
for ( int s = 0 ; s < sessions . Length ; s + + )
2015-12-25 20:47:40 +00:00
if ( s = = 0 )
{
2017-12-22 06:55:04 +00:00
sessions [ s ] . SessionSequence = 1 ;
2015-12-25 20:47:40 +00:00
2017-12-24 00:12:31 +00:00
foreach ( GdiTrack trk in discimage . Tracks . Where ( trk = > ! trk . HighDensity ) )
{
2017-12-22 06:55:04 +00:00
if ( sessions [ s ] . StartTrack = = 0 ) sessions [ s ] . StartTrack = trk . Sequence ;
else if ( sessions [ s ] . StartTrack > trk . Sequence ) sessions [ s ] . StartTrack = trk . Sequence ;
2015-12-25 20:47:40 +00:00
2017-12-22 06:55:04 +00:00
if ( sessions [ s ] . EndTrack < trk . Sequence ) sessions [ s ] . EndTrack = trk . Sequence ;
2015-12-25 20:47:40 +00:00
2017-12-24 00:12:31 +00:00
if ( sessions [ s ] . StartSector > trk . StartSector ) sessions [ s ] . StartSector = trk . StartSector ;
2015-12-25 20:47:40 +00:00
2017-12-22 06:55:04 +00:00
if ( sessions [ s ] . EndSector < trk . Sectors + trk . StartSector - 1 )
sessions [ s ] . EndSector = trk . Sectors + trk . StartSector - 1 ;
2017-12-21 07:08:26 +00:00
}
2015-12-25 20:47:40 +00:00
}
else
{
2017-12-22 06:55:04 +00:00
sessions [ s ] . SessionSequence = 2 ;
2015-12-25 20:47:40 +00:00
2017-12-24 00:12:31 +00:00
foreach ( GdiTrack trk in discimage . Tracks . Where ( trk = > trk . HighDensity ) )
{
2017-12-22 06:55:04 +00:00
if ( sessions [ s ] . StartTrack = = 0 ) sessions [ s ] . StartTrack = trk . Sequence ;
else if ( sessions [ s ] . StartTrack > trk . Sequence ) sessions [ s ] . StartTrack = trk . Sequence ;
2015-12-25 20:47:40 +00:00
2017-12-22 06:55:04 +00:00
if ( sessions [ s ] . EndTrack < trk . Sequence ) sessions [ s ] . EndTrack = trk . Sequence ;
2015-12-25 20:47:40 +00:00
2017-12-24 00:12:31 +00:00
if ( sessions [ s ] . StartSector > trk . StartSector ) sessions [ s ] . StartSector = trk . StartSector ;
2015-12-25 20:47:40 +00:00
2017-12-22 06:55:04 +00:00
if ( sessions [ s ] . EndSector < trk . Sectors + trk . StartSector - 1 )
sessions [ s ] . EndSector = trk . Sectors + trk . StartSector - 1 ;
2017-12-21 07:08:26 +00:00
}
2015-12-25 20:47:40 +00:00
}
2017-12-22 06:55:04 +00:00
discimage . Sessions . Add ( sessions [ 0 ] ) ;
discimage . Sessions . Add ( sessions [ 1 ] ) ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
discimage . Disktype = MediaType . GDROM ;
2015-12-25 20:47:40 +00:00
// DEBUG information
DicConsole . DebugWriteLine ( "GDI plugin" , "Disc image parsing results" ) ;
DicConsole . DebugWriteLine ( "GDI plugin" , "Session information:" ) ;
2017-12-20 17:15:26 +00:00
DicConsole . DebugWriteLine ( "GDI plugin" , "\tDisc contains {0} sessions" , discimage . Sessions . Count ) ;
for ( int i = 0 ; i < discimage . Sessions . Count ; i + + )
2015-12-25 20:47:40 +00:00
{
DicConsole . DebugWriteLine ( "GDI plugin" , "\tSession {0} information:" , i + 1 ) ;
2017-12-19 20:33:03 +00:00
DicConsole . DebugWriteLine ( "GDI plugin" , "\t\tStarting track: {0}" ,
2017-12-20 17:15:26 +00:00
discimage . Sessions [ i ] . StartTrack ) ;
2017-12-19 20:33:03 +00:00
DicConsole . DebugWriteLine ( "GDI plugin" , "\t\tStarting sector: {0}" ,
2017-12-20 17:15:26 +00:00
discimage . Sessions [ i ] . StartSector ) ;
DicConsole . DebugWriteLine ( "GDI plugin" , "\t\tEnding track: {0}" , discimage . Sessions [ i ] . EndTrack ) ;
DicConsole . DebugWriteLine ( "GDI plugin" , "\t\tEnding sector: {0}" , discimage . Sessions [ i ] . EndSector ) ;
2015-12-25 20:47:40 +00:00
}
2017-12-19 20:33:03 +00:00
2015-12-25 20:47:40 +00:00
DicConsole . DebugWriteLine ( "GDI plugin" , "Track information:" ) ;
2017-12-20 17:15:26 +00:00
DicConsole . DebugWriteLine ( "GDI plugin" , "\tDisc contains {0} tracks" , discimage . Tracks . Count ) ;
for ( int i = 0 ; i < discimage . Tracks . Count ; i + + )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
DicConsole . DebugWriteLine ( "GDI plugin" , "\tTrack {0} information:" , discimage . Tracks [ i ] . Sequence ) ;
DicConsole . DebugWriteLine ( "GDI plugin" , "\t\t{0} bytes per sector" , discimage . Tracks [ i ] . Bps ) ;
DicConsole . DebugWriteLine ( "GDI plugin" , "\t\tPregap: {0} sectors" , discimage . Tracks [ i ] . Pregap ) ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
if ( ( discimage . Tracks [ i ] . Flags & 0x80 ) = = 0x80 )
2015-12-25 20:47:40 +00:00
DicConsole . DebugWriteLine ( "GDI plugin" , "\t\tTrack is flagged as quadraphonic" ) ;
2017-12-20 17:15:26 +00:00
if ( ( discimage . Tracks [ i ] . Flags & 0x40 ) = = 0x40 )
2015-12-25 20:47:40 +00:00
DicConsole . DebugWriteLine ( "GDI plugin" , "\t\tTrack is data" ) ;
2017-12-20 17:15:26 +00:00
if ( ( discimage . Tracks [ i ] . Flags & 0x20 ) = = 0x20 )
2015-12-25 20:47:40 +00:00
DicConsole . DebugWriteLine ( "GDI plugin" , "\t\tTrack allows digital copy" ) ;
2017-12-20 17:15:26 +00:00
if ( ( discimage . Tracks [ i ] . Flags & 0x10 ) = = 0x10 )
2015-12-25 20:47:40 +00:00
DicConsole . DebugWriteLine ( "GDI plugin" , "\t\tTrack has pre-emphasis applied" ) ;
2017-12-19 20:33:03 +00:00
DicConsole . DebugWriteLine ( "GDI plugin" ,
"\t\tTrack resides in file {0}, type defined as {1}, starting at byte {2}" ,
2017-12-20 17:15:26 +00:00
discimage . Tracks [ i ] . Trackfilter , discimage . Tracks [ i ] . Tracktype ,
discimage . Tracks [ i ] . Offset ) ;
2015-12-25 20:47:40 +00:00
}
DicConsole . DebugWriteLine ( "GDI plugin" , "Building offset map" ) ;
partitions = new List < Partition > ( ) ;
2017-12-20 17:15:26 +00:00
ulong byteOffset = 0 ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
for ( int i = 0 ; i < discimage . Tracks . Count ; i + + )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
if ( discimage . Tracks [ i ] . Sequence = = 1 & & i ! = 0 )
2015-12-25 20:47:40 +00:00
throw new ImageNotSupportedException ( "Unordered tracks" ) ;
// Index 01
2017-12-22 06:55:04 +00:00
Partition partition = new Partition
{
Description = $"Track {discimage.Tracks[i].Sequence}." ,
Name = null ,
Start = discimage . Tracks [ i ] . StartSector ,
Size = discimage . Tracks [ i ] . Sectors * discimage . Tracks [ i ] . Bps ,
Length = discimage . Tracks [ i ] . Sectors ,
Sequence = discimage . Tracks [ i ] . Sequence ,
Offset = byteOffset ,
Type = discimage . Tracks [ i ] . Tracktype . ToString ( )
} ;
2017-12-20 17:15:26 +00:00
byteOffset + = partition . Size ;
offsetmap . Add ( discimage . Tracks [ i ] . Sequence , partition . Start ) ;
2015-12-25 20:47:40 +00:00
partitions . Add ( partition ) ;
}
2017-12-26 06:05:12 +00:00
foreach ( GdiTrack track in discimage . Tracks ) imageInfo . ImageSize + = track . Bps * track . Sectors ;
foreach ( GdiTrack track in discimage . Tracks ) imageInfo . Sectors + = track . Sectors ;
2015-12-25 20:47:40 +00:00
2017-12-26 06:05:12 +00:00
imageInfo . Sectors + = densitySeparationSectors ;
2015-12-25 20:47:40 +00:00
2017-12-26 06:05:12 +00:00
imageInfo . SectorSize = 2352 ; // All others
2015-12-25 20:47:40 +00:00
2017-12-24 00:12:31 +00:00
foreach ( GdiTrack unused in
discimage . Tracks . Where ( track = > ( track . Flags & 0x40 ) = = 0x40 & & track . Bps = = 2352 ) )
{
2017-12-26 06:05:12 +00:00
imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorSync ) ;
imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorHeader ) ;
imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorSubHeader ) ;
imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorEcc ) ;
imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorEccP ) ;
imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorEccQ ) ;
imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorEdc ) ;
2017-12-21 07:08:26 +00:00
}
2015-12-25 20:47:40 +00:00
2017-12-26 06:05:12 +00:00
imageInfo . CreationTime = imageFilter . GetCreationTime ( ) ;
imageInfo . LastModificationTime = imageFilter . GetLastWriteTime ( ) ;
2015-12-25 20:47:40 +00:00
2017-12-26 06:05:12 +00:00
imageInfo . MediaType = discimage . Disktype ;
2015-12-25 20:47:40 +00:00
2017-12-26 06:05:12 +00:00
imageInfo . ReadableSectorTags . Add ( SectorTagType . CdTrackFlags ) ;
2015-12-25 20:47:40 +00:00
2017-12-26 06:05:12 +00:00
imageInfo . XmlMediaType = XmlMediaType . OpticalDisc ;
2015-12-25 20:47:40 +00:00
2017-12-26 06:05:12 +00:00
DicConsole . VerboseWriteLine ( "GDI image describes a disc of type {0}" , imageInfo . MediaType ) ;
2016-08-21 17:35:35 +01:00
2015-12-25 20:47:40 +00:00
return true ;
}
2016-04-19 02:11:47 +01:00
catch ( Exception ex )
2015-12-25 20:47:40 +00:00
{
2016-09-05 17:37:31 +01:00
DicConsole . ErrorWriteLine ( "Exception trying to identify image file {0}" , imageFilter . GetBasePath ( ) ) ;
2015-12-25 20:47:40 +00:00
DicConsole . ErrorWriteLine ( "Exception: {0}" , ex . Message ) ;
DicConsole . ErrorWriteLine ( "Stack trace: {0}" , ex . StackTrace ) ;
return false ;
}
}
2017-12-26 06:05:12 +00:00
public virtual byte [ ] ReadDiskTag ( MediaTagType tag )
2015-12-25 20:47:40 +00:00
{
throw new FeatureSupportedButNotImplementedImageException ( "Feature not supported by image format" ) ;
}
2017-12-26 06:05:12 +00:00
public virtual byte [ ] ReadSector ( ulong sectorAddress )
2015-12-25 20:47:40 +00:00
{
return ReadSectors ( sectorAddress , 1 ) ;
}
2017-12-26 06:05:12 +00:00
public virtual byte [ ] ReadSectorTag ( ulong sectorAddress , SectorTagType tag )
2015-12-25 20:47:40 +00:00
{
return ReadSectorsTag ( sectorAddress , 1 , tag ) ;
}
2017-12-26 06:05:12 +00:00
public virtual byte [ ] ReadSector ( ulong sectorAddress , uint track )
2015-12-25 20:47:40 +00:00
{
return ReadSectors ( sectorAddress , 1 , track ) ;
}
2017-12-26 06:05:12 +00:00
public virtual byte [ ] ReadSectorTag ( ulong sectorAddress , uint track , SectorTagType tag )
2015-12-25 20:47:40 +00:00
{
return ReadSectorsTag ( sectorAddress , 1 , track , tag ) ;
}
2017-12-26 06:05:12 +00:00
public virtual byte [ ] ReadSectors ( ulong sectorAddress , uint length )
2015-12-25 20:47:40 +00:00
{
2017-12-24 00:12:31 +00:00
foreach ( KeyValuePair < uint , ulong > kvp in from kvp in offsetmap
where sectorAddress > = kvp . Value
from gdiTrack in discimage . Tracks
where gdiTrack . Sequence = = kvp . Key
where sectorAddress - kvp . Value < gdiTrack . Sectors
select kvp )
return ReadSectors ( sectorAddress - kvp . Value , length , kvp . Key ) ;
2015-12-25 20:47:40 +00:00
2017-12-22 06:55:04 +00:00
offsetmap . TryGetValue ( 0 , out ulong transitionStart ) ;
2017-12-20 17:26:28 +00:00
if ( sectorAddress > = transitionStart & & sectorAddress < densitySeparationSectors + transitionStart )
return ReadSectors ( sectorAddress - transitionStart , length , 0 ) ;
2015-12-25 20:47:40 +00:00
2016-07-28 22:25:26 +01:00
throw new ArgumentOutOfRangeException ( nameof ( sectorAddress ) , "Sector address not found" ) ;
2015-12-25 20:47:40 +00:00
}
2017-12-26 06:05:12 +00:00
public virtual byte [ ] ReadSectorsTag ( ulong sectorAddress , uint length , SectorTagType tag )
2015-12-25 20:47:40 +00:00
{
2017-12-24 00:12:31 +00:00
foreach ( KeyValuePair < uint , ulong > kvp in from kvp in offsetmap
where sectorAddress > = kvp . Value
from gdiTrack in discimage . Tracks
where gdiTrack . Sequence = = kvp . Key
where sectorAddress - kvp . Value < gdiTrack . Sectors
select kvp )
return ReadSectorsTag ( sectorAddress - kvp . Value , length , kvp . Key , tag ) ;
2015-12-25 20:47:40 +00:00
2017-12-22 06:55:04 +00:00
offsetmap . TryGetValue ( 0 , out ulong transitionStart ) ;
2017-12-20 17:26:28 +00:00
if ( sectorAddress > = transitionStart & & sectorAddress < densitySeparationSectors + transitionStart )
return ReadSectorsTag ( sectorAddress - transitionStart , length , 0 , tag ) ;
2015-12-25 20:47:40 +00:00
2016-07-28 22:25:26 +01:00
throw new ArgumentOutOfRangeException ( nameof ( sectorAddress ) , "Sector address not found" ) ;
2015-12-25 20:47:40 +00:00
}
2017-12-26 06:05:12 +00:00
public virtual byte [ ] ReadSectors ( ulong sectorAddress , uint length , uint track )
2015-12-25 20:47:40 +00:00
{
2016-04-19 02:11:47 +01:00
if ( track = = 0 )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:26:28 +00:00
if ( sectorAddress + length > densitySeparationSectors )
2017-12-19 20:33:03 +00:00
throw new ArgumentOutOfRangeException ( nameof ( length ) ,
"Requested more sectors than present in track, won't cross tracks" ) ;
2015-12-25 20:47:40 +00:00
return new byte [ length * 2352 ] ;
}
2017-12-22 06:55:04 +00:00
GdiTrack dicTrack = new GdiTrack { Sequence = 0 } ;
2015-12-25 20:47:40 +00:00
2017-12-24 00:12:31 +00:00
foreach ( GdiTrack gdiTrack in discimage . Tracks . Where ( gdiTrack = > gdiTrack . Sequence = = track ) )
{
2017-12-22 06:55:04 +00:00
dicTrack = gdiTrack ;
2017-12-21 07:08:26 +00:00
break ;
}
2015-12-25 20:47:40 +00:00
2017-12-22 06:55:04 +00:00
if ( dicTrack . Sequence = = 0 )
2016-07-28 22:25:26 +01:00
throw new ArgumentOutOfRangeException ( nameof ( track ) , "Track does not exist in disc image" ) ;
2015-12-25 20:47:40 +00:00
2017-12-22 06:55:04 +00:00
if ( sectorAddress + length > dicTrack . Sectors )
2017-12-19 20:33:03 +00:00
throw new ArgumentOutOfRangeException ( nameof ( length ) ,
"Requested more sectors than present in track, won't cross tracks" ) ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
uint sectorOffset ;
uint sectorSize ;
uint sectorSkip ;
2015-12-25 20:47:40 +00:00
2017-12-22 06:55:04 +00:00
switch ( dicTrack . Tracktype )
2015-12-25 20:47:40 +00:00
{
case TrackType . Audio :
2017-12-19 20:33:03 +00:00
{
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-22 06:55:04 +00:00
if ( dicTrack . Bps = = 2352 )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
sectorOffset = 16 ;
sectorSize = 2048 ;
sectorSkip = 288 ;
2015-12-25 20:47:40 +00:00
}
2017-12-19 20:33:03 +00:00
else
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
sectorOffset = 0 ;
sectorSize = 2048 ;
sectorSkip = 0 ;
2015-12-25 20:47:40 +00:00
}
2017-12-19 20:33:03 +00:00
break ;
}
default : throw new FeatureSupportedButNotImplementedImageException ( "Unsupported track type" ) ;
2015-12-25 20:47:40 +00:00
}
2017-12-20 17:15:26 +00:00
byte [ ] buffer = new byte [ sectorSize * length ] ;
2015-12-25 20:47:40 +00:00
ulong remainingSectors = length ;
2017-12-22 06:55:04 +00:00
if ( dicTrack . Pregap > 0 & & sectorAddress < dicTrack . Pregap )
2015-12-25 20:47:40 +00:00
{
2017-12-22 06:55:04 +00:00
ulong remainingPregap = dicTrack . Pregap - sectorAddress ;
2015-12-25 20:47:40 +00:00
byte [ ] zero ;
2016-04-19 02:11:47 +01:00
if ( length > remainingPregap )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
zero = new byte [ remainingPregap * sectorSize ] ;
2015-12-25 20:47:40 +00:00
remainingSectors - = remainingPregap ;
}
else
{
2017-12-20 17:15:26 +00:00
zero = new byte [ length * sectorSize ] ;
2015-12-25 20:47:40 +00:00
remainingSectors - = length ;
}
Array . Copy ( zero , 0 , buffer , 0 , zero . Length ) ;
}
2017-12-19 20:33:03 +00:00
if ( remainingSectors = = 0 ) return buffer ;
2015-12-25 20:47:40 +00:00
2017-12-22 06:55:04 +00:00
imageStream = dicTrack . Trackfilter . GetDataForkStream ( ) ;
2016-09-05 17:37:31 +01:00
BinaryReader br = new BinaryReader ( imageStream ) ;
2017-12-19 20:33:03 +00:00
br . BaseStream
2017-12-22 06:55:04 +00:00
. Seek ( dicTrack . Offset + ( long ) ( sectorAddress * ( sectorOffset + sectorSize + sectorSkip ) + dicTrack . Pregap * dicTrack . Bps ) ,
2017-12-19 20:33:03 +00:00
SeekOrigin . Begin ) ;
2017-12-20 17:15:26 +00:00
if ( sectorOffset = = 0 & & sectorSkip = = 0 ) buffer = br . ReadBytes ( ( int ) ( sectorSize * remainingSectors ) ) ;
2016-09-05 17:37:31 +01:00
else
for ( ulong i = 0 ; i < remainingSectors ; i + + )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
br . BaseStream . Seek ( sectorOffset , SeekOrigin . Current ) ;
2017-12-22 06:55:04 +00:00
byte [ ] sector = br . ReadBytes ( ( int ) sectorSize ) ;
2017-12-20 17:15:26 +00:00
br . BaseStream . Seek ( sectorSkip , SeekOrigin . Current ) ;
Array . Copy ( sector , 0 , buffer , ( int ) ( i * sectorSize ) , sectorSize ) ;
2015-12-25 20:47:40 +00:00
}
return buffer ;
}
2017-12-26 06:05:12 +00:00
public virtual byte [ ] ReadSectorsTag ( ulong sectorAddress , uint length , uint track , SectorTagType tag )
2015-12-25 20:47:40 +00:00
{
2016-04-19 02:11:47 +01:00
if ( track = = 0 )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:26:28 +00:00
if ( sectorAddress + length > densitySeparationSectors )
2017-12-19 20:33:03 +00:00
throw new ArgumentOutOfRangeException ( nameof ( length ) ,
"Requested more sectors than present in track, won't cross tracks" ) ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
if ( tag = = SectorTagType . CdTrackFlags ) return new byte [ ] { 0x00 } ;
2015-12-25 20:47:40 +00:00
2016-07-28 22:25:26 +01:00
throw new ArgumentException ( "Unsupported tag requested for this track" , nameof ( tag ) ) ;
2015-12-25 20:47:40 +00:00
}
2017-12-22 06:55:04 +00:00
GdiTrack dicTrack = new GdiTrack { Sequence = 0 } ;
2015-12-25 20:47:40 +00:00
2017-12-24 00:12:31 +00:00
foreach ( GdiTrack gdiTrack in discimage . Tracks . Where ( gdiTrack = > gdiTrack . Sequence = = track ) )
{
2017-12-22 06:55:04 +00:00
dicTrack = gdiTrack ;
2017-12-21 07:08:26 +00:00
break ;
}
2015-12-25 20:47:40 +00:00
2017-12-22 06:55:04 +00:00
if ( dicTrack . Sequence = = 0 )
2016-07-28 22:25:26 +01:00
throw new ArgumentOutOfRangeException ( nameof ( track ) , "Track does not exist in disc image" ) ;
2015-12-25 20:47:40 +00:00
2017-12-22 06:55:04 +00:00
if ( length > dicTrack . Sectors )
2017-12-19 20:33:03 +00:00
throw new ArgumentOutOfRangeException ( nameof ( length ) ,
"Requested more sectors than present in track, won't cross tracks" ) ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
uint sectorOffset ;
uint sectorSize ;
uint sectorSkip ;
2015-12-25 20:47:40 +00:00
2016-04-19 02:11:47 +01:00
switch ( tag )
2015-12-25 20:47:40 +00:00
{
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 . CdSectorSync : break ;
case SectorTagType . CdTrackFlags :
2017-12-19 20:33:03 +00:00
{
byte [ ] flags = new byte [ 1 ] ;
2015-12-25 20:47:40 +00:00
2017-12-22 06:55:04 +00:00
flags [ 0 ] + = dicTrack . Flags ;
2015-12-25 20:47:40 +00:00
2017-12-19 20:33:03 +00:00
return flags ;
}
default : throw new ArgumentException ( "Unsupported tag requested" , nameof ( tag ) ) ;
2015-12-25 20:47:40 +00:00
}
2017-12-22 06:55:04 +00:00
switch ( dicTrack . Tracktype )
2015-12-25 20:47:40 +00:00
{
2017-12-19 20:33:03 +00:00
case TrackType . Audio : throw new ArgumentException ( "There are no tags on audio tracks" , nameof ( tag ) ) ;
2017-12-20 17:15:26 +00:00
case TrackType . CdMode1 :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
if ( dicTrack . Bps ! = 2352 )
2017-12-19 20:33:03 +00:00
throw new FeatureNotPresentImageException ( "Image does not include tags for mode 1 sectors" ) ;
2016-04-19 02:11:47 +01:00
2017-12-19 20:33:03 +00:00
switch ( tag )
{
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorSync :
2015-12-25 20:47:40 +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 ;
2015-12-25 20:47:40 +00:00
}
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 . CdSectorSubchannel :
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 ) ) ;
2015-12-25 20:47:40 +00:00
}
2017-12-19 20:33:03 +00:00
break ;
}
default : throw new FeatureSupportedButNotImplementedImageException ( "Unsupported track type" ) ;
2015-12-25 20:47:40 +00:00
}
2017-12-20 17:15:26 +00:00
byte [ ] buffer = new byte [ sectorSize * length ] ;
2015-12-25 20:47:40 +00:00
ulong remainingSectors = length ;
2017-12-22 06:55:04 +00:00
if ( dicTrack . Pregap > 0 & & sectorAddress < dicTrack . Pregap )
2015-12-25 20:47:40 +00:00
{
2017-12-22 06:55:04 +00:00
ulong remainingPregap = dicTrack . Pregap - sectorAddress ;
2015-12-25 20:47:40 +00:00
byte [ ] zero ;
2016-04-19 02:11:47 +01:00
if ( length > remainingPregap )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
zero = new byte [ remainingPregap * sectorSize ] ;
2015-12-25 20:47:40 +00:00
remainingSectors - = remainingPregap ;
}
else
{
2017-12-20 17:15:26 +00:00
zero = new byte [ length * sectorSize ] ;
2015-12-25 20:47:40 +00:00
remainingSectors - = length ;
}
Array . Copy ( zero , 0 , buffer , 0 , zero . Length ) ;
}
2017-12-19 20:33:03 +00:00
if ( remainingSectors = = 0 ) return buffer ;
2015-12-25 20:47:40 +00:00
2017-12-22 06:55:04 +00:00
imageStream = dicTrack . Trackfilter . GetDataForkStream ( ) ;
2016-09-05 17:37:31 +01:00
BinaryReader br = new BinaryReader ( imageStream ) ;
2017-12-19 20:33:03 +00:00
br . BaseStream
2017-12-22 06:55:04 +00:00
. Seek ( dicTrack . Offset + ( long ) ( sectorAddress * ( sectorOffset + sectorSize + sectorSkip ) + dicTrack . Pregap * dicTrack . Bps ) ,
2017-12-19 20:33:03 +00:00
SeekOrigin . Begin ) ;
2017-12-20 17:15:26 +00:00
if ( sectorOffset = = 0 & & sectorSkip = = 0 ) buffer = br . ReadBytes ( ( int ) ( sectorSize * remainingSectors ) ) ;
2016-09-05 17:37:31 +01:00
else
for ( ulong i = 0 ; i < remainingSectors ; i + + )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
br . BaseStream . Seek ( sectorOffset , SeekOrigin . Current ) ;
2017-12-22 06:55:04 +00:00
byte [ ] sector = br . ReadBytes ( ( int ) sectorSize ) ;
2017-12-20 17:15:26 +00:00
br . BaseStream . Seek ( sectorSkip , SeekOrigin . Current ) ;
Array . Copy ( sector , 0 , buffer , ( int ) ( i * sectorSize ) , sectorSize ) ;
2015-12-25 20:47:40 +00:00
}
return buffer ;
}
2017-12-26 06:05:12 +00:00
public virtual byte [ ] ReadSectorLong ( ulong sectorAddress )
2015-12-25 20:47:40 +00:00
{
return ReadSectorsLong ( sectorAddress , 1 ) ;
}
2017-12-26 06:05:12 +00:00
public virtual byte [ ] ReadSectorLong ( ulong sectorAddress , uint track )
2015-12-25 20:47:40 +00:00
{
return ReadSectorsLong ( sectorAddress , 1 , track ) ;
}
2017-12-26 06:05:12 +00:00
public virtual byte [ ] ReadSectorsLong ( ulong sectorAddress , uint length )
2015-12-25 20:47:40 +00:00
{
2017-12-24 00:12:31 +00:00
foreach ( KeyValuePair < uint , ulong > kvp in from kvp in offsetmap
where sectorAddress > = kvp . Value
from gdiTrack in discimage . Tracks
where gdiTrack . Sequence = = kvp . Key
where sectorAddress - kvp . Value < gdiTrack . Sectors
select kvp )
return ReadSectorsLong ( sectorAddress - kvp . Value , length , kvp . Key ) ;
2015-12-25 20:47:40 +00:00
2016-07-28 22:25:26 +01:00
throw new ArgumentOutOfRangeException ( nameof ( sectorAddress ) , "Sector address not found" ) ;
2015-12-25 20:47:40 +00:00
}
2017-12-26 06:05:12 +00:00
public virtual byte [ ] ReadSectorsLong ( ulong sectorAddress , uint length , uint track )
2015-12-25 20:47:40 +00:00
{
2016-04-19 02:11:47 +01:00
if ( track = = 0 )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:26:28 +00:00
if ( sectorAddress + length > densitySeparationSectors )
2017-12-19 20:33:03 +00:00
throw new ArgumentOutOfRangeException ( nameof ( length ) ,
"Requested more sectors than present in track, won't cross tracks" ) ;
2015-12-25 20:47:40 +00:00
return new byte [ length * 2352 ] ;
}
2017-12-22 06:55:04 +00:00
GdiTrack dicTrack = new GdiTrack { Sequence = 0 } ;
2015-12-25 20:47:40 +00:00
2017-12-24 00:12:31 +00:00
foreach ( GdiTrack gdiTrack in discimage . Tracks . Where ( gdiTrack = > gdiTrack . Sequence = = track ) )
{
2017-12-22 06:55:04 +00:00
dicTrack = gdiTrack ;
2017-12-21 07:08:26 +00:00
break ;
}
2015-12-25 20:47:40 +00:00
2017-12-22 06:55:04 +00:00
if ( dicTrack . Sequence = = 0 )
2016-07-28 22:25:26 +01:00
throw new ArgumentOutOfRangeException ( nameof ( track ) , "Track does not exist in disc image" ) ;
2015-12-25 20:47:40 +00:00
2017-12-22 06:55:04 +00:00
if ( sectorAddress + length > dicTrack . Sectors )
2017-12-19 20:33:03 +00:00
throw new ArgumentOutOfRangeException ( nameof ( length ) ,
"Requested more sectors than present in track, won't cross tracks" ) ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
uint sectorOffset ;
uint sectorSize ;
uint sectorSkip ;
2015-12-25 20:47:40 +00:00
2017-12-22 06:55:04 +00:00
switch ( dicTrack . Tracktype )
2015-12-25 20:47:40 +00:00
{
case TrackType . Audio :
2017-12-19 20:33:03 +00:00
{
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-22 06:55:04 +00:00
if ( dicTrack . Bps = = 2352 )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
sectorOffset = 0 ;
sectorSize = 2352 ;
sectorSkip = 0 ;
2015-12-25 20:47:40 +00:00
}
2017-12-19 20:33:03 +00:00
else
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
sectorOffset = 0 ;
sectorSize = 2048 ;
sectorSkip = 0 ;
2015-12-25 20:47:40 +00:00
}
2017-12-19 20:33:03 +00:00
break ;
}
default : throw new FeatureSupportedButNotImplementedImageException ( "Unsupported track type" ) ;
2015-12-25 20:47:40 +00:00
}
2017-12-20 17:15:26 +00:00
byte [ ] buffer = new byte [ sectorSize * length ] ;
2015-12-25 20:47:40 +00:00
ulong remainingSectors = length ;
2017-12-22 06:55:04 +00:00
if ( dicTrack . Pregap > 0 & & sectorAddress < dicTrack . Pregap )
2015-12-25 20:47:40 +00:00
{
2017-12-22 06:55:04 +00:00
ulong remainingPregap = dicTrack . Pregap - sectorAddress ;
2015-12-25 20:47:40 +00:00
byte [ ] zero ;
2016-04-19 02:11:47 +01:00
if ( length > remainingPregap )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
zero = new byte [ remainingPregap * sectorSize ] ;
2015-12-25 20:47:40 +00:00
remainingSectors - = remainingPregap ;
}
else
{
2017-12-20 17:15:26 +00:00
zero = new byte [ length * sectorSize ] ;
2015-12-25 20:47:40 +00:00
remainingSectors - = length ;
}
Array . Copy ( zero , 0 , buffer , 0 , zero . Length ) ;
}
2017-12-19 20:33:03 +00:00
if ( remainingSectors = = 0 ) return buffer ;
2015-12-25 20:47:40 +00:00
2017-12-22 06:55:04 +00:00
imageStream = dicTrack . Trackfilter . GetDataForkStream ( ) ;
2016-09-05 17:37:31 +01:00
BinaryReader br = new BinaryReader ( imageStream ) ;
2017-12-19 20:33:03 +00:00
br . BaseStream
2017-12-22 06:55:04 +00:00
. Seek ( dicTrack . Offset + ( long ) ( sectorAddress * ( sectorOffset + sectorSize + sectorSkip ) + dicTrack . Pregap * dicTrack . Bps ) ,
2017-12-19 20:33:03 +00:00
SeekOrigin . Begin ) ;
2017-12-20 17:15:26 +00:00
if ( sectorOffset = = 0 & & sectorSkip = = 0 ) buffer = br . ReadBytes ( ( int ) ( sectorSize * remainingSectors ) ) ;
2016-09-05 17:37:31 +01:00
else
for ( ulong i = 0 ; i < remainingSectors ; i + + )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
br . BaseStream . Seek ( sectorOffset , SeekOrigin . Current ) ;
2017-12-22 06:55:04 +00:00
byte [ ] sector = br . ReadBytes ( ( int ) sectorSize ) ;
2017-12-20 17:15:26 +00:00
br . BaseStream . Seek ( sectorSkip , SeekOrigin . Current ) ;
Array . Copy ( sector , 0 , buffer , ( int ) ( i * sectorSize ) , sectorSize ) ;
2015-12-25 20:47:40 +00:00
}
return buffer ;
}
2017-12-26 06:05:12 +00:00
public virtual List < Track > GetSessionTracks ( Session session )
2015-12-25 20:47:40 +00:00
{
2017-12-20 23:07:46 +00:00
if ( discimage . Sessions . Contains ( session ) ) return GetSessionTracks ( session . SessionSequence ) ;
2017-12-19 20:33:03 +00:00
2015-12-25 20:47:40 +00:00
throw new ImageNotSupportedException ( "Session does not exist in disc image" ) ;
}
2017-12-26 06:05:12 +00:00
public virtual List < Track > GetSessionTracks ( ushort session )
2015-12-25 20:47:40 +00:00
{
List < Track > tracks = new List < Track > ( ) ;
bool expectedDensity ;
switch ( session )
{
case 1 :
expectedDensity = false ;
break ;
case 2 :
expectedDensity = true ;
break ;
2017-12-19 20:33:03 +00:00
default : throw new ImageNotSupportedException ( "Session does not exist in disc image" ) ;
2015-12-25 20:47:40 +00:00
}
2017-12-20 17:15:26 +00:00
foreach ( GdiTrack gdiTrack in discimage . Tracks )
if ( gdiTrack . HighDensity = = expectedDensity )
2015-12-25 20:47:40 +00:00
{
2017-12-22 06:55:04 +00:00
Track track = new Track
{
Indexes = new Dictionary < int , ulong > ( ) ,
TrackDescription = null ,
TrackStartSector = gdiTrack . StartSector ,
TrackPregap = gdiTrack . Pregap ,
TrackSession = ( ushort ) ( gdiTrack . HighDensity ? 2 : 1 ) ,
TrackSequence = gdiTrack . Sequence ,
TrackType = gdiTrack . Tracktype ,
TrackFilter = gdiTrack . Trackfilter ,
TrackFile = gdiTrack . Trackfile ,
TrackFileOffset = ( ulong ) gdiTrack . Offset ,
TrackFileType = "BINARY" ,
TrackRawBytesPerSector = gdiTrack . Bps ,
TrackBytesPerSector = gdiTrack . Tracktype = = TrackType . Data ? 2048 : 2352 ,
TrackSubchannelType = TrackSubchannelType . None
} ;
track . TrackEndSector = track . TrackStartSector + gdiTrack . Sectors - 1 ;
tracks . Add ( track ) ;
2015-12-25 20:47:40 +00:00
}
return tracks ;
}
2017-12-26 06:05:12 +00:00
public virtual bool? VerifySector ( ulong sectorAddress )
2015-12-25 20:47:40 +00:00
{
byte [ ] buffer = ReadSectorLong ( sectorAddress ) ;
2017-12-21 14:30:38 +00:00
return CdChecksums . CheckCdSector ( buffer ) ;
2015-12-25 20:47:40 +00:00
}
2017-12-26 06:05:12 +00:00
public virtual bool? VerifySector ( ulong sectorAddress , uint track )
2015-12-25 20:47:40 +00:00
{
byte [ ] buffer = ReadSectorLong ( sectorAddress , track ) ;
2017-12-21 14:30:38 +00:00
return CdChecksums . CheckCdSector ( buffer ) ;
2015-12-25 20:47:40 +00:00
}
2017-12-26 06:05:12 +00:00
public virtual bool? VerifySectors ( ulong sectorAddress , uint length , out List < ulong > failingLbas ,
2017-12-20 17:15:26 +00:00
out List < ulong > unknownLbas )
2015-12-25 20:47:40 +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 > ( ) ;
2015-12-25 20:47:40 +00:00
2016-04-19 02:11:47 +01:00
for ( int i = 0 ; i < length ; i + + )
2015-12-25 20:47:40 +00:00
{
Array . Copy ( buffer , i * bps , sector , 0 , bps ) ;
2017-12-21 14:30:38 +00:00
bool? sectorStatus = CdChecksums . CheckCdSector ( sector ) ;
2015-12-25 20:47:40 +00:00
2016-04-19 02:11:47 +01:00
switch ( sectorStatus )
2015-12-25 20:47:40 +00:00
{
case null :
2017-12-20 17:15:26 +00:00
unknownLbas . Add ( ( ulong ) i + sectorAddress ) ;
2015-12-25 20:47:40 +00:00
break ;
case false :
2017-12-20 17:15:26 +00:00
failingLbas . Add ( ( ulong ) i + sectorAddress ) ;
2015-12-25 20:47:40 +00:00
break ;
}
}
2017-12-20 17:15:26 +00:00
if ( unknownLbas . Count > 0 ) return null ;
2017-12-19 20:33:03 +00:00
2017-12-24 00:12:31 +00:00
return failingLbas . Count < = 0 ;
2015-12-25 20:47:40 +00:00
}
2017-12-26 06:05:12 +00:00
public virtual bool? VerifySectors ( ulong sectorAddress , uint length , uint track , out List < ulong > failingLbas ,
2017-12-20 17:15:26 +00:00
out List < ulong > unknownLbas )
2015-12-25 20:47:40 +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 > ( ) ;
2015-12-25 20:47:40 +00:00
2016-04-19 02:11:47 +01:00
for ( int i = 0 ; i < length ; i + + )
2015-12-25 20:47:40 +00:00
{
Array . Copy ( buffer , i * bps , sector , 0 , bps ) ;
2017-12-21 14:30:38 +00:00
bool? sectorStatus = CdChecksums . CheckCdSector ( sector ) ;
2015-12-25 20:47:40 +00:00
2016-04-19 02:11:47 +01:00
switch ( sectorStatus )
2015-12-25 20:47:40 +00:00
{
case null :
2017-12-20 17:15:26 +00:00
unknownLbas . Add ( ( ulong ) i + sectorAddress ) ;
2015-12-25 20:47:40 +00:00
break ;
case false :
2017-12-20 17:15:26 +00:00
failingLbas . Add ( ( ulong ) i + sectorAddress ) ;
2015-12-25 20:47:40 +00:00
break ;
}
}
2017-12-20 17:15:26 +00:00
if ( unknownLbas . Count > 0 ) return null ;
2017-12-19 20:33:03 +00:00
2017-12-24 00:12:31 +00:00
return failingLbas . Count < = 0 ;
2015-12-25 20:47:40 +00:00
}
2017-12-26 06:05:12 +00:00
public virtual bool? VerifyMediaImage ( )
2015-12-25 20:47:40 +00:00
{
return null ;
}
2017-12-24 00:12:31 +00:00
struct GdiTrack
{
/// <summary>Track #</summary>
public uint Sequence ;
/// <summary>Track filter</summary>
2017-12-26 06:05:12 +00:00
public IFilter Trackfilter ;
2017-12-24 00:12:31 +00:00
/// <summary>Track file</summary>
public string Trackfile ;
/// <summary>Track byte offset in file</summary>
public long Offset ;
/// <summary>Track flags</summary>
public byte Flags ;
/// <summary>Track starting sector</summary>
public ulong StartSector ;
/// <summary>Bytes per sector</summary>
public ushort Bps ;
/// <summary>Sectors in track</summary>
public ulong Sectors ;
/// <summary>Track type</summary>
public TrackType Tracktype ;
/// <summary>Track session</summary>
public bool HighDensity ;
/// <summary>Pregap sectors not stored in track file</summary>
public ulong Pregap ;
}
struct GdiDisc
{
/// <summary>Sessions</summary>
public List < Session > Sessions ;
/// <summary>Tracks</summary>
public List < GdiTrack > Tracks ;
/// <summary>Disk type</summary>
public MediaType Disktype ;
}
2015-12-25 20:47:40 +00:00
}
2017-12-19 20:33:03 +00:00
}