mirror of
https://github.com/modernw/App-Installer-For-Windows-8.x-Reset.git
synced 2026-04-11 17:57:19 +10:00
189 lines
4.7 KiB
C#
189 lines
4.7 KiB
C#
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System;
|
|
|
|
namespace PriFileFormat
|
|
{
|
|
public class PriFile: IDisposable
|
|
{
|
|
public string Version { get; private set; }
|
|
public uint TotalFileSize { get; private set; }
|
|
public IReadOnlyList <TocEntry> TableOfContents { get; private set; }
|
|
public IReadOnlyList <Section> Sections { get; private set; }
|
|
private bool _disposed = false;
|
|
private Stream _internalStream; // 跟踪内部流
|
|
private PriFile ()
|
|
{
|
|
}
|
|
|
|
public static PriFile Parse (Stream stream)
|
|
{
|
|
PriFile priFile = new PriFile ();
|
|
priFile.ParseInternal (stream, false);
|
|
return priFile;
|
|
}
|
|
|
|
public static PriFile Parse (System.Runtime.InteropServices.ComTypes.IStream stream, out Stream output)
|
|
{
|
|
|
|
ComStreamWrapper csw = new ComStreamWrapper (stream);
|
|
output = csw;
|
|
PriFile priFile = new PriFile ();
|
|
priFile.ParseInternal (csw, true);
|
|
return priFile;
|
|
}
|
|
|
|
private void ParseInternal (Stream stream, bool ownStream)
|
|
{
|
|
if (ownStream) { _internalStream = stream; }
|
|
using (BinaryReader binaryReader = new BinaryReader (stream, Encoding.ASCII, true))
|
|
{
|
|
long fileStartOffset = binaryReader.BaseStream.Position;
|
|
|
|
string magic = new string (binaryReader.ReadChars (8));
|
|
|
|
switch (magic)
|
|
{
|
|
case "mrm_pri0":
|
|
case "mrm_pri1":
|
|
case "mrm_pri2":
|
|
case "mrm_prif":
|
|
Version = magic;
|
|
break;
|
|
default:
|
|
throw new InvalidDataException ("Data does not start with a PRI file header.");
|
|
}
|
|
|
|
binaryReader.ExpectUInt16 (0);
|
|
binaryReader.ExpectUInt16 (1);
|
|
TotalFileSize = binaryReader.ReadUInt32 ();
|
|
uint tocOffset = binaryReader.ReadUInt32 ();
|
|
uint sectionStartOffset = binaryReader.ReadUInt32 ();
|
|
ushort numSections = binaryReader.ReadUInt16 ();
|
|
|
|
binaryReader.ExpectUInt16 (0xFFFF);
|
|
binaryReader.ExpectUInt32 (0);
|
|
|
|
binaryReader.BaseStream.Seek (fileStartOffset + TotalFileSize - 16, SeekOrigin.Begin);
|
|
|
|
binaryReader.ExpectUInt32 (0xDEFFFADE);
|
|
binaryReader.ExpectUInt32 (TotalFileSize);
|
|
binaryReader.ExpectString (magic);
|
|
|
|
binaryReader.BaseStream.Seek (tocOffset, SeekOrigin.Begin);
|
|
|
|
List<TocEntry> toc = new List<TocEntry> (numSections);
|
|
|
|
for (int i = 0; i < numSections; i++)
|
|
toc.Add (TocEntry.Parse (binaryReader));
|
|
|
|
TableOfContents = toc;
|
|
|
|
Section [] sections = new Section [numSections];
|
|
|
|
Sections = sections;
|
|
|
|
bool parseSuccess = false;
|
|
bool parseFailure = false;
|
|
|
|
do
|
|
{
|
|
for (int i = 0; i < sections.Length; i++)
|
|
if (sections [i] == null)
|
|
{
|
|
binaryReader.BaseStream.Seek (sectionStartOffset + toc [i].SectionOffset, SeekOrigin.Begin);
|
|
|
|
Section section = Section.CreateForIdentifier (toc [i].SectionIdentifier, this);
|
|
|
|
if (section.Parse (binaryReader))
|
|
{
|
|
sections [i] = section;
|
|
parseSuccess = true;
|
|
}
|
|
else
|
|
parseFailure = true;
|
|
}
|
|
} while (parseFailure && parseSuccess);
|
|
|
|
if (parseFailure)
|
|
throw new InvalidDataException ();
|
|
}
|
|
}
|
|
|
|
public void Dispose ()
|
|
{
|
|
Dispose (true);
|
|
GC.SuppressFinalize (this);
|
|
}
|
|
protected virtual void Dispose (bool disposing)
|
|
{
|
|
if (_disposed) return;
|
|
if (disposing)
|
|
{
|
|
// 释放托管资源
|
|
if (_internalStream != null)
|
|
{
|
|
_internalStream.Dispose ();
|
|
_internalStream = null;
|
|
}
|
|
|
|
// 释放 section 内容
|
|
if (Sections != null)
|
|
{
|
|
foreach (var section in Sections)
|
|
{
|
|
var unknown = section as UnknownSection;
|
|
if (unknown != null)
|
|
unknown.ClearContent ();
|
|
|
|
var dataSection = section as DataItemSection;
|
|
if (dataSection != null)
|
|
dataSection.ClearData ();
|
|
}
|
|
Sections = null;
|
|
}
|
|
}
|
|
|
|
_disposed = true;
|
|
}
|
|
|
|
~PriFile ()
|
|
{
|
|
Dispose (false);
|
|
}
|
|
|
|
PriDescriptorSection priDescriptorSection;
|
|
|
|
public PriDescriptorSection PriDescriptorSection
|
|
{
|
|
get
|
|
{
|
|
if (priDescriptorSection == null) priDescriptorSection = Sections.OfType<PriDescriptorSection> ().Single ();
|
|
return priDescriptorSection;
|
|
}
|
|
}
|
|
|
|
public T GetSectionByRef<T> (SectionRef<T> sectionRef) where T : Section
|
|
{
|
|
return (T)Sections [sectionRef.sectionIndex];
|
|
}
|
|
|
|
public ResourceMapItem GetResourceMapItemByRef (ResourceMapItemRef resourceMapItemRef)
|
|
{
|
|
return GetSectionByRef (resourceMapItemRef.schemaSection).Items [resourceMapItemRef.itemIndex];
|
|
}
|
|
|
|
public ByteSpan GetDataItemByRef (DataItemRef dataItemRef)
|
|
{
|
|
return GetSectionByRef (dataItemRef.dataItemSection).DataItems [dataItemRef.itemIndex];
|
|
}
|
|
|
|
public ReferencedFile GetReferencedFileByRef (ReferencedFileRef referencedFileRef)
|
|
{
|
|
return GetSectionByRef (PriDescriptorSection.ReferencedFileSections.First ()).ReferencedFiles [referencedFileRef.fileIndex];
|
|
}
|
|
}
|
|
}
|