Beispiel #1
0
        /// <summary>
        ///     Defines a new segment in the file.
        /// </summary>
        /// <param name="offset">The offset at which the segment starts.</param>
        /// <param name="size">The size of the segment.</param>
        /// <param name="offsetAlignment">A power of two which the offset must be a multiple of (e.g. 0x1000 = 4kb-aligned).</param>
        /// <param name="sizeAlignment">A power of two which the size must be a multiple of (e.g. 0x1000 = 4kb-aligned).</param>
        /// <param name="resizeOrigin">The origin at which to insert/remove data in the segment.</param>
        /// <returns>The segment's ID number which can be used to retrieve information about it.</returns>
        public int DefineSegment(int offset, int size, int offsetAlignment, int sizeAlignment,
                                 SegmentResizeOrigin resizeOrigin)
        {
            if (offset != Align(offset, offsetAlignment))
            {
                throw new ArgumentException("The segment offset is not aligned to the given alignment.");
            }
            if (size != Align(size, sizeAlignment))
            {
                throw new ArgumentException("The segment size is not aligned to the given alignment.");
            }
            if (_segmentsByOffset.ContainsKey(offset))
            {
                throw new ArgumentException("A segment has already been defined at the given offset.");
            }

            // Create and add the segment definition
            int id      = _segmentsById.Count;
            var segment = new InternalSegment
            {
                ID              = id,
                Offset          = offset,
                Size            = size,
                OffsetAlignment = offsetAlignment,
                SizeAlignment   = sizeAlignment,
                ResizeOrigin    = resizeOrigin
            };

            _segmentsById.Add(segment);
            _segmentsByOffset[offset] = segment;

            RecalculateActualSizes();
            return(id);
        }
Beispiel #2
0
        /// <summary>
        ///     Resizes a segment in the file.
        /// </summary>
        /// <param name="id">The ID of the segment to resize.</param>
        /// <param name="newSize">The minimum amount of space that the segment must occupy.</param>
        /// <param name="stream">The stream to write padding to.</param>
        /// <returns>The new size of the segment after alignment has been applied.</returns>
        public int ResizeSegment(int id, int newSize, IStream stream)
        {
            InternalSegment segment = GetSegmentFromID(id);

            int oldSize = segment.Size;

            if (newSize == oldSize)
            {
                return(oldSize);
            }

            // Change the size of the segment
            int oldActualSize = segment.ActualSize;
            int oldSegmentEnd = segment.Offset + segment.ActualSize;

            segment.Size       = Align(newSize, segment.SizeAlignment);
            segment.ActualSize = Math.Max(segment.Size, segment.ActualSize);

            // Recalculate the segment offsets,
            // and then use the recalculated offsets to recalculate the sizes
            RecalculateOffsets();
            RecalculateActualSizes();

            int resizeOffset;

            switch (segment.ResizeOrigin)
            {
            case SegmentResizeOrigin.Beginning:
                resizeOffset = segment.Offset;
                break;

            case SegmentResizeOrigin.End:
                resizeOffset = oldSegmentEnd;
                break;

            default:
                throw new ArgumentException("The segment cannot be resized.");
            }

            // Insert/remove data into/from the stream
            // FIXME: There's a bug here where changing the size of a SegmentResizeOrigin.Beginning segment won't move the data back if ActualSize doesn't change
            //        Some sort of StreamUtil.Copy() method is necessary for that
            stream.SeekTo(resizeOffset);
            if (oldActualSize < segment.ActualSize)
            {
                StreamUtil.Insert(stream, segment.ActualSize - oldActualSize, 0);
            }
            else if (segment.ActualSize < oldActualSize)
            {
                throw new NotImplementedException("Segment shrinking is not supported yet.");
            }

            OnSegmentResized(new SegmentResizedEventArgs(id, oldSize, segment.Size, segment.ResizeOrigin));
            return(segment.Size);
        }
Beispiel #3
0
        /// <summary>
        ///     Recalculates the offset of each segment in the file after a segment's size has been changed.
        /// </summary>
        private void RecalculateOffsets()
        {
            IList <InternalSegment> segments = _segmentsByOffset.Values;

            for (int i = 1; i < segments.Count; i++)
            {
                InternalSegment thisSegment = segments[i];
                InternalSegment prevSegment = segments[i - 1];
                thisSegment.Offset = Align(prevSegment.Offset + prevSegment.ActualSize, thisSegment.OffsetAlignment);
            }
        }
Beispiel #4
0
        /// <summary>
        /// Defines a new segment in the file.
        /// </summary>
        /// <param name="offset">The offset at which the segment starts.</param>
        /// <param name="size">The size of the segment.</param>
        /// <param name="offsetAlignment">A power of two which the offset must be a multiple of (e.g. 0x1000 = 4kb-aligned).</param>
        /// <param name="sizeAlignment">A power of two which the size must be a multiple of (e.g. 0x1000 = 4kb-aligned).</param>
        /// <param name="resizeOrigin">The origin at which to insert/remove data in the segment.</param>
        /// <returns>The segment's ID number which can be used to retrieve information about it.</returns>
        public int DefineSegment(int offset, int size, int offsetAlignment, int sizeAlignment, SegmentResizeOrigin resizeOrigin)
        {
            if (offset != Align(offset, offsetAlignment))
                throw new ArgumentException("The segment offset is not aligned to the given alignment.");
            if (size != Align(size, sizeAlignment))
                throw new ArgumentException("The segment size is not aligned to the given alignment.");
            if (_segmentsByOffset.ContainsKey(offset))
                throw new ArgumentException("A segment has already been defined at the given offset.");

            // Create and add the segment definition
            int id = _segmentsById.Count;
            var segment = new InternalSegment
            {
                ID = id,
                Offset = offset,
                Size = size,
                OffsetAlignment = offsetAlignment,
                SizeAlignment = sizeAlignment,
                ResizeOrigin = resizeOrigin
            };
            _segmentsById.Add(segment);
            _segmentsByOffset[offset] = segment;

            RecalculateActualSizes();
            return id;
        }