lzma1 0.1.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -6
- package/lib/decoder.js +468 -0
- package/lib/encoder.js +1473 -0
- package/lib/index.js +16 -10
- package/lib/len-coder.js +171 -0
- package/lib/lit-coder.js +162 -0
- package/lib/lz-window.js +88 -0
- package/lib/lzma.js +65 -2639
- package/lib/match-finder.js +402 -0
- package/lib/range-bit-tree-coder.js +95 -0
- package/lib/range-decoder.js +85 -0
- package/lib/range-encoder.js +119 -0
- package/lib/streams.js +64 -0
- package/lib/utils.js +202 -0
- package/package.json +24 -13
- package/src/decoder.ts +604 -0
- package/src/encoder.ts +2108 -0
- package/src/index.ts +71 -0
- package/src/len-coder.ts +217 -0
- package/src/lit-coder.ts +196 -0
- package/src/lz-window.ts +99 -0
- package/src/lzma.ts +142 -0
- package/src/match-finder.ts +548 -0
- package/src/range-bit-tree-coder.ts +109 -0
- package/src/range-decoder.ts +98 -0
- package/src/range-encoder.ts +136 -0
- package/src/streams.ts +73 -0
- package/src/utils.ts +263 -0
- package/lib/index.d.ts +0 -37
- package/lib/lzma.d.ts +0 -66
package/README.md
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<h1>lzma1</h1>
|
|
4
|
+
|
|
5
|
+
This is a [fork][fork-link] of [Nathan Rugg's][fork-author] LZMA-JS package and
|
|
6
|
+
inspiration of [Java][7zip-sdk] and Googles [Go][go-sdk] implementations.
|
|
7
|
+
|
|
8
|
+
</div>
|
|
4
9
|
|
|
5
10
|
[fork-link]: https://github.com/LZMA-JS/LZMA-JS
|
|
6
11
|
[fork-author]: https://github.com/nmrugg
|
|
12
|
+
[7zip-sdk]: https://www.7-zip.org/sdk.html
|
|
13
|
+
[go-sdk]: https://code.google.com/p/lzma
|
|
7
14
|
|
|
8
15
|
## Why
|
|
9
16
|
|
|
@@ -18,9 +25,9 @@ to read and maintain.
|
|
|
18
25
|
|
|
19
26
|
- Encode and decode LZMA streams
|
|
20
27
|
- Supports both string and Uint8Array data
|
|
21
|
-
- Supports both browser and Node.js environments
|
|
22
|
-
- Pure JavaScript implementation with TypeScript types
|
|
23
28
|
- No dependencies on runtime-specific APIs
|
|
29
|
+
- Pure JavaScript implementation with TypeScript types
|
|
30
|
+
- Isomorphic browser- and runtime-independent implementation
|
|
24
31
|
|
|
25
32
|
## Installation
|
|
26
33
|
|
|
@@ -148,7 +155,14 @@ commonly used in the 7z archive format.
|
|
|
148
155
|
The LZMA compressed data begins with a header that contains information needed
|
|
149
156
|
for decompression:
|
|
150
157
|
|
|
151
|
-
|
|
158
|
+
```mermaid
|
|
159
|
+
packet-beta
|
|
160
|
+
0-7: "lc (literal context)"
|
|
161
|
+
8-11: "lp (literal pos)"
|
|
162
|
+
12-15: "pb (position bits)"
|
|
163
|
+
16-47: "Dictionary Size (32-bit, LE)"
|
|
164
|
+
48-111: "Uncompressed Size (64-bit, LE)"
|
|
165
|
+
```
|
|
152
166
|
|
|
153
167
|
More [information][header_link] about the LZMA header structure.
|
|
154
168
|
|
|
@@ -156,7 +170,6 @@ More [information][header_link] about the LZMA header structure.
|
|
|
156
170
|
|
|
157
171
|
## Related
|
|
158
172
|
|
|
159
|
-
- [7-Zip SDK](https://www.7-zip.org/sdk.html)
|
|
160
173
|
- [lzma-purejs](https://github.com/cscott/lzma-purejs)
|
|
161
174
|
- [lzmajs](https://github.com/glinscott/lzmajs)
|
|
162
175
|
- [lzma-purejs fork](https://github.com/mauron85/lzma-purejs/tree/master)
|
package/lib/decoder.js
ADDED
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
import { LzOutWindow } from "./lz-window.js";
|
|
2
|
+
import { RangeDecoder } from "./range-decoder.js";
|
|
3
|
+
import { _MAX_UINT32, CHOICE_ARRAY_SIZE, createBitTree, DEFAULT_WINDOW_SIZE, getLenToPosState, initArray, initBitModels, LITERAL_DECODER_SIZE, MATCH_DECODERS_SIZE, POS_DECODERS_SIZE, REP_DECODERS_SIZE, stateUpdateChar, } from "./utils.js";
|
|
4
|
+
export class Decoder {
|
|
5
|
+
rangeDecoder;
|
|
6
|
+
outWindow;
|
|
7
|
+
// Decoder state
|
|
8
|
+
state = 0;
|
|
9
|
+
rep0 = 0;
|
|
10
|
+
rep1 = 0;
|
|
11
|
+
rep2 = 0;
|
|
12
|
+
rep3 = 0;
|
|
13
|
+
prevByte = 0;
|
|
14
|
+
nowPos64 = 0n;
|
|
15
|
+
outSize = 0n;
|
|
16
|
+
// Decoder configuration
|
|
17
|
+
posStateMask = 0;
|
|
18
|
+
dictSizeCheck = 0;
|
|
19
|
+
// Probability models for different symbols
|
|
20
|
+
matchDecoders = [];
|
|
21
|
+
rep0LongDecoders = [];
|
|
22
|
+
repDecoders = [];
|
|
23
|
+
repG0Decoders = [];
|
|
24
|
+
repG1Decoders = [];
|
|
25
|
+
repG2Decoders = [];
|
|
26
|
+
posDecoders = [];
|
|
27
|
+
// Complex decoders
|
|
28
|
+
literalDecoder;
|
|
29
|
+
posSlotDecoders = [];
|
|
30
|
+
lenDecoder;
|
|
31
|
+
repLenDecoder;
|
|
32
|
+
posAlignDecoder;
|
|
33
|
+
// Alias for compatibility with LZMA class
|
|
34
|
+
get literalCoder() {
|
|
35
|
+
return this.literalDecoder;
|
|
36
|
+
}
|
|
37
|
+
constructor() {
|
|
38
|
+
// Initialize range decoder
|
|
39
|
+
this.rangeDecoder = new RangeDecoder();
|
|
40
|
+
// Initialize output window using proper LzOutWindow
|
|
41
|
+
this.outWindow = new LzOutWindow(null, DEFAULT_WINDOW_SIZE);
|
|
42
|
+
// Initialize probability models
|
|
43
|
+
this.matchDecoders = initArray(MATCH_DECODERS_SIZE);
|
|
44
|
+
this.rep0LongDecoders = initArray(MATCH_DECODERS_SIZE);
|
|
45
|
+
this.repDecoders = initArray(REP_DECODERS_SIZE);
|
|
46
|
+
this.repG0Decoders = initArray(REP_DECODERS_SIZE);
|
|
47
|
+
this.repG1Decoders = initArray(REP_DECODERS_SIZE);
|
|
48
|
+
this.repG2Decoders = initArray(REP_DECODERS_SIZE);
|
|
49
|
+
this.posDecoders = initArray(POS_DECODERS_SIZE);
|
|
50
|
+
// Initialize literal decoder
|
|
51
|
+
this.literalDecoder = {
|
|
52
|
+
coders: [],
|
|
53
|
+
numPrevBits: 0,
|
|
54
|
+
numPosBits: 0,
|
|
55
|
+
posMask: 0,
|
|
56
|
+
init: () => this.initLiteralDecoder(),
|
|
57
|
+
};
|
|
58
|
+
// Initialize position slot decoders (4 different length-to-position states)
|
|
59
|
+
for (let i = 0; i < 4; i++) {
|
|
60
|
+
this.posSlotDecoders[i] = createBitTree(6);
|
|
61
|
+
}
|
|
62
|
+
// Initialize length decoders
|
|
63
|
+
this.lenDecoder = this.createLenDecoder();
|
|
64
|
+
this.repLenDecoder = this.createLenDecoder();
|
|
65
|
+
// Initialize position alignment decoder
|
|
66
|
+
this.posAlignDecoder = createBitTree(4);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Read LZMA header, configure decoder, and prepare for decompression.
|
|
70
|
+
*/
|
|
71
|
+
initDecompression(input, output) {
|
|
72
|
+
// Read 5-byte header properties
|
|
73
|
+
const properties = [];
|
|
74
|
+
for (let i = 0; i < 5; ++i) {
|
|
75
|
+
const r = input.readByte();
|
|
76
|
+
if (r === -1) {
|
|
77
|
+
throw new Error("truncated input");
|
|
78
|
+
}
|
|
79
|
+
properties[i] = r << 24 >> 24;
|
|
80
|
+
}
|
|
81
|
+
if (!this.setDecoderProperties(properties)) {
|
|
82
|
+
throw new Error("corrupted input");
|
|
83
|
+
}
|
|
84
|
+
// Read 8-byte uncompressed length from header
|
|
85
|
+
let outSize;
|
|
86
|
+
{
|
|
87
|
+
let value = 0n;
|
|
88
|
+
for (let i = 0; i < 8; i++) {
|
|
89
|
+
const r = input.readByte();
|
|
90
|
+
if (r === -1) {
|
|
91
|
+
throw new Error("truncated input");
|
|
92
|
+
}
|
|
93
|
+
value += BigInt(r & 0xFF) << BigInt(i * 8);
|
|
94
|
+
}
|
|
95
|
+
// Check for unknown size marker (all 0xFF bytes)
|
|
96
|
+
if (value === 0xffffffffffffffffn) {
|
|
97
|
+
outSize = -1n;
|
|
98
|
+
}
|
|
99
|
+
else if (value > BigInt(_MAX_UINT32)) {
|
|
100
|
+
outSize = -1n;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
outSize = value;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Set up range decoder and output window
|
|
107
|
+
this.rangeDecoder.setStream(input);
|
|
108
|
+
this.flush();
|
|
109
|
+
this.outWindow.stream = null;
|
|
110
|
+
this.outWindow.stream = output;
|
|
111
|
+
// Initialize decoder state
|
|
112
|
+
this.init();
|
|
113
|
+
this.state = 0;
|
|
114
|
+
this.rep0 = 0;
|
|
115
|
+
this.rep1 = 0;
|
|
116
|
+
this.rep2 = 0;
|
|
117
|
+
this.rep3 = 0;
|
|
118
|
+
this.outSize = outSize;
|
|
119
|
+
this.nowPos64 = 0n;
|
|
120
|
+
this.prevByte = 0;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Full decompression: read header, decode all chunks, flush and cleanup.
|
|
124
|
+
*/
|
|
125
|
+
decompress(input, output) {
|
|
126
|
+
this.initDecompression(input, output);
|
|
127
|
+
while (true) {
|
|
128
|
+
const result = this.codeOneChunk();
|
|
129
|
+
if (result === -1) {
|
|
130
|
+
throw new Error("corrupted input");
|
|
131
|
+
}
|
|
132
|
+
const isOutputComplete = (this.outSize >= 0n)
|
|
133
|
+
&& (this.nowPos64 >= this.outSize);
|
|
134
|
+
if (result || isOutputComplete) {
|
|
135
|
+
this.flush();
|
|
136
|
+
this.cleanup();
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
createLenDecoder() {
|
|
142
|
+
const decoder = {
|
|
143
|
+
choice: initArray(CHOICE_ARRAY_SIZE),
|
|
144
|
+
lowCoder: [],
|
|
145
|
+
midCoder: [],
|
|
146
|
+
highCoder: createBitTree(0x08),
|
|
147
|
+
numPosStates: 0,
|
|
148
|
+
};
|
|
149
|
+
return decoder;
|
|
150
|
+
}
|
|
151
|
+
setDecoderProperties(properties) {
|
|
152
|
+
if (properties.length < 5) {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
const lc = properties[0] % 9;
|
|
156
|
+
const remainder = Math.floor(properties[0] / 9);
|
|
157
|
+
const lp = remainder % 5;
|
|
158
|
+
const pb = Math.floor(remainder / 5);
|
|
159
|
+
if (pb > 4) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
// Set literal decoder properties
|
|
163
|
+
this.literalDecoder.numPrevBits = lc;
|
|
164
|
+
this.literalDecoder.numPosBits = lp;
|
|
165
|
+
this.literalDecoder.posMask = (1 << lp) - 1;
|
|
166
|
+
// Set position state mask
|
|
167
|
+
this.posStateMask = (1 << pb) - 1;
|
|
168
|
+
// Calculate dictionary size from properties[1-4]
|
|
169
|
+
let dictSize = 0;
|
|
170
|
+
for (let i = 0; i < 4; i++) {
|
|
171
|
+
// Treat bytes as unsigned (0-255) instead of signed (-128 to 127)
|
|
172
|
+
const unsignedByte = properties[1 + i] & 0xFF;
|
|
173
|
+
dictSize += unsignedByte << (i * 8);
|
|
174
|
+
}
|
|
175
|
+
// Set dictionary size and check value
|
|
176
|
+
this.dictSizeCheck = Math.max(dictSize, 1);
|
|
177
|
+
// Initialize output window
|
|
178
|
+
if (dictSize > 0) {
|
|
179
|
+
this.outWindow.windowSize = Math.max(dictSize, 4096);
|
|
180
|
+
this.outWindow.buffer = new Uint8Array(this.outWindow.windowSize);
|
|
181
|
+
}
|
|
182
|
+
// Initialize literal decoder coders
|
|
183
|
+
const numStates = 1 << (this.literalDecoder.numPrevBits + this.literalDecoder.numPosBits);
|
|
184
|
+
this.literalDecoder.coders = [];
|
|
185
|
+
for (let i = 0; i < numStates; i++) {
|
|
186
|
+
this.literalDecoder.coders[i] = {
|
|
187
|
+
decoders: initArray(LITERAL_DECODER_SIZE), // 0x300
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
// Initialize length decoders
|
|
191
|
+
this.lenDecoder.numPosStates = 1 << pb;
|
|
192
|
+
this.repLenDecoder.numPosStates = 1 << pb;
|
|
193
|
+
// Initialize low and mid coders for length decoders
|
|
194
|
+
this.lenDecoder.lowCoder = [];
|
|
195
|
+
this.lenDecoder.midCoder = [];
|
|
196
|
+
this.repLenDecoder.lowCoder = [];
|
|
197
|
+
this.repLenDecoder.midCoder = [];
|
|
198
|
+
for (let posState = 0; posState < (1 << pb); posState++) {
|
|
199
|
+
this.lenDecoder.lowCoder[posState] = createBitTree(3);
|
|
200
|
+
this.lenDecoder.midCoder[posState] = createBitTree(3);
|
|
201
|
+
this.repLenDecoder.lowCoder[posState] = createBitTree(3);
|
|
202
|
+
this.repLenDecoder.midCoder[posState] = createBitTree(3);
|
|
203
|
+
}
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
// Methods that modify decoder state
|
|
207
|
+
copyBlock(len) {
|
|
208
|
+
const outputWindow = this.outWindow;
|
|
209
|
+
const distance = this.rep0;
|
|
210
|
+
let pos = outputWindow.pos - distance - 1;
|
|
211
|
+
if (pos < 0) {
|
|
212
|
+
pos += outputWindow.windowSize;
|
|
213
|
+
}
|
|
214
|
+
for (; len != 0; len -= 1) {
|
|
215
|
+
if (pos >= outputWindow.windowSize) {
|
|
216
|
+
pos = 0;
|
|
217
|
+
}
|
|
218
|
+
outputWindow.buffer[outputWindow.pos] = outputWindow.buffer[pos];
|
|
219
|
+
outputWindow.pos += 1;
|
|
220
|
+
pos += 1;
|
|
221
|
+
if (outputWindow.pos >= outputWindow.windowSize) {
|
|
222
|
+
this.flush();
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
putByte(b) {
|
|
227
|
+
this.outWindow.buffer[this.outWindow.pos] = b;
|
|
228
|
+
this.outWindow.pos += 1;
|
|
229
|
+
if (this.outWindow.pos >= this.outWindow.windowSize) {
|
|
230
|
+
this.flush();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
getByte(distance) {
|
|
234
|
+
const outputWindow = this.outWindow;
|
|
235
|
+
let pos = outputWindow.pos - distance - 1;
|
|
236
|
+
if (pos < 0) {
|
|
237
|
+
pos += outputWindow.windowSize;
|
|
238
|
+
}
|
|
239
|
+
return outputWindow.buffer[pos];
|
|
240
|
+
}
|
|
241
|
+
getDecoder(pos, prevByte) {
|
|
242
|
+
// Calculate index based on position and previous byte
|
|
243
|
+
const positionMask = pos & this.literalDecoder.posMask;
|
|
244
|
+
const prevBitsMask = (prevByte & 0xFF) >>> (8 - this.literalDecoder.numPrevBits);
|
|
245
|
+
const index = (positionMask << this.literalDecoder.numPrevBits) + prevBitsMask;
|
|
246
|
+
// Return decoder at calculated index
|
|
247
|
+
return this.literalDecoder.coders[index];
|
|
248
|
+
}
|
|
249
|
+
initLiteralDecoder() {
|
|
250
|
+
let numStates = 1 << (this.literalDecoder.numPrevBits + this.literalDecoder.numPosBits);
|
|
251
|
+
for (let i = 0; i < numStates; ++i) {
|
|
252
|
+
// Initialize bit models for each coder
|
|
253
|
+
for (let j = 0; j < this.literalDecoder.coders[i].decoders.length; j++) {
|
|
254
|
+
this.literalDecoder.coders[i].decoders[j] = 1024;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
init() {
|
|
259
|
+
this.outWindow.streamPos = 0;
|
|
260
|
+
this.outWindow.pos = 0;
|
|
261
|
+
initBitModels(this.matchDecoders);
|
|
262
|
+
initBitModels(this.rep0LongDecoders);
|
|
263
|
+
initBitModels(this.repDecoders);
|
|
264
|
+
initBitModels(this.repG0Decoders);
|
|
265
|
+
initBitModels(this.repG1Decoders);
|
|
266
|
+
initBitModels(this.repG2Decoders);
|
|
267
|
+
initBitModels(this.posDecoders);
|
|
268
|
+
this.initLiteralDecoder();
|
|
269
|
+
for (let i = 0; i < 4; ++i) {
|
|
270
|
+
initBitModels(this.posSlotDecoders[i].models);
|
|
271
|
+
}
|
|
272
|
+
this.initLenDecoder(this.lenDecoder);
|
|
273
|
+
this.initLenDecoder(this.repLenDecoder);
|
|
274
|
+
initBitModels(this.posAlignDecoder.models);
|
|
275
|
+
this.initRangeDecoder();
|
|
276
|
+
}
|
|
277
|
+
initLenDecoder(decoder) {
|
|
278
|
+
initBitModels(decoder.choice);
|
|
279
|
+
for (let posState = 0; posState < decoder.numPosStates; ++posState) {
|
|
280
|
+
initBitModels(decoder.lowCoder[posState].models);
|
|
281
|
+
initBitModels(decoder.midCoder[posState].models);
|
|
282
|
+
}
|
|
283
|
+
initBitModels(decoder.highCoder.models);
|
|
284
|
+
}
|
|
285
|
+
outWindowReleaseStream() {
|
|
286
|
+
this.flush();
|
|
287
|
+
this.outWindow.stream = null;
|
|
288
|
+
}
|
|
289
|
+
decodeBit(probs, index) {
|
|
290
|
+
return this.rangeDecoder.decodeBit(probs, index);
|
|
291
|
+
}
|
|
292
|
+
decodeDirectBits(numTotalBits) {
|
|
293
|
+
return this.rangeDecoder.decodeDirectBits(numTotalBits);
|
|
294
|
+
}
|
|
295
|
+
initRangeDecoder() {
|
|
296
|
+
this.rangeDecoder.init();
|
|
297
|
+
}
|
|
298
|
+
rangeBitTreeDecoder(bitTree) {
|
|
299
|
+
let bitIndex, m = 1;
|
|
300
|
+
for (bitIndex = bitTree.numBitLevels; bitIndex != 0; bitIndex -= 1) {
|
|
301
|
+
m = (m << 1) + this.decodeBit(bitTree.models, m);
|
|
302
|
+
}
|
|
303
|
+
return m - (1 << bitTree.numBitLevels);
|
|
304
|
+
}
|
|
305
|
+
reverseDecode(models, startIndex, numBitLevels) {
|
|
306
|
+
let symbol = 0;
|
|
307
|
+
for (let bitIndex = 0, m = 1, bit; bitIndex < numBitLevels; ++bitIndex) {
|
|
308
|
+
bit = this.decodeBit(models, startIndex + m);
|
|
309
|
+
m <<= 1;
|
|
310
|
+
m += bit;
|
|
311
|
+
symbol |= bit << bitIndex;
|
|
312
|
+
}
|
|
313
|
+
return symbol;
|
|
314
|
+
}
|
|
315
|
+
reverseDecodeAlignDecoder() {
|
|
316
|
+
let symbol = 0;
|
|
317
|
+
for (let m = 1, bitIndex = 0, bit; bitIndex < this.posAlignDecoder.numBitLevels; ++bitIndex) {
|
|
318
|
+
bit = this.decodeBit(this.posAlignDecoder.models, m);
|
|
319
|
+
m <<= 1;
|
|
320
|
+
m += bit;
|
|
321
|
+
symbol |= bit << bitIndex;
|
|
322
|
+
}
|
|
323
|
+
return symbol;
|
|
324
|
+
}
|
|
325
|
+
// Update the placeholder implementations with actual logic
|
|
326
|
+
decodeNormalWithRangeDecoder(decoder) {
|
|
327
|
+
let symbol = 1;
|
|
328
|
+
do {
|
|
329
|
+
symbol = symbol << 1 | this.decodeBit(decoder.decoders, symbol);
|
|
330
|
+
} while (symbol < 0x100);
|
|
331
|
+
return symbol << 24 >> 24;
|
|
332
|
+
}
|
|
333
|
+
decodeWithMatchByteWithRangeDecoder(encoder, matchByte) {
|
|
334
|
+
let bit, matchBit, symbol = 1;
|
|
335
|
+
do {
|
|
336
|
+
matchBit = (matchByte >> 7) & 1;
|
|
337
|
+
matchByte <<= 1;
|
|
338
|
+
bit = this.decodeBit(encoder.decoders, ((1 + matchBit) << 8) + symbol);
|
|
339
|
+
symbol = symbol << 1 | bit;
|
|
340
|
+
if (matchBit != bit) {
|
|
341
|
+
while (symbol < 0x100) {
|
|
342
|
+
symbol = symbol << 1 | this.decodeBit(encoder.decoders, symbol);
|
|
343
|
+
}
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
} while (symbol < 0x100);
|
|
347
|
+
return symbol << 24 >> 24;
|
|
348
|
+
}
|
|
349
|
+
decodeLenWithRangeDecoder(decoder, posState) {
|
|
350
|
+
if (!this.decodeBit(decoder.choice, 0)) {
|
|
351
|
+
return this.rangeBitTreeDecoder(decoder.lowCoder[posState]);
|
|
352
|
+
}
|
|
353
|
+
let symbol = 0x08;
|
|
354
|
+
if (!this.decodeBit(decoder.choice, 1)) {
|
|
355
|
+
symbol += this.rangeBitTreeDecoder(decoder.midCoder[posState]);
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
symbol += 0x08 + this.rangeBitTreeDecoder(decoder.highCoder);
|
|
359
|
+
}
|
|
360
|
+
return symbol;
|
|
361
|
+
}
|
|
362
|
+
codeOneChunk() {
|
|
363
|
+
let decoder2, distance, len, numDirectBits, positionSlot;
|
|
364
|
+
let posState = Number(this.nowPos64 & 0xffffffffn) & this.posStateMask;
|
|
365
|
+
if (!this.decodeBit(this.matchDecoders, (this.state << 4) + posState)) {
|
|
366
|
+
decoder2 = this.getDecoder(Number(this.nowPos64 & 0xffffffffn), this.prevByte);
|
|
367
|
+
if (this.state < 7) {
|
|
368
|
+
this.prevByte = this.decodeNormalWithRangeDecoder(decoder2);
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
this.prevByte = this.decodeWithMatchByteWithRangeDecoder(decoder2, this.getByte(this.rep0));
|
|
372
|
+
}
|
|
373
|
+
this.putByte(this.prevByte);
|
|
374
|
+
this.state = stateUpdateChar(this.state);
|
|
375
|
+
this.nowPos64 += 1n;
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
if (this.decodeBit(this.repDecoders, this.state)) {
|
|
379
|
+
len = 0;
|
|
380
|
+
if (!this.decodeBit(this.repG0Decoders, this.state)) {
|
|
381
|
+
if (!this.decodeBit(this.rep0LongDecoders, (this.state << 4) + posState)) {
|
|
382
|
+
this.state = this.state < 7 ? 9 : 11;
|
|
383
|
+
len = 1;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
if (!this.decodeBit(this.repG1Decoders, this.state)) {
|
|
388
|
+
distance = this.rep1;
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
if (!this.decodeBit(this.repG2Decoders, this.state)) {
|
|
392
|
+
distance = this.rep2;
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
distance = this.rep3;
|
|
396
|
+
this.rep3 = this.rep2;
|
|
397
|
+
}
|
|
398
|
+
this.rep2 = this.rep1;
|
|
399
|
+
}
|
|
400
|
+
this.rep1 = this.rep0;
|
|
401
|
+
this.rep0 = distance;
|
|
402
|
+
}
|
|
403
|
+
if (!len) {
|
|
404
|
+
len = this.decodeLenWithRangeDecoder(this.repLenDecoder, posState) + 2;
|
|
405
|
+
this.state = this.state < 7 ? 0x08 : 11;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
409
|
+
this.rep3 = this.rep2;
|
|
410
|
+
this.rep2 = this.rep1;
|
|
411
|
+
this.rep1 = this.rep0;
|
|
412
|
+
len = 2 + this.decodeLenWithRangeDecoder(this.lenDecoder, posState);
|
|
413
|
+
this.state = this.state < 7 ? 7 : 10;
|
|
414
|
+
positionSlot = this.rangeBitTreeDecoder(this.posSlotDecoders[getLenToPosState(len)]);
|
|
415
|
+
if (positionSlot >= 4) {
|
|
416
|
+
numDirectBits = (positionSlot >> 1) - 1;
|
|
417
|
+
this.rep0 = (2 | (positionSlot & 1)) << numDirectBits;
|
|
418
|
+
if (positionSlot < 14) {
|
|
419
|
+
this.rep0 += this.reverseDecode(this.posDecoders, this.rep0 - positionSlot - 1, numDirectBits);
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
this.rep0 += this.decodeDirectBits(numDirectBits - 4) << 4;
|
|
423
|
+
this.rep0 += this.reverseDecodeAlignDecoder();
|
|
424
|
+
if (this.rep0 < 0) {
|
|
425
|
+
if (this.rep0 == -1) {
|
|
426
|
+
return 1;
|
|
427
|
+
}
|
|
428
|
+
return -1;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
433
|
+
this.rep0 = positionSlot;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
if (BigInt(this.rep0) >= this.nowPos64 || this.rep0 >= this.dictSizeCheck) {
|
|
437
|
+
return -1;
|
|
438
|
+
}
|
|
439
|
+
this.copyBlock(len);
|
|
440
|
+
this.nowPos64 += BigInt(len);
|
|
441
|
+
this.prevByte = this.getByte(0);
|
|
442
|
+
}
|
|
443
|
+
return 0;
|
|
444
|
+
}
|
|
445
|
+
writeToOutput(buffer, data, offset, length) {
|
|
446
|
+
buffer.writeBytes(data, offset, length);
|
|
447
|
+
}
|
|
448
|
+
flush() {
|
|
449
|
+
const size = this.outWindow.pos - this.outWindow.streamPos;
|
|
450
|
+
if (!size) {
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
if (this.outWindow.stream && this.outWindow.buffer) {
|
|
454
|
+
this.outWindow.stream.writeBytes(this.outWindow.buffer, this.outWindow.streamPos, size);
|
|
455
|
+
}
|
|
456
|
+
if (this.outWindow.pos >= this.outWindow.windowSize) {
|
|
457
|
+
this.outWindow.pos = 0;
|
|
458
|
+
}
|
|
459
|
+
this.outWindow.streamPos = this.outWindow.pos;
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Cleanup decoder resources
|
|
463
|
+
*/
|
|
464
|
+
cleanup() {
|
|
465
|
+
this.outWindow.stream = null;
|
|
466
|
+
this.rangeDecoder.stream = null;
|
|
467
|
+
}
|
|
468
|
+
}
|