using System; using System.IO; using System.Text; using System.Runtime.InteropServices; namespace PriFileFormat { public abstract class Section { protected PriFile PriFile { get; private set; } public string SectionIdentifier { get; private set; } public uint SectionQualifier { get; private set; } public uint Flags { get; private set; } public uint SectionFlags { get; private set; } public uint SectionLength { get; private set; } protected Section (string sectionIdentifier, PriFile priFile) { if (sectionIdentifier.Length != 16) throw new ArgumentException ("Section identifiers need to be exactly 16 characters long.", nameof (sectionIdentifier)); SectionIdentifier = sectionIdentifier; PriFile = priFile; } internal bool Parse (BinaryReader binaryReader) { if (new string (binaryReader.ReadChars (16)) != SectionIdentifier) throw new InvalidDataException ("Unexpected section identifier."); SectionQualifier = binaryReader.ReadUInt32 (); Flags = binaryReader.ReadUInt16 (); SectionFlags = binaryReader.ReadUInt16 (); SectionLength = binaryReader.ReadUInt32 (); binaryReader.ExpectUInt32 (0); binaryReader.BaseStream.Seek (SectionLength - 16 - 24, SeekOrigin.Current); binaryReader.ExpectUInt32 (0xDEF5FADE); binaryReader.ExpectUInt32 (SectionLength); binaryReader.BaseStream.Seek (-8 - (SectionLength - 16 - 24), SeekOrigin.Current); using (SubStream subStream = new SubStream (binaryReader.BaseStream, binaryReader.BaseStream.Position, (int)SectionLength - 16 - 24)) using (BinaryReader subBinaryReader = new BinaryReader (subStream, Encoding.ASCII)) { return ParseSectionContent (subBinaryReader); } } protected abstract bool ParseSectionContent (BinaryReader binaryReader); public override string ToString () { return $"{SectionIdentifier.TrimEnd ('\0', ' ')} length: {SectionLength}"; } internal static Section CreateForIdentifier (string sectionIdentifier, PriFile priFile) { switch (sectionIdentifier) { case PriDescriptorSection.Identifier: return new PriDescriptorSection (priFile); case HierarchicalSchemaSection.Identifier1: return new HierarchicalSchemaSection (priFile, false); case HierarchicalSchemaSection.Identifier2: return new HierarchicalSchemaSection (priFile, true); case DecisionInfoSection.Identifier: return new DecisionInfoSection (priFile); case ResourceMapSection.Identifier1: return new ResourceMapSection (priFile, false); case ResourceMapSection.Identifier2: return new ResourceMapSection (priFile, true); case DataItemSection.Identifier: return new DataItemSection (priFile); case ReverseMapSection.Identifier: return new ReverseMapSection (priFile); case ReferencedFileSection.Identifier: return new ReferencedFileSection (priFile); default: return new UnknownSection (sectionIdentifier, priFile); } } ~Section () { PriFile = null; } } }