/// <summary> /// Inserts or removes data in a tag. /// </summary> /// <param name="stream">The stream to write to.</param> /// <param name="tag">The tag.</param> /// <param name="insertOffset">The offset, from the start of the tag's header, to insert data at.</param> /// <param name="sizeDelta">The size of the data to insert or remove. If positive, data will be inserted. If negative, data will be removed.</param> /// <param name="origin">The type of resize to perform. See <see cref="InsertOrigin"/>.</param> /// <param name="mode">The resize mode. See <see cref="ResizeMode"/>.</param> private void ResizeTag(Stream stream, HaloTag tag, uint insertOffset, int sizeDelta, InsertOrigin origin, ResizeMode mode) { if (sizeDelta == 0) return; var headerSize = GetHeaderSize(tag); if (sizeDelta < 0 && ((origin == InsertOrigin.Before && -sizeDelta > insertOffset) || (origin == InsertOrigin.After && insertOffset + -sizeDelta > headerSize + tag.Size))) throw new ArgumentException("Cannot remove more bytes than there are available in the tag"); // In insertion mode, correct relative offsets to account for inserted data var relativeCompareOffset = (origin == InsertOrigin.Before) ? insertOffset : insertOffset + 1; // hack if (headerSize < relativeCompareOffset) { tag.Size = (uint)(tag.Size + sizeDelta); if (mode == ResizeMode.Insert) { foreach (var fixup in tag.DataFixups.Concat(tag.ResourceFixups)) { if (fixup.WriteOffset + headerSize >= relativeCompareOffset) fixup.WriteOffset = (uint)(fixup.WriteOffset + sizeDelta); if (fixup.TargetOffset + headerSize >= relativeCompareOffset) fixup.TargetOffset = (uint)(fixup.TargetOffset + sizeDelta); } if (tag.MainStructOffset + headerSize >= relativeCompareOffset) tag.MainStructOffset = (uint)(tag.MainStructOffset + sizeDelta); } } // Correct tag offsets var absoluteOffset = _headerOffsets[tag.Index] + insertOffset; var absoluteCompareOffset = (origin == InsertOrigin.Before) ? absoluteOffset : absoluteOffset + 1; // hack for (var i = 0; i < _tags.Count; i++) { if (_tags[i] == null) continue; if (_headerOffsets[i] >= absoluteCompareOffset) // Header offset (absolute) _headerOffsets[i] = (uint)(_headerOffsets[i] + sizeDelta); if (_tags[i].Offset >= absoluteCompareOffset) // Data offset (absolute) _tags[i].Offset = (uint)(_tags[i].Offset + sizeDelta); } // Insert/remove the data if (sizeDelta < 0 && origin == InsertOrigin.Before) absoluteOffset = (uint)(absoluteOffset + sizeDelta); stream.Position = absoluteOffset; if (sizeDelta > 0) StreamUtil.Insert(stream, sizeDelta, 0); else StreamUtil.Remove(stream, -sizeDelta); }
/// <summary> /// Inserts or removes data in a tag. /// </summary> /// <param name="stream">The stream to write to.</param> /// <param name="tag">The tag.</param> /// <param name="insertOffset">The offset, from the start of the tag's header, to insert data at.</param> /// <param name="sizeDelta">The size of the data to insert or remove. If positive, data will be inserted. If negative, data will be removed.</param> /// <param name="origin">The type of resize to perform. See <see cref="InsertOrigin"/>.</param> /// <param name="mode">The resize mode. See <see cref="ResizeMode"/>.</param> private void ResizeTag(Stream stream, HaloTag tag, uint insertOffset, int sizeDelta, InsertOrigin origin, ResizeMode mode) { if (sizeDelta == 0) { return; } var headerSize = GetHeaderSize(tag); if (sizeDelta < 0 && ((origin == InsertOrigin.Before && -sizeDelta > insertOffset) || (origin == InsertOrigin.After && insertOffset + -sizeDelta > headerSize + tag.Size))) { throw new ArgumentException("Cannot remove more bytes than there are available in the tag"); } // In insertion mode, correct relative offsets to account for inserted data var relativeCompareOffset = (origin == InsertOrigin.Before) ? insertOffset : insertOffset + 1; // hack if (headerSize < relativeCompareOffset) { tag.Size = (uint)(tag.Size + sizeDelta); if (mode == ResizeMode.Insert) { foreach (var fixup in tag.DataFixups.Concat(tag.ResourceFixups)) { if (fixup.WriteOffset + headerSize >= relativeCompareOffset) { fixup.WriteOffset = (uint)(fixup.WriteOffset + sizeDelta); } if (fixup.TargetOffset + headerSize >= relativeCompareOffset) { fixup.TargetOffset = (uint)(fixup.TargetOffset + sizeDelta); } } if (tag.MainStructOffset + headerSize >= relativeCompareOffset) { tag.MainStructOffset = (uint)(tag.MainStructOffset + sizeDelta); } } } // Correct tag offsets var absoluteOffset = _headerOffsets[tag.Index] + insertOffset; var absoluteCompareOffset = (origin == InsertOrigin.Before) ? absoluteOffset : absoluteOffset + 1; // hack for (var i = 0; i < _tags.Count; i++) { if (_tags[i] == null) { continue; } if (_headerOffsets[i] >= absoluteCompareOffset) // Header offset (absolute) { _headerOffsets[i] = (uint)(_headerOffsets[i] + sizeDelta); } if (_tags[i].Offset >= absoluteCompareOffset) // Data offset (absolute) { _tags[i].Offset = (uint)(_tags[i].Offset + sizeDelta); } } // Insert/remove the data if (sizeDelta < 0 && origin == InsertOrigin.Before) { absoluteOffset = (uint)(absoluteOffset + sizeDelta); } stream.Position = absoluteOffset; if (sizeDelta > 0) { StreamUtil.Insert(stream, sizeDelta, 0); } else { StreamUtil.Remove(stream, -sizeDelta); } }
/// <summary> /// Inserts or removes data in a tag and then updates it if necessary. /// </summary> /// <param name="stream">The stream to write to.</param> /// <param name="tag">The tag.</param> /// <param name="insertOffset">The offset, from the start of the tag's data, to insert data at.</param> /// <param name="sizeDelta">The size of the data to insert or remove. If positive, data will be inserted. If negative, data will be removed.</param> /// <param name="origin">The type of resize to perform. See <see cref="InsertOrigin"/>.</param> public void InsertTagData(Stream stream, HaloTag tag, uint insertOffset, int sizeDelta, InsertOrigin origin) { if (tag == null) throw new ArgumentNullException("tag"); if (sizeDelta == 0) return; ResizeTag(stream, tag, insertOffset + GetHeaderSize(tag), sizeDelta, origin, ResizeMode.Insert); UpdateTag(stream, tag); }
/// <summary> /// Inserts or removes data in a tag and then updates it if necessary. /// </summary> /// <param name="stream">The stream to write to.</param> /// <param name="tag">The tag.</param> /// <param name="insertOffset">The offset, from the start of the tag's data, to insert data at.</param> /// <param name="sizeDelta">The size of the data to insert or remove. If positive, data will be inserted. If negative, data will be removed.</param> /// <param name="origin">The type of resize to perform. See <see cref="InsertOrigin"/>.</param> public void InsertTagData(Stream stream, HaloTag tag, uint insertOffset, int sizeDelta, InsertOrigin origin) { if (tag == null) { throw new ArgumentNullException("tag"); } if (sizeDelta == 0) { return; } ResizeTag(stream, tag, insertOffset + GetHeaderSize(tag), sizeDelta, origin, ResizeMode.Insert); UpdateTag(stream, tag); }