예제 #1
0
        /// <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);
        }
예제 #2
0
        /// <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);
            }
        }
예제 #3
0
 /// <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);
 }
예제 #4
0
 /// <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);
 }