using System.Collections.Generic; using System.IO; using System.Text; using SabreTools.Data.Models.PIC; using SabreTools.IO.Extensions; using SabreTools.Numerics.Extensions; using static SabreTools.Data.Models.PIC.Constants; #pragma warning disable IDE0017 // Simplify object initialization namespace SabreTools.Serialization.Readers { public class PIC : BaseBinaryReader { /// public override DiscInformation? Deserialize(Stream? data) { // If the data is invalid if (data is null || !data.CanRead) return null; try { var di = new DiscInformation(); // Read the initial disc information di.DataStructureLength = data.ReadUInt16BigEndian(); if (di.DataStructureLength > data.Length) return null; di.Reserved0 = data.ReadByteValue(); di.Reserved1 = data.ReadByteValue(); // Create a list for the units var diUnits = new List(); // Loop and read all available units for (int i = 0; i < 32; i++) { var unit = ParseDiscInformationUnit(data); diUnits.Add(unit); } // Assign the units and return di.Units = [.. diUnits]; return di; } catch { // Ignore the actual error return null; } } /// /// Parse a Stream into a DiscInformationUnit /// /// Stream to parse /// Filled DiscInformationUnit on success, null on error public static DiscInformationUnit ParseDiscInformationUnit(Stream data) { var obj = new DiscInformationUnit(); #region Header // We only accept Disc Information units, not Emergency Brake or other obj.Header = ParseDiscInformationUnitHeader(data); if (obj.Header.DiscInformationIdentifier != "DI") return obj; #endregion #region Body // Set the information unit body obj.Body = ParseDiscInformationUnitBody(data); #endregion #region Trailer // Set the information unit trailer if (obj.Body.DiscTypeIdentifier == DiscTypeIdentifierReWritable || obj.Body.DiscTypeIdentifier == DiscTypeIdentifierRecordable) obj.Trailer = ParseDiscInformationUnitTrailer(data); #endregion return obj; } /// /// Parse a Stream into a disc information unit body /// /// Stream to parse /// Filled disc information unit body on success, null on error private static DiscInformationUnitBody ParseDiscInformationUnitBody(Stream data) { var obj = new DiscInformationUnitBody(); byte[] dti = data.ReadBytes(3); obj.DiscTypeIdentifier = Encoding.ASCII.GetString(dti); obj.DiscSizeClassVersion = data.ReadByteValue(); switch (obj.DiscTypeIdentifier) { case DiscTypeIdentifierROM: case DiscTypeIdentifierROMUltra: case DiscTypeIdentifierXGD4: obj.FormatDependentContents = data.ReadBytes(52); break; case DiscTypeIdentifierReWritable: case DiscTypeIdentifierRecordable: obj.FormatDependentContents = data.ReadBytes(100); break; default: // TODO: Log invalid values break; } return obj; } /// /// Parse a Stream into a DiscInformationUnitHeader /// /// Stream to parse /// DiscInformationUnitHeader on success, null on error public static DiscInformationUnitHeader ParseDiscInformationUnitHeader(Stream data) { var obj = new DiscInformationUnitHeader(); byte[] discInformationIdentifier = data.ReadBytes(2); obj.DiscInformationIdentifier = Encoding.ASCII.GetString(discInformationIdentifier); if (obj.DiscInformationIdentifier != "DI") return obj; obj.DiscInformationFormat = data.ReadByteValue(); obj.NumberOfUnitsInBlock = data.ReadByteValue(); obj.Reserved0 = data.ReadByteValue(); obj.SequenceNumber = data.ReadByteValue(); obj.BytesInUse = data.ReadByteValue(); obj.Reserved1 = data.ReadByteValue(); return obj; } /// /// Parse a Stream into a DiscInformationUnitTrailer /// /// Stream to parse /// DiscInformationUnitTrailer on success, null on error public static DiscInformationUnitTrailer ParseDiscInformationUnitTrailer(Stream data) { var obj = new DiscInformationUnitTrailer(); obj.DiscManufacturerID = data.ReadBytes(6); obj.MediaTypeID = data.ReadBytes(3); obj.TimeStamp = data.ReadUInt16LittleEndian(); obj.ProductRevisionNumber = data.ReadByteValue(); return obj; } } }