internal HierarchicalSchemaReference(HierarchicalSchemaVersionInfo versionInfo, uint unknown1, uint unknown2, string uniqueName)
 {
     VersionInfo = versionInfo;
     Unknown1    = unknown1;
     Unknown2    = unknown2;
     UniqueName  = uniqueName;
 }
        protected override bool ParseSectionContent(BinaryReader binaryReader)
        {
            long sectionPosition = (binaryReader.BaseStream as SubStream)?.SubStreamPosition ?? 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>();

            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>();

            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>();

            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;

                            if (candidateInfo.SourceFileIndex == 0)
                            {
                                sourceFile = null;
                            }
                            else
                            {
                                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);
        }
Example #3
0
        protected override bool ParseSectionContent(BinaryReader binaryReader)
        {
            if (binaryReader.BaseStream.Length == 0)
            {
                Version    = null;
                UniqueName = null;
                Name       = null;
                Scopes     = Array.Empty <ResourceMapScope>();
                Items      = Array.Empty <ResourceMapItem>();
                return(true);
            }

            binaryReader.ExpectUInt16(1);
            ushort uniqueNameLength = binaryReader.ReadUInt16();
            ushort nameLength       = binaryReader.ReadUInt16();

            binaryReader.ExpectUInt16(0);

            bool extendedHNames;

            if (extendedVersion)
            {
                switch (new string(binaryReader.ReadChars(16)))
                {
                case "[def_hnamesx]  \0":
                    extendedHNames = true;
                    break;

                case "[def_hnames]   \0":
                    extendedHNames = false;
                    break;

                default:
                    throw new InvalidDataException();
                }
            }
            else
            {
                extendedHNames = false;
            }

            // hierarchical schema version info
            ushort majorVersion = binaryReader.ReadUInt16();
            ushort minorVersion = binaryReader.ReadUInt16();

            binaryReader.ExpectUInt32(0);
            uint checksum  = binaryReader.ReadUInt32();
            uint numScopes = binaryReader.ReadUInt32();
            uint numItems  = binaryReader.ReadUInt32();

            Version = new HierarchicalSchemaVersionInfo(majorVersion, minorVersion, checksum, numScopes, numItems);

            UniqueName = binaryReader.ReadNullTerminatedString(Encoding.Unicode);
            Name       = binaryReader.ReadNullTerminatedString(Encoding.Unicode);

            if (UniqueName.Length != uniqueNameLength - 1 || Name.Length != nameLength - 1)
            {
                throw new InvalidDataException();
            }

            binaryReader.ExpectUInt16(0);
            ushort maxFullPathLength = binaryReader.ReadUInt16();

            binaryReader.ExpectUInt16(0);
            binaryReader.ExpectUInt32(numScopes + numItems);
            binaryReader.ExpectUInt32(numScopes);
            binaryReader.ExpectUInt32(numItems);
            uint unicodeDataLength = binaryReader.ReadUInt32();

            binaryReader.ReadUInt32(); // meaning unknown

            if (extendedHNames)
            {
                binaryReader.ReadUInt32(); // meaning unknown
            }
            List <ScopeAndItemInfo> scopeAndItemInfos = new List <ScopeAndItemInfo>((int)(numScopes + numItems));

            for (int i = 0; i < numScopes + numItems; i++)
            {
                ushort parent             = binaryReader.ReadUInt16();
                ushort fullPathLength     = binaryReader.ReadUInt16();
                char   uppercaseFirstChar = (char)binaryReader.ReadUInt16();
                byte   nameLength2        = binaryReader.ReadByte();
                byte   flags       = binaryReader.ReadByte();
                uint   nameOffset  = binaryReader.ReadUInt16() | (uint)((flags & 0xF) << 16);
                ushort index       = binaryReader.ReadUInt16();
                bool   isScope     = (flags & 0x10) != 0;
                bool   nameInAscii = (flags & 0x20) != 0;
                scopeAndItemInfos.Add(new ScopeAndItemInfo(parent, fullPathLength, isScope, nameInAscii, nameOffset, index));
            }

            List <ScopeExInfo> scopeExInfos = new List <ScopeExInfo>((int)numScopes);

            for (int i = 0; i < numScopes; i++)
            {
                ushort scopeIndex      = binaryReader.ReadUInt16();
                ushort childCount      = binaryReader.ReadUInt16();
                ushort firstChildIndex = binaryReader.ReadUInt16();
                binaryReader.ExpectUInt16(0);
                scopeExInfos.Add(new ScopeExInfo(scopeIndex, childCount, firstChildIndex));
            }

            ushort[] itemIndexPropertyToIndex = new ushort[numItems];
            for (int i = 0; i < numItems; i++)
            {
                itemIndexPropertyToIndex[i] = binaryReader.ReadUInt16();
            }

            long unicodeDataOffset = binaryReader.BaseStream.Position;
            long asciiDataOffset   = binaryReader.BaseStream.Position + unicodeDataLength * 2;

            ResourceMapScope[] scopes = new ResourceMapScope[numScopes];
            ResourceMapItem[]  items  = new ResourceMapItem[numItems];

            for (int i = 0; i < numScopes + numItems; i++)
            {
                long pos;

                if (scopeAndItemInfos[i].NameInAscii)
                {
                    pos = asciiDataOffset + scopeAndItemInfos[i].NameOffset;
                }
                else
                {
                    pos = unicodeDataOffset + scopeAndItemInfos[i].NameOffset * 2;
                }

                binaryReader.BaseStream.Seek(pos, SeekOrigin.Begin);

                string name;

                if (scopeAndItemInfos[i].FullPathLength != 0)
                {
                    name = binaryReader.ReadNullTerminatedString(scopeAndItemInfos[i].NameInAscii ? Encoding.ASCII : Encoding.Unicode);
                }
                else
                {
                    name = string.Empty;
                }

                ushort index = scopeAndItemInfos[i].Index;

                if (scopeAndItemInfos[i].IsScope)
                {
                    if (scopes[index] != null)
                    {
                        throw new InvalidDataException();
                    }

                    scopes[index] = new ResourceMapScope(index, null, name);
                }
                else
                {
                    if (items[index] != null)
                    {
                        throw new InvalidDataException();
                    }

                    items[index] = new ResourceMapItem(index, null, name);
                }
            }

            for (int i = 0; i < numScopes + numItems; i++)
            {
                ushort index = scopeAndItemInfos[i].Index;

                ushort parent = scopeAndItemInfos[scopeAndItemInfos[i].Parent].Index;

                if (parent != 0xFFFF)
                {
                    if (scopeAndItemInfos[i].IsScope)
                    {
                        if (parent != index)
                        {
                            scopes[index].Parent = scopes[parent];
                        }
                    }
                    else
                    {
                        items[index].Parent = scopes[parent];
                    }
                }
            }

            for (int i = 0; i < numScopes; i++)
            {
                List <ResourceMapEntry> children = new List <ResourceMapEntry>(scopeExInfos[i].ChildCount);

                for (int j = 0; j < scopeExInfos[i].ChildCount; j++)
                {
                    ScopeAndItemInfo saiInfo = scopeAndItemInfos[scopeExInfos[i].FirstChildIndex + j];

                    if (saiInfo.IsScope)
                    {
                        children.Add(scopes[saiInfo.Index]);
                    }
                    else
                    {
                        children.Add(items[saiInfo.Index]);
                    }
                }

                scopes[i].Children = children;
            }

            Scopes = scopes;
            Items  = items;

            //if (checksum != ComputeHierarchicalSchemaVersionInfoChecksum())
            //    throw new Exception();

            return(true);
        }