mirror of
https://github.com/modernw/App-Installer-For-Windows-8.x-Reset.git
synced 2026-04-13 20:28:33 +10:00
Organized the project files.
And also fixed some bugs.
This commit is contained in:
187
PriFileFormat/PriFile.cs
Normal file
187
PriFileFormat/PriFile.cs
Normal file
@@ -0,0 +1,187 @@
|
||||
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)
|
||||
{
|
||||
|
||||
ComStreamWrapper csw = new ComStreamWrapper (stream);
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user