public void SaveChanges(IStream stream) { if (!_changed) { return; } var scenarioLayout = _buildInfo.Layouts.GetLayout("scnr"); stream.SeekTo(_scenario.MetaLocation.AsOffset()); var scenarioData = StructureReader.ReadStructure(stream, scenarioLayout); var oldCount = (int)scenarioData.GetInteger("simulation definition table count"); var oldAddress = (uint)scenarioData.GetInteger("simulation definition table address"); long expand = _expander.Expand(oldAddress); var entryLayout = _buildInfo.Layouts.GetLayout("simulation definition table entry"); var newTable = _table.Select(SerializeTag); var newAddr = ReflexiveWriter.WriteReflexive(newTable, oldCount, expand, _table.Count, entryLayout, _metaArea, _allocator, stream); uint cont = _expander.Contract(newAddr); scenarioData.SetInteger("simulation definition table count", (uint)_table.Count); scenarioData.SetInteger("simulation definition table address", cont); stream.SeekTo(_scenario.MetaLocation.AsOffset()); StructureWriter.WriteStructure(scenarioData, scenarioLayout, stream); _changed = false; }
private List <ScriptGlobal> LoadGlobals(IReader reader, StructureValueCollection values) { int count = (int)values.GetInteger("number of script globals"); uint address = (uint)values.GetInteger("script global table address"); long expand = _expander.Expand(address); StructureLayout layout = _buildInfo.Layouts.GetLayout("script global element"); StructureValueCollection[] entries = TagBlockReader.ReadTagBlock(reader, count, expand, layout, _metaArea); return(entries.Select(e => new ScriptGlobal(e, _stringIDs)).ToList()); }
private void Load(StructureValueCollection values, ushort index, FileSegmentGroup metaArea, IList <ITagClass> classList, IPointerExpander expander) { uint address = (uint)values.GetInteger("memory address"); if (address != 0 && address != 0xFFFFFFFF) { long expanded = expander.Expand(address); MetaLocation = SegmentPointer.FromPointer(expanded, metaArea); } var classIndex = (int)values.GetInteger("class index"); if (classIndex >= 0 && classIndex < classList.Count) { Class = classList[classIndex]; } var salt = (ushort)values.GetInteger("datum index salt"); if (salt != 0xFFFF) { Index = new DatumIndex(salt, index); } else { Index = DatumIndex.Null; } }
private BitArray LoadBitArray(StructureValueCollection values, string countName, string addressName, IReader reader, IPointerExpander expander) { if (!values.HasInteger(countName) || !values.HasInteger(addressName)) { return(new BitArray(0)); } var count = (int)values.GetInteger(countName); uint address = (uint)values.GetInteger(addressName); if (count <= 0 || address == 0) { return(new BitArray(0)); } long expand = expander.Expand(address); var ints = new int[count]; reader.SeekTo(_metaArea.PointerToOffset(expand)); for (int i = 0; i < count; i++) { ints[i] = reader.ReadInt32(); } return(new BitArray(ints)); }
private IEnumerable <ThirdGenZoneSet> ReadZoneSetTable(StructureValueCollection tagValues, string countName, string addressName, IReader reader) { if (!tagValues.HasInteger(countName) || !tagValues.HasInteger(addressName)) { return(Enumerable.Empty <ThirdGenZoneSet>()); } var count = (int)tagValues.GetInteger(countName); uint address = (uint)tagValues.GetInteger(addressName); long expand = _expander.Expand(address); StructureLayout layout = _buildInfo.Layouts.GetLayout("zone set definition"); StructureValueCollection[] entries = TagBlockReader.ReadTagBlock(reader, count, expand, layout, _metaArea); return(entries.Select(e => new ThirdGenZoneSet(e, reader, _metaArea, _expander))); }
public IEnumerable <ResourcePage> LoadPages(IReader reader) { StructureValueCollection values = LoadTag(reader); ThirdGenCacheFileReference[] files = LoadExternalFiles(values, reader); var count = (int)values.GetInteger("number of raw pages"); uint address = (uint)values.GetInteger("raw page table address"); long expand = _expander.Expand(address); StructureLayout layout = _buildInfo.Layouts.GetLayout("raw page table element"); StructureValueCollection[] entries = TagBlockReader.ReadTagBlock(reader, count, expand, layout, _metaArea); return(entries.Select((e, i) => LoadPage(e, i, files))); }
/// <summary> /// Reads all child objects of this block. /// </summary> /// <param name="values">The values read from the parent.</param> /// <param name="reader">The stream to read from.</param> /// <param name="metaArea">The meta area of the cache file.</param> /// <param name="stringIDs">The string ID source for the cache file.</param> /// <param name="buildInfo">The build info for the cache file.</param> /// <returns>The objects that were read.</returns> public ScriptObject[] ReadObjects(StructureValueCollection values, IReader reader, FileSegmentGroup metaArea, StringIDSource stringIDs, EngineDescription buildInfo, IPointerExpander expander) { var count = (int)values.GetInteger(_countEntryName); uint address = (uint)values.GetInteger(_addressEntryName); long expand = expander.Expand(address); StructureLayout layout = buildInfo.Layouts.GetLayout(_layoutName); StructureValueCollection[] entries = TagBlockReader.ReadTagBlock(reader, count, expand, layout, metaArea); return(entries.Select(e => ReadScriptObject(e, reader, metaArea, stringIDs, buildInfo, expander)).ToArray()); }
private IList <ScriptParameter> LoadParameters(IReader reader, StructureValueCollection values, FileSegmentGroup metaArea, EngineDescription buildInfo, IPointerExpander expander) { var count = (int)values.GetInteger("number of parameters"); uint address = (uint)values.GetInteger("address of parameter list"); long expand = expander.Expand(address); StructureLayout layout = buildInfo.Layouts.GetLayout("script parameter element"); StructureValueCollection[] entries = TagBlockReader.ReadTagBlock(reader, count, expand, layout, metaArea); return(entries.Select(e => new ScriptParameter(e)).ToList()); }
public static void WriteContractedTagBlock(IEnumerable <StructureValueCollection> elements, uint address, StructureLayout layout, FileSegmentGroup metaArea, IWriter writer, IPointerExpander expander) { long cont = expander.Expand(address); int offset = metaArea.PointerToOffset(address); int index = 0; foreach (StructureValueCollection entry in elements) { writer.SeekTo(offset + index * layout.Size); StructureWriter.WriteStructure(entry, layout, writer); index++; } }
private static void FreeBitArray(StructureValueCollection values, string countName, string addressName, MetaAllocator allocator, IPointerExpander expander) { if (!values.HasInteger(countName) || !values.HasInteger(addressName)) { return; } var oldCount = (int)values.GetInteger(countName); uint oldAddress = (uint)values.GetInteger(addressName); long expand = expander.Expand(oldAddress); if (oldCount > 0 && oldAddress > 0) { allocator.Free(expand, oldCount * 4); } }
private void Load(StructureValueCollection values, ushort index, FileSegmentGroup metaArea, IList<ITagGroup> groupList, IPointerExpander expander) { uint address = (uint)values.GetInteger("memory address"); if (address != 0 && address != 0xFFFFFFFF) { long expanded = expander.Expand(address); MetaLocation = SegmentPointer.FromPointer(expanded, metaArea); } var groupIndex = (int) values.GetInteger("tag group index"); if (groupIndex >= 0 && groupIndex < groupList.Count) Group = groupList[groupIndex]; var salt = (ushort) values.GetInteger("datum index salt"); if (salt != 0xFFFF) Index = new DatumIndex(salt, index); else Index = DatumIndex.Null; }
private void SaveData(IStream stream, EffectInteropType type) { long pointer; byte[] data; switch (type) { case EffectInteropType.Effect: pointer = _effePointer; data = _effe.SelectMany(a => a).ToArray(); break; case EffectInteropType.Beam: pointer = _beamPointer; data = _beam.SelectMany(a => a).ToArray(); break; case EffectInteropType.Contrail: pointer = _cntlPointer; data = _cntl.SelectMany(a => a).ToArray(); break; case EffectInteropType.LightVolume: pointer = _ltvlPointer; data = _ltvl.SelectMany(a => a).ToArray(); break; default: return; } var pointerLayout = _buildInfo.Layouts.GetLayout("data reference"); stream.SeekTo(_metaArea.PointerToOffset(pointer)); var pointerData = StructureReader.ReadStructure(stream, pointerLayout); var oldSize = (int)pointerData.GetInteger("size"); var oldAddress = (uint)pointerData.GetInteger("pointer"); var oldExpand = _expander.Expand(oldAddress); if (oldExpand >= 0 && oldSize > 0) { _allocator.Free(oldExpand, oldSize); } long newAddress = 0; if (data.Length > 0) { newAddress = _allocator.Allocate(data.Length, 0x10, stream); stream.SeekTo(_metaArea.PointerToOffset(newAddress)); stream.WriteBlock(data); } uint cont = _expander.Contract(newAddress); pointerData.SetInteger("size", (ulong)data.Length); pointerData.SetInteger("pointer", cont); stream.SeekTo(_metaArea.PointerToOffset(pointer)); StructureWriter.WriteStructure(pointerData, pointerLayout, stream); }
public void AnalyzeArea(IReader reader, long startAddress, MetaMap resultMap) { // Right now, this method only searches for the signatures of a few complex meta values. // Reflexives: int32 entry count + uint32 address + 4 bytes of padding // Data references: int32 size + 8 bytes of padding + uint32 address // Tag references: int32 class id + 8 bytes of padding + uint32 datum index // ASCII strings: characters with the values 0 or 0x20 - 0x7F // End at the next-highest address long endAddress = _memMap.GetNextHighestAddress(startAddress); if (endAddress == 0xFFFFFFFF) { throw new InvalidOperationException("Invalid start address for area analysis"); } uint size = (uint)(endAddress - startAddress); // The size of the block of data int paddingLength = 0; // The number of 4-byte padding values that have been read uint prePadding = 0; // The last non-padding uint32 that was read MetaValueGuess pendingGuess = null; // If not null and padding is encountered, this guess is confirmed for (int offset = 0; offset < size; offset += 4) { uint value = reader.ReadUInt32(); long expValue = _expander.Expand(value); if (IsPadding(value)) { if (paddingLength == 0 && pendingGuess != null) { resultMap.AddGuess(pendingGuess); // Add the address to the memory map long address = pendingGuess.Pointer; _memMap.AddAddress(address, (int)reader.Position); } // More padding! :D paddingLength++; pendingGuess = null; } else { pendingGuess = null; if (offset <= size - 8 && prePadding > 0 && prePadding < 0x80000000 // && (value & 3) == 0 && IsValidAddress(expValue) && expValue + prePadding > value && IsValidAddress(expValue + prePadding - 1) && !_memMap.BlockCrossesBoundary(expValue, (int)prePadding)) { // Either a reflexive or a data reference // Check the padding to determine which (see the comments at the beginning of this method) if (paddingLength == 2 && offset >= 12 && (prePadding & 3) == 0) { // Found a data reference uint dataSize = prePadding; pendingGuess = new MetaValueGuess(offset - 12, MetaValueType.DataReference, expValue, dataSize); // Guess with Pointer = address, Data1 = data size } else if (paddingLength == 0 && offset >= 4) { // Found a reflexive! uint entryCount = prePadding; pendingGuess = new MetaValueGuess(offset - 4, MetaValueType.Reflexive, expValue, entryCount); // Guess with Pointer = address, Data1 = entry count } } if (paddingLength == 2 && offset >= 12 && (_classIds.Contains((int)prePadding) || (prePadding == 0xFFFFFFFF && value == 0xFFFFFFFF))) { // Found a tag reference uint classId = prePadding; uint datumIndex = value; var guess = new MetaValueGuess(offset - 12, MetaValueType.TagReference, datumIndex, classId); // Guess with Pointer = datum index, Data1 = class id resultMap.AddGuess(guess); } // This obviously isn't a padding value because IsPadding returned false, // so update padding run information accordingly prePadding = value; paddingLength = 0; } } }
public IList <ResourcePointer> SaveResources(ICollection <Resource> resources, IStream stream) { StructureValueCollection values = LoadTag(stream); StructureLayout layout = _buildInfo.Layouts.GetLayout("resource table entry"); FreeResources(values, stream); FreeInfoBuffer(values); // Serialize each resource entry // This can't be lazily evaluated because allocations might cause the stream to expand int infoOffset = 0; int altInfoOffset = 0; var infocache = new ReflexiveCache <int>(); var pointers = new List <ResourcePointer>(); var entries = new List <StructureValueCollection>(); var fixupCache = new ReflexiveCache <ResourceFixup>(); var defFixupCache = new ReflexiveCache <ResourceDefinitionFixup>(); List <byte[]> paddedInfos = new List <byte[]>(); foreach (Resource resource in resources) { StructureValueCollection entry = SerializeResource(resource, (resource.Location != null) ? pointers.Count : -1, stream); entries.Add(entry); // Save fixups SaveResourceFixups(resource.ResourceFixups, entry, stream, fixupCache); SaveDefinitionFixups(resource.DefinitionFixups, entry, stream, defFixupCache); uint bits = (uint)entry.GetInteger("resource bits"); int size = (int)entry.GetInteger("resource info size"); List <int> offsets = new List <int>(); if (size > 0) { int dirtyoffset = infoOffset; infoOffset = AlignInfoBlockOffset(resource, infoOffset); offsets.Add(infoOffset); int padding = infoOffset - dirtyoffset; byte[] temp = new byte[padding + size]; Buffer.BlockCopy(resource.Info, 0, temp, padding, size); paddedInfos.Add(temp); infoOffset += size; } else { offsets.Add(0); } if ((bits & 2) > 0) { int tempalt = AlignInfoBlockOffset(resource, altInfoOffset); offsets.Add(tempalt); altInfoOffset += size; } else { offsets.Add(size > 0 ? -1 : 0); } if ((bits & 4) > 0) { int tempalt = AlignInfoBlockOffset(resource, altInfoOffset); offsets.Add(tempalt); altInfoOffset += size; } else { offsets.Add(size > 0 ? -1 : 0); } if (layout.HasField("number of resource info offsets")) { var oldCount = (int)entry.GetIntegerOrDefault("number of resource info offsets", 0); uint oldAddress = (uint)entry.GetIntegerOrDefault("resource info offsets table address", 0); long expand = _expander.Expand(oldAddress); StructureLayout infolayout = _buildInfo.Layouts.GetLayout("resource info offset entry"); if (size > 0) { long newBlockAddress; // Write a new reflexive IEnumerable <StructureValueCollection> infoentries = offsets.Select(f => SerializeInfos(f)); newBlockAddress = ReflexiveWriter.WriteReflexive(infoentries, oldCount, expand, offsets.Count, infolayout, _metaArea, _allocator, stream); infocache.Add(newBlockAddress, offsets); uint cont = _expander.Contract(newBlockAddress); entry.SetInteger("number of resource info offsets", (uint)offsets.Count); entry.SetInteger("resource info offsets table address", cont); } else { entry.SetInteger("number of resource info offsets", 0); entry.SetInteger("resource info offsets table address", 0); } } else { if (size > 0) { entry.SetInteger("resource info offset", (uint)offsets[0]); entry.SetInteger("alt resource info offset", (uint)offsets[1]); } else { entry.SetInteger("resource info offset", 0); entry.SetInteger("alt resource info offset", 0); } } // Update pointer info if (resource.Location != null) { pointers.Add(resource.Location); } } // Write the reflexive and update the tag values long newAddress = ReflexiveWriter.WriteReflexive(entries, layout, _metaArea, _allocator, stream); uint contr = _expander.Contract(newAddress); values.SetInteger("number of resources", (uint)entries.Count); values.SetInteger("resource table address", contr); // Save the info buffer SaveResourceInfoBuffer(paddedInfos.SelectMany(a => a).ToArray(), values, stream); SaveTag(values, stream); return(pointers); }