diff --git a/Aaru.Archives/Aaru.Archives.csproj b/Aaru.Archives/Aaru.Archives.csproj index d40894f9a..5ab453eb7 100644 --- a/Aaru.Archives/Aaru.Archives.csproj +++ b/Aaru.Archives/Aaru.Archives.csproj @@ -51,6 +51,7 @@ + diff --git a/Aaru.Archives/Localization/Localization.Designer.cs b/Aaru.Archives/Localization/Localization.Designer.cs index b8d997d47..9574ce670 100644 --- a/Aaru.Archives/Localization/Localization.Designer.cs +++ b/Aaru.Archives/Localization/Localization.Designer.cs @@ -506,5 +506,149 @@ namespace Aaru.Archives { return ResourceManager.GetString("Conditions", resourceCulture); } } + + internal static string Console_package { + get { + return ResourceManager.GetString("Console_package", resourceCulture); + } + } + + internal static string Live_package { + get { + return ResourceManager.GetString("Live_package", resourceCulture); + } + } + + internal static string Microsoft_package { + get { + return ResourceManager.GetString("Microsoft_package", resourceCulture); + } + } + + internal static string Certificate_owner_console_ID_0_1_2_3_4 { + get { + return ResourceManager.GetString("Certificate_owner_console_ID_0_1_2_3_4", resourceCulture); + } + } + + internal static string Certificate_owner_console_part_number_0 { + get { + return ResourceManager.GetString("Certificate_owner_console_part_number_0", resourceCulture); + } + } + + internal static string Certificate_owner_console_type_0 { + get { + return ResourceManager.GetString("Certificate_owner_console_type_0", resourceCulture); + } + } + + internal static string Certificate_date_of_generation_0 { + get { + return ResourceManager.GetString("Certificate_date_of_generation_0", resourceCulture); + } + } + + internal static string Signatures_SHA1_0 { + get { + return ResourceManager.GetString("Signatures_SHA1_0", resourceCulture); + } + } + + internal static string Header_size_0 { + get { + return ResourceManager.GetString("Header_size_0", resourceCulture); + } + } + + internal static string Content_type_0 { + get { + return ResourceManager.GetString("Content_type_0", resourceCulture); + } + } + + internal static string Content_size_0 { + get { + return ResourceManager.GetString("Content_size_0", resourceCulture); + } + } + + internal static string Title_ID_0 { + get { + return ResourceManager.GetString("Title_ID_0", resourceCulture); + } + } + + internal static string Media_ID_0 { + get { + return ResourceManager.GetString("Media_ID_0", resourceCulture); + } + } + + internal static string Publisher_name_0 { + get { + return ResourceManager.GetString("Publisher_name_0", resourceCulture); + } + } + + internal static string Title_name_0 { + get { + return ResourceManager.GetString("Title_name_0", resourceCulture); + } + } + + internal static string Metadata_version_0 { + get { + return ResourceManager.GetString("Metadata_version_0", resourceCulture); + } + } + + internal static string Version_0 { + get { + return ResourceManager.GetString("Version_0", resourceCulture); + } + } + + internal static string Base_version_0 { + get { + return ResourceManager.GetString("Base_version_0", resourceCulture); + } + } + + internal static string Descriptor_type_0 { + get { + return ResourceManager.GetString("Descriptor_type_0", resourceCulture); + } + } + + internal static string Display_name_0 { + get { + return ResourceManager.GetString("Display_name_0", resourceCulture); + } + } + + internal static string Display_description_0 { + get { + return ResourceManager.GetString("Display_description_0", resourceCulture); + } + } + + internal static string Device_ID_0 { + get { + return ResourceManager.GetString("Device_ID_0", resourceCulture); + } + } + + internal static string Console_ID_0 { + get { + return ResourceManager.GetString("Console_ID_0", resourceCulture); + } + } + + internal static string Profile_ID_0 { + get { + return ResourceManager.GetString("Profile_ID_0", resourceCulture); + } + } } } diff --git a/Aaru.Archives/Localization/Localization.es.resx b/Aaru.Archives/Localization/Localization.es.resx index 3dd27255c..3f6d9414b 100644 --- a/Aaru.Archives/Localization/Localization.es.resx +++ b/Aaru.Archives/Localization/Localization.es.resx @@ -246,4 +246,76 @@ [bold][slateblue1]Condiciones:[/][/] + + [bold][slateblue1]Versión base:[/][/] [teal]{0}[/] + + + [bold][slateblue1]Fecha de generación del certificado:[/][/] [aqua]{0}[/] + + + [bold][slateblue1]ID de consola dueña del certificado:[/][/] [teal]{0:X2}{1:X2}{2:X2}{3:X2}{4:X2}[/] + + + [bold][slateblue1]Número de parte de consola dueña del certificado:[/][/] [teal]{0}[/] + + + [bold][slateblue1]Tipo de consola dueña del certificado:[/][/] [green]{0}[/] + + + [bold][slateblue1]ID de consola:[/][/] [teal]{0}[/] + + + [bold][blue]Paquete de consola:[/][/] + + + [bold][slateblue1]Tamaño del contenido:[/][/] [lime]{0}[/] + + + [bold][slateblue1]Tipo del contenido:[/][/] [green]{0}[/] + + + [bold][slateblue1]Tipo del descriptor:[/][/] [teal]{0}[/] + + + [bold][slateblue1]ID del dispositivo:[/][/] [teal]{0}[/] + + + [bold][slateblue1]Descripción:[/][/] [green]{0}[/] + + + [bold][slateblue1]Nombre:[/][/] [green]{0}[/] + + + [bold][slateblue1]Tamaño de cabecera:[/][/] [lime]{0}[/] + + + [bold][blue]Paquete Live!:[/][/] + + + [bold][slateblue1]ID del medio:[/][/] [teal]{0:X8}[/] + + + [bold][slateblue1]Versión de los metadatos:[/][/] [teal]{0}[/] + + + [bold][blue]Paquete de Microsoft:[/][/] + + + [bold][slateblue1]ID del perfil:[/][/] [teal]{0}[/] + + + [bold][slateblue1]Nombre del publicador:[/][/] [green]{0}[/] + + + [bold][slateblue1]SHA1 de la firma:[/][/] [teal]{0}[/] + + + [bold][slateblue1]Título:[/][/] [green]{0}[/] + + + [bold][slateblue1]ID del título:[/][/] [teal]{0:X8}[/] + + + [bold][slateblue1]Versión:[/][/] [teal]{0}[/] + \ No newline at end of file diff --git a/Aaru.Archives/Localization/Localization.resx b/Aaru.Archives/Localization/Localization.resx index bbc73cd3b..8d843eb73 100644 --- a/Aaru.Archives/Localization/Localization.resx +++ b/Aaru.Archives/Localization/Localization.resx @@ -254,4 +254,76 @@ [bold][slateblue1]Conditions:[/][/] + + [bold][blue]Console package:[/][/] + + + [bold][blue]Live! package:[/][/] + + + [bold][blue]Microsoft package:[/][/] + + + [bold][slateblue1]Certificate owner console ID:[/][/] [teal]{0:X2}{1:X2}{2:X2}{3:X2}{4:X2}[/] + + + [bold][slateblue1]Certificate owner console part number:[/][/] [teal]{0}[/] + + + [bold][slateblue1]Certificate owner console type:[/][/] [green]{0}[/] + + + [bold][slateblue1]Certificate date of generation:[/][/] [aqua]{0}[/] + + + [bold][slateblue1]Signature's SHA1:[/][/] [teal]{0}[/] + + + [bold][slateblue1]Header size:[/][/] [lime]{0}[/] + + + [bold][slateblue1]Content type:[/][/] [green]{0}[/] + + + [bold][slateblue1]Content size:[/][/] [lime]{0}[/] + + + [bold][slateblue1]Title ID:[/][/] [teal]{0:X8}[/] + + + [bold][slateblue1]Media ID:[/][/] [teal]{0:X8}[/] + + + [bold][slateblue1]Publisher name:[/][/] [green]{0}[/] + + + [bold][slateblue1]Title name:[/][/] [green]{0}[/] + + + [bold][slateblue1]Metadata version:[/][/] [teal]{0}[/] + + + [bold][slateblue1]Version:[/][/] [teal]{0}[/] + + + [bold][slateblue1]Base version:[/][/] [teal]{0}[/] + + + [bold][slateblue1]Descriptor type:[/][/] [teal]{0}[/] + + + [bold][slateblue1]Display name:[/][/] [green]{0}[/] + + + [bold][slateblue1]Display description:[/][/] [green]{0}[/] + + + [bold][slateblue1]Device ID:[/][/] [teal]{0}[/] + + + [bold][slateblue1]Console ID:[/][/] [teal]{0}[/] + + + [bold][slateblue1]Profile ID:[/][/] [teal]{0}[/] + \ No newline at end of file diff --git a/Aaru.Archives/Stfs/Info.cs b/Aaru.Archives/Stfs/Info.cs index af73d6abc..bde5b5183 100644 --- a/Aaru.Archives/Stfs/Info.cs +++ b/Aaru.Archives/Stfs/Info.cs @@ -1,12 +1,19 @@ using System; using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; using Aaru.CommonTypes.Interfaces; using Aaru.Helpers; +using Humanizer; +using Spectre.Console; namespace Aaru.Archives; public sealed partial class Stfs { +#region IArchive Members + /// public bool Identify(IFilter filter) { @@ -21,6 +28,140 @@ public sealed partial class Stfs RemotePackage header = Marshal.ByteArrayToStructureBigEndian(hdr); - return header.Magic is PackageMagic.Console or PackageMagic.Live or PackageMagic.Microsoft; + if(header.Magic is not (PackageMagic.Console or PackageMagic.Live or PackageMagic.Microsoft)) return false; + + // SVOD is managed as a media image + return header.Metadata.DescriptorType == 0; + } + + /// + public void GetInformation(IFilter filter, Encoding encoding, out string information) + { + information = ""; + + if(filter.DataForkLength < Marshal.SizeOf()) return; + + Stream stream = filter.GetDataForkStream(); + stream.Position = 0; + + byte[] hdr = new byte[Marshal.SizeOf()]; + + stream.ReadExactly(hdr, 0, hdr.Length); + + // Reverse positions that hold UTF16-BE strings + ReverseShorts(hdr, 0x0411, 0x1300); + + RemotePackage header = Marshal.ByteArrayToStructureBigEndian(hdr); + + if(header.Magic is not (PackageMagic.Console or PackageMagic.Live or PackageMagic.Microsoft)) return; + + // SVOD is managed as a media image + if(header.Metadata.DescriptorType != 0) return; + + var sb = new StringBuilder(); + + switch(header.Magic) + { + case PackageMagic.Console: + sb.AppendLine(Localization.Console_package); + + break; + case PackageMagic.Live: + sb.AppendLine(Localization.Live_package); + + break; + case PackageMagic.Microsoft: + sb.AppendLine(Localization.Microsoft_package); + + break; + } + + if(header.Magic == PackageMagic.Console) + { + ConsolePackage consolePackage = Marshal.ByteArrayToStructureBigEndian(hdr); + + sb.AppendFormat(Localization.Certificate_owner_console_ID_0_1_2_3_4, + consolePackage.CertificateOwnerConsoleId[0], + consolePackage.CertificateOwnerConsoleId[1], + consolePackage.CertificateOwnerConsoleId[2], + consolePackage.CertificateOwnerConsoleId[3], + consolePackage.CertificateOwnerConsoleId[4]) + .AppendLine(); + + sb.AppendFormat(Localization.Certificate_owner_console_part_number_0, + Markup.Escape(consolePackage.CertificateOwnerConsolePartNumber)) + .AppendLine(); + + sb.AppendFormat(Localization.Certificate_owner_console_type_0, consolePackage.CertificateOwnerConsoleType) + .AppendLine(); + + sb.AppendFormat(Localization.Certificate_date_of_generation_0, + Markup.Escape(consolePackage.CertificateDateOfGeneration)) + .AppendLine(); + } + else + { + // Calculate signature's SHA1 + using var sha1 = SHA1.Create(); + byte[] signatureSha1 = sha1.ComputeHash(header.Signature); + + sb.AppendFormat(Localization.Signatures_SHA1_0, BitConverter.ToString(signatureSha1).Replace("-", "")) + .AppendLine(); + } + + sb.AppendFormat(Localization.Header_size_0, header.Metadata.HeaderSize).AppendLine(); + sb.AppendFormat(Localization.Content_type_0, header.Metadata.ContentType.Humanize()).AppendLine(); + + if(header.Metadata.ContentSize > 0) + sb.AppendFormat(Localization.Content_size_0, header.Metadata.ContentSize).AppendLine(); + + if(header.Metadata.TitleId > 0) sb.AppendFormat(Localization.Title_ID_0, header.Metadata.TitleId).AppendLine(); + if(header.Metadata.MediaId > 0) sb.AppendFormat(Localization.Media_ID_0, header.Metadata.MediaId).AppendLine(); + + if(header.Metadata.PublisherName != "") + sb.AppendFormat(Localization.Publisher_name_0, header.Metadata.PublisherName).AppendLine(); + + if(header.Metadata.TitleName != "") + sb.AppendFormat(Localization.Title_name_0, header.Metadata.TitleName).AppendLine(); + + sb.AppendFormat(Localization.Metadata_version_0, header.Metadata.MetadataVersion).AppendLine(); + if(header.Metadata.Version > 0) sb.AppendFormat(Localization.Version_0, header.Metadata.Version).AppendLine(); + + if(header.Metadata.BaseVersion > 0) + sb.AppendFormat(Localization.Base_version_0, header.Metadata.BaseVersion).AppendLine(); + + sb.AppendFormat(Localization.Descriptor_type_0, header.Metadata.DescriptorType).AppendLine(); + + foreach(LocalizedString displayName in + header.Metadata.DisplayName.Where(displayName => displayName.Name is not "")) + sb.AppendFormat(Localization.Display_name_0, displayName.Name).AppendLine(); + + foreach(LocalizedString description in + header.Metadata.DisplayDescription.Where(description => description.Name is not "")) + sb.AppendFormat(Localization.Display_description_0, description.Name).AppendLine(); + + if(header.Metadata.DeviceId.Any(c => c != 0x00)) + sb.AppendFormat(Localization.Device_ID_0, + StringHandlers.CToString(header.Metadata.DeviceId, Encoding.ASCII).Trim()) + .AppendLine(); + + if(header.Metadata.ConsoleId.Any(c => c != 0x00)) + sb.AppendFormat(Localization.Console_ID_0, + BitConverter.ToString(header.Metadata.ConsoleId).Replace("-", "")) + .AppendLine(); + + if(header.Metadata.ProfileId.Any(c => c != 0x00)) + sb.AppendFormat(Localization.Profile_ID_0, + BitConverter.ToString(header.Metadata.ProfileId).Replace("-", "")) + .AppendLine(); + + information = sb.ToString(); + } + +#endregion + + static void ReverseShorts(byte[] shorts, int start, int count) + { + for(int i = start; i < start + count; i += 2) (shorts[i], shorts[i + 1]) = (shorts[i + 1], shorts[i]); } } \ No newline at end of file diff --git a/Aaru.Archives/Stfs/Structs.cs b/Aaru.Archives/Stfs/Structs.cs index 70cd76dff..3987c9790 100644 --- a/Aaru.Archives/Stfs/Structs.cs +++ b/Aaru.Archives/Stfs/Structs.cs @@ -6,7 +6,7 @@ public sealed partial class Stfs { #region Nested type: ConsolePackage - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] struct ConsolePackage { public PackageMagic Magic; @@ -48,7 +48,7 @@ public sealed partial class Stfs [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)] struct LocalizedString { - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string Name; } @@ -96,9 +96,9 @@ public sealed partial class Stfs public byte[] Padding; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] public byte[] DeviceId; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 18)] + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)] public LocalizedString[] DisplayName; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 18)] + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)] public LocalizedString[] DisplayDescription; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public string PublisherName; diff --git a/Aaru.Archives/Stfs/Unimplemented.cs b/Aaru.Archives/Stfs/Unimplemented.cs index 3cd4440a0..055aeb1db 100644 --- a/Aaru.Archives/Stfs/Unimplemented.cs +++ b/Aaru.Archives/Stfs/Unimplemented.cs @@ -12,7 +12,6 @@ public sealed partial class Stfs { #region IArchive Members - /// public ErrorNumber Open(IFilter filter, Encoding encoding) => throw new NotImplementedException(); @@ -52,11 +51,5 @@ public sealed partial class Stfs /// public ErrorNumber GetEntry(int entryNumber, out IFilter filter) => throw new NotImplementedException(); - /// - public void GetInformation(IFilter filter, Encoding encoding, out string information) - { - throw new NotImplementedException(); - } - #endregion } \ No newline at end of file