From 574b993985832a21fb90fef7c68778c83bc31fad Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Tue, 7 Apr 2026 22:20:14 -0400 Subject: [PATCH] Editorconfig cleanup of STFS --- .../STFS/ConsoleSignature.cs | 2 - SabreTools.Data.Models/STFS/Constants.cs | 2 - SabreTools.Data.Models/STFS/HashTable.cs | 4 +- SabreTools.Data.Models/STFS/HashTableEntry.cs | 1 - SabreTools.Data.Models/STFS/Header.cs | 4 +- SabreTools.Data.Models/STFS/LicenseEntry.cs | 2 - .../STFS/MicrosoftSignature.cs | 2 - SabreTools.Data.Models/STFS/STFSDescriptor.cs | 1 - SabreTools.Data.Models/STFS/SVODDescriptor.cs | 1 - SabreTools.Data.Models/STFS/Signature.cs | 2 - SabreTools.Data.Models/STFS/Volume.cs | 2 - .../STFS/VolumeDescriptor.cs | 2 - SabreTools.Serialization.Readers/STFS.cs | 454 +++++++++--------- SabreTools.Wrappers/STFS.Printing.cs | 9 +- SabreTools.Wrappers/STFS.cs | 1 - 15 files changed, 233 insertions(+), 256 deletions(-) diff --git a/SabreTools.Data.Models/STFS/ConsoleSignature.cs b/SabreTools.Data.Models/STFS/ConsoleSignature.cs index b590a8ab..ecb0bc40 100644 --- a/SabreTools.Data.Models/STFS/ConsoleSignature.cs +++ b/SabreTools.Data.Models/STFS/ConsoleSignature.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace SabreTools.Data.Models.STFS { /// diff --git a/SabreTools.Data.Models/STFS/Constants.cs b/SabreTools.Data.Models/STFS/Constants.cs index 302bb93a..2e719722 100644 --- a/SabreTools.Data.Models/STFS/Constants.cs +++ b/SabreTools.Data.Models/STFS/Constants.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace SabreTools.Data.Models.STFS { /// diff --git a/SabreTools.Data.Models/STFS/HashTable.cs b/SabreTools.Data.Models/STFS/HashTable.cs index 6acf27c5..ea6d1992 100644 --- a/SabreTools.Data.Models/STFS/HashTable.cs +++ b/SabreTools.Data.Models/STFS/HashTable.cs @@ -1,9 +1,7 @@ -using System.Collections.Generic; - namespace SabreTools.Data.Models.STFS { /// - /// STFS Hash Table in a Hash Table Block + /// STFS Hash Table in a Hash Table Block /// /// public class HashTable diff --git a/SabreTools.Data.Models/STFS/HashTableEntry.cs b/SabreTools.Data.Models/STFS/HashTableEntry.cs index b92888db..065082b7 100644 --- a/SabreTools.Data.Models/STFS/HashTableEntry.cs +++ b/SabreTools.Data.Models/STFS/HashTableEntry.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using SabreTools.Numerics; namespace SabreTools.Data.Models.STFS diff --git a/SabreTools.Data.Models/STFS/Header.cs b/SabreTools.Data.Models/STFS/Header.cs index 1d88fc2f..6ff6cc94 100644 --- a/SabreTools.Data.Models/STFS/Header.cs +++ b/SabreTools.Data.Models/STFS/Header.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace SabreTools.Data.Models.STFS { /// @@ -30,7 +28,7 @@ namespace SabreTools.Data.Models.STFS public LicenseEntry[] LicensingData { get; set; } = new LicenseEntry[16]; /// - /// SHA-1 Integrity Hash of the header (from ContentType/0x344 to first hash table) + /// SHA-1 Integrity Hash of the header (from ContentType/0x344 to first hash table) /// /// 20 bytes public byte[] HeaderHash { get; set; } = new byte[20]; diff --git a/SabreTools.Data.Models/STFS/LicenseEntry.cs b/SabreTools.Data.Models/STFS/LicenseEntry.cs index 93f97ae7..f6149219 100644 --- a/SabreTools.Data.Models/STFS/LicenseEntry.cs +++ b/SabreTools.Data.Models/STFS/LicenseEntry.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace SabreTools.Data.Models.STFS { /// diff --git a/SabreTools.Data.Models/STFS/MicrosoftSignature.cs b/SabreTools.Data.Models/STFS/MicrosoftSignature.cs index 9bdab7c7..3fa9c61f 100644 --- a/SabreTools.Data.Models/STFS/MicrosoftSignature.cs +++ b/SabreTools.Data.Models/STFS/MicrosoftSignature.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace SabreTools.Data.Models.STFS { /// diff --git a/SabreTools.Data.Models/STFS/STFSDescriptor.cs b/SabreTools.Data.Models/STFS/STFSDescriptor.cs index 8a79fcd0..8678d540 100644 --- a/SabreTools.Data.Models/STFS/STFSDescriptor.cs +++ b/SabreTools.Data.Models/STFS/STFSDescriptor.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using SabreTools.Numerics; namespace SabreTools.Data.Models.STFS diff --git a/SabreTools.Data.Models/STFS/SVODDescriptor.cs b/SabreTools.Data.Models/STFS/SVODDescriptor.cs index f543d26f..a6832b83 100644 --- a/SabreTools.Data.Models/STFS/SVODDescriptor.cs +++ b/SabreTools.Data.Models/STFS/SVODDescriptor.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using SabreTools.Numerics; namespace SabreTools.Data.Models.STFS diff --git a/SabreTools.Data.Models/STFS/Signature.cs b/SabreTools.Data.Models/STFS/Signature.cs index efd795f9..8ed435d6 100644 --- a/SabreTools.Data.Models/STFS/Signature.cs +++ b/SabreTools.Data.Models/STFS/Signature.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace SabreTools.Data.Models.STFS { /// diff --git a/SabreTools.Data.Models/STFS/Volume.cs b/SabreTools.Data.Models/STFS/Volume.cs index 968a32e7..543602f5 100644 --- a/SabreTools.Data.Models/STFS/Volume.cs +++ b/SabreTools.Data.Models/STFS/Volume.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace SabreTools.Data.Models.STFS { /// diff --git a/SabreTools.Data.Models/STFS/VolumeDescriptor.cs b/SabreTools.Data.Models/STFS/VolumeDescriptor.cs index d3e95d24..54fe928d 100644 --- a/SabreTools.Data.Models/STFS/VolumeDescriptor.cs +++ b/SabreTools.Data.Models/STFS/VolumeDescriptor.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace SabreTools.Data.Models.STFS { /// diff --git a/SabreTools.Serialization.Readers/STFS.cs b/SabreTools.Serialization.Readers/STFS.cs index 8e778874..9597e517 100644 --- a/SabreTools.Serialization.Readers/STFS.cs +++ b/SabreTools.Serialization.Readers/STFS.cs @@ -1,228 +1,226 @@ -using System.Collections.Generic; -using System.IO; -using SabreTools.Data.Models.STFS; -using SabreTools.IO.Extensions; -using SabreTools.Numerics; -using SabreTools.Numerics.Extensions; - -namespace SabreTools.Serialization.Readers -{ - public class STFS : BaseBinaryReader - { - /// - public override Volume? Deserialize(Stream? data) - { - // If the data is invalid - if (data is null || !data.CanRead) - return null; - - // Simple check for a valid stream length - if (Constants.StandardHeaderSize > data.Length - data.Position) - return null; - - try - { - // Cache the current offset - long initialOffset = data.Position; - - // Create a new Volume to fill - var volume = new Volume(); - - // Read and validate the header - var header = ParseHeader(data); - if (header is null) - return null; - - volume.Header = header; - - // TODO: Parse the hash table blocks - - // Don't parse the data blocks into memory - - return volume; - } - catch - { - // Ignore the actual error - return null; - } - } - - /// - /// Parse a Stream into a Header - /// - /// Stream to parse - /// Filled Header on success, null on error - public static Header? ParseHeader(Stream data) - { - var obj = new Header(); - - obj.MagicBytes = data.ReadBytes(4); - var signature = System.Text.Encoding.ASCII.GetString(obj.MagicBytes); - bool remoteSigned = signature.Equals(Constants.MagicStringLIVE) | signature.Equals(Constants.MagicStringPIRS); - if (!remoteSigned && !signature.Equals(Constants.MagicStringCON)) - return null; - - obj.Signature = ParseSignature(data, remoteSigned); - - obj.LicensingData = ParseLicensingData(data); - - obj.HeaderHash = data.ReadBytes(20); - obj.HeaderSize = data.ReadUInt32BigEndian(); - obj.ContentType = data.ReadInt32BigEndian(); - obj.MetadataVersion = data.ReadInt32BigEndian(); - obj.ContentSize = data.ReadInt64BigEndian(); - obj.MediaID = data.ReadUInt32BigEndian(); - obj.Version = data.ReadInt32BigEndian(); - obj.BaseVersion = data.ReadInt32BigEndian(); - obj.TitleID = data.ReadUInt32BigEndian(); - obj.Platform = data.ReadByteValue(); - obj.ExecutableType = data.ReadByteValue(); - obj.DiscNumber = data.ReadByteValue(); - obj.DiscInSet = data.ReadByteValue(); - obj.SaveGameID = data.ReadUInt32BigEndian(); - obj.ConsoleID = data.ReadBytes(5); - obj.ProfileID = data.ReadBytes(8); - - // Peek forward to read whether VolumeDescriptor is SVOD or STFS - byte[] peeked = data.PeekBytes(52); - bool svod = peeked[51] == 0x01; - obj.VolumeDescriptor = ParseVolumeDescriptor(data, svod); - - obj.DataFileCount = data.ReadInt32BigEndian(); - obj.DataFileCombinedSize = data.ReadInt64BigEndian(); - obj.DescriptorType = data.ReadUInt32BigEndian(); - obj.Reserved = data.ReadUInt32BigEndian(); - - if (obj.MetadataVersion == 2) - { - obj.SeriesID = data.ReadBytes(16); - obj.SeasonID = data.ReadBytes(16); - obj.SeasonNumber = data.ReadInt16BigEndian(); - obj.EpisodeNumber = data.ReadInt16BigEndian(); - obj.Padding = data.ReadBytes(40); - } - else - { - obj.Padding = data.ReadBytes(76); - } - - obj.DeviceID = data.ReadBytes(20); - obj.DisplayName = data.ReadBytes(2304); - obj.DisplayDescription = data.ReadBytes(2304); - obj.PublisherName = data.ReadBytes(128); - obj.TitleName = data.ReadBytes(128); - obj.TransferFlags = data.ReadByteValue(); - obj.ThumbnailImageSize = data.ReadInt32BigEndian(); - obj.TitleThumbnailImageSize = data.ReadInt32BigEndian(); - - if (obj.MetadataVersion == 2) - { - obj.ThumbnailImage = data.ReadBytes(0x3D00); - obj.AdditionalDisplayNames = data.ReadBytes(768); - obj.TitleThumbnailImage = data.ReadBytes(0x3D00); - obj.AdditionalDisplayDescriptions = data.ReadBytes(768); - } - else - { - obj.ThumbnailImage = data.ReadBytes(0x4000); - obj.TitleThumbnailImage = data.ReadBytes(0x4000); - } - - return obj; - } - - /// - /// Parse a Stream into a Signature - /// - /// Stream to parse - /// Filled Signature - public static Signature ParseSignature(Stream data, bool remoteSigned) - { - if (remoteSigned) - { - var obj = new MicrosoftSignature(); - - obj.PackageSignature = data.ReadBytes(256); - obj.Padding = data.ReadBytes(296); - - return obj; - } - else - { - var obj = new ConsoleSignature(); - - obj.CertificateSize = data.ReadUInt16BigEndian(); - obj.ConsoleID = data.ReadBytes(5); - obj.PartNumber = data.ReadBytes(20); - obj.ConsoleType = data.ReadByteValue(); - obj.CertificateDate = data.ReadBytes(8); - obj.PublicExponent = data.ReadBytes(4); - obj.PublicModulus = data.ReadBytes(128); - obj.CertificateSignature = data.ReadBytes(256); - obj.Signature = data.ReadBytes(128); - - return obj; - } - } - - /// - /// Parse a Stream into an array of LicenseEntry - /// - /// Stream to parse - /// Filled array of LicenseEntry - public static LicenseEntry[] ParseLicensingData(Stream data) - { - var obj = new LicenseEntry[16]; - - for (int i = 0; i < 16; i++) - { - obj[i] = new LicenseEntry(); - obj[i].LicenseID = data.ReadInt64BigEndian(); - obj[i].LicenseBits = data.ReadInt32BigEndian(); - obj[i].LicenseFlags = data.ReadInt32BigEndian(); - } - - return obj; - } - - /// - /// Parse a Stream into a VolumeDescriptor - /// - /// Stream to parse - /// Filled VolumeDescriptor - public static VolumeDescriptor ParseVolumeDescriptor(Stream data, bool svod) - { - if (svod) - { - var obj = new SVODDescriptor(); - - obj.VolumeDescriptorSize = data.ReadByteValue(); - obj.BlockCacheElementCount = data.ReadByteValue(); - obj.WorkerThreadProcessor = data.ReadByteValue(); - obj.WorkerThreadPriority = data.ReadByteValue(); - obj.Hash = data.ReadBytes(20); - obj.DataBlockCount = data.ReadUInt24BigEndian(); - obj.DataBlockOffset = data.ReadUInt24BigEndian(); - obj.Hash = data.ReadBytes(5); - - return obj; - } - else - { - var obj = new STFSDescriptor(); - - obj.VolumeDescriptorSize = data.ReadByteValue(); - obj.Reserved = data.ReadByteValue(); - obj.BlockSeparation = data.ReadByteValue(); - obj.FileTableBlockCount = data.ReadInt16BigEndian(); - obj.FileTableBlockNumber = data.ReadInt24BigEndian(); - obj.TopHashTableHash = data.ReadBytes(20); - obj.TotalAllocatedBlockCount = data.ReadInt32BigEndian(); - obj.TotalUnallocatedBlockCount = data.ReadInt32BigEndian(); - - return obj; - } - } - } -} +using System.IO; +using SabreTools.Data.Models.STFS; +using SabreTools.IO.Extensions; +using SabreTools.Numerics.Extensions; + +namespace SabreTools.Serialization.Readers +{ + public class STFS : BaseBinaryReader + { + /// + public override Volume? Deserialize(Stream? data) + { + // If the data is invalid + if (data is null || !data.CanRead) + return null; + + // Simple check for a valid stream length + if (Constants.StandardHeaderSize > data.Length - data.Position) + return null; + + try + { + // Cache the current offset + long initialOffset = data.Position; + + // Create a new Volume to fill + var volume = new Volume(); + + // Read and validate the header + var header = ParseHeader(data); + if (header is null) + return null; + + volume.Header = header; + + // TODO: Parse the hash table blocks + + // Don't parse the data blocks into memory + + return volume; + } + catch + { + // Ignore the actual error + return null; + } + } + + /// + /// Parse a Stream into a Header + /// + /// Stream to parse + /// Filled Header on success, null on error + public static Header? ParseHeader(Stream data) + { + var obj = new Header(); + + obj.MagicBytes = data.ReadBytes(4); + var signature = System.Text.Encoding.ASCII.GetString(obj.MagicBytes); + bool remoteSigned = signature.Equals(Constants.MagicStringLIVE) | signature.Equals(Constants.MagicStringPIRS); + if (!remoteSigned && !signature.Equals(Constants.MagicStringCON)) + return null; + + obj.Signature = ParseSignature(data, remoteSigned); + + obj.LicensingData = ParseLicensingData(data); + + obj.HeaderHash = data.ReadBytes(20); + obj.HeaderSize = data.ReadUInt32BigEndian(); + obj.ContentType = data.ReadInt32BigEndian(); + obj.MetadataVersion = data.ReadInt32BigEndian(); + obj.ContentSize = data.ReadInt64BigEndian(); + obj.MediaID = data.ReadUInt32BigEndian(); + obj.Version = data.ReadInt32BigEndian(); + obj.BaseVersion = data.ReadInt32BigEndian(); + obj.TitleID = data.ReadUInt32BigEndian(); + obj.Platform = data.ReadByteValue(); + obj.ExecutableType = data.ReadByteValue(); + obj.DiscNumber = data.ReadByteValue(); + obj.DiscInSet = data.ReadByteValue(); + obj.SaveGameID = data.ReadUInt32BigEndian(); + obj.ConsoleID = data.ReadBytes(5); + obj.ProfileID = data.ReadBytes(8); + + // Peek forward to read whether VolumeDescriptor is SVOD or STFS + byte[] peeked = data.PeekBytes(52); + bool svod = peeked[51] == 0x01; + obj.VolumeDescriptor = ParseVolumeDescriptor(data, svod); + + obj.DataFileCount = data.ReadInt32BigEndian(); + obj.DataFileCombinedSize = data.ReadInt64BigEndian(); + obj.DescriptorType = data.ReadUInt32BigEndian(); + obj.Reserved = data.ReadUInt32BigEndian(); + + if (obj.MetadataVersion == 2) + { + obj.SeriesID = data.ReadBytes(16); + obj.SeasonID = data.ReadBytes(16); + obj.SeasonNumber = data.ReadInt16BigEndian(); + obj.EpisodeNumber = data.ReadInt16BigEndian(); + obj.Padding = data.ReadBytes(40); + } + else + { + obj.Padding = data.ReadBytes(76); + } + + obj.DeviceID = data.ReadBytes(20); + obj.DisplayName = data.ReadBytes(2304); + obj.DisplayDescription = data.ReadBytes(2304); + obj.PublisherName = data.ReadBytes(128); + obj.TitleName = data.ReadBytes(128); + obj.TransferFlags = data.ReadByteValue(); + obj.ThumbnailImageSize = data.ReadInt32BigEndian(); + obj.TitleThumbnailImageSize = data.ReadInt32BigEndian(); + + if (obj.MetadataVersion == 2) + { + obj.ThumbnailImage = data.ReadBytes(0x3D00); + obj.AdditionalDisplayNames = data.ReadBytes(768); + obj.TitleThumbnailImage = data.ReadBytes(0x3D00); + obj.AdditionalDisplayDescriptions = data.ReadBytes(768); + } + else + { + obj.ThumbnailImage = data.ReadBytes(0x4000); + obj.TitleThumbnailImage = data.ReadBytes(0x4000); + } + + return obj; + } + + /// + /// Parse a Stream into a Signature + /// + /// Stream to parse + /// Filled Signature + public static Signature ParseSignature(Stream data, bool remoteSigned) + { + if (remoteSigned) + { + var obj = new MicrosoftSignature(); + + obj.PackageSignature = data.ReadBytes(256); + obj.Padding = data.ReadBytes(296); + + return obj; + } + else + { + var obj = new ConsoleSignature(); + + obj.CertificateSize = data.ReadUInt16BigEndian(); + obj.ConsoleID = data.ReadBytes(5); + obj.PartNumber = data.ReadBytes(20); + obj.ConsoleType = data.ReadByteValue(); + obj.CertificateDate = data.ReadBytes(8); + obj.PublicExponent = data.ReadBytes(4); + obj.PublicModulus = data.ReadBytes(128); + obj.CertificateSignature = data.ReadBytes(256); + obj.Signature = data.ReadBytes(128); + + return obj; + } + } + + /// + /// Parse a Stream into an array of LicenseEntry + /// + /// Stream to parse + /// Filled array of LicenseEntry + public static LicenseEntry[] ParseLicensingData(Stream data) + { + var obj = new LicenseEntry[16]; + + for (int i = 0; i < 16; i++) + { + obj[i] = new LicenseEntry(); + obj[i].LicenseID = data.ReadInt64BigEndian(); + obj[i].LicenseBits = data.ReadInt32BigEndian(); + obj[i].LicenseFlags = data.ReadInt32BigEndian(); + } + + return obj; + } + + /// + /// Parse a Stream into a VolumeDescriptor + /// + /// Stream to parse + /// Filled VolumeDescriptor + public static VolumeDescriptor ParseVolumeDescriptor(Stream data, bool svod) + { + if (svod) + { + var obj = new SVODDescriptor(); + + obj.VolumeDescriptorSize = data.ReadByteValue(); + obj.BlockCacheElementCount = data.ReadByteValue(); + obj.WorkerThreadProcessor = data.ReadByteValue(); + obj.WorkerThreadPriority = data.ReadByteValue(); + obj.Hash = data.ReadBytes(20); + obj.DataBlockCount = data.ReadUInt24BigEndian(); + obj.DataBlockOffset = data.ReadUInt24BigEndian(); + obj.Hash = data.ReadBytes(5); + + return obj; + } + else + { + var obj = new STFSDescriptor(); + + obj.VolumeDescriptorSize = data.ReadByteValue(); + obj.Reserved = data.ReadByteValue(); + obj.BlockSeparation = data.ReadByteValue(); + obj.FileTableBlockCount = data.ReadInt16BigEndian(); + obj.FileTableBlockNumber = data.ReadInt24BigEndian(); + obj.TopHashTableHash = data.ReadBytes(20); + obj.TotalAllocatedBlockCount = data.ReadInt32BigEndian(); + obj.TotalUnallocatedBlockCount = data.ReadInt32BigEndian(); + + return obj; + } + } + } +} diff --git a/SabreTools.Wrappers/STFS.Printing.cs b/SabreTools.Wrappers/STFS.Printing.cs index 0cacb82b..ee6fd801 100644 --- a/SabreTools.Wrappers/STFS.Printing.cs +++ b/SabreTools.Wrappers/STFS.Printing.cs @@ -1,7 +1,6 @@ using System; using System.Text; using SabreTools.Data.Models.STFS; -using SabreTools.Numerics; using SabreTools.Text.Extensions; namespace SabreTools.Wrappers @@ -60,7 +59,7 @@ namespace SabreTools.Wrappers builder.AppendLine(header.DataFileCombinedSize, " Data File Combined Size"); builder.AppendLine(header.DescriptorType, " Descriptor Type"); builder.AppendLine(header.Reserved, " Reserved"); - + if (header.MetadataVersion == 2) { builder.AppendLine(header.SeriesID, " Series ID"); @@ -135,7 +134,7 @@ namespace SabreTools.Wrappers builder.AppendLine(header.TransferFlags, " Transfer Flags"); // See Enums.TransferFlags builder.AppendLine(header.ThumbnailImageSize, " Thumbnail Image Size"); builder.AppendLine(header.TitleThumbnailImageSize, " Title Thumbnail Image Size"); - + if (header.AdditionalDisplayNames is not null) { for (int i = 0; i < 18; i++) @@ -149,6 +148,7 @@ namespace SabreTools.Wrappers } } } + if (header.AdditionalDisplayDescriptions is not null) { for (int i = 0; i < 18; i++) @@ -160,7 +160,7 @@ namespace SabreTools.Wrappers builder.AppendLine(localeString, $" Additional Display Description {i}"); builder.AppendLine(Encoding.BigEndianUnicode.GetString(localeString), $" Additional Display Description {i} (Parsed)"); } - } + } } builder.AppendLine(); @@ -212,6 +212,7 @@ namespace SabreTools.Wrappers lastLicenseData = i + 1; break; } + if (i == 0) builder.AppendLine("Zeroed", " Licensing Data"); } diff --git a/SabreTools.Wrappers/STFS.cs b/SabreTools.Wrappers/STFS.cs index 7ac5b656..391b1398 100644 --- a/SabreTools.Wrappers/STFS.cs +++ b/SabreTools.Wrappers/STFS.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.IO; using SabreTools.Data.Models.STFS;