Пример #1
0
        static void FollowPath(ZopfliBlockState s,
                               byte[] InFile, int instart, int inend,
                               List <ushort> path, ulong pathsize,
                               ZopfliLZ77Store store, ZopfliHash h)
        {
            int i, j, pos;
            int windowstart = instart > ZopfliHash.ZOPFLI_WINDOW_SIZE
                ? instart - ZopfliHash.ZOPFLI_WINDOW_SIZE : 0;

            ulong total_length_test = 0;

            if (instart == inend)
            {
                return;
            }

            h.ZopfliResetHash();
            h.ZopfliWarmupHash(InFile, windowstart, inend);
            for (i = windowstart; i < instart; i++)
            {
                h.ZopfliUpdateHash(InFile, i, inend);
            }

            pos = instart;
            for (i = 0; i < (int)pathsize; i++)
            {
                ushort length       = path[i];
                ushort dummy_length = 0;
                ushort dist         = 0;
                Debug.Assert(pos < inend);

                h.ZopfliUpdateHash(InFile, pos, inend);

                /* Add to output. */
                if (length >= ZOPFLI_MIN_MATCH)
                {
                    /* Get the distance by recalculating longest match. The found length
                     * should match the length from the path. */
                    ZopfliFindLongestMatch(s, h, InFile, pos, inend, length, null,
                                           ref dist, ref dummy_length);
                    Debug.Assert(!(dummy_length != length && length > 2 && dummy_length > 2));
                    ZopfliVerifyLenDist(InFile, inend, pos, dist, length);
                    ZopfliStoreLitLenDist(length, dist, pos, store);
                    total_length_test += length;
                }
                else
                {
                    length = 1;
                    ZopfliStoreLitLenDist(InFile[pos], 0, pos, store);
                    total_length_test++;
                }


                Debug.Assert(pos + length <= inend);
                for (j = 1; j < length; j++)
                {
                    h.ZopfliUpdateHash(InFile, pos + j, inend);
                }

                pos += length;
            }
        }
Пример #2
0
        /*
         * Performs the forward pass for "squeeze". Gets the most optimal length to reach
         * every byte from a previous byte, using cost calculations.
         * s: the ZopfliBlockState
         * in: the input data array
         * instart: where to start
         * inend: where to stop (not inclusive)
         * costmodel: function to calculate the cost of some lit/len/dist pair.
         * costcontext: abstract context for the costmodel function
         * length_array: output array of size (inend - instart) which will receive the best
         *  length to reach this byte from a previous byte.
         * returns the cost that was, according to the costmodel, needed to get to the end.
         */
        static double GetBestLengths(ZopfliBlockState s,
                                     byte[] InFile,
                                     int instart, int inend,
                                     SymbolStats stats,
                                     ushort[] length_array,
                                     ZopfliHash h, float[] costs, bool fixedcosts)
        {
            /* Best cost to get here so far. */
            ulong  blocksize = (ulong)(inend - instart);
            ulong  i, k, kend;
            ushort leng = 0; //bogus value
            ushort dist = 0; //bogusvalue

            ushort[] sublen      = new ushort[259];
            ulong    windowstart = (ulong)(instart > ZopfliHash.ZOPFLI_WINDOW_SIZE
                ? instart - ZopfliHash.ZOPFLI_WINDOW_SIZE : 0);
            double result;
            double mincost = GetCostModelMinCost(stats);
            double mincostaddcostj;

            if (instart == inend)
            {
                return(0);
            }

            h.ZopfliResetHash();
            h.ZopfliWarmupHash(InFile, (int)windowstart, inend);
            for (i = windowstart; i < (ulong)instart; i++)
            {
                h.ZopfliUpdateHash(InFile, (int)i, inend);
            }

            Array.Fill(costs, (float)Compress.ZOPFLI_LARGE_FLOAT);
            costs[0]        = 0; /* Because it's the start. */
            length_array[0] = 0;

            for (i = (ulong)instart; i < (ulong)inend; i++)
            {
                ulong j = i - (ulong)instart;  /* Index in the costs array and length_array. */
                h.ZopfliUpdateHash(InFile, (int)i, inend);

                /* If we're in a long repetition of the same character and have more than
                 * ZOPFLI_MAX_MATCH characters before and after our position. */
                if (h.same[i & ZopfliHash.ZOPFLI_WINDOW_MASK] > ZOPFLI_MAX_MATCH * 2 &&
                    (int)i > instart + ZOPFLI_MAX_MATCH + 1 &&
                    i + ZOPFLI_MAX_MATCH * 2 + 1 < (ulong)inend &&
                    h.same[(i - ZOPFLI_MAX_MATCH) & ZopfliHash.ZOPFLI_WINDOW_MASK]
                    > ZOPFLI_MAX_MATCH)
                {
                    double symbolcost;

                    if (fixedcosts)
                    {
                        symbolcost = GetCostFixed(ZOPFLI_MAX_MATCH, 1);
                    }
                    else
                    {
                        symbolcost = GetCostStat(ZOPFLI_MAX_MATCH, 1, stats);
                    }

                    /* Set the length to reach each one to ZOPFLI_MAX_MATCH, and the cost to
                     * the cost corresponding to that length. Doing this, we skip
                     * ZOPFLI_MAX_MATCH values to avoid calling ZopfliFindLongestMatch. */
                    for (k = 0; k < ZOPFLI_MAX_MATCH; k++)
                    {
                        costs[j + ZOPFLI_MAX_MATCH]        = costs[j] + (float)symbolcost;
                        length_array[j + ZOPFLI_MAX_MATCH] = ZOPFLI_MAX_MATCH;
                        i++;
                        j++;
                        h.ZopfliUpdateHash(InFile, (int)i, inend);
                    }
                }

                ZopfliFindLongestMatch(s, h, InFile, (int)i, inend, ZOPFLI_MAX_MATCH, sublen,
                                       ref dist, ref leng);

                /* Literal. */
                if (i + 1 <= (ulong)inend)
                {
                    double newCost;
                    if (fixedcosts)
                    {
                        newCost = GetCostFixed(InFile[i], 0) + costs[j];
                    }
                    else
                    {
                        newCost = GetCostStat(InFile[i], 0, stats) + costs[j];
                    }
                    Debug.Assert(newCost >= 0);
                    if (newCost < costs[j + 1])
                    {
                        costs[j + 1]        = (float)newCost;
                        length_array[j + 1] = 1;
                    }
                }
                /* Lengths. */
                kend            = zopfli_min(leng, (ulong)inend - i);
                mincostaddcostj = mincost + costs[j];
                for (k = 3; k <= kend; k++)
                {
                    double newCost;

                    /* Calling the cost model is expensive, avoid this if we are already at
                     * the minimum possible cost that it can return. */
                    if (costs[j + k] <= mincostaddcostj)
                    {
                        continue;
                    }

                    if (fixedcosts)
                    {
                        newCost = GetCostFixed((int)k, sublen[k]) + costs[j];
                    }
                    else
                    {
                        newCost = GetCostStat((int)k, sublen[k], stats) + costs[j];
                    }
                    Debug.Assert(newCost >= 0);
                    if (newCost < costs[j + k])
                    {
                        Debug.Assert(k <= ZOPFLI_MAX_MATCH);
                        costs[j + k]        = (float)newCost;
                        length_array[j + k] = (ushort)k;
                    }
                }
            }

            Debug.Assert(costs[blocksize] >= 0);
            result = costs[blocksize];

            return(result);
        }