IronPython.Zlib / src / Decompress.cs

/* ****************************************************************************
 *
 * Copyright (c) Jeff Hardy 2007-2009.
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.txt file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * jdhardy@gmail.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * ***************************************************************************/

using System;
using System.Runtime.InteropServices;
using ComponentAce.Compression.Libs.ZLib;
using IronPython.Runtime;
using IronPython.Runtime.Operations;

namespace IronPython.Zlib
{
    [PythonType]
    public class Decompress
    {
        private const int Z_OK = ZlibModule.Z_OK;
        private const int Z_STREAM_END = ZlibModule.Z_STREAM_END;
        private const int Z_BUF_ERROR = ZlibModule.Z_BUF_ERROR;

        private const int Z_SYNC_FLUSH = ZlibModule.Z_SYNC_FLUSH;
        private const int Z_FINISH = ZlibModule.Z_FINISH;

        internal Decompress(int wbits)
        {
            zst = new ZStream();
            int err = zst.inflateInit(wbits);
            switch(err)
            {
                case ZlibModule.Z_OK:
                    break;

                case ZlibModule.Z_STREAM_ERROR:
                    throw PythonOps.ValueError("Invalid initialization option");

                default:
                    throw ZlibModule.zlib_error(this.zst, err, "while creating decompression object");
            }

            _unused_data = string.Empty;
            _unconsumed_tail = string.Empty;
        }

        private string _unused_data;
        public string unused_data
        {
            get { return _unused_data; }
        }

        private string _unconsumed_tail;
        public string unconsumed_tail
        {
            get { return _unconsumed_tail; }
        }

        public string decompress(string value)
        {
            return decompress(value, 0);
        }

        public string decompress(string value, int max_length)
        {
            if(max_length < 0) throw new ArgumentException("max_length must be greater than zero");

            byte[] input = ZlibModule.Latin1.GetBytes(value);
            byte[] output = new byte[max_length > 0 ? max_length : ZlibModule.DEFAULTALLOC];

            long start_total_out = zst.total_out;
            zst.next_in = input;
            zst.next_in_index = 0;
            zst.avail_in = input.Length;
            zst.next_out = output;
            zst.next_out_index = 0;
            zst.avail_out = output.Length;

            int err = zst.inflate(FlushStrategy.Z_SYNC_FLUSH);

            while(err == Z_OK && zst.avail_out == 0)
            {
                if(max_length > 0 && output.Length >= max_length)
                    break;

                int old_length = output.Length;
                Array.Resize(ref output, output.Length * 2);
                zst.next_out = output;
                zst.avail_out = old_length;

                err = zst.inflate(FlushStrategy.Z_SYNC_FLUSH);
            }

            if(max_length > 0)
            {
                _unconsumed_tail = ZlibModule.Latin1.GetString(zst.next_in, zst.next_in_index, zst.avail_in);
            }

            if(err == Z_STREAM_END)
            {
                _unused_data += ZlibModule.Latin1.GetString(zst.next_in, zst.next_in_index, zst.avail_in);
            }
            else if(err != Z_OK && err != Z_BUF_ERROR)
            {
                throw ZlibModule.zlib_error(this.zst, err, "while decompressing");
            }

            return ZlibModule.Latin1.GetString(output, 0, (int)(zst.total_out - start_total_out));
        }

        public string flush([DefaultParameterValue(ZlibModule.DEFAULTALLOC)]int length)
        {
            if(length < 1)
                throw PythonOps.ValueError("length must be greater than 0.");

            byte[] output = new byte[length];

            long start_total_out = zst.total_out;
            zst.next_out = output;
            zst.next_out_index = 0;
            zst.avail_out = output.Length;

            int err = zst.inflate(FlushStrategy.Z_FINISH);

            while((err == Z_OK || err == Z_BUF_ERROR) &&zst.avail_out == 0)
            {
                int old_length = output.Length;
                Array.Resize(ref output, output.Length * 2);
                zst.next_out = output;
                zst.avail_out = old_length;

                err = zst.inflate(FlushStrategy.Z_FINISH);
            }

            if(err == Z_STREAM_END)
            {
                err = zst.inflateEnd();
                if(err != Z_OK)
                {
                    throw ZlibModule.zlib_error(this.zst, err, "from inflateEnd()");
                }
            }

            return ZlibModule.Latin1.GetString(output, 0, (int)(zst.total_out - start_total_out));
        }

        //public Compress copy()
        //{
        //    throw new NotImplementedException();
        //}

        private ZStream zst;
    }
}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.