using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.IO.Compression; namespace GMWare.IO { /// /// Provides some commonly used methods for Stream manipulation. /// public static class StreamUtils { /// /// Opens a DeflateStream for reading Zlib compressed data from the current position of the parameter. Closing this Stream will not close the underlying Stream. /// /// The Stream to create a DeflateStream from. /// The opened DeflateStream. public static DeflateStream OpenDeflateDecompressionStreamCheap(Stream stream) { return OpenDeflateDecompressionStreamCheap(stream, true); } /// /// Opens a DeflateStream for reading Zlib compressed data from the current position of the parameter. /// /// The Stream to create a DeflateStream from. /// Specifies whether or not the underlying Stream will be left open when this Stream is closed. /// The opened DeflateStream. public static DeflateStream OpenDeflateDecompressionStreamCheap(Stream stream, bool leaveOpen) { if (stream == null) throw new ArgumentNullException("stream"); stream.ReadByte(); stream.ReadByte(); return new DeflateStream(stream, CompressionMode.Decompress, leaveOpen); } /// /// Copies a number of bytes from one Stream to the other. The current position of each is used. /// /// The Stream to copy from. /// The Stream to copy to. /// The number of bytes to copy. /// Whether or not all requested bytes are copied. [Obsolete("For backward compatibility only. Please use StreamCopy().")] public static bool StreamCopyWithLength(Stream src, Stream dest, int length) { return StreamCopy(src, dest, length); } /// /// Copies a number of bytes from one Stream to the other. The current position of each is used. /// /// The Stream to copy from. /// The Stream to copy to. /// The number of bytes to copy. /// Whether or not all requested bytes are copied. public static bool StreamCopy(Stream src, Stream dest, long length) { return StreamCopy(src, dest, length, null); } /// /// Copies a number of bytes from one Stream to the other. The current position of each is used. /// /// The Stream to copy from. /// The Stream to copy to. /// The number of bytes to copy. /// A delegate to process the read buffer before it's written to the destination. /// Whether or not all requested bytes are copied. public static bool StreamCopy(Stream src, Stream dest, long length, StreamCopyProcessor procDelegate) { if (src == null) throw new ArgumentNullException("src"); if (dest == null) throw new ArgumentNullException("dest"); if (length == 0) return true; const int BUFFER_SIZE = 4096; byte[] buffer = new byte[BUFFER_SIZE]; int read; long left = length; bool continueProcessing = true; while (continueProcessing && left / buffer.Length != 0 && (read = src.Read(buffer, 0, buffer.Length)) > 0) { if (procDelegate != null) { continueProcessing = procDelegate(buffer, read); } dest.Write(buffer, 0, read); left -= read; } // Should stop if zero bytes have been read from stream although some should have been read if (length > BUFFER_SIZE && left == length) return false; if (src.CanSeek && src.Position == src.Length && left != 0) throw new EndOfStreamException(); while (continueProcessing && left > 0 && (read = src.Read(buffer, 0, (int)left)) > 0) { if (procDelegate != null) { continueProcessing = procDelegate(buffer, read); } dest.Write(buffer, 0, read); left -= read; } return left == 0; } /// /// Copies one Stream to the other. The current position of each is used. /// /// The Stream to copy from. /// The Stream to copy to. /// The number of bytes copied. public static long StreamCopy(Stream src, Stream dest) { return StreamCopy(src, dest, null); } /// /// Copies one Stream to the other. The current position of each is used. /// /// The Stream to copy from. /// The Stream to copy to. /// A delegate for processing a read chunk before it is written. /// The number of bytes copied. public static long StreamCopy(Stream src, Stream dest, StreamCopyProcessor procDelegate) { if (src == null) throw new ArgumentNullException("src"); if (dest == null) throw new ArgumentNullException("dest"); // From Stack Overflow, probably const int BUFFER_SIZE = 4096; byte[] buffer = new byte[BUFFER_SIZE]; long bytesCopied = 0; int bytesRead; bool continueProcessing = true; do { bytesRead = src.Read(buffer, 0, BUFFER_SIZE); if (procDelegate != null) { continueProcessing = procDelegate(buffer, bytesRead); } dest.Write(buffer, 0, bytesRead); bytesCopied += bytesRead; } while (continueProcessing && bytesRead != 0); return bytesCopied; } /// /// Encapsulates a method for processing bytes that are being copied. /// /// The bytes that have been read from the source stream and will be written to the destination stream /// The number of bytes that have been read from the source stream stored in /// public delegate bool StreamCopyProcessor(byte[] buffer, int bytesRead); } }