diff --git a/SabreTools.Serialization/Extensions/StringBuilderExtensions.cs b/SabreTools.Serialization/Extensions/StringBuilderExtensions.cs index a29f7833..9f339e68 100644 --- a/SabreTools.Serialization/Extensions/StringBuilderExtensions.cs +++ b/SabreTools.Serialization/Extensions/StringBuilderExtensions.cs @@ -455,6 +455,24 @@ namespace SabreTools.Data.Extensions return sb.AppendLine($"{prefixString}: {valueString}"); } + /// + /// Append a line containing a String[] value to a StringBuilder + /// + public static StringBuilder AppendLine(this StringBuilder sb, string?[]? value, string prefixString) + { + string valueString = "[NULL]"; + if (value is not null) + { + var valueArr = Array.ConvertAll(value, s => s is null ? "[NULL]" : s); + valueString = string.Join(", ", valueArr); + } + + if (valueString.Length == 0) + return sb.AppendLine($"{prefixString}: [EMPTY]"); + + return sb.AppendLine($"{prefixString}: {valueString}"); + } + /// /// Append a line containing a UInt64[] value to a StringBuilder /// diff --git a/SabreTools.Serialization/Models/XboxExecutable/Certificate.cs b/SabreTools.Serialization/Models/XboxExecutable/Certificate.cs index e27cb131..fbfa7d78 100644 --- a/SabreTools.Serialization/Models/XboxExecutable/Certificate.cs +++ b/SabreTools.Serialization/Models/XboxExecutable/Certificate.cs @@ -35,7 +35,7 @@ namespace SabreTools.Data.Models.XboxExecutable /// to matter with unsigned code (or signed code, for that matter), so they can all /// be set to zero. /// - public uint[] AlternativeTitleIDs { get; set; } = new uint[16]; + public byte[][] AlternativeTitleIDs { get; set; } = new byte[16][]; /// /// Allowed media types for this .XBE. diff --git a/SabreTools.Serialization/Readers/XboxExecutable.cs b/SabreTools.Serialization/Readers/XboxExecutable.cs index 24f0a471..a27b40fe 100644 --- a/SabreTools.Serialization/Readers/XboxExecutable.cs +++ b/SabreTools.Serialization/Readers/XboxExecutable.cs @@ -156,10 +156,10 @@ namespace SabreTools.Serialization.Readers obj.TitleID = data.ReadBytes(4); obj.TitleName = data.ReadBytes(0x50); - obj.AlternativeTitleIDs = new uint[16]; + obj.AlternativeTitleIDs = new byte[16][]; for (int i = 0; i < obj.AlternativeTitleIDs.Length; i++) { - obj.AlternativeTitleIDs[i] = data.ReadUInt32LittleEndian(); + obj.AlternativeTitleIDs[i] = data.ReadBytes(4); } obj.AllowedMediaTypes = (AllowedMediaTypes)data.ReadUInt32LittleEndian(); diff --git a/SabreTools.Serialization/Wrappers/XboxExecutable.Printing.cs b/SabreTools.Serialization/Wrappers/XboxExecutable.Printing.cs index 1a8a5ed4..8fe3c454 100644 --- a/SabreTools.Serialization/Wrappers/XboxExecutable.Printing.cs +++ b/SabreTools.Serialization/Wrappers/XboxExecutable.Printing.cs @@ -1,3 +1,4 @@ +using System; using System.Text; using SabreTools.Data.Extensions; using SabreTools.Data.Models.XboxExecutable; @@ -45,6 +46,7 @@ namespace SabreTools.Serialization.Wrappers builder.AppendLine(certificate.TitleName, " Title name"); builder.AppendLine(Encoding.Unicode.GetString(certificate.TitleName).TrimEnd('\0'), " Title name (Unicode)"); builder.AppendLine(certificate.AlternativeTitleIDs, " Alternative title IDs"); + builder.AppendLine(Array.ConvertAll(certificate.AlternativeTitleIDs, b => b.ToFormattedXBETitleID()), " Alternative title IDs (Formatted)"); builder.AppendLine($" Allowed media types: {certificate.AllowedMediaTypes} (0x{certificate.AllowedMediaTypes:X})"); builder.AppendLine($" Game region: {certificate.GameRegion} (0x{certificate.GameRegion:X})"); builder.AppendLine(certificate.GameRatings, " Game ratings"); diff --git a/SabreTools.Serialization/Wrappers/XboxExecutable.cs b/SabreTools.Serialization/Wrappers/XboxExecutable.cs index 425c96e7..729d67fd 100644 --- a/SabreTools.Serialization/Wrappers/XboxExecutable.cs +++ b/SabreTools.Serialization/Wrappers/XboxExecutable.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using System.Text; using SabreTools.Data.Extensions; @@ -16,6 +17,22 @@ namespace SabreTools.Serialization.Wrappers #region Extension Properties + /// + public byte[][]? AlternativeTitleIDsBytes => Certificate?.AlternativeTitleIDs; + + /// + public string[]? AlternativeTitleIDsStrings + { + get + { + // Ignore invalid alternative title IDs + if (AlternativeTitleIDsBytes is null) + return null; + + return Array.ConvertAll(AlternativeTitleIDsBytes, ba => ba.ToFormattedXBETitleID() ?? "[NULL]"); + } + } + /// public uint BaseAddress => Model.Header?.BaseAddress ?? 0;