public InMemoryMetadataStream(IIndexItem item, XmlDocument doc) { var gen3Cache = item.CacheFile as IGen3CacheFile; if (gen3Cache == null) { throw new ArgumentException("Cache must implement IGen3CacheFile."); } segmenter = new CacheSegmenter(gen3Cache); SourceItem = item; AllBlocks = new List <InMemoryBlockCollection>(); using (var reader = item.CacheFile.CreateReader(item.CacheFile.DefaultAddressTranslator)) { var expander = (item.CacheFile as IMccCacheFile)?.PointerExpander; if (expander != null) { reader.RegisterInstance(expander); } reader.Seek(item.MetaPointer.Address, SeekOrigin.Begin); RootBlock = ReadBlocks(reader, doc.DocumentElement, null, 0); } currentBlock = AllBlocks.FirstOrDefault(b => b.ContainsVirtualAddress(position)); isInitialised = true; }
private InMemoryBlockCollection ReadBlocks(EndianReader reader, XmlNode node, InMemoryBlockCollection parent, int parentBlockIndex) { var result = new InMemoryBlockCollection(this, reader, node, parent, parentBlockIndex); var lastBlock = AllBlocks.LastOrDefault(); var nextAddress = (lastBlock?.VirtualAddress + lastBlock?.AllocatedSize) ?? 0; var nextSize = PageSize; while (nextSize < result.VirtualSize) { nextSize += PageSize; } result.Allocate(nextAddress, nextSize); AllBlocks.Add(result); var blockAddress = parent == null ? SourceItem.MetaPointer.Address : result.BlockRef.Pointer.Address; for (int i = 0; i < result.EntryCount; i++) { var indexAddress = blockAddress + result.EntrySize * i; foreach (var childNode in node.SelectNodes("tagblock").OfType <XmlNode>()) { reader.Seek(indexAddress + childNode.GetIntAttribute("offset").Value, SeekOrigin.Begin); ReadBlocks(reader, childNode, result, i); } } return(result); }
public InMemoryBlockCollection(IMetadataStream stream, EndianReader reader, XmlNode node, InMemoryBlockCollection parent, int parentBlockIndex) { this.stream = stream; defaultValues = new Dictionary <int, byte[]>(); XmlNode = node; ParentBlock = parent; ParentEntryIndex = parentBlockIndex; ChildBlocks = new List <InMemoryBlockCollection>(); ParentBlock?.ChildBlocks.Add(this); if (parent == null) //tag root { Name = stream.SourceTag.FileName(); blockRef = null; EntryCount = 1; EntrySize = node.GetIntAttribute("baseSize") ?? 0; data = reader.ReadBytes(VirtualSize); } else { offsetInParent = node.GetIntAttribute("offset") ?? 0; Name = node.GetStringAttribute("name"); blockRef = reader.ReadObject <TagBlock>(); EntryCount = BlockRef.IsInvalid ? 0 : BlockRef.Count; EntrySize = node.GetIntAttribute("elementSize", "entrySize", "size") ?? 0; if (EntryCount > 0) { reader.Seek(BlockRef.Pointer.Address, SeekOrigin.Begin); data = reader.ReadBytes(VirtualSize); } else { data = Array.Empty <byte>(); } } foreach (var element in node.SelectNodes("*[@offset][@defaultValue]").OfType <XmlNode>()) { var offset = element.GetIntAttribute("offset").Value; var defaultValue = element.GetStringAttribute("defaultValue"); Func <string, int> getFlagValue = (val) => val.Split('|').Select(s => 1 << int.Parse(s)).Sum(); byte[] bytes; switch (element.Name.ToLower()) { case "int8": case "enum8": case "blockindex8": bytes = new[] { defaultValue == "-1" ? byte.MaxValue : byte.Parse(defaultValue) }; break; case "int16": case "blockindex16": bytes = BitConverter.GetBytes(short.Parse(defaultValue)); break; case "uint16": case "enum16": bytes = BitConverter.GetBytes(ushort.Parse(defaultValue)); break; case "int32": case "blockindex32": bytes = BitConverter.GetBytes(int.Parse(defaultValue)); break; case "uint32": case "enum32": bytes = BitConverter.GetBytes(uint.Parse(defaultValue)); break; case "float32": bytes = BitConverter.GetBytes(float.Parse(defaultValue)); break; case "flags8": bytes = BitConverter.GetBytes((byte)getFlagValue(defaultValue)); break; case "flags16": bytes = BitConverter.GetBytes((ushort)getFlagValue(defaultValue)); break; case "flags32": bytes = BitConverter.GetBytes((uint)getFlagValue(defaultValue)); break; default: continue; } if (stream.ByteOrder == ByteOrder.BigEndian) { Array.Reverse(bytes); } defaultValues.Add(offset, bytes); } }