1 | /*
|
---|
2 | * LZMADecoder
|
---|
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 java.io.IOException;
|
---|
14 | import org.tukaani.xz.lz.LZDecoder;
|
---|
15 | import org.tukaani.xz.rangecoder.RangeDecoder;
|
---|
16 |
|
---|
17 | public final class LZMADecoder extends LZMACoder {
|
---|
18 | private final LZDecoder lz;
|
---|
19 | private final RangeDecoder rc;
|
---|
20 | private final LiteralDecoder literalDecoder;
|
---|
21 | private final LengthDecoder matchLenDecoder = new LengthDecoder();
|
---|
22 | private final LengthDecoder repLenDecoder = new LengthDecoder();
|
---|
23 |
|
---|
24 | public LZMADecoder(LZDecoder lz, RangeDecoder rc, int lc, int lp, int pb) {
|
---|
25 | super(pb);
|
---|
26 | this.lz = lz;
|
---|
27 | this.rc = rc;
|
---|
28 | this.literalDecoder = new LiteralDecoder(lc, lp);
|
---|
29 | reset();
|
---|
30 | }
|
---|
31 |
|
---|
32 | public void reset() {
|
---|
33 | super.reset();
|
---|
34 | literalDecoder.reset();
|
---|
35 | matchLenDecoder.reset();
|
---|
36 | repLenDecoder.reset();
|
---|
37 | }
|
---|
38 |
|
---|
39 | /**
|
---|
40 | * Returns true if LZMA end marker was detected. It is encoded as
|
---|
41 | * the maximum match distance which with signed ints becomes -1. This
|
---|
42 | * function is needed only for LZMA1. LZMA2 doesn't use the end marker
|
---|
43 | * in the LZMA layer.
|
---|
44 | */
|
---|
45 | public boolean endMarkerDetected() {
|
---|
46 | return reps[0] == -1;
|
---|
47 | }
|
---|
48 |
|
---|
49 | public void decode() throws IOException {
|
---|
50 | lz.repeatPending();
|
---|
51 |
|
---|
52 | while (lz.hasSpace()) {
|
---|
53 | int posState = lz.getPos() & posMask;
|
---|
54 |
|
---|
55 | if (rc.decodeBit(isMatch[state.get()], posState) == 0) {
|
---|
56 | literalDecoder.decode();
|
---|
57 | } else {
|
---|
58 | int len = rc.decodeBit(isRep, state.get()) == 0
|
---|
59 | ? decodeMatch(posState)
|
---|
60 | : decodeRepMatch(posState);
|
---|
61 |
|
---|
62 | // NOTE: With LZMA1 streams that have the end marker,
|
---|
63 | // this will throw CorruptedInputException. LZMAInputStream
|
---|
64 | // handles it specially.
|
---|
65 | lz.repeat(reps[0], len);
|
---|
66 | }
|
---|
67 | }
|
---|
68 |
|
---|
69 | rc.normalize();
|
---|
70 | }
|
---|
71 |
|
---|
72 | private int decodeMatch(int posState) throws IOException {
|
---|
73 | state.updateMatch();
|
---|
74 |
|
---|
75 | reps[3] = reps[2];
|
---|
76 | reps[2] = reps[1];
|
---|
77 | reps[1] = reps[0];
|
---|
78 |
|
---|
79 | int len = matchLenDecoder.decode(posState);
|
---|
80 | int distSlot = rc.decodeBitTree(distSlots[getDistState(len)]);
|
---|
81 |
|
---|
82 | if (distSlot < DIST_MODEL_START) {
|
---|
83 | reps[0] = distSlot;
|
---|
84 | } else {
|
---|
85 | int limit = (distSlot >> 1) - 1;
|
---|
86 | reps[0] = (2 | (distSlot & 1)) << limit;
|
---|
87 |
|
---|
88 | if (distSlot < DIST_MODEL_END) {
|
---|
89 | reps[0] |= rc.decodeReverseBitTree(
|
---|
90 | distSpecial[distSlot - DIST_MODEL_START]);
|
---|
91 | } else {
|
---|
92 | reps[0] |= rc.decodeDirectBits(limit - ALIGN_BITS)
|
---|
93 | << ALIGN_BITS;
|
---|
94 | reps[0] |= rc.decodeReverseBitTree(distAlign);
|
---|
95 | }
|
---|
96 | }
|
---|
97 |
|
---|
98 | return len;
|
---|
99 | }
|
---|
100 |
|
---|
101 | private int decodeRepMatch(int posState) throws IOException {
|
---|
102 | if (rc.decodeBit(isRep0, state.get()) == 0) {
|
---|
103 | if (rc.decodeBit(isRep0Long[state.get()], posState) == 0) {
|
---|
104 | state.updateShortRep();
|
---|
105 | return 1;
|
---|
106 | }
|
---|
107 | } else {
|
---|
108 | int tmp;
|
---|
109 |
|
---|
110 | if (rc.decodeBit(isRep1, state.get()) == 0) {
|
---|
111 | tmp = reps[1];
|
---|
112 | } else {
|
---|
113 | if (rc.decodeBit(isRep2, state.get()) == 0) {
|
---|
114 | tmp = reps[2];
|
---|
115 | } else {
|
---|
116 | tmp = reps[3];
|
---|
117 | reps[3] = reps[2];
|
---|
118 | }
|
---|
119 |
|
---|
120 | reps[2] = reps[1];
|
---|
121 | }
|
---|
122 |
|
---|
123 | reps[1] = reps[0];
|
---|
124 | reps[0] = tmp;
|
---|
125 | }
|
---|
126 |
|
---|
127 | state.updateLongRep();
|
---|
128 |
|
---|
129 | return repLenDecoder.decode(posState);
|
---|
130 | }
|
---|
131 |
|
---|
132 |
|
---|
133 | private class LiteralDecoder extends LiteralCoder {
|
---|
134 | private final LiteralSubdecoder[] subdecoders;
|
---|
135 |
|
---|
136 | LiteralDecoder(int lc, int lp) {
|
---|
137 | super(lc, lp);
|
---|
138 |
|
---|
139 | subdecoders = new LiteralSubdecoder[1 << (lc + lp)];
|
---|
140 | for (int i = 0; i < subdecoders.length; ++i)
|
---|
141 | subdecoders[i] = new LiteralSubdecoder();
|
---|
142 | }
|
---|
143 |
|
---|
144 | void reset() {
|
---|
145 | for (int i = 0; i < subdecoders.length; ++i)
|
---|
146 | subdecoders[i].reset();
|
---|
147 | }
|
---|
148 |
|
---|
149 | void decode() throws IOException {
|
---|
150 | int i = getSubcoderIndex(lz.getByte(0), lz.getPos());
|
---|
151 | subdecoders[i].decode();
|
---|
152 | }
|
---|
153 |
|
---|
154 |
|
---|
155 | private class LiteralSubdecoder extends LiteralSubcoder {
|
---|
156 | void decode() throws IOException {
|
---|
157 | int symbol = 1;
|
---|
158 |
|
---|
159 | if (state.isLiteral()) {
|
---|
160 | do {
|
---|
161 | symbol = (symbol << 1) | rc.decodeBit(probs, symbol);
|
---|
162 | } while (symbol < 0x100);
|
---|
163 |
|
---|
164 | } else {
|
---|
165 | int matchByte = lz.getByte(reps[0]);
|
---|
166 | int offset = 0x100;
|
---|
167 | int matchBit;
|
---|
168 | int bit;
|
---|
169 |
|
---|
170 | do {
|
---|
171 | matchByte <<= 1;
|
---|
172 | matchBit = matchByte & offset;
|
---|
173 | bit = rc.decodeBit(probs, offset + matchBit + symbol);
|
---|
174 | symbol = (symbol << 1) | bit;
|
---|
175 | offset &= (0 - bit) ^ ~matchBit;
|
---|
176 | } while (symbol < 0x100);
|
---|
177 | }
|
---|
178 |
|
---|
179 | lz.putByte((byte)symbol);
|
---|
180 | state.updateLiteral();
|
---|
181 | }
|
---|
182 | }
|
---|
183 | }
|
---|
184 |
|
---|
185 |
|
---|
186 | private class LengthDecoder extends LengthCoder {
|
---|
187 | int decode(int posState) throws IOException {
|
---|
188 | if (rc.decodeBit(choice, 0) == 0)
|
---|
189 | return rc.decodeBitTree(low[posState]) + MATCH_LEN_MIN;
|
---|
190 |
|
---|
191 | if (rc.decodeBit(choice, 1) == 0)
|
---|
192 | return rc.decodeBitTree(mid[posState])
|
---|
193 | + MATCH_LEN_MIN + LOW_SYMBOLS;
|
---|
194 |
|
---|
195 | return rc.decodeBitTree(high)
|
---|
196 | + MATCH_LEN_MIN + LOW_SYMBOLS + MID_SYMBOLS;
|
---|
197 | }
|
---|
198 | }
|
---|
199 | }
|
---|