From 74a02a31944837dfb7a88bc8f1355bbe7a2be9f0 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Fri, 19 Jul 2019 14:59:35 +0100 Subject: [PATCH] Implement ISO9660 file record timestamp decoding. --- DiscImageChef.Filesystems/ISO9660/Date.cs | 18 +- .../ISO9660/Structs/ISO.cs | 199 +++++++++--------- .../ISO9660/Structs/Internal.cs | 2 +- 3 files changed, 123 insertions(+), 96 deletions(-) diff --git a/DiscImageChef.Filesystems/ISO9660/Date.cs b/DiscImageChef.Filesystems/ISO9660/Date.cs index 20810a984..e5c67e86b 100644 --- a/DiscImageChef.Filesystems/ISO9660/Date.cs +++ b/DiscImageChef.Filesystems/ISO9660/Date.cs @@ -4,6 +4,22 @@ namespace DiscImageChef.Filesystems.ISO9660 { public partial class ISO9660 { - DateTime DecodeIsoDateTime(byte[] date) => throw new NotImplementedException(); + DateTime? DecodeIsoDateTime(IsoTimestamp timestamp) + { + try + { + DateTime date = new DateTime(timestamp.Years + 1900, timestamp.Month, timestamp.Day, timestamp.Hour, + timestamp.Minute, timestamp.Second, DateTimeKind.Unspecified); + + date = date.AddMinutes(timestamp.GmtOffset * 15); + + return TimeZoneInfo.ConvertTimeToUtc(date, TimeZoneInfo.FindSystemTimeZoneById("GMT")); + } + catch(Exception e) + { + // ISO says timestamp can be unspecified + return null; + } + } } } \ No newline at end of file diff --git a/DiscImageChef.Filesystems/ISO9660/Structs/ISO.cs b/DiscImageChef.Filesystems/ISO9660/Structs/ISO.cs index 824de1735..d1a626da0 100644 --- a/DiscImageChef.Filesystems/ISO9660/Structs/ISO.cs +++ b/DiscImageChef.Filesystems/ISO9660/Structs/ISO.cs @@ -85,162 +85,173 @@ namespace DiscImageChef.Filesystems.ISO9660 [StructLayout(LayoutKind.Sequential, Pack = 1)] struct PrimaryVolumeDescriptor { - public byte type; + public readonly byte type; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] - public byte[] id; - public byte version; + public readonly byte[] id; + public readonly byte version; // Only used in SVDs - public byte flags; + public readonly byte flags; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public byte[] system_id; + public readonly byte[] system_id; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public byte[] volume_id; - public ulong reserved1; - public uint volume_space_size; - public uint volume_space_size_be; + public readonly byte[] volume_id; + public readonly ulong reserved1; + public readonly uint volume_space_size; + public readonly uint volume_space_size_be; // Only used in SVDs [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public byte[] escape_sequences; - public ushort volume_set_size; - public ushort volume_set_size_be; - public ushort volume_sequence_number; - public ushort volume_sequence_number_be; - public ushort logical_block_size; - public ushort logical_block_size_be; - public uint path_table_size; - public uint path_table_size_be; - public uint type_1_path_table; - public uint opt_type_1_path_table; - public uint type_m_path_table; - public uint opt_type_m_path_table; - public DirectoryRecord root_directory_record; - public byte root_directory_name; + public readonly byte[] escape_sequences; + public readonly ushort volume_set_size; + public readonly ushort volume_set_size_be; + public readonly ushort volume_sequence_number; + public readonly ushort volume_sequence_number_be; + public readonly ushort logical_block_size; + public readonly ushort logical_block_size_be; + public readonly uint path_table_size; + public readonly uint path_table_size_be; + public readonly uint type_1_path_table; + public readonly uint opt_type_1_path_table; + public readonly uint type_m_path_table; + public readonly uint opt_type_m_path_table; + public readonly DirectoryRecord root_directory_record; + public readonly byte root_directory_name; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] - public byte[] volume_set_id; + public readonly byte[] volume_set_id; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] - public byte[] publisher_id; + public readonly byte[] publisher_id; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] - public byte[] preparer_id; + public readonly byte[] preparer_id; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] - public byte[] application_id; + public readonly byte[] application_id; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 37)] - public byte[] copyright_file_id; + public readonly byte[] copyright_file_id; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 37)] - public byte[] abstract_file_id; + public readonly byte[] abstract_file_id; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 37)] - public byte[] bibliographic_file_id; + public readonly byte[] bibliographic_file_id; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] - public byte[] creation_date; + public readonly byte[] creation_date; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] - public byte[] modification_date; + public readonly byte[] modification_date; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] - public byte[] expiration_date; + public readonly byte[] expiration_date; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] - public byte[] effective_date; - public byte file_structure_version; - public byte reserved2; + public readonly byte[] effective_date; + public readonly byte file_structure_version; + public readonly byte reserved2; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)] - public byte[] application_data; + public readonly byte[] application_data; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 653)] - public byte[] reserved3; + public readonly byte[] reserved3; } [StructLayout(LayoutKind.Sequential, Pack = 1)] struct BootRecord { - public byte type; + public readonly byte type; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] - public byte[] id; - public byte version; + public readonly byte[] id; + public readonly byte version; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public byte[] system_id; + public readonly byte[] system_id; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public byte[] boot_id; + public readonly byte[] boot_id; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1977)] - public byte[] boot_use; + public readonly byte[] boot_use; } [StructLayout(LayoutKind.Sequential, Pack = 1)] struct PartitionDescriptor { - public byte type; + public readonly byte type; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] - public byte[] id; - public byte version; - public byte reserved1; + public readonly byte[] id; + public readonly byte version; + public readonly byte reserved1; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public byte[] system_id; + public readonly byte[] system_id; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public byte[] partition_id; - public uint partition_location; - public uint partition_location_be; - public uint partition_size; - public uint partition_size_be; + public readonly byte[] partition_id; + public readonly uint partition_location; + public readonly uint partition_location_be; + public readonly uint partition_size; + public readonly uint partition_size_be; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1960)] - public byte[] system_use; + public readonly byte[] system_use; } [StructLayout(LayoutKind.Sequential, Pack = 1)] struct DirectoryRecord { - public byte length; - public byte xattr_len; - public uint extent; - public uint extent_be; - public uint size; - public uint size_be; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] - public byte[] date; - public FileFlags flags; - public byte file_unit_size; - public byte interleave; - public ushort volume_sequence_number; - public ushort volume_sequence_number_be; - public byte name_len; + public readonly byte length; + public readonly byte xattr_len; + public readonly uint extent; + public readonly uint extent_be; + public readonly uint size; + public readonly uint size_be; + public readonly IsoTimestamp date; + public readonly FileFlags flags; + public readonly byte file_unit_size; + public readonly byte interleave; + public readonly ushort volume_sequence_number; + public readonly ushort volume_sequence_number_be; + public readonly byte name_len; // Followed by name[name_len] and then system area until length arrives } [StructLayout(LayoutKind.Sequential, Pack = 1)] struct ExtendedAttributeRecord { - public ushort owner; - public ushort owner_be; - public ushort group; - public ushort group_be; - public Permissions permissions; + public readonly ushort owner; + public readonly ushort owner_be; + public readonly ushort group; + public readonly ushort group_be; + public readonly Permissions permissions; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] - public byte[] creation_date; + public readonly byte[] creation_date; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] - public byte[] modification_date; + public readonly byte[] modification_date; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] - public byte[] expiration_date; + public readonly byte[] expiration_date; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] - public byte[] effective_date; - public RecordFormat record_format; - public RecordAttribute record_attributes; - public ushort record_length; - public ushort record_length_be; + public readonly byte[] effective_date; + public readonly RecordFormat record_format; + public readonly RecordAttribute record_attributes; + public readonly ushort record_length; + public readonly ushort record_length_be; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public byte[] system_id; + public readonly byte[] system_id; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public byte[] system_use; - public byte record_version; - public byte escape_len; + public readonly byte[] system_use; + public readonly byte record_version; + public readonly byte escape_len; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public byte[] reserved1; - public ushort app_use_len; - public ushort app_use_len_be; + public readonly byte[] reserved1; + public readonly ushort app_use_len; + public readonly 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; + public readonly byte name_len; + public readonly byte xattr_len; + public readonly uint start_lbn; + public readonly ushort parent_dirno; // Followed by name[name_len] } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct IsoTimestamp + { + public readonly byte Years; + public readonly byte Month; + public readonly byte Day; + public readonly byte Hour; + public readonly byte Minute; + public readonly byte Second; + public readonly sbyte GmtOffset; + } } } \ No newline at end of file diff --git a/DiscImageChef.Filesystems/ISO9660/Structs/Internal.cs b/DiscImageChef.Filesystems/ISO9660/Structs/Internal.cs index ed9932fc9..804468805 100644 --- a/DiscImageChef.Filesystems/ISO9660/Structs/Internal.cs +++ b/DiscImageChef.Filesystems/ISO9660/Structs/Internal.cs @@ -64,7 +64,7 @@ namespace DiscImageChef.Filesystems.ISO9660 public byte Interleave; public ushort VolumeSequenceNumber; public string IsoFilename; - public DateTime Timestamp; + public DateTime? Timestamp; public override string ToString() => IsoFilename; }