@patrickdk77/archive-defuse 0.1.2 → 0.1.3

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.
@@ -1,484 +1,206 @@
1
1
  "use strict";
2
- // Copied from lzma1 (Apache-2.0, Copyright Filip Seman) and changed for lzma-defuse. NOTICE in this folder lists the changes.
2
+ // Copied from lzma1 0.6.1 (Apache-2.0, Copyright Filip Seman) and changed for archive-defuse. NOTICE in this folder lists the changes.
3
3
  /**
4
4
  * LZMA decoder: turns range-coded symbols back into literals and matches.
5
5
  *
6
- * Ported from XZ for Java (0BSD) by Lasse Collin and Igor Pavlov. The main
7
- * loop is structured like `LzmaDec_DecodeReal` of the LZMA SDK.
6
+ * Ported from XZ for Java (0BSD), `src/org/tukaani/xz/lzma/LZMADecoder.java`,
7
+ * by Lasse Collin and Igor Pavlov.
8
+ *
9
+ * Contract adaptations, pinned by the recorded malformed-stream
10
+ * expectations in `fixtures/malformed.json` and
11
+ * `fixtures/raw-malformed.json`:
12
+ * - `decode(outLimit, inLimit)` drives the loop by the number of bytes
13
+ * produced (`outPos`) and the input position, instead of the Java code's
14
+ * `LZDecoder` window limit, because the input arrives in chunks and the
15
+ * output goes to a sink. `outPos` also provides the position bits
16
+ * (`posState` and the literal subcoder index). The Java code reads them
17
+ * from `LZDecoder.getPos()`, its position in a circular dictionary
18
+ * buffer that `LZMAInputStream.getDictSize` and
19
+ * `LZMA2InputStream.getDictSize` round up to a multiple of 16 for exactly
20
+ * this purpose, so that position equals `outPos` modulo 16. LZMA2 sets
21
+ * `outPos` to the bytes since the last dictionary reset, where
22
+ * `LZDecoder.reset` puts the Java position back to 0. The position masks
23
+ * keep at most the low 4 bits (`pb`, `lp` <= 4), so the two agree for
24
+ * every dictionary size.
25
+ * - The end marker returns `true` instead of surfacing as the error the
26
+ * Java code's `lz.repeat` raises for it; a match that would cross the
27
+ * output limit, the declared size or the end of an LZMA2 chunk, is an
28
+ * error.
8
29
  */
9
30
  Object.defineProperty(exports, "__esModule", { value: true });
10
31
  exports.LzmaDecoder = void 0;
11
32
  const lzma_coder_1 = require("./lzma-coder");
12
- const range_coder_1 = require("./range-coder");
13
- /** Distance value that marks the end of the stream. */
33
+ /** Distance value that marks the end of the stream (0xFFFFFFFF as int32). */
14
34
  const END_MARKER_DIST = -1;
15
35
  class LzmaDecoder extends lzma_coder_1.LzmaCoder {
36
+ // Package-private in Java: the literal subdecoders read these.
16
37
  lz;
17
38
  rc;
18
- /** Number of bytes decoded so far. */
39
+ literalDecoder;
40
+ matchLenDecoder = new LengthDecoder(this.probs, lzma_coder_1.MATCH_LEN);
41
+ repLenDecoder = new LengthDecoder(this.probs, lzma_coder_1.REP_LEN);
42
+ /** Bytes decoded so far; for LZMA2, since the last dictionary reset. */
19
43
  outPos = 0;
44
+ /**
45
+ * @param probs Probability array of an earlier decoder to reuse, of
46
+ * `probsSize(lc, lp)` entries; a new one is allocated without it.
47
+ */
20
48
  constructor(lz, rc, lc, lp, pb, probs) {
21
49
  super(lc, lp, pb, probs);
22
50
  this.lz = lz;
23
51
  this.rc = rc;
52
+ this.literalDecoder = new LiteralDecoder(this, lc, lp);
24
53
  this.reset();
25
54
  }
26
55
  /**
27
- * Decodes symbols until `outLimit` bytes have been produced or the input
56
+ * Returns true if LZMA end marker was detected. It is encoded as
57
+ * the maximum match distance which with int32 values becomes -1.
58
+ */
59
+ endMarkerDetected() {
60
+ return this.reps[0] === END_MARKER_DIST;
61
+ }
62
+ /**
63
+ * Decodes symbols until `outPos` reaches `outLimit` or the input
28
64
  * position passes `inLimit`.
29
65
  *
30
- * Performance: this is the hot loop of decompression. The range decoder
31
- * state, the coder state and the reps live in local variables, and the
32
- * bit decoding step (`decodeBit` in `range-coder_test.ts`) is repeated inline:
33
- *
34
- * prob = probs[i];
35
- * bound = (range >>> 11) * prob;
36
- * if (code < bound) { range = bound; probs[i] = prob + ((2048 - prob) >>> 5); bit 0 }
37
- * else { range -= bound; code -= bound; probs[i] = prob - (prob >>> 5); bit 1 }
38
- * if (range < 2^24) { shift in the next input byte }
39
- *
40
- * With the state in object fields, engines store and reload it around
41
- * every probability update, which costs 10-15% on V8.
42
- *
43
66
  * @returns `true` if the end marker was decoded
44
67
  */
45
68
  decode(outLimit, inLimit) {
46
- const probs = this.probs;
47
- const lz = this.lz;
48
- const reps = this.reps;
49
- const posMask = this.posMask;
50
69
  const rc = this.rc;
51
- const input = rc.input;
52
- const inputEnd = input.length;
53
- let range = rc.range;
54
- let code = rc.code;
55
- let inPos = rc.pos;
56
- let state = this.state;
57
- let outPos = this.outPos;
58
- let rep0 = reps[0];
59
- let rep1 = reps[1];
60
- let rep2 = reps[2];
61
- let rep3 = reps[3];
70
+ const lz = this.lz;
62
71
  let endMarker = false;
63
- let i = 0;
64
- let prob = 0;
65
- let bound = 0;
66
- while (outPos < outLimit && inPos <= inLimit) {
67
- const posState = outPos & posMask;
68
- // -- Literal or match? --
69
- i = lzma_coder_1.IS_MATCH + (state << 4) + posState;
70
- prob = probs[i];
71
- bound = (range >>> range_coder_1.BIT_MODEL_TOTAL_BITS) * prob;
72
- if (code < bound) {
73
- range = bound;
74
- probs[i] = prob + ((range_coder_1.BIT_MODEL_TOTAL - prob) >>> range_coder_1.MOVE_BITS);
75
- if (range < range_coder_1.TOP_VALUE) {
76
- if (inPos >= inputEnd)
77
- throw truncated();
78
- range = (range << 8) >>> 0;
79
- code = ((code << 8) | input[inPos++]) >>> 0;
80
- }
81
- // -- Literal: 8 bits, MSB first --
82
- const offset = this.literalOffset(lz.getByte(0), outPos);
83
- let symbol = 1;
84
- if ((0, lzma_coder_1.isLiteralState)(state)) {
85
- do {
86
- i = offset + symbol;
87
- prob = probs[i];
88
- bound = (range >>> range_coder_1.BIT_MODEL_TOTAL_BITS) * prob;
89
- if (code < bound) {
90
- range = bound;
91
- probs[i] = prob + ((range_coder_1.BIT_MODEL_TOTAL - prob) >>> range_coder_1.MOVE_BITS);
92
- symbol <<= 1;
93
- }
94
- else {
95
- range -= bound;
96
- code -= bound;
97
- probs[i] = prob - (prob >>> range_coder_1.MOVE_BITS);
98
- symbol = (symbol << 1) | 1;
99
- }
100
- if (range < range_coder_1.TOP_VALUE) {
101
- if (inPos >= inputEnd)
102
- throw truncated();
103
- range = (range << 8) >>> 0;
104
- code = ((code << 8) | input[inPos++]) >>> 0;
105
- }
106
- } while (symbol < 0x100);
107
- }
108
- else {
109
- // After a match, the bits of the byte at rep0 select the
110
- // probabilities until the first bit that differs.
111
- let matchByte = lz.getByte(rep0);
112
- let matchOffset = 0x100;
113
- do {
114
- matchByte <<= 1;
115
- const matchBit = matchByte & matchOffset;
116
- i = offset + matchOffset + matchBit + symbol;
117
- prob = probs[i];
118
- bound = (range >>> range_coder_1.BIT_MODEL_TOTAL_BITS) * prob;
119
- if (code < bound) {
120
- range = bound;
121
- probs[i] = prob + ((range_coder_1.BIT_MODEL_TOTAL - prob) >>> range_coder_1.MOVE_BITS);
122
- symbol <<= 1;
123
- matchOffset &= ~matchBit;
124
- }
125
- else {
126
- range -= bound;
127
- code -= bound;
128
- probs[i] = prob - (prob >>> range_coder_1.MOVE_BITS);
129
- symbol = (symbol << 1) | 1;
130
- matchOffset &= matchBit;
131
- }
132
- if (range < range_coder_1.TOP_VALUE) {
133
- if (inPos >= inputEnd)
134
- throw truncated();
135
- range = (range << 8) >>> 0;
136
- code = ((code << 8) | input[inPos++]) >>> 0;
137
- }
138
- } while (symbol < 0x100);
139
- }
140
- lz.putByte(symbol & 0xff);
141
- state = (0, lzma_coder_1.stateAfterLiteral)(state);
142
- ++outPos;
143
- continue;
144
- }
145
- range -= bound;
146
- code -= bound;
147
- probs[i] = prob - (prob >>> range_coder_1.MOVE_BITS);
148
- if (range < range_coder_1.TOP_VALUE) {
149
- if (inPos >= inputEnd)
150
- throw truncated();
151
- range = (range << 8) >>> 0;
152
- code = ((code << 8) | input[inPos++]) >>> 0;
153
- }
154
- // -- Match or rep match? --
155
- let lenCoder;
156
- i = lzma_coder_1.IS_REP + state;
157
- prob = probs[i];
158
- bound = (range >>> range_coder_1.BIT_MODEL_TOTAL_BITS) * prob;
159
- if (code < bound) {
160
- range = bound;
161
- probs[i] = prob + ((range_coder_1.BIT_MODEL_TOTAL - prob) >>> range_coder_1.MOVE_BITS);
162
- if (range < range_coder_1.TOP_VALUE) {
163
- if (inPos >= inputEnd)
164
- throw truncated();
165
- range = (range << 8) >>> 0;
166
- code = ((code << 8) | input[inPos++]) >>> 0;
167
- }
168
- // Match: the distance follows the length.
169
- state = (0, lzma_coder_1.stateAfterMatch)(state);
170
- rep3 = rep2;
171
- rep2 = rep1;
172
- rep1 = rep0;
173
- lenCoder = lzma_coder_1.MATCH_LEN;
72
+ while (this.outPos < outLimit && rc.pos <= inLimit) {
73
+ const posState = this.outPos & this.posMask;
74
+ if (rc.decodeBit(this.probs, lzma_coder_1.IS_MATCH + (this.state.get() << 4) + posState) === 0) {
75
+ this.literalDecoder.decode();
76
+ ++this.outPos;
174
77
  }
175
78
  else {
176
- range -= bound;
177
- code -= bound;
178
- probs[i] = prob - (prob >>> range_coder_1.MOVE_BITS);
179
- if (range < range_coder_1.TOP_VALUE) {
180
- if (inPos >= inputEnd)
181
- throw truncated();
182
- range = (range << 8) >>> 0;
183
- code = ((code << 8) | input[inPos++]) >>> 0;
184
- }
185
- // Rep match: one of the four recent distances.
186
- i = lzma_coder_1.IS_REP0 + state;
187
- prob = probs[i];
188
- bound = (range >>> range_coder_1.BIT_MODEL_TOTAL_BITS) * prob;
189
- if (code < bound) {
190
- range = bound;
191
- probs[i] = prob + ((range_coder_1.BIT_MODEL_TOTAL - prob) >>> range_coder_1.MOVE_BITS);
192
- if (range < range_coder_1.TOP_VALUE) {
193
- if (inPos >= inputEnd)
194
- throw truncated();
195
- range = (range << 8) >>> 0;
196
- code = ((code << 8) | input[inPos++]) >>> 0;
197
- }
198
- // rep0: a single byte ("short rep") or a longer match?
199
- i = lzma_coder_1.IS_REP0_LONG + (state << 4) + posState;
200
- prob = probs[i];
201
- bound = (range >>> range_coder_1.BIT_MODEL_TOTAL_BITS) * prob;
202
- if (code < bound) {
203
- range = bound;
204
- probs[i] = prob + ((range_coder_1.BIT_MODEL_TOTAL - prob) >>> range_coder_1.MOVE_BITS);
205
- if (range < range_coder_1.TOP_VALUE) {
206
- if (inPos >= inputEnd)
207
- throw truncated();
208
- range = (range << 8) >>> 0;
209
- code = ((code << 8) | input[inPos++]) >>> 0;
210
- }
211
- state = (0, lzma_coder_1.stateAfterShortRep)(state);
212
- if (outPos >= outLimit)
213
- throw exceedsSize();
214
- lz.repeat(rep0, 1);
215
- ++outPos;
216
- continue;
217
- }
218
- range -= bound;
219
- code -= bound;
220
- probs[i] = prob - (prob >>> range_coder_1.MOVE_BITS);
221
- if (range < range_coder_1.TOP_VALUE) {
222
- if (inPos >= inputEnd)
223
- throw truncated();
224
- range = (range << 8) >>> 0;
225
- code = ((code << 8) | input[inPos++]) >>> 0;
226
- }
79
+ const len = rc.decodeBit(this.probs, lzma_coder_1.IS_REP + this.state.get()) === 0 ? this.decodeMatch(posState) : this.decodeRepMatch(posState);
80
+ if (this.endMarkerDetected()) {
81
+ endMarker = true;
82
+ break;
227
83
  }
228
- else {
229
- range -= bound;
230
- code -= bound;
231
- probs[i] = prob - (prob >>> range_coder_1.MOVE_BITS);
232
- if (range < range_coder_1.TOP_VALUE) {
233
- if (inPos >= inputEnd)
234
- throw truncated();
235
- range = (range << 8) >>> 0;
236
- code = ((code << 8) | input[inPos++]) >>> 0;
237
- }
238
- let dist;
239
- // rep1, or rep2/rep3?
240
- i = lzma_coder_1.IS_REP1 + state;
241
- prob = probs[i];
242
- bound = (range >>> range_coder_1.BIT_MODEL_TOTAL_BITS) * prob;
243
- if (code < bound) {
244
- range = bound;
245
- probs[i] = prob + ((range_coder_1.BIT_MODEL_TOTAL - prob) >>> range_coder_1.MOVE_BITS);
246
- dist = rep1;
247
- }
248
- else {
249
- range -= bound;
250
- code -= bound;
251
- probs[i] = prob - (prob >>> range_coder_1.MOVE_BITS);
252
- if (range < range_coder_1.TOP_VALUE) {
253
- if (inPos >= inputEnd)
254
- throw truncated();
255
- range = (range << 8) >>> 0;
256
- code = ((code << 8) | input[inPos++]) >>> 0;
257
- }
258
- // rep2 or rep3?
259
- i = lzma_coder_1.IS_REP2 + state;
260
- prob = probs[i];
261
- bound = (range >>> range_coder_1.BIT_MODEL_TOTAL_BITS) * prob;
262
- if (code < bound) {
263
- range = bound;
264
- probs[i] = prob + ((range_coder_1.BIT_MODEL_TOTAL - prob) >>> range_coder_1.MOVE_BITS);
265
- dist = rep2;
266
- }
267
- else {
268
- range -= bound;
269
- code -= bound;
270
- probs[i] = prob - (prob >>> range_coder_1.MOVE_BITS);
271
- dist = rep3;
272
- rep3 = rep2;
273
- }
274
- rep2 = rep1;
275
- }
276
- if (range < range_coder_1.TOP_VALUE) {
277
- if (inPos >= inputEnd)
278
- throw truncated();
279
- range = (range << 8) >>> 0;
280
- code = ((code << 8) | input[inPos++]) >>> 0;
281
- }
282
- rep1 = rep0;
283
- rep0 = dist;
84
+ if (len > outLimit - this.outPos) {
85
+ throw new Error('Corrupted input: data exceeds the declared size');
284
86
  }
285
- state = (0, lzma_coder_1.stateAfterLongRep)(state);
286
- lenCoder = lzma_coder_1.REP_LEN;
87
+ lz.repeat(this.reps[0], len);
88
+ this.outPos += len;
287
89
  }
288
- // -- Length: choice bits select the low, mid or high tree --
289
- let treeOffset;
290
- let treeBits;
291
- let len;
292
- i = lenCoder + lzma_coder_1.LEN_CHOICE;
293
- prob = probs[i];
294
- bound = (range >>> range_coder_1.BIT_MODEL_TOTAL_BITS) * prob;
295
- if (code < bound) {
296
- range = bound;
297
- probs[i] = prob + ((range_coder_1.BIT_MODEL_TOTAL - prob) >>> range_coder_1.MOVE_BITS);
298
- treeOffset = lenCoder + lzma_coder_1.LEN_LOW + posState * lzma_coder_1.LOW_SYMBOLS;
299
- treeBits = 3;
300
- len = lzma_coder_1.MATCH_LEN_MIN;
90
+ }
91
+ rc.normalize();
92
+ return endMarker;
93
+ }
94
+ decodeMatch(posState) {
95
+ this.state.updateMatch();
96
+ this.reps[3] = this.reps[2];
97
+ this.reps[2] = this.reps[1];
98
+ this.reps[1] = this.reps[0];
99
+ const len = this.matchLenDecoder.decode(this.rc, posState);
100
+ const distSlot = this.rc.decodeBitTree(this.probs, lzma_coder_1.DIST_SLOT_OFFSET + ((0, lzma_coder_1.getDistState)(len) << lzma_coder_1.DIST_SLOT_BITS), lzma_coder_1.DIST_SLOT_BITS);
101
+ if (distSlot < lzma_coder_1.DIST_MODEL_START) {
102
+ this.reps[0] = distSlot;
103
+ }
104
+ else {
105
+ const limit = (distSlot >> 1) - 1;
106
+ this.reps[0] = (2 | (distSlot & 1)) << limit;
107
+ if (distSlot < lzma_coder_1.DIST_MODEL_END) {
108
+ this.reps[0] |= this.rc.decodeReverseBitTree(this.probs, (0, lzma_coder_1.distSpecialOffset)(distSlot, this.reps[0]), limit);
301
109
  }
302
110
  else {
303
- range -= bound;
304
- code -= bound;
305
- probs[i] = prob - (prob >>> range_coder_1.MOVE_BITS);
306
- if (range < range_coder_1.TOP_VALUE) {
307
- if (inPos >= inputEnd)
308
- throw truncated();
309
- range = (range << 8) >>> 0;
310
- code = ((code << 8) | input[inPos++]) >>> 0;
311
- }
312
- i = lenCoder + lzma_coder_1.LEN_CHOICE2;
313
- prob = probs[i];
314
- bound = (range >>> range_coder_1.BIT_MODEL_TOTAL_BITS) * prob;
315
- if (code < bound) {
316
- range = bound;
317
- probs[i] = prob + ((range_coder_1.BIT_MODEL_TOTAL - prob) >>> range_coder_1.MOVE_BITS);
318
- treeOffset = lenCoder + lzma_coder_1.LEN_MID + posState * lzma_coder_1.MID_SYMBOLS;
319
- treeBits = 3;
320
- len = lzma_coder_1.MATCH_LEN_MIN + lzma_coder_1.LOW_SYMBOLS;
321
- }
322
- else {
323
- range -= bound;
324
- code -= bound;
325
- probs[i] = prob - (prob >>> range_coder_1.MOVE_BITS);
326
- treeOffset = lenCoder + lzma_coder_1.LEN_HIGH;
327
- treeBits = 8;
328
- len = lzma_coder_1.MATCH_LEN_MIN + lzma_coder_1.LOW_SYMBOLS + lzma_coder_1.MID_SYMBOLS;
329
- }
111
+ this.reps[0] |= this.rc.decodeDirectBits(limit - lzma_coder_1.ALIGN_BITS) << lzma_coder_1.ALIGN_BITS;
112
+ this.reps[0] |= this.rc.decodeReverseBitTree(this.probs, lzma_coder_1.DIST_ALIGN, lzma_coder_1.ALIGN_BITS);
330
113
  }
331
- if (range < range_coder_1.TOP_VALUE) {
332
- if (inPos >= inputEnd)
333
- throw truncated();
334
- range = (range << 8) >>> 0;
335
- code = ((code << 8) | input[inPos++]) >>> 0;
114
+ }
115
+ return len;
116
+ }
117
+ decodeRepMatch(posState) {
118
+ if (this.rc.decodeBit(this.probs, lzma_coder_1.IS_REP0 + this.state.get()) === 0) {
119
+ if (this.rc.decodeBit(this.probs, lzma_coder_1.IS_REP0_LONG + (this.state.get() << 4) + posState) === 0) {
120
+ this.state.updateShortRep();
121
+ return 1;
336
122
  }
337
- {
338
- const end = 1 << treeBits;
339
- let symbol = 1;
340
- do {
341
- i = treeOffset + symbol;
342
- prob = probs[i];
343
- bound = (range >>> range_coder_1.BIT_MODEL_TOTAL_BITS) * prob;
344
- if (code < bound) {
345
- range = bound;
346
- probs[i] = prob + ((range_coder_1.BIT_MODEL_TOTAL - prob) >>> range_coder_1.MOVE_BITS);
347
- symbol <<= 1;
348
- }
349
- else {
350
- range -= bound;
351
- code -= bound;
352
- probs[i] = prob - (prob >>> range_coder_1.MOVE_BITS);
353
- symbol = (symbol << 1) | 1;
354
- }
355
- if (range < range_coder_1.TOP_VALUE) {
356
- if (inPos >= inputEnd)
357
- throw truncated();
358
- range = (range << 8) >>> 0;
359
- code = ((code << 8) | input[inPos++]) >>> 0;
360
- }
361
- } while (symbol < end);
362
- len += symbol - end;
123
+ }
124
+ else {
125
+ let tmp;
126
+ if (this.rc.decodeBit(this.probs, lzma_coder_1.IS_REP1 + this.state.get()) === 0) {
127
+ tmp = this.reps[1];
363
128
  }
364
- // -- Distance (normal matches only) --
365
- if (lenCoder === lzma_coder_1.MATCH_LEN) {
366
- // Distance slot: 6 bits, MSB first
367
- const slotTree = lzma_coder_1.DIST_SLOTS + ((0, lzma_coder_1.getDistState)(len) << lzma_coder_1.DIST_SLOT_BITS);
368
- let distSlot = 1;
369
- do {
370
- i = slotTree + distSlot;
371
- prob = probs[i];
372
- bound = (range >>> range_coder_1.BIT_MODEL_TOTAL_BITS) * prob;
373
- if (code < bound) {
374
- range = bound;
375
- probs[i] = prob + ((range_coder_1.BIT_MODEL_TOTAL - prob) >>> range_coder_1.MOVE_BITS);
376
- distSlot <<= 1;
377
- }
378
- else {
379
- range -= bound;
380
- code -= bound;
381
- probs[i] = prob - (prob >>> range_coder_1.MOVE_BITS);
382
- distSlot = (distSlot << 1) | 1;
383
- }
384
- if (range < range_coder_1.TOP_VALUE) {
385
- if (inPos >= inputEnd)
386
- throw truncated();
387
- range = (range << 8) >>> 0;
388
- code = ((code << 8) | input[inPos++]) >>> 0;
389
- }
390
- } while (distSlot < 1 << lzma_coder_1.DIST_SLOT_BITS);
391
- distSlot -= 1 << lzma_coder_1.DIST_SLOT_BITS;
392
- if (distSlot < lzma_coder_1.DIST_MODEL_START) {
393
- rep0 = distSlot;
129
+ else {
130
+ if (this.rc.decodeBit(this.probs, lzma_coder_1.IS_REP2 + this.state.get()) === 0) {
131
+ tmp = this.reps[2];
394
132
  }
395
133
  else {
396
- // The slot gives the top two bits; the footer bits follow.
397
- const footerBits = (distSlot >>> 1) - 1;
398
- let dist = (2 | (distSlot & 1)) << footerBits;
399
- let reverseTree;
400
- let reverseBits;
401
- if (distSlot < lzma_coder_1.DIST_MODEL_END) {
402
- reverseTree = (0, lzma_coder_1.distSpecialOffset)(distSlot, dist);
403
- reverseBits = footerBits;
404
- }
405
- else {
406
- // Direct bits with a fixed 50% probability, then 4
407
- // align bits with probabilities.
408
- let direct = 0;
409
- for (let k = footerBits - lzma_coder_1.ALIGN_BITS; k > 0; --k) {
410
- range >>>= 1;
411
- let bit = 0;
412
- if (code >= range) {
413
- code -= range;
414
- bit = 1;
415
- }
416
- direct = ((direct << 1) | bit) >>> 0;
417
- if (range < range_coder_1.TOP_VALUE) {
418
- if (inPos >= inputEnd)
419
- throw truncated();
420
- range = (range << 8) >>> 0;
421
- code = ((code << 8) | input[inPos++]) >>> 0;
422
- }
423
- }
424
- dist |= direct << lzma_coder_1.ALIGN_BITS;
425
- reverseTree = lzma_coder_1.DIST_ALIGN;
426
- reverseBits = lzma_coder_1.ALIGN_BITS;
427
- }
428
- // Footer or align bits, LSB first
429
- let symbol = 1;
430
- for (let k = 0; k < reverseBits; ++k) {
431
- i = reverseTree + symbol;
432
- prob = probs[i];
433
- bound = (range >>> range_coder_1.BIT_MODEL_TOTAL_BITS) * prob;
434
- if (code < bound) {
435
- range = bound;
436
- probs[i] = prob + ((range_coder_1.BIT_MODEL_TOTAL - prob) >>> range_coder_1.MOVE_BITS);
437
- symbol <<= 1;
438
- }
439
- else {
440
- range -= bound;
441
- code -= bound;
442
- probs[i] = prob - (prob >>> range_coder_1.MOVE_BITS);
443
- symbol = (symbol << 1) | 1;
444
- dist |= 1 << k;
445
- }
446
- if (range < range_coder_1.TOP_VALUE) {
447
- if (inPos >= inputEnd)
448
- throw truncated();
449
- range = (range << 8) >>> 0;
450
- code = ((code << 8) | input[inPos++]) >>> 0;
451
- }
452
- }
453
- // As int32, the end marker distance 0xFFFFFFFF is -1.
454
- rep0 = dist | 0;
455
- if (rep0 === END_MARKER_DIST) {
456
- endMarker = true;
457
- break;
458
- }
134
+ tmp = this.reps[3];
135
+ this.reps[3] = this.reps[2];
459
136
  }
137
+ this.reps[2] = this.reps[1];
460
138
  }
461
- if (len > outLimit - outPos)
462
- throw exceedsSize();
463
- lz.repeat(rep0, len);
464
- outPos += len;
139
+ this.reps[1] = this.reps[0];
140
+ this.reps[0] = tmp;
465
141
  }
466
- rc.range = range;
467
- rc.code = code;
468
- rc.pos = inPos;
469
- this.state = state;
470
- this.outPos = outPos;
471
- reps[0] = rep0;
472
- reps[1] = rep1;
473
- reps[2] = rep2;
474
- reps[3] = rep3;
475
- return endMarker;
142
+ this.state.updateLongRep();
143
+ return this.repLenDecoder.decode(this.rc, posState);
476
144
  }
477
145
  }
478
146
  exports.LzmaDecoder = LzmaDecoder;
479
- function truncated() {
480
- return new Error('Truncated input');
147
+ class LiteralDecoder extends lzma_coder_1.LiteralCoder {
148
+ decoder;
149
+ subdecoders;
150
+ constructor(decoder, lc, lp) {
151
+ super(lc, lp);
152
+ this.decoder = decoder;
153
+ this.subdecoders = Array.from({ length: 1 << (lc + lp) }, (_, i) => new LiteralSubdecoder(decoder, lzma_coder_1.LITERAL + 0x300 * i));
154
+ }
155
+ decode() {
156
+ const decoder = this.decoder;
157
+ // The Java code reads the position bits from the dictionary
158
+ // position; `outPos` is equivalent (see the module comment).
159
+ const i = this.getSubcoderIndex(decoder.lz.getByte(0), decoder.outPos);
160
+ this.subdecoders[i].decode();
161
+ }
481
162
  }
482
- function exceedsSize() {
483
- return new Error('Corrupted input: data exceeds the declared size');
163
+ class LiteralSubdecoder extends lzma_coder_1.LiteralSubcoder {
164
+ decoder;
165
+ constructor(decoder, literalOffset) {
166
+ super(decoder.probs, literalOffset);
167
+ this.decoder = decoder;
168
+ }
169
+ decode() {
170
+ const decoder = this.decoder;
171
+ const rc = decoder.rc;
172
+ const probs = this.probs;
173
+ let symbol = 1;
174
+ if (decoder.state.isLiteral()) {
175
+ do {
176
+ symbol = (symbol << 1) | rc.decodeBit(probs, this.literalOffset + symbol);
177
+ } while (symbol < 0x100);
178
+ }
179
+ else {
180
+ let matchByte = decoder.lz.getByte(decoder.reps[0]);
181
+ let offset = 0x100;
182
+ let matchBit;
183
+ let bit;
184
+ do {
185
+ matchByte <<= 1;
186
+ matchBit = matchByte & offset;
187
+ bit = rc.decodeBit(probs, this.literalOffset + offset + matchBit + symbol);
188
+ symbol = (symbol << 1) | bit;
189
+ offset &= -bit ^ ~matchBit;
190
+ } while (symbol < 0x100);
191
+ }
192
+ decoder.lz.putByte(symbol & 0xff);
193
+ decoder.state.updateLiteral();
194
+ }
195
+ }
196
+ class LengthDecoder extends lzma_coder_1.LengthCoder {
197
+ decode(rc, posState) {
198
+ if (rc.decodeBit(this.probs, this.coder + lzma_coder_1.LEN_CHOICE) === 0) {
199
+ return rc.decodeBitTree(this.probs, this.coder + lzma_coder_1.LEN_LOW + posState * lzma_coder_1.LOW_SYMBOLS, 3) + lzma_coder_1.MATCH_LEN_MIN;
200
+ }
201
+ if (rc.decodeBit(this.probs, this.coder + lzma_coder_1.LEN_CHOICE2) === 0) {
202
+ return rc.decodeBitTree(this.probs, this.coder + lzma_coder_1.LEN_MID + posState * lzma_coder_1.MID_SYMBOLS, 3) + lzma_coder_1.MATCH_LEN_MIN + lzma_coder_1.LOW_SYMBOLS;
203
+ }
204
+ return rc.decodeBitTree(this.probs, this.coder + lzma_coder_1.LEN_HIGH, 8) + lzma_coder_1.MATCH_LEN_MIN + lzma_coder_1.LOW_SYMBOLS + lzma_coder_1.MID_SYMBOLS;
205
+ }
484
206
  }
@@ -2,7 +2,8 @@
2
2
  * Fast LZMA encoder: picks symbols with simple heuristics, similar to a
3
3
  * lazy-matching LZ77 encoder.
4
4
  *
5
- * Ported from XZ for Java (0BSD) by Lasse Collin and Igor Pavlov.
5
+ * Ported from XZ for Java (0BSD), `src/org/tukaani/xz/lzma/LZMAEncoderFast.java`,
6
+ * by Lasse Collin and Igor Pavlov.
6
7
  */
7
8
  import { LzmaEncoder } from './lzma-encoder';
8
9
  export declare const FAST_EXTRA_SIZE_BEFORE = 1;
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
- // Copied from lzma1 (Apache-2.0, Copyright Filip Seman) and changed for lzma-defuse. NOTICE in this folder lists the changes.
2
+ // Copied from lzma1 0.6.1 (Apache-2.0, Copyright Filip Seman) and changed for archive-defuse. NOTICE in this folder lists the changes.
3
3
  /**
4
4
  * Fast LZMA encoder: picks symbols with simple heuristics, similar to a
5
5
  * lazy-matching LZ77 encoder.
6
6
  *
7
- * Ported from XZ for Java (0BSD) by Lasse Collin and Igor Pavlov.
7
+ * Ported from XZ for Java (0BSD), `src/org/tukaani/xz/lzma/LZMAEncoderFast.java`,
8
+ * by Lasse Collin and Igor Pavlov.
8
9
  */
9
10
  Object.defineProperty(exports, "__esModule", { value: true });
10
11
  exports.LzmaEncoderFast = exports.FAST_EXTRA_SIZE_AFTER = exports.FAST_EXTRA_SIZE_BEFORE = void 0;