2017-07-19 16:31:08 +01:00
// /***************************************************************************
2016-07-28 18:13:49 +01:00
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
2017-10-08 20:41:54 +01:00
// Filename : Info.cs
2016-07-28 18:13:49 +01:00
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
2017-10-08 20:41:54 +01:00
// Component : Component
2016-07-28 18:13:49 +01:00
//
// --[ Description ] ----------------------------------------------------------
//
2017-10-08 20:41:54 +01:00
// Description
2016-07-28 18:13:49 +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/>.
//
// ----------------------------------------------------------------------------
2017-05-19 20:28:49 +01:00
// Copyright © 2011-2017 Natalia Portillo
2016-07-28 18:13:49 +01:00
// ****************************************************************************/
2011-03-03 18:34:33 +00:00
using System ;
2017-10-09 11:25:47 +01:00
using System.Collections.Generic ;
2017-10-08 20:28:56 +01:00
using System.Runtime.InteropServices ;
2014-04-14 02:29:13 +00:00
using System.Text ;
2017-07-19 16:31:08 +01:00
using DiscImageChef.CommonTypes ;
2015-10-18 22:04:03 +01:00
using DiscImageChef.Console ;
2017-10-08 20:41:54 +01:00
namespace DiscImageChef.Filesystems.ISO9660
2011-03-03 18:34:33 +00:00
{
2017-10-08 20:41:54 +01:00
public partial class ISO9660 : Filesystem
2011-03-03 18:34:33 +00:00
{
2017-07-19 16:31:08 +01:00
public override bool Identify ( ImagePlugins . ImagePlugin imagePlugin , Partition partition )
2011-03-03 18:34:33 +00:00
{
2014-04-14 02:29:13 +00:00
byte VDType ;
2012-08-03 05:43:58 +00:00
2014-04-14 01:14:20 +00:00
// ISO9660 is designed for 2048 bytes/sector devices
2016-04-19 02:11:47 +01:00
if ( imagePlugin . GetSectorSize ( ) < 2048 )
2014-04-14 01:14:20 +00:00
return false ;
// ISO9660 Primary Volume Descriptor starts at sector 16, so that's minimal size.
2017-07-19 16:37:11 +01:00
if ( partition . End < = ( 16 + partition . Start ) )
2011-03-03 18:34:33 +00:00
return false ;
2014-04-14 01:14:20 +00:00
// Read to Volume Descriptor
2017-07-19 16:37:11 +01:00
byte [ ] vd_sector = imagePlugin . ReadSector ( 16 + partition . Start ) ;
2014-04-14 01:14:20 +00:00
2015-12-06 07:51:46 +00:00
int xa_off = 0 ;
2016-04-19 02:11:47 +01:00
if ( vd_sector . Length = = 2336 )
2015-12-06 07:51:46 +00:00
xa_off = 8 ;
VDType = vd_sector [ 0 + xa_off ] ;
2014-04-14 02:29:13 +00:00
byte [ ] VDMagic = new byte [ 5 ] ;
2017-10-08 22:47:09 +01:00
byte [ ] HSMagic = new byte [ 5 ] ;
2011-03-03 18:34:33 +00:00
2017-10-08 22:47:09 +01:00
// This indicates the end of a volume descriptor. HighSierra here would have 16 so no problem
if ( VDType = = 255 )
2016-04-19 02:11:47 +01:00
return false ;
2011-03-03 18:34:33 +00:00
2015-12-06 07:51:46 +00:00
Array . Copy ( vd_sector , 0x001 + xa_off , VDMagic , 0 , 5 ) ;
2017-10-08 22:47:09 +01:00
Array . Copy ( vd_sector , 0x009 + xa_off , HSMagic , 0 , 5 ) ;
2015-12-06 07:51:46 +00:00
2017-06-06 21:23:20 +01:00
DicConsole . DebugWriteLine ( "ISO9660 plugin" , "VDMagic = {0}" , CurrentEncoding . GetString ( VDMagic ) ) ;
2017-10-08 22:47:09 +01:00
DicConsole . DebugWriteLine ( "ISO9660 plugin" , "HSMagic = {0}" , CurrentEncoding . GetString ( HSMagic ) ) ;
2011-03-03 18:34:33 +00:00
2017-10-08 22:47:09 +01:00
return CurrentEncoding . GetString ( VDMagic ) = = IsoMagic | | CurrentEncoding . GetString ( HSMagic ) = = HighSierraMagic ;
2014-04-14 02:29:13 +00:00
}
2016-04-19 02:11:47 +01:00
2017-07-19 16:31:08 +01:00
public override void GetInformation ( ImagePlugins . ImagePlugin imagePlugin , Partition partition , out string information )
2016-04-19 02:11:47 +01:00
{
2011-03-03 18:34:33 +00:00
information = "" ;
StringBuilder ISOMetadata = new StringBuilder ( ) ;
bool RockRidge = false ;
byte VDType ; // Volume Descriptor Type, should be 1 or 2.
byte [ ] VDMagic = new byte [ 5 ] ; // Volume Descriptor magic "CD001"
2017-10-08 22:47:09 +01:00
byte [ ] HSMagic = new byte [ 5 ] ; // Volume Descriptor magic "CDROM"
2017-10-08 20:28:56 +01:00
2011-03-03 18:34:33 +00:00
string BootSpec = "" ;
byte [ ] VDPathTableStart = new byte [ 4 ] ;
byte [ ] RootDirectoryLocation = new byte [ 4 ] ;
2017-10-08 20:28:56 +01:00
PrimaryVolumeDescriptor ? pvd = null ;
PrimaryVolumeDescriptor ? jolietvd = null ;
BootRecord ? bvd = null ;
2017-10-08 22:47:09 +01:00
HighSierraPrimaryVolumeDescriptor ? hsvd = null ;
2017-10-09 00:32:17 +01:00
ElToritoBootRecord ? torito = null ;
2017-10-08 20:28:56 +01:00
2014-04-14 01:14:20 +00:00
// ISO9660 is designed for 2048 bytes/sector devices
2016-04-19 02:11:47 +01:00
if ( imagePlugin . GetSectorSize ( ) < 2048 )
2014-04-14 01:14:20 +00:00
return ;
2011-03-03 18:34:33 +00:00
2014-04-14 01:14:20 +00:00
// ISO9660 Primary Volume Descriptor starts at sector 16, so that's minimal size.
2017-07-19 16:37:11 +01:00
if ( partition . End < 16 )
2011-03-03 18:34:33 +00:00
return ;
2014-04-14 01:14:20 +00:00
ulong counter = 0 ;
2011-03-03 18:34:33 +00:00
2017-10-08 22:47:09 +01:00
byte [ ] vd_sector = imagePlugin . ReadSector ( 16 + counter + partition . Start ) ;
int xa_off = imagePlugin . GetSectorSize ( ) = = 2336 ? 8 : 0 ;
Array . Copy ( vd_sector , 0x009 + xa_off , HSMagic , 0 , 5 ) ;
bool HighSierra = CurrentEncoding . GetString ( HSMagic ) = = HighSierraMagic ;
int hs_off = 0 ;
if ( HighSierra )
hs_off = 8 ;
2016-04-19 02:11:47 +01:00
while ( true )
2011-03-03 18:34:33 +00:00
{
2015-10-18 22:04:03 +01:00
DicConsole . DebugWriteLine ( "ISO9660 plugin" , "Processing VD loop no. {0}" , counter ) ;
2011-03-03 18:34:33 +00:00
// Seek to Volume Descriptor
2017-07-19 16:37:11 +01:00
DicConsole . DebugWriteLine ( "ISO9660 plugin" , "Reading sector {0}" , 16 + counter + partition . Start ) ;
byte [ ] vd_sector_tmp = imagePlugin . ReadSector ( 16 + counter + partition . Start ) ;
2017-10-08 22:47:09 +01:00
vd_sector = new byte [ vd_sector_tmp . Length - xa_off ] ;
Array . Copy ( vd_sector_tmp , xa_off , vd_sector , 0 , vd_sector . Length ) ;
2011-03-03 18:34:33 +00:00
2017-10-08 22:47:09 +01:00
VDType = vd_sector [ 0 + hs_off ] ;
2015-10-18 22:04:03 +01:00
DicConsole . DebugWriteLine ( "ISO9660 plugin" , "VDType = {0}" , VDType ) ;
2011-03-03 18:34:33 +00:00
2016-04-19 02:11:47 +01:00
if ( VDType = = 255 ) // Supposedly we are in the PVD.
2011-03-03 18:34:33 +00:00
{
2016-04-19 02:11:47 +01:00
if ( counter = = 0 )
2011-03-03 18:34:33 +00:00
return ;
break ;
}
2014-04-14 01:14:20 +00:00
Array . Copy ( vd_sector , 0x001 , VDMagic , 0 , 5 ) ;
2017-10-08 22:47:09 +01:00
Array . Copy ( vd_sector , 0x009 , HSMagic , 0 , 5 ) ;
2011-03-03 18:34:33 +00:00
2017-10-08 22:47:09 +01:00
if ( CurrentEncoding . GetString ( VDMagic ) ! = IsoMagic & & CurrentEncoding . GetString ( HSMagic ) ! = HighSierraMagic ) // Recognized, it is an ISO9660, now check for rest of data.
2011-03-03 18:34:33 +00:00
{
2016-04-19 02:11:47 +01:00
if ( counter = = 0 )
2011-03-03 18:34:33 +00:00
return ;
break ;
}
switch ( VDType )
{
2017-10-09 00:32:17 +01:00
case 0 :
2011-03-03 18:34:33 +00:00
{
2017-10-08 20:28:56 +01:00
bvd = new BootRecord ( ) ;
IntPtr ptr = Marshal . AllocHGlobal ( 2048 ) ;
2017-10-08 22:47:09 +01:00
Marshal . Copy ( vd_sector , hs_off , ptr , 2048 - hs_off ) ;
2017-10-08 20:28:56 +01:00
bvd = ( BootRecord ) Marshal . PtrToStructure ( ptr , typeof ( BootRecord ) ) ;
Marshal . FreeHGlobal ( ptr ) ;
2011-03-03 18:34:33 +00:00
2017-10-08 20:28:56 +01:00
BootSpec = "Unknown" ;
2011-03-03 18:34:33 +00:00
2017-10-08 20:28:56 +01:00
if ( CurrentEncoding . GetString ( bvd . Value . system_id ) . Substring ( 0 , 23 ) = = "EL TORITO SPECIFICATION" )
2017-10-09 00:32:17 +01:00
{
2011-03-03 18:34:33 +00:00
BootSpec = "El Torito" ;
2017-10-09 00:32:17 +01:00
torito = new ElToritoBootRecord ( ) ;
ptr = Marshal . AllocHGlobal ( 2048 ) ;
Marshal . Copy ( vd_sector , hs_off , ptr , 2048 - hs_off ) ;
torito = ( ElToritoBootRecord ) Marshal . PtrToStructure ( ptr , typeof ( ElToritoBootRecord ) ) ;
Marshal . FreeHGlobal ( ptr ) ;
}
2011-03-03 18:34:33 +00:00
break ;
}
case 1 :
{
2017-10-08 22:47:09 +01:00
if ( HighSierra )
{
hsvd = new HighSierraPrimaryVolumeDescriptor ( ) ;
IntPtr ptr = Marshal . AllocHGlobal ( 2048 ) ;
Marshal . Copy ( vd_sector , 0 , ptr , 2048 ) ;
hsvd = ( HighSierraPrimaryVolumeDescriptor ) Marshal . PtrToStructure ( ptr , typeof ( HighSierraPrimaryVolumeDescriptor ) ) ;
Marshal . FreeHGlobal ( ptr ) ;
}
else
{
pvd = new PrimaryVolumeDescriptor ( ) ;
IntPtr ptr = Marshal . AllocHGlobal ( 2048 ) ;
Marshal . Copy ( vd_sector , 0 , ptr , 2048 ) ;
pvd = ( PrimaryVolumeDescriptor ) Marshal . PtrToStructure ( ptr , typeof ( PrimaryVolumeDescriptor ) ) ;
Marshal . FreeHGlobal ( ptr ) ;
}
2011-03-03 18:34:33 +00:00
break ;
}
case 2 :
{
2017-10-08 20:28:56 +01:00
PrimaryVolumeDescriptor svd = new PrimaryVolumeDescriptor ( ) ;
IntPtr ptr = Marshal . AllocHGlobal ( 2048 ) ;
Marshal . Copy ( vd_sector , 0 , ptr , 2048 ) ;
svd = ( PrimaryVolumeDescriptor ) Marshal . PtrToStructure ( ptr , typeof ( PrimaryVolumeDescriptor ) ) ;
Marshal . FreeHGlobal ( ptr ) ;
2011-03-03 18:34:33 +00:00
// Check if this is Joliet
2017-10-08 20:28:56 +01:00
if ( svd . escape_sequences [ 0 ] = = '%' & & svd . escape_sequences [ 1 ] = = '/' )
2011-03-03 18:34:33 +00:00
{
2017-10-08 20:28:56 +01:00
if ( svd . escape_sequences [ 2 ] = = '@' | | svd . escape_sequences [ 2 ] = = 'C' | | svd . escape_sequences [ 2 ] = = 'E' )
2011-03-03 18:34:33 +00:00
{
2017-10-08 20:28:56 +01:00
jolietvd = svd ;
2011-03-03 18:34:33 +00:00
}
else
{
break ;
}
}
else
2017-10-08 20:28:56 +01:00
DicConsole . WriteLine ( "ISO9660 plugin" , "Found unknown supplementary volume descriptor" ) ;
2011-03-03 18:34:33 +00:00
break ;
}
}
counter + + ;
}
2016-04-19 02:11:47 +01:00
DecodedVolumeDescriptor decodedVD = new DecodedVolumeDescriptor ( ) ;
DecodedVolumeDescriptor decodedJolietVD = new DecodedVolumeDescriptor ( ) ;
2012-08-03 05:43:58 +00:00
2017-10-08 20:28:56 +01:00
xmlFSType = new Schemas . FileSystemType ( ) ;
2017-10-08 22:47:09 +01:00
if ( pvd = = null & & hsvd = = null )
2017-10-08 20:28:56 +01:00
{
information = "ERROR: Could not find primary volume descriptor" ;
return ;
}
2017-10-08 22:47:09 +01:00
if ( HighSierra )
decodedVD = DecodeVolumeDescriptor ( hsvd . Value ) ;
else
decodedVD = DecodeVolumeDescriptor ( pvd . Value ) ;
2017-10-08 20:28:56 +01:00
if ( jolietvd ! = null )
decodedJolietVD = DecodeJolietDescriptor ( jolietvd . Value ) ;
2012-08-03 05:43:58 +00:00
2017-10-09 02:26:45 +01:00
uint rootLocation = HighSierra ? hsvd . Value . root_directory_record . extent : pvd . Value . root_directory_record . extent ;
2017-10-09 09:21:30 +01:00
uint rootSize = 0 ;
if ( HighSierra )
{
rootSize = hsvd . Value . root_directory_record . size / hsvd . Value . logical_block_size ;
if ( hsvd . Value . root_directory_record . size % hsvd . Value . logical_block_size > 0 )
rootSize + + ;
}
else
{
rootSize = pvd . Value . root_directory_record . size / pvd . Value . logical_block_size ;
if ( pvd . Value . root_directory_record . size % pvd . Value . logical_block_size > 0 )
rootSize + + ;
}
2017-10-09 02:26:45 +01:00
byte [ ] root_dir = imagePlugin . ReadSectors ( rootLocation + partition . Start , rootSize ) ;
int rootOff = 0 ;
bool XA = false ;
2017-10-09 09:48:28 +01:00
bool Apple = false ;
2017-10-09 11:25:47 +01:00
bool SUSP = false ;
List < ContinuationArea > contareas = new List < ContinuationArea > ( ) ;
List < byte [ ] > refareas = new List < byte [ ] > ( ) ;
StringBuilder suspInformation = new StringBuilder ( ) ;
2017-10-09 09:48:28 +01:00
BigEndianBitConverter . IsLittleEndian = BitConverter . IsLittleEndian ;
2017-10-09 02:26:45 +01:00
// Walk thru root directory to see system area extensions in use
2017-10-09 09:21:30 +01:00
while ( rootOff + Marshal . SizeOf ( typeof ( DirectoryRecord ) ) < root_dir . Length )
2017-10-09 02:26:45 +01:00
{
DirectoryRecord record = new DirectoryRecord ( ) ;
IntPtr ptr = Marshal . AllocHGlobal ( Marshal . SizeOf ( record ) ) ;
Marshal . Copy ( root_dir , rootOff , ptr , Marshal . SizeOf ( record ) ) ;
record = ( DirectoryRecord ) Marshal . PtrToStructure ( ptr , typeof ( DirectoryRecord ) ) ;
Marshal . FreeHGlobal ( ptr ) ;
int sa_off = Marshal . SizeOf ( record ) + record . name_len ;
2017-10-09 09:21:30 +01:00
sa_off + = sa_off % 2 ;
2017-10-09 02:26:45 +01:00
int sa_len = record . length - sa_off ;
if ( sa_len > 0 & & rootOff + sa_off + sa_len < = root_dir . Length )
{
byte [ ] sa = new byte [ sa_len ] ;
Array . Copy ( root_dir , rootOff + sa_off , sa , 0 , sa_len ) ;
2017-10-09 09:21:30 +01:00
sa_off = 0 ;
2017-10-09 02:26:45 +01:00
2017-10-09 09:48:28 +01:00
while ( sa_off < sa_len )
2017-10-09 02:26:45 +01:00
{
2017-10-09 09:48:28 +01:00
bool noneFound = true ;
if ( Marshal . SizeOf ( typeof ( CdromXa ) ) + sa_off < = sa_len )
{
CdromXa xa = BigEndianMarshal . ByteArrayToStructureBigEndian < CdromXa > ( sa ) ;
if ( xa . signature = = XaMagic )
{
XA = true ;
sa_off + = Marshal . SizeOf ( typeof ( CdromXa ) ) ;
noneFound = false ;
}
}
if ( sa_off > = sa_len )
break ;
ushort nextSignature = BigEndianBitConverter . ToUInt16 ( sa , sa_off ) ;
// Easy, contains size field
if ( nextSignature = = AppleMagic )
{
Apple = true ;
sa_off + = sa [ sa_off + 2 ] ;
noneFound = false ;
}
// Not easy, contains size field
if ( nextSignature = = AppleMagicOld )
2017-10-09 09:21:30 +01:00
{
2017-10-09 09:48:28 +01:00
Apple = true ;
AppleOldId apple_id = ( AppleOldId ) sa [ sa_off + 2 ] ;
noneFound = false ;
switch ( apple_id )
{
case AppleOldId . ProDOS :
sa_off + = Marshal . SizeOf ( typeof ( AppleProDOSOldSystemUse ) ) ;
break ;
case AppleOldId . TypeCreator :
case AppleOldId . TypeCreatorBundle :
sa_off + = Marshal . SizeOf ( typeof ( AppleHFSTypeCreatorSystemUse ) ) ;
break ;
case AppleOldId . TypeCreatorIcon :
case AppleOldId . TypeCreatorIconBundle :
sa_off + = Marshal . SizeOf ( typeof ( AppleHFSIconSystemUse ) ) ;
break ;
case AppleOldId . HFS :
sa_off + = Marshal . SizeOf ( typeof ( AppleHFSOldSystemUse ) ) ;
break ;
}
2017-10-09 09:21:30 +01:00
}
2017-10-09 09:48:28 +01:00
2017-10-09 11:25:47 +01:00
// IEEE-P1281 aka SUSP 1.12
if ( nextSignature = = SUSP_Indicator )
{
SUSP = true ;
sa_off + = sa [ sa_off + 2 ] ;
noneFound = false ;
while ( sa_off < sa_len )
{
nextSignature = BigEndianBitConverter . ToUInt16 ( sa , sa_off ) ;
if ( nextSignature = = AppleMagic )
{
// Can collide with AAIP
if ( sa [ sa_off + 3 ] = = 1 & & sa [ sa_off + 2 ] = = 7 )
Apple = true ;
else Apple | = sa [ sa_off + 3 ] ! = 1 ;
}
if ( nextSignature = = SUSP_Continuation & & sa_off + sa [ sa_off + 2 ] < = sa_len )
{
byte [ ] ce = new byte [ sa [ sa_off + 2 ] ] ;
Array . Copy ( sa , sa_off , ce , 0 , ce . Length ) ;
ContinuationArea ca = BigEndianMarshal . ByteArrayToStructureBigEndian < ContinuationArea > ( ce ) ;
contareas . Add ( ca ) ;
}
if ( nextSignature = = SUSP_Reference & & sa_off + sa [ sa_off + 2 ] < = sa_len )
{
byte [ ] er = new byte [ sa [ sa_off + 2 ] ] ;
Array . Copy ( sa , sa_off , er , 0 , er . Length ) ;
refareas . Add ( er ) ;
}
sa_off + = sa [ sa_off + 2 ] ;
if ( nextSignature = = SUSP_Terminator )
break ;
}
}
2017-10-09 09:48:28 +01:00
if ( noneFound )
break ;
2017-10-09 02:26:45 +01:00
}
}
rootOff + = record . length ;
if ( record . length = = 0 )
break ;
}
2017-10-09 11:25:47 +01:00
foreach ( ContinuationArea ca in contareas )
{
uint ca_len = ( ca . ca_length_be + ca . offset_be ) / ( HighSierra ? hsvd . Value . logical_block_size : pvd . Value . logical_block_size ) ;
if ( ( ca . ca_length_be + ca . offset_be ) % ( HighSierra ? hsvd . Value . logical_block_size : pvd . Value . logical_block_size ) > 0 )
ca_len + + ;
byte [ ] ca_sectors = imagePlugin . ReadSectors ( ca . block_be , ca_len ) ;
byte [ ] ca_data = new byte [ ca . ca_length_be ] ;
Array . Copy ( ca_sectors , ca . offset_be , ca_data , 0 , ca . ca_length_be ) ;
int ca_off = 0 ;
while ( ca_off < ca . ca_length_be )
{
ushort nextSignature = BigEndianBitConverter . ToUInt16 ( ca_data , ca_off ) ;
// Apple never said to include its extensions inside a continuation area, but just in case
if ( nextSignature = = AppleMagic )
{
// Can collide with AAIP
if ( ca_data [ ca_off + 3 ] = = 1 & & ca_data [ ca_off + 2 ] = = 7 )
Apple = true ;
else Apple | = ca_data [ ca_off + 3 ] ! = 1 ;
}
if ( nextSignature = = SUSP_Reference & & ca_off + ca_data [ ca_off + 2 ] < = ca . ca_length_be )
{
byte [ ] er = new byte [ ca_data [ ca_off + 2 ] ] ;
Array . Copy ( ca_data , ca_off , er , 0 , er . Length ) ;
refareas . Add ( er ) ;
}
ca_off + = ca_data [ ca_off + 2 ] ;
}
}
if ( refareas . Count > 0 )
{
suspInformation . AppendLine ( "----------------------------------------" ) ;
suspInformation . AppendLine ( "SYSTEM USE SHARING PROTOCOL INFORMATION:" ) ;
suspInformation . AppendLine ( "----------------------------------------" ) ;
counter = 1 ;
foreach ( byte [ ] erb in refareas )
{
ReferenceArea er = BigEndianMarshal . ByteArrayToStructureBigEndian < ReferenceArea > ( erb ) ;
string ext_id = CurrentEncoding . GetString ( erb , Marshal . SizeOf ( er ) , er . id_len ) ;
string ext_des = CurrentEncoding . GetString ( erb , Marshal . SizeOf ( er ) + er . id_len , er . des_len ) ;
string ext_src = CurrentEncoding . GetString ( erb , Marshal . SizeOf ( er ) + er . id_len + er . des_len , er . src_len ) ;
suspInformation . AppendFormat ( "Extension: {0}" , counter ) . AppendLine ( ) ;
suspInformation . AppendFormat ( "\tID: {0}, version {1}" , ext_id , er . ext_ver ) . AppendLine ( ) ;
suspInformation . AppendFormat ( "\tDescription: {0}" , ext_des ) . AppendLine ( ) ;
suspInformation . AppendFormat ( "\tSource: {0}" , ext_src ) . AppendLine ( ) ;
counter + + ;
}
}
2011-03-03 18:34:33 +00:00
2014-07-09 19:50:16 +01:00
// TODO: Check this
2017-07-25 15:00:12 +01:00
/ *
2017-07-19 16:37:11 +01:00
if ( ( i + partition . Start ) < partition . End )
2014-07-09 19:50:16 +01:00
{
2011-03-03 18:34:33 +00:00
2017-07-19 16:37:11 +01:00
byte [ ] path_table = imagePlugin . ReadSector ( i + partition . Start ) ;
2014-07-09 19:50:16 +01:00
Array . Copy ( path_table , 2 , RootDirectoryLocation , 0 , 4 ) ;
// Check for Rock Ridge
2017-07-19 16:37:11 +01:00
byte [ ] root_dir = imagePlugin . ReadSector ( ( ulong ) BitConverter . ToInt32 ( RootDirectoryLocation , 0 ) + partition . Start ) ;
2011-03-03 18:34:33 +00:00
2014-07-09 19:50:16 +01:00
byte [ ] SUSPMagic = new byte [ 2 ] ;
byte [ ] RRMagic = new byte [ 2 ] ;
Array . Copy ( root_dir , 0x22 , SUSPMagic , 0 , 2 ) ;
2017-06-06 21:23:20 +01:00
if ( CurrentEncoding . GetString ( SUSPMagic ) = = "SP" )
2014-07-09 19:50:16 +01:00
{
Array . Copy ( root_dir , 0x29 , RRMagic , 0 , 2 ) ;
2017-06-06 21:23:20 +01:00
RockRidge | = CurrentEncoding . GetString ( RRMagic ) = = "RR" ;
2014-07-09 19:50:16 +01:00
}
2017-07-25 15:00:12 +01:00
} * /
2011-03-03 18:34:33 +00:00
2017-07-19 16:37:11 +01:00
byte [ ] ipbin_sector = imagePlugin . ReadSector ( 0 + partition . Start ) ;
2017-10-08 17:50:29 +01:00
Decoders . Sega . CD . IPBin ? SegaCD = Decoders . Sega . CD . DecodeIPBin ( ipbin_sector ) ;
Decoders . Sega . Saturn . IPBin ? Saturn = Decoders . Sega . Saturn . DecodeIPBin ( ipbin_sector ) ;
Decoders . Sega . Dreamcast . IPBin ? Dreamcast = Decoders . Sega . Dreamcast . DecodeIPBin ( ipbin_sector ) ;
2011-03-03 18:34:33 +00:00
2017-10-08 22:47:09 +01:00
ISOMetadata . AppendFormat ( "{0} file system" , HighSierra ? "High Sierra Format" : "ISO9660" ) . AppendLine ( ) ;
2017-10-09 02:26:45 +01:00
if ( XA )
ISOMetadata . AppendLine ( "CD-ROM XA extensions present." ) ;
2017-10-09 09:48:28 +01:00
if ( Apple )
ISOMetadata . AppendLine ( "Apple extensions present." ) ;
2017-10-08 20:28:56 +01:00
if ( jolietvd ! = null )
2017-10-09 02:26:45 +01:00
ISOMetadata . AppendLine ( "Joliet extensions present." ) ;
2017-10-09 11:25:47 +01:00
if ( SUSP )
ISOMetadata . AppendLine ( "System Use Sharing Protocol present." ) ;
2016-04-19 02:11:47 +01:00
if ( RockRidge )
2017-10-09 02:26:45 +01:00
ISOMetadata . AppendLine ( "Rock Ridge Interchange Protocol present." ) ;
2017-10-08 20:28:56 +01:00
if ( bvd ! = null )
2011-03-03 18:34:33 +00:00
ISOMetadata . AppendFormat ( "Disc bootable following {0} specifications." , BootSpec ) . AppendLine ( ) ;
2017-10-08 17:50:29 +01:00
if ( SegaCD ! = null )
2011-03-03 18:34:33 +00:00
{
ISOMetadata . AppendLine ( "This is a SegaCD / MegaCD disc." ) ;
2017-10-08 17:50:29 +01:00
ISOMetadata . AppendLine ( Decoders . Sega . CD . Prettify ( SegaCD ) ) ;
2011-03-03 18:34:33 +00:00
}
2017-10-08 17:50:29 +01:00
if ( Saturn ! = null )
2011-03-03 18:34:33 +00:00
{
ISOMetadata . AppendLine ( "This is a Sega Saturn disc." ) ;
2017-10-08 17:50:29 +01:00
ISOMetadata . AppendLine ( Decoders . Sega . Saturn . Prettify ( Saturn ) ) ;
2011-03-03 18:34:33 +00:00
}
2017-10-08 17:50:29 +01:00
if ( Dreamcast ! = null )
2011-03-03 18:34:33 +00:00
{
ISOMetadata . AppendLine ( "This is a Sega Dreamcast disc." ) ;
2017-10-08 17:50:29 +01:00
ISOMetadata . AppendLine ( Decoders . Sega . Dreamcast . Prettify ( Dreamcast ) ) ;
2011-03-03 18:34:33 +00:00
}
2017-10-09 00:32:17 +01:00
ISOMetadata . AppendLine ( "------------------------------" ) ;
2011-03-03 18:34:33 +00:00
ISOMetadata . AppendLine ( "VOLUME DESCRIPTOR INFORMATION:" ) ;
2017-10-09 00:32:17 +01:00
ISOMetadata . AppendLine ( "------------------------------" ) ;
2011-03-03 18:34:33 +00:00
ISOMetadata . AppendFormat ( "System identifier: {0}" , decodedVD . SystemIdentifier ) . AppendLine ( ) ;
ISOMetadata . AppendFormat ( "Volume identifier: {0}" , decodedVD . VolumeIdentifier ) . AppendLine ( ) ;
ISOMetadata . AppendFormat ( "Volume set identifier: {0}" , decodedVD . VolumeSetIdentifier ) . AppendLine ( ) ;
ISOMetadata . AppendFormat ( "Publisher identifier: {0}" , decodedVD . PublisherIdentifier ) . AppendLine ( ) ;
ISOMetadata . AppendFormat ( "Data preparer identifier: {0}" , decodedVD . DataPreparerIdentifier ) . AppendLine ( ) ;
ISOMetadata . AppendFormat ( "Application identifier: {0}" , decodedVD . ApplicationIdentifier ) . AppendLine ( ) ;
2014-04-14 02:29:13 +00:00
ISOMetadata . AppendFormat ( "Volume creation date: {0}" , decodedVD . CreationTime ) . AppendLine ( ) ;
2016-04-19 02:11:47 +01:00
if ( decodedVD . HasModificationTime )
2014-04-14 02:29:13 +00:00
ISOMetadata . AppendFormat ( "Volume modification date: {0}" , decodedVD . ModificationTime ) . AppendLine ( ) ;
2011-03-03 18:34:33 +00:00
else
ISOMetadata . AppendFormat ( "Volume has not been modified." ) . AppendLine ( ) ;
2016-04-19 02:11:47 +01:00
if ( decodedVD . HasExpirationTime )
2014-04-14 02:29:13 +00:00
ISOMetadata . AppendFormat ( "Volume expiration date: {0}" , decodedVD . ExpirationTime ) . AppendLine ( ) ;
2011-03-03 18:34:33 +00:00
else
ISOMetadata . AppendFormat ( "Volume does not expire." ) . AppendLine ( ) ;
2016-04-19 02:11:47 +01:00
if ( decodedVD . HasEffectiveTime )
2014-04-14 02:29:13 +00:00
ISOMetadata . AppendFormat ( "Volume effective date: {0}" , decodedVD . EffectiveTime ) . AppendLine ( ) ;
2011-03-03 18:34:33 +00:00
else
ISOMetadata . AppendFormat ( "Volume has always been effective." ) . AppendLine ( ) ;
2017-10-08 21:54:56 +01:00
ISOMetadata . AppendFormat ( "Volume has {0} blocks of {1} bytes each" , decodedVD . Blocks , decodedVD . BlockSize ) . AppendLine ( ) ;
2011-03-03 18:34:33 +00:00
2017-10-08 20:28:56 +01:00
if ( jolietvd ! = null )
2016-04-19 02:11:47 +01:00
{
2017-10-09 00:32:17 +01:00
ISOMetadata . AppendLine ( "-------------------------------------" ) ;
2016-04-19 02:11:47 +01:00
ISOMetadata . AppendLine ( "JOLIET VOLUME DESCRIPTOR INFORMATION:" ) ;
2017-10-09 00:32:17 +01:00
ISOMetadata . AppendLine ( "-------------------------------------" ) ;
2016-04-19 02:11:47 +01:00
ISOMetadata . AppendFormat ( "System identifier: {0}" , decodedJolietVD . SystemIdentifier ) . AppendLine ( ) ;
ISOMetadata . AppendFormat ( "Volume identifier: {0}" , decodedJolietVD . VolumeIdentifier ) . AppendLine ( ) ;
ISOMetadata . AppendFormat ( "Volume set identifier: {0}" , decodedJolietVD . VolumeSetIdentifier ) . AppendLine ( ) ;
ISOMetadata . AppendFormat ( "Publisher identifier: {0}" , decodedJolietVD . PublisherIdentifier ) . AppendLine ( ) ;
ISOMetadata . AppendFormat ( "Data preparer identifier: {0}" , decodedJolietVD . DataPreparerIdentifier ) . AppendLine ( ) ;
ISOMetadata . AppendFormat ( "Application identifier: {0}" , decodedJolietVD . ApplicationIdentifier ) . AppendLine ( ) ;
ISOMetadata . AppendFormat ( "Volume creation date: {0}" , decodedJolietVD . CreationTime ) . AppendLine ( ) ;
if ( decodedJolietVD . HasModificationTime )
ISOMetadata . AppendFormat ( "Volume modification date: {0}" , decodedJolietVD . ModificationTime ) . AppendLine ( ) ;
else
ISOMetadata . AppendFormat ( "Volume has not been modified." ) . AppendLine ( ) ;
if ( decodedJolietVD . HasExpirationTime )
ISOMetadata . AppendFormat ( "Volume expiration date: {0}" , decodedJolietVD . ExpirationTime ) . AppendLine ( ) ;
else
ISOMetadata . AppendFormat ( "Volume does not expire." ) . AppendLine ( ) ;
if ( decodedJolietVD . HasEffectiveTime )
2014-04-14 02:29:13 +00:00
ISOMetadata . AppendFormat ( "Volume effective date: {0}" , decodedJolietVD . EffectiveTime ) . AppendLine ( ) ;
2016-04-19 02:11:47 +01:00
else
ISOMetadata . AppendFormat ( "Volume has always been effective." ) . AppendLine ( ) ;
}
2012-08-03 05:43:58 +00:00
2017-10-09 00:32:17 +01:00
if ( torito ! = null )
{
vd_sector = imagePlugin . ReadSector ( torito . Value . catalog_sector + partition . Start ) ;
Checksums . SHA1Context sha1Ctx = new Checksums . SHA1Context ( ) ;
sha1Ctx . Init ( ) ;
byte [ ] boot_image ;
int torito_off = 0 ;
if ( vd_sector [ torito_off ] ! = 1 )
goto exit_torito ;
ElToritoValidationEntry valentry = new ElToritoValidationEntry ( ) ;
IntPtr ptr = Marshal . AllocHGlobal ( ElToritoEntrySize ) ;
Marshal . Copy ( vd_sector , torito_off , ptr , ElToritoEntrySize ) ;
valentry = ( ElToritoValidationEntry ) Marshal . PtrToStructure ( ptr , typeof ( ElToritoValidationEntry ) ) ;
Marshal . FreeHGlobal ( ptr ) ;
if ( valentry . signature ! = ElToritoMagic )
goto exit_torito ;
torito_off + = ElToritoEntrySize ;
ElToritoInitialEntry initial_entry = new ElToritoInitialEntry ( ) ;
ptr = Marshal . AllocHGlobal ( ElToritoEntrySize ) ;
Marshal . Copy ( vd_sector , torito_off , ptr , ElToritoEntrySize ) ;
initial_entry = ( ElToritoInitialEntry ) Marshal . PtrToStructure ( ptr , typeof ( ElToritoInitialEntry ) ) ;
Marshal . FreeHGlobal ( ptr ) ;
initial_entry . boot_type = ( ElToritoEmulation ) ( ( byte ) initial_entry . boot_type & 0xF ) ;
boot_image = imagePlugin . ReadSectors ( initial_entry . load_rba + partition . Start , initial_entry . sector_count ) ;
ISOMetadata . AppendLine ( "----------------------" ) ;
ISOMetadata . AppendLine ( "EL TORITO INFORMATION:" ) ;
ISOMetadata . AppendLine ( "----------------------" ) ;
ISOMetadata . AppendLine ( "Initial entry:" ) ;
ISOMetadata . AppendFormat ( "\tDeveloper ID: {0}" , CurrentEncoding . GetString ( valentry . developer_id ) ) . AppendLine ( ) ;
if ( initial_entry . bootable = = ElToritoIndicator . Bootable )
{
ISOMetadata . AppendFormat ( "\tBootable on {0}" , valentry . platform_id ) . AppendLine ( ) ;
ISOMetadata . AppendFormat ( "\tBootable image starts at sector {0} and runs for {1} sectors" , initial_entry . load_rba , initial_entry . sector_count ) . AppendLine ( ) ;
if ( valentry . platform_id = = ElToritoPlatform . x86 )
ISOMetadata . AppendFormat ( "\tBootable image will be loaded at segment {0:X4}h" , initial_entry . load_seg = = 0 ? 0x7C0 : initial_entry . load_seg ) . AppendLine ( ) ;
else
ISOMetadata . AppendFormat ( "\tBootable image will be loaded at 0x{0:X8}" , ( uint ) initial_entry . load_seg * 10 ) . AppendLine ( ) ;
switch ( initial_entry . boot_type )
{
case ElToritoEmulation . None :
ISOMetadata . AppendLine ( "\tImage uses no emulation" ) ;
break ;
case ElToritoEmulation . Md2hd :
ISOMetadata . AppendLine ( "\tImage emulates a 5.25\" high-density (MD2HD, 1.2Mb) floppy" ) ;
break ;
case ElToritoEmulation . Mf2hd :
ISOMetadata . AppendLine ( "\tImage emulates a 3.5\" high-density (MF2HD, 1.44Mb) floppy" ) ;
break ;
case ElToritoEmulation . Mf2ed :
ISOMetadata . AppendLine ( "\tImage emulates a 3.5\" extra-density (MF2ED, 2.88Mb) floppy" ) ;
break ;
default :
ISOMetadata . AppendFormat ( "\tImage uses unknown emulation type {0}" , ( byte ) initial_entry . boot_type ) . AppendLine ( ) ;
break ;
}
ISOMetadata . AppendFormat ( "\tSystem type: 0x{0:X2}" , initial_entry . system_type ) . AppendLine ( ) ;
ISOMetadata . AppendFormat ( "\tBootable image's SHA1: {0}" , sha1Ctx . Data ( boot_image , out byte [ ] hash ) ) . AppendLine ( ) ;
}
else
ISOMetadata . AppendLine ( "\tNot bootable" ) ;
torito_off + = ElToritoEntrySize ;
int section_counter = 2 ;
while ( torito_off < vd_sector . Length & & ( vd_sector [ torito_off ] = = ( byte ) ElToritoIndicator . Header | | vd_sector [ torito_off ] = = ( byte ) ElToritoIndicator . LastHeader ) )
{
ElToritoSectionHeaderEntry section_header = new ElToritoSectionHeaderEntry ( ) ;
ptr = Marshal . AllocHGlobal ( ElToritoEntrySize ) ;
Marshal . Copy ( vd_sector , torito_off , ptr , ElToritoEntrySize ) ;
section_header = ( ElToritoSectionHeaderEntry ) Marshal . PtrToStructure ( ptr , typeof ( ElToritoSectionHeaderEntry ) ) ;
Marshal . FreeHGlobal ( ptr ) ;
torito_off + = ElToritoEntrySize ;
ISOMetadata . AppendFormat ( "Boot section {0}:" , section_counter ) ;
ISOMetadata . AppendFormat ( "\tSection ID: {0}" , CurrentEncoding . GetString ( section_header . identifier ) ) . AppendLine ( ) ;
for ( int entry_counter = 1 ; entry_counter < = section_header . entries & & torito_off < vd_sector . Length ; entry_counter + + )
{
ElToritoSectionEntry section_entry = new ElToritoSectionEntry ( ) ;
ptr = Marshal . AllocHGlobal ( ElToritoEntrySize ) ;
Marshal . Copy ( vd_sector , torito_off , ptr , ElToritoEntrySize ) ;
section_entry = ( ElToritoSectionEntry ) Marshal . PtrToStructure ( ptr , typeof ( ElToritoSectionEntry ) ) ;
Marshal . FreeHGlobal ( ptr ) ;
torito_off + = ElToritoEntrySize ;
ISOMetadata . AppendFormat ( "\tEntry {0}:" , entry_counter ) ;
if ( section_entry . bootable = = ElToritoIndicator . Bootable )
{
boot_image = imagePlugin . ReadSectors ( section_entry . load_rba + partition . Start , section_entry . sector_count ) ;
ISOMetadata . AppendFormat ( "\t\tBootable on {0}" , section_header . platform_id ) . AppendLine ( ) ;
ISOMetadata . AppendFormat ( "\t\tBootable image starts at sector {0} and runs for {1} sectors" , section_entry . load_rba , section_entry . sector_count ) . AppendLine ( ) ;
if ( valentry . platform_id = = ElToritoPlatform . x86 )
ISOMetadata . AppendFormat ( "\t\tBootable image will be loaded at segment {0:X4}h" , section_entry . load_seg = = 0 ? 0x7C0 : section_entry . load_seg ) . AppendLine ( ) ;
else
ISOMetadata . AppendFormat ( "\t\tBootable image will be loaded at 0x{0:X8}" , ( uint ) section_entry . load_seg * 10 ) . AppendLine ( ) ;
switch ( ( ElToritoEmulation ) ( ( byte ) section_entry . boot_type & 0xF ) )
{
case ElToritoEmulation . None :
ISOMetadata . AppendLine ( "\t\tImage uses no emulation" ) ;
break ;
case ElToritoEmulation . Md2hd :
ISOMetadata . AppendLine ( "\t\tImage emulates a 5.25\" high-density (MD2HD, 1.2Mb) floppy" ) ;
break ;
case ElToritoEmulation . Mf2hd :
ISOMetadata . AppendLine ( "\t\tImage emulates a 3.5\" high-density (MF2HD, 1.44Mb) floppy" ) ;
break ;
case ElToritoEmulation . Mf2ed :
ISOMetadata . AppendLine ( "\t\tImage emulates a 3.5\" extra-density (MF2ED, 2.88Mb) floppy" ) ;
break ;
default :
ISOMetadata . AppendFormat ( "\t\tImage uses unknown emulation type {0}" , ( byte ) initial_entry . boot_type ) . AppendLine ( ) ;
break ;
}
ISOMetadata . AppendFormat ( "\t\tSelection criteria type: {0}" , section_entry . selection_criteria_type ) . AppendLine ( ) ;
ISOMetadata . AppendFormat ( "\t\tSystem type: 0x{0:X2}" , section_entry . system_type ) . AppendLine ( ) ;
ISOMetadata . AppendFormat ( "\t\tBootable image's SHA1: {0}" , sha1Ctx . Data ( boot_image , out byte [ ] hash ) ) . AppendLine ( ) ;
}
else
ISOMetadata . AppendLine ( "\t\tNot bootable" ) ;
ElToritoFlags flags = ( ElToritoFlags ) ( ( byte ) section_entry . boot_type & 0xF0 ) ;
if ( flags . HasFlag ( ElToritoFlags . ATAPI ) )
ISOMetadata . AppendLine ( "\t\tImage contains ATAPI drivers" ) ;
if ( flags . HasFlag ( ElToritoFlags . SCSI ) )
ISOMetadata . AppendLine ( "\t\tImage contains SCSI drivers" ) ;
if ( flags . HasFlag ( ElToritoFlags . Continued ) )
{
while ( true & & torito_off < vd_sector . Length )
{
ElToritoSectionEntryExtension section_extension = new ElToritoSectionEntryExtension ( ) ;
ptr = Marshal . AllocHGlobal ( ElToritoEntrySize ) ;
Marshal . Copy ( vd_sector , torito_off , ptr , ElToritoEntrySize ) ;
section_extension = ( ElToritoSectionEntryExtension ) Marshal . PtrToStructure ( ptr , typeof ( ElToritoSectionEntryExtension ) ) ;
Marshal . FreeHGlobal ( ptr ) ;
torito_off + = ElToritoEntrySize ;
if ( ! section_extension . extension_flags . HasFlag ( ElToritoFlags . Continued ) )
break ;
}
}
}
if ( section_header . header_id = = ElToritoIndicator . LastHeader )
break ;
}
}
exit_torito :
2017-10-09 11:25:47 +01:00
if ( refareas . Count > 0 )
ISOMetadata . Append ( suspInformation . ToString ( ) ) ;
2017-10-08 22:47:09 +01:00
xmlFSType . Type = HighSierra ? "High Sierra Format" : "ISO9660" ;
2015-12-23 23:46:31 +00:00
2017-10-08 20:28:56 +01:00
if ( jolietvd ! = null )
2015-12-05 17:10:27 +00:00
{
2015-12-06 05:09:31 +00:00
xmlFSType . VolumeName = decodedJolietVD . VolumeIdentifier ;
2015-12-23 23:46:31 +00:00
if ( decodedJolietVD . SystemIdentifier = = null | | decodedVD . SystemIdentifier . Length > decodedJolietVD . SystemIdentifier . Length )
xmlFSType . SystemIdentifier = decodedVD . SystemIdentifier ;
else
xmlFSType . SystemIdentifier = decodedJolietVD . SystemIdentifier ;
2016-04-19 02:11:47 +01:00
2015-12-23 23:46:31 +00:00
if ( decodedJolietVD . VolumeSetIdentifier = = null | | decodedVD . VolumeSetIdentifier . Length > decodedJolietVD . VolumeSetIdentifier . Length )
xmlFSType . VolumeSetIdentifier = decodedVD . VolumeSetIdentifier ;
else
xmlFSType . VolumeSetIdentifier = decodedJolietVD . VolumeSetIdentifier ;
2016-04-19 02:11:47 +01:00
2015-12-23 23:46:31 +00:00
if ( decodedJolietVD . PublisherIdentifier = = null | | decodedVD . PublisherIdentifier . Length > decodedJolietVD . PublisherIdentifier . Length )
xmlFSType . PublisherIdentifier = decodedVD . PublisherIdentifier ;
else
xmlFSType . PublisherIdentifier = decodedJolietVD . PublisherIdentifier ;
2016-04-19 02:11:47 +01:00
2015-12-23 23:46:31 +00:00
if ( decodedJolietVD . DataPreparerIdentifier = = null | | decodedVD . DataPreparerIdentifier . Length > decodedJolietVD . DataPreparerIdentifier . Length )
xmlFSType . DataPreparerIdentifier = decodedVD . DataPreparerIdentifier ;
else
xmlFSType . DataPreparerIdentifier = decodedJolietVD . SystemIdentifier ;
2016-04-19 02:11:47 +01:00
2015-12-23 23:46:31 +00:00
if ( decodedJolietVD . ApplicationIdentifier = = null | | decodedVD . ApplicationIdentifier . Length > decodedJolietVD . ApplicationIdentifier . Length )
xmlFSType . ApplicationIdentifier = decodedVD . ApplicationIdentifier ;
else
xmlFSType . ApplicationIdentifier = decodedJolietVD . SystemIdentifier ;
2015-12-06 05:09:31 +00:00
xmlFSType . CreationDate = decodedJolietVD . CreationTime ;
xmlFSType . CreationDateSpecified = true ;
2016-04-19 02:11:47 +01:00
if ( decodedJolietVD . HasModificationTime )
2015-12-06 05:09:31 +00:00
{
xmlFSType . ModificationDate = decodedJolietVD . ModificationTime ;
xmlFSType . ModificationDateSpecified = true ;
}
2016-04-19 02:11:47 +01:00
if ( decodedJolietVD . HasExpirationTime )
2015-12-06 05:09:31 +00:00
{
xmlFSType . ExpirationDate = decodedJolietVD . ExpirationTime ;
xmlFSType . ExpirationDateSpecified = true ;
}
2016-04-19 02:11:47 +01:00
if ( decodedJolietVD . HasEffectiveTime )
2015-12-06 05:09:31 +00:00
{
xmlFSType . EffectiveDate = decodedJolietVD . EffectiveTime ;
xmlFSType . EffectiveDateSpecified = true ;
}
}
else
{
xmlFSType . SystemIdentifier = decodedVD . SystemIdentifier ;
xmlFSType . VolumeName = decodedVD . VolumeIdentifier ;
xmlFSType . VolumeSetIdentifier = decodedVD . VolumeSetIdentifier ;
xmlFSType . PublisherIdentifier = decodedVD . PublisherIdentifier ;
xmlFSType . DataPreparerIdentifier = decodedVD . DataPreparerIdentifier ;
xmlFSType . ApplicationIdentifier = decodedVD . ApplicationIdentifier ;
xmlFSType . CreationDate = decodedVD . CreationTime ;
xmlFSType . CreationDateSpecified = true ;
2016-04-19 02:11:47 +01:00
if ( decodedVD . HasModificationTime )
2015-12-06 05:09:31 +00:00
{
xmlFSType . ModificationDate = decodedVD . ModificationTime ;
xmlFSType . ModificationDateSpecified = true ;
}
2016-04-19 02:11:47 +01:00
if ( decodedVD . HasExpirationTime )
2015-12-06 05:09:31 +00:00
{
xmlFSType . ExpirationDate = decodedVD . ExpirationTime ;
xmlFSType . ExpirationDateSpecified = true ;
}
2016-04-19 02:11:47 +01:00
if ( decodedVD . HasEffectiveTime )
2015-12-06 05:09:31 +00:00
{
xmlFSType . EffectiveDate = decodedVD . EffectiveTime ;
xmlFSType . EffectiveDateSpecified = true ;
}
2015-12-05 17:10:27 +00:00
}
2017-10-08 20:28:56 +01:00
xmlFSType . Bootable | = bvd ! = null | | SegaCD ! = null | | Saturn ! = null | | Dreamcast ! = null ;
2017-10-08 21:54:56 +01:00
xmlFSType . Clusters = decodedVD . Blocks ;
xmlFSType . ClusterSize = decodedVD . BlockSize ;
2015-12-06 05:09:31 +00:00
2011-03-03 18:34:33 +00:00
information = ISOMetadata . ToString ( ) ;
}
}
2017-10-08 20:41:54 +01:00
}