/**
         * Reads compressed data into a byte buffer.
         *
         * @param b
         *            the byte buffer that compressed data will be read into.
         * @param off
         *            the offset in the byte buffer where compressed data will start
         *            to be read into.
         * @param len
         *            the length of the compressed data that is expected to read.
         * @return the number of bytes read or -1 if the end of the compressed input
         *         stream has been reached.
         */

        public override int read(byte[] b, int off, int len)  //throws IOException {
        {
            checkClosed();
            if (null == b)
            {
                throw new java.lang.NullPointerException();
            }
            if (off < 0 || len < 0 || len > b.Length - off)
            {
                throw new java.lang.IndexOutOfBoundsException();
            }

            if (!availableJ)
            {
                return(EOF);
            }

            int count = 0;

            while (count < len && !def.finished())
            {
                if (def.needsInput())
                {
                    // read data from input stream
                    int readed = inJ.read(buf);
                    if (EOF == readed)
                    {
                        // gets to the end of the input stream
                        def.finish();
                    }
                    else
                    {
                        def.setInput(buf, 0, readed);
                    }
                }
                // gets compressed data from def
                int readedJ = def.deflate(buf, 0, java.lang.Math.min(buf.Length, len - count));
                if (EOF == readedJ)
                {
                    break;
                }
                java.lang.SystemJ.arraycopy(buf, 0, b, off + count, readedJ);
                count += readedJ;
            }
            if (0 == count)
            {
                count      = EOF;
                availableJ = false;
            }
            return(count);
        }
        /*
         * Writes any unwritten data to the underlying stream. Does not close the
         * stream.
         *
         * @throws IOException
         *             If an error occurs.
         */
        public virtual void finish() // throws IOException {
        {
            if (done)
            {
                return;
            }
            def.finish();
            int x = 0;

            while (!def.finished())
            {
                if (def.needsInput())
                {
                    def.setInput(buf, 0, 0);
                }
                x = def.deflate(buf);
                outJ.write(buf, 0, x);
            }
            done = true;
        }