Beispiel #1
0
        // Decode PKWare Compression Library stream.
        public static byte[] Decompress(byte[] src)
        {
            var br = new BitReader(src);

            // Are literals coded?
            var coded = br.ReadBits(8);

            if (coded < 0 || coded > 1)
            {
                throw new NotImplementedException("Invalid data stream");
            }
            var encodedLiterals = coded == 1;

            // log2(dictionary size) - 6
            var dict = br.ReadBits(8);

            if (dict < 4 || dict > 6)
            {
                throw new InvalidDataException("Invalid dictionary size");
            }

            // output state
            ushort next      = 0;                // index of next write location in out[]
            var    first     = true;             // true to check distances (for first 4K)
            var    outBuffer = new byte[MAXWIN]; // output buffer and sliding window
            var    ms        = new MemoryStream();

            // decode literals and length/distance pairs
            do
            {
                // length/distance pair
                if (br.ReadBits(1) == 1)
                {
                    // Length
                    var symbol = Decode(lencode, br);
                    var len    = lengthbase[symbol] + br.ReadBits(extra[symbol]);

                    // Magic number for "done"
                    if (len == 519)
                    {
                        for (var i = 0; i < next; i++)
                        {
                            ms.WriteByte(outBuffer[i]);
                        }
                        break;
                    }

                    // Distance
                    symbol = len == 2 ? 2 : dict;
                    var dist = Decode(distcode, br) << symbol;
                    dist += br.ReadBits(symbol);
                    dist++;

                    if (first && dist > next)
                    {
                        throw new InvalidDataException("Attempt to jump before data");
                    }

                    // copy length bytes from distance bytes back
                    do
                    {
                        var dest   = next;
                        var source = dest - dist;

                        var copy = MAXWIN;
                        if (next < dist)
                        {
                            source += copy;
                            copy    = dist;
                        }

                        copy -= next;
                        if (copy > len)
                        {
                            copy = len;
                        }

                        len  -= copy;
                        next += (ushort)copy;

                        // copy with old-fashioned memcpy semantics
                        // in case of overlapping ranges. this is NOT
                        // the same as Array.Copy()
                        while (copy-- > 0)
                        {
                            outBuffer[dest++] = outBuffer[source++];
                        }

                        // Flush window to outstream
                        if (next == MAXWIN)
                        {
                            for (var i = 0; i < next; i++)
                            {
                                ms.WriteByte(outBuffer[i]);
                            }
                            next  = 0;
                            first = false;
                        }
                    } while (len != 0);
                }
                else
                {
                    // literal value
                    var symbol = encodedLiterals ? Decode(litcode, br) : br.ReadBits(8);
                    outBuffer[next++] = (byte)symbol;
                    if (next == MAXWIN)
                    {
                        for (var i = 0; i < next; i++)
                        {
                            ms.WriteByte(outBuffer[i]);
                        }
                        next  = 0;
                        first = false;
                    }
                }
            } while (true);

            return(ms.ToArray());
        }