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 ;
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-20 17:15:26 +00:00
public class Gdi : ImagePlugin
2015-12-25 20:47:40 +00:00
{
#region Internal structures
2017-12-20 17:15:26 +00:00
struct GdiTrack
2015-12-25 20:47:40 +00:00
{
/// <summary>Track #</summary>
2017-12-20 17:15:26 +00:00
public uint Sequence ;
2016-09-05 17:37:31 +01:00
/// <summary>Track filter</summary>
2017-12-20 17:15:26 +00:00
public Filter Trackfilter ;
2015-12-25 20:47:40 +00:00
/// <summary>Track file</summary>
2017-12-20 17:15:26 +00:00
public string Trackfile ;
2015-12-25 20:47:40 +00:00
/// <summary>Track byte offset in file</summary>
2017-12-20 17:15:26 +00:00
public long Offset ;
2015-12-25 20:47:40 +00:00
/// <summary>Track flags</summary>
2017-12-20 17:15:26 +00:00
public byte Flags ;
2015-12-25 20:47:40 +00:00
/// <summary>Track starting sector</summary>
2017-12-20 17:15:26 +00:00
public ulong StartSector ;
2015-12-25 20:47:40 +00:00
/// <summary>Bytes per sector</summary>
2017-12-20 17:15:26 +00:00
public ushort Bps ;
2015-12-25 20:47:40 +00:00
/// <summary>Sectors in track</summary>
2017-12-20 17:15:26 +00:00
public ulong Sectors ;
2015-12-25 20:47:40 +00:00
/// <summary>Track type</summary>
2017-12-20 17:15:26 +00:00
public TrackType Tracktype ;
2015-12-25 20:47:40 +00:00
/// <summary>Track session</summary>
2017-12-20 17:15:26 +00:00
public bool HighDensity ;
2015-12-25 20:47:40 +00:00
/// <summary>Pregap sectors not stored in track file</summary>
2017-12-20 17:15:26 +00:00
public ulong Pregap ;
2015-12-25 20:47:40 +00:00
}
2017-12-20 17:15:26 +00:00
struct GdiDisc
2015-12-25 20:47:40 +00:00
{
/// <summary>Sessions</summary>
2017-12-20 17:15:26 +00:00
public List < Session > Sessions ;
2015-12-25 20:47:40 +00:00
/// <summary>Tracks</summary>
2017-12-20 17:15:26 +00:00
public List < GdiTrack > Tracks ;
2015-12-25 20:47:40 +00:00
/// <summary>Disk type</summary>
2017-12-20 17:15:26 +00:00
public MediaType Disktype ;
2015-12-25 20:47:40 +00:00
}
#endregion Internal structures
#region Internal variables
StreamReader gdiStream ;
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 ;
2017-12-20 17:15:26 +00:00
GdiDisc discimage ;
2015-12-25 20:47:40 +00:00
List < Partition > partitions ;
ulong densitySeparationSectors ;
#endregion Internal variables
#region Parsing regexs
2017-12-20 17:15:26 +00:00
const string TRACK_REGEX =
2017-12-19 20:33:03 +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
#endregion Parsing regexs
#region Public methods
2017-12-20 17:15:26 +00:00
public Gdi ( )
2015-12-25 20:47:40 +00:00
{
Name = "Dreamcast GDI image" ;
2017-12-20 17:15:26 +00:00
PluginUuid = new Guid ( "281ECBF2-D2A7-414C-8497-1A33F6DCB2DD" ) ;
2015-12-25 20:47:40 +00:00
ImageInfo = new ImageInfo ( ) ;
2017-12-20 17:15:26 +00:00
ImageInfo . ReadableSectorTags = new List < SectorTagType > ( ) ;
ImageInfo . ReadableMediaTags = new List < MediaTagType > ( ) ;
ImageInfo . ImageHasPartitions = true ;
ImageInfo . ImageHasSessions = true ;
ImageInfo . ImageVersion = null ;
ImageInfo . ImageApplicationVersion = null ;
ImageInfo . ImageName = null ;
ImageInfo . ImageCreator = null ;
ImageInfo . MediaManufacturer = null ;
ImageInfo . MediaModel = null ;
ImageInfo . MediaPartNumber = null ;
ImageInfo . MediaSequence = 0 ;
ImageInfo . LastMediaSequence = 0 ;
ImageInfo . DriveManufacturer = null ;
ImageInfo . DriveModel = null ;
ImageInfo . DriveSerialNumber = null ;
ImageInfo . DriveFirmwareRevision = null ;
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()).
2016-09-05 17:37:31 +01:00
public override bool IdentifyImage ( Filter 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 ( ) ) ;
2015-12-25 20:47:40 +00:00
int line = 0 ;
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
{
line + + ;
string _line = gdiStream . ReadLine ( ) ;
2017-12-19 20:33:03 +00:00
if ( line = = 1 ) { if ( ! int . TryParse ( _line , out tracks ) ) return false ; }
2015-12-25 20:47:40 +00:00
else
{
2017-12-20 17:15:26 +00:00
Regex regexTrack = new Regex ( TRACK_REGEX ) ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
Match trackMatch = regexTrack . Match ( _line ) ;
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 ;
}
}
2016-09-05 17:37:31 +01:00
public override bool OpenImage ( Filter 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 ( ) ) ;
2015-12-25 20:47:40 +00:00
int line = 0 ;
int tracksFound = 0 ;
int tracks = 0 ;
bool highDensity = false ;
// Initialize all RegExs
2017-12-20 17:15:26 +00:00
Regex regexTrack = new Regex ( TRACK_REGEX ) ;
2015-12-25 20:47:40 +00:00
// Initialize all RegEx matches
2017-12-20 17:15:26 +00:00
Match trackMatch ;
2015-12-25 20:47:40 +00:00
// Initialize disc
2017-12-20 17:15:26 +00:00
discimage = new GdiDisc ( ) ;
discimage . Sessions = new List < Session > ( ) ;
discimage . Tracks = new List < GdiTrack > ( ) ;
2015-12-25 20:47:40 +00:00
ulong currentStart = 0 ;
offsetmap = new Dictionary < uint , ulong > ( ) ;
2017-12-20 17:15:26 +00:00
GdiTrack currentTrack ;
2015-12-25 20:47:40 +00:00
densitySeparationSectors = 0 ;
2017-12-19 20:33:03 +00:00
FiltersList filtersList ;
2016-09-05 17:37:31 +01:00
2016-04-19 02:11:47 +01:00
while ( gdiStream . Peek ( ) > = 0 )
2015-12-25 20:47:40 +00:00
{
line + + ;
string _line = gdiStream . ReadLine ( ) ;
if ( line = = 1 )
{
if ( ! int . TryParse ( _line , out tracks ) )
throw new ImageNotSupportedException ( "Not a correct Dreamcast GDI image" ) ;
}
else
{
2017-12-20 17:15:26 +00:00
trackMatch = regexTrack . Match ( _line ) ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
if ( ! trackMatch . Success )
2017-12-19 20:33:03 +00:00
throw new ImageNotSupportedException ( string . Format ( "Unknown line \"{0}\" at line {1}" ,
_line , line ) ) ;
2015-12-25 20:47:40 +00:00
tracksFound + + ;
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 ,
trackMatch . Groups [ "offset" ] . Value , line ) ;
2015-12-25 20:47:40 +00:00
2017-12-19 20:33:03 +00:00
filtersList = new FiltersList ( ) ;
2017-12-20 17:15:26 +00:00
currentTrack = new GdiTrack ( ) ;
currentTrack . Bps = ushort . Parse ( trackMatch . Groups [ "type" ] . Value ) ;
currentTrack . Flags = ( byte ) ( byte . Parse ( trackMatch . Groups [ "flags" ] . Value ) * 0x10 ) ;
currentTrack . Offset = long . Parse ( trackMatch . Groups [ "offset" ] . Value ) ;
currentTrack . Sequence = uint . Parse ( trackMatch . Groups [ "track" ] . Value ) ;
currentTrack . StartSector = ulong . Parse ( trackMatch . Groups [ "start" ] . Value ) ;
currentTrack . Trackfilter =
2017-12-19 20:33:03 +00:00
filtersList . GetFilter ( Path . Combine ( imageFilter . GetParentFolder ( ) ,
2017-12-20 17:15:26 +00:00
trackMatch . Groups [ "filename" ] . Value . Replace ( "\\\"" , "\"" )
2017-12-19 20:33:03 +00:00
. Trim ( new [ ] { '"' } ) ) ) ;
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-20 17:26:28 +00:00
if ( ( currentTrack . Trackfilter . GetDataForkLength ( ) - currentTrack . Offset ) % currentTrack . Bps ! =
2017-12-19 20:33:03 +00:00
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-20 17:15:26 +00:00
if ( ( currentTrack . Flags & 0x40 ) = = 0x40 ) currentTrack . Tracktype = TrackType . CdMode1 ;
else currentTrack . Tracktype = 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
}
}
Session [ ] _sessions = new Session [ 2 ] ;
2016-04-19 02:11:47 +01:00
for ( int s = 0 ; s < _sessions . Length ; s + + )
2015-12-25 20:47:40 +00:00
if ( s = = 0 )
{
_sessions [ s ] . SessionSequence = 1 ;
2017-12-21 07:08:26 +00:00
foreach ( GdiTrack trk in discimage . Tracks . Where ( trk = > ! trk . HighDensity ) ) {
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-21 07:08:26 +00:00
if ( _sessions [ s ] . EndTrack < trk . Sequence ) _sessions [ s ] . EndTrack = trk . Sequence ;
2015-12-25 20:47:40 +00:00
2017-12-21 07:08:26 +00:00
if ( _sessions [ s ] . StartSector > trk . StartSector )
_sessions [ s ] . StartSector = trk . StartSector ;
2015-12-25 20:47:40 +00:00
2017-12-21 07:08:26 +00:00
if ( _sessions [ s ] . EndSector < trk . Sectors + trk . StartSector - 1 )
_sessions [ s ] . EndSector = trk . Sectors + trk . StartSector - 1 ;
}
2015-12-25 20:47:40 +00:00
}
else
{
_sessions [ s ] . SessionSequence = 2 ;
2017-12-21 07:08:26 +00:00
foreach ( GdiTrack trk in discimage . Tracks . Where ( trk = > trk . HighDensity ) ) {
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-21 07:08:26 +00:00
if ( _sessions [ s ] . EndTrack < trk . Sequence ) _sessions [ s ] . EndTrack = trk . Sequence ;
2015-12-25 20:47:40 +00:00
2017-12-21 07:08:26 +00:00
if ( _sessions [ s ] . StartSector > trk . StartSector )
_sessions [ s ] . StartSector = trk . StartSector ;
2015-12-25 20:47:40 +00:00
2017-12-21 07:08:26 +00:00
if ( _sessions [ s ] . EndSector < trk . Sectors + trk . StartSector - 1 )
_sessions [ s ] . EndSector = trk . Sectors + trk . StartSector - 1 ;
}
2015-12-25 20:47:40 +00:00
}
2017-12-20 17:15:26 +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" ) ;
Partition partition = new Partition ( ) ;
// Index 01
2017-12-20 17:15:26 +00:00
partition . Description = string . Format ( "Track {0}." , discimage . Tracks [ i ] . Sequence ) ;
2017-07-19 16:37:11 +01:00
partition . Name = null ;
2017-12-20 17:15:26 +00:00
partition . Start = discimage . Tracks [ i ] . StartSector ;
partition . Size = discimage . Tracks [ i ] . Sectors * discimage . Tracks [ i ] . Bps ;
partition . Length = discimage . Tracks [ i ] . Sectors ;
partition . Sequence = discimage . Tracks [ i ] . Sequence ;
partition . Offset = byteOffset ;
partition . Type = discimage . Tracks [ i ] . Tracktype . ToString ( ) ;
byteOffset + = partition . Size ;
offsetmap . Add ( discimage . Tracks [ i ] . Sequence , partition . Start ) ;
2015-12-25 20:47:40 +00:00
partitions . Add ( partition ) ;
}
2017-12-20 17:15:26 +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-20 17:15:26 +00:00
ImageInfo . Sectors + = densitySeparationSectors ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
ImageInfo . SectorSize = 2352 ; // All others
2015-12-25 20:47:40 +00:00
2017-12-21 07:08:26 +00:00
foreach ( GdiTrack track in discimage . Tracks . Where ( track = > ( track . Flags & 0x40 ) = = 0x40 & & track . Bps = = 2352 ) ) {
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 ) ;
}
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
ImageInfo . ImageCreationTime = imageFilter . GetCreationTime ( ) ;
ImageInfo . ImageLastModificationTime = imageFilter . GetLastWriteTime ( ) ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
ImageInfo . MediaType = discimage . Disktype ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
ImageInfo . ReadableSectorTags . Add ( SectorTagType . CdTrackFlags ) ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
ImageInfo . XmlMediaType = XmlMediaType . OpticalDisc ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +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 ;
}
}
public override bool ImageHasPartitions ( )
{
2017-12-20 17:15:26 +00:00
return ImageInfo . ImageHasPartitions ;
2015-12-25 20:47:40 +00:00
}
2016-07-28 22:25:26 +01:00
public override ulong GetImageSize ( )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
return ImageInfo . ImageSize ;
2015-12-25 20:47:40 +00:00
}
2016-07-28 22:25:26 +01:00
public override ulong GetSectors ( )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
return ImageInfo . Sectors ;
2015-12-25 20:47:40 +00:00
}
2016-07-28 22:25:26 +01:00
public override uint GetSectorSize ( )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
return ImageInfo . SectorSize ;
2015-12-25 20:47:40 +00:00
}
2016-01-16 03:54:55 +00:00
public override byte [ ] ReadDiskTag ( MediaTagType tag )
2015-12-25 20:47:40 +00:00
{
throw new FeatureSupportedButNotImplementedImageException ( "Feature not supported by image format" ) ;
}
2016-07-28 22:25:26 +01:00
public override byte [ ] ReadSector ( ulong sectorAddress )
2015-12-25 20:47:40 +00:00
{
return ReadSectors ( sectorAddress , 1 ) ;
}
2016-07-28 22:25:26 +01:00
public override byte [ ] ReadSectorTag ( ulong sectorAddress , SectorTagType tag )
2015-12-25 20:47:40 +00:00
{
return ReadSectorsTag ( sectorAddress , 1 , tag ) ;
}
2016-07-28 22:25:26 +01:00
public override byte [ ] ReadSector ( ulong sectorAddress , uint track )
2015-12-25 20:47:40 +00:00
{
return ReadSectors ( sectorAddress , 1 , track ) ;
}
2016-07-28 22:25:26 +01:00
public override byte [ ] ReadSectorTag ( ulong sectorAddress , uint track , SectorTagType tag )
2015-12-25 20:47:40 +00:00
{
return ReadSectorsTag ( sectorAddress , 1 , track , tag ) ;
}
2016-07-28 22:25:26 +01:00
public override byte [ ] ReadSectors ( ulong sectorAddress , uint length )
2015-12-25 20:47:40 +00:00
{
2017-12-21 07:08:26 +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
ulong transitionStart ;
offsetmap . TryGetValue ( 0 , out 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
}
2016-07-28 22:25:26 +01:00
public override byte [ ] ReadSectorsTag ( ulong sectorAddress , uint length , SectorTagType tag )
2015-12-25 20:47:40 +00:00
{
2017-12-21 07:08:26 +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
ulong transitionStart ;
offsetmap . TryGetValue ( 0 , out 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
}
2016-07-28 22:25:26 +01:00
public override 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-20 17:15:26 +00:00
GdiTrack _track = new GdiTrack ( ) ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
_track . Sequence = 0 ;
2015-12-25 20:47:40 +00:00
2017-12-21 07:08:26 +00:00
foreach ( GdiTrack gdiTrack in discimage . Tracks . Where ( gdiTrack = > gdiTrack . Sequence = = track ) ) {
_track = gdiTrack ;
break ;
}
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
if ( _track . 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-20 17:26:28 +00:00
if ( sectorAddress + length > _track . 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-20 17:15:26 +00:00
switch ( _track . 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-20 17:15:26 +00:00
if ( _track . 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-20 17:15:26 +00:00
if ( _track . Pregap > 0 & & sectorAddress < _track . Pregap )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
ulong remainingPregap = _track . 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-20 17:15:26 +00:00
imageStream = _track . 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-20 17:15:26 +00:00
. Seek ( _track . Offset + ( long ) ( sectorAddress * ( sectorOffset + sectorSize + sectorSkip ) + _track . Pregap * _track . 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
{
2016-09-05 17:37:31 +01:00
byte [ ] sector ;
2017-12-20 17:15:26 +00:00
br . BaseStream . Seek ( sectorOffset , SeekOrigin . Current ) ;
sector = br . ReadBytes ( ( int ) sectorSize ) ;
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 ;
}
2016-07-28 22:25:26 +01:00
public override 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-20 17:15:26 +00:00
GdiTrack _track = new GdiTrack ( ) ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
_track . Sequence = 0 ;
2015-12-25 20:47:40 +00:00
2017-12-21 07:08:26 +00:00
foreach ( GdiTrack gdiTrack in discimage . Tracks . Where ( gdiTrack = > gdiTrack . Sequence = = track ) ) {
_track = gdiTrack ;
break ;
}
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
if ( _track . 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-20 17:15:26 +00:00
if ( length > _track . 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-20 17:15:26 +00:00
flags [ 0 ] + = _track . 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-20 17:15:26 +00:00
switch ( _track . 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-20 17:15:26 +00:00
if ( _track . 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-20 17:15:26 +00:00
if ( _track . Pregap > 0 & & sectorAddress < _track . Pregap )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
ulong remainingPregap = _track . 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-20 17:15:26 +00:00
imageStream = _track . 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-20 17:15:26 +00:00
. Seek ( _track . Offset + ( long ) ( sectorAddress * ( sectorOffset + sectorSize + sectorSkip ) + _track . Pregap * _track . 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
{
2016-09-05 17:37:31 +01:00
byte [ ] sector ;
2017-12-20 17:15:26 +00:00
br . BaseStream . Seek ( sectorOffset , SeekOrigin . Current ) ;
sector = br . ReadBytes ( ( int ) sectorSize ) ;
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 ;
}
2016-07-28 22:25:26 +01:00
public override byte [ ] ReadSectorLong ( ulong sectorAddress )
2015-12-25 20:47:40 +00:00
{
return ReadSectorsLong ( sectorAddress , 1 ) ;
}
2016-07-28 22:25:26 +01:00
public override byte [ ] ReadSectorLong ( ulong sectorAddress , uint track )
2015-12-25 20:47:40 +00:00
{
return ReadSectorsLong ( sectorAddress , 1 , track ) ;
}
2016-07-28 22:25:26 +01:00
public override byte [ ] ReadSectorsLong ( ulong sectorAddress , uint length )
2015-12-25 20:47:40 +00:00
{
2017-12-21 07:08:26 +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
}
2016-07-28 22:25:26 +01:00
public override 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-20 17:15:26 +00:00
GdiTrack _track = new GdiTrack ( ) ;
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
_track . Sequence = 0 ;
2015-12-25 20:47:40 +00:00
2017-12-21 07:08:26 +00:00
foreach ( GdiTrack gdiTrack in discimage . Tracks . Where ( gdiTrack = > gdiTrack . Sequence = = track ) ) {
_track = gdiTrack ;
break ;
}
2015-12-25 20:47:40 +00:00
2017-12-20 17:15:26 +00:00
if ( _track . 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-20 17:26:28 +00:00
if ( sectorAddress + length > _track . 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-20 17:15:26 +00:00
switch ( _track . 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-20 17:15:26 +00:00
if ( _track . 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-20 17:15:26 +00:00
if ( _track . Pregap > 0 & & sectorAddress < _track . Pregap )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
ulong remainingPregap = _track . 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-20 17:15:26 +00:00
imageStream = _track . 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-20 17:15:26 +00:00
. Seek ( _track . Offset + ( long ) ( sectorAddress * ( sectorOffset + sectorSize + sectorSkip ) + _track . Pregap * _track . 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
{
2016-09-05 17:37:31 +01:00
byte [ ] sector ;
2017-12-20 17:15:26 +00:00
br . BaseStream . Seek ( sectorOffset , SeekOrigin . Current ) ;
sector = br . ReadBytes ( ( int ) sectorSize ) ;
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 ;
}
2016-04-19 02:11:47 +01:00
public override string GetImageFormat ( )
2015-12-25 20:47:40 +00:00
{
return "Dreamcast GDI image" ;
}
2016-04-19 02:11:47 +01:00
public override string GetImageVersion ( )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
return ImageInfo . ImageVersion ;
2015-12-25 20:47:40 +00:00
}
2016-04-19 02:11:47 +01:00
public override string GetImageApplication ( )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
return ImageInfo . ImageApplication ;
2015-12-25 20:47:40 +00:00
}
2016-04-19 02:11:47 +01:00
public override string GetImageApplicationVersion ( )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
return ImageInfo . ImageApplicationVersion ;
2015-12-25 20:47:40 +00:00
}
public override DateTime GetImageCreationTime ( )
{
2017-12-20 17:15:26 +00:00
return ImageInfo . ImageCreationTime ;
2015-12-25 20:47:40 +00:00
}
public override DateTime GetImageLastModificationTime ( )
{
2017-12-20 17:15:26 +00:00
return ImageInfo . ImageLastModificationTime ;
2015-12-25 20:47:40 +00:00
}
2016-04-19 02:11:47 +01:00
public override string GetImageComments ( )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
return ImageInfo . ImageComments ;
2015-12-25 20:47:40 +00:00
}
2016-01-16 03:54:55 +00:00
public override string GetMediaSerialNumber ( )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
return ImageInfo . MediaSerialNumber ;
2015-12-25 20:47:40 +00:00
}
2016-01-16 03:54:55 +00:00
public override string GetMediaBarcode ( )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
return ImageInfo . MediaBarcode ;
2015-12-25 20:47:40 +00:00
}
2016-01-16 03:54:55 +00:00
public override MediaType GetMediaType ( )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
return ImageInfo . MediaType ;
2015-12-25 20:47:40 +00:00
}
public override List < Partition > GetPartitions ( )
{
return partitions ;
}
public override List < Track > GetTracks ( )
{
List < Track > tracks = new List < Track > ( ) ;
2017-12-20 17:15:26 +00:00
foreach ( GdiTrack gdiTrack in discimage . Tracks )
2015-12-25 20:47:40 +00:00
{
Track _track = new Track ( ) ;
_track . Indexes = new Dictionary < int , ulong > ( ) ;
_track . TrackDescription = null ;
2017-12-20 17:15:26 +00:00
_track . TrackStartSector = gdiTrack . StartSector ;
_track . TrackEndSector = _track . TrackStartSector + gdiTrack . Sectors - 1 ;
_track . TrackPregap = gdiTrack . Pregap ;
if ( gdiTrack . HighDensity ) _track . TrackSession = 2 ;
2017-12-19 20:33:03 +00:00
else _track . TrackSession = 1 ;
2017-12-20 17:15:26 +00:00
_track . TrackSequence = gdiTrack . Sequence ;
_track . TrackType = gdiTrack . Tracktype ;
_track . TrackFilter = gdiTrack . Trackfilter ;
_track . TrackFile = gdiTrack . Trackfile ;
_track . TrackFileOffset = ( ulong ) gdiTrack . Offset ;
2015-12-25 20:47:40 +00:00
_track . TrackFileType = "BINARY" ;
2017-12-20 17:15:26 +00:00
_track . TrackRawBytesPerSector = gdiTrack . Bps ;
if ( gdiTrack . Tracktype = = TrackType . Data ) _track . TrackBytesPerSector = 2048 ;
2017-12-19 20:33:03 +00:00
else _track . TrackBytesPerSector = 2352 ;
2015-12-25 20:47:40 +00:00
_track . TrackSubchannelType = TrackSubchannelType . None ;
tracks . Add ( _track ) ;
}
return tracks ;
}
public override List < Track > GetSessionTracks ( Session session )
{
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" ) ;
}
2016-07-28 22:25:26 +01:00
public override 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
{
Track _track = new Track ( ) ;
_track . Indexes = new Dictionary < int , ulong > ( ) ;
_track . TrackDescription = null ;
2017-12-20 17:15:26 +00:00
_track . TrackStartSector = gdiTrack . StartSector ;
_track . TrackEndSector = _track . TrackStartSector + gdiTrack . Sectors - 1 ;
_track . TrackPregap = gdiTrack . Pregap ;
if ( gdiTrack . HighDensity ) _track . TrackSession = 2 ;
2017-12-19 20:33:03 +00:00
else _track . TrackSession = 1 ;
2017-12-20 17:15:26 +00:00
_track . TrackSequence = gdiTrack . Sequence ;
_track . TrackType = gdiTrack . Tracktype ;
_track . TrackFilter = gdiTrack . Trackfilter ;
_track . TrackFile = gdiTrack . Trackfile ;
_track . TrackFileOffset = ( ulong ) gdiTrack . Offset ;
2015-12-25 20:47:40 +00:00
_track . TrackFileType = "BINARY" ;
2017-12-20 17:15:26 +00:00
_track . TrackRawBytesPerSector = gdiTrack . Bps ;
if ( gdiTrack . Tracktype = = TrackType . Data ) _track . TrackBytesPerSector = 2048 ;
2017-12-19 20:33:03 +00:00
else _track . TrackBytesPerSector = 2352 ;
2015-12-25 20:47:40 +00:00
_track . TrackSubchannelType = TrackSubchannelType . None ;
tracks . Add ( _track ) ;
}
return tracks ;
}
public override List < Session > GetSessions ( )
{
2017-12-20 17:15:26 +00:00
return discimage . Sessions ;
2015-12-25 20:47:40 +00:00
}
2016-07-28 22:25:26 +01:00
public override bool? VerifySector ( ulong sectorAddress )
2015-12-25 20:47:40 +00:00
{
byte [ ] buffer = ReadSectorLong ( sectorAddress ) ;
2017-12-20 17:15:26 +00:00
return Checksums . CdChecksums . CheckCdSector ( buffer ) ;
2015-12-25 20:47:40 +00:00
}
2016-07-28 22:25:26 +01:00
public override bool? VerifySector ( ulong sectorAddress , uint track )
2015-12-25 20:47:40 +00:00
{
byte [ ] buffer = ReadSectorLong ( sectorAddress , track ) ;
2017-12-20 17:15:26 +00:00
return Checksums . CdChecksums . CheckCdSector ( buffer ) ;
2015-12-25 20:47:40 +00:00
}
2017-12-20 17:15:26 +00:00
public override bool? VerifySectors ( ulong sectorAddress , uint length , out List < ulong > failingLbas ,
out List < ulong > unknownLbas )
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-20 17:15:26 +00:00
bool? sectorStatus = Checksums . 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 ;
if ( failingLbas . Count > 0 ) return false ;
2017-12-19 20:33:03 +00:00
2015-12-25 20:47:40 +00:00
return true ;
}
2017-12-20 17:15:26 +00:00
public override bool? VerifySectors ( ulong sectorAddress , uint length , uint track , out List < ulong > failingLbas ,
out List < ulong > unknownLbas )
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-20 17:15:26 +00:00
bool? sectorStatus = Checksums . 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 ;
if ( failingLbas . Count > 0 ) return false ;
2017-12-19 20:33:03 +00:00
2015-12-25 20:47:40 +00:00
return true ;
}
2016-01-16 03:54:55 +00:00
public override bool? VerifyMediaImage ( )
2015-12-25 20:47:40 +00:00
{
return null ;
}
#endregion Public methods
#region Unsupported features
2016-04-19 02:11:47 +01:00
public override int GetMediaSequence ( )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
return ImageInfo . MediaSequence ;
2015-12-25 20:47:40 +00:00
}
2016-04-19 02:11:47 +01:00
public override int GetLastDiskSequence ( )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
return ImageInfo . LastMediaSequence ;
2015-12-25 20:47:40 +00:00
}
public override string GetDriveManufacturer ( )
{
2017-12-20 17:15:26 +00:00
return ImageInfo . DriveManufacturer ;
2015-12-25 20:47:40 +00:00
}
public override string GetDriveModel ( )
{
2017-12-20 17:15:26 +00:00
return ImageInfo . DriveModel ;
2015-12-25 20:47:40 +00:00
}
public override string GetDriveSerialNumber ( )
{
2017-12-20 17:15:26 +00:00
return ImageInfo . DriveSerialNumber ;
2015-12-25 20:47:40 +00:00
}
2016-01-16 03:54:55 +00:00
public override string GetMediaPartNumber ( )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
return ImageInfo . MediaPartNumber ;
2015-12-25 20:47:40 +00:00
}
2016-01-16 03:54:55 +00:00
public override string GetMediaManufacturer ( )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
return ImageInfo . MediaManufacturer ;
2015-12-25 20:47:40 +00:00
}
2016-01-16 03:54:55 +00:00
public override string GetMediaModel ( )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
return ImageInfo . MediaModel ;
2015-12-25 20:47:40 +00:00
}
2016-04-19 02:11:47 +01:00
public override string GetImageName ( )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
return ImageInfo . ImageName ;
2015-12-25 20:47:40 +00:00
}
2016-04-19 02:11:47 +01:00
public override string GetImageCreator ( )
2015-12-25 20:47:40 +00:00
{
2017-12-20 17:15:26 +00:00
return ImageInfo . ImageCreator ;
2015-12-25 20:47:40 +00:00
}
#endregion Unsupported features
}
2017-12-19 20:33:03 +00:00
}