1 | /*
|
---|
2 | * LZMAEncoderFast
|
---|
3 | *
|
---|
4 | * Authors: Lasse Collin <lasse.collin@tukaani.org>
|
---|
5 | * Igor Pavlov <http://7-zip.org/>
|
---|
6 | *
|
---|
7 | * This file has been put into the public domain.
|
---|
8 | * You can do whatever you want with this file.
|
---|
9 | */
|
---|
10 |
|
---|
11 | package org.tukaani.xz.lzma;
|
---|
12 |
|
---|
13 | import org.tukaani.xz.ArrayCache;
|
---|
14 | import org.tukaani.xz.lz.LZEncoder;
|
---|
15 | import org.tukaani.xz.lz.Matches;
|
---|
16 | import org.tukaani.xz.rangecoder.RangeEncoder;
|
---|
17 |
|
---|
18 | final class LZMAEncoderFast extends LZMAEncoder {
|
---|
19 | private static final int EXTRA_SIZE_BEFORE = 1;
|
---|
20 | private static final int EXTRA_SIZE_AFTER = MATCH_LEN_MAX - 1;
|
---|
21 |
|
---|
22 | private Matches matches = null;
|
---|
23 |
|
---|
24 | static int getMemoryUsage(int dictSize, int extraSizeBefore, int mf) {
|
---|
25 | return LZEncoder.getMemoryUsage(
|
---|
26 | dictSize, Math.max(extraSizeBefore, EXTRA_SIZE_BEFORE),
|
---|
27 | EXTRA_SIZE_AFTER, MATCH_LEN_MAX, mf);
|
---|
28 | }
|
---|
29 |
|
---|
30 | LZMAEncoderFast(RangeEncoder rc, int lc, int lp, int pb,
|
---|
31 | int dictSize, int extraSizeBefore,
|
---|
32 | int niceLen, int mf, int depthLimit,
|
---|
33 | ArrayCache arrayCache) {
|
---|
34 | super(rc, LZEncoder.getInstance(dictSize,
|
---|
35 | Math.max(extraSizeBefore,
|
---|
36 | EXTRA_SIZE_BEFORE),
|
---|
37 | EXTRA_SIZE_AFTER,
|
---|
38 | niceLen, MATCH_LEN_MAX,
|
---|
39 | mf, depthLimit, arrayCache),
|
---|
40 | lc, lp, pb, dictSize, niceLen);
|
---|
41 | }
|
---|
42 |
|
---|
43 | private boolean changePair(int smallDist, int bigDist) {
|
---|
44 | return smallDist < (bigDist >>> 7);
|
---|
45 | }
|
---|
46 |
|
---|
47 | int getNextSymbol() {
|
---|
48 | // Get the matches for the next byte unless readAhead indicates
|
---|
49 | // that we already got the new matches during the previous call
|
---|
50 | // to this function.
|
---|
51 | if (readAhead == -1)
|
---|
52 | matches = getMatches();
|
---|
53 |
|
---|
54 | back = -1;
|
---|
55 |
|
---|
56 | // Get the number of bytes available in the dictionary, but
|
---|
57 | // not more than the maximum match length. If there aren't
|
---|
58 | // enough bytes remaining to encode a match at all, return
|
---|
59 | // immediately to encode this byte as a literal.
|
---|
60 | int avail = Math.min(lz.getAvail(), MATCH_LEN_MAX);
|
---|
61 | if (avail < MATCH_LEN_MIN)
|
---|
62 | return 1;
|
---|
63 |
|
---|
64 | // Look for a match from the previous four match distances.
|
---|
65 | int bestRepLen = 0;
|
---|
66 | int bestRepIndex = 0;
|
---|
67 | for (int rep = 0; rep < REPS; ++rep) {
|
---|
68 | int len = lz.getMatchLen(reps[rep], avail);
|
---|
69 | if (len < MATCH_LEN_MIN)
|
---|
70 | continue;
|
---|
71 |
|
---|
72 | // If it is long enough, return it.
|
---|
73 | if (len >= niceLen) {
|
---|
74 | back = rep;
|
---|
75 | skip(len - 1);
|
---|
76 | return len;
|
---|
77 | }
|
---|
78 |
|
---|
79 | // Remember the index and length of the best repeated match.
|
---|
80 | if (len > bestRepLen) {
|
---|
81 | bestRepIndex = rep;
|
---|
82 | bestRepLen = len;
|
---|
83 | }
|
---|
84 | }
|
---|
85 |
|
---|
86 | int mainLen = 0;
|
---|
87 | int mainDist = 0;
|
---|
88 |
|
---|
89 | if (matches.count > 0) {
|
---|
90 | mainLen = matches.len[matches.count - 1];
|
---|
91 | mainDist = matches.dist[matches.count - 1];
|
---|
92 |
|
---|
93 | if (mainLen >= niceLen) {
|
---|
94 | back = mainDist + REPS;
|
---|
95 | skip(mainLen - 1);
|
---|
96 | return mainLen;
|
---|
97 | }
|
---|
98 |
|
---|
99 | while (matches.count > 1
|
---|
100 | && mainLen == matches.len[matches.count - 2] + 1) {
|
---|
101 | if (!changePair(matches.dist[matches.count - 2], mainDist))
|
---|
102 | break;
|
---|
103 |
|
---|
104 | --matches.count;
|
---|
105 | mainLen = matches.len[matches.count - 1];
|
---|
106 | mainDist = matches.dist[matches.count - 1];
|
---|
107 | }
|
---|
108 |
|
---|
109 | if (mainLen == MATCH_LEN_MIN && mainDist >= 0x80)
|
---|
110 | mainLen = 1;
|
---|
111 | }
|
---|
112 |
|
---|
113 | if (bestRepLen >= MATCH_LEN_MIN) {
|
---|
114 | if (bestRepLen + 1 >= mainLen
|
---|
115 | || (bestRepLen + 2 >= mainLen && mainDist >= (1 << 9))
|
---|
116 | || (bestRepLen + 3 >= mainLen && mainDist >= (1 << 15))) {
|
---|
117 | back = bestRepIndex;
|
---|
118 | skip(bestRepLen - 1);
|
---|
119 | return bestRepLen;
|
---|
120 | }
|
---|
121 | }
|
---|
122 |
|
---|
123 | if (mainLen < MATCH_LEN_MIN || avail <= MATCH_LEN_MIN)
|
---|
124 | return 1;
|
---|
125 |
|
---|
126 | // Get the next match. Test if it is better than the current match.
|
---|
127 | // If so, encode the current byte as a literal.
|
---|
128 | matches = getMatches();
|
---|
129 |
|
---|
130 | if (matches.count > 0) {
|
---|
131 | int newLen = matches.len[matches.count - 1];
|
---|
132 | int newDist = matches.dist[matches.count - 1];
|
---|
133 |
|
---|
134 | if ((newLen >= mainLen && newDist < mainDist)
|
---|
135 | || (newLen == mainLen + 1
|
---|
136 | && !changePair(mainDist, newDist))
|
---|
137 | || newLen > mainLen + 1
|
---|
138 | || (newLen + 1 >= mainLen
|
---|
139 | && mainLen >= MATCH_LEN_MIN + 1
|
---|
140 | && changePair(newDist, mainDist)))
|
---|
141 | return 1;
|
---|
142 | }
|
---|
143 |
|
---|
144 | int limit = Math.max(mainLen - 1, MATCH_LEN_MIN);
|
---|
145 | for (int rep = 0; rep < REPS; ++rep)
|
---|
146 | if (lz.getMatchLen(reps[rep], limit) == limit)
|
---|
147 | return 1;
|
---|
148 |
|
---|
149 | back = mainDist + REPS;
|
---|
150 | skip(mainLen - 2);
|
---|
151 | return mainLen;
|
---|
152 | }
|
---|
153 | }
|
---|