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/>.
//
// ----------------------------------------------------------------------------
2020-12-31 23:08:23 +00:00
// Copyright © 2011-2021 Natalia Portillo
2016-08-09 15:31:44 +01:00
// ****************************************************************************/
2016-08-09 15:33:41 +01:00
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.Exceptions ;
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
2020-02-27 00:33:26 +00:00
namespace Aaru.DiscImages
2016-08-09 15:31:44 +01:00
{
2020-07-22 13:20:25 +01:00
public sealed partial class Alcohol120
2016-08-09 15:31:44 +01:00
{
2017-12-28 19:56:36 +00:00
public bool Open ( IFilter imageFilter )
2016-08-09 15:33:41 +01:00
{
2016-09-05 17:37:31 +01:00
Stream stream = imageFilter . GetDataForkStream ( ) ;
2016-08-09 15:33:41 +01:00
stream . Seek ( 0 , SeekOrigin . Begin ) ;
2020-01-11 22:44:25 +00:00
if ( stream . Length < 88 )
return false ;
2016-08-09 15:33:41 +01:00
2020-07-20 21:11:32 +01:00
_isDvd = false ;
2016-08-09 15:33:41 +01:00
byte [ ] hdr = new byte [ 88 ] ;
stream . Read ( hdr , 0 , 88 ) ;
2020-11-11 04:19:18 +00:00
_header = Marshal . ByteArrayToStructureLittleEndian < Header > ( hdr ) ;
2016-08-09 15:33:41 +01:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "header.signature = {0}" ,
2020-07-20 21:11:32 +01:00
Encoding . ASCII . GetString ( _header . signature ) ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "header.version = {0}.{1}" , _header . version [ 0 ] ,
_header . version [ 1 ] ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01: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
2020-07-20 21:11:32 +01:00
for ( int 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
2020-07-20 21:11:32 +01:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "header.bcaLength = {0}" , _header . bcaLength ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01:00
for ( int 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
2020-07-20 21:11:32 +01:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "header.bcaOffset = {0}" , _header . bcaOffset ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01:00
for ( int 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
2020-07-20 21:11:32 +01:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "header.structuresOffset = {0}" ,
_header . structuresOffset ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01:00
for ( int 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
2020-07-20 21:11:32 +01: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
2020-07-20 21:11:32 +01:00
if ( _header . version [ 0 ] > _maximumSupportedVersion )
2020-03-09 21:36:32 +00:00
return false ;
2020-07-20 21:11:32 +01:00
stream . Seek ( _header . sessionOffset , SeekOrigin . Begin ) ;
2020-11-11 04:19:18 +00:00
_alcSessions = new Dictionary < int , Session > ( ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01:00
for ( int i = 0 ; i < _header . sessions ; i + + )
2016-08-09 15:33:41 +01:00
{
byte [ ] sesHdr = new byte [ 24 ] ;
stream . Read ( sesHdr , 0 , 24 ) ;
2020-11-11 04:19:18 +00:00
Session session = Marshal . SpanToStructureLittleEndian < Session > ( sesHdr ) ;
2016-08-09 15:33:41 +01:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{1}].sessionStart = {0}" ,
2020-02-29 18:03:35 +00:00
session . sessionStart , i ) ;
2020-01-11 22:44:25 +00:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{1}].sessionEnd = {0}" , session . sessionEnd ,
2020-02-29 18:03:35 +00:00
i ) ;
2020-01-11 22:44:25 +00:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{1}].sessionSequence = {0}" ,
2020-02-29 18:03:35 +00:00
session . sessionSequence , i ) ;
2020-01-11 22:44:25 +00:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{1}].allBlocks = {0}" , session . allBlocks , i ) ;
2020-01-11 22:44:25 +00:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{1}].nonTrackBlocks = {0}" ,
2020-02-29 18:03:35 +00:00
session . nonTrackBlocks , i ) ;
2020-01-11 22:44:25 +00:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{1}].firstTrack = {0}" , session . firstTrack ,
2020-02-29 18:03:35 +00:00
i ) ;
2020-01-11 22:44:25 +00:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{1}].lastTrack = {0}" , session . lastTrack , i ) ;
2020-02-29 18:03:35 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{1}].unknown = 0x{0:X8}" , session . unknown ,
i ) ;
2020-01-11 22:44:25 +00:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{1}].trackOffset = {0}" , session . trackOffset ,
2020-02-29 18:03:35 +00:00
i ) ;
2016-08-09 15:33:41 +01:00
2020-07-20 21:11:32 +01:00
_alcSessions . Add ( session . sessionSequence , session ) ;
2016-08-09 15:33:41 +01:00
}
2018-07-15 21:19:39 +01:00
long footerOff = 0 ;
bool oldIncorrectImage = false ;
2016-08-09 15:33:41 +01:00
2020-11-11 04:19:18 +00:00
_alcTracks = new Dictionary < int , Track > ( ) ;
_alcToc = new Dictionary < int , Dictionary < int , Track > > ( ) ;
2021-07-07 02:41:40 +01:00
uint track1Index1 = 0 ;
2020-01-11 22:44:25 +00:00
2020-11-11 04:19:18 +00:00
foreach ( Session session in _alcSessions . Values )
2016-08-09 15:33:41 +01:00
{
stream . Seek ( session . trackOffset , SeekOrigin . Begin ) ;
2020-11-11 04:19:18 +00:00
Dictionary < int , Track > sesToc = new Dictionary < int , Track > ( ) ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
for ( int i = 0 ; i < session . allBlocks ; i + + )
{
2017-12-22 06:55:04 +00:00
byte [ ] trkHdr = new byte [ 80 ] ;
2016-08-09 15:33:41 +01:00
stream . Read ( trkHdr , 0 , 80 ) ;
2020-11-11 04:19:18 +00:00
Track track = Marshal . ByteArrayToStructureLittleEndian < Track > ( trkHdr ) ;
2016-08-09 15:33:41 +01:00
2020-11-11 04:19:18 +00:00
if ( track . mode = = TrackMode . Mode2F1Alt | |
track . mode = = TrackMode . Mode2F1Alt )
2018-07-15 21:19:39 +01:00
oldIncorrectImage = true ;
// Solve our own mistake here, sorry, but anyway seems Alcohol doesn't support DDCD
2020-06-16 13:02:03 +01:00
if ( track . zero > 0 & &
track . point > = 1 & &
track . point < = 99 )
2018-07-15 21:19:39 +01:00
{
track . pmin + = ( byte ) ( track . zero * 60 ) ;
track . zero = 0 ;
oldIncorrectImage = true ;
}
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].mode = {0}" , track . mode ,
2020-02-29 18:03:35 +00:00
track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].subMode = {0}" ,
2020-02-29 18:03:35 +00:00
track . subMode , track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].adrCtl = {0}" ,
2020-02-29 18:03:35 +00:00
track . adrCtl , track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].tno = {0}" , track . tno ,
2020-02-29 18:03:35 +00:00
track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].point = {0:X2}" ,
2020-02-29 18:03:35 +00:00
track . point , track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].min = {0}" , track . min ,
2020-02-29 18:03:35 +00:00
track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].sec = {0}" , track . sec ,
2020-02-29 18:03:35 +00:00
track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2020-02-29 18:03:35 +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
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].zero = {0}" , track . zero ,
2020-02-29 18:03:35 +00:00
track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].pmin = {0}" , track . pmin ,
2020-02-29 18:03:35 +00:00
track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].psec = {0}" , track . psec ,
2020-02-29 18:03:35 +00:00
track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].pframe = {0}" ,
2020-02-29 18:03:35 +00:00
track . pframe , track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].extraOffset = {0}" ,
2020-02-29 18:03:35 +00:00
track . extraOffset , track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].sectorSize = {0}" ,
2020-02-29 18:03:35 +00:00
track . sectorSize , track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
//for(int j = 0; j < track.unknown.Length; j++)
2020-02-27 23:48:41 +00:00
// 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}" ,
2020-02-29 18:03:35 +00:00
track . startLba , track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].startOffset = {0}" ,
2020-02-29 18:03:35 +00:00
track . startOffset , track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2020-02-29 18:03:35 +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
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "session[{2}].track[{1}].footerOffset = {0}" ,
2020-02-29 18:03:35 +00:00
track . footerOffset , track . point , session . sessionSequence ) ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
//for(int j = 0; j < track.unknown2.Length; j++)
2020-02-27 23:48:41 +00:00
// AaruConsole.DebugWriteLine("Alcohol 120% plugin", "session[{2}].track[{1}].unknown2[{2}] = {0}", track.unknown2[j], i, j, session.sessionSequence);
2016-08-09 15:33:41 +01:00
2020-11-11 04:19:18 +00:00
if ( track . subMode = = SubchannelMode . Interleaved )
2020-01-11 22:44:25 +00:00
track . sectorSize - = 96 ;
2018-01-08 19:30:49 +00:00
2021-07-06 18:00:23 +01: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-07 02:41:40 +01:00
track1Index1 = track . startLba ;
2021-07-06 18:00:23 +01:00
track . startLba = 0 ;
}
2020-01-11 22:44:25 +00:00
if ( ! sesToc . ContainsKey ( track . point ) )
sesToc . Add ( track . point , track ) ;
2016-08-09 15:33:41 +01:00
2020-01-11 22:44:25 +00:00
if ( track . point < 0xA0 )
2020-07-20 21:11:32 +01:00
_alcTracks . Add ( track . point , track ) ;
2016-08-09 15:33:41 +01:00
2020-01-11 22:44:25 +00:00
if ( footerOff = = 0 )
footerOff = track . footerOffset ;
2016-08-09 15:33:41 +01:00
2020-11-11 04:19:18 +00:00
_isDvd | = track . mode = = TrackMode . DVD ;
2016-08-09 15:33:41 +01:00
}
2017-12-19 20:33:03 +00:00
2020-07-20 21:11:32 +01:00
_alcToc . Add ( session . sessionSequence , sesToc ) ;
2016-08-09 15:33:41 +01:00
}
2020-11-11 04:19:18 +00:00
_alcTrackExtras = new Dictionary < int , TrackExtra > ( ) ;
2020-01-11 22:44:25 +00:00
2020-11-11 04:19:18 +00:00
foreach ( Track track in _alcTracks . Values )
2020-01-11 22:44:25 +00:00
if ( track . extraOffset > 0 & &
2020-07-20 21:11:32 +01:00
! _isDvd )
2016-08-09 15:33:41 +01:00
{
byte [ ] extHdr = new byte [ 8 ] ;
stream . Seek ( track . extraOffset , SeekOrigin . Begin ) ;
stream . Read ( extHdr , 0 , 8 ) ;
2020-11-11 04:19:18 +00:00
TrackExtra extra = Marshal . SpanToStructureLittleEndian < TrackExtra > ( extHdr ) ;
2016-08-09 15:33:41 +01:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "track[{1}].extra.pregap = {0}" , extra . pregap ,
2020-02-29 18:03:35 +00:00
track . point ) ;
2020-01-11 22:44:25 +00:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "track[{1}].extra.sectors = {0}" , extra . sectors ,
2020-02-29 18:03:35 +00:00
track . point ) ;
2016-08-09 15:33:41 +01:00
2021-07-06 18:00:23 +01:00
if ( track . point = = 1 )
2021-07-07 02:41:40 +01:00
{
extra . pregap = track1Index1 + 150 ; // Needed because faulty UltraISO implementation
2021-07-06 18:00:23 +01:00
extra . sectors + = extra . pregap - 150 ;
2021-07-07 02:41:40 +01:00
}
2021-07-06 18:00:23 +01:00
2020-07-20 21:11:32 +01:00
_alcTrackExtras . Add ( track . point , extra ) ;
2016-08-09 15:33:41 +01:00
}
2020-07-20 21:11:32 +01:00
else if ( _isDvd )
2016-08-09 15:33:41 +01:00
{
2020-11-11 04:19:18 +00:00
var extra = new TrackExtra
2020-01-11 22:44:25 +00:00
{
sectors = track . extraOffset
} ;
2020-07-20 21:11:32 +01:00
_alcTrackExtras . Add ( track . point , extra ) ;
2016-08-09 15:33:41 +01:00
}
if ( footerOff > 0 )
{
byte [ ] footer = new byte [ 16 ] ;
stream . Seek ( footerOff , SeekOrigin . Begin ) ;
stream . Read ( footer , 0 , 16 ) ;
2020-11-11 04:19:18 +00:00
_alcFooter = Marshal . SpanToStructureLittleEndian < Footer > ( footer ) ;
2016-08-09 15:33:41 +01:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "footer.filenameOffset = {0}" ,
2020-07-20 21:11:32 +01:00
_alcFooter . filenameOffset ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01: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 15:33:41 +01:00
}
2016-09-05 17:37:31 +01:00
string alcFile = "*.mdf" ;
2020-07-20 21:11:32 +01:00
if ( _alcFooter . filenameOffset > 0 )
2016-08-09 15:33:41 +01:00
{
2020-07-20 21:11:32 +01:00
stream . Seek ( _alcFooter . filenameOffset , SeekOrigin . Begin ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01:00
byte [ ] filename = _header . dpmOffset = = 0 ? new byte [ stream . Length - stream . Position ]
: new byte [ _header . dpmOffset - stream . Position ] ;
2016-08-09 17:12:17 +01:00
2016-08-09 15:33:41 +01:00
stream . Read ( filename , 0 , filename . Length ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01:00
alcFile = _alcFooter . widechar = = 1 ? Encoding . Unicode . GetString ( filename )
2017-12-24 00:12:31 +00:00
: Encoding . Default . GetString ( filename ) ;
2016-08-09 15:33:41 +01:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "footer.filename = {0}" , alcFile ) ;
2016-08-09 15:33:41 +01:00
}
2020-07-20 21:11:32 +01:00
if ( _alcFooter . filenameOffset = = 0 | |
2017-12-19 20:33:03 +00:00
string . Compare ( alcFile , "*.mdf" , StringComparison . InvariantCultureIgnoreCase ) = = 0 )
2016-09-05 17:37:31 +01:00
alcFile = Path . GetFileNameWithoutExtension ( imageFilter . GetBasePath ( ) ) + ".mdf" ;
2016-08-09 17:12:17 +01:00
2020-07-20 21:11:32 +01:00
if ( _header . bcaLength > 0 & &
_header . bcaOffset > 0 & &
_isDvd )
2016-08-09 15:33:41 +01:00
{
2020-07-20 21:11:32 +01:00
_bca = new byte [ _header . bcaLength ] ;
stream . Seek ( _header . bcaOffset , SeekOrigin . Begin ) ;
int readBytes = stream . Read ( _bca , 0 , _bca . Length ) ;
2016-08-09 15:33:41 +01:00
2020-07-20 21:11:32 +01:00
if ( readBytes = = _bca . Length )
switch ( _header . type )
2016-08-09 15:33:41 +01:00
{
2020-11-11 04:19:18 +00:00
case MediumType . DVD :
case MediumType . DVDR :
2020-07-20 21:11:32 +01:00
_imageInfo . ReadableMediaTags . Add ( MediaTagType . DVD_BCA ) ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
}
}
2020-11-11 04:19:18 +00:00
_imageInfo . MediaType = MediumTypeToMediaType ( _header . type ) ;
2016-08-09 15:33:41 +01:00
2020-11-11 04:19:18 +00:00
Sessions = new List < CommonTypes . Structs . Session > ( ) ;
2020-01-11 22:44:25 +00:00
2020-11-11 04:19:18 +00:00
foreach ( Session alcSes in _alcSessions . Values )
2018-06-20 22:50:50 +01:00
{
2020-11-11 04:19:18 +00:00
var session = new CommonTypes . Structs . Session ( ) ;
2018-06-20 22:50:50 +01:00
2020-11-11 04:19:18 +00:00
if ( ! _alcTracks . TryGetValue ( alcSes . firstTrack , out Track startingTrack ) )
2020-01-11 22:44:25 +00:00
break ;
2020-11-11 04:19:18 +00:00
if ( ! _alcTracks . TryGetValue ( alcSes . lastTrack , out Track endingTrack ) )
2020-01-11 22:44:25 +00:00
break ;
2020-11-11 04:19:18 +00:00
if ( ! _alcTrackExtras . TryGetValue ( alcSes . lastTrack , out TrackExtra endingTrackExtra ) )
2020-01-11 22:44:25 +00:00
break ;
2018-06-20 22:50:50 +01:00
session . StartSector = startingTrack . startLba ;
session . StartTrack = alcSes . firstTrack ;
session . SessionSequence = alcSes . sessionSequence ;
2020-11-20 19:29:04 +00:00
session . EndSector = endingTrack . startLba + endingTrackExtra . sectors - 1 ;
2018-06-20 22:50:50 +01:00
session . EndTrack = alcSes . lastTrack ;
Sessions . Add ( session ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01:00
if ( session . EndSector > _imageInfo . Sectors )
_imageInfo . Sectors = session . EndSector + 1 ;
2018-06-20 22:50:50 +01:00
}
2020-07-20 21:11:32 +01:00
if ( _isDvd )
2016-08-09 15:33:41 +01:00
{
// TODO: Second layer
2020-07-20 21:11:32 +01:00
if ( _header . structuresOffset > 0 )
2016-08-09 15:33:41 +01:00
{
byte [ ] structures = new byte [ 4100 ] ;
2020-07-20 21:11:32 +01:00
stream . Seek ( _header . structuresOffset , SeekOrigin . Begin ) ;
2016-08-09 15:33:41 +01:00
stream . Read ( structures , 0 , 4100 ) ;
2020-07-20 21:11:32 +01:00
_dmi = new byte [ 2052 ] ;
_pfi = new byte [ 2052 ] ;
2016-08-09 15:33:41 +01:00
2020-03-11 14:01:01 +00:00
// TODO: CMI
2020-07-20 21:11:32 +01:00
Array . Copy ( structures , 4 , _dmi , 4 , 2048 ) ;
Array . Copy ( structures , 0x804 , _pfi , 4 , 2048 ) ;
2016-08-09 15:33:41 +01:00
2020-07-20 21:11:32 +01:00
_pfi [ 0 ] = 0x08 ;
_pfi [ 1 ] = 0x02 ;
_dmi [ 0 ] = 0x08 ;
_dmi [ 1 ] = 0x02 ;
2016-08-09 15:33:41 +01:00
2021-06-23 14:48:22 +01:00
PFI . PhysicalFormatInformation ? pfi0 = PFI . Decode ( _pfi , _imageInfo . MediaType ) ;
2016-08-09 15:33:41 +01:00
// 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 )
{
switch ( pfi0 . Value . DiskCategory )
{
2017-12-21 14:30:38 +00:00
case DiskCategory . DVDPR :
2020-07-20 21:11:32 +01:00
_imageInfo . MediaType = MediaType . DVDPR ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
2017-12-21 14:30:38 +00:00
case DiskCategory . DVDPRDL :
2020-07-20 21:11:32 +01:00
_imageInfo . MediaType = MediaType . DVDPRDL ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
2017-12-21 14:30:38 +00:00
case DiskCategory . DVDPRW :
2020-07-20 21:11:32 +01:00
_imageInfo . MediaType = MediaType . DVDPRW ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
2017-12-21 14:30:38 +00:00
case DiskCategory . DVDPRWDL :
2020-07-20 21:11:32 +01:00
_imageInfo . MediaType = MediaType . DVDPRWDL ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
2017-12-21 14:30:38 +00:00
case DiskCategory . DVDR :
2020-11-01 18:02:29 +00:00
_imageInfo . MediaType = pfi0 . Value . PartVersion > = 6 ? MediaType . DVDRDL : MediaType . DVDR ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
2017-12-21 14:30:38 +00:00
case DiskCategory . DVDRAM :
2020-07-20 21:11:32 +01:00
_imageInfo . MediaType = MediaType . DVDRAM ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
default :
2020-07-20 21:11:32 +01:00
_imageInfo . MediaType = MediaType . DVDROM ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
2017-12-21 14:30:38 +00:00
case DiskCategory . DVDRW :
2020-07-20 21:11:32 +01:00
_imageInfo . MediaType =
2020-11-20 19:29:04 +00:00
pfi0 . Value . PartVersion > = 15 ? MediaType . DVDRWDL : MediaType . DVDRW ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
2017-12-21 14:30:38 +00:00
case DiskCategory . HDDVDR :
2020-07-20 21:11:32 +01:00
_imageInfo . MediaType = MediaType . HDDVDR ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
2017-12-21 14:30:38 +00:00
case DiskCategory . HDDVDRAM :
2020-07-20 21:11:32 +01:00
_imageInfo . MediaType = MediaType . HDDVDRAM ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
2017-12-21 14:30:38 +00:00
case DiskCategory . HDDVDROM :
2020-07-20 21:11:32 +01:00
_imageInfo . MediaType = MediaType . HDDVDROM ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
2017-12-21 14:30:38 +00:00
case DiskCategory . HDDVDRW :
2020-07-20 21:11:32 +01:00
_imageInfo . MediaType = MediaType . HDDVDRW ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
2017-12-21 14:30:38 +00:00
case DiskCategory . Nintendo :
2020-07-20 21:11:32 +01:00
_imageInfo . MediaType =
2017-12-24 00:12:31 +00:00
pfi0 . Value . DiscSize = = DVDSize . Eighty ? MediaType . GOD : MediaType . WOD ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
2017-12-21 14:30:38 +00:00
case DiskCategory . UMD :
2020-07-20 21:11:32 +01:00
_imageInfo . MediaType = MediaType . UMD ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
}
2020-07-20 21:11:32 +01: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
2020-03-11 14:01:01 +00:00
byte [ ] tmp = new byte [ 2048 ] ;
2020-07-20 21:11:32 +01:00
Array . Copy ( _dmi , 4 , tmp , 0 , 2048 ) ;
_dmi = tmp ;
tmp = new byte [ 2048 ] ;
Array . Copy ( _pfi , 4 , tmp , 0 , 2048 ) ;
_pfi = tmp ;
_imageInfo . ReadableMediaTags . Add ( MediaTagType . DVD_PFI ) ;
_imageInfo . ReadableMediaTags . Add ( MediaTagType . DVD_DMI ) ;
2016-08-09 15:33:41 +01:00
}
}
}
2020-11-11 04:19:18 +00:00
else if ( _header . type = = MediumType . CD )
2016-08-09 15:33:41 +01:00
{
2018-01-08 19:30:49 +00:00
bool data = false ;
bool mode2 = false ;
2020-11-11 04:19:18 +00:00
bool firstAudio = false ;
bool firstData = false ;
2018-01-08 19:30:49 +00:00
bool audio = false ;
2016-08-09 15:33:41 +01:00
2020-11-11 04:19:18 +00:00
foreach ( Track alcoholTrack in _alcTracks . Values )
2016-08-09 15:33:41 +01:00
{
// First track is audio
2020-11-11 04:19:18 +00:00
firstAudio | = alcoholTrack . point = = 1 & & alcoholTrack . mode = = TrackMode . Audio ;
2016-08-09 15:33:41 +01:00
// First track is data
2020-11-11 04:19:18 +00:00
firstData | = alcoholTrack . point = = 1 & & alcoholTrack . mode ! = TrackMode . Audio ;
2016-08-09 15:33:41 +01:00
// Any non first track is data
2020-11-11 04:19:18 +00:00
data | = alcoholTrack . point ! = 1 & & alcoholTrack . mode ! = TrackMode . Audio ;
2016-08-09 15:33:41 +01:00
// Any non first track is audio
2020-11-11 04:19:18 +00:00
audio | = alcoholTrack . point ! = 1 & & alcoholTrack . mode = = TrackMode . Audio ;
2016-08-09 15:33:41 +01:00
2017-12-22 06:55:04 +00:00
switch ( alcoholTrack . mode )
2016-08-09 15:33:41 +01:00
{
2020-11-11 04:19:18 +00:00
case TrackMode . Mode2 :
case TrackMode . Mode2F1 :
case TrackMode . Mode2F2 :
case TrackMode . Mode2F1Alt :
case TrackMode . Mode2F2Alt :
2016-08-09 15:33:41 +01:00
mode2 = true ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
}
}
2020-01-11 22:44:25 +00:00
if ( ! data & &
2020-11-11 04:19:18 +00:00
! firstData )
2020-07-20 21:11:32 +01:00
_imageInfo . MediaType = MediaType . CDDA ;
2020-11-11 04:19:18 +00:00
else if ( firstAudio & &
2020-01-11 22:44:25 +00:00
data & &
Sessions . Count > 1 & &
mode2 )
2020-07-20 21:11:32 +01:00
_imageInfo . MediaType = MediaType . CDPLUS ;
2020-11-11 04:19:18 +00:00
else if ( ( firstData & & audio ) | | mode2 )
2020-07-20 21:11:32 +01:00
_imageInfo . MediaType = MediaType . CDROMXA ;
2020-01-11 22:44:25 +00:00
else if ( ! audio )
2020-07-20 21:11:32 +01:00
_imageInfo . MediaType = MediaType . CDROM ;
2020-01-11 22:44:25 +00:00
else
2020-07-20 21:11:32 +01:00
_imageInfo . MediaType = MediaType . CD ;
2016-08-09 15:33:41 +01:00
}
2020-07-20 21:11:32 +01:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "ImageInfo.mediaType = {0}" , _imageInfo . MediaType ) ;
2016-08-09 15:33:41 +01:00
2018-06-22 08:08:38 +01:00
Partitions = new List < Partition > ( ) ;
2020-11-11 04:19:18 +00:00
_offsetMap = new Dictionary < uint , ulong > ( ) ;
2017-12-22 06:55:04 +00:00
ulong byteOffset = 0 ;
2016-08-09 15:33:41 +01:00
2020-11-11 04:19:18 +00:00
foreach ( Track trk in _alcTracks . Values )
2016-08-09 15:33:41 +01:00
{
2020-11-11 04:19:18 +00:00
if ( _alcTrackExtras . TryGetValue ( trk . point , out TrackExtra extra ) )
2016-08-09 15:33:41 +01:00
{
2020-01-11 22:44:25 +00:00
var partition = new Partition
2017-12-22 06:55:04 +00:00
{
2020-07-20 04:34:16 +01:00
Description = $"Track {trk.point}." ,
Start = trk . startLba ,
Size = extra . sectors * trk . sectorSize ,
Length = extra . sectors ,
Sequence = trk . point ,
Offset = byteOffset ,
Type = trk . mode . ToString ( )
2017-12-22 06:55:04 +00:00
} ;
2016-08-09 15:33:41 +01:00
2018-01-08 19:30:49 +00:00
Partitions . Add ( partition ) ;
2018-07-28 14:13:14 +01:00
byteOffset + = partition . Size ;
2016-08-09 15:33:41 +01:00
}
2020-11-11 04:19:18 +00:00
if ( ! _offsetMap . ContainsKey ( trk . point ) )
_offsetMap . Add ( trk . point , trk . startLba ) ;
2016-08-09 15:33:41 +01:00
switch ( trk . mode )
{
2020-11-11 04:19:18 +00:00
case TrackMode . Mode1 :
case TrackMode . Mode2F1 :
case TrackMode . Mode2F1Alt :
2020-07-20 21:11:32 +01:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorSync ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorSync ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorHeader ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorHeader ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorSubHeader ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorSubHeader ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorEcc ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorEcc ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorEccP ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorEccP ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorEccQ ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorEccQ ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorEdc ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorEdc ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01:00
if ( _imageInfo . SectorSize < 2048 )
_imageInfo . SectorSize = 2048 ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
2020-11-11 04:19:18 +00:00
case TrackMode . Mode2 :
2020-07-20 21:11:32 +01:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorSync ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorSync ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorHeader ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorHeader ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorSubHeader ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorSubHeader ) ;
2020-06-21 22:30:07 +01:00
2020-07-20 21:11:32 +01:00
if ( _imageInfo . SectorSize < 2336 )
_imageInfo . SectorSize = 2336 ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
2020-11-11 04:19:18 +00:00
case TrackMode . Mode2F2 :
case TrackMode . Mode2F2Alt :
2020-07-20 21:11:32 +01:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorSync ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorSync ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorHeader ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorHeader ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorSubHeader ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorSubHeader ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01:00
if ( ! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorEdc ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorEdc ) ;
2020-01-11 22:44:25 +00:00
2020-07-20 21:11:32 +01:00
if ( _imageInfo . SectorSize < 2324 )
_imageInfo . SectorSize = 2324 ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
2020-11-11 04:19:18 +00:00
case TrackMode . DVD :
2020-07-20 21:11:32 +01:00
_imageInfo . SectorSize = 2048 ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
default :
2020-07-20 21:11:32 +01:00
_imageInfo . SectorSize = 2352 ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
}
2018-01-08 19:30:49 +00:00
2020-11-11 04:19:18 +00:00
if ( trk . subMode ! = SubchannelMode . None & &
2020-07-20 21:11:32 +01:00
! _imageInfo . ReadableSectorTags . Contains ( SectorTagType . CdSectorSubchannel ) )
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdSectorSubchannel ) ;
2016-08-09 15:33:41 +01:00
}
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "printing partition map" ) ;
2020-01-11 22:44:25 +00:00
2018-01-08 19:30:49 +00:00
foreach ( Partition partition in Partitions )
2016-08-09 15:33:41 +01:00
{
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "Partition sequence: {0}" , partition . Sequence ) ;
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "\tPartition name: {0}" , partition . Name ) ;
2020-02-29 18:03:35 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "\tPartition description: {0}" ,
partition . Description ) ;
2020-02-27 23:48:41 +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
}
2020-07-20 21:11:32 +01:00
_imageInfo . Application = "Alcohol 120%" ;
2016-08-09 15:33:41 +01:00
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "Data filename: {0}" , alcFile ) ;
2016-09-05 17:37:31 +01:00
2020-01-11 22:44:25 +00:00
var filtersList = new FiltersList ( ) ;
2020-07-20 21:11:32 +01:00
_alcImage = filtersList . GetFilter ( alcFile ) ;
2016-09-05 17:37:31 +01:00
2020-07-20 21:11:32 +01:00
if ( _alcImage = = null )
2020-01-11 22:44:25 +00:00
throw new Exception ( "Cannot open data file" ) ;
2016-08-09 15:33:41 +01:00
2020-07-20 21:11:32 +01:00
_imageInfo . ImageSize = ( ulong ) _alcImage . GetDataForkLength ( ) ;
_imageInfo . CreationTime = _alcImage . GetCreationTime ( ) ;
_imageInfo . LastModificationTime = _alcImage . GetLastWriteTime ( ) ;
_imageInfo . XmlMediaType = XmlMediaType . OpticalDisc ;
_imageInfo . Version = $"{_header.version[0]}.{_header.version[1]}" ;
2016-08-09 15:33:41 +01:00
2020-07-20 21:11:32 +01:00
if ( ! _isDvd )
2016-08-09 15:33:41 +01:00
{
2020-02-27 23:48:41 +00:00
AaruConsole . DebugWriteLine ( "Alcohol 120% plugin" , "Rebuilding TOC" ) ;
2020-01-11 22:44:25 +00:00
byte firstSession = byte . MaxValue ;
byte lastSession = 0 ;
var tocMs = new MemoryStream ( ) ;
tocMs . Write ( new byte [ ]
{
2020-03-11 14:01:01 +00:00
0 , 0
} , 0 , 2 ) ; // Reserved for TOC session numbers
2020-01-11 22:44:25 +00:00
2020-11-11 04:19:18 +00:00
foreach ( KeyValuePair < int , Dictionary < int , Track > > sessionToc in _alcToc )
2016-08-09 15:33:41 +01:00
{
2020-01-11 22:44:25 +00:00
if ( sessionToc . Key < firstSession )
firstSession = ( byte ) sessionToc . Key ;
if ( sessionToc . Key > lastSession )
lastSession = ( byte ) sessionToc . Key ;
2016-08-09 15:33:41 +01:00
2020-11-11 04:19:18 +00:00
foreach ( Track sessionTrack in sessionToc . Value . Values )
2016-08-09 15:33:41 +01:00
{
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
2020-07-20 21:11:32 +01:00
_fullToc = tocMs . ToArray ( ) ;
_fullToc [ 0 ] = firstSession ;
_fullToc [ 1 ] = lastSession ;
2016-08-09 15:33:41 +01:00
2020-07-20 21:11:32 +01:00
_imageInfo . ReadableMediaTags . Add ( MediaTagType . CD_FullTOC ) ;
_imageInfo . ReadableSectorTags . Add ( SectorTagType . CdTrackFlags ) ;
2016-08-09 15:33:41 +01:00
}
2020-07-20 21:11:32 +01:00
if ( _imageInfo . MediaType = = MediaType . XGD2 )
if ( _imageInfo . Sectors = = 25063 | | // Locked (or non compatible drive)
_imageInfo . Sectors = = 4229664 | | // Xtreme unlock
_imageInfo . Sectors = = 4246304 ) // Wxripper unlock
_imageInfo . MediaType = MediaType . XGD3 ;
2017-05-23 19:25:17 +01:00
2020-07-20 21:11:32 +01:00
AaruConsole . VerboseWriteLine ( "Alcohol 120% image describes a disc of type {0}" , _imageInfo . MediaType ) ;
2016-08-21 17:35:35 +01:00
2018-07-15 21:19:39 +01:00
if ( oldIncorrectImage )
2020-02-29 18:03:35 +00:00
AaruConsole .
WriteLine ( "Incorrect Alcohol 120% image created by an old version of Aaru. Convert image to correct it." ) ;
2018-07-15 21:19:39 +01:00
2016-08-09 15:33:41 +01:00
return true ;
}
2017-12-26 07:28:40 +00:00
public byte [ ] ReadDiskTag ( MediaTagType tag )
2016-08-09 15:33:41 +01:00
{
switch ( tag )
{
case MediaTagType . DVD_BCA :
2017-12-19 20:33:03 +00:00
{
2020-07-20 21:11:32 +01:00
if ( _bca ! = null )
return ( byte [ ] ) _bca . Clone ( ) ;
2017-12-19 20:33:03 +00:00
throw new FeatureNotPresentImageException ( "Image does not contain BCA information." ) ;
}
2019-05-11 20:49:32 +01:00
2016-08-09 17:12:17 +01:00
case MediaTagType . DVD_PFI :
2017-12-19 20:33:03 +00:00
{
2020-07-20 21:11:32 +01:00
if ( _pfi ! = null )
return ( byte [ ] ) _pfi . Clone ( ) ;
2017-12-19 20:33:03 +00:00
throw new FeatureNotPresentImageException ( "Image does not contain PFI." ) ;
}
2019-05-11 20:49:32 +01:00
2016-08-09 17:12:17 +01:00
case MediaTagType . DVD_DMI :
2017-12-19 20:33:03 +00:00
{
2020-07-20 21:11:32 +01:00
if ( _dmi ! = null )
return ( byte [ ] ) _dmi . Clone ( ) ;
2017-12-19 20:33:03 +00:00
throw new FeatureNotPresentImageException ( "Image does not contain DMI." ) ;
}
2019-05-11 20:49:32 +01:00
2016-08-09 15:33:41 +01:00
case MediaTagType . CD_FullTOC :
2017-12-19 20:33:03 +00:00
{
2020-07-20 21:11:32 +01:00
if ( _fullToc ! = null )
return ( byte [ ] ) _fullToc . Clone ( ) ;
2017-12-19 20:33:03 +00:00
throw new FeatureNotPresentImageException ( "Image does not contain TOC information." ) ;
}
2019-05-11 20:49:32 +01:00
2016-08-09 15:33:41 +01:00
default :
throw new FeatureSupportedButNotImplementedImageException ( "Feature not supported by image format" ) ;
}
}
2019-01-20 22:24:15 +00:00
public byte [ ] ReadSector ( ulong sectorAddress ) = > ReadSectors ( sectorAddress , 1 ) ;
2016-08-09 15:33:41 +01:00
2019-01-20 22:24:15 +00:00
public byte [ ] ReadSectorTag ( ulong sectorAddress , SectorTagType tag ) = > ReadSectorsTag ( sectorAddress , 1 , tag ) ;
2016-08-09 15:33:41 +01:00
2019-01-20 22:24:15 +00:00
public byte [ ] ReadSector ( ulong sectorAddress , uint track ) = > ReadSectors ( sectorAddress , 1 , track ) ;
2016-08-09 15:33:41 +01:00
2019-01-20 22:24:15 +00:00
public byte [ ] ReadSectorTag ( ulong sectorAddress , uint track , SectorTagType tag ) = >
ReadSectorsTag ( sectorAddress , 1 , track , tag ) ;
2016-08-09 15:33:41 +01:00
2017-12-26 07:28:40 +00:00
public byte [ ] ReadSectors ( ulong sectorAddress , uint length )
2016-08-09 15:33:41 +01:00
{
2020-11-11 04:19:18 +00:00
foreach ( KeyValuePair < uint , ulong > kvp in _offsetMap )
2016-08-09 15:33:41 +01:00
if ( sectorAddress > = kvp . Value )
2020-11-11 04:19:18 +00:00
foreach ( Track track in _alcTracks . Values )
2016-08-09 15:33:41 +01:00
{
2017-12-24 00:12:31 +00:00
if ( track . point ! = kvp . Key | |
2020-11-11 04:19:18 +00:00
! _alcTrackExtras . TryGetValue ( track . point , out TrackExtra extra ) )
2020-01-11 22:44:25 +00:00
continue ;
2017-12-21 06:06:19 +00:00
2018-06-22 08:08:38 +01:00
if ( sectorAddress - kvp . Value < extra . sectors )
2017-12-21 06:06:19 +00:00
return ReadSectors ( sectorAddress - kvp . Value , length , kvp . Key ) ;
2016-08-09 15:33:41 +01:00
}
throw new ArgumentOutOfRangeException ( nameof ( sectorAddress ) , "Sector address not found" ) ;
}
2017-12-26 07:28:40 +00:00
public byte [ ] ReadSectorsTag ( ulong sectorAddress , uint length , SectorTagType tag )
2016-08-09 15:33:41 +01:00
{
2020-11-11 04:19:18 +00:00
foreach ( KeyValuePair < uint , ulong > kvp in _offsetMap )
2016-08-09 15:33:41 +01:00
if ( sectorAddress > = kvp . Value )
2020-11-11 04:19:18 +00:00
foreach ( Track track in _alcTracks . Values )
2016-08-09 15:33:41 +01:00
{
2017-12-24 00:12:31 +00:00
if ( track . point ! = kvp . Key | |
2020-11-11 04:19:18 +00:00
! _alcTrackExtras . TryGetValue ( track . point , out TrackExtra extra ) )
2020-01-11 22:44:25 +00:00
continue ;
2017-12-21 06:06:19 +00:00
2018-06-22 08:08:38 +01:00
if ( sectorAddress - kvp . Value < extra . sectors )
2017-12-21 06:06:19 +00:00
return ReadSectorsTag ( sectorAddress - kvp . Value , length , kvp . Key , tag ) ;
2016-08-09 15:33:41 +01:00
}
throw new ArgumentOutOfRangeException ( nameof ( sectorAddress ) , "Sector address not found" ) ;
}
2017-12-26 07:28:40 +00:00
public byte [ ] ReadSectors ( ulong sectorAddress , uint length , uint track )
2016-08-09 15:33:41 +01:00
{
2020-11-11 04:19:18 +00:00
if ( ! _alcTracks . TryGetValue ( ( int ) track , out Track alcTrack ) | |
! _alcTrackExtras . TryGetValue ( ( int ) track , out TrackExtra alcExtra ) )
2016-08-09 15:33:41 +01:00
throw new ArgumentOutOfRangeException ( nameof ( track ) , "Track does not exist in disc image" ) ;
2017-12-22 06:55:04 +00:00
if ( length + sectorAddress > alcExtra . sectors )
2017-12-19 20:33:03 +00:00
throw new ArgumentOutOfRangeException ( nameof ( length ) ,
2017-12-22 06:55:04 +00:00
$"Requested more sectors ({length + sectorAddress}) than present in track ({alcExtra.sectors}), won't cross tracks" ) ;
2016-08-09 15:33:41 +01:00
2017-12-22 06:55:04 +00:00
uint sectorOffset ;
uint sectorSize ;
uint sectorSkip ;
2020-01-11 22:44:25 +00:00
bool mode2 = false ;
2016-08-09 15:33:41 +01:00
2017-12-22 06:55:04 +00:00
switch ( alcTrack . mode )
2016-08-09 15:33:41 +01:00
{
2020-11-11 04:19:18 +00:00
case TrackMode . Mode1 :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
sectorOffset = 16 ;
2018-01-08 19:30:49 +00:00
sectorSize = 2048 ;
sectorSkip = 288 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2020-11-11 04:19:18 +00:00
case TrackMode . Mode2 :
case TrackMode . Mode2F1 :
case TrackMode . Mode2F1Alt :
case TrackMode . Mode2F2 :
case TrackMode . Mode2F2Alt :
2017-12-19 20:33:03 +00:00
{
2020-01-12 01:00:26 +00:00
mode2 = true ;
sectorOffset = 0 ;
sectorSize = 2352 ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2020-11-11 04:19:18 +00:00
case TrackMode . Audio :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
sectorOffset = 0 ;
2018-01-08 19:30:49 +00:00
sectorSize = 2352 ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2020-11-11 04:19:18 +00:00
case TrackMode . DVD :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
sectorOffset = 0 ;
2018-01-08 19:30:49 +00:00
sectorSize = 2048 ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-19 20:33:03 +00:00
default : throw new FeatureSupportedButNotImplementedImageException ( "Unsupported track type" ) ;
2016-08-09 15:33:41 +01:00
}
2017-12-22 06:55:04 +00:00
switch ( alcTrack . subMode )
2016-08-09 15:33:41 +01:00
{
2020-11-11 04:19:18 +00:00
case SubchannelMode . None :
2017-12-22 06:55:04 +00:00
sectorSkip + = 0 ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
2020-11-11 04:19:18 +00:00
case SubchannelMode . Interleaved :
2017-12-22 06:55:04 +00:00
sectorSkip + = 96 ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
2017-12-19 20:33:03 +00:00
default : throw new FeatureSupportedButNotImplementedImageException ( "Unsupported subchannel type" ) ;
2016-08-09 15:33:41 +01:00
}
2017-12-22 06:55:04 +00:00
byte [ ] buffer = new byte [ sectorSize * length ] ;
2016-08-09 15:33:41 +01:00
2021-07-06 18:00:23 +01:00
if ( alcTrack . point = = 1 & &
alcExtra . pregap > 150 )
{
if ( sectorAddress + 150 < alcExtra . pregap )
return buffer ;
sectorAddress - = alcExtra . pregap - 150 ;
}
2020-07-20 21:11:32 +01:00
_imageStream = _alcImage . GetDataForkStream ( ) ;
var br = new BinaryReader ( _imageStream ) ;
2020-01-11 22:44:25 +00:00
br . BaseStream .
Seek ( ( long ) alcTrack . startOffset + ( long ) ( sectorAddress * ( sectorOffset + sectorSize + sectorSkip ) ) ,
2017-12-19 20:33:03 +00:00
SeekOrigin . Begin ) ;
2020-01-11 22:44:25 +00:00
if ( mode2 )
{
var mode2Ms = new MemoryStream ( ( int ) ( sectorSize * length ) ) ;
2020-01-12 01:00:26 +00:00
buffer = br . ReadBytes ( ( int ) ( ( sectorSize + sectorSkip ) * length ) ) ;
2020-01-11 22:44:25 +00:00
for ( int i = 0 ; i < length ; i + + )
{
byte [ ] sector = new byte [ sectorSize ] ;
2020-01-12 01:00:26 +00:00
Array . Copy ( buffer , ( sectorSize + sectorSkip ) * i , sector , 0 , sectorSize ) ;
2020-01-11 22:44:25 +00:00
sector = Sector . GetUserDataFromMode2 ( sector ) ;
mode2Ms . Write ( sector , 0 , sector . Length ) ;
}
buffer = mode2Ms . ToArray ( ) ;
}
else if ( sectorOffset = = 0 & &
sectorSkip = = 0 )
buffer = br . ReadBytes ( ( int ) ( sectorSize * length ) ) ;
2016-09-05 17:37:31 +01:00
else
for ( int i = 0 ; i < length ; i + + )
2016-08-09 15:33:41 +01:00
{
2017-12-22 06:55:04 +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
}
return buffer ;
}
2017-12-26 07:28:40 +00:00
public byte [ ] ReadSectorsTag ( ulong sectorAddress , uint length , uint track , SectorTagType tag )
2016-08-09 15:33:41 +01:00
{
2020-06-14 23:45:26 +01:00
if ( tag = = SectorTagType . CdTrackFlags )
track = ( uint ) sectorAddress ;
2020-11-11 04:19:18 +00:00
if ( ! _alcTracks . TryGetValue ( ( int ) track , out Track alcTrack ) | |
! _alcTrackExtras . TryGetValue ( ( int ) track , out TrackExtra alcExtra ) )
2016-08-09 15:33:41 +01:00
throw new ArgumentOutOfRangeException ( nameof ( track ) , "Track does not exist in disc image" ) ;
2017-12-22 06:55:04 +00:00
if ( length + sectorAddress > alcExtra . sectors )
2017-12-19 20:33:03 +00:00
throw new ArgumentOutOfRangeException ( nameof ( length ) ,
2017-12-22 06:55:04 +00:00
$"Requested more sectors ({length}) than present in track ({alcExtra.sectors}), won't cross tracks" ) ;
2016-08-09 15:33:41 +01:00
2017-12-22 06:55:04 +00:00
uint sectorOffset ;
uint sectorSize ;
uint sectorSkip ;
2016-08-09 15:33:41 +01:00
2020-11-11 04:19:18 +00:00
if ( alcTrack . mode = = TrackMode . DVD )
2016-08-09 15:33:41 +01:00
throw new ArgumentException ( "Unsupported tag requested" , nameof ( tag ) ) ;
switch ( tag )
{
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorEcc :
case SectorTagType . CdSectorEccP :
case SectorTagType . CdSectorEccQ :
case SectorTagType . CdSectorEdc :
case SectorTagType . CdSectorHeader :
case SectorTagType . CdSectorSubchannel :
case SectorTagType . CdSectorSubHeader :
case SectorTagType . CdSectorSync : break ;
2020-01-11 22:44:25 +00:00
case SectorTagType . CdTrackFlags :
return new [ ]
{
( byte ) ( alcTrack . adrCtl & 0x0F )
} ;
default : throw new ArgumentException ( "Unsupported tag requested" , nameof ( tag ) ) ;
2016-08-09 15:33:41 +01:00
}
2017-12-22 06:55:04 +00:00
switch ( alcTrack . mode )
2016-08-09 15:33:41 +01:00
{
2020-11-11 04:19:18 +00:00
case TrackMode . Mode1 :
2017-12-19 20:33:03 +00:00
switch ( tag )
2016-08-09 15:33:41 +01:00
{
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorSync :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
sectorOffset = 0 ;
2018-01-08 19:30:49 +00:00
sectorSize = 12 ;
sectorSkip = 2340 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorHeader :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
sectorOffset = 12 ;
2018-01-08 19:30:49 +00:00
sectorSize = 4 ;
sectorSkip = 2336 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorSubHeader :
2016-08-09 15:33:41 +01: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-22 06:55:04 +00:00
sectorOffset = 2076 ;
2018-01-08 19:30:49 +00:00
sectorSize = 276 ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorEccP :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
sectorOffset = 2076 ;
2018-01-08 19:30:49 +00:00
sectorSize = 172 ;
sectorSkip = 104 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorEccQ :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
sectorOffset = 2248 ;
2018-01-08 19:30:49 +00:00
sectorSize = 104 ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorEdc :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
sectorOffset = 2064 ;
2018-01-08 19:30:49 +00:00
sectorSize = 4 ;
sectorSkip = 284 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorSubchannel :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
switch ( alcTrack . subMode )
2016-08-09 15:33:41 +01:00
{
2020-11-11 04:19:18 +00:00
case SubchannelMode . Interleaved :
2017-12-19 20:33:03 +00:00
2017-12-22 06:55:04 +00:00
sectorOffset = 2352 ;
2018-01-08 19:30:49 +00:00
sectorSize = 96 ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
default : throw new ArgumentException ( "Unsupported tag requested" , nameof ( tag ) ) ;
2016-08-09 15:33:41 +01:00
}
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-19 20:33:03 +00:00
default : throw new ArgumentException ( "Unsupported tag requested" , nameof ( tag ) ) ;
2016-08-09 15:33:41 +01:00
}
2017-12-19 20:33:03 +00:00
2016-08-09 15:33:41 +01:00
break ;
2020-11-11 04:19:18 +00:00
case TrackMode . Mode2 :
2017-12-19 20:33:03 +00:00
{
switch ( tag )
2016-08-09 15:33:41 +01:00
{
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorSync :
case SectorTagType . CdSectorHeader :
case SectorTagType . CdSectorEcc :
case SectorTagType . CdSectorEccP :
case SectorTagType . CdSectorEccQ :
2017-12-19 20:33:03 +00:00
throw new ArgumentException ( "Unsupported tag requested for this track" , nameof ( tag ) ) ;
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorSubHeader :
2016-08-09 15:33:41 +01:00
{
2017-12-22 06:55:04 +00:00
sectorOffset = 0 ;
2018-01-08 19:30:49 +00:00
sectorSize = 8 ;
sectorSkip = 2328 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorEdc :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
sectorOffset = 2332 ;
2018-01-08 19:30:49 +00:00
sectorSize = 4 ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorSubchannel :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
switch ( alcTrack . subMode )
2017-12-19 20:33:03 +00:00
{
2020-11-11 04:19:18 +00:00
case SubchannelMode . Interleaved :
2017-12-19 20:33:03 +00:00
2017-12-22 06:55:04 +00:00
sectorOffset = 2352 ;
2018-01-08 19:30:49 +00:00
sectorSize = 96 ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
2017-12-19 20:33:03 +00:00
default : throw new ArgumentException ( "Unsupported tag requested" , nameof ( tag ) ) ;
}
break ;
2016-08-09 15:33:41 +01:00
}
2019-05-11 20:49:32 +01:00
2017-12-19 20:33:03 +00:00
default : throw new ArgumentException ( "Unsupported tag requested" , nameof ( tag ) ) ;
2016-08-09 15:33:41 +01:00
}
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2020-11-11 04:19:18 +00:00
case TrackMode . Mode2F1 :
case TrackMode . Mode2F1Alt :
2017-12-19 20:33:03 +00:00
switch ( tag )
2016-08-09 15:33:41 +01:00
{
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorSync :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
sectorOffset = 0 ;
2018-01-08 19:30:49 +00:00
sectorSize = 12 ;
sectorSkip = 2340 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorHeader :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
sectorOffset = 12 ;
2018-01-08 19:30:49 +00:00
sectorSize = 4 ;
sectorSkip = 2336 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorSubHeader :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
sectorOffset = 16 ;
2018-01-08 19:30:49 +00:00
sectorSize = 8 ;
sectorSkip = 2328 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorEcc :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
sectorOffset = 2076 ;
2018-01-08 19:30:49 +00:00
sectorSize = 276 ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorEccP :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
sectorOffset = 2076 ;
2018-01-08 19:30:49 +00:00
sectorSize = 172 ;
sectorSkip = 104 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorEccQ :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
sectorOffset = 2248 ;
2018-01-08 19:30:49 +00:00
sectorSize = 104 ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorEdc :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
sectorOffset = 2072 ;
2018-01-08 19:30:49 +00:00
sectorSize = 4 ;
sectorSkip = 276 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorSubchannel :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
switch ( alcTrack . subMode )
2016-08-09 15:33:41 +01:00
{
2020-11-11 04:19:18 +00:00
case SubchannelMode . Interleaved :
2017-12-19 20:33:03 +00:00
2017-12-22 06:55:04 +00:00
sectorOffset = 2352 ;
2018-01-08 19:30:49 +00:00
sectorSize = 96 ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
default : throw new ArgumentException ( "Unsupported tag requested" , nameof ( tag ) ) ;
2016-08-09 15:33:41 +01:00
}
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-19 20:33:03 +00:00
default : throw new ArgumentException ( "Unsupported tag requested" , nameof ( tag ) ) ;
2016-08-09 15:33:41 +01:00
}
2017-12-19 20:33:03 +00:00
2016-08-09 15:33:41 +01:00
break ;
2020-11-11 04:19:18 +00:00
case TrackMode . Mode2F2 :
case TrackMode . Mode2F2Alt :
2016-08-09 15:33:41 +01:00
switch ( tag )
{
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorSync :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
sectorOffset = 0 ;
2018-01-08 19:30:49 +00:00
sectorSize = 12 ;
sectorSkip = 2340 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorHeader :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
sectorOffset = 12 ;
2018-01-08 19:30:49 +00:00
sectorSize = 4 ;
sectorSkip = 2336 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorSubHeader :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
sectorOffset = 16 ;
2018-01-08 19:30:49 +00:00
sectorSize = 8 ;
sectorSkip = 2328 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorEdc :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
sectorOffset = 2348 ;
2018-01-08 19:30:49 +00:00
sectorSize = 4 ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorSubchannel :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
switch ( alcTrack . subMode )
2016-08-09 15:33:41 +01:00
{
2020-11-11 04:19:18 +00:00
case SubchannelMode . Interleaved :
2017-12-19 20:33:03 +00:00
2017-12-22 06:55:04 +00:00
sectorOffset = 2352 ;
2018-01-08 19:30:49 +00:00
sectorSize = 96 ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
default : throw new ArgumentException ( "Unsupported tag requested" , nameof ( tag ) ) ;
2016-08-09 15:33:41 +01:00
}
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-19 20:33:03 +00:00
default : throw new ArgumentException ( "Unsupported tag requested" , nameof ( tag ) ) ;
2016-08-09 15:33:41 +01:00
}
2017-12-19 20:33:03 +00:00
2016-08-09 15:33:41 +01:00
break ;
2020-11-11 04:19:18 +00:00
case TrackMode . Audio :
2017-12-19 20:33:03 +00:00
{
switch ( tag )
2016-08-09 15:33:41 +01:00
{
2017-12-20 17:15:26 +00:00
case SectorTagType . CdSectorSubchannel :
2016-08-09 15:33:41 +01:00
{
2017-12-22 06:55:04 +00:00
switch ( alcTrack . subMode )
2017-12-19 20:33:03 +00:00
{
2020-11-11 04:19:18 +00:00
case SubchannelMode . Interleaved :
2017-12-19 20:33:03 +00:00
2017-12-22 06:55:04 +00:00
sectorOffset = 2352 ;
2018-01-08 19:30:49 +00:00
sectorSize = 96 ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
2017-12-19 20:33:03 +00:00
default : throw new ArgumentException ( "Unsupported tag requested" , nameof ( tag ) ) ;
}
break ;
2016-08-09 15:33:41 +01:00
}
2019-05-11 20:49:32 +01:00
2017-12-19 20:33:03 +00:00
default : throw new ArgumentException ( "Unsupported tag requested" , nameof ( tag ) ) ;
2016-08-09 15:33:41 +01:00
}
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-19 20:33:03 +00:00
default : throw new FeatureSupportedButNotImplementedImageException ( "Unsupported track type" ) ;
2016-08-09 15:33:41 +01:00
}
2017-12-22 06:55:04 +00:00
switch ( alcTrack . subMode )
2016-08-09 15:33:41 +01:00
{
2020-11-11 04:19:18 +00:00
case SubchannelMode . None :
2017-12-22 06:55:04 +00:00
sectorSkip + = 0 ;
2020-01-11 22:44:25 +00:00
2016-08-09 15:33:41 +01:00
break ;
2020-11-11 04:19:18 +00:00
case SubchannelMode . Interleaved :
2020-01-11 22:44:25 +00:00
if ( tag ! = SectorTagType . CdSectorSubchannel )
sectorSkip + = 96 ;
2016-08-09 15:33:41 +01:00
break ;
2017-12-19 20:33:03 +00:00
default : throw new FeatureSupportedButNotImplementedImageException ( "Unsupported subchannel type" ) ;
2016-08-09 15:33:41 +01:00
}
2017-12-22 06:55:04 +00:00
byte [ ] buffer = new byte [ sectorSize * length ] ;
2016-08-09 15:33:41 +01:00
2021-07-06 18:00:23 +01:00
if ( alcTrack . point = = 1 & &
alcExtra . pregap > 150 )
{
if ( sectorAddress + 150 < alcExtra . pregap )
return buffer ;
sectorAddress - = alcExtra . pregap - 150 ;
}
2020-07-20 21:11:32 +01:00
_imageStream = _alcImage . GetDataForkStream ( ) ;
var br = new BinaryReader ( _imageStream ) ;
2020-01-11 22:44:25 +00:00
br . BaseStream .
Seek ( ( long ) alcTrack . startOffset + ( long ) ( sectorAddress * ( sectorOffset + sectorSize + sectorSkip ) ) ,
2017-12-19 20:33:03 +00:00
SeekOrigin . Begin ) ;
2020-01-11 22:44:25 +00:00
if ( sectorOffset = = 0 & &
sectorSkip = = 0 )
buffer = br . ReadBytes ( ( int ) ( sectorSize * length ) ) ;
2016-09-05 17:37:31 +01:00
else
for ( int i = 0 ; i < length ; i + + )
2016-08-09 15:33:41 +01:00
{
2017-12-22 06:55:04 +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
}
return buffer ;
}
2019-01-20 22:24:15 +00:00
public byte [ ] ReadSectorLong ( ulong sectorAddress ) = > ReadSectorsLong ( sectorAddress , 1 ) ;
2016-08-09 15:33:41 +01:00
2019-01-20 22:24:15 +00:00
public byte [ ] ReadSectorLong ( ulong sectorAddress , uint track ) = > ReadSectorsLong ( sectorAddress , 1 , track ) ;
2016-08-09 15:33:41 +01:00
2017-12-26 07:28:40 +00:00
public byte [ ] ReadSectorsLong ( ulong sectorAddress , uint length )
2016-08-09 15:33:41 +01:00
{
2020-11-11 04:19:18 +00:00
foreach ( KeyValuePair < uint , ulong > kvp in _offsetMap )
2016-08-09 15:33:41 +01:00
if ( sectorAddress > = kvp . Value )
2020-11-11 04:19:18 +00:00
foreach ( Track alcTrack in _alcTracks . Values )
2016-08-09 15:33:41 +01:00
{
2017-12-24 00:12:31 +00:00
if ( alcTrack . point ! = kvp . Key | |
2020-11-11 04:19:18 +00:00
! _alcTrackExtras . TryGetValue ( alcTrack . point , out TrackExtra alcExtra ) )
2020-01-11 22:44:25 +00:00
continue ;
2017-12-21 06:06:19 +00:00
2018-06-22 08:08:38 +01:00
if ( sectorAddress - kvp . Value < alcExtra . sectors )
2017-12-21 06:06:19 +00:00
return ReadSectorsLong ( sectorAddress - kvp . Value , length , kvp . Key ) ;
2016-08-09 15:33:41 +01:00
}
throw new ArgumentOutOfRangeException ( nameof ( sectorAddress ) , "Sector address not found" ) ;
}
2017-12-26 07:28:40 +00:00
public byte [ ] ReadSectorsLong ( ulong sectorAddress , uint length , uint track )
2016-08-09 15:33:41 +01:00
{
2020-11-11 04:19:18 +00:00
if ( ! _alcTracks . TryGetValue ( ( int ) track , out Track alcTrack ) | |
! _alcTrackExtras . TryGetValue ( ( int ) track , out TrackExtra alcExtra ) )
2016-08-09 15:33:41 +01:00
throw new ArgumentOutOfRangeException ( nameof ( track ) , "Track does not exist in disc image" ) ;
2017-12-22 06:55:04 +00:00
if ( length + sectorAddress > alcExtra . sectors )
2017-12-19 20:33:03 +00:00
throw new ArgumentOutOfRangeException ( nameof ( length ) ,
2017-12-22 06:55:04 +00:00
$"Requested more sectors ({length}) than present in track ({alcExtra.sectors}), won't cross tracks" ) ;
2016-08-09 15:33:41 +01:00
2017-12-22 06:55:04 +00:00
uint sectorOffset ;
uint sectorSize ;
uint sectorSkip ;
2016-08-09 15:33:41 +01:00
2017-12-22 06:55:04 +00:00
switch ( alcTrack . mode )
2016-08-09 15:33:41 +01:00
{
2020-11-11 04:19:18 +00:00
case TrackMode . Mode1 :
case TrackMode . Mode2 :
case TrackMode . Mode2F1 :
case TrackMode . Mode2F1Alt :
case TrackMode . Mode2F2 :
case TrackMode . Mode2F2Alt :
case TrackMode . Audio :
case TrackMode . DVD :
2017-12-19 20:33:03 +00:00
{
2017-12-22 06:55:04 +00:00
sectorOffset = 0 ;
2018-01-08 19:30:49 +00:00
sectorSize = alcTrack . sectorSize ;
sectorSkip = 0 ;
2020-01-11 22:44:25 +00:00
2017-12-19 20:33:03 +00:00
break ;
}
2019-05-11 20:49:32 +01:00
2017-12-19 20:33:03 +00:00
default : throw new FeatureSupportedButNotImplementedImageException ( "Unsupported track type" ) ;
2016-08-09 15:33:41 +01:00
}
2020-11-11 04:19:18 +00:00
if ( alcTrack . subMode = = SubchannelMode . Interleaved )
2020-01-11 22:44:25 +00:00
sectorSkip = 96 ;
2018-01-08 19:30:49 +00:00
byte [ ] buffer = new byte [ sectorSize * length ] ;
2021-07-06 18:00:23 +01:00
if ( alcTrack . point = = 1 & &
alcExtra . pregap > 150 )
{
if ( sectorAddress + 150 < alcExtra . pregap )
return buffer ;
sectorAddress - = alcExtra . pregap - 150 ;
}
2020-07-20 21:11:32 +01:00
_imageStream = _alcImage . GetDataForkStream ( ) ;
var br = new BinaryReader ( _imageStream ) ;
2018-01-08 19:30:49 +00:00
2020-01-11 22:44:25 +00:00
br . BaseStream .
Seek ( ( long ) alcTrack . startOffset + ( long ) ( sectorAddress * ( sectorOffset + sectorSize + sectorSkip ) ) ,
2017-12-19 20:33:03 +00:00
SeekOrigin . Begin ) ;
2018-01-08 19:30:49 +00:00
2020-01-11 22:44:25 +00:00
if ( sectorOffset = = 0 & &
sectorSkip = = 0 )
buffer = br . ReadBytes ( ( int ) ( sectorSize * length ) ) ;
2018-01-08 19:30:49 +00:00
else
for ( int i = 0 ; i < length ; i + + )
{
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
return buffer ;
}
2020-11-11 04:19:18 +00:00
public List < CommonTypes . Structs . Track > GetSessionTracks ( CommonTypes . Structs . Session session )
2016-08-09 15:33:41 +01:00
{
2020-01-11 22:44:25 +00:00
if ( Sessions . Contains ( session ) )
return GetSessionTracks ( session . SessionSequence ) ;
2017-12-19 20:33:03 +00:00
2016-08-09 15:33:41 +01:00
throw new ImageNotSupportedException ( "Session does not exist in disc image" ) ;
}
2020-11-11 04:19:18 +00:00
public List < CommonTypes . Structs . Track > GetSessionTracks ( ushort session )
2016-08-09 15:33:41 +01:00
{
2020-11-11 04:19:18 +00:00
List < CommonTypes . Structs . Track > tracks = new List < CommonTypes . Structs . Track > ( ) ;
2016-08-09 15:33:41 +01:00
2020-11-11 04:19:18 +00:00
foreach ( Track alcTrack in _alcTracks . Values )
2016-08-09 15:33:41 +01:00
{
2017-12-24 00:12:31 +00:00
ushort sessionNo =
2020-01-11 22:44:25 +00:00
( from ses in Sessions where alcTrack . point > = ses . StartTrack | | alcTrack . point < = ses . EndTrack
2017-12-24 00:12:31 +00:00
select ses . SessionSequence ) . FirstOrDefault ( ) ;
2017-12-22 06:55:04 +00:00
2020-11-11 04:19:18 +00:00
if ( ! _alcTrackExtras . TryGetValue ( alcTrack . point , out TrackExtra alcExtra ) | |
2020-01-11 22:44:25 +00:00
session ! = sessionNo )
continue ;
2017-12-22 06:55:04 +00:00
2020-11-11 04:19:18 +00:00
var aaruTrack = new CommonTypes . Structs . Track
2017-12-22 06:55:04 +00:00
{
2020-07-20 04:34:16 +01:00
TrackStartSector = alcTrack . startLba ,
TrackEndSector = alcExtra . sectors - 1 ,
TrackPregap = alcExtra . pregap ,
TrackSession = sessionNo ,
TrackSequence = alcTrack . point ,
2020-11-11 04:19:18 +00:00
TrackType = TrackModeToTrackType ( alcTrack . mode ) ,
2020-07-20 21:11:32 +01:00
TrackFilter = _alcImage ,
TrackFile = _alcImage . GetFilename ( ) ,
2020-07-20 04:34:16 +01:00
TrackFileOffset = alcTrack . startOffset ,
TrackFileType = "BINARY" ,
TrackRawBytesPerSector = alcTrack . sectorSize ,
2020-11-11 04:19:18 +00:00
TrackBytesPerSector = TrackModeToCookedBytesPerSector ( alcTrack . mode )
2017-12-22 06:55:04 +00:00
} ;
2020-06-17 21:32:19 +01:00
if ( alcExtra . pregap > 0 )
aaruTrack . Indexes . Add ( 0 , ( int ) ( alcTrack . startLba - alcExtra . pregap ) ) ;
aaruTrack . Indexes . Add ( 1 , ( int ) alcTrack . startLba ) ;
2017-12-22 06:55:04 +00:00
switch ( alcTrack . subMode )
2016-08-09 15:33:41 +01:00
{
2020-11-11 04:19:18 +00:00
case SubchannelMode . Interleaved :
2020-07-20 21:11:32 +01:00
aaruTrack . TrackSubchannelFilter = _alcImage ;
aaruTrack . TrackSubchannelFile = _alcImage . GetFilename ( ) ;
2020-02-28 00:19:50 +00:00
aaruTrack . TrackSubchannelOffset = alcTrack . startOffset ;
aaruTrack . TrackSubchannelType = TrackSubchannelType . RawInterleaved ;
2020-01-11 22:44:25 +00:00
2017-12-21 06:06:19 +00:00
break ;
2020-11-11 04:19:18 +00:00
case SubchannelMode . None :
2020-02-28 00:19:50 +00:00
aaruTrack . TrackSubchannelType = TrackSubchannelType . None ;
2020-01-11 22:44:25 +00:00
2017-12-21 06:06:19 +00:00
break ;
2016-08-09 15:33:41 +01:00
}
2017-12-21 06:06:19 +00:00
2020-02-28 00:19:50 +00:00
tracks . Add ( aaruTrack ) ;
2016-08-09 15:33:41 +01:00
}
return tracks ;
}
2016-08-09 15:31:44 +01:00
}
2017-12-19 20:33:03 +00:00
}