// // Copyright (c) 2008-2011, Kenneth Bell // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // using System; using System.Collections.Generic; namespace DiscUtils.Streams { /// /// Class representing a portion of an existing buffer. /// public class SubBuffer : Buffer { private readonly long _first; private readonly long _length; private readonly IBuffer _parent; /// /// Initializes a new instance of the SubBuffer class. /// /// The parent buffer. /// The first byte in represented by this sub-buffer. /// The number of bytes of represented by this sub-buffer. public SubBuffer(IBuffer parent, long first, long length) { _parent = parent; _first = first; _length = length; if (_first + _length > _parent.Capacity) { throw new ArgumentException("Substream extends beyond end of parent stream"); } } /// /// Can this buffer be read. /// public override bool CanRead { get { return _parent.CanRead; } } /// /// Can this buffer be modified. /// public override bool CanWrite { get { return _parent.CanWrite; } } /// /// Gets the current capacity of the buffer, in bytes. /// public override long Capacity { get { return _length; } } /// /// Gets the parts of the buffer that are stored. /// /// This may be an empty enumeration if all bytes are zero. public override IEnumerable Extents { get { return OffsetExtents(_parent.GetExtentsInRange(_first, _length)); } } /// /// Flushes all data to the underlying storage. /// public override void Flush() { _parent.Flush(); } /// /// Reads from the buffer into a byte array. /// /// The offset within the buffer to start reading. /// The destination byte array. /// The start offset within the destination buffer. /// The number of bytes to read. /// The actual number of bytes read. public override int Read(long pos, byte[] buffer, int offset, int count) { if (count < 0) { throw new ArgumentOutOfRangeException(nameof(count), "Attempt to read negative bytes"); } if (pos >= _length) { return 0; } return _parent.Read(pos + _first, buffer, offset, (int)Math.Min(count, Math.Min(_length - pos, int.MaxValue))); } /// /// Writes a byte array into the buffer. /// /// The start offset within the buffer. /// The source byte array. /// The start offset within the source byte array. /// The number of bytes to write. public override void Write(long pos, byte[] buffer, int offset, int count) { if (count < 0) { throw new ArgumentOutOfRangeException(nameof(count), "Attempt to write negative bytes"); } if (pos + count > _length) { throw new ArgumentOutOfRangeException(nameof(count), "Attempt to write beyond end of substream"); } _parent.Write(pos + _first, buffer, offset, count); } /// /// Sets the capacity of the buffer, truncating if appropriate. /// /// The desired capacity of the buffer. public override void SetCapacity(long value) { throw new NotSupportedException("Attempt to change length of a subbuffer"); } /// /// Gets the parts of a buffer that are stored, within a specified range. /// /// The offset of the first byte of interest. /// The number of bytes of interest. /// An enumeration of stream extents, indicating stored bytes. public override IEnumerable GetExtentsInRange(long start, long count) { long absStart = _first + start; long absEnd = Math.Min(absStart + count, _first + _length); return OffsetExtents(_parent.GetExtentsInRange(absStart, absEnd - absStart)); } private IEnumerable OffsetExtents(IEnumerable src) { foreach (StreamExtent e in src) { yield return new StreamExtent(e.Start - _first, e.Length); } } } }