public void Commit(EndianWriterEx writer) { if (!hasChanged) { return; } if (BlockRef != null && EntryCount != BlockRef.Count) { stream.ResizeTagBlock(writer, ref blockRef, EntrySize, EntryCount); //we dont know if our parent has already been written (or even will be) //just to be sure, we need to go back and update it with the new reference var refOffset = ParentBlock.EntrySize * ParentEntryIndex + OffsetInParent; writer.Seek(ParentBlock.PhysicalAddress + refOffset, SeekOrigin.Begin); BlockRef.Write(writer, null); } var rootAddress = BlockRef?.Pointer.Address ?? OffsetInParent; if (EntryCount > 0) { writer.Seek(rootAddress, SeekOrigin.Begin); writer.Write(data); //this writes our virtual pointers to disk (fix them below) } //the block references in our data array currently use virtual pointers //this restores the original pointers that got overwritten above foreach (var child in ChildBlocks) { writer.Seek(rootAddress + EntrySize * child.ParentEntryIndex + child.OffsetInParent + 4, SeekOrigin.Begin); writer.Write(child.BlockRef.Pointer.Value); } hasChanged = false; }
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); }