StreamUtils.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. // StreamUtils.cs
  2. //
  3. // Copyright 2005 John Reilly
  4. //
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software
  17. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18. //
  19. // Linking this library statically or dynamically with other modules is
  20. // making a combined work based on this library. Thus, the terms and
  21. // conditions of the GNU General Public License cover the whole
  22. // combination.
  23. //
  24. // As a special exception, the copyright holders of this library give you
  25. // permission to link this library with independent modules to produce an
  26. // executable, regardless of the license terms of these independent
  27. // modules, and to copy and distribute the resulting executable under
  28. // terms of your choice, provided that you also meet, for each linked
  29. // independent module, the terms and conditions of the license of that
  30. // module. An independent module is a module which is not derived from
  31. // or based on this library. If you modify this library, you may extend
  32. // this exception to your version of the library, but you are not
  33. // obligated to do so. If you do not wish to do so, delete this
  34. // exception statement from your version.
  35. using System;
  36. using System.IO;
  37. namespace CommonMPQ.SharpZipLib.Core
  38. {
  39. /// <summary>
  40. /// Provides simple <see cref="Stream"/>" utilities.
  41. /// </summary>
  42. public sealed class StreamUtils
  43. {
  44. /// <summary>
  45. /// Read from a <see cref="Stream"/> ensuring all the required data is read.
  46. /// </summary>
  47. /// <param name="stream">The stream to read.</param>
  48. /// <param name="buffer">The buffer to fill.</param>
  49. /// <seealso cref="ReadFully(Stream,byte[],int,int)"/>
  50. static public void ReadFully(Stream stream, byte[] buffer)
  51. {
  52. ReadFully(stream, buffer, 0, buffer.Length);
  53. }
  54. /// <summary>
  55. /// Read from a <see cref="Stream"/>" ensuring all the required data is read.
  56. /// </summary>
  57. /// <param name="stream">The stream to read data from.</param>
  58. /// <param name="buffer">The buffer to store data in.</param>
  59. /// <param name="offset">The offset at which to begin storing data.</param>
  60. /// <param name="count">The number of bytes of data to store.</param>
  61. /// <exception cref="ArgumentNullException">Required parameter is null</exception>
  62. /// <exception cref="ArgumentOutOfRangeException"><paramref name="offset"/> and or <paramref name="count"/> are invalid.</exception>
  63. /// <exception cref="EndOfStreamException">End of stream is encountered before all the data has been read.</exception>
  64. static public void ReadFully(Stream stream, byte[] buffer, int offset, int count)
  65. {
  66. if ( stream == null ) {
  67. throw new ArgumentNullException("stream");
  68. }
  69. if ( buffer == null ) {
  70. throw new ArgumentNullException("buffer");
  71. }
  72. // Offset can equal length when buffer and count are 0.
  73. if ( (offset < 0) || (offset > buffer.Length) ) {
  74. throw new ArgumentOutOfRangeException("offset");
  75. }
  76. if ( (count < 0) || (offset + count > buffer.Length) ) {
  77. throw new ArgumentOutOfRangeException("count");
  78. }
  79. while ( count > 0 ) {
  80. int readCount = stream.Read(buffer, offset, count);
  81. if ( readCount <= 0 ) {
  82. throw new EndOfStreamException();
  83. }
  84. offset += readCount;
  85. count -= readCount;
  86. }
  87. }
  88. /// <summary>
  89. /// Copy the contents of one <see cref="Stream"/> to another.
  90. /// </summary>
  91. /// <param name="source">The stream to source data from.</param>
  92. /// <param name="destination">The stream to write data to.</param>
  93. /// <param name="buffer">The buffer to use during copying.</param>
  94. static public void Copy(Stream source, Stream destination, byte[] buffer)
  95. {
  96. if (source == null) {
  97. throw new ArgumentNullException("source");
  98. }
  99. if (destination == null) {
  100. throw new ArgumentNullException("destination");
  101. }
  102. if (buffer == null) {
  103. throw new ArgumentNullException("buffer");
  104. }
  105. // Ensure a reasonable size of buffer is used without being prohibitive.
  106. if (buffer.Length < 128) {
  107. throw new ArgumentException("Buffer is too small", "buffer");
  108. }
  109. bool copying = true;
  110. while (copying) {
  111. int bytesRead = source.Read(buffer, 0, buffer.Length);
  112. if (bytesRead > 0) {
  113. destination.Write(buffer, 0, bytesRead);
  114. }
  115. else {
  116. destination.Flush();
  117. copying = false;
  118. }
  119. }
  120. }
  121. /// <summary>
  122. /// Copy the contents of one <see cref="Stream"/> to another.
  123. /// </summary>
  124. /// <param name="source">The stream to source data from.</param>
  125. /// <param name="destination">The stream to write data to.</param>
  126. /// <param name="buffer">The buffer to use during copying.</param>
  127. /// <param name="progressHandler">The <see cref="ProgressHandler">progress handler delegate</see> to use.</param>
  128. /// <param name="updateInterval">The minimum <see cref="TimeSpan"/> between progress updates.</param>
  129. /// <param name="sender">The source for this event.</param>
  130. /// <param name="name">The name to use with the event.</param>
  131. /// <remarks>This form is specialised for use within #Zip to support events during archive operations.</remarks>
  132. static public void Copy(Stream source, Stream destination,
  133. byte[] buffer, ProgressHandler progressHandler, TimeSpan updateInterval, object sender, string name)
  134. {
  135. Copy(source, destination, buffer, progressHandler, updateInterval, sender, name, -1);
  136. }
  137. /// <summary>
  138. /// Copy the contents of one <see cref="Stream"/> to another.
  139. /// </summary>
  140. /// <param name="source">The stream to source data from.</param>
  141. /// <param name="destination">The stream to write data to.</param>
  142. /// <param name="buffer">The buffer to use during copying.</param>
  143. /// <param name="progressHandler">The <see cref="ProgressHandler">progress handler delegate</see> to use.</param>
  144. /// <param name="updateInterval">The minimum <see cref="TimeSpan"/> between progress updates.</param>
  145. /// <param name="sender">The source for this event.</param>
  146. /// <param name="name">The name to use with the event.</param>
  147. /// <param name="fixedTarget">A predetermined fixed target value to use with progress updates.
  148. /// If the value is negative the target is calculated by looking at the stream.</param>
  149. /// <remarks>This form is specialised for use within #Zip to support events during archive operations.</remarks>
  150. static public void Copy(Stream source, Stream destination,
  151. byte[] buffer,
  152. ProgressHandler progressHandler, TimeSpan updateInterval,
  153. object sender, string name, long fixedTarget)
  154. {
  155. if (source == null) {
  156. throw new ArgumentNullException("source");
  157. }
  158. if (destination == null) {
  159. throw new ArgumentNullException("destination");
  160. }
  161. if (buffer == null) {
  162. throw new ArgumentNullException("buffer");
  163. }
  164. // Ensure a reasonable size of buffer is used without being prohibitive.
  165. if (buffer.Length < 128) {
  166. throw new ArgumentException("Buffer is too small", "buffer");
  167. }
  168. if (progressHandler == null) {
  169. throw new ArgumentNullException("progressHandler");
  170. }
  171. bool copying = true;
  172. DateTime marker = DateTime.Now;
  173. long processed = 0;
  174. long target = 0;
  175. if (fixedTarget >= 0) {
  176. target = fixedTarget;
  177. }
  178. else if (source.CanSeek) {
  179. target = source.Length - source.Position;
  180. }
  181. // Always fire 0% progress..
  182. ProgressEventArgs args = new ProgressEventArgs(name, processed, target);
  183. progressHandler(sender, args);
  184. bool progressFired = true;
  185. while (copying) {
  186. int bytesRead = source.Read(buffer, 0, buffer.Length);
  187. if (bytesRead > 0) {
  188. processed += bytesRead;
  189. progressFired = false;
  190. destination.Write(buffer, 0, bytesRead);
  191. }
  192. else {
  193. destination.Flush();
  194. copying = false;
  195. }
  196. if (DateTime.Now - marker > updateInterval) {
  197. progressFired = true;
  198. marker = DateTime.Now;
  199. args = new ProgressEventArgs(name, processed, target);
  200. progressHandler(sender, args);
  201. copying = args.ContinueRunning;
  202. }
  203. }
  204. if (!progressFired) {
  205. args = new ProgressEventArgs(name, processed, target);
  206. progressHandler(sender, args);
  207. }
  208. }
  209. /// <summary>
  210. /// Initialise an instance of <see cref="StreamUtils"></see>
  211. /// </summary>
  212. private StreamUtils()
  213. {
  214. // Do nothing.
  215. }
  216. }
  217. }