// // 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.IO; namespace DiscUtils.Streams { public static class StreamUtilities { /// /// Validates standard buffer, offset, count parameters to a method. /// /// The byte array to read from / write to. /// The starting offset in buffer. /// The number of bytes to read / write. public static void AssertBufferParameters(byte[] buffer, int offset, int count) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } if (offset < 0) { throw new ArgumentOutOfRangeException(nameof(offset), offset, "Offset is negative"); } if (count < 0) { throw new ArgumentOutOfRangeException(nameof(count), count, "Count is negative"); } if (buffer.Length < offset + count) { throw new ArgumentException("buffer is too small", nameof(buffer)); } } #region Stream Manipulation /// /// Read bytes until buffer filled or throw EndOfStreamException. /// /// The stream to read. /// The buffer to populate. /// Offset in the buffer to start. /// The number of bytes to read. public static void ReadExact(Stream stream, byte[] buffer, int offset, int count) { int originalCount = count; while (count > 0) { int numRead = stream.Read(buffer, offset, count); if (numRead == 0) { throw new EndOfStreamException("Unable to complete read of " + originalCount + " bytes"); } offset += numRead; count -= numRead; } } /// /// Read bytes until buffer filled or throw EndOfStreamException. /// /// The stream to read. /// The number of bytes to read. /// The data read from the stream. public static byte[] ReadExact(Stream stream, int count) { byte[] buffer = new byte[count]; ReadExact(stream, buffer, 0, count); return buffer; } /// /// Read bytes until buffer filled or throw EndOfStreamException. /// /// The stream to read. /// The position in buffer to read from. /// The buffer to populate. /// Offset in the buffer to start. /// The number of bytes to read. public static void ReadExact(IBuffer buffer, long pos, byte[] data, int offset, int count) { int originalCount = count; while (count > 0) { int numRead = buffer.Read(pos, data, offset, count); if (numRead == 0) { throw new EndOfStreamException("Unable to complete read of " + originalCount + " bytes"); } pos += numRead; offset += numRead; count -= numRead; } } /// /// Read bytes until buffer filled or throw EndOfStreamException. /// /// The buffer to read. /// The position in buffer to read from. /// The number of bytes to read. /// The data read from the stream. public static byte[] ReadExact(IBuffer buffer, long pos, int count) { byte[] result = new byte[count]; ReadExact(buffer, pos, result, 0, count); return result; } /// /// Read bytes until buffer filled or EOF. /// /// The stream to read. /// The buffer to populate. /// Offset in the buffer to start. /// The number of bytes to read. /// The number of bytes actually read. public static int ReadMaximum(Stream stream, byte[] buffer, int offset, int count) { int totalRead = 0; while (count > 0) { int numRead = stream.Read(buffer, offset, count); if (numRead == 0) { return totalRead; } offset += numRead; count -= numRead; totalRead += numRead; } return totalRead; } /// /// Read bytes until buffer filled or EOF. /// /// The stream to read. /// The position in buffer to read from. /// The buffer to populate. /// Offset in the buffer to start. /// The number of bytes to read. /// The number of bytes actually read. public static int ReadMaximum(IBuffer buffer, long pos, byte[] data, int offset, int count) { int totalRead = 0; while (count > 0) { int numRead = buffer.Read(pos, data, offset, count); if (numRead == 0) { return totalRead; } pos += numRead; offset += numRead; count -= numRead; totalRead += numRead; } return totalRead; } /// /// Read bytes until buffer filled or throw EndOfStreamException. /// /// The buffer to read. /// The data read from the stream. public static byte[] ReadAll(IBuffer buffer) { return ReadExact(buffer, 0, (int)buffer.Capacity); } /// /// Reads a disk sector (512 bytes). /// /// The stream to read. /// The sector data as a byte array. public static byte[] ReadSector(Stream stream) { return ReadExact(stream, Sizes.Sector); } /// /// Reads a structure from a stream. /// /// The type of the structure. /// The stream to read. /// The structure. public static T ReadStruct(Stream stream) where T : IByteArraySerializable, new() { T result = new T(); byte[] buffer = ReadExact(stream, result.Size); result.ReadFrom(buffer, 0); return result; } /// /// Reads a structure from a stream. /// /// The type of the structure. /// The stream to read. /// The number of bytes to read. /// The structure. public static T ReadStruct(Stream stream, int length) where T : IByteArraySerializable, new() { T result = new T(); byte[] buffer = ReadExact(stream, length); result.ReadFrom(buffer, 0); return result; } /// /// Writes a structure to a stream. /// /// The type of the structure. /// The stream to write to. /// The structure to write. public static void WriteStruct(Stream stream, T obj) where T : IByteArraySerializable { byte[] buffer = new byte[obj.Size]; obj.WriteTo(buffer, 0); stream.Write(buffer, 0, buffer.Length); } /// /// Copies the contents of one stream to another. /// /// The stream to copy from. /// The destination stream. /// Copying starts at the current stream positions. public static void PumpStreams(Stream source, Stream dest) { byte[] buffer = new byte[8192]; int numRead; while ((numRead = source.Read(buffer, 0, buffer.Length)) > 0) { dest.Write(buffer, 0, numRead); } } #endregion } }