private void LoadInteropData(StructureValueCollection headerValues) { // TODO: fix this shit for the h3beta better if (headerValues.HasArray("offset masks") && headerValues.HasArray("sections")) { SectionOffsetMasks = headerValues.GetArray("offset masks").Select(v => (uint)v.GetInteger("mask")).ToArray(); Sections = headerValues.GetArray("sections").Select(v => new ThirdGenInteropSection(v)).ToArray(); // H3 MCC currently doesn't store section data for campaign/shared, so it must be hacked together if (_expander.IsValid && (Type == CacheFileType.Shared || Type == CacheFileType.SinglePlayerShared)) { if (Sections[(int)ThirdGenInteropSectionType.Resource].Size == 0) { Sections[(int)ThirdGenInteropSectionType.Resource].VirtualAddress = (uint)HeaderSize; Sections[(int)ThirdGenInteropSectionType.Resource].Size = (uint)FileSize - (uint)HeaderSize; } } } else //else hack up our own sections { SectionOffsetMasks = new uint[] { 0, 0, 0, 0 }; ThirdGenInteropSection debugSection = new ThirdGenInteropSection( (uint)headerValues.GetInteger("string index table offset"), (uint)(headerValues.GetInteger("file size") - headerValues.GetInteger("string index table offset"))); ThirdGenInteropSection resourceSection = new ThirdGenInteropSection(0, 0); // this is between locales and tag, so if we had a locale size, this section could be calculated. Using 0's for now seems to work at least ThirdGenInteropSection tagSection = new ThirdGenInteropSection( (uint)headerValues.GetInteger("tag buffer offset"), (uint)headerValues.GetInteger("virtual size")); ThirdGenInteropSection localeSection = new ThirdGenInteropSection( (uint)HeaderSize, (uint)headerValues.GetInteger("tag buffer offset")); //bs the size for now Sections = new ThirdGenInteropSection[] { debugSection, resourceSection, tagSection, localeSection }; } DebugPointerConverter = MakePointerConverter(ThirdGenInteropSectionType.Debug); ResourcePointerConverter = MakePointerConverter(ThirdGenInteropSectionType.Resource); TagBufferPointerConverter = MakePointerConverter(ThirdGenInteropSectionType.Tag); LocalePointerConverter = MakePointerConverter(ThirdGenInteropSectionType.Localization); }
/// <summary> /// Rebuilds the interop data table in a cache file. /// </summary> /// <param name="localeArea">The localization area of the file.</param> private void RebuildInteropData(FileSegmentGroup localeArea) { ThirdGenInteropSection debugSection = Sections[(int)ThirdGenInteropSectionType.Debug]; ThirdGenInteropSection rsrcSection = Sections[(int)ThirdGenInteropSectionType.Resource]; ThirdGenInteropSection tagSection = Sections[(int)ThirdGenInteropSectionType.Tag]; ThirdGenInteropSection localeSection = Sections[(int)ThirdGenInteropSectionType.Localization]; // Recompute base addresses // Section addresses are usually in the following order: resource, locale, tag, debug. // Each address can immediately follow after the previous non-null section, // even though this isn't the case in some of the official files (because of removed debug data). // // TODO: This could possibly be made into a for loop and cleaned up if the pointer converters are stored in an array. // I just want to get this working for now. //rsrcSection.VirtualAddress = 0; // This is (not) always zero if (cacheSegmentAlignment == 0x800) { rsrcSection.VirtualAddress = 0x800; // hax for h3b saving, sections aren't in the same order as final } rsrcSection.Size = (ResourcePointerConverter != null) ? (uint)RawTable.Size : 0; localeSection.VirtualAddress = (LocalePointerConverter != null) ? rsrcSection.VirtualAddress + rsrcSection.Size : 0; localeSection.Size = (LocalePointerConverter != null) ? (uint)localeArea.Size : 0; tagSection.VirtualAddress = (TagBufferPointerConverter != null) ? rsrcSection.VirtualAddress + rsrcSection.Size + localeSection.Size : 0; tagSection.Size = (TagBufferPointerConverter != null) ? (uint)MetaArea.Size : 0; debugSection.VirtualAddress = (DebugPointerConverter != null) ? rsrcSection.VirtualAddress + rsrcSection.Size + localeSection.Size + tagSection.Size : 0; debugSection.Size = (DebugPointerConverter != null) ? (uint)StringArea.Size : 0; // If the offset mask for the debug section wasn't originally zero, then we have to subtract the first partition size from the debug base address // Not entirely sure why this is the case, but that's what the official files do if (debugSection.VirtualAddress != 0 && SectionOffsetMasks[(int)ThirdGenInteropSectionType.Debug] != 0) { debugSection.VirtualAddress -= Partitions[0].Size; } // Recompute offset masks SectionOffsetMasks[(int)ThirdGenInteropSectionType.Debug] = (debugSection.Size > 0) ? (uint)(StringArea.Offset - debugSection.VirtualAddress) : 0; SectionOffsetMasks[(int)ThirdGenInteropSectionType.Resource] = (rsrcSection.Size > 0) ? (uint)(RawTable.Offset - rsrcSection.VirtualAddress) : 0; SectionOffsetMasks[(int)ThirdGenInteropSectionType.Tag] = (tagSection.Size > 0) ? (uint)(MetaArea.Offset - tagSection.VirtualAddress) : 0; SectionOffsetMasks[(int)ThirdGenInteropSectionType.Localization] = (localeSection.Size > 0) ? (uint)(localeArea.Offset - localeSection.VirtualAddress) : 0; // Update pointer converters if (DebugPointerConverter != null) { DebugPointerConverter.BasePointer = debugSection.VirtualAddress; } if (ResourcePointerConverter != null) { ResourcePointerConverter.BasePointer = rsrcSection.VirtualAddress; } if (TagBufferPointerConverter != null) { TagBufferPointerConverter.BasePointer = tagSection.VirtualAddress; } if (LocalePointerConverter != null) { LocalePointerConverter.BasePointer = localeSection.VirtualAddress; } }