root/trunk/BazaReklam.Updater/ICSharpCode.SharpZipLib/Zip/Compression/Streams/DeflaterOutputStream.cs @ 732

Wersja 597, 16.2 KB (wprowadzona przez marek, 17 years temu)

re #165

Line 
1// DeflaterOutputStream.cs
2//
3// Copyright (C) 2001 Mike Krueger
4//
5// This file was translated from java, it was part of the GNU Classpath
6// Copyright (C) 2001 Free Software Foundation, Inc.
7//
8// This program is free software; you can redistribute it and/or
9// modify it under the terms of the GNU General Public License
10// as published by the Free Software Foundation; either version 2
11// of the License, or (at your option) any later version.
12//
13// This program is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16// GNU General Public License for more details.
17//
18// You should have received a copy of the GNU General Public License
19// along with this program; if not, write to the Free Software
20// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21//
22// Linking this library statically or dynamically with other modules is
23// making a combined work based on this library.  Thus, the terms and
24// conditions of the GNU General Public License cover the whole
25// combination.
26//
27// As a special exception, the copyright holders of this library give you
28// permission to link this library with independent modules to produce an
29// executable, regardless of the license terms of these independent
30// modules, and to copy and distribute the resulting executable under
31// terms of your choice, provided that you also meet, for each linked
32// independent module, the terms and conditions of the license of that
33// module.  An independent module is a module which is not derived from
34// or based on this library.  If you modify this library, you may extend
35// this exception to your version of the library, but you are not
36// obligated to do so.  If you do not wish to do so, delete this
37// exception statement from your version.
38
39using System;
40using System.IO;
41using ICSharpCode.SharpZipLib.Checksums;
42using ICSharpCode.SharpZipLib.Zip.Compression;
43
44#if !NETCF_1_0
45using System.Security.Cryptography;
46using ICSharpCode.SharpZipLib.Encryption;
47#endif
48
49namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
50{
51        /// <summary>
52        /// A special stream deflating or compressing the bytes that are
53        /// written to it.  It uses a Deflater to perform actual deflating.<br/>
54        /// Authors of the original java version : Tom Tromey, Jochen Hoenicke
55        /// </summary>
56        public class DeflaterOutputStream : Stream
57        {
58                #region Constructors
59                /// <summary>
60                /// Creates a new DeflaterOutputStream with a default Deflater and default buffer size.
61                /// </summary>
62                /// <param name="baseOutputStream">
63                /// the output stream where deflated output should be written.
64                /// </param>
65                public DeflaterOutputStream(Stream baseOutputStream)
66                        : this(baseOutputStream, new Deflater(), 512)
67                {
68                }
69               
70                /// <summary>
71                /// Creates a new DeflaterOutputStream with the given Deflater and
72                /// default buffer size.
73                /// </summary>
74                /// <param name="baseOutputStream">
75                /// the output stream where deflated output should be written.
76                /// </param>
77                /// <param name="deflater">
78                /// the underlying deflater.
79                /// </param>
80                public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater)
81                        : this(baseOutputStream, deflater, 512)
82                {
83                }
84               
85                /// <summary>
86                /// Creates a new DeflaterOutputStream with the given Deflater and
87                /// buffer size.
88                /// </summary>
89                /// <param name="baseOutputStream">
90                /// The output stream where deflated output is written.
91                /// </param>
92                /// <param name="deflater">
93                /// The underlying deflater to use
94                /// </param>
95                /// <param name="bufferSize">
96                /// The buffer size to use when deflating
97                /// </param>
98                /// <exception cref="ArgumentOutOfRangeException">
99                /// bufsize is less than or equal to zero.
100                /// </exception>
101                /// <exception cref="ArgumentException">
102                /// baseOutputStream does not support writing
103                /// </exception>
104                /// <exception cref="ArgumentNullException">
105                /// deflater instance is null
106                /// </exception>
107                public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater, int bufferSize)
108                {
109                        if ( baseOutputStream == null ) {
110                                throw new ArgumentNullException("baseOutputStream");
111                        }
112
113                        if (baseOutputStream.CanWrite == false) {
114                                throw new ArgumentException("Must support writing", "baseOutputStream");
115                        }
116
117                        if (deflater == null) {
118                                throw new ArgumentNullException("deflater");
119                        }
120                       
121                        if (bufferSize <= 0) {
122                                throw new ArgumentOutOfRangeException("bufferSize");
123                        }
124                       
125                        baseOutputStream_ = baseOutputStream;
126                        buffer_ = new byte[bufferSize];
127                        deflater_ = deflater;
128                }
129                #endregion
130               
131                #region Public API
132                /// <summary>
133                /// Finishes the stream by calling finish() on the deflater.
134                /// </summary>
135                /// <exception cref="SharpZipBaseException">
136                /// Not all input is deflated
137                /// </exception>
138                public virtual void Finish()
139                {
140                        deflater_.Finish();
141                        while (!deflater_.IsFinished)  {
142                                int len = deflater_.Deflate(buffer_, 0, buffer_.Length);
143                                if (len <= 0) {
144                                        break;
145                                }
146                               
147#if NETCF_1_0
148                                if ( keys != null ) {
149#else
150                                if (cryptoTransform_ != null) {
151#endif 
152                                        EncryptBlock(buffer_, 0, len);
153                                }
154                               
155                                baseOutputStream_.Write(buffer_, 0, len);
156                        }
157
158                        if (!deflater_.IsFinished) {
159                                throw new SharpZipBaseException("Can't deflate all input?");
160                        }
161
162                        baseOutputStream_.Flush();
163                       
164#if NETCF_1_0
165                        if ( keys != null ) {
166                                keys = null;
167                        }
168#else
169                        if (cryptoTransform_ != null) {
170                                cryptoTransform_.Dispose();
171                                cryptoTransform_ = null;
172                        }
173#endif                 
174                }
175               
176                /// <summary>
177                /// Get/set flag indicating ownership of the underlying stream.
178                /// When the flag is true <see cref="Close"></see> will close the underlying stream also.
179                /// </summary>
180                public bool IsStreamOwner
181                {
182                        get { return isStreamOwner_; }
183                        set { isStreamOwner_ = value; }
184                }
185               
186                ///     <summary>
187                /// Allows client to determine if an entry can be patched after its added
188                /// </summary>
189                public bool CanPatchEntries {
190                        get {
191                                return baseOutputStream_.CanSeek;
192                        }
193                }
194               
195                #endregion
196               
197                #region Encryption
198               
199                string password;
200               
201#if NETCF_1_0
202                uint[] keys;
203#else
204                ICryptoTransform cryptoTransform_;
205#endif
206               
207                /// <summary>
208                /// Get/set the password used for encryption.
209                /// </summary>
210                /// <remarks>When set to null or if the password is empty no encryption is performed</remarks>
211                public string Password {
212                        get {
213                                return password;
214                        }
215                        set {
216                                if ( (value != null) && (value.Length == 0) ) {
217                                        password = null;
218                                } else {
219                                        password = value;
220                                }
221                        }
222                }
223
224                /// <summary>
225                /// Encrypt a block of data
226                /// </summary>
227                /// <param name="buffer">
228                /// Data to encrypt.  NOTE the original contents of the buffer are lost
229                /// </param>
230                /// <param name="offset">
231                /// Offset of first byte in buffer to encrypt
232                /// </param>
233                /// <param name="length">
234                /// Number of bytes in buffer to encrypt
235                /// </param>
236                protected void EncryptBlock(byte[] buffer, int offset, int length)
237                {
238#if NETCF_1_0
239                        for (int i = offset; i < offset + length; ++i) {
240                                byte oldbyte = buffer[i];
241                                buffer[i] ^= EncryptByte();
242                                UpdateKeys(oldbyte);
243                        }
244#else
245                        cryptoTransform_.TransformBlock(buffer, 0, length, buffer, 0);
246#endif
247                }
248
249                /// <summary>
250                /// Initializes encryption keys based on given <paramref name="password"/>.
251                /// </summary>
252                /// <param name="password">The password.</param>
253                protected void InitializePassword(string password)
254                {
255#if NETCF_1_0
256                        keys = new uint[] {
257                                0x12345678,
258                                0x23456789,
259                                0x34567890
260                        };
261                       
262                        byte[] rawPassword = ZipConstants.ConvertToArray(password);
263                       
264                        for (int i = 0; i < rawPassword.Length; ++i) {
265                                UpdateKeys((byte)rawPassword[i]);
266                        }
267                       
268#else                   
269                        PkzipClassicManaged pkManaged = new PkzipClassicManaged();
270                        byte[] key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(password));
271                        cryptoTransform_ = pkManaged.CreateEncryptor(key, null);
272#endif
273                }
274
275#if NETCF_1_0
276               
277                /// <summary>
278                /// Encrypt a single byte
279                /// </summary>
280                /// <returns>
281                /// The encrypted value
282                /// </returns>
283                protected byte EncryptByte()
284                {
285                        uint temp = ((keys[2] & 0xFFFF) | 2);
286                        return (byte)((temp * (temp ^ 1)) >> 8);
287                }
288
289                /// <summary>
290                /// Update encryption keys
291                /// </summary>         
292                protected void UpdateKeys(byte ch)
293                {
294                        keys[0] = Crc32.ComputeCrc32(keys[0], ch);
295                        keys[1] = keys[1] + (byte)keys[0];
296                        keys[1] = keys[1] * 134775813 + 1;
297                        keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24));
298                }
299#endif
300
301                #endregion
302               
303                #region Deflation Support
304                /// <summary>
305                /// Deflates everything in the input buffers.  This will call
306                /// <code>def.deflate()</code> until all bytes from the input buffers
307                /// are processed.
308                /// </summary>
309                protected void Deflate()
310                {
311                        while (!deflater_.IsNeedingInput)
312                        {
313                                int deflateCount = deflater_.Deflate(buffer_, 0, buffer_.Length);
314                               
315                                if (deflateCount <= 0) {
316                                        break;
317                                }
318#if NETCF_1_0
319                                if (keys != null)
320#else
321                                if (cryptoTransform_ != null)
322#endif
323                                {
324                                        EncryptBlock(buffer_, 0, deflateCount);
325                                }
326                               
327                                baseOutputStream_.Write(buffer_, 0, deflateCount);
328                        }
329                       
330                        if (!deflater_.IsNeedingInput) {
331                                throw new SharpZipBaseException("DeflaterOutputStream can't deflate all input?");
332                        }
333                }
334                #endregion
335               
336                #region Stream Overrides
337                /// <summary>
338                /// Gets value indicating stream can be read from
339                /// </summary>
340                public override bool CanRead
341                {
342                        get {
343                                return false;
344                        }
345                }
346               
347                /// <summary>
348                /// Gets a value indicating if seeking is supported for this stream
349                /// This property always returns false
350                /// </summary>
351                public override bool CanSeek {
352                        get {
353                                return false;
354                        }
355                }
356               
357                /// <summary>
358                /// Get value indicating if this stream supports writing
359                /// </summary>
360                public override bool CanWrite {
361                        get {
362                                return baseOutputStream_.CanWrite;
363                        }
364                }
365               
366                /// <summary>
367                /// Get current length of stream
368                /// </summary>
369                public override long Length {
370                        get {
371                                return baseOutputStream_.Length;
372                        }
373                }
374               
375                /// <summary>
376                /// Gets the current position within the stream.
377                /// </summary>
378                /// <exception cref="NotSupportedException">Any attempt to set position</exception>
379                public override long Position {
380                        get {
381                                return baseOutputStream_.Position;
382                        }
383                        set {
384                                throw new NotSupportedException("Position property not supported");
385                        }
386                }
387               
388                /// <summary>
389                /// Sets the current position of this stream to the given value. Not supported by this class!
390                /// </summary>
391                /// <param name="offset">The offset relative to the <paramref name="origin"/> to seek.</param>
392                /// <param name="origin">The <see cref="SeekOrigin"/> to seek from.</param>
393                /// <returns>The new position in the stream.</returns>
394                /// <exception cref="NotSupportedException">Any access</exception>
395                public override long Seek(long offset, SeekOrigin origin)
396                {
397                        throw new NotSupportedException("DeflaterOutputStream Seek not supported");
398                }
399               
400                /// <summary>
401                /// Sets the length of this stream to the given value. Not supported by this class!
402                /// </summary>
403                /// <param name="value">The new stream length.</param>
404                /// <exception cref="NotSupportedException">Any access</exception>
405                public override void SetLength(long value)
406                {
407                        throw new NotSupportedException("DeflaterOutputStream SetLength not supported");
408                }
409               
410                /// <summary>
411                /// Read a byte from stream advancing position by one
412                /// </summary>
413                /// <returns>The byte read cast to an int.  THe value is -1 if at the end of the stream.</returns>
414                /// <exception cref="NotSupportedException">Any access</exception>
415                public override int ReadByte()
416                {
417                        throw new NotSupportedException("DeflaterOutputStream ReadByte not supported");
418                }
419               
420                /// <summary>
421                /// Read a block of bytes from stream
422                /// </summary>
423                /// <param name="buffer">The buffer to store read data in.</param>
424                /// <param name="offset">The offset to start storing at.</param>
425                /// <param name="count">The maximum number of bytes to read.</param>
426                /// <returns>The actual number of bytes read.  Zero if end of stream is detected.</returns>
427                /// <exception cref="NotSupportedException">Any access</exception>
428                public override int Read(byte[] buffer, int offset, int count)
429                {
430                        throw new NotSupportedException("DeflaterOutputStream Read not supported");
431                }
432               
433                /// <summary>
434                /// Asynchronous reads are not supported a NotSupportedException is always thrown
435                /// </summary>
436                /// <param name="buffer">The buffer to read into.</param>
437                /// <param name="offset">The offset to start storing data at.</param>
438                /// <param name="count">The number of bytes to read</param>
439                /// <param name="callback">The async callback to use.</param>
440                /// <param name="state">The state to use.</param>
441                /// <returns>Returns an <see cref="IAsyncResult"/></returns>
442                /// <exception cref="NotSupportedException">Any access</exception>
443                public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
444                {
445                        throw new NotSupportedException("DeflaterOutputStream BeginRead not currently supported");
446                }
447               
448                /// <summary>
449                /// Asynchronous writes arent supported, a NotSupportedException is always thrown
450                /// </summary>
451                /// <param name="buffer">The buffer to write.</param>
452                /// <param name="offset">The offset to begin writing at.</param>
453                /// <param name="count">The number of bytes to write.</param>
454                /// <param name="callback">The <see cref="AsyncCallback"/> to use.</param>
455                /// <param name="state">The state object.</param>
456                /// <returns>Returns an IAsyncResult.</returns>
457                /// <exception cref="NotSupportedException">Any access</exception>
458                public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
459                {
460                        throw new NotSupportedException("BeginWrite is not supported");
461                }
462               
463                /// <summary>
464                /// Flushes the stream by calling <see cref="DeflaterOutputStream.Flush">Flush</see> on the deflater and then
465                /// on the underlying stream.  This ensures that all bytes are flushed.
466                /// </summary>
467                public override void Flush()
468                {
469                        deflater_.Flush();
470                        Deflate();
471                        baseOutputStream_.Flush();
472                }
473               
474                /// <summary>
475                /// Calls <see cref="Finish"/> and closes the underlying
476                /// stream when <see cref="IsStreamOwner"></see> is true.
477                /// </summary>
478                public override void Close()
479                {
480                        if ( !isClosed_ ) {
481                                isClosed_ = true;
482
483                                try {
484                                        Finish();
485#if NETCF_1_0
486                                        keys=null;
487#else
488                                        if ( cryptoTransform_ != null ) {
489                                                cryptoTransform_.Dispose();
490                                                cryptoTransform_ = null;
491                                        }
492#endif
493                                }
494                                finally {
495                                        if( isStreamOwner_ ) {
496                                                baseOutputStream_.Close();
497                                        }
498                                }
499                        }
500                }
501               
502                /// <summary>
503                /// Writes a single byte to the compressed output stream.
504                /// </summary>
505                /// <param name="value">
506                /// The byte value.
507                /// </param>
508                public override void WriteByte(byte value)
509                {
510                        byte[] b = new byte[1];
511                        b[0] = value;
512                        Write(b, 0, 1);
513                }
514               
515                /// <summary>
516                /// Writes bytes from an array to the compressed stream.
517                /// </summary>
518                /// <param name="buffer">
519                /// The byte array
520                /// </param>
521                /// <param name="offset">
522                /// The offset into the byte array where to start.
523                /// </param>
524                /// <param name="count">
525                /// The number of bytes to write.
526                /// </param>
527                public override void Write(byte[] buffer, int offset, int count)
528                {
529                        deflater_.SetInput(buffer, offset, count);
530                        Deflate();
531                }               
532                #endregion
533               
534                #region Instance Fields
535                /// <summary>
536                /// This buffer is used temporarily to retrieve the bytes from the
537                /// deflater and write them to the underlying output stream.
538                /// </summary>
539                byte[] buffer_;
540               
541                /// <summary>
542                /// The deflater which is used to deflate the stream.
543                /// </summary>
544                protected Deflater deflater_;
545               
546                /// <summary>
547                /// Base stream the deflater depends on.
548                /// </summary>
549                protected Stream baseOutputStream_;
550
551                bool isClosed_;
552               
553                bool isStreamOwner_ = true;
554                #endregion
555        }
556}
Notatka: Zobacz TracBrowser aby uzyskać więcej informacji.