Exemple #1
0
        /// <summary>
        /// Resizes a block of tag data, updating relative pointers which do not point into the block.
        /// </summary>
        /// <param name="stream">The stream to write to.</param>
        /// <param name="tag">The tag.</param>
        /// <param name="startOffset">The offset, from the start of the tag's data, where the block to resize begins at.</param>
        /// <param name="oldSize">The current size of the block to resize.</param>
        /// <param name="newSize">The new size of the block.</param>
        /// <param name="origin">The origin where data should be inserted or removed.</param>
        public void ResizeTagData(Stream stream, TagInstance tag, long startOffset, long oldSize, long newSize, ResizeOrigin origin)
        {
            if (tag == null)
            {
                throw new ArgumentNullException("tag");
            }
            if (tag.HeaderOffset < 0)
            {
                throw new ArgumentException("The tag is not in the cache file");
            }
            if (oldSize < 0)
            {
                throw new ArgumentException("The old block size cannot be negative");
            }
            if (newSize < 0)
            {
                throw new ArgumentException("Cannot resize a block to a negative size");
            }
            if (newSize == tag.DataSize)
            {
                return;
            }

            // Correct offsets pointing after the block
            var sizeDelta      = newSize - oldSize;
            var blockEndOffset = startOffset + oldSize;

            tag.DataSize += sizeDelta;
            foreach (var fixup in tag.DataFixups.Concat(tag.ResourceFixups))
            {
                if (fixup.WriteOffset >= blockEndOffset)
                {
                    fixup.WriteOffset = (uint)(fixup.WriteOffset + sizeDelta);
                }
                if (fixup.TargetOffset >= blockEndOffset)
                {
                    fixup.TargetOffset = (uint)(fixup.TargetOffset + sizeDelta);
                }
            }
            if (tag.MainStructOffset >= blockEndOffset)
            {
                tag.MainStructOffset = (uint)(tag.MainStructOffset + sizeDelta);
            }
            FixTagOffsets(tag.DataOffset + blockEndOffset, sizeDelta, tag);

            // Insert/remove the data
            long editOffset;

            if (origin == ResizeOrigin.Beginning)
            {
                editOffset = startOffset;
            }
            else if (sizeDelta > 0)
            {
                editOffset = blockEndOffset;
            }
            else
            {
                editOffset = blockEndOffset + sizeDelta;
            }
            stream.Position = tag.DataOffset + editOffset;
            if (sizeDelta > 0)
            {
                StreamUtil.Insert(stream, (int)sizeDelta, 0);
            }
            else
            {
                StreamUtil.Remove(stream, (int)-sizeDelta);
            }
            UpdateTag(stream, tag);
        }
        /// <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);
            }
        }