root/trunk/BazaReklam.Updater/ICSharpCode.SharpZipLib/Zip/Compression/Streams/InflaterInputStream.cs @ 818

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

re #165

Line 
1// InflaterInputStream.cs
2//
3// Copyright (C) 2001 Mike Krueger
4// Copyright (C) 2004 John Reilly
5//
6// This file was translated from java, it was part of the GNU Classpath
7// Copyright (C) 2001 Free Software Foundation, Inc.
8//
9// This program is free software; you can redistribute it and/or
10// modify it under the terms of the GNU General Public License
11// as published by the Free Software Foundation; either version 2
12// of the License, or (at your option) any later version.
13//
14// This program is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17// GNU General Public License for more details.
18//
19// You should have received a copy of the GNU General Public License
20// along with this program; if not, write to the Free Software
21// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22//
23// Linking this library statically or dynamically with other modules is
24// making a combined work based on this library.  Thus, the terms and
25// conditions of the GNU General Public License cover the whole
26// combination.
27//
28// As a special exception, the copyright holders of this library give you
29// permission to link this library with independent modules to produce an
30// executable, regardless of the license terms of these independent
31// modules, and to copy and distribute the resulting executable under
32// terms of your choice, provided that you also meet, for each linked
33// independent module, the terms and conditions of the license of that
34// module.  An independent module is a module which is not derived from
35// or based on this library.  If you modify this library, you may extend
36// this exception to your version of the library, but you are not
37// obligated to do so.  If you do not wish to do so, delete this
38// exception statement from your version.
39
40using System;
41using System.IO;
42
43#if !NETCF_1_0
44using System.Security.Cryptography;
45#endif
46
47using ICSharpCode.SharpZipLib.Zip.Compression;
48using ICSharpCode.SharpZipLib.Checksums;
49
50namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams
51{
52
53        /// <summary>
54        /// An input buffer customised for use by <see cref="InflaterInputStream"/>
55        /// </summary>
56        /// <remarks>
57        /// The buffer supports decryption of incoming data.
58        /// </remarks>
59        public class InflaterInputBuffer
60        {
61                #region Constructors
62                /// <summary>
63                /// Initialise a new instance of <see cref="InflaterInputBuffer"/> with a default buffer size
64                /// </summary>
65                /// <param name="stream">The stream to buffer.</param>
66                public InflaterInputBuffer(Stream stream) : this(stream , 4096)
67                {
68                }
69               
70                /// <summary>
71                /// Initialise a new instance of <see cref="InflaterInputBuffer"/>
72                /// </summary>
73                /// <param name="stream">The stream to buffer.</param>
74                /// <param name="bufferSize">The size to use for the buffer</param>
75                /// <remarks>A minimum buffer size of 1KB is permitted.  Lower sizes are treated as 1KB.</remarks>
76                public InflaterInputBuffer(Stream stream, int bufferSize)
77                {
78                        inputStream = stream;
79                        if ( bufferSize < 1024 ) {
80                                bufferSize = 1024;
81                        }
82                        rawData = new byte[bufferSize];
83                        clearText = rawData;
84                }
85                #endregion
86
87                /// <summary>
88                /// Get the length of bytes bytes in the <see cref="RawData"/>
89                /// </summary>
90                public int RawLength
91                {
92                        get {
93                                return rawLength;
94                        }
95                }
96               
97                /// <summary>
98                /// Get the contents of the raw data buffer.
99                /// </summary>
100                /// <remarks>This may contain encrypted data.</remarks>
101                public byte[] RawData
102                {
103                        get {
104                                return rawData;
105                        }
106                }
107               
108                /// <summary>
109                /// Get the number of useable bytes in <see cref="ClearText"/>
110                /// </summary>
111                public int ClearTextLength
112                {
113                        get {
114                                return clearTextLength;
115                        }
116                }
117               
118                /// <summary>
119                /// Get the contents of the clear text buffer.
120                /// </summary>
121                public byte[] ClearText
122                {
123                        get {
124                                return clearText;
125                        }
126                }
127               
128                /// <summary>
129                /// Get/set the number of bytes available
130                /// </summary>
131                public int Available
132                {
133                        get { return available; }
134                        set { available = value; }
135                }
136
137                /// <summary>
138                /// Call <see cref="Inflater.SetInput(byte[], int, int)"/> passing the current clear text buffer contents.
139                /// </summary>
140                /// <param name="inflater">The inflater to set input for.</param>
141                public void SetInflaterInput(Inflater inflater)
142                {
143                        if ( available > 0 ) {
144                                inflater.SetInput(clearText, clearTextLength - available, available);
145                                available = 0;
146                        }
147                }
148
149                /// <summary>
150                /// Fill the buffer from the underlying input stream.
151                /// </summary>
152                public void Fill()
153                {
154                        rawLength = 0;
155                        int toRead = rawData.Length;
156                       
157                        while (toRead > 0) {
158                                int count = inputStream.Read(rawData, rawLength, toRead);
159                                if ( count <= 0 ) {
160                                        if (rawLength == 0) {
161                                                throw new SharpZipBaseException("Unexpected EOF");
162                                        }
163                                        break;
164                                }
165                                rawLength += count;
166                                toRead -= count;
167                        }
168                       
169#if !NETCF_1_0
170                        if ( cryptoTransform != null ) {
171                                clearTextLength = cryptoTransform.TransformBlock(rawData, 0, rawLength, clearText, 0);
172                        }
173                        else
174#endif                         
175                        {
176                                clearTextLength = rawLength;
177                        }
178
179                        available = clearTextLength;
180                }
181               
182                /// <summary>
183                /// Read a buffer directly from the input stream
184                /// </summary>
185                /// <param name="buffer">The buffer to fill</param>
186                /// <returns>Returns the number of bytes read.</returns>
187                public int ReadRawBuffer(byte[] buffer)
188                {
189                        return ReadRawBuffer(buffer, 0, buffer.Length);
190                }
191
192                /// <summary>
193                /// Read a buffer directly from the input stream
194                /// </summary>
195                /// <param name="outBuffer">The buffer to read into</param>
196                /// <param name="offset">The offset to start reading data into.</param>
197                /// <param name="length">The number of bytes to read.</param>
198                /// <returns>Returns the number of bytes read.</returns>
199                public int ReadRawBuffer(byte[] outBuffer, int offset, int length)
200                {
201                        if ( length < 0 ) {
202                                throw new ArgumentOutOfRangeException("length");
203                        }
204                       
205                        int currentOffset = offset;
206                        int currentLength = length;
207                       
208                        while ( currentLength > 0 ) {
209                                if ( available <= 0 ) {
210                                        Fill();
211                                        if (available <= 0) {
212                                                return 0;
213                                        }
214                                }
215                                int toCopy = Math.Min(currentLength, available);
216                                System.Array.Copy(rawData, rawLength - (int)available, outBuffer, currentOffset, toCopy);
217                                currentOffset += toCopy;
218                                currentLength -= toCopy;
219                                available -= toCopy;
220                        }
221                        return length;
222                }
223               
224                /// <summary>
225                /// Read clear text data from the input stream.
226                /// </summary>
227                /// <param name="outBuffer">The buffer to add data to.</param>
228                /// <param name="offset">The offset to start adding data at.</param>
229                /// <param name="length">The number of bytes to read.</param>
230                /// <returns>Returns the number of bytes actually read.</returns>
231                public int ReadClearTextBuffer(byte[] outBuffer, int offset, int length)
232                {
233                        if ( length < 0 ) {
234                                throw new ArgumentOutOfRangeException("length");
235                        }
236                       
237                        int currentOffset = offset;
238                        int currentLength = length;
239                       
240                        while ( currentLength > 0 ) {
241                                if ( available <= 0 ) {
242                                        Fill();
243                                        if (available <= 0) {
244                                                return 0;
245                                        }
246                                }
247                               
248                                int toCopy = Math.Min(currentLength, available);
249                                System.Array.Copy(clearText, clearTextLength - (int)available, outBuffer, currentOffset, toCopy);
250                                currentOffset += toCopy;
251                                currentLength -= toCopy;
252                                available -= toCopy;
253                        }
254                        return length;
255                }
256               
257                /// <summary>
258                /// Read a <see cref="byte"/> from the input stream.
259                /// </summary>
260                /// <returns>Returns the byte read.</returns>
261                public int ReadLeByte()
262                {
263                        if (available <= 0) {
264                                Fill();
265                                if (available <= 0) {
266                                        throw new ZipException("EOF in header");
267                                }
268                        }
269                        byte result = rawData[rawLength - available];
270                        available -= 1;
271                        return result;
272                }
273               
274                /// <summary>
275                /// Read an <see cref="short"/> in little endian byte order.
276                /// </summary>
277                /// <returns>The short value read case to an int.</returns>
278                public int ReadLeShort()
279                {
280                        return ReadLeByte() | (ReadLeByte() << 8);
281                }
282               
283                /// <summary>
284                /// Read an <see cref="int"/> in little endian byte order.
285                /// </summary>
286                /// <returns>The int value read.</returns>
287                public int ReadLeInt()
288                {
289                        return ReadLeShort() | (ReadLeShort() << 16);
290                }
291               
292                /// <summary>
293                /// Read a <see cref="long"/> in little endian byte order.
294                /// </summary>
295                /// <returns>The long value read.</returns>
296                public long ReadLeLong()
297                {
298                        return (uint)ReadLeInt() | ((long)ReadLeInt() << 32);
299                }
300
301#if !NETCF_1_0
302                /// <summary>
303                /// Get/set the <see cref="ICryptoTransform"/> to apply to any data.
304                /// </summary>
305                /// <remarks>Set this value to null to have no transform applied.</remarks>
306                public ICryptoTransform CryptoTransform
307                {
308                        set {
309                                cryptoTransform = value;
310                                if ( cryptoTransform != null ) {
311                                        if ( rawData == clearText ) {
312                                                if ( internalClearText == null ) {
313                                                        internalClearText = new byte[rawData.Length];
314                                                }
315                                                clearText = internalClearText;
316                                        }
317                                        clearTextLength = rawLength;
318                                        if ( available > 0 ) {
319                                                cryptoTransform.TransformBlock(rawData, rawLength - available, available, clearText, rawLength - available);
320                                        }
321                                } else {
322                                        clearText = rawData;
323                                        clearTextLength = rawLength;
324                                }
325                        }
326                }
327#endif
328
329                #region Instance Fields
330                int rawLength;
331                byte[] rawData;
332               
333                int clearTextLength;
334                byte[] clearText;
335#if !NETCF_1_0         
336                byte[] internalClearText;
337#endif
338               
339                int available;
340               
341#if !NETCF_1_0
342                ICryptoTransform cryptoTransform;
343#endif         
344                Stream inputStream;
345                #endregion
346        }
347       
348        /// <summary>
349        /// This filter stream is used to decompress data compressed using the "deflate"
350        /// format. The "deflate" format is described in RFC 1951.
351        ///
352        /// This stream may form the basis for other decompression filters, such
353        /// as the <see cref="ICSharpCode.SharpZipLib.GZip.GZipInputStream">GZipInputStream</see>.
354        ///
355        /// Author of the original java version : John Leuner.
356        /// </summary>
357        public class InflaterInputStream : Stream
358        {
359                #region Constructors
360                /// <summary>
361                /// Create an InflaterInputStream with the default decompressor
362                /// and a default buffer size of 4KB.
363                /// </summary>
364                /// <param name = "baseInputStream">
365                /// The InputStream to read bytes from
366                /// </param>
367                public InflaterInputStream(Stream baseInputStream)
368                        : this(baseInputStream, new Inflater(), 4096)
369                {
370                }
371               
372                /// <summary>
373                /// Create an InflaterInputStream with the specified decompressor
374                /// and a default buffer size of 4KB.
375                /// </summary>
376                /// <param name = "baseInputStream">
377                /// The source of input data
378                /// </param>
379                /// <param name = "inf">
380                /// The decompressor used to decompress data read from baseInputStream
381                /// </param>
382                public InflaterInputStream(Stream baseInputStream, Inflater inf)
383                        : this(baseInputStream, inf, 4096)
384                {
385                }
386               
387                /// <summary>
388                /// Create an InflaterInputStream with the specified decompressor
389                /// and the specified buffer size.
390                /// </summary>
391                /// <param name = "baseInputStream">
392                /// The InputStream to read bytes from
393                /// </param>
394                /// <param name = "inflater">
395                /// The decompressor to use
396                /// </param>
397                /// <param name = "bufferSize">
398                /// Size of the buffer to use
399                /// </param>
400                public InflaterInputStream(Stream baseInputStream, Inflater inflater, int bufferSize)
401                {
402                        if (baseInputStream == null) {
403                                throw new ArgumentNullException("baseInputStream");
404                        }
405                       
406                        if (inflater == null) {
407                                throw new ArgumentNullException("inflater");
408                        }
409                       
410                        if (bufferSize <= 0) {
411                                throw new ArgumentOutOfRangeException("bufferSize");
412                        }
413                       
414                        this.baseInputStream = baseInputStream;
415                        this.inf = inflater;
416                       
417                        inputBuffer = new InflaterInputBuffer(baseInputStream, bufferSize);
418                }
419               
420                #endregion
421
422                /// <summary>
423                /// Get/set flag indicating ownership of underlying stream.
424                /// When the flag is true <see cref="Close"/> will close the underlying stream also.
425                /// </summary>
426                /// <remarks>
427                /// The default value is true.
428                /// </remarks>
429                public bool IsStreamOwner
430                {
431                        get { return isStreamOwner; }
432                        set { isStreamOwner = value; }
433                }
434               
435                /// <summary>
436                /// Skip specified number of bytes of uncompressed data
437                /// </summary>
438                /// <param name ="count">
439                /// Number of bytes to skip
440                /// </param>
441                /// <returns>
442                /// The number of bytes skipped, zero if the end of
443                /// stream has been reached
444                /// </returns>
445                /// <exception cref="ArgumentOutOfRangeException">
446                /// <paramref name="count">The number of bytes</paramref> to skip is less than or equal to zero.
447                /// </exception>
448                public long Skip(long count)
449                {
450                        if (count <= 0) {
451                                throw new ArgumentOutOfRangeException("count");
452                        }
453                       
454                        // v0.80 Skip by seeking if underlying stream supports it...
455                        if (baseInputStream.CanSeek) {
456                                baseInputStream.Seek(count, SeekOrigin.Current);
457                                return count;
458                        }
459                        else {
460                                int length = 2048;
461                                if (count < length) {
462                                        length = (int) count;
463                                }
464
465                                byte[] tmp = new byte[length];
466                                int readCount = 1;
467                                long toSkip = count;
468
469                                while ((toSkip > 0) && (readCount > 0) ) {
470                                        if (toSkip < length) {
471                                                length = (int)toSkip;
472                                        }
473
474                                        readCount = baseInputStream.Read(tmp, 0, length);
475                                        toSkip -= readCount;
476                                }
477
478                                return count - toSkip;
479                        }
480                }
481               
482                /// <summary>
483                /// Clear any cryptographic state.
484                /// </summary>         
485                protected void StopDecrypting()
486                {
487#if !NETCF_1_0                 
488                        inputBuffer.CryptoTransform = null;
489#endif                 
490                }
491
492                /// <summary>
493                /// Returns 0 once the end of the stream (EOF) has been reached.
494                /// Otherwise returns 1.
495                /// </summary>
496                public virtual int Available
497                {
498                        get {
499                                return inf.IsFinished ? 0 : 1;
500                        }
501                }
502               
503                /// <summary>
504                /// Fills the buffer with more data to decompress.
505                /// </summary>
506                /// <exception cref="SharpZipBaseException">
507                /// Stream ends early
508                /// </exception>
509                protected void Fill()
510                {
511                        inputBuffer.Fill();
512                        inputBuffer.SetInflaterInput(inf);
513                }
514
515                #region Stream Overrides
516                /// <summary>
517                /// Gets a value indicating whether the current stream supports reading
518                /// </summary>
519                public override bool CanRead
520                {
521                        get {
522                                return baseInputStream.CanRead;
523                        }
524                }
525               
526                /// <summary>
527                /// Gets a value of false indicating seeking is not supported for this stream.
528                /// </summary>
529                public override bool CanSeek {
530                        get {
531                                return false;
532                        }
533                }
534               
535                /// <summary>
536                /// Gets a value of false indicating that this stream is not writeable.
537                /// </summary>
538                public override bool CanWrite {
539                        get {
540                                return false;
541                        }
542                }
543               
544                /// <summary>
545                /// A value representing the length of the stream in bytes.
546                /// </summary>
547                public override long Length {
548                        get {
549                                return inputBuffer.RawLength;
550                        }
551                }
552               
553                /// <summary>
554                /// The current position within the stream.
555                /// Throws a NotSupportedException when attempting to set the position
556                /// </summary>
557                /// <exception cref="NotSupportedException">Attempting to set the position</exception>
558                public override long Position {
559                        get {
560                                return baseInputStream.Position;
561                        }
562                        set {
563                                throw new NotSupportedException("InflaterInputStream Position not supported");
564                        }
565                }
566               
567                /// <summary>
568                /// Flushes the baseInputStream
569                /// </summary>
570                public override void Flush()
571                {
572                        baseInputStream.Flush();
573                }
574               
575                /// <summary>
576                /// Sets the position within the current stream
577                /// Always throws a NotSupportedException
578                /// </summary>
579                /// <param name="offset">The relative offset to seek to.</param>
580                /// <param name="origin">The <see cref="SeekOrigin"/> defining where to seek from.</param>
581                /// <returns>The new position in the stream.</returns>
582                /// <exception cref="NotSupportedException">Any access</exception>
583                public override long Seek(long offset, SeekOrigin origin)
584                {
585                        throw new NotSupportedException("Seek not supported");
586                }
587               
588                /// <summary>
589                /// Set the length of the current stream
590                /// Always throws a NotSupportedException
591                /// </summary>
592                /// <param name="value">The new length value for the stream.</param>
593                /// <exception cref="NotSupportedException">Any access</exception>
594                public override void SetLength(long value)
595                {
596                        throw new NotSupportedException("InflaterInputStream SetLength not supported");
597                }
598               
599                /// <summary>
600                /// Writes a sequence of bytes to stream and advances the current position
601                /// This method always throws a NotSupportedException
602                /// </summary>
603                /// <param name="buffer">Thew buffer containing data to write.</param>
604                /// <param name="offset">The offset of the first byte to write.</param>
605                /// <param name="count">The number of bytes to write.</param>
606                /// <exception cref="NotSupportedException">Any access</exception>
607                public override void Write(byte[] buffer, int offset, int count)
608                {
609                        throw new NotSupportedException("InflaterInputStream Write not supported");
610                }
611               
612                /// <summary>
613                /// Writes one byte to the current stream and advances the current position
614                /// Always throws a NotSupportedException
615                /// </summary>
616                /// <param name="value">The byte to write.</param>
617                /// <exception cref="NotSupportedException">Any access</exception>
618                public override void WriteByte(byte value)
619                {
620                        throw new NotSupportedException("InflaterInputStream WriteByte not supported");
621                }
622               
623                /// <summary>
624                /// Entry point to begin an asynchronous write.  Always throws a NotSupportedException.
625                /// </summary>
626                /// <param name="buffer">The buffer to write data from</param>
627                /// <param name="offset">Offset of first byte to write</param>
628                /// <param name="count">The maximum number of bytes to write</param>
629                /// <param name="callback">The method to be called when the asynchronous write operation is completed</param>
630                /// <param name="state">A user-provided object that distinguishes this particular asynchronous write request from other requests</param>
631                /// <returns>An <see cref="System.IAsyncResult">IAsyncResult</see> that references the asynchronous write</returns>
632                /// <exception cref="NotSupportedException">Any access</exception>
633                public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
634                {
635                        throw new NotSupportedException("InflaterInputStream BeginWrite not supported");
636                }
637               
638                /// <summary>
639                /// Closes the input stream.  When <see cref="IsStreamOwner"></see>
640                /// is true the underlying stream is also closed.
641                /// </summary>
642                public override void Close()
643                {
644                        if ( !isClosed ) {
645                                isClosed = true;
646                                if ( isStreamOwner ) {
647                                        baseInputStream.Close();
648                                }
649                        }
650                }
651
652                /// <summary>
653                /// Reads decompressed data into the provided buffer byte array
654                /// </summary>
655                /// <param name ="buffer">
656                /// The array to read and decompress data into
657                /// </param>
658                /// <param name ="offset">
659                /// The offset indicating where the data should be placed
660                /// </param>
661                /// <param name ="count">
662                /// The number of bytes to decompress
663                /// </param>
664                /// <returns>The number of bytes read.  Zero signals the end of stream</returns>
665                /// <exception cref="SharpZipBaseException">
666                /// Inflater needs a dictionary
667                /// </exception>
668                public override int Read(byte[] buffer, int offset, int count)
669                {
670                        if (inf.IsNeedingDictionary)
671                        {
672                                throw new SharpZipBaseException("Need a dictionary");
673                        }
674
675                        int remainingBytes = count;
676                        while (true) {
677                                int bytesRead = inf.Inflate(buffer, offset, remainingBytes);
678                                offset += bytesRead;
679                                remainingBytes -= bytesRead;
680
681                                if (remainingBytes == 0 || inf.IsFinished) {
682                                        break;
683                                }
684
685                                if ( inf.IsNeedingInput ) {
686                                        Fill();
687                                }
688                                else if ( bytesRead == 0 ) {
689                                        throw new ZipException("Dont know what to do");
690                                }
691                        }
692                        return count - remainingBytes;
693                }
694                #endregion
695                #region Instance Fields
696                /// <summary>
697                /// Decompressor for this stream
698                /// </summary>
699                protected Inflater inf;
700
701                /// <summary>
702                /// <see cref="InflaterInputBuffer">Input buffer</see> for this stream.
703                /// </summary>
704                protected InflaterInputBuffer inputBuffer;
705
706                /// <summary>
707                /// Base stream the inflater reads from.
708                /// </summary>
709                protected Stream baseInputStream;
710               
711                /// <summary>
712                /// The compressed size
713                /// </summary>
714                protected long csize;
715
716                /// <summary>
717                /// Flag indicating wether this instance has been closed or not.
718                /// </summary>
719                bool isClosed;
720
721                /// <summary>
722                /// Flag indicating wether this instance is designated the stream owner.
723                /// When closing if this flag is true the underlying stream is closed.
724                /// </summary>
725                bool isStreamOwner = true;
726                #endregion
727        }
728}
Notatka: Zobacz TracBrowser aby uzyskać więcej informacji.