source: josm/trunk/src/org/tukaani/xz/lzma/LZMAEncoderFast.java@ 15147

Last change on this file since 15147 was 13350, checked in by stoecker, 7 years ago

see #15816 - add XZ support

File size: 5.2 KB
Line 
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
11package org.tukaani.xz.lzma;
12
13import org.tukaani.xz.ArrayCache;
14import org.tukaani.xz.lz.LZEncoder;
15import org.tukaani.xz.lz.Matches;
16import org.tukaani.xz.rangecoder.RangeEncoder;
17
18final 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}
Note: See TracBrowser for help on using the repository browser.