Exemple #1
0
        /// <summary>Transforms a stream.</summary>
        /// <param name="input">The input <see cref="Stream"/> containing the data to compress or decompress</param>
        /// <param name="output">The output <see cref="Stream"/> where the results should be written</param>
        /// <param name="flush">The flush mode to use. The default is <see cref="ZlibFlush.Finish"/>, which means that
        /// <paramref name="input"/> represents the entire remaining data to transform.
        /// </param>
        public unsafe void Transform(Stream input, Stream output, ZlibFlush flush = ZlibFlush.Finish)
        {
            if (input == null)
            {
                throw new ArgumentNullException(nameof(input));
            }
            if (output == null)
            {
                throw new ArgumentNullException(nameof(output));
            }
            AssertUsable();
            byte[] inbuf = ArrayPool <byte> .Shared.Rent(4096), outbuf = ArrayPool <byte> .Shared.Rent(4096);

            bool more;

            while (true)
            {
                int read = input.Read(inbuf, 0, inbuf.Length); // read some data from the input
                if (read == 0)                                 // if there was no more data...
                {
                    if (Mode == CompressionMode.Decompress && flush == ZlibFlush.Finish)
                    {
                        throw new EndOfStreamException();
                    }
                    break;
                }
                for (int index = 0; index < read;)                 // transform the input we read
                {
                    more = Transform(inbuf, index, read - index, out int consumed,
                                     outbuf, 0, outbuf.Length, out int produced, ZlibFlush.None);            // transform some of the input
                    output.Write(outbuf, 0, produced);
                    index += consumed;
                    if (!more)                    // if no more data is needed (e.g. because we reached the end of the decompressed data)
                    {
                        if (input.CanSeek)
                        {
                            input.Seek(index - read, SeekOrigin.Current); // try to put back the extra input we read
                        }
                        return;                                           // and we're done
                    }
                }
            }
            while (true)            // at this point, we've transformed all of the input, but we need to flush the remaining output
            {
                more = Transform(inbuf, 0, 0, out int _, outbuf, 0, outbuf.Length, out int produced, flush);
                output.Write(outbuf, 0, produced);
                if (!more || produced == 0)
                {
                    break;                                        // if we've reached the end while decompressing or if no data was produced, we're done
                }
            }
        }
Exemple #2
0
        public unsafe byte[] Transform(byte[] input, int index, int length, ZlibFlush flush = ZlibFlush.Finish)
#endif
        {
            Utility.ValidateRange(input, index, length);
            byte[] buffer       = new byte[Math.Max(64, Mode == CompressionMode.Compress ? input.Length / 4 : input.Length * 3 / 2)];
            int    outputLength = 0;

            while (true)
            {
                bool more = Transform(input, index, length, out int read,
                                      buffer, outputLength, buffer.Length - outputLength, out int written, flush);
                outputLength += written;
                index        += read;
                length       -= read;
                if (!more)                // if we transformed everything (when flush is Finish)
                {
                    // if we were decompressing and reached the end of compressed data before the input was exhausted, complain
                    if (length != 0)
                    {
                        throw new InvalidDataException("Too much data was provided.");
                    }
                    break;                              // otherwise, we're done
                }
                else if (outputLength == buffer.Length) // if the buffer is full, maybe we need to provide more output space
                {
                    Array.Resize(ref buffer, buffer.Length + Math.Max(64, Mode == CompressionMode.Compress ? length : length * 3 / 2));
                }
                else if (length == 0)                // otherwise, we've given all we got, but zlib still wants more
                {
                    if (flush == ZlibFlush.Finish)
                    {
                        throw new EndOfStreamException(); // if they didn't provide enough data, throw
                    }
                    break;                                // otherwise, the user should call us again with more input
                }
            }

#if !NETSTANDARD2_0 && !NET45 && !NET46
            return(new Memory <byte>(buffer, 0, outputLength));
#else
            Array.Resize(ref buffer, outputLength);
            return(buffer);
#endif
        }
Exemple #3
0
        /// <summary>Transforms a single chunks of data.</summary>
        /// <param name="input">The array containing the data to compress or decompress</param>
        /// <param name="inputIndex">The index within <paramref name="input"/> where the data to transform begins</param>
        /// <param name="inputLength">The number of bytes within <paramref name="input"/> to transform</param>
        /// <param name="bytesRead">A variable that will receive the number of bytes read from the input</param>
        /// <param name="output">The array where the compressed or decompressed data should be written</param>
        /// <param name="outputIndex">The index within <paramref name="output"/> where the transformed data should be written</param>
        /// <param name="outputLength">The available space within <paramref name="output"/> for transformed data to be written</param>
        /// <param name="bytesWritten">A variable that will receive the number of bytes written to the output</param>
        /// <param name="flush">The <see cref="ZlibFlush"/> mode of the transformation</param>
        /// <returns>Returns false if the transformation is complete (when <paramref name="flush"/> is <see cref="ZlibFlush.Finish"/>),
        /// and true otherwise.
        /// </returns>
        public unsafe bool Transform(byte[] input, int inputIndex, int inputLength, out int bytesRead,
                                     byte[] output, int outputIndex, int outputLength, out int bytesWritten, ZlibFlush flush)
        {
            Utility.ValidateRange(input, inputIndex, inputLength);
            Utility.ValidateRange(output, outputIndex, outputLength);
            AssertUsable();
            used = true;
            codec.InputBuffer       = input;
            codec.NextIn            = inputIndex;
            codec.AvailableBytesIn  = inputLength;
            codec.OutputBuffer      = output;
            codec.NextOut           = outputIndex;
            codec.AvailableBytesOut = outputLength;
retry:
            var res = (Result)(Mode == CompressionMode.Compress ?
                               codec.Deflate((Ionic.Zlib.FlushType)flush) : codec.Inflate((Ionic.Zlib.FlushType)flush));

            if (res == Result.NeedDict)                               // if we're decompressing and need the initial dictionary...
            {
                CheckResult((Result)codec.SetDictionary(dictionary)); // provide it
                if (codec.AvailableBytesIn != 0 && codec.AvailableBytesOut != 0)
                {
                    goto retry;                                                                             // if more space is available, continue
                }
            }
            bytesRead    = codec.NextIn - inputIndex;
            bytesWritten = codec.NextOut - outputIndex;
            return(res != Result.EOF);
        }
Exemple #4
0
        /// <summary>Transforms a region of memory.</summary>
        /// <param name="input">The array containing the data to compress or decompress</param>
        /// <param name="index">The index within <paramref name="input"/> where the data begins</param>
        /// <param name="length">The number of bytes to transform</param>
        /// <param name="flush">The flush mode to use. The default is <see cref="ZlibFlush.Finish"/>, which means that
        /// <paramref name="input"/> represents the entire remaining data to transform.
        /// </param>
        /// <remarks>It is not efficient to use this method to transform a large amount of data.</remarks>
#if !NETSTANDARD2_0 && !NET45 && !NET46
        public unsafe Memory <byte> Transform(byte[] input, int index, int length, ZlibFlush flush = ZlibFlush.Finish)
Exemple #5
0
 public byte[] Transform(byte[] input, ZlibFlush flush = ZlibFlush.Finish) => Transform(input, 0, input.Length, flush);