// // 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.Collections.Generic; using System.IO; namespace DiscUtils.Streams { /// /// Converts a Buffer into a Stream. /// public class BufferStream : SparseStream { private readonly FileAccess _access; private readonly IBuffer _buffer; private long _position; /// /// Initializes a new instance of the BufferStream class. /// /// The buffer to use. /// The access permitted to clients. public BufferStream(IBuffer buffer, FileAccess access) { _buffer = buffer; _access = access; } /// /// Gets an indication of whether read access is permitted. /// public override bool CanRead { get { return _access != FileAccess.Write; } } /// /// Gets an indication of whether seeking is permitted. /// public override bool CanSeek { get { return true; } } /// /// Gets an indication of whether write access is permitted. /// public override bool CanWrite { get { return _access != FileAccess.Read; } } /// /// Gets the stored extents within the sparse stream. /// public override IEnumerable Extents { get { return _buffer.Extents; } } /// /// Gets the length of the stream (the capacity of the underlying buffer). /// public override long Length { get { return _buffer.Capacity; } } /// /// Gets and sets the current position within the stream. /// public override long Position { get { return _position; } set { _position = value; } } /// /// Flushes all data to the underlying storage. /// public override void Flush() {} /// /// Reads a number of bytes from the stream. /// /// The destination buffer. /// The start offset within the destination buffer. /// The number of bytes to read. /// The number of bytes read. public override int Read(byte[] buffer, int offset, int count) { if (!CanRead) { throw new IOException("Attempt to read from write-only stream"); } StreamUtilities.AssertBufferParameters(buffer, offset, count); int numRead = _buffer.Read(_position, buffer, offset, count); _position += numRead; return numRead; } /// /// Changes the current stream position. /// /// The origin-relative stream position. /// The origin for the stream position. /// The new stream position. public override long Seek(long offset, SeekOrigin origin) { long effectiveOffset = offset; if (origin == SeekOrigin.Current) { effectiveOffset += _position; } else if (origin == SeekOrigin.End) { effectiveOffset += _buffer.Capacity; } if (effectiveOffset < 0) { throw new IOException("Attempt to move before beginning of disk"); } _position = effectiveOffset; return _position; } /// /// Sets the length of the stream (the underlying buffer's capacity). /// /// The new length of the stream. public override void SetLength(long value) { _buffer.SetCapacity(value); } /// /// Writes a buffer to the stream. /// /// The buffer to write. /// The starting offset within buffer. /// The number of bytes to write. public override void Write(byte[] buffer, int offset, int count) { if (!CanWrite) { throw new IOException("Attempt to write to read-only stream"); } StreamUtilities.AssertBufferParameters(buffer, offset, count); _buffer.Write(_position, buffer, offset, count); _position += count; } /// /// Clears bytes from the stream. /// /// The number of bytes (from the current position) to clear. /// /// Logically equivalent to writing count null/zero bytes to the stream, some /// implementations determine that some (or all) of the range indicated is not actually /// stored. There is no direct, automatic, correspondence to clearing bytes and them /// not being represented as an 'extent' - for example, the implementation of the underlying /// stream may not permit fine-grained extent storage. /// It is always safe to call this method to 'zero-out' a section of a stream, regardless of /// the underlying stream implementation. /// public override void Clear(int count) { if (!CanWrite) { throw new IOException("Attempt to erase bytes in a read-only stream"); } _buffer.Clear(_position, count); _position += count; } /// /// Gets the parts of a stream 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) { return _buffer.GetExtentsInRange(start, count); } } }