2018-07-23 23:25:43 +01:00
// /***************************************************************************
2020-02-27 12:31:25 +00:00
// Aaru Data Preservation Suite
2016-08-09 15:31:44 +01:00
// ----------------------------------------------------------------------------
//
2018-07-23 23:25:43 +01:00
// Filename : Read.cs
2016-08-09 15:31:44 +01:00
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
2016-08-17 01:32:20 +01:00
// Component : Disc image plugins.
2016-08-09 15:31:44 +01:00
//
// --[ Description ] ----------------------------------------------------------
//
2018-07-23 23:25:43 +01:00
// Reads Alcohol 120% disc images.
2016-08-09 15:31:44 +01:00
//
// --[ License ] --------------------------------------------------------------
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
2022-02-18 10:02:53 +00:00
// Copyright © 2011-2022 Natalia Portillo
2016-08-09 15:31:44 +01:00
// ****************************************************************************/
2016-08-09 15:33:41 +01:00
2022-03-07 07:36:44 +00:00
namespace Aaru.DiscImages ;
2016-08-09 15:31:44 +01:00
using System ;
2016-08-09 15:33:41 +01:00
using System.Collections.Generic ;
using System.IO ;
2017-12-21 07:08:26 +00:00
using System.Linq ;
2017-12-19 19:33:46 +00:00
using System.Text ;
2020-02-27 00:33:26 +00:00
using Aaru.CommonTypes ;
using Aaru.CommonTypes.Enums ;
using Aaru.CommonTypes.Interfaces ;
using Aaru.Console ;
using Aaru.Decoders.CD ;
using Aaru.Decoders.DVD ;
using Aaru.Helpers ;
using DMI = Aaru . Decoders . Xbox . DMI ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
public sealed partial class Alcohol120
2016-08-09 15:31:44 +01:00
{
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public ErrorNumber Open ( IFilter imageFilter )
2016-08-09 15:31:44 +01:00
{
2022-03-06 13:29:38 +00:00
Stream stream = imageFilter . GetDataForkStream ( ) ;
stream . Seek ( 0 , SeekOrigin . Begin ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( stream . Length < 88 )
return ErrorNumber . InvalidArgument ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
_isDvd = false ;
2022-03-07 07:36:44 +00:00
var hdr = new byte [ 88 ] ;
2022-03-06 13:29:38 +00:00
stream . Read ( hdr , 0 , 88 ) ;
_header = Marshal . ByteArrayToStructureLittleEndian < Header > ( hdr ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "header.signature = {0}" ,
Encoding . ASCII . GetString ( _header . signature ) ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "header.version = {0}.{1}" , _header . version [ 0 ] ,
_header . version [ 1 ] ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "header.type = {0}" , _header . type ) ;
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "header.sessions = {0}" , _header . sessions ) ;
2020-01-11 22:44:25 +00:00
2022-03-07 07:36:44 +00:00
for ( var i = 0 ; i < _header . unknown1 . Length ; i + + )
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "header.unknown1[{1}] = 0x{0:X4}" , _header . unknown1 [ i ] ,
i ) ;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "header.bcaLength = {0}" , _header . bcaLength ) ;
2020-01-11 22:44:25 +00:00
2022-03-07 07:36:44 +00:00
for ( var i = 0 ; i < _header . unknown2 . Length ; i + + )
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "header.unknown2[{1}] = 0x{0:X8}" , _header . unknown2 [ i ] ,
i ) ;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "header.bcaOffset = {0}" , _header . bcaOffset ) ;
2020-01-11 22:44:25 +00:00
2022-03-07 07:36:44 +00:00
for ( var i = 0 ; i < _header . unknown3 . Length ; i + + )
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "header.unknown3[{1}] = 0x{0:X8}" , _header . unknown3 [ i ] ,
i ) ;
2017-12-19 20:33:03 +00:00
2022-03-07 07:36:44 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "header.structuresOffset = {0}" , _header . structuresOffset ) ;
2020-01-11 22:44:25 +00:00
2022-03-07 07:36:44 +00:00
for ( var i = 0 ; i < _header . unknown4 . Length ; i + + )
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "header.unknown4[{1}] = 0x{0:X8}" , _header . unknown4 [ i ] ,
i ) ;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "header.sessionOffset = {0}" , _header . sessionOffset ) ;
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "header.dpmOffset = {0}" , _header . dpmOffset ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
if ( _header . version [ 0 ] > MAXIMUM_SUPPORTED_VERSION )
return ErrorNumber . NotSupported ;
2020-03-09 21:36:32 +00:00
2022-03-06 13:29:38 +00:00
stream . Seek ( _header . sessionOffset , SeekOrigin . Begin ) ;
_alcSessions = new Dictionary < int , Session > ( ) ;
2020-01-11 22:44:25 +00:00
2022-03-07 07:36:44 +00:00
for ( var i = 0 ; i < _header . sessions ; i + + )
2022-03-06 13:29:38 +00:00
{
2022-03-07 07:36:44 +00:00
var sesHdr = new byte [ 24 ] ;
2022-03-06 13:29:38 +00:00
stream . Read ( sesHdr , 0 , 24 ) ;
Session session = Marshal . SpanToStructureLittleEndian < Session > ( sesHdr ) ;
2016-08-09 15:33:41 +01:00
2022-03-07 07:36:44 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{1}].sessionStart = {0}" , session . sessionStart ,
2022-03-06 13:29:38 +00:00
i ) ;
2020-01-11 22:44:25 +00:00
2022-03-07 07:36:44 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{1}].sessionEnd = {0}" , session . sessionEnd , i ) ;
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{1}].sessionSequence = {0}" ,
session . sessionSequence , i ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{1}].allBlocks = {0}" , session . allBlocks , i ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{1}].nonTrackBlocks = {0}" ,
session . nonTrackBlocks , i ) ;
2020-01-11 22:44:25 +00:00
2022-03-07 07:36:44 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{1}].firstTrack = {0}" , session . firstTrack , i ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{1}].lastTrack = {0}" , session . lastTrack , i ) ;
2020-02-29 18:03:35 +00:00
2022-03-07 07:36:44 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{1}].unknown = 0x{0:X8}" , session . unknown , i ) ;
2020-01-11 22:44:25 +00:00
2022-03-07 07:36:44 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{1}].trackOffset = {0}" , session . trackOffset , i ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
_alcSessions . Add ( session . sessionSequence , session ) ;
}
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
long footerOff = 0 ;
2022-03-07 07:36:44 +00:00
var oldIncorrectImage = false ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
_alcTracks = new Dictionary < int , Track > ( ) ;
_alcToc = new Dictionary < int , Dictionary < int , Track > > ( ) ;
uint track1Index1 = 0 ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
foreach ( Session session in _alcSessions . Values )
{
stream . Seek ( session . trackOffset , SeekOrigin . Begin ) ;
Dictionary < int , Track > sesToc = new ( ) ;
2020-01-11 22:44:25 +00:00
2022-03-07 07:36:44 +00:00
for ( var i = 0 ; i < session . allBlocks ; i + + )
2022-03-06 13:29:38 +00:00
{
2022-03-07 07:36:44 +00:00
var trkHdr = new byte [ 80 ] ;
2022-03-06 13:29:38 +00:00
stream . Read ( trkHdr , 0 , 80 ) ;
Track track = Marshal . ByteArrayToStructureLittleEndian < Track > ( trkHdr ) ;
2022-03-16 11:47:00 +00:00
if ( track . mode is TrackMode . Mode2F1Alt or TrackMode . Mode2F1Alt )
2022-03-06 13:29:38 +00:00
oldIncorrectImage = true ;
// Solve our own mistake here, sorry, but anyway seems Alcohol doesn't support DDCD
if ( track . zero > 0 & &
track . point > = 1 & &
track . point < = 99 )
2016-08-09 15:33:41 +01:00
{
2022-03-06 13:29:38 +00:00
track . pmin + = ( byte ) ( track . zero * 60 ) ;
track . zero = 0 ;
oldIncorrectImage = true ;
}
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].mode = {0}" , track . mode ,
track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].subMode = {0}" ,
track . subMode , track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2022-03-07 07:36:44 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].adrCtl = {0}" , track . adrCtl ,
track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].tno = {0}" , track . tno ,
track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2022-03-07 07:36:44 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].point = {0:X2}" , track . point ,
track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].min = {0}" , track . min ,
track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].sec = {0}" , track . sec ,
track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2022-03-07 07:36:44 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].frame = {0}" , track . frame ,
track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].zero = {0}" , track . zero ,
track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].pmin = {0}" , track . pmin ,
track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].psec = {0}" , track . psec ,
track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2022-03-07 07:36:44 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].pframe = {0}" , track . pframe ,
track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].extraOffset = {0}" ,
track . extraOffset , track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].sectorSize = {0}" ,
track . sectorSize , track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
//for(int j = 0; j < track.unknown.Length; j++)
// AaruConsole.DebugWriteLine("Alcohol 120% plugin", "session[{2}].track[{1}].unknown[{2}] = {0}", track.unknown[j], i, j, session.sessionSequence);
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].startLba = {0}" ,
track . startLba , track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].startOffset = {0}" ,
track . startOffset , track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2022-03-07 07:36:44 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].files = {0}" , track . files ,
track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].footerOffset = {0}" ,
track . footerOffset , track . point , session . sessionSequence ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
//for(int j = 0; j < track.unknown2.Length; j++)
// AaruConsole.DebugWriteLine("Alcohol 120% plugin", "session[{2}].track[{1}].unknown2[{2}] = {0}", track.unknown2[j], i, j, session.sessionSequence);
2018-01-08 19:30:49 +00:00
2022-03-06 13:29:38 +00:00
if ( track . subMode = = SubchannelMode . Interleaved )
track . sectorSize - = 96 ;
2021-07-06 18:00:23 +01:00
2022-03-06 13:29:38 +00:00
if ( track . point = = 1 & &
track . startLba > 0 )
{
AaruConsole .
ErrorWriteLine ( "The disc this image represents contained a hidden track in the first pregap, that this image format cannot store. This dump is therefore, incorrect." ) ;
2021-07-06 18:00:23 +01:00
2022-03-06 13:29:38 +00:00
track1Index1 = track . startLba ;
track . startLba = 0 ;
}
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
if ( ! sesToc . ContainsKey ( track . point ) )
sesToc . Add ( track . point , track ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
if ( track . point < 0xA0 )
_alcTracks . Add ( track . point , track ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
if ( footerOff = = 0 )
footerOff = track . footerOffset ;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
_isDvd | = track . mode = = TrackMode . DVD ;
2016-08-09 15:33:41 +01:00
}
2022-03-06 13:29:38 +00:00
_alcToc . Add ( session . sessionSequence , sesToc ) ;
}
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
_alcTrackExtras = new Dictionary < int , TrackExtra > ( ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
foreach ( Track track in _alcTracks . Values )
if ( track . extraOffset > 0 & &
! _isDvd )
{
2022-03-07 07:36:44 +00:00
var extHdr = new byte [ 8 ] ;
2022-03-06 13:29:38 +00:00
stream . Seek ( track . extraOffset , SeekOrigin . Begin ) ;
stream . Read ( extHdr , 0 , 8 ) ;
TrackExtra extra = Marshal . SpanToStructureLittleEndian < TrackExtra > ( extHdr ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "track[{1}].extra.pregap = {0}" , extra . pregap ,
track . point ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "track[{1}].extra.sectors = {0}" , extra . sectors ,
track . point ) ;
2021-07-06 18:00:23 +01:00
2022-03-06 13:29:38 +00:00
if ( track . point = = 1 )
2016-08-09 15:33:41 +01:00
{
2022-03-06 13:29:38 +00:00
extra . pregap = track1Index1 + 150 ; // Needed because faulty UltraISO implementation
extra . sectors + = extra . pregap - 150 ;
2016-08-09 15:33:41 +01:00
}
2022-03-06 13:29:38 +00:00
_alcTrackExtras . Add ( track . point , extra ) ;
}
else if ( _isDvd )
2016-08-09 15:33:41 +01:00
{
2022-03-06 13:29:38 +00:00
var extra = new TrackExtra
{
sectors = track . extraOffset
} ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
_alcTrackExtras . Add ( track . point , extra ) ;
2016-08-09 15:33:41 +01:00
}
2022-03-06 13:29:38 +00:00
if ( footerOff > 0 )
{
2022-03-07 07:36:44 +00:00
var footer = new byte [ 16 ] ;
2022-03-06 13:29:38 +00:00
stream . Seek ( footerOff , SeekOrigin . Begin ) ;
stream . Read ( footer , 0 , 16 ) ;
_alcFooter = Marshal . SpanToStructureLittleEndian < Footer > ( footer ) ;
2016-09-05 17:37:31 +01:00
2022-03-07 07:36:44 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "footer.filenameOffset = {0}" , _alcFooter . filenameOffset ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "footer.widechar = {0}" , _alcFooter . widechar ) ;
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "footer.unknown1 = 0x{0:X8}" , _alcFooter . unknown1 ) ;
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "footer.unknown2 = 0x{0:X8}" , _alcFooter . unknown2 ) ;
}
2016-08-09 17:12:17 +01:00
2022-03-07 07:36:44 +00:00
var alcFile = "*.mdf" ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( _alcFooter . filenameOffset > 0 )
{
stream . Seek ( _alcFooter . filenameOffset , SeekOrigin . Begin ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
byte [ ] filename = _header . dpmOffset = = 0 ? new byte [ stream . Length - stream . Position ]
: new byte [ _header . dpmOffset - stream . Position ] ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
stream . Read ( filename , 0 , filename . Length ) ;
alcFile = _alcFooter . widechar = = 1 ? StringHandlers . CToString ( filename , Encoding . Unicode , true )
: StringHandlers . CToString ( filename , Encoding . Default ) ;
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "footer.filename = {0}" , alcFile ) ;
}
if ( _alcFooter . filenameOffset = = 0 )
{
if ( Path . GetExtension ( imageFilter . BasePath ) . ToLowerInvariant ( ) = = ".mds" )
2021-09-15 11:25:26 +01:00
alcFile = Path . GetFileNameWithoutExtension ( imageFilter . BasePath ) + ".mdf" ;
2022-03-06 13:29:38 +00:00
else if ( Path . GetExtension ( imageFilter . BasePath ) . ToLowerInvariant ( ) = = ".xmd" )
2021-09-15 11:25:26 +01:00
alcFile = Path . GetFileNameWithoutExtension ( imageFilter . BasePath ) + ".xmf" ;
2022-03-06 13:29:38 +00:00
}
else if ( string . Compare ( alcFile , "*.mdf" , StringComparison . InvariantCultureIgnoreCase ) = = 0 )
alcFile = Path . GetFileNameWithoutExtension ( imageFilter . BasePath ) + ".mdf" ;
else if ( string . Compare ( alcFile , "*.xmf" , StringComparison . InvariantCultureIgnoreCase ) = = 0 )
alcFile = Path . GetFileNameWithoutExtension ( imageFilter . BasePath ) + ".xmf" ;
if ( _header . bcaLength > 0 & &
_header . bcaOffset > 0 & &
_isDvd )
{
_bca = new byte [ _header . bcaLength ] ;
stream . Seek ( _header . bcaOffset , SeekOrigin . Begin ) ;
int readBytes = stream . Read ( _bca , 0 , _bca . Length ) ;
2016-08-09 17:12:17 +01:00
2022-03-06 13:29:38 +00:00
if ( readBytes = = _bca . Length )
switch ( _header . type )
{
case MediumType . DVD :
case MediumType . DVDR :
_imageInfo . ReadableMediaTags . Add ( MediaTagType . DVD_BCA ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
break ;
}
}
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
_imageInfo . MediaType = MediumTypeToMediaType ( _header . type ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
Sessions = new List < CommonTypes . Structs . Session > ( ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
foreach ( Session alcSes in _alcSessions . Values )
{
var session = new CommonTypes . Structs . Session ( ) ;
2018-06-20 22:50:50 +01:00
2022-03-06 13:29:38 +00:00
if ( ! _alcTracks . TryGetValue ( alcSes . firstTrack , out Track startingTrack ) )
break ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( ! _alcTracks . TryGetValue ( alcSes . lastTrack , out Track endingTrack ) )
break ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( ! _alcTrackExtras . TryGetValue ( alcSes . firstTrack , out _ ) )
break ;
2021-07-09 03:26:51 +01:00
2022-03-06 13:29:38 +00:00
if ( ! _alcTrackExtras . TryGetValue ( alcSes . lastTrack , out TrackExtra endingTrackExtra ) )
break ;
2018-06-20 22:50:50 +01:00
2022-03-06 13:29:38 +00:00
session . StartSector = startingTrack . startLba ;
session . StartTrack = alcSes . firstTrack ;
session . Sequence = alcSes . sessionSequence ;
session . EndSector = endingTrack . startLba + endingTrackExtra . sectors - 1 ;
session . EndTrack = alcSes . lastTrack ;
2018-06-20 22:50:50 +01:00
2022-03-06 13:29:38 +00:00
Sessions . Add ( session ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( session . EndSector > _imageInfo . Sectors )
_imageInfo . Sectors = session . EndSector + 1 ;
}
2018-06-20 22:50:50 +01:00
2022-03-06 13:29:38 +00:00
if ( _isDvd )
{
// TODO: Second layer
if ( _header . structuresOffset > 0 )
2016-08-09 15:33:41 +01:00
{
2022-03-07 07:36:44 +00:00
var structures = new byte [ 4100 ] ;
2022-03-06 13:29:38 +00:00
stream . Seek ( _header . structuresOffset , SeekOrigin . Begin ) ;
stream . Read ( structures , 0 , 4100 ) ;
_dmi = new byte [ 2052 ] ;
_pfi = new byte [ 2052 ] ;
// TODO: CMI
Array . Copy ( structures , 4 , _dmi , 4 , 2048 ) ;
Array . Copy ( structures , 0x804 , _pfi , 4 , 2048 ) ;
_pfi [ 0 ] = 0x08 ;
_pfi [ 1 ] = 0x02 ;
_dmi [ 0 ] = 0x08 ;
_dmi [ 1 ] = 0x02 ;
PFI . PhysicalFormatInformation ? pfi0 = PFI . Decode ( _pfi , _imageInfo . MediaType ) ;
// All discs I tested the disk category and part version (as well as the start PSN for DVD-RAM) where modified by Alcohol
// So much for archival value
if ( pfi0 . HasValue )
2016-08-09 15:33:41 +01:00
{
2022-11-13 19:59:24 +00:00
_imageInfo . MediaType = pfi0 . Value . DiskCategory switch
{
DiskCategory . DVDPR = > MediaType . DVDPR ,
DiskCategory . DVDPRDL = > MediaType . DVDPRDL ,
DiskCategory . DVDPRW = > MediaType . DVDPRW ,
DiskCategory . DVDPRWDL = > MediaType . DVDPRWDL ,
DiskCategory . DVDR = > pfi0 . Value . PartVersion > = 6 ? MediaType . DVDRDL
: MediaType . DVDR ,
DiskCategory . DVDRAM = > MediaType . DVDRAM ,
DiskCategory . DVDRW = > pfi0 . Value . PartVersion > = 15 ? MediaType . DVDRWDL
: MediaType . DVDRW ,
DiskCategory . HDDVDR = > MediaType . HDDVDR ,
DiskCategory . HDDVDRAM = > MediaType . HDDVDRAM ,
DiskCategory . HDDVDROM = > MediaType . HDDVDROM ,
DiskCategory . HDDVDRW = > MediaType . HDDVDRW ,
DiskCategory . Nintendo = > pfi0 . Value . DiscSize = = DVDSize . Eighty
? MediaType . GOD : MediaType . WOD ,
DiskCategory . UMD = > MediaType . UMD ,
_ = > MediaType . DVDROM
} ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
if ( DMI . IsXbox ( _dmi ) )
_imageInfo . MediaType = MediaType . XGD ;
else if ( DMI . IsXbox360 ( _dmi ) )
_imageInfo . MediaType = MediaType . XGD2 ;
2016-08-09 15:33:41 +01:00
2022-03-07 07:36:44 +00:00
var tmp = new byte [ 2048 ] ;
2022-03-06 13:29:38 +00:00
Array . Copy ( _dmi , 4 , tmp , 0 , 2048 ) ;
_dmi = tmp ;
tmp = new byte [ 2048 ] ;
Array . Copy ( _pfi , 4 , tmp , 0 , 2048 ) ;
_pfi = tmp ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
_imageInfo . ReadableMediaTags . Add ( MediaTagType . DVD_PFI ) ;
_imageInfo . ReadableMediaTags . Add ( MediaTagType . DVD_DMI ) ;
2016-08-09 15:33:41 +01:00
}
}
2022-03-06 13:29:38 +00:00
}
else if ( _header . type = = MediumType . CD )
{
2022-03-07 07:36:44 +00:00
var data = false ;
var mode2 = false ;
var firstAudio = false ;
var firstData = false ;
var audio = false ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
foreach ( Track alcoholTrack in _alcTracks . Values )
{
// First track is audio
2022-03-16 11:47:00 +00:00
firstAudio | = alcoholTrack . point = = 1 & & alcoholTrack . mode is TrackMode . Audio or TrackMode . AudioAlt ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
// First track is data
firstData | = alcoholTrack . point = = 1 & &
2022-03-17 23:54:41 +00:00
alcoholTrack . mode ! = TrackMode . Audio & & alcoholTrack . mode ! = TrackMode . AudioAlt ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
// Any non first track is data
2022-03-17 23:54:41 +00:00
data | = alcoholTrack . point ! = 1 & & alcoholTrack . mode ! = TrackMode . Audio & & alcoholTrack . mode ! = TrackMode . AudioAlt ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
// Any non first track is audio
2022-03-16 11:47:00 +00:00
audio | = alcoholTrack . point ! = 1 & & alcoholTrack . mode is TrackMode . Audio or TrackMode . AudioAlt ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
switch ( alcoholTrack . mode )
2016-08-09 15:33:41 +01:00
{
2022-03-06 13:29:38 +00:00
case TrackMode . Mode2 :
2020-11-11 04:19:18 +00:00
case TrackMode . Mode2F1 :
2022-03-06 13:29:38 +00:00
case TrackMode . Mode2F2 :
2020-11-11 04:19:18 +00:00
case TrackMode . Mode2F1Alt :
2022-03-06 13:29:38 +00:00
case TrackMode . Mode2F2Alt :
mode2 = true ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
break ;
}
}
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( ! data & &
! firstData )
_imageInfo . MediaType = MediaType . CDDA ;
else if ( firstAudio & &
data & &
Sessions . Count > 1 & &
mode2 )
_imageInfo . MediaType = MediaType . CDPLUS ;
2022-03-07 07:36:44 +00:00
else if ( firstData & & audio | | mode2 )
2022-03-06 13:29:38 +00:00
_imageInfo . MediaType = MediaType . CDROMXA ;
else if ( ! audio )
_imageInfo . MediaType = MediaType . CDROM ;
else
_imageInfo . MediaType = MediaType . CD ;
}
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "ImageInfo.mediaType = {0}" , _imageInfo . MediaType ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
Partitions = new List < Partition > ( ) ;
_offsetMap = new Dictionary < uint , ulong > ( ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
foreach ( Track trk in _alcTracks . Values )
{
if ( _alcTrackExtras . TryGetValue ( trk . point , out TrackExtra extra ) )
{
var partition = new Partition
{
Description = $"Track {trk.point}." ,
Start = trk . startLba ,
Size = extra . sectors * trk . sectorSize ,
Length = extra . sectors ,
Sequence = trk . point ,
Offset = trk . startOffset ,
Type = trk . mode . ToString ( )
} ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
Partitions . Add ( partition ) ;
}
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( trk . startLba > = extra . pregap )
_offsetMap [ trk . point ] = trk . startLba - extra . pregap ;
else
_offsetMap [ trk . point ] = trk . startLba ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
switch ( trk . mode )
{
case TrackMode . Mode1 :
case TrackMode . Mode1Alt :
case TrackMode . Mode2F1 :
case TrackMode . Mode2F1Alt :
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorSync ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorSync ) ;
2020-06-21 22:30:07 +01:00
2022-03-06 13:29:38 +00:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorHeader ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorHeader ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorSubHeader ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorSubHeader ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorEcc ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorEcc ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorEccP ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorEccP ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorEccQ ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorEccQ ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorEdc ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorEdc ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( _imageInfo . SectorSize < 2048 )
2020-07-20 21:11:32 +01:00
_imageInfo . SectorSize = 2048 ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
break ;
case TrackMode . Mode2 :
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorSync ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorSync ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorHeader ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorHeader ) ;
2018-01-08 19:30:49 +00:00
2022-03-06 13:29:38 +00:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorSubHeader ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorSubHeader ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
if ( _imageInfo . SectorSize < 2336 )
_imageInfo . SectorSize = 2336 ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
break ;
case TrackMode . Mode2F2 :
case TrackMode . Mode2F2Alt :
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorSync ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorSync ) ;
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorHeader ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorHeader ) ;
2020-02-29 18:03:35 +00:00
2022-03-06 13:29:38 +00:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorSubHeader ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorSubHeader ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorEdc ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorEdc ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
if ( _imageInfo . SectorSize < 2324 )
_imageInfo . SectorSize = 2324 ;
2016-09-05 17:37:31 +01:00
2022-03-06 13:29:38 +00:00
break ;
case TrackMode . DVD :
_imageInfo . SectorSize = 2048 ;
2016-09-05 17:37:31 +01:00
2022-03-06 13:29:38 +00:00
break ;
default :
_imageInfo . SectorSize = 2352 ;
2021-09-16 19:10:39 +01:00
2022-03-06 13:29:38 +00:00
break ;
2021-09-16 19:10:39 +01:00
}
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
if ( trk . subMode ! = SubchannelMode . None & &
! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorSubchannel ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorSubchannel ) ;
}
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "printing partition map" ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
foreach ( Partition partition in Partitions )
{
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "Partition sequence: {0}" , partition . Sequence ) ;
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "\tPartition name: {0}" , partition . Name ) ;
2016-08-09 15:33:41 +01:00
2022-03-07 07:36:44 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "\tPartition description: {0}" , partition . Description ) ;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "\tPartition type: {0}" , partition . Type ) ;
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "\tPartition starting sector: {0}" , partition . Start ) ;
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "\tPartition sectors: {0}" , partition . Length ) ;
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "\tPartition starting offset: {0}" , partition . Offset ) ;
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "\tPartition size in bytes: {0}" , partition . Size ) ;
}
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
_imageInfo . Application = "Alcohol 120%" ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "Data filename: {0}" , alcFile ) ;
2017-05-23 19:25:17 +01:00
2022-03-06 13:29:38 +00:00
var filtersList = new FiltersList ( ) ;
_alcImage = filtersList . GetFilter ( alcFile ) ;
2016-08-21 17:35:35 +01:00
2022-03-06 13:29:38 +00:00
if ( _alcImage = = null )
{
AaruConsole . ErrorWriteLine ( "Cannot open data file" ) ;
2018-07-15 21:19:39 +01:00
2022-03-06 13:29:38 +00:00
return ErrorNumber . NoSuchFile ;
2016-08-09 15:33:41 +01:00
}
2022-03-06 13:29:38 +00:00
_imageInfo . ImageSize = ( ulong ) _alcImage . DataForkLength ;
_imageInfo . CreationTime = _alcImage . CreationTime ;
_imageInfo . LastModificationTime = _alcImage . LastWriteTime ;
_imageInfo . XmlMediaType = XmlMediaType . OpticalDisc ;
_imageInfo . Version = $"{_header.version[0]}.{_header.version[1]}" ;
if ( ! _isDvd )
2016-08-09 15:33:41 +01:00
{
2022-03-06 13:29:38 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "Rebuilding TOC" ) ;
byte firstSession = byte . MaxValue ;
byte lastSession = 0 ;
var tocMs = new MemoryStream ( ) ;
2021-09-18 15:01:31 +01:00
2022-03-06 13:29:38 +00:00
tocMs . Write ( new byte [ ]
2016-08-09 15:33:41 +01:00
{
2022-03-06 13:29:38 +00:00
0 , 0
} , 0 , 2 ) ; // Reserved for TOC session numbers
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
foreach ( KeyValuePair < int , Dictionary < int , Track > > sessionToc in _alcToc )
{
if ( sessionToc . Key < firstSession )
firstSession = ( byte ) sessionToc . Key ;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
if ( sessionToc . Key > lastSession )
lastSession = ( byte ) sessionToc . Key ;
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
foreach ( Track sessionTrack in sessionToc . Value . Values )
{
tocMs . WriteByte ( ( byte ) sessionToc . Key ) ;
tocMs . WriteByte ( sessionTrack . adrCtl ) ;
tocMs . WriteByte ( sessionTrack . tno ) ;
tocMs . WriteByte ( sessionTrack . point ) ;
tocMs . WriteByte ( sessionTrack . min ) ;
tocMs . WriteByte ( sessionTrack . sec ) ;
tocMs . WriteByte ( sessionTrack . frame ) ;
tocMs . WriteByte ( sessionTrack . zero ) ;
tocMs . WriteByte ( sessionTrack . pmin ) ;
tocMs . WriteByte ( sessionTrack . psec ) ;
tocMs . WriteByte ( sessionTrack . pframe ) ;
}
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
_fullToc = tocMs . ToArray ( ) ;
_fullToc [ 0 ] = firstSession ;
_fullToc [ 1 ] = lastSession ;
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
_imageInfo . ReadableMediaTags . Add ( MediaTagType . CD_FullTOC ) ;
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdTrackFlags ) ;
2016-08-09 15:33:41 +01:00
}
2022-03-06 13:29:38 +00:00
if ( _imageInfo . MediaType = = MediaType . XGD2 )
2022-03-16 11:47:00 +00:00
if ( _imageInfo . Sectors is 25063 or 4229664 or 4246304 ) // Wxripper unlock
2022-03-06 13:29:38 +00:00
_imageInfo . MediaType = MediaType . XGD3 ;
AaruConsole . VerboseWriteLine ( "Alcohol 120% image describes a disc of type {0}" , _imageInfo . MediaType ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
if ( oldIncorrectImage )
AaruConsole .
WriteLine ( "Incorrect Alcohol 120% image created by an old version of Aaru. Convert image to correct it." ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
return ErrorNumber . NoError ;
}
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public ErrorNumber ReadMediaTag ( MediaTagType tag , out byte [ ] buffer )
{
buffer = null ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
switch ( tag )
2016-08-09 15:33:41 +01:00
{
2022-03-06 13:29:38 +00:00
case MediaTagType . DVD_BCA :
buffer = _bca ? . Clone ( ) as byte [ ] ;
2021-09-19 21:16:47 +01:00
2022-03-06 13:29:38 +00:00
return buffer ! = null ? ErrorNumber . NoError : ErrorNumber . NoData ;
2017-12-21 06:06:19 +00:00
2022-03-06 13:29:38 +00:00
case MediaTagType . DVD_PFI :
buffer = _bca ? . Clone ( ) as byte [ ] ;
2021-09-19 21:16:47 +01:00
2022-03-06 13:29:38 +00:00
return buffer ! = null ? ErrorNumber . NoError : ErrorNumber . NoData ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
case MediaTagType . DVD_DMI :
buffer = _bca ? . Clone ( ) as byte [ ] ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
return buffer ! = null ? ErrorNumber . NoError : ErrorNumber . NoData ;
2021-09-20 20:52:18 +01:00
2022-03-06 13:29:38 +00:00
case MediaTagType . CD_FullTOC :
buffer = _bca ? . Clone ( ) as byte [ ] ;
2017-12-21 06:06:19 +00:00
2022-03-06 13:29:38 +00:00
return buffer ! = null ? ErrorNumber . NoError : ErrorNumber . NoData ;
2021-09-20 20:52:18 +01:00
2022-03-06 13:29:38 +00:00
default : return ErrorNumber . NotSupported ;
2016-08-09 15:33:41 +01:00
}
2022-03-06 13:29:38 +00:00
}
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
2022-03-07 07:36:44 +00:00
public ErrorNumber ReadSector ( ulong sectorAddress , out byte [ ] buffer ) = > ReadSectors ( sectorAddress , 1 , out buffer ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public ErrorNumber ReadSectorTag ( ulong sectorAddress , SectorTagType tag , out byte [ ] buffer ) = >
ReadSectorsTag ( sectorAddress , 1 , tag , out buffer ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public ErrorNumber ReadSector ( ulong sectorAddress , uint track , out byte [ ] buffer ) = >
ReadSectors ( sectorAddress , 1 , track , out buffer ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public ErrorNumber ReadSectorTag ( ulong sectorAddress , uint track , SectorTagType tag , out byte [ ] buffer ) = >
ReadSectorsTag ( sectorAddress , 1 , track , tag , out buffer ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public ErrorNumber ReadSectors ( ulong sectorAddress , uint length , out byte [ ] buffer )
{
buffer = null ;
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
foreach ( KeyValuePair < uint , ulong > kvp in _offsetMap )
if ( sectorAddress > = kvp . Value )
foreach ( Track track in _alcTracks . Values )
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
if ( track . point ! = kvp . Key | |
! _alcTrackExtras . TryGetValue ( track . point , out TrackExtra extra ) )
continue ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( sectorAddress - kvp . Value > = extra . sectors + extra . pregap )
continue ;
return ReadSectors ( sectorAddress - kvp . Value , length , kvp . Key , out buffer ) ;
2017-12-19 20:33:03 +00:00
}
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
return ErrorNumber . SectorNotFound ;
}
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public ErrorNumber ReadSectorsTag ( ulong sectorAddress , uint length , SectorTagType tag , out byte [ ] buffer )
{
buffer = null ;
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
foreach ( KeyValuePair < uint , ulong > kvp in _offsetMap )
if ( sectorAddress > = kvp . Value )
foreach ( Track track in _alcTracks . Values )
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
if ( track . point ! = kvp . Key | |
! _alcTrackExtras . TryGetValue ( track . point , out TrackExtra extra ) )
continue ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( sectorAddress - kvp . Value > = extra . sectors + extra . pregap )
continue ;
return ReadSectorsTag ( sectorAddress - kvp . Value , length , kvp . Key , tag , out buffer ) ;
2017-12-19 20:33:03 +00:00
}
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
return ErrorNumber . SectorNotFound ;
}
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public ErrorNumber ReadSectors ( ulong sectorAddress , uint length , uint track , out byte [ ] buffer )
{
buffer = null ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( ! _alcTracks . TryGetValue ( ( int ) track , out Track alcTrack ) | |
! _alcTrackExtras . TryGetValue ( ( int ) track , out TrackExtra alcExtra ) )
return ErrorNumber . OutOfRange ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( length + sectorAddress > alcExtra . sectors + alcExtra . pregap )
return ErrorNumber . OutOfRange ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
uint sectorOffset ;
uint sectorSize ;
uint sectorSkip ;
2022-03-07 07:36:44 +00:00
var mode2 = false ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
switch ( alcTrack . mode )
{
case TrackMode . Mode1 :
case TrackMode . Mode1Alt :
2021-07-06 18:00:23 +01:00
{
2022-03-06 13:29:38 +00:00
sectorOffset = 16 ;
sectorSize = 2048 ;
sectorSkip = 288 ;
2021-07-06 18:00:23 +01:00
2022-03-06 13:29:38 +00:00
break ;
2021-07-06 18:00:23 +01:00
}
2022-03-06 13:29:38 +00:00
case TrackMode . Mode2 :
case TrackMode . Mode2F1 :
case TrackMode . Mode2F1Alt :
case TrackMode . Mode2F2 :
case TrackMode . Mode2F2Alt :
{
mode2 = true ;
sectorOffset = 0 ;
sectorSize = 2352 ;
sectorSkip = 0 ;
2021-07-09 03:26:51 +01:00
2022-03-06 13:29:38 +00:00
break ;
}
2021-07-09 03:26:51 +01:00
2022-03-06 13:29:38 +00:00
case TrackMode . Audio :
case TrackMode . AudioAlt :
{
sectorOffset = 0 ;
sectorSize = 2352 ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
break ;
}
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
case TrackMode . DVD :
2020-01-11 22:44:25 +00:00
{
2022-03-06 13:29:38 +00:00
sectorOffset = 0 ;
sectorSize = 2048 ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
break ;
}
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
default : return ErrorNumber . NotSupported ;
}
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
switch ( alcTrack . subMode )
{
case SubchannelMode . None :
sectorSkip + = 0 ;
break ;
case SubchannelMode . Interleaved :
sectorSkip + = 96 ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
break ;
default : return ErrorNumber . NotSupported ;
2016-08-09 15:33:41 +01:00
}
2022-03-06 13:29:38 +00:00
buffer = new byte [ sectorSize * length ] ;
if ( alcTrack . point = = 1 & &
alcExtra . pregap > 150 )
2016-08-09 15:33:41 +01:00
{
2022-03-06 13:29:38 +00:00
if ( sectorAddress + 150 < alcExtra . pregap )
return ErrorNumber . NoError ;
2021-09-21 03:42:15 +01:00
2022-03-06 13:29:38 +00:00
sectorAddress - = alcExtra . pregap - 150 ;
}
2020-06-14 23:45:26 +01:00
2022-03-06 13:29:38 +00:00
uint pregapBytes = alcExtra . pregap * ( sectorOffset + sectorSize + sectorSkip ) ;
2022-03-07 07:36:44 +00:00
var fileOffset = ( long ) alcTrack . startOffset ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
if ( alcTrack . startOffset > = pregapBytes )
fileOffset = ( long ) ( alcTrack . startOffset - pregapBytes ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
_imageStream = _alcImage . GetDataForkStream ( ) ;
var br = new BinaryReader ( _imageStream ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
br . BaseStream . Seek ( fileOffset + ( long ) ( sectorAddress * ( sectorOffset + sectorSize + sectorSkip ) ) ,
SeekOrigin . Begin ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
if ( mode2 )
{
var mode2Ms = new MemoryStream ( ( int ) ( sectorSize * length ) ) ;
buffer = br . ReadBytes ( ( int ) ( ( sectorSize + sectorSkip ) * length ) ) ;
2021-09-21 03:42:15 +01:00
2022-03-07 07:36:44 +00:00
for ( var i = 0 ; i < length ; i + + )
2022-03-06 13:29:38 +00:00
{
2022-03-07 07:36:44 +00:00
var sector = new byte [ sectorSize ] ;
2022-03-06 13:29:38 +00:00
Array . Copy ( buffer , ( sectorSize + sectorSkip ) * i , sector , 0 , sectorSize ) ;
sector = Sector . GetUserDataFromMode2 ( sector ) ;
mode2Ms . Write ( sector , 0 , sector . Length ) ;
2016-08-09 15:33:41 +01:00
}
2022-03-06 13:29:38 +00:00
buffer = mode2Ms . ToArray ( ) ;
}
else if ( sectorOffset = = 0 & &
sectorSkip = = 0 )
buffer = br . ReadBytes ( ( int ) ( sectorSize * length ) ) ;
else
2022-03-07 07:36:44 +00:00
for ( var i = 0 ; i < length ; i + + )
2016-08-09 15:33:41 +01:00
{
2022-03-06 13:29:38 +00:00
br . BaseStream . Seek ( sectorOffset , SeekOrigin . Current ) ;
byte [ ] sector = br . ReadBytes ( ( int ) sectorSize ) ;
br . BaseStream . Seek ( sectorSkip , SeekOrigin . Current ) ;
Array . Copy ( sector , 0 , buffer , i * sectorSize , sectorSize ) ;
}
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
return ErrorNumber . NoError ;
}
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public ErrorNumber ReadSectorsTag ( ulong sectorAddress , uint length , uint track , SectorTagType tag ,
out byte [ ] buffer )
{
buffer = null ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( tag = = SectorTagType . CdTrackFlags )
track = ( uint ) sectorAddress ;
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
if ( ! _alcTracks . TryGetValue ( ( int ) track , out Track alcTrack ) | |
! _alcTrackExtras . TryGetValue ( ( int ) track , out TrackExtra alcExtra ) )
return ErrorNumber . SectorNotFound ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( length + sectorAddress > alcExtra . sectors + alcExtra . pregap )
return ErrorNumber . OutOfRange ;
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
uint sectorOffset ;
uint sectorSize ;
uint sectorSkip ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( alcTrack . mode = = TrackMode . DVD )
return ErrorNumber . NotSupported ;
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
switch ( tag )
{
case SectorTagType . CdSectorEcc :
case SectorTagType . CdSectorEccP :
case SectorTagType . CdSectorEccQ :
case SectorTagType . CdSectorEdc :
case SectorTagType . CdSectorHeader :
case SectorTagType . CdSectorSubchannel :
case SectorTagType . CdSectorSubHeader :
case SectorTagType . CdSectorSync : break ;
case SectorTagType . CdTrackFlags :
buffer = new [ ]
{
( byte ) ( alcTrack . adrCtl & 0x0F )
} ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
return ErrorNumber . NoError ;
default : return ErrorNumber . NotSupported ;
}
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
switch ( alcTrack . mode )
{
case TrackMode . Mode1 :
case TrackMode . Mode1Alt :
switch ( tag )
{
case SectorTagType . CdSectorSync :
{
sectorOffset = 0 ;
sectorSize = 12 ;
sectorSkip = 2340 ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
case SectorTagType . CdSectorHeader :
{
sectorOffset = 12 ;
sectorSize = 4 ;
sectorSkip = 2336 ;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break ;
}
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
case SectorTagType . CdSectorSubHeader : return ErrorNumber . NotSupported ;
case SectorTagType . CdSectorEcc :
{
sectorOffset = 2076 ;
sectorSize = 276 ;
sectorSkip = 0 ;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break ;
}
case SectorTagType . CdSectorEccP :
{
sectorOffset = 2076 ;
sectorSize = 172 ;
sectorSkip = 104 ;
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
break ;
2016-08-09 15:33:41 +01:00
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
case SectorTagType . CdSectorEccQ :
2016-08-09 15:33:41 +01:00
{
2022-03-06 13:29:38 +00:00
sectorOffset = 2248 ;
sectorSize = 104 ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
case SectorTagType . CdSectorEdc :
{
sectorOffset = 2064 ;
sectorSize = 4 ;
sectorSkip = 284 ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
case SectorTagType . CdSectorSubchannel :
{
switch ( alcTrack . subMode )
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
case SubchannelMode . Interleaved :
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
sectorOffset = 2352 ;
sectorSize = 96 ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
break ;
default : return ErrorNumber . NotSupported ;
2016-08-09 15:33:41 +01:00
}
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
break ;
2016-08-09 15:33:41 +01:00
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
default : return ErrorNumber . NotSupported ;
2017-12-19 20:33:03 +00:00
}
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
break ;
case TrackMode . Mode2 :
{
switch ( tag )
{
case SectorTagType . CdSectorSync :
case SectorTagType . CdSectorHeader :
case SectorTagType . CdSectorEcc :
case SectorTagType . CdSectorEccP :
case SectorTagType . CdSectorEccQ : return ErrorNumber . NotSupported ;
case SectorTagType . CdSectorSubHeader :
2016-08-09 15:33:41 +01:00
{
2022-03-06 13:29:38 +00:00
sectorOffset = 0 ;
sectorSize = 8 ;
sectorSkip = 2328 ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
case SectorTagType . CdSectorEdc :
{
sectorOffset = 2332 ;
sectorSize = 4 ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
case SectorTagType . CdSectorSubchannel :
{
switch ( alcTrack . subMode )
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
case SubchannelMode . Interleaved :
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
sectorOffset = 2352 ;
sectorSize = 96 ;
sectorSkip = 0 ;
break ;
default : return ErrorNumber . NotSupported ;
2017-12-19 20:33:03 +00:00
}
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
break ;
}
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
default : return ErrorNumber . NotSupported ;
}
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
break ;
}
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
case TrackMode . Mode2F1 :
case TrackMode . Mode2F1Alt :
switch ( tag )
{
case SectorTagType . CdSectorSync :
{
sectorOffset = 0 ;
sectorSize = 12 ;
sectorSkip = 2340 ;
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
break ;
}
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
case SectorTagType . CdSectorHeader :
{
sectorOffset = 12 ;
sectorSize = 4 ;
sectorSkip = 2336 ;
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
break ;
}
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
case SectorTagType . CdSectorSubHeader :
{
sectorOffset = 16 ;
sectorSize = 8 ;
sectorSkip = 2328 ;
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
break ;
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
case SectorTagType . CdSectorEcc :
{
sectorOffset = 2076 ;
sectorSize = 276 ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
break ;
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
case SectorTagType . CdSectorEccP :
{
sectorOffset = 2076 ;
sectorSize = 172 ;
sectorSkip = 104 ;
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
break ;
2016-08-09 15:33:41 +01:00
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
case SectorTagType . CdSectorEccQ :
2016-08-09 15:33:41 +01:00
{
2022-03-06 13:29:38 +00:00
sectorOffset = 2248 ;
sectorSize = 104 ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
case SectorTagType . CdSectorEdc :
{
sectorOffset = 2072 ;
sectorSize = 4 ;
sectorSkip = 276 ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
case SectorTagType . CdSectorSubchannel :
{
switch ( alcTrack . subMode )
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
case SubchannelMode . Interleaved :
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
sectorOffset = 2352 ;
sectorSize = 96 ;
sectorSkip = 0 ;
break ;
default : return ErrorNumber . NotSupported ;
2017-12-19 20:33:03 +00:00
}
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
break ;
}
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
default : return ErrorNumber . NotSupported ;
}
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
break ;
case TrackMode . Mode2F2 :
case TrackMode . Mode2F2Alt :
switch ( tag )
{
case SectorTagType . CdSectorSync :
{
sectorOffset = 0 ;
sectorSize = 12 ;
sectorSkip = 2340 ;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break ;
}
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
case SectorTagType . CdSectorHeader :
{
sectorOffset = 12 ;
sectorSize = 4 ;
sectorSkip = 2336 ;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break ;
}
case SectorTagType . CdSectorSubHeader :
{
sectorOffset = 16 ;
sectorSize = 8 ;
sectorSkip = 2328 ;
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
break ;
2016-08-09 15:33:41 +01:00
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
case SectorTagType . CdSectorEdc :
2016-08-09 15:33:41 +01:00
{
2022-03-06 13:29:38 +00:00
sectorOffset = 2348 ;
sectorSize = 4 ;
sectorSkip = 0 ;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break ;
}
case SectorTagType . CdSectorSubchannel :
{
switch ( alcTrack . subMode )
{
case SubchannelMode . Interleaved :
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
sectorOffset = 2352 ;
sectorSize = 96 ;
sectorSkip = 0 ;
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
break ;
default : return ErrorNumber . NotSupported ;
2016-08-09 15:33:41 +01:00
}
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
break ;
2016-08-09 15:33:41 +01:00
}
2017-12-19 20:33:03 +00:00
2022-03-06 13:29:38 +00:00
default : return ErrorNumber . NotSupported ;
2017-12-19 20:33:03 +00:00
}
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
break ;
case TrackMode . Audio :
case TrackMode . AudioAlt :
2016-08-09 15:33:41 +01:00
{
2022-03-06 13:29:38 +00:00
switch ( tag )
{
case SectorTagType . CdSectorSubchannel :
{
switch ( alcTrack . subMode )
{
case SubchannelMode . Interleaved :
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
sectorOffset = 2352 ;
sectorSize = 96 ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
break ;
default : return ErrorNumber . NotSupported ;
}
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
break ;
}
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
default : return ErrorNumber . NotSupported ;
}
2021-07-06 18:00:23 +01:00
2022-03-06 13:29:38 +00:00
break ;
2021-07-06 18:00:23 +01:00
}
2022-03-06 13:29:38 +00:00
default : return ErrorNumber . NotSupported ;
}
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
switch ( alcTrack . subMode )
{
case SubchannelMode . None :
sectorSkip + = 0 ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
break ;
case SubchannelMode . Interleaved :
if ( tag ! = SectorTagType . CdSectorSubchannel )
sectorSkip + = 96 ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
break ;
default : return ErrorNumber . NotSupported ;
2016-08-09 15:33:41 +01:00
}
2022-03-06 13:29:38 +00:00
buffer = new byte [ sectorSize * length ] ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
if ( alcTrack . point = = 1 & &
alcExtra . pregap > 150 )
2016-08-09 15:33:41 +01:00
{
2022-03-06 13:29:38 +00:00
if ( sectorAddress + 150 < alcExtra . pregap )
return ErrorNumber . NoError ;
2021-09-20 14:22:22 +01:00
2022-03-06 13:29:38 +00:00
sectorAddress - = alcExtra . pregap - 150 ;
}
2017-12-21 06:06:19 +00:00
2022-03-06 13:29:38 +00:00
uint pregapBytes = alcExtra . pregap * ( sectorOffset + sectorSize + sectorSkip ) ;
2022-03-07 07:36:44 +00:00
var fileOffset = ( long ) alcTrack . startOffset ;
2021-09-20 14:22:22 +01:00
2022-03-06 13:29:38 +00:00
if ( alcTrack . startOffset > = pregapBytes )
fileOffset = ( long ) ( alcTrack . startOffset - pregapBytes ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
_imageStream = _alcImage . GetDataForkStream ( ) ;
var br = new BinaryReader ( _imageStream ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
br . BaseStream . Seek ( fileOffset + ( long ) ( sectorAddress * ( sectorOffset + sectorSize + sectorSkip ) ) ,
SeekOrigin . Begin ) ;
2021-09-21 02:59:54 +01:00
2022-03-06 13:29:38 +00:00
if ( sectorOffset = = 0 & &
sectorSkip = = 0 )
buffer = br . ReadBytes ( ( int ) ( sectorSize * length ) ) ;
else
2022-03-07 07:36:44 +00:00
for ( var i = 0 ; i < length ; i + + )
2022-03-06 13:29:38 +00:00
{
br . BaseStream . Seek ( sectorOffset , SeekOrigin . Current ) ;
byte [ ] sector = br . ReadBytes ( ( int ) sectorSize ) ;
br . BaseStream . Seek ( sectorSkip , SeekOrigin . Current ) ;
Array . Copy ( sector , 0 , buffer , i * sectorSize , sectorSize ) ;
}
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
return ErrorNumber . NoError ;
}
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public ErrorNumber ReadSectorLong ( ulong sectorAddress , out byte [ ] buffer ) = >
ReadSectorsLong ( sectorAddress , 1 , out buffer ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public ErrorNumber ReadSectorLong ( ulong sectorAddress , uint track , out byte [ ] buffer ) = >
ReadSectorsLong ( sectorAddress , 1 , track , out buffer ) ;
/// <inheritdoc />
public ErrorNumber ReadSectorsLong ( ulong sectorAddress , uint length , out byte [ ] buffer )
{
buffer = null ;
foreach ( KeyValuePair < uint , ulong > kvp in _offsetMap )
if ( sectorAddress > = kvp . Value )
foreach ( Track alcTrack in _alcTracks . Values )
2017-12-19 20:33:03 +00:00
{
2022-03-06 13:29:38 +00:00
if ( alcTrack . point ! = kvp . Key | |
! _alcTrackExtras . TryGetValue ( alcTrack . point , out TrackExtra alcExtra ) )
continue ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( sectorAddress - kvp . Value > = alcExtra . sectors + alcExtra . pregap )
continue ;
return ReadSectorsLong ( sectorAddress - kvp . Value , length , kvp . Key , out buffer ) ;
2017-12-19 20:33:03 +00:00
}
2019-05-11 20:49:32 +01:00
2022-03-06 13:29:38 +00:00
return ErrorNumber . SectorNotFound ;
}
/// <inheritdoc />
public ErrorNumber ReadSectorsLong ( ulong sectorAddress , uint length , uint track , out byte [ ] buffer )
{
buffer = null ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
if ( ! _alcTracks . TryGetValue ( ( int ) track , out Track alcTrack ) | |
! _alcTrackExtras . TryGetValue ( ( int ) track , out TrackExtra alcExtra ) )
return ErrorNumber . SectorNotFound ;
if ( length + sectorAddress > alcExtra . sectors + alcExtra . pregap )
return ErrorNumber . OutOfRange ;
2018-01-08 19:30:49 +00:00
2022-03-06 13:29:38 +00:00
uint sectorOffset ;
uint sectorSize ;
uint sectorSkip ;
2018-01-08 19:30:49 +00:00
2022-03-06 13:29:38 +00:00
switch ( alcTrack . mode )
{
case TrackMode . Mode1 :
case TrackMode . Mode1Alt :
case TrackMode . Mode2 :
case TrackMode . Mode2F1 :
case TrackMode . Mode2F1Alt :
case TrackMode . Mode2F2 :
case TrackMode . Mode2F2Alt :
case TrackMode . Audio :
case TrackMode . AudioAlt :
case TrackMode . DVD :
2021-07-06 18:00:23 +01:00
{
2022-03-06 13:29:38 +00:00
sectorOffset = 0 ;
sectorSize = alcTrack . sectorSize ;
sectorSkip = 0 ;
2021-07-06 18:00:23 +01:00
2022-03-06 13:29:38 +00:00
break ;
2021-07-06 18:00:23 +01:00
}
2022-03-06 13:29:38 +00:00
default : return ErrorNumber . NotSupported ;
}
2021-07-09 03:26:51 +01:00
2022-03-06 13:29:38 +00:00
if ( alcTrack . subMode = = SubchannelMode . Interleaved )
sectorSkip = 96 ;
2021-07-09 03:26:51 +01:00
2022-03-06 13:29:38 +00:00
buffer = new byte [ sectorSize * length ] ;
2018-01-08 19:30:49 +00:00
2022-03-06 13:29:38 +00:00
if ( alcTrack . point = = 1 & &
alcExtra . pregap > 150 )
{
if ( sectorAddress + 150 < alcExtra . pregap )
return ErrorNumber . NoError ;
2018-01-08 19:30:49 +00:00
2022-03-06 13:29:38 +00:00
sectorAddress - = alcExtra . pregap - 150 ;
}
2018-01-08 19:30:49 +00:00
2022-03-17 23:54:41 +00:00
uint pregapBytes = alcExtra . pregap * ( sectorSize + sectorSkip ) ;
2022-03-07 07:36:44 +00:00
var fileOffset = ( long ) alcTrack . startOffset ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
if ( alcTrack . startOffset > = pregapBytes )
fileOffset = ( long ) ( alcTrack . startOffset - pregapBytes ) ;
2016-08-09 15:33:41 +01:00
2022-03-06 13:29:38 +00:00
_imageStream = _alcImage . GetDataForkStream ( ) ;
var br = new BinaryReader ( _imageStream ) ;
2016-08-09 15:33:41 +01:00
2022-03-17 23:54:41 +00:00
br . BaseStream . Seek ( fileOffset + ( long ) ( sectorAddress * ( sectorSize + sectorSkip ) ) ,
2022-03-06 13:29:38 +00:00
SeekOrigin . Begin ) ;
2016-08-09 15:33:41 +01:00
2022-03-17 23:54:41 +00:00
if ( sectorSkip = = 0 )
2022-03-06 13:29:38 +00:00
buffer = br . ReadBytes ( ( int ) ( sectorSize * length ) ) ;
else
2022-03-07 07:36:44 +00:00
for ( var i = 0 ; i < length ; i + + )
2016-08-09 15:33:41 +01:00
{
2022-03-06 13:29:38 +00:00
br . BaseStream . Seek ( sectorOffset , SeekOrigin . Current ) ;
byte [ ] sector = br . ReadBytes ( ( int ) sectorSize ) ;
br . BaseStream . Seek ( sectorSkip , SeekOrigin . Current ) ;
2017-12-22 06:55:04 +00:00
2022-03-06 13:29:38 +00:00
Array . Copy ( sector , 0 , buffer , i * sectorSize , sectorSize ) ;
}
2017-12-22 06:55:04 +00:00
2022-03-06 13:29:38 +00:00
return ErrorNumber . NoError ;
}
2017-12-22 06:55:04 +00:00
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public List < CommonTypes . Structs . Track > GetSessionTracks ( CommonTypes . Structs . Session session ) = >
Sessions . Contains ( session ) ? GetSessionTracks ( session . Sequence ) : null ;
2020-06-17 21:32:19 +01:00
2022-03-06 13:29:38 +00:00
/// <inheritdoc />
public List < CommonTypes . Structs . Track > GetSessionTracks ( ushort session )
{
List < CommonTypes . Structs . Track > tracks = new ( ) ;
2020-06-17 21:32:19 +01:00
2022-03-06 13:29:38 +00:00
foreach ( Track alcTrack in _alcTracks . Values )
{
ushort sessionNo =
( from ses in Sessions where alcTrack . point > = ses . StartTrack | | alcTrack . point < = ses . EndTrack
select ses . Sequence ) . FirstOrDefault ( ) ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
if ( ! _alcTrackExtras . TryGetValue ( alcTrack . point , out TrackExtra alcExtra ) | |
session ! = sessionNo )
continue ;
2020-01-11 22:44:25 +00:00
2022-03-06 13:29:38 +00:00
var aaruTrack = new CommonTypes . Structs . Track
{
StartSector = alcTrack . startLba ,
EndSector = alcExtra . sectors - 1 ,
Pregap = alcExtra . pregap ,
Session = sessionNo ,
Sequence = alcTrack . point ,
Type = TrackModeToTrackType ( alcTrack . mode ) ,
Filter = _alcImage ,
File = _alcImage . Filename ,
FileOffset = alcTrack . startOffset ,
FileType = "BINARY" ,
RawBytesPerSector = alcTrack . sectorSize ,
BytesPerSector = TrackModeToCookedBytesPerSector ( alcTrack . mode )
} ;
if ( alcExtra . pregap > 0 )
aaruTrack . Indexes . Add ( 0 , ( int ) ( alcTrack . startLba - alcExtra . pregap ) ) ;
aaruTrack . Indexes . Add ( 1 , ( int ) alcTrack . startLba ) ;
2017-12-21 06:06:19 +00:00
2022-03-06 13:29:38 +00:00
switch ( alcTrack . subMode )
{
case SubchannelMode . Interleaved :
aaruTrack . SubchannelFilter = _alcImage ;
aaruTrack . SubchannelFile = _alcImage . Filename ;
aaruTrack . SubchannelOffset = alcTrack . startOffset ;
aaruTrack . SubchannelType = TrackSubchannelType . RawInterleaved ;
break ;
case SubchannelMode . None :
aaruTrack . SubchannelType = TrackSubchannelType . None ;
break ;
2016-08-09 15:33:41 +01:00
}
2022-03-06 13:29:38 +00:00
tracks . Add ( aaruTrack ) ;
2016-08-09 15:33:41 +01:00
}
2022-03-06 13:29:38 +00:00
return tracks ;
2016-08-09 15:31:44 +01:00
}
2017-12-19 20:33:03 +00:00
}