diff --git a/DiscImageChef.Filesystems/ISO9660/Consts.cs b/DiscImageChef.Filesystems/ISO9660/Consts.cs index 31708b1b3..fb653779e 100644 --- a/DiscImageChef.Filesystems/ISO9660/Consts.cs +++ b/DiscImageChef.Filesystems/ISO9660/Consts.cs @@ -42,6 +42,13 @@ namespace DiscImageChef.Filesystems.ISO9660 const ushort XaMagic = 0x5841; // "XA" const ushort AppleMagic = 0x4141; // "AA" const ushort AppleMagicOld = 0x4241; // "BA" + const ushort SUSP_Continuation = 0x4345; // "CE" + const ushort SUSP_Padding = 0x5044; // "PD" + const ushort SUSP_Indicator = 0x5350; // "SP" + const ushort SUSP_Terminator = 0x5354; // "ST" + const ushort SUSP_Reference = 0x4552; // "ER" + const ushort SUSP_Selector = 0x4553; // "ES" + const ushort SUSP_Magic = 0xBEEF; [Flags] enum FileFlags : byte diff --git a/DiscImageChef.Filesystems/ISO9660/Info.cs b/DiscImageChef.Filesystems/ISO9660/Info.cs index 0e6f81177..f528fa253 100644 --- a/DiscImageChef.Filesystems/ISO9660/Info.cs +++ b/DiscImageChef.Filesystems/ISO9660/Info.cs @@ -30,6 +30,7 @@ // Copyright © 2011-2017 Natalia Portillo // ****************************************************************************/ using System; +using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; using DiscImageChef.CommonTypes; @@ -255,6 +256,10 @@ namespace DiscImageChef.Filesystems.ISO9660 int rootOff = 0; bool XA = false; bool Apple = false; + bool SUSP = false; + List contareas = new List(); + List refareas = new List(); + StringBuilder suspInformation = new StringBuilder(); BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; @@ -331,6 +336,47 @@ namespace DiscImageChef.Filesystems.ISO9660 } } + // 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(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; + } + } + if(noneFound) break; } @@ -342,6 +388,61 @@ namespace DiscImageChef.Filesystems.ISO9660 break; } + 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(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++; + } + } // TODO: Check this /* @@ -376,6 +477,8 @@ namespace DiscImageChef.Filesystems.ISO9660 ISOMetadata.AppendLine("Apple extensions present."); if(jolietvd != null) ISOMetadata.AppendLine("Joliet extensions present."); + if(SUSP) + ISOMetadata.AppendLine("System Use Sharing Protocol present."); if(RockRidge) ISOMetadata.AppendLine("Rock Ridge Interchange Protocol present."); if(bvd != null) @@ -605,6 +708,9 @@ namespace DiscImageChef.Filesystems.ISO9660 } exit_torito: + if(refareas.Count > 0) + ISOMetadata.Append(suspInformation.ToString()); + xmlFSType.Type = HighSierra ? "High Sierra Format" : "ISO9660"; if(jolietvd != null) diff --git a/DiscImageChef.Filesystems/ISO9660/Structs.cs b/DiscImageChef.Filesystems/ISO9660/Structs.cs index 08f10426f..6c7896587 100644 --- a/DiscImageChef.Filesystems/ISO9660/Structs.cs +++ b/DiscImageChef.Filesystems/ISO9660/Structs.cs @@ -429,6 +429,70 @@ namespace DiscImageChef.Filesystems.ISO9660 public ushort finder_flags; } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct ContinuationArea + { + public ushort signature; + public byte length; + public byte version; + public uint block; + public uint block_be; + public uint offset; + public uint offset_be; + public uint ca_length; + public uint ca_length_be; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct PaddingArea + { + public ushort signature; + public byte length; + public byte version; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct IndicatorArea + { + public ushort signature; + public byte length; + public byte version; + public ushort magic; + public byte skipped; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct TerminatorArea + { + public ushort signature; + public byte length; + public byte version; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct ReferenceArea + { + public ushort signature; + public byte length; + public byte version; + public byte id_len; + public byte des_len; + public byte src_len; + public byte ext_ver; + // Follows extension identifier for id_len bytes + // Follows extension descriptor for des_len bytes + // Follows extension source for src_len bytes + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct SelectorArea + { + public ushort signature; + public byte length; + public byte version; + public byte sequence; + } + struct DecodedVolumeDescriptor { public string SystemIdentifier;