예제 #1
0
        public CompressionState Compress(ZLibStream zStream, FlushMode flush)
        {
            FlushMode old_flush;

            if (flush > FlushMode.Finish || flush < 0)
            {
                return(CompressionState.ZSTREAMERROR);
            }

            if (zStream.NextOut == null ||
                (zStream.NextIn == null && zStream.AvailableIn != 0) ||
                (this.status == FINISHSTATE && flush != FlushMode.Finish))
            {
                zStream.Message = ZErrmsg[CompressionState.ZNEEDDICT - CompressionState.ZSTREAMERROR];
                return(CompressionState.ZSTREAMERROR);
            }

            if (zStream.AvailableOut == 0)
            {
                zStream.Message = ZErrmsg[CompressionState.ZNEEDDICT - CompressionState.ZBUFERROR];
                return(CompressionState.ZBUFERROR);
            }

            this.strm      = zStream; // just in case
            old_flush      = this.lastFlush;
            this.lastFlush = flush;

            // Write the zlib header
            if (this.status == INITSTATE)
            {
                int header      = (ZDEFLATED + ((this.wBits - 8) << 4)) << 8;
                int level_flags = (((int)this.level - 1) & 0xff) >> 1;

                if (level_flags > 3)
                {
                    level_flags = 3;
                }

                header |= level_flags << 6;
                if (this.strStart != 0)
                {
                    header |= PRESETDICT;
                }

                header += 31 - (header % 31);

                this.status = BUSYSTATE;
                this.PutShortMSB(header);

                // Save the adler32 of the preset dictionary:
                if (this.strStart != 0)
                {
                    this.PutShortMSB((int)zStream.Adler >> 16);
                    this.PutShortMSB((int)zStream.Adler);
                }

                zStream.Adler = Adler32.SeedValue;
            }

            // Flush as much pending output as possible
            if (this.Pending != 0)
            {
                this.Flush_pending(zStream);
                if (zStream.AvailableOut == 0)
                {
                    // System.out.println("  avail_out==0");
                    // Since avail_out is 0, deflate will be called again with
                    // more output space, but possibly with both pending and
                    // avail_in equal to zero. There won't be anything to do,
                    // but this is not an error situation so make sure we
                    // return OK instead of BUF_ERROR at next call of deflate:
                    this.lastFlush = (FlushMode)(-1);
                    return(CompressionState.ZOK);
                }

                // Make sure there is something to do and avoid duplicate consecutive
                // flushes. For repeated and useless calls with Z_FINISH, we keep
                // returning Z_STREAM_END instead of Z_BUFF_ERROR.
            }
            else if (zStream.AvailableIn == 0 && flush <= old_flush && flush != FlushMode.Finish)
            {
                zStream.Message = ZErrmsg[CompressionState.ZNEEDDICT - CompressionState.ZBUFERROR];
                return(CompressionState.ZBUFERROR);
            }

            // User must not provide more input after the first FINISH:
            if (this.status == FINISHSTATE && zStream.AvailableIn != 0)
            {
                zStream.Message = ZErrmsg[CompressionState.ZNEEDDICT - CompressionState.ZBUFERROR];
                return(CompressionState.ZBUFERROR);
            }

            // Start a new block or continue the current one.
            if (zStream.AvailableIn != 0 ||
                this.lookahead != 0 ||
                (flush != FlushMode.NoFlush && this.status != FINISHSTATE))
            {
                int bstate = -1;

                if (this.Strategy == CompressionStrategy.Rle)
                {
                    bstate = this.DeflateRle(flush);
                }
                else
                {
                    switch (ConfigTable[(int)this.level].Func)
                    {
                    case STORED:
                        bstate = this.DeflateStored(flush);
                        break;

                    case FAST:
                        bstate = this.DeflateFast(flush);
                        break;

                    case SLOW:
                        bstate = this.DeflateSlow(flush);
                        break;

                    case QUICK:
                        bstate = this.DeflateQuick(flush);
                        break;
                    }
                }

                if (bstate == FinishStarted || bstate == FinishDone)
                {
                    this.status = FINISHSTATE;
                }

                if (bstate == NeedMore || bstate == FinishStarted)
                {
                    if (zStream.AvailableOut == 0)
                    {
                        this.lastFlush = (FlushMode)(-1); // avoid BUF_ERROR next call, see above
                    }

                    return(CompressionState.ZOK);

                    // If flush != Z_NO_FLUSH && avail_out == 0, the next call
                    // of deflate should use the same flush parameter to make sure
                    // that the flush is complete. So we don't have to output an
                    // empty block here, this will be done at next call. This also
                    // ensures that for a very small output buffer, we emit at most
                    // one empty block.
                }

                if (bstate == BlockDone)
                {
                    if (flush == FlushMode.PartialFlush)
                    {
                        Trees.Tr_align(this);
                    }
                    else
                    {
                        // FULL_FLUSH or SYNC_FLUSH
                        Trees.Tr_stored_block(this, 0, 0, false);

                        // For a full flush, this empty block will be recognized
                        // as a special marker by inflate_sync().
                        if (flush == FlushMode.FullFlush)
                        {
                            // state.head[s.hash_size-1]=0;
                            ushort *head = this.DynamicBuffers.HeadPointer;
                            for (int i = 0; i < this.hashSize; i++)
                            {
                                // forget history
                                head[i] = 0;
                            }
                        }
                    }

                    this.Flush_pending(zStream);
                    if (zStream.AvailableOut == 0)
                    {
                        this.lastFlush = (FlushMode)(-1); // avoid BUF_ERROR at next call, see above
                        return(CompressionState.ZOK);
                    }
                }
            }

            if (flush != FlushMode.Finish)
            {
                return(CompressionState.ZOK);
            }

            if (this.NoHeader != 0)
            {
                return(CompressionState.ZSTREAMEND);
            }

            // Write the zlib trailer (adler32)
            this.PutShortMSB((int)zStream.Adler >> 16);
            this.PutShortMSB((int)zStream.Adler);
            this.Flush_pending(zStream);

            // If avail_out is zero, the application will call deflate again
            // to flush the rest.
            this.NoHeader = -1; // write the trailer only once!
            return(this.Pending != 0 ? CompressionState.ZOK : CompressionState.ZSTREAMEND);
        }
예제 #2
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Deflate"/> class.
 /// </summary>
 /// <param name="zStream">The zlib stream.</param>
 /// <param name="options">The zlib options.</param>
 /// <param name="windowBits">The window size in bits.</param>
 public Deflate(ZLibStream zStream, ZlibOptions options, int windowBits)
     : this(zStream, options, ZDEFLATED, windowBits, DEFMEMLEVEL)
 {
 }
예제 #3
0
        public Deflate(
            ZLibStream zStream,
            ZlibOptions options,
            int method,
            int windowBits,
            int memLevel)
        {
            int noheader = 0;

            zStream.Message = null;

            CompressionLevel    level    = options.CompressionLevel.GetValueOrDefault();
            CompressionStrategy strategy = options.CompressionStrategy;

            if (level == CompressionLevel.DefaultCompression)
            {
                level = CompressionLevel.Level6;
            }

            if (level == CompressionLevel.NoCompression)
            {
                memLevel = DEFNOCOMPRESSIONMEMLEVEL;
            }

            if (windowBits < 0)
            {
                // undocumented feature: suppress zlib header
                noheader   = 1;
                windowBits = -windowBits;
            }

            if (memLevel < 1 || memLevel > MAXMEMLEVEL)
            {
                ThrowHelper.ThrowArgumentRangeException(nameof(memLevel));
            }

            if (method != ZDEFLATED)
            {
                ThrowHelper.ThrowArgumentRangeException(nameof(method));
            }

            if (windowBits < 9 || windowBits > 15)
            {
                ThrowHelper.ThrowArgumentRangeException(nameof(windowBits));
            }

            if (level < CompressionLevel.NoCompression || level > CompressionLevel.BestCompression)
            {
                ThrowHelper.ThrowArgumentRangeException(nameof(level));
            }

            if (strategy < CompressionStrategy.DefaultStrategy || strategy > CompressionStrategy.Fixed)
            {
                ThrowHelper.ThrowArgumentRangeException(nameof(strategy));
            }

#if USE_QUICK
            if (level == ZlibCompressionLevel.ZBESTSPEED)
            {
                windowBits = 13;
            }
#endif
            this.NoHeader = noheader;
            this.wBits    = windowBits;
            this.wSize    = 1 << this.wBits;
            this.wMask    = this.wSize - 1;

            this.hashBits = memLevel + 7;
            this.hashSize = 1 << this.hashBits;
            this.hashMask = (uint)this.hashSize - 1;

            this.litBufsize = 1 << (memLevel + 6); // 16K elements by default
            this.dBuf       = this.litBufsize;
            this.lBuf       = (1 + 2) * this.litBufsize;

            this.level    = level;
            this.Strategy = strategy;
            this.method   = (byte)method;

            this.FixedBuffers   = new FixedLengthBuffers();
            this.DynamicBuffers = new DynamicLengthBuffers(this.wSize, this.hashSize, this.litBufsize * 4);

            this.DeflateReset(zStream);
        }
예제 #4
0
        internal static CompressionState Inflate_trees_dynamic(int nl, int nd, int[] c, int[] bl, int[] bd, int[] tl, int[] td, int[] hp, ZLibStream z)
        {
            CompressionState r;
            var hn = new int[1];   // hufts used in space
            var v  = new int[288]; // work area for huft_build

            // build literal/length tree
            r = Huft_build(c, 0, nl, 257, Cplens, Cplext, tl, bl, hp, hn, v);
            if (r != CompressionState.ZOK || bl[0] == 0)
            {
                if (r == CompressionState.ZDATAERROR)
                {
                    z.Message = "oversubscribed literal/length tree";
                }
                else if (r != CompressionState.ZMEMERROR)
                {
                    z.Message = "incomplete literal/length tree";
                    r         = CompressionState.ZDATAERROR;
                }

                return(r);
            }

            // build distance tree
            r = Huft_build(c, nl, nd, 0, Cpdist, Cpdext, td, bd, hp, hn, v);

            if (r != CompressionState.ZOK || (bd[0] == 0 && nl > 257))
            {
                if (r == CompressionState.ZDATAERROR)
                {
                    z.Message = "oversubscribed distance tree";
                }
                else if (r == CompressionState.ZBUFERROR)
                {
                    z.Message = "incomplete distance tree";
                    r         = CompressionState.ZDATAERROR;
                }
                else if (r != CompressionState.ZMEMERROR)
                {
                    z.Message = "empty distance tree with lengths";
                    r         = CompressionState.ZDATAERROR;
                }

                return(r);
            }

            return(CompressionState.ZOK);
        }
예제 #5
0
        internal static CompressionState Inflate_trees_bits(int[] c, int[] bb, int[] tb, int[] hp, ZLibStream z)
        {
            CompressionState r;
            var hn = new int[1];  // hufts used in space
            var v  = new int[19]; // work area for huft_build

            r = Huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v);

            if (r == CompressionState.ZDATAERROR)
            {
                z.Message = "oversubscribed dynamic bit lengths tree";
            }
            else if (r == CompressionState.ZBUFERROR || bb[0] == 0)
            {
                z.Message = "incomplete dynamic bit lengths tree";
                r         = CompressionState.ZDATAERROR;
            }

            return(r);
        }
예제 #6
0
 // Returns true if inflate is currently at the end of a block generated
 // by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
 // implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
 // but removes the length bytes of the resulting empty stored block. When
 // decompressing, PPP checks that at the end of input packet, inflate is
 // waiting for these length bytes.
 internal static CompressionState InflateSyncPoint(ZLibStream z)
 => (z == null || z.InflateState == null || z.InflateState.Blocks == null)
     ? CompressionState.ZSTREAMERROR
     : z.InflateState.Blocks.Sync_point();
예제 #7
0
        internal static CompressionState InflateSync(ZLibStream zStream)
        {
            int  n;    // number of bytes to look at
            int  p;    // pointer to bytes
            int  m;    // number of marker bytes found in a row
            long r, w; // temporaries to save total_in and total_out

            // set up
            if (zStream == null || zStream.InflateState == null)
            {
                return(CompressionState.ZSTREAMERROR);
            }

            if (zStream.InflateState.Mode != BAD)
            {
                zStream.InflateState.Mode   = BAD;
                zStream.InflateState.Marker = 0;
            }

            if ((n = zStream.AvailableIn) == 0)
            {
                return(CompressionState.ZBUFERROR);
            }

            p = zStream.NextInIndex;
            m = zStream.InflateState.Marker;

            // search
            while (n != 0 && m < 4)
            {
                if (zStream.NextIn[p] == Mark[m])
                {
                    m++;
                }
                else
                {
                    m = zStream.NextIn[p] != 0 ? 0 : 4 - m;
                }

                p++;
                n--;
            }

            // restore
            zStream.TotalIn            += p - zStream.NextInIndex;
            zStream.NextInIndex         = p;
            zStream.AvailableIn         = n;
            zStream.InflateState.Marker = m;

            // return no joy or set up to restart on a new block
            if (m != 4)
            {
                return(CompressionState.ZDATAERROR);
            }

            r = zStream.TotalIn;
            w = zStream.TotalOut;
            InflateReset(zStream, zStream.InflateState);
            zStream.TotalIn           = r;
            zStream.TotalOut          = w;
            zStream.InflateState.Mode = BLOCKS;
            return(CompressionState.ZOK);
        }
예제 #8
0
        internal static CompressionState Decompress(ZLibStream zStream, FlushMode strategy)
        {
            CompressionState state;
            int b;

            if (zStream == null || zStream.InflateState == null || zStream.NextIn == null)
            {
                return(CompressionState.ZSTREAMERROR);
            }

            // f = f == ZlibFlushStrategy.ZFINISH ? ZlibCompressionState.ZBUFERROR : ZlibCompressionState.ZOK;
            state = CompressionState.ZBUFERROR;
            while (true)
            {
                // System.out.println("mode: "+z.istate.mode);
                switch (zStream.InflateState.Mode)
                {
                case METHOD:

                    if (zStream.AvailableIn == 0)
                    {
                        return(state);
                    }

                    state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK;

                    zStream.AvailableIn--;
                    zStream.TotalIn++;
                    if (((zStream.InflateState.Method = zStream.NextIn[zStream.NextInIndex++]) & 0xf) != ZDEFLATED)
                    {
                        zStream.InflateState.Mode   = BAD;
                        zStream.Message             = "unknown compression method";
                        zStream.InflateState.Marker = 5;     // can't try inflateSync
                        break;
                    }

                    if ((zStream.InflateState.Method >> 4) + 8 > zStream.InflateState.WindowBits)
                    {
                        zStream.InflateState.Mode   = BAD;
                        zStream.Message             = "invalid window size";
                        zStream.InflateState.Marker = 5;     // can't try inflateSync
                        break;
                    }

                    zStream.InflateState.Mode = FLAG;
                    goto case FLAG;

                case FLAG:

                    if (zStream.AvailableIn == 0)
                    {
                        return(state);
                    }

                    state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK;

                    zStream.AvailableIn--;
                    zStream.TotalIn++;
                    b = zStream.NextIn[zStream.NextInIndex++] & 0xff;

                    if ((((zStream.InflateState.Method << 8) + b) % 31) != 0)
                    {
                        zStream.InflateState.Mode   = BAD;
                        zStream.Message             = "incorrect header check";
                        zStream.InflateState.Marker = 5;     // can't try inflateSync
                        break;
                    }

                    if ((b & PRESETDICT) == 0)
                    {
                        zStream.InflateState.Mode = BLOCKS;
                        break;
                    }

                    zStream.InflateState.Mode = DICT4;
                    goto case DICT4;

                case DICT4:

                    if (zStream.AvailableIn == 0)
                    {
                        return(state);
                    }

                    state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK;

                    zStream.AvailableIn--;
                    zStream.TotalIn++;
                    zStream.InflateState.Need = ((zStream.NextIn[zStream.NextInIndex++] & 0xff) << 24) & unchecked ((int)0xff000000L);
                    zStream.InflateState.Mode = DICT3;
                    goto case DICT3;

                case DICT3:

                    if (zStream.AvailableIn == 0)
                    {
                        return(state);
                    }

                    state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK;

                    zStream.AvailableIn--;
                    zStream.TotalIn++;
                    zStream.InflateState.Need += ((zStream.NextIn[zStream.NextInIndex++] & 0xff) << 16) & 0xff0000L;
                    zStream.InflateState.Mode  = DICT2;
                    goto case DICT2;

                case DICT2:

                    if (zStream.AvailableIn == 0)
                    {
                        return(state);
                    }

                    state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK;

                    zStream.AvailableIn--;
                    zStream.TotalIn++;
                    zStream.InflateState.Need += ((zStream.NextIn[zStream.NextInIndex++] & 0xff) << 8) & 0xff00L;
                    zStream.InflateState.Mode  = DICT1;
                    goto case DICT1;

                case DICT1:

                    if (zStream.AvailableIn == 0)
                    {
                        return(state);
                    }

                    state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK;

                    zStream.AvailableIn--;
                    zStream.TotalIn++;
                    zStream.InflateState.Need += zStream.NextIn[zStream.NextInIndex++] & 0xffL;
                    zStream.Adler              = (uint)zStream.InflateState.Need;
                    zStream.InflateState.Mode  = DICT0;
                    return(CompressionState.ZNEEDDICT);

                case DICT0:
                    zStream.InflateState.Mode   = BAD;
                    zStream.Message             = "need dictionary";
                    zStream.InflateState.Marker = 0;     // can try inflateSync
                    return(CompressionState.ZSTREAMERROR);

                case BLOCKS:

                    state = zStream.InflateState.Blocks.Process(zStream, state);
                    if (state == CompressionState.ZDATAERROR)
                    {
                        zStream.InflateState.Mode   = BAD;
                        zStream.InflateState.Marker = 0;     // can try inflateSync
                        break;
                    }

                    if (state == CompressionState.ZOK)
                    {
                        state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK;
                    }

                    if (state != CompressionState.ZSTREAMEND)
                    {
                        return(state);
                    }

                    state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK;
                    zStream.InflateState.Blocks.Reset(zStream, zStream.InflateState.Was);
                    if (zStream.InflateState.NoWrap)
                    {
                        zStream.InflateState.Mode = DONE;
                        break;
                    }

                    zStream.InflateState.Mode = CHECK4;
                    goto case CHECK4;

                case CHECK4:

                    if (zStream.AvailableIn == 0)
                    {
                        return(state);
                    }

                    state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK;

                    zStream.AvailableIn--;
                    zStream.TotalIn++;
                    zStream.InflateState.Need = ((zStream.NextIn[zStream.NextInIndex++] & 0xff) << 24) & unchecked ((int)0xff000000L);
                    zStream.InflateState.Mode = CHECK3;
                    goto case CHECK3;

                case CHECK3:

                    if (zStream.AvailableIn == 0)
                    {
                        return(state);
                    }

                    state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK;

                    zStream.AvailableIn--;
                    zStream.TotalIn++;
                    zStream.InflateState.Need += ((zStream.NextIn[zStream.NextInIndex++] & 0xff) << 16) & 0xff0000L;
                    zStream.InflateState.Mode  = CHECK2;
                    goto case CHECK2;

                case CHECK2:

                    if (zStream.AvailableIn == 0)
                    {
                        return(state);
                    }

                    state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK;

                    zStream.AvailableIn--;
                    zStream.TotalIn++;
                    zStream.InflateState.Need += ((zStream.NextIn[zStream.NextInIndex++] & 0xff) << 8) & 0xff00L;
                    zStream.InflateState.Mode  = CHECK1;
                    goto case CHECK1;

                case CHECK1:

                    if (zStream.AvailableIn == 0)
                    {
                        return(state);
                    }

                    state = strategy == FlushMode.Finish ? CompressionState.ZBUFERROR : CompressionState.ZOK;

                    zStream.AvailableIn--;
                    zStream.TotalIn++;
                    zStream.InflateState.Need += zStream.NextIn[zStream.NextInIndex++] & 0xffL;

                    if (((int)zStream.InflateState.Was[0]) != ((int)zStream.InflateState.Need))
                    {
                        zStream.InflateState.Mode   = BAD;
                        zStream.Message             = "incorrect data check";
                        zStream.InflateState.Marker = 5;     // can't try inflateSync
                        break;
                    }

                    zStream.InflateState.Mode = DONE;
                    goto case DONE;

                case DONE:
                    return(CompressionState.ZSTREAMEND);

                case BAD:
                    return(CompressionState.ZDATAERROR);

                default:
                    return(CompressionState.ZSTREAMERROR);
                }
            }
        }