internal CacheFile(CacheArgs args) { if (!File.Exists(args.FileName)) { throw Exceptions.FileNotFound(args.FileName); } FileName = args.FileName; ByteOrder = args.ByteOrder; BuildString = args.BuildString; CacheType = args.CacheType; Metadata = args.Metadata; HeaderTranslator = new SectionAddressTranslator(this, 0); MetadataTranslator = new TagAddressTranslator(this); PointerExpander = new PointerExpander(this); using (var reader = CreateReader(HeaderTranslator)) Header = reader.ReadObject <CacheHeader>((int)CacheType); //change IndexPointer to use MetadataTranslator instead of HeaderTranslator Header.IndexPointer = new Pointer64(Header.IndexPointer.Value, MetadataTranslator); using (var reader = CreateReader(MetadataTranslator)) { reader.Seek(Header.IndexPointer.Address, SeekOrigin.Begin); TagIndex = reader.ReadObject(new TagIndex(this)); StringIndex = new StringIndex(this); TagIndex.ReadItems(); StringIndex.ReadItems(); switch (CacheType) { case CacheType.MccHalo3: case CacheType.MccHalo3U4: LocaleIndex = new LocaleIndex(this, 464, 80, 12); break; case CacheType.MccHalo3ODST: LocaleIndex = new LocaleIndex(this, 520, 80, 12); break; } } Task.Factory.StartNew(() => { TagIndex.GetGlobalTag("play")?.ReadMetadata <Halo3.cache_file_resource_layout_table>(); TagIndex.GetGlobalTag("zone")?.ReadMetadata <Halo3.cache_file_resource_gestalt>(); TagIndex.GetGlobalTag("scnr")?.ReadMetadata <Halo3.scenario>(); }); }
public CacheSegmenter(IGen3CacheFile cache) { if (cache.CacheType < CacheType.Halo3Retail || cache.Metadata.IsPreRelease) { throw new NotSupportedException(); } this.cache = cache; var debugTranslator = new SectionAddressTranslator(cache, 0); var resourceTranslator = new SectionAddressTranslator(cache, 1); var metadataTranslator = new SectionAddressTranslator(cache, 2); var localeTranslator = new SectionAddressTranslator(cache, 3); //header segments.Add(new Segment(0, cache.GetHeaderSize(), 1)); //eof segments.Add(new Segment((int)cache.Header.FileSize, 0, 1)); //sections var origin = (int)resourceTranslator.GetAddress(resourceTranslator.VirtualAddress); var size = (int)cache.Header.SectionTable[1].Size; segments.Add(resourceSegment = new Segment(origin, size, 0x1000)); origin = (int)metadataTranslator.GetAddress(metadataTranslator.VirtualAddress); size = cache.Header.VirtualSize; segments.Add(metadataSegment = new Segment(origin, size, 0x10000)); //strings origin = (int)debugTranslator.GetAddress(cache.Header.StringTableIndexPointer.Value); size = cache.Header.StringCount * 4; segments.Add(stringsGroup.Add(stringSegments[0] = new Segment(origin, size, 4))); origin = (int)debugTranslator.GetAddress(cache.Header.StringTablePointer.Value); size = cache.Header.StringTableSize; segments.Add(stringsGroup.Add(stringSegments[1] = new Segment(origin, size, cache.UsesStringEncryption ? 16 : 1))); //tag names origin = (int)debugTranslator.GetAddress(cache.Header.FileTableIndexPointer.Value); size = cache.Header.FileCount * 4; segments.Add(stringsGroup.Add(stringSegments[2] = new Segment(origin, size, 4))); origin = (int)debugTranslator.GetAddress(cache.Header.FileTablePointer.Value); size = cache.Header.FileTableSize; segments.Add(stringsGroup.Add(stringSegments[3] = new Segment(origin, size, 1))); //only exists in mcc reach (U3+) var mcc3 = cache.Header as IMccGen3Header; if (mcc3?.StringNamespaceCount > 0) { origin = (int)debugTranslator.GetAddress(mcc3.StringNamespaceTablePointer.Value); size = mcc3.StringNamespaceCount * 4; segments.Add(stringSegments[4] = stringsGroup.Add(new Segment(origin, size, 4))); } var gen4 = cache.Header as IGen4Header; if (gen4?.UnknownTableSize > 0) { origin = (int)debugTranslator.GetAddress(gen4.UnknownTablePointer.Value); size = gen4.UnknownTableSize * 16; segments.Add(stringSegments[5] = stringsGroup.Add(new Segment(origin, size, 16))); } for (int i = 0; i < cache.LocaleIndex.Languages.Count; i++) { var def = cache.LocaleIndex.Languages[i]; if (def.StringCount <= 0) { continue; } var segs = new Segment[2]; origin = (int)localeTranslator.GetAddress(def.IndicesOffset); size = def.StringCount * 8; segments.Add(segs[0] = localesGroup.Add(new Segment(origin, size, 8))); origin = (int)localeTranslator.GetAddress(def.StringsOffset); size = def.StringsSize; segments.Add(segs[1] = localesGroup.Add(new Segment(origin, size, cache.UsesStringEncryption ? 16 : 1))); localeSegments.Add(i, segs); } segments.Sort((a, b) => a.Offset.CompareTo(b.Offset)); for (int i = 0; i < segments.Count - 1; i++) { segments[i].NextSegment = segments[i + 1]; } }
public void AddMetadata(EndianWriterEx writer, int length, out int insertedAt, out int insertedCount) { length = metadataSegment.Expand(length); cache.Header.FileSize = eofSegment.Offset; var debugTranslator = new SectionAddressTranslator(cache, 0); //var metadataTranslator = new SectionAddressTranslator(cache, 2); var localeTranslator = new SectionAddressTranslator(cache, 3); var remaining = metadataSegment.AvailableSize - cache.Header.PartitionTable.Skip(1).Sum(p => (int)p.Size); var pointer = cache.DefaultAddressTranslator.GetPointer(metadataSegment.Offset) - length; //DefaultAddressTranslator should always be the MetadataTranslator cache.Header.PartitionTable[0].Size = (ulong)remaining; cache.Header.PartitionTable[0].Address = (ulong)pointer; var debugSection = cache.Header.SectionTable[0]; var resourceSection = cache.Header.SectionTable[1]; var metadataSection = cache.Header.SectionTable[2]; var localesSection = cache.Header.SectionTable[3]; resourceSection.Size = (uint)resourceSegment.AvailableSize; localesSection.Address = resourceSection.Address + resourceSection.Size; localesSection.Size = (uint)localesGroup.AvailableSize; metadataSection.Address = resourceSection.Address + resourceSection.Size + localesSection.Size; metadataSection.Size = (uint)metadataSegment.AvailableSize; debugSection.Address = resourceSection.Address + resourceSection.Size + localesSection.Size + metadataSection.Size; debugSection.Size = (uint)stringsGroup.AvailableSize; if (debugSection.Address != 0 && cache.Header.SectionOffsetTable[0] != 0) { debugSection.Address -= (uint)cache.Header.PartitionTable[0].Size; } var offsets = cache.Header.SectionOffsetTable; offsets[0] = (uint)(stringsGroup.Offset - debugSection.Address); offsets[1] = (uint)(resourceSegment.Offset - resourceSection.Address); offsets[2] = (uint)(metadataSegment.Offset - metadataSection.Address); offsets[3] = (uint)(localesGroup.Offset - localesSection.Address); cache.Header.TagDataAddress = (int)metadataSection.Address; cache.Header.VirtualBaseAddress = pointer; //index header address cache.Header.VirtualSize = metadataSegment.AvailableSize; pointer = debugTranslator.GetPointer(stringSegments[0].Offset); cache.Header.StringTableIndexPointer = new Pointer((int)pointer, cache.Header.StringTableIndexPointer); pointer = debugTranslator.GetPointer(stringSegments[1].Offset); cache.Header.StringTablePointer = new Pointer((int)pointer, cache.Header.StringTablePointer); pointer = debugTranslator.GetPointer(stringSegments[2].Offset); cache.Header.FileTableIndexPointer = new Pointer((int)pointer, cache.Header.FileTableIndexPointer); pointer = debugTranslator.GetPointer(stringSegments[3].Offset); cache.Header.FileTablePointer = new Pointer((int)pointer, cache.Header.FileTablePointer); //only exists in mcc reach (U3+) var mcc3 = cache.Header as IMccGen3Header; if (mcc3?.StringNamespaceCount > 0) { pointer = debugTranslator.GetPointer(stringSegments[4].Offset); mcc3.StringNamespaceTablePointer = new Pointer((int)pointer, mcc3.StringNamespaceTablePointer); } var gen4 = cache.Header as IGen4Header; if (gen4?.UnknownTableSize > 0) { pointer = debugTranslator.GetPointer(stringSegments[5].Offset); gen4.UnknownTablePointer = new Pointer((int)pointer, gen4.UnknownTablePointer); } foreach (var pair in localeSegments) { var def = cache.LocaleIndex.Languages[pair.Key]; var segs = pair.Value; def.IndicesOffset = (int)localeTranslator.GetPointer(segs[0].Offset); def.StringsOffset = (int)localeTranslator.GetPointer(segs[1].Offset); } insertedAt = metadataSegment.Offset; insertedCount = length; writer.Seek(0, SeekOrigin.Begin); writer.WriteObject(cache.Header, (int)cache.CacheType); writer.Seek(metadataSegment.Offset, SeekOrigin.Begin); writer.Insert(0, length); var globalsTag = cache.TagIndex.GetGlobalTag("matg"); writer.Seek(globalsTag.MetaPointer.Address, SeekOrigin.Begin); writer.WriteObject(cache.LocaleIndex); }