/// <summary> /// Builds a memory map for a tag. /// </summary> /// <param name="data">The tag data to build a memory map for.</param> /// <returns>The built map.</returns> private static MemoryMap BuildTagMap(CachedTagData data) { // Create a memory map with a boundary at each fixup target // and at the main structure var result = new MemoryMap(0, (uint)data.Data.Length); result.AddBoundary(data.MainStructOffset); result.AddBoundaries(data.PointerFixups.Select(f => f.TargetOffset)); return(result); }
public TagLayoutGuess Analyze(CachedTagData data) { _tagMap = BuildTagMap(data); _dataFixupsByWriteOffset = data.PointerFixups.ToDictionary(f => f.WriteOffset); _resourceFixupsByWriteOffset = new HashSet <uint>(data.ResourcePointerOffsets); using (var reader = new BinaryReader(new MemoryStream(data.Data))) { reader.BaseStream.Position = data.MainStructOffset; return(AnalyzeStructure(reader, 1)); } }
public void BeginSerialize(TagStructureInfo info) { Data = new CachedTagData { Group = new TagGroup ( tag: info.GroupTag, parentTag: info.ParentGroupTag, grandparentTag: info.GrandparentGroupTag, name: (info.Structure.Name != null) ? Context.GetStringId(info.Structure.Name) : StringId.Invalid ), }; }
private void AddTags(HashSet <int> tagIndices) { // define current cache tags, names var modTagCache = ModPackage.TagCaches[0]; var modTagNames = ModPackage.TagCacheNames[0]; var modTagStream = ModPackage.TagCachesStreams[0]; using (var srcTagStream = CacheContext.OpenCacheRead()) { var resourceIndices = new Dictionary <ResourceLocation, Dictionary <int, PageableResource> > { [ResourceLocation.Audio] = new Dictionary <int, PageableResource>(), [ResourceLocation.Lightmaps] = new Dictionary <int, PageableResource>(), [ResourceLocation.Mods] = new Dictionary <int, PageableResource>(), [ResourceLocation.RenderModels] = new Dictionary <int, PageableResource>(), [ResourceLocation.Resources] = new Dictionary <int, PageableResource>(), [ResourceLocation.ResourcesB] = new Dictionary <int, PageableResource>(), [ResourceLocation.Textures] = new Dictionary <int, PageableResource>(), [ResourceLocation.TexturesB] = new Dictionary <int, PageableResource>() }; var srcResourceCaches = new Dictionary <ResourceLocation, ResourceCacheHaloOnline>(); var srcResourceStreams = new Dictionary <ResourceLocation, Stream>(); foreach (var value in Enum.GetValues(typeof(ResourceLocation))) { ResourceCacheHaloOnline resourceCache = null; var location = (ResourceLocation)value; if (location == ResourceLocation.None) { continue; } try { resourceCache = CacheContext.ResourceCaches.GetResourceCache(location); } catch (FileNotFoundException) { continue; } srcResourceCaches[location] = resourceCache; srcResourceStreams[location] = CacheContext.ResourceCaches.OpenCacheRead(location); } for (var tagIndex = 0; tagIndex < CacheContext.TagCache.Count; tagIndex++) { var srcTag = CacheContext.TagCache.GetTag(tagIndex); if (srcTag == null) { modTagCache.AllocateTag(new TagTool.Tags.TagGroup()); continue; } if (!tagIndices.Contains(tagIndex)) { var emptyTag = modTagCache.AllocateTag(srcTag.Group, srcTag.Name); var cachedTagData = new CachedTagData(); cachedTagData.Data = new byte[0]; cachedTagData.Group = emptyTag.Group; modTagCache.SetTagData(modTagStream, (CachedTagHaloOnline)emptyTag, cachedTagData); continue; } var destTag = modTagCache.AllocateTag(srcTag.Group, srcTag.Name); using (var tagDataStream = new MemoryStream(CacheContext.TagCacheGenHO.ExtractTagRaw(srcTagStream, (CachedTagHaloOnline)srcTag))) using (var tagDataReader = new EndianReader(tagDataStream, leaveOpen: true)) using (var tagDataWriter = new EndianWriter(tagDataStream, leaveOpen: true)) { var resourcePointerOffsets = new HashSet <uint>(); foreach (var resourcePointerOffset in ((CachedTagHaloOnline)srcTag).ResourcePointerOffsets) { if (resourcePointerOffset == 0 || resourcePointerOffsets.Contains(resourcePointerOffset)) { continue; } resourcePointerOffsets.Add(resourcePointerOffset); tagDataStream.Position = resourcePointerOffset; var resourcePointer = tagDataReader.ReadUInt32(); if (resourcePointer == 0) { continue; } var resourceOffset = ((CachedTagHaloOnline)srcTag).PointerToOffset(resourcePointer); tagDataReader.BaseStream.Position = resourceOffset + 2; var locationFlags = (OldRawPageFlags)tagDataReader.ReadByte(); var resourceLocation = locationFlags.HasFlag(OldRawPageFlags.InAudio) ? ResourceLocation.Audio : locationFlags.HasFlag(OldRawPageFlags.InResources) ? ResourceLocation.Resources : locationFlags.HasFlag(OldRawPageFlags.InResourcesB) ? ResourceLocation.ResourcesB : locationFlags.HasFlag(OldRawPageFlags.InTextures) ? ResourceLocation.Textures : locationFlags.HasFlag(OldRawPageFlags.InTexturesB) ? ResourceLocation.TexturesB : ResourceLocation.ResourcesB; tagDataReader.BaseStream.Position = resourceOffset + 4; var resourceIndex = tagDataReader.ReadInt32(); var compressedSize = tagDataReader.ReadUInt32(); if (resourceIndex == -1) { continue; } PageableResource pageable = null; if (resourceIndices[resourceLocation].ContainsKey(resourceIndex)) { pageable = resourceIndices[resourceLocation][resourceIndex]; } else { var newResourceIndex = ModPackage.Resources.AddRaw( ModPackage.ResourcesStream, srcResourceCaches[resourceLocation].ExtractRaw( srcResourceStreams[resourceLocation], resourceIndex, compressedSize)); pageable = resourceIndices[resourceLocation][resourceIndex] = new PageableResource { Page = new ResourcePage { OldFlags = OldRawPageFlags.InMods, Index = newResourceIndex } }; } tagDataReader.BaseStream.Position = resourceOffset + 2; tagDataWriter.Write((byte)pageable.Page.OldFlags); tagDataReader.BaseStream.Position = resourceOffset + 4; tagDataWriter.Write(pageable.Page.Index); } modTagCache.SetTagDataRaw(modTagStream, (CachedTagHaloOnline)destTag, tagDataStream.ToArray()); } } foreach (var stream in srcResourceStreams.Values) { if (stream != null) { stream.Dispose(); } } modTagCache.UpdateTagOffsets(new EndianWriter(modTagStream)); } }