private void ProcessPlacedCreature( MajorRecordFrame majorFrame, long fileOffset) { int amount = 0; if (majorFrame.TryLocateSubrecordPinFrame(RecordTypes.DATA, out var dataRec)) { ProcessZeroFloats(dataRec, fileOffset, 6); } ProcessLengths( majorFrame, amount, fileOffset); }
/// <summary> /// Retrieves the character representing a Global's data type from a MajorRecordFrame /// </summary> /// <param name="frame">Frame to retrieve from</param> /// <returns>Character representing data type</returns> /// <exception cref="ArgumentException">If FNAM not present or malformed</exception> public static char GetGlobalChar(MajorRecordFrame frame) { var subrecordSpan = frame.Content; var fnamLocation = UtilityTranslation.FindFirstSubrecord(subrecordSpan, frame.Header.Meta, FNAM); if (fnamLocation == null) { throw new ArgumentException($"Could not find FNAM."); } var fnamMeta = frame.Header.Meta.SubrecordFrame(subrecordSpan.Slice(fnamLocation.Value)); if (fnamMeta.Content.Length != 1) { throw new ArgumentException($"FNAM had non 1 length: {fnamMeta.Content.Length}"); } return((char)fnamMeta.Content[0]); }
private void ProcessGameSettings( MajorRecordFrame majorFrame, long fileOffset) { var edidRec = majorFrame.LocateSubrecordFrame("EDID"); if ((char)edidRec.Content[0] != 'f') { return; } if (majorFrame.TryLocateSubrecord(RecordTypes.DATA, out var dataRec, out var dataIndex)) { dataIndex += dataRec.HeaderLength; ProcessZeroFloat(majorFrame, fileOffset, ref dataIndex); } }
/// <summary> /// Finds and iterates subrecords of a given type /// </summary> /// <param name="majorFrame">Frame to read from</param> /// <param name="type">Type to search for</param> /// <param name="onlyFirstSet"> /// If true, iteration will stop after finding the first non-applicable record after some applicable ones.<br/> /// If false, records will continue to be searched in their entirety for all matching subrecords. /// </param> /// <returns>First encountered SubrecordFrame with the given type</returns> public static IEnumerable <SubrecordPinFrame> FindEnumerateSubrecords(this MajorRecordFrame majorFrame, RecordType type, bool onlyFirstSet = false) { bool encountered = false; foreach (var subrecord in majorFrame) { if (subrecord.RecordType == type) { encountered = true; yield return(subrecord); } else if (onlyFirstSet && encountered) { yield break; } } }
private void ProcessAIPackages( MajorRecordFrame majorFrame, long fileOffset) { int amount = 0; foreach (var ctdt in majorFrame.FindEnumerateSubrecords(RecordTypes.CTDT)) { this._instructions.SetSubstitution( loc: ctdt.Location + fileOffset + 3, sub: new byte[] { (byte)'A', 0x18 }); this._instructions.SetAddition( addition: new byte[4], loc: ctdt.Location + fileOffset + 0x1A); amount += 4; } foreach (var ctdt in majorFrame.FindEnumerateSubrecords(RecordTypes.PKDT)) { if (ctdt.ContentLength != 4) { continue; } this._instructions.SetSubstitution( loc: fileOffset + ctdt.Location + 4, sub: new byte[] { 0x8 }); var first1 = ctdt.Content[0]; var first2 = ctdt.Content[1]; var second1 = ctdt.Content[2]; var second2 = ctdt.Content[3]; this._instructions.SetSubstitution( loc: fileOffset + ctdt.Location + 6, sub: new byte[] { first1, first2, 0, 0 }); this._instructions.SetAddition( loc: fileOffset + ctdt.Location + 10, addition: new byte[] { second1, 0, 0, 0 }); amount += 4; } ProcessLengths( majorFrame, amount, fileOffset); }
private void ProcessRegions( MajorRecordFrame majorFrame, long fileOffset) { var rdat = UtilityTranslation.FindFirstSubrecord(majorFrame.Content, majorFrame.Meta, RecordTypes.RDAT, navigateToContent: false); if (rdat == null) { return; } // Order RDATs by index SortedList <uint, RangeInt64> rdats = new SortedList <uint, RangeInt64>(); List <uint> raw = new List <uint>(); while (rdat != null) { var rdatHeader = majorFrame.Meta.SubrecordFrame(majorFrame.Content.Slice(rdat.Value)); var index = BinaryPrimitives.ReadUInt32LittleEndian(rdatHeader.Content); var nextRdat = UtilityTranslation.FindFirstSubrecord( majorFrame.Content, majorFrame.Meta, RecordTypes.RDAT, navigateToContent: false, offset: rdat.Value + rdatHeader.TotalLength); rdats[index] = new RangeInt64( fileOffset + majorFrame.HeaderLength + rdat.Value, nextRdat == null ? fileOffset + majorFrame.TotalLength - 1 : nextRdat.Value - 1 + fileOffset + majorFrame.HeaderLength); raw.Add(index); rdat = nextRdat; } if (raw.SequenceEqual(rdats.Keys)) { return; } foreach (var item in rdats.Reverse()) { this._Instructions.SetMove( loc: fileOffset + majorFrame.TotalLength, section: item.Value); } }
private void ProcessGameSettings( MajorRecordFrame majorFrame, long fileOffset) { if (!majorFrame.TryLocateSubrecordFrame("EDID", out var edidFrame)) { return; } if ((char)edidFrame.Content[0] != 'f') { return; } if (!majorFrame.TryLocateSubrecordPinFrame(RecordTypes.DATA, out var dataRec)) { return; } ProcessZeroFloat(dataRec, fileOffset); }
private void ProcessPlaced( MajorRecordFrame majorFrame, long fileOffset) { var sizeChange = 0; if (majorFrame.TryLocateSubrecordPinFrame(RecordTypes.DATA, out var dataRec)) { ProcessZeroFloats(dataRec, fileOffset, 6); } if (majorFrame.TryLocateSubrecordPinFrame(RecordTypes.XTEL, out var xtelRec)) { var offset = 4; ProcessZeroFloats(xtelRec, fileOffset, ref offset, 6); } if (majorFrame.TryLocateSubrecordPinFrame(RecordTypes.XPRM, out var xprmRec)) { int offset = 0; ProcessZeroFloats(xprmRec, fileOffset, ref offset, 3); ProcessColorFloat(xprmRec, fileOffset, ref offset); ProcessZeroFloat(xprmRec, fileOffset, ref offset); } if (majorFrame.TryLocateSubrecordFrame(RecordTypes.XRMR, out var xrmrRec, out var xrmrIndex)) { if (xrmrRec.AsInt32() == 0) { _Instructions.SetRemove( RangeInt64.FactoryFromLength( fileOffset + xrmrIndex, 10)); sizeChange -= 10; } } ProcessLengths( majorFrame, sizeChange, fileOffset); }
private void ProcessDialogItems( MajorRecordFrame majorFrame, long fileOffset) { int amount = 0; foreach (var ctdt in majorFrame.FindEnumerateSubrecords(RecordTypes.CTDT)) { this._instructions.SetSubstitution( loc: ctdt.Location + fileOffset + 3, sub: new byte[] { (byte)'A', 0x18 }); this._instructions.SetAddition( addition: new byte[4], loc: ctdt.Location + fileOffset + 0x1A); amount += 4; } foreach (var schd in majorFrame.FindEnumerateSubrecords(RecordTypes.SCHD)) { var existingLen = schd.ContentLength; var diff = existingLen - 0x14; this._instructions.SetSubstitution( loc: schd.Location + fileOffset + 3, sub: new byte[] { (byte)'R', 0x14 }); if (diff == 0) { continue; } var locToRemove = fileOffset + schd.Location + schd.HeaderLength + 0x14; this._instructions.SetRemove( section: new RangeInt64( locToRemove, locToRemove + diff - 1)); amount -= diff; } ProcessLengths( majorFrame, amount, fileOffset); }
private void ProcessDialogs( IMutagenReadStream stream, MajorRecordFrame majorFrame, long fileOffset) { var formKey = FormKey.Factory(stream.MetaData.MasterReferences !, majorFrame.FormID.Raw); CleanEmptyDialogGroups( stream, formKey, fileOffset); // Reset misnumbered counter if (majorFrame.TryLocateSubrecordFrame(RecordTypes.TIFC, out var tifcRec, out var tifcIndex)) { var count = tifcRec.AsUInt32(); uint actualCount = 0; stream.Position = fileOffset + majorFrame.TotalLength; if (stream.TryReadGroupFrame(out var groupFrame)) { int groupPos = 0; while (groupPos < groupFrame.Content.Length) { var majorMeta = stream.MetaData.Constants.MajorRecord(groupFrame.Content.Slice(groupPos)); actualCount++; groupPos += checked ((int)majorMeta.TotalLength); } } if (actualCount != count) { byte[] b = new byte[4]; BinaryPrimitives.WriteUInt32LittleEndian(b, actualCount); _Instructions.SetSubstitution( fileOffset + tifcIndex + stream.MetaData.Constants.SubConstants.HeaderLength, b); } } }
private void ProcessNPC( MajorRecordFrame majorFrame, long fileOffset) { this.DynamicMove( majorFrame, fileOffset, offendingIndices: new RecordType[] { new RecordType("CNTO"), new RecordType("SCRI"), new RecordType("AIDT") }, offendingLimits: new RecordType[] { new RecordType("ACBS") }, locationsToMove: new RecordType[] { new RecordType("CNAM") }); }
private void ProcessIdleAnimations( MajorRecordFrame majorFrame, long fileOffset) { int amount = 0; foreach (var ctdt in majorFrame.FindEnumerateSubrecords(RecordTypes.CTDT)) { this._instructions.SetSubstitution( loc: ctdt.Location + fileOffset + 3, sub: new byte[] { (byte)'A', 0x18 }); this._instructions.SetAddition( addition: new byte[4], loc: ctdt.Location + fileOffset + 0x1A); amount += 4; } ProcessLengths( majorFrame, amount, fileOffset); }
/// <summary> /// Enumerates locations of the contained subrecords, while considering some specified RecordTypes as special length overflow subrecords.<br/> /// These length overflow subrecords will be skipped, and simply used to parse the next subrecord properly.<br /> /// Locations are relative to the RecordType of the MajorRecordFrame. /// </summary> /// <param name="majorFrame">MajorRecordFrame to iterate</param> /// <param name="lengthOverflowTypes">Collection of known RecordTypes that signify a length overflow subrecord</param> public static IEnumerable <SubrecordPinFrame> EnumerateSubrecords(this MajorRecordFrame majorFrame, ICollection <RecordType> lengthOverflowTypes) { int loc = majorFrame.HeaderLength; while (loc < majorFrame.HeaderAndContentData.Length) { var subFrame = new SubrecordPinFrame(majorFrame.Meta, majorFrame.HeaderAndContentData.Slice(loc), loc); if (lengthOverflowTypes.Contains(subFrame.RecordType)) { // Length overflow record var nextLen = subFrame.AsUInt32(); loc += subFrame.TotalLength; var span = majorFrame.HeaderAndContentData.Slice(loc, checked ((int)(nextLen + majorFrame.Meta.SubConstants.HeaderLength))); var subHeader = new SubrecordHeader(majorFrame.Meta, span); yield return(SubrecordPinFrame.FactoryNoTrim(subHeader, span, loc)); continue; } yield return(subFrame); loc += subFrame.TotalLength; } }
/// <summary> /// Enumerates locations of the contained subrecords.<br/> /// Locations are relative to the RecordType of the MajorRecordFrame. /// </summary> /// <param name="majorFrame">MajorRecordFrame to iterate</param> public static IEnumerable <SubrecordPinFrame> EnumerateSubrecords(this MajorRecordFrame majorFrame) => EnumerateSubrecords(majorFrame.HeaderAndContentData, majorFrame.Meta, majorFrame.HeaderLength);
private void ProcessWater( MajorRecordFrame majorFrame, long fileOffset) { var amount = 0; if (majorFrame.TryLocateSubrecord(RecordTypes.DATA, out var dataRec, out var dataLoc)) { var len = dataRec.ContentLength; if (len == 0x02) { this._instructions.SetSubstitution( loc: fileOffset + dataLoc + Plugins.Internals.Constants.HeaderLength, sub: new byte[] { 0, 0 }); this._instructions.SetRemove( section: RangeInt64.FactoryFromLength( loc: fileOffset + dataLoc + dataRec.HeaderLength, length: 2)); amount -= 2; } if (len == 0x56) { this._instructions.SetSubstitution( loc: fileOffset + dataLoc + Plugins.Internals.Constants.HeaderLength, sub: new byte[] { 0x54, 0 }); this._instructions.SetRemove( section: RangeInt64.FactoryFromLength( loc: fileOffset + dataLoc + dataRec.HeaderLength + 0x54, length: 2)); amount -= 2; } if (len == 0x2A) { this._instructions.SetSubstitution( loc: fileOffset + dataLoc + Plugins.Internals.Constants.HeaderLength, sub: new byte[] { 0x28, 0 }); this._instructions.SetRemove( section: RangeInt64.FactoryFromLength( loc: fileOffset + dataLoc + dataRec.HeaderLength + 0x28, length: 2)); amount -= 2; } if (len == 0x3E) { this._instructions.SetSubstitution( loc: fileOffset + dataLoc + Plugins.Internals.Constants.HeaderLength, sub: new byte[] { 0x3C, 0 }); this._instructions.SetRemove( section: RangeInt64.FactoryFromLength( loc: fileOffset + dataLoc + dataRec.HeaderLength + 0x3C, length: 2)); amount -= 2; } var move = 0x39; if (len >= 3 + move) { this._instructions.SetSubstitution( sub: new byte[] { 0, 0, 0 }, loc: fileOffset + dataLoc + dataRec.HeaderLength + move); } } ProcessLengths( majorFrame, amount, fileOffset); }
/// <summary> /// Iterates a MajorRecordFrame's subrecords and locates the first occurance of the desired type /// </summary> /// <param name="majorFrame">Frame to read from</param> /// <param name="type">Type to search for</param> /// <exception cref="System.ArgumentException">Thrown if target type cannot be found.</exception> /// <returns>First encountered SubrecordHeader with the given type</returns> public static SubrecordHeader LocateSubrecord(this MajorRecordFrame majorFrame, RecordType type) { return(majorFrame.LocateSubrecord(type, loc: out var _)); }
/// <summary> /// Iterates a MajorRecordFrame's contents and locates the first occurance of the desired type /// </summary> /// <param name="majorFrame">Frame to read from</param> /// <param name="type">Type to search for</param> /// <param name="header">SubrecordHeader if found</param> /// <returns>True if matching subrecord is found</returns> public static bool TryLocateSubrecord(this MajorRecordFrame majorFrame, RecordType type, out SubrecordHeader header) { return(majorFrame.TryLocateSubrecord(type, header: out header, loc: out var _)); }
/// <summary> /// Enumerates locations of the contained subrecords, while considering some specified RecordTypes as special length overflow subrecords.<br/> /// These length overflow subrecords will be skipped, and simply used to parse the next subrecord properly.<br /> /// Locations are relative to the RecordType of the MajorRecordFrame. /// </summary> /// <param name="majorFrame">MajorRecordFrame to iterate</param> /// <param name="lengthOverflowTypes">Known RecordTypes that signify a length overflow subrecord</param> public static IEnumerable <SubrecordPinFrame> EnumerateSubrecordsWithLengthOverflow(this MajorRecordFrame majorFrame, params RecordType[] lengthOverflowTypes) { return(EnumerateSubrecords(majorFrame, (ICollection <RecordType>)lengthOverflowTypes.ToHashSet())); }
private void ProcessPackages( MajorRecordFrame majorFrame, long fileOffset) { // Reorder Idle subrecords // Reorder data values var xnamPos = UtilityTranslation.FindFirstSubrecord(majorFrame.Content, majorFrame.Meta, RecordTypes.XNAM); if (xnamPos == null) { throw new ArgumentException(); } if (!majorFrame.TryLocateSubrecordFrame(RecordTypes.PKCU, out var pkcuRec)) { throw new ArgumentException(); } var count = pkcuRec.Content.Int32(); if (count == 0) { return; } var anamPos = UtilityTranslation.FindFirstSubrecord(majorFrame.Content, majorFrame.Meta, RecordTypes.ANAM); RecordType pldt = new RecordType("PLDT"); RecordType ptda = new RecordType("PTDA"); RecordType pdto = new RecordType("PDTO"); RecordType tpic = new RecordType("TPIC"); RecordType unam = new RecordType("UNAM"); RecordType bnam = new RecordType("BNAM"); RecordType pnam = new RecordType("PNAM"); // Reorder data values to be in index ordering if (anamPos.HasValue && anamPos.Value < xnamPos.Value) { var startLoc = anamPos.Value; var dataValues = new List <(sbyte Index, ReadOnlyMemorySlice <byte> Data)>(); var curLoc = startLoc; while (anamPos.HasValue && anamPos.Value < xnamPos.Value) { var anamRecord = majorFrame.Meta.SubrecordFrame(majorFrame.Content.Slice(anamPos.Value)); var recs = UtilityTranslation.FindNextSubrecords( majorFrame.Content.Slice(anamPos.Value + anamRecord.TotalLength), majorFrame.Meta, out var _, RecordTypes.ANAM, RecordTypes.CNAM, pldt, ptda, pdto, tpic); int finalLoc; if (recs[0] == null) { finalLoc = recs.NotNull().Max(); } else if (recs[0] == 0) { dataValues.Add( (-1, majorFrame.Content.Slice(anamPos.Value, anamRecord.TotalLength))); curLoc = anamPos.Value + anamRecord.TotalLength; anamPos = anamPos.Value + anamRecord.TotalLength; continue; } else { finalLoc = recs .NotNull() .Where(i => i < recs[0] !.Value) .Max(); } var finalRec = majorFrame.Meta.Subrecord(majorFrame.Content.Slice(anamPos.Value + anamRecord.TotalLength + finalLoc)); var dataSlice = majorFrame.Content.Slice(anamPos.Value, anamRecord.TotalLength + finalLoc + finalRec.TotalLength); if (BinaryStringUtility.ProcessWholeToZString(anamRecord.Content) == "Bool" && recs[1] != null) { // Ensure bool value is 1 or 0 var cnam = majorFrame.Meta.SubrecordFrame(majorFrame.Content.Slice(anamPos.Value + anamRecord.TotalLength + recs[1].Value)); if (cnam.Content.Length != 1) { throw new ArgumentException(); } if (cnam.Content[0] > 1) { var bytes = dataSlice.ToArray(); int boolIndex = anamRecord.TotalLength + recs[1].Value + cnam.HeaderLength; bytes[boolIndex] = (byte)(bytes[boolIndex] > 0 ? 1 : 0); dataSlice = bytes; } } dataValues.Add((-1, dataSlice)); curLoc = anamPos.Value + anamRecord.TotalLength + finalLoc + finalRec.TotalLength; anamPos = anamPos.Value + anamRecord.TotalLength + recs[0]; } var unamLocs = UtilityTranslation.ParseRepeatingSubrecord( majorFrame.Content.Slice(curLoc), majorFrame.Meta, unam, out var _); if (unamLocs == null || unamLocs.Length != dataValues.Count || unamLocs.Length != count) { throw new ArgumentException(); } for (sbyte i = 0; i < unamLocs.Length; i++) { var unamRec = majorFrame.Meta.SubrecordFrame(majorFrame.Content.Slice(curLoc + unamLocs[i])); dataValues[i] = ( (sbyte)unamRec.Content[0], dataValues[i].Data); } var subLoc = startLoc; foreach (var item in dataValues.OrderBy(i => i.Index)) { _Instructions.SetSubstitution( fileOffset + majorFrame.HeaderLength + subLoc, item.Data.ToArray()); subLoc += item.Data.Length; } foreach (var item in dataValues.OrderBy(i => i.Index)) { byte[] bytes = new byte[] { 0x55, 0x4E, 0x41, 0x4D, 0x01, 0x00, 0x00 }; bytes[6] = (byte)item.Index; _Instructions.SetSubstitution( fileOffset + majorFrame.HeaderLength + subLoc, bytes.ToArray()); subLoc += bytes.Length; } } // Reorder inputs var unamPos = UtilityTranslation.FindFirstSubrecord(majorFrame.Content.Slice(xnamPos.Value), majorFrame.Meta, unam); if (!unamPos.HasValue) { return; } unamPos += xnamPos.Value; var writeLoc = fileOffset + majorFrame.HeaderLength + unamPos.Value; var inputValues = new List <(sbyte Index, ReadOnlyMemorySlice <byte> Data)>(); while (unamPos.HasValue) { var unamRecord = majorFrame.Meta.SubrecordFrame(majorFrame.Content.Slice(unamPos.Value)); var recs = UtilityTranslation.FindNextSubrecords( majorFrame.Content.Slice(unamPos.Value + unamRecord.TotalLength), majorFrame.Meta, out var _, unam, bnam, pnam); int finalLoc; if (recs[0] == null) { finalLoc = recs.NotNull().Max(); } else if (recs[0] == 0) { inputValues.Add( ((sbyte)unamRecord.Content[0], majorFrame.Content.Slice(unamPos.Value, unamRecord.TotalLength))); unamPos = unamPos.Value + unamRecord.TotalLength; continue; } else { finalLoc = recs .NotNull() .Where(i => i < recs[0] !.Value) .Max(); } var finalRec = majorFrame.Meta.Subrecord(majorFrame.Content.Slice(unamPos.Value + unamRecord.TotalLength + finalLoc)); inputValues.Add( ((sbyte)unamRecord.Content[0], majorFrame.Content.Slice(unamPos.Value, unamRecord.TotalLength + finalLoc + finalRec.TotalLength))); unamPos = unamPos.Value + unamRecord.TotalLength + recs[0]; } foreach (var item in inputValues.OrderBy(i => i.Index)) { _Instructions.SetSubstitution( writeLoc, item.Data.ToArray()); writeLoc += item.Data.Length; } }
private void ProcessQuests( MajorRecordFrame majorFrame, long fileOffset) { if (majorFrame.TryLocateSubrecordFrame(RecordTypes.ANAM, out var anamRec, out var anamIndex)) { var next = anamRec.AsUInt32(); var targets = new RecordType[] { RecordTypes.ALST, RecordTypes.ALLS }; var locs = UtilityTranslation.FindAllOfSubrecords( majorFrame.Content, majorFrame.Meta, targets.ToGetter(), navigateToContent: true); uint actualNext = 0; if (locs.Length > 0) { actualNext = locs .Select(l => { return(BinaryPrimitives.ReadUInt32LittleEndian(majorFrame.Content.Slice(l))); }) .Max(); actualNext++; } if (actualNext != next) { byte[] sub = new byte[4]; BinaryPrimitives.WriteUInt32LittleEndian(sub, actualNext); _Instructions.SetSubstitution( fileOffset + anamIndex + anamRec.HeaderLength, sub); } } var sizeChange = FixMissingCounters( majorFrame, fileOffset, new RecordType("COCT"), new RecordType("CNTO")); ProcessLengths( majorFrame, sizeChange, fileOffset); FixVMADFormIDs( majorFrame, fileOffset, out var vmadPos, out var objectFormat, out var processedLen); if (vmadPos != null) { var vmadFrame = Meta.SubrecordFrame(majorFrame.Content.Slice(vmadPos.Value)); var stream = new MutagenMemoryReadStream(vmadFrame.Content, Bundle) { Position = processedLen - vmadFrame.HeaderLength }; if (stream.Complete) { return; } // skip unknown stream.Position += 1; var fragCount = stream.ReadUInt16(); // skip name var len = stream.ReadUInt16(); stream.Position += len; for (int i = 0; i < fragCount; i++) { stream.Position += 9; // skip name len = stream.ReadUInt16(); stream.Position += len; // skip name len = stream.ReadUInt16(); stream.Position += len; } var aliasCount = stream.ReadUInt16(); for (int i = 0; i < aliasCount; i++) { FixObjectPropertyIDs(stream, fileOffset, objectFormat); // skip version stream.Position += 2; objectFormat = stream.ReadUInt16(); var numScripts = stream.ReadUInt16(); for (int j = 0; j < numScripts; j++) { FixVMADScriptIDs(stream, fileOffset, objectFormat); } } } }
private void ProcessRegions( IMutagenReadStream stream, MajorRecordFrame majorFrame, long fileOffset) { if (!majorFrame.TryLocateSubrecordFrame(RecordTypes.RDAT, out var rdatFrame, out var rdatIndex)) { return; } int amount = 0; SortedList <uint, RangeInt64> rdats = new SortedList <uint, RangeInt64>(); bool foundNext = true; while (foundNext) { foundNext = majorFrame.TryLocateSubrecordFrame(RecordTypes.RDAT, offset: rdatIndex + rdatFrame.TotalLength, out var nextRdatFrame, out var nextRdatIndex); var index = rdatFrame.Content.UInt32(); rdats[index] = new RangeInt64( rdatIndex + fileOffset, foundNext ? nextRdatIndex - 1 + fileOffset : fileOffset + majorFrame.TotalLength - 1); rdatFrame = nextRdatFrame; rdatIndex = nextRdatIndex; } foreach (var item in rdats.Reverse()) { if (item.Key == (int)RegionData.RegionDataType.Icon) { continue; } this._instructions.SetMove( loc: fileOffset + majorFrame.TotalLength, section: item.Value); } if (rdats.ContainsKey((int)RegionData.RegionDataType.Icon)) { // Need to create icon record if (!majorFrame.TryLocateSubrecordFrame("EDID", out var edidFrame, out var edidLoc)) { throw new ArgumentException(); } var locToPlace = fileOffset + edidLoc + edidFrame.TotalLength; // Get icon string var iconLoc = rdats[(int)RegionData.RegionDataType.Icon]; stream.Position = iconLoc.Min + 20; var iconStr = BinaryStringUtility.ToZString(stream.ReadMemory((int)(iconLoc.Max - stream.Position)), MutagenEncodingProvider._1252); // Get icon bytes MemoryStream memStream = new MemoryStream(); using (var writer = new MutagenWriter(memStream, this.GameRelease)) { using (HeaderExport.Header( writer, new RecordType("ICON"), ObjectType.Subrecord)) { StringBinaryTranslation.Instance.Write(writer, iconStr, StringBinaryType.NullTerminate); } } var arr = memStream.ToArray(); this._instructions.SetAddition( loc: locToPlace, addition: arr); this._instructions.SetRemove( section: iconLoc); amount += arr.Length; amount -= (int)iconLoc.Width; } ProcessLengths( majorFrame, amount, fileOffset); }