mirror of
https://github.com/modernw/App-Installer-For-Windows-8.x-Reset.git
synced 2026-04-11 17:57:19 +10:00
415 lines
13 KiB
C#
415 lines
13 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
|
|
namespace PriFormat
|
|
{
|
|
public class ResourceMapSection: Section
|
|
{
|
|
public HierarchicalSchemaReference HierarchicalSchemaReference { get; private set; }
|
|
public SectionRef<HierarchicalSchemaSection> SchemaSection { get; private set; }
|
|
public SectionRef<DecisionInfoSection> DecisionInfoSection { get; private set; }
|
|
public IDictionary<ushort, CandidateSet> CandidateSets { get; private set; }
|
|
|
|
readonly bool version2;
|
|
|
|
internal const string Identifier1 = "[mrm_res_map__]\0";
|
|
internal const string Identifier2 = "[mrm_res_map2_]\0";
|
|
|
|
internal ResourceMapSection (PriFile priFile, bool version2)
|
|
: base (version2 ? Identifier2 : Identifier1, priFile)
|
|
{
|
|
this.version2 = version2;
|
|
}
|
|
|
|
protected override bool ParseSectionContent (BinaryReader binaryReader)
|
|
{
|
|
long sectionPosition = (binaryReader.BaseStream as SubStream) != null ?
|
|
((SubStream)binaryReader.BaseStream).Position : 0;
|
|
|
|
ushort environmentReferencesLength = binaryReader.ReadUInt16 ();
|
|
ushort numEnvironmentReferences = binaryReader.ReadUInt16 ();
|
|
|
|
if (!version2)
|
|
{
|
|
if (environmentReferencesLength == 0 || numEnvironmentReferences == 0)
|
|
throw new InvalidDataException ();
|
|
}
|
|
else
|
|
{
|
|
if (environmentReferencesLength != 0 || numEnvironmentReferences != 0)
|
|
throw new InvalidDataException ();
|
|
}
|
|
|
|
SchemaSection = new SectionRef<HierarchicalSchemaSection> (binaryReader.ReadUInt16 ());
|
|
ushort hierarchicalSchemaReferenceLength = binaryReader.ReadUInt16 ();
|
|
DecisionInfoSection = new SectionRef<DecisionInfoSection> (binaryReader.ReadUInt16 ());
|
|
ushort resourceValueTypeTableSize = binaryReader.ReadUInt16 ();
|
|
ushort ItemToItemInfoGroupCount = binaryReader.ReadUInt16 ();
|
|
ushort itemInfoGroupCount = binaryReader.ReadUInt16 ();
|
|
uint itemInfoCount = binaryReader.ReadUInt32 ();
|
|
uint numCandidates = binaryReader.ReadUInt32 ();
|
|
uint dataLength = binaryReader.ReadUInt32 ();
|
|
uint largeTableLength = binaryReader.ReadUInt32 ();
|
|
|
|
if (PriFile.GetSectionByRef (DecisionInfoSection) == null)
|
|
return false;
|
|
|
|
byte [] environmentReferencesData = binaryReader.ReadBytes (environmentReferencesLength);
|
|
byte [] schemaReferenceData = binaryReader.ReadBytes (hierarchicalSchemaReferenceLength);
|
|
|
|
if (schemaReferenceData.Length != 0)
|
|
{
|
|
using (BinaryReader r = new BinaryReader (new MemoryStream (schemaReferenceData, false)))
|
|
{
|
|
ushort majorVersion = r.ReadUInt16 ();
|
|
ushort minorVersion = r.ReadUInt16 ();
|
|
r.ExpectUInt32 (0);
|
|
uint checksum = r.ReadUInt32 ();
|
|
uint numScopes = r.ReadUInt32 ();
|
|
uint numItems = r.ReadUInt32 ();
|
|
|
|
HierarchicalSchemaVersionInfo versionInfo = new HierarchicalSchemaVersionInfo (
|
|
majorVersion, minorVersion, checksum, numScopes, numItems);
|
|
|
|
ushort stringDataLength = r.ReadUInt16 ();
|
|
r.ExpectUInt16 (0);
|
|
uint unknown1 = r.ReadUInt32 ();
|
|
uint unknown2 = r.ReadUInt32 ();
|
|
string uniqueName = r.ReadNullTerminatedString (Encoding.Unicode);
|
|
|
|
if (uniqueName.Length != stringDataLength - 1)
|
|
throw new InvalidDataException ();
|
|
|
|
HierarchicalSchemaReference = new HierarchicalSchemaReference (versionInfo, unknown1, unknown2, uniqueName);
|
|
}
|
|
}
|
|
|
|
List<ResourceValueType> resourceValueTypeTable = new List<ResourceValueType> (resourceValueTypeTableSize);
|
|
for (int i = 0; i < resourceValueTypeTableSize; i++)
|
|
{
|
|
binaryReader.ExpectUInt32 (4);
|
|
ResourceValueType resourceValueType = (ResourceValueType)binaryReader.ReadUInt32 ();
|
|
resourceValueTypeTable.Add (resourceValueType);
|
|
}
|
|
|
|
List<ItemToItemInfoGroup> itemToItemInfoGroups = new List<ItemToItemInfoGroup> (ItemToItemInfoGroupCount);
|
|
for (int i = 0; i < ItemToItemInfoGroupCount; i++)
|
|
{
|
|
ushort firstItem = binaryReader.ReadUInt16 ();
|
|
ushort itemInfoGroup = binaryReader.ReadUInt16 ();
|
|
itemToItemInfoGroups.Add (new ItemToItemInfoGroup (firstItem, itemInfoGroup));
|
|
}
|
|
|
|
List<ItemInfoGroup> itemInfoGroups = new List<ItemInfoGroup> (itemInfoGroupCount);
|
|
for (int i = 0; i < itemInfoGroupCount; i++)
|
|
{
|
|
ushort groupSize = binaryReader.ReadUInt16 ();
|
|
ushort firstItemInfo = binaryReader.ReadUInt16 ();
|
|
itemInfoGroups.Add (new ItemInfoGroup (groupSize, firstItemInfo));
|
|
}
|
|
|
|
List<ItemInfo> itemInfos = new List<ItemInfo> ((int)itemInfoCount);
|
|
for (int i = 0; i < itemInfoCount; i++)
|
|
{
|
|
ushort decision = binaryReader.ReadUInt16 ();
|
|
ushort firstCandidate = binaryReader.ReadUInt16 ();
|
|
itemInfos.Add (new ItemInfo (decision, firstCandidate));
|
|
}
|
|
|
|
byte [] largeTable = binaryReader.ReadBytes ((int)largeTableLength);
|
|
|
|
if (largeTable.Length != 0)
|
|
{
|
|
using (BinaryReader r = new BinaryReader (new MemoryStream (largeTable, false)))
|
|
{
|
|
uint ItemToItemInfoGroupCountLarge = r.ReadUInt32 ();
|
|
uint itemInfoGroupCountLarge = r.ReadUInt32 ();
|
|
uint itemInfoCountLarge = r.ReadUInt32 ();
|
|
|
|
for (int i = 0; i < ItemToItemInfoGroupCountLarge; i++)
|
|
{
|
|
uint firstItem = r.ReadUInt32 ();
|
|
uint itemInfoGroup = r.ReadUInt32 ();
|
|
itemToItemInfoGroups.Add (new ItemToItemInfoGroup (firstItem, itemInfoGroup));
|
|
}
|
|
|
|
for (int i = 0; i < itemInfoGroupCountLarge; i++)
|
|
{
|
|
uint groupSize = r.ReadUInt32 ();
|
|
uint firstItemInfo = r.ReadUInt32 ();
|
|
itemInfoGroups.Add (new ItemInfoGroup (groupSize, firstItemInfo));
|
|
}
|
|
|
|
for (int i = 0; i < itemInfoCountLarge; i++)
|
|
{
|
|
uint decision = r.ReadUInt32 ();
|
|
uint firstCandidate = r.ReadUInt32 ();
|
|
itemInfos.Add (new ItemInfo (decision, firstCandidate));
|
|
}
|
|
|
|
if (r.BaseStream.Position != r.BaseStream.Length)
|
|
throw new InvalidDataException ();
|
|
}
|
|
}
|
|
|
|
List<CandidateInfo> candidateInfos = new List<CandidateInfo> ((int)numCandidates);
|
|
for (int i = 0; i < numCandidates; i++)
|
|
{
|
|
byte type = binaryReader.ReadByte ();
|
|
|
|
if (type == 0x01)
|
|
{
|
|
ResourceValueType resourceValueType = resourceValueTypeTable [binaryReader.ReadByte ()];
|
|
ushort sourceFileIndex = binaryReader.ReadUInt16 ();
|
|
ushort valueLocation = binaryReader.ReadUInt16 ();
|
|
ushort dataItemSection = binaryReader.ReadUInt16 ();
|
|
candidateInfos.Add (new CandidateInfo (resourceValueType, sourceFileIndex, valueLocation, dataItemSection));
|
|
}
|
|
else if (type == 0x00)
|
|
{
|
|
ResourceValueType resourceValueType = resourceValueTypeTable [binaryReader.ReadByte ()];
|
|
ushort length = binaryReader.ReadUInt16 ();
|
|
uint stringOffset = binaryReader.ReadUInt32 ();
|
|
candidateInfos.Add (new CandidateInfo (resourceValueType, length, stringOffset));
|
|
}
|
|
else
|
|
{
|
|
throw new InvalidDataException ();
|
|
}
|
|
}
|
|
|
|
long stringDataStartOffset = binaryReader.BaseStream.Position;
|
|
|
|
Dictionary<ushort, CandidateSet> candidateSets = new Dictionary<ushort, CandidateSet> ();
|
|
|
|
for (int itemToItemInfoGroupIndex = 0; itemToItemInfoGroupIndex < itemToItemInfoGroups.Count; itemToItemInfoGroupIndex++)
|
|
{
|
|
ItemToItemInfoGroup itemToItemInfoGroup = itemToItemInfoGroups [itemToItemInfoGroupIndex];
|
|
|
|
ItemInfoGroup itemInfoGroup;
|
|
|
|
if (itemToItemInfoGroup.ItemInfoGroup < itemInfoGroups.Count)
|
|
itemInfoGroup = itemInfoGroups [(int)itemToItemInfoGroup.ItemInfoGroup];
|
|
else
|
|
itemInfoGroup = new ItemInfoGroup (1, (uint)(itemToItemInfoGroup.ItemInfoGroup - itemInfoGroups.Count));
|
|
|
|
for (uint itemInfoIndex = itemInfoGroup.FirstItemInfo; itemInfoIndex < itemInfoGroup.FirstItemInfo + itemInfoGroup.GroupSize; itemInfoIndex++)
|
|
{
|
|
ItemInfo itemInfo = itemInfos [(int)itemInfoIndex];
|
|
|
|
ushort decisionIndex = (ushort)itemInfo.Decision;
|
|
|
|
Decision decision = PriFile.GetSectionByRef (DecisionInfoSection).Decisions [decisionIndex];
|
|
|
|
List<Candidate> candidates = new List<Candidate> (decision.QualifierSets.Count);
|
|
|
|
for (int i = 0; i < decision.QualifierSets.Count; i++)
|
|
{
|
|
CandidateInfo candidateInfo = candidateInfos [(int)itemInfo.FirstCandidate + i];
|
|
|
|
if (candidateInfo.Type == 0x01)
|
|
{
|
|
ReferencedFileRef sourceFile = null;
|
|
|
|
if (candidateInfo.SourceFileIndex != 0)
|
|
sourceFile = new ReferencedFileRef (candidateInfo.SourceFileIndex - 1);
|
|
|
|
candidates.Add (new Candidate (decision.QualifierSets [i].Index, candidateInfo.ResourceValueType, sourceFile,
|
|
new DataItemRef (new SectionRef<DataItemSection> (candidateInfo.DataItemSection), candidateInfo.DataItemIndex)));
|
|
}
|
|
else if (candidateInfo.Type == 0x00)
|
|
{
|
|
ByteSpan data = new ByteSpan (sectionPosition + stringDataStartOffset + candidateInfo.DataOffset, candidateInfo.DataLength);
|
|
|
|
candidates.Add (new Candidate (decision.QualifierSets [i].Index, candidateInfo.ResourceValueType, data));
|
|
}
|
|
}
|
|
|
|
ushort resourceMapItemIndex = (ushort)(itemToItemInfoGroup.FirstItem + (itemInfoIndex - itemInfoGroup.FirstItemInfo));
|
|
|
|
CandidateSet candidateSet = new CandidateSet (
|
|
new ResourceMapItemRef (SchemaSection, resourceMapItemIndex),
|
|
decisionIndex,
|
|
candidates);
|
|
|
|
candidateSets.Add (resourceMapItemIndex, candidateSet);
|
|
}
|
|
}
|
|
|
|
CandidateSets = candidateSets;
|
|
|
|
return true;
|
|
}
|
|
|
|
private struct ItemToItemInfoGroup
|
|
{
|
|
public uint FirstItem;
|
|
public uint ItemInfoGroup;
|
|
|
|
public ItemToItemInfoGroup (uint firstItem, uint itemInfoGroup)
|
|
{
|
|
FirstItem = firstItem;
|
|
ItemInfoGroup = itemInfoGroup;
|
|
}
|
|
}
|
|
|
|
private struct ItemInfoGroup
|
|
{
|
|
public uint GroupSize;
|
|
public uint FirstItemInfo;
|
|
|
|
public ItemInfoGroup (uint groupSize, uint firstItemInfo)
|
|
{
|
|
GroupSize = groupSize;
|
|
FirstItemInfo = firstItemInfo;
|
|
}
|
|
}
|
|
|
|
private struct ItemInfo
|
|
{
|
|
public uint Decision;
|
|
public uint FirstCandidate;
|
|
|
|
public ItemInfo (uint decision, uint firstCandidate)
|
|
{
|
|
Decision = decision;
|
|
FirstCandidate = firstCandidate;
|
|
}
|
|
}
|
|
|
|
private struct CandidateInfo
|
|
{
|
|
public byte Type;
|
|
public ResourceValueType ResourceValueType;
|
|
|
|
// Type 1
|
|
public ushort SourceFileIndex;
|
|
public ushort DataItemIndex;
|
|
public ushort DataItemSection;
|
|
|
|
// Type 0
|
|
public ushort DataLength;
|
|
public uint DataOffset;
|
|
|
|
public CandidateInfo (ResourceValueType resourceValueType, ushort sourceFileIndex, ushort dataItemIndex, ushort dataItemSection)
|
|
{
|
|
Type = 0x01;
|
|
ResourceValueType = resourceValueType;
|
|
SourceFileIndex = sourceFileIndex;
|
|
DataItemIndex = dataItemIndex;
|
|
DataItemSection = dataItemSection;
|
|
DataLength = 0;
|
|
DataOffset = 0;
|
|
}
|
|
|
|
public CandidateInfo (ResourceValueType resourceValueType, ushort dataLength, uint dataOffset)
|
|
{
|
|
Type = 0x00;
|
|
ResourceValueType = resourceValueType;
|
|
SourceFileIndex = 0;
|
|
DataItemIndex = 0;
|
|
DataItemSection = 0;
|
|
DataLength = dataLength;
|
|
DataOffset = dataOffset;
|
|
}
|
|
}
|
|
public override void Dispose ()
|
|
{
|
|
HierarchicalSchemaReference = null;
|
|
CandidateSets?.Clear ();
|
|
CandidateSets = null;
|
|
base.Dispose ();
|
|
}
|
|
~ResourceMapSection () { Dispose (); }
|
|
}
|
|
|
|
public enum ResourceValueType
|
|
{
|
|
String,
|
|
Path,
|
|
EmbeddedData,
|
|
AsciiString,
|
|
Utf8String,
|
|
AsciiPath,
|
|
Utf8Path
|
|
}
|
|
|
|
public class CandidateSet: IDisposable
|
|
{
|
|
public ResourceMapItemRef ResourceMapItem { get; private set; }
|
|
public ushort DecisionIndex { get; private set; }
|
|
public IList<Candidate> Candidates { get; private set; }
|
|
|
|
internal CandidateSet (ResourceMapItemRef resourceMapItem, ushort decisionIndex, IList<Candidate> candidates)
|
|
{
|
|
ResourceMapItem = resourceMapItem;
|
|
DecisionIndex = decisionIndex;
|
|
Candidates = candidates;
|
|
}
|
|
|
|
public virtual void Dispose ()
|
|
{
|
|
Candidates?.Clear ();
|
|
Candidates = null;
|
|
}
|
|
~CandidateSet () { Dispose (); }
|
|
}
|
|
|
|
public class Candidate
|
|
{
|
|
public ushort QualifierSet { get; private set; }
|
|
public ResourceValueType Type { get; private set; }
|
|
public ReferencedFileRef SourceFile { get; private set; }
|
|
public DataItemRef DataItem { get; private set; }
|
|
public ByteSpan Data { get; private set; }
|
|
|
|
internal Candidate (ushort qualifierSet, ResourceValueType type, ReferencedFileRef sourceFile, DataItemRef dataItem)
|
|
{
|
|
QualifierSet = qualifierSet;
|
|
Type = type;
|
|
SourceFile = sourceFile;
|
|
DataItem = dataItem;
|
|
}
|
|
|
|
internal Candidate (ushort qualifierSet, ResourceValueType type, ByteSpan data)
|
|
{
|
|
QualifierSet = qualifierSet;
|
|
Type = type;
|
|
SourceFile = null;
|
|
DataItem = null;
|
|
Data = data;
|
|
}
|
|
}
|
|
|
|
public class HierarchicalSchemaReference
|
|
{
|
|
public HierarchicalSchemaVersionInfo VersionInfo { get; private set; }
|
|
public uint Unknown1 { get; private set; }
|
|
public uint Unknown2 { get; private set; }
|
|
public string UniqueName { get; private set; }
|
|
|
|
internal HierarchicalSchemaReference (HierarchicalSchemaVersionInfo versionInfo, uint unknown1, uint unknown2, string uniqueName)
|
|
{
|
|
VersionInfo = versionInfo;
|
|
Unknown1 = unknown1;
|
|
Unknown2 = unknown2;
|
|
UniqueName = uniqueName;
|
|
}
|
|
}
|
|
|
|
public struct ResourceMapItemRef
|
|
{
|
|
internal SectionRef<HierarchicalSchemaSection> schemaSection;
|
|
internal int itemIndex;
|
|
public SectionRef<HierarchicalSchemaSection> SchemaSection => schemaSection;
|
|
public int ItemIndex => itemIndex;
|
|
internal ResourceMapItemRef (SectionRef<HierarchicalSchemaSection> schemaSection, int itemIndex)
|
|
{
|
|
this.schemaSection = schemaSection;
|
|
this.itemIndex = itemIndex;
|
|
}
|
|
}
|
|
}
|