diff --git a/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj b/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj
index a81b38ad..7a3ee9c9 100644
--- a/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj
+++ b/DiscImageChef.Filesystems/DiscImageChef.Filesystems.csproj
@@ -164,6 +164,8 @@
+
+
diff --git a/DiscImageChef.Filesystems/ISO9660/Consts/CDi.cs b/DiscImageChef.Filesystems/ISO9660/Consts/CDi.cs
new file mode 100644
index 00000000..69ebbd8f
--- /dev/null
+++ b/DiscImageChef.Filesystems/ISO9660/Consts/CDi.cs
@@ -0,0 +1,66 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : CDi.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Component
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Description
+//
+// --[ 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 .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2017 Natalia Portillo
+// ****************************************************************************/
+using System;
+
+namespace DiscImageChef.Filesystems.ISO9660
+{
+ public partial class ISO9660 : Filesystem
+ {
+ readonly string CdiMagic = "CD-I ";
+
+ [Flags]
+ enum CdiVolumeFlags
+ {
+ // Escapes are not ISO 2375 but ISO 2022
+ NotISO2375 = 1,
+ }
+
+ [Flags]
+ enum CdiFileFlags : byte
+ {
+ Hidden = 0x01,
+ }
+
+ [Flags]
+ enum CdiAttributes : ushort
+ {
+ OwnerRead = 1 << 0,
+ OwnerExecute = 1 << 2,
+ GroupRead = 1 << 4,
+ GroupExecute = 1 << 6,
+ OtherRead = 1 << 8,
+ OtherExecute = 1 << 10,
+ DigitalAudio = 1 << 14,
+ Directory = 1 << 15,
+ }
+ }
+}
diff --git a/DiscImageChef.Filesystems/ISO9660/Info.cs b/DiscImageChef.Filesystems/ISO9660/Info.cs
index 8b520fa7..b7fc17e2 100644
--- a/DiscImageChef.Filesystems/ISO9660/Info.cs
+++ b/DiscImageChef.Filesystems/ISO9660/Info.cs
@@ -73,7 +73,7 @@ namespace DiscImageChef.Filesystems.ISO9660
DicConsole.DebugWriteLine("ISO9660 plugin", "VDMagic = {0}", CurrentEncoding.GetString(VDMagic));
DicConsole.DebugWriteLine("ISO9660 plugin", "HSMagic = {0}", CurrentEncoding.GetString(HSMagic));
- return CurrentEncoding.GetString(VDMagic) == IsoMagic || CurrentEncoding.GetString(HSMagic) == HighSierraMagic;
+ return CurrentEncoding.GetString(VDMagic) == IsoMagic || CurrentEncoding.GetString(HSMagic) == HighSierraMagic || CurrentEncoding.GetString(VDMagic) == CdiMagic;
}
public override void GetInformation(ImagePlugins.ImagePlugin imagePlugin, Partition partition, out string information)
@@ -93,6 +93,7 @@ namespace DiscImageChef.Filesystems.ISO9660
PrimaryVolumeDescriptor? jolietvd = null;
BootRecord? bvd = null;
HighSierraPrimaryVolumeDescriptor? hsvd = null;
+ FileStructureVolumeDescriptor? fsvd = null;
ElToritoBootRecord? torito = null;
// ISO9660 is designed for 2048 bytes/sector devices
@@ -112,6 +113,7 @@ namespace DiscImageChef.Filesystems.ISO9660
int hs_off = 0;
if(HighSierra)
hs_off = 8;
+ bool CDi = false;
while(true)
{
@@ -135,13 +137,15 @@ namespace DiscImageChef.Filesystems.ISO9660
Array.Copy(vd_sector, 0x001, VDMagic, 0, 5);
Array.Copy(vd_sector, 0x009, HSMagic, 0, 5);
- if(CurrentEncoding.GetString(VDMagic) != IsoMagic && CurrentEncoding.GetString(HSMagic) != HighSierraMagic) // Recognized, it is an ISO9660, now check for rest of data.
+ if(CurrentEncoding.GetString(VDMagic) != IsoMagic && CurrentEncoding.GetString(HSMagic) != HighSierraMagic && CurrentEncoding.GetString(VDMagic) != CdiMagic) // Recognized, it is an ISO9660, now check for rest of data.
{
if(counter == 0)
return;
break;
}
+ CDi |= CurrentEncoding.GetString(VDMagic) == CdiMagic;
+
switch(VDType)
{
case 0:
@@ -176,6 +180,8 @@ namespace DiscImageChef.Filesystems.ISO9660
hsvd = (HighSierraPrimaryVolumeDescriptor)Marshal.PtrToStructure(ptr, typeof(HighSierraPrimaryVolumeDescriptor));
Marshal.FreeHGlobal(ptr);
}
+ else if(CDi)
+ fsvd = BigEndianMarshal.ByteArrayToStructureBigEndian(vd_sector);
else
{
pvd = new PrimaryVolumeDescriptor();
@@ -221,7 +227,7 @@ namespace DiscImageChef.Filesystems.ISO9660
xmlFSType = new Schemas.FileSystemType();
- if(pvd == null && hsvd == null)
+ if(pvd == null && hsvd == null && fsvd == null)
{
information = "ERROR: Could not find primary volume descriptor";
return;
@@ -229,6 +235,8 @@ namespace DiscImageChef.Filesystems.ISO9660
if(HighSierra)
decodedVD = DecodeVolumeDescriptor(hsvd.Value);
+ else if(CDi)
+ decodedVD = DecodeVolumeDescriptor(fsvd.Value);
else
decodedVD = DecodeVolumeDescriptor(pvd.Value);
@@ -267,7 +275,7 @@ namespace DiscImageChef.Filesystems.ISO9660
BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;
// Walk thru root directory to see system area extensions in use
- while(rootOff + Marshal.SizeOf(typeof(DirectoryRecord)) < root_dir.Length)
+ while(rootOff + Marshal.SizeOf(typeof(DirectoryRecord)) < root_dir.Length && !CDi)
{
DirectoryRecord record = new DirectoryRecord();
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(record));
@@ -472,7 +480,15 @@ namespace DiscImageChef.Filesystems.ISO9660
Decoders.Sega.Saturn.IPBin? Saturn = Decoders.Sega.Saturn.DecodeIPBin(ipbin_sector);
Decoders.Sega.Dreamcast.IPBin? Dreamcast = Decoders.Sega.Dreamcast.DecodeIPBin(ipbin_sector);
- ISOMetadata.AppendFormat("{0} file system", HighSierra ? "High Sierra Format" : "ISO9660").AppendLine();
+ string fsFormat;
+ if(HighSierra)
+ fsFormat = "High Sierra Format";
+ else if (CDi)
+ fsFormat = "CD-i";
+ else
+ fsFormat = "ISO9660";
+
+ ISOMetadata.AppendFormat("{0} file system", fsFormat).AppendLine();
if(XA)
ISOMetadata.AppendLine("CD-ROM XA extensions present.");
if(Apple)
@@ -717,7 +733,7 @@ namespace DiscImageChef.Filesystems.ISO9660
if(refareas.Count > 0)
ISOMetadata.Append(suspInformation.ToString());
- xmlFSType.Type = HighSierra ? "High Sierra Format" : "ISO9660";
+ xmlFSType.Type = fsFormat;
if(jolietvd != null)
{
diff --git a/DiscImageChef.Filesystems/ISO9660/Structs/CDi.cs b/DiscImageChef.Filesystems/ISO9660/Structs/CDi.cs
new file mode 100644
index 00000000..5118199c
--- /dev/null
+++ b/DiscImageChef.Filesystems/ISO9660/Structs/CDi.cs
@@ -0,0 +1,191 @@
+// /***************************************************************************
+// The Disc Image Chef
+// ----------------------------------------------------------------------------
+//
+// Filename : CDi.cs
+// Author(s) : Natalia Portillo
+//
+// Component : Component
+//
+// --[ Description ] ----------------------------------------------------------
+//
+// Description
+//
+// --[ 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 .
+//
+// ----------------------------------------------------------------------------
+// Copyright © 2011-2017 Natalia Portillo
+// ****************************************************************************/
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace DiscImageChef.Filesystems.ISO9660
+{
+ public partial class ISO9660 : Filesystem
+ {
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ struct FileStructureVolumeDescriptor
+ {
+ public byte type;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
+ public byte[] id;
+ public byte version;
+ public CdiVolumeFlags flags;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
+ public byte[] system_id;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
+ public byte[] volume_id;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
+ public byte[] reserved1;
+ public uint volume_space_size;
+ // Only used in SVDs
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
+ public byte[] escape_sequences;
+ public ushort reserved2;
+ public ushort volume_set_siz;
+ public ushort reserved3;
+ public ushort volume_sequence_number;
+ public ushort reserved4;
+ public ushort logical_block_size;
+ public uint reserved5;
+ public uint path_table_size;
+ public ulong reserved6;
+ public uint type_m_path_table;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 38)]
+ public byte[] reserved7;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
+ public byte[] volume_set_id;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
+ public byte[] publisher_id;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
+ public byte[] preparer_id;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
+ public byte[] application_id;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
+ public byte[] copyright_file_id;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
+ public byte[] reserved8;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
+ public byte[] abstract_file_id;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
+ public byte[] reserved9;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
+ public byte[] bibliographic_file_id;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
+ public byte[] reserved10;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
+ public byte[] creation_date;
+ public byte reserved11;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
+ public byte[] modification_date;
+ public byte reserved12;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
+ public byte[] expiration_date;
+ public byte reserved13;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
+ public byte[] effective_date;
+ public byte reserved14;
+ public byte file_structure_version;
+ public byte reserved15;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
+ public byte[] application_data;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 653)]
+ public byte[] reserved16;
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ struct CdiDirectoryRecord
+ {
+ public byte length;
+ public byte xattr_len;
+ public uint reserved1;
+ public uint start_lbn;
+ public uint reserved2;
+ public uint size;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
+ public byte[] date;
+ public byte reserved3;
+ public CdiFileFlags flags;
+ public ushort file_unit_size;
+ public ushort reserved4;
+ public ushort volume_sequence_number;
+ public byte name_len;
+ // Followed by name[name_len] and then CdiSystemArea until length arrives
+ }
+
+ // Follows filename on directory record
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ struct CdiSystemArea
+ {
+ public uint owner;
+ public CdiAttributes attributes;
+ public ushort reserved1;
+ public byte file_no;
+ public byte reserved2;
+ }
+
+ static DecodedVolumeDescriptor DecodeVolumeDescriptor(FileStructureVolumeDescriptor pvd)
+ {
+ DecodedVolumeDescriptor decodedVD = new DecodedVolumeDescriptor();
+
+ decodedVD.SystemIdentifier = Encoding.ASCII.GetString(pvd.system_id).TrimEnd().Trim(new[] { '\0' });
+ decodedVD.VolumeIdentifier = Encoding.ASCII.GetString(pvd.volume_id).TrimEnd().Trim(new[] { '\0' });
+ decodedVD.VolumeSetIdentifier = Encoding.ASCII.GetString(pvd.volume_set_id).TrimEnd().Trim(new[] { '\0' });
+ decodedVD.PublisherIdentifier = Encoding.ASCII.GetString(pvd.publisher_id).TrimEnd().Trim(new[] { '\0' });
+ decodedVD.DataPreparerIdentifier = Encoding.ASCII.GetString(pvd.preparer_id).TrimEnd().Trim(new[] { '\0' });
+ decodedVD.ApplicationIdentifier = Encoding.ASCII.GetString(pvd.application_data).TrimEnd().Trim(new[] { '\0' });
+ if(pvd.creation_date[0] == '0' || pvd.creation_date[0] == 0x00)
+ decodedVD.CreationTime = System.DateTime.MinValue;
+ else
+ decodedVD.CreationTime = DateHandlers.HighSierraToDateTime(pvd.creation_date);
+
+ if(pvd.modification_date[0] == '0' || pvd.modification_date[0] == 0x00)
+ {
+ decodedVD.HasModificationTime = false;
+ }
+ else
+ {
+ decodedVD.HasModificationTime = true;
+ decodedVD.ModificationTime = DateHandlers.HighSierraToDateTime(pvd.modification_date);
+ }
+
+ if(pvd.expiration_date[0] == '0' || pvd.expiration_date[0] == 0x00)
+ {
+ decodedVD.HasExpirationTime = false;
+ }
+ else
+ {
+ decodedVD.HasExpirationTime = true;
+ decodedVD.ExpirationTime = DateHandlers.HighSierraToDateTime(pvd.expiration_date);
+ }
+
+ if(pvd.effective_date[0] == '0' || pvd.effective_date[0] == 0x00)
+ {
+ decodedVD.HasEffectiveTime = false;
+ }
+ else
+ {
+ decodedVD.HasEffectiveTime = true;
+ decodedVD.EffectiveTime = DateHandlers.HighSierraToDateTime(pvd.effective_date);
+ }
+
+ decodedVD.Blocks = pvd.volume_space_size;
+ decodedVD.BlockSize = pvd.logical_block_size;
+
+ return decodedVD;
+ }
+ }
+}
diff --git a/DiscImageChef.Filesystems/ISO9660/Structs/ISO.cs b/DiscImageChef.Filesystems/ISO9660/Structs/ISO.cs
index 4e461e13..5c54bd10 100644
--- a/DiscImageChef.Filesystems/ISO9660/Structs/ISO.cs
+++ b/DiscImageChef.Filesystems/ISO9660/Structs/ISO.cs
@@ -186,6 +186,17 @@ namespace DiscImageChef.Filesystems.ISO9660
public ushort app_use_len_be;
}
+ // There are two tables one in little endian one in big endian
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ struct PathTableEntry
+ {
+ public byte name_len;
+ public byte xattr_len;
+ public uint start_lbn;
+ public ushort parent_dirno;
+ // Followed by name[name_len]
+ }
+
static DecodedVolumeDescriptor DecodeVolumeDescriptor(PrimaryVolumeDescriptor pvd)
{
DecodedVolumeDescriptor decodedVD = new DecodedVolumeDescriptor();
diff --git a/DiscImageChef.Helpers/DateHandlers.cs b/DiscImageChef.Helpers/DateHandlers.cs
index 915f31b2..ee612530 100644
--- a/DiscImageChef.Helpers/DateHandlers.cs
+++ b/DiscImageChef.Helpers/DateHandlers.cs
@@ -88,6 +88,7 @@ namespace DiscImageChef
return ISO9660ToDateTime(isotime);
}
+ // TODO: Timezone
public static DateTime ISO9660ToDateTime(byte[] VDDateTime)
{
int year, month, day, hour, minute, second, hundredths;
diff --git a/README.md b/README.md
index a2175662..f339924a 100644
--- a/README.md
+++ b/README.md
@@ -136,6 +136,7 @@ Supported file systems for identification and information only
* BSD Fast File System (FFS) / Unix File System (UFS)
* BSD Unix File System 2 (UFS2)
* BeOS filesystem
+* CD-i file system
* Coherent UNIX file system
* Commodore 1540/1541/1571/1581 filesystems
* Cram file system