@patrickdk77/archive-defuse 0.1.1 → 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,5 +1,5 @@
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 encoder base: codes the symbols chosen by a subclass and keeps the
5
5
  * price tables the subclasses use to choose between symbols.
@@ -8,60 +8,73 @@
8
8
  * - `LzmaEncoderFast` uses simple heuristics (levels 1-3).
9
9
  * - `LzmaEncoderNormal` searches for the cheapest symbol sequence (levels 4-9).
10
10
  *
11
- * Ported from XZ for Java (0BSD) by Lasse Collin and Igor Pavlov.
11
+ * Ported from XZ for Java (0BSD), `src/org/tukaani/xz/lzma/LZMAEncoder.java`,
12
+ * by Lasse Collin and Igor Pavlov. The LZMA2 entry points and chunk limits
13
+ * are not ported; this library produces only LZMA1 (".lzma") streams. The
14
+ * inner coder classes take their outer encoder (or the range encoder) as
15
+ * an explicit parameter where Java captures it implicitly.
12
16
  */
13
17
  Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.LengthEncoder = exports.LzmaEncoder = void 0;
18
+ exports.LengthEncoder = exports.LiteralEncoder = exports.LzmaEncoder = void 0;
15
19
  exports.getDistSlot = getDistSlot;
16
20
  const lzma_coder_1 = require("./lzma-coder");
17
21
  const range_coder_1 = require("./range-coder");
18
22
  const range_encoder_1 = require("./range-encoder");
19
23
  const DIST_PRICE_UPDATE_INTERVAL = lzma_coder_1.FULL_DISTANCES;
20
24
  const ALIGN_PRICE_UPDATE_INTERVAL = lzma_coder_1.ALIGN_SIZE;
21
- const LEN_PRICE_UPDATE_INTERVAL = 32;
22
- /** Returns the distance slot: roughly 2 * log2(dist), plus the next bit. */
25
+ /**
26
+ * Gets an integer [0, 63] matching the highest two bits of an integer.
27
+ * This is like bit scan reverse (BSR) on x86 except that this also
28
+ * cares about the second highest bit.
29
+ */
23
30
  function getDistSlot(dist) {
24
31
  if (dist <= lzma_coder_1.DIST_MODEL_START && dist >= 0) {
25
32
  return dist;
26
33
  }
34
+ // 31 - Integer.numberOfLeadingZeros(dist)
27
35
  const i = 31 - Math.clz32(dist);
28
36
  return (i << 1) + ((dist >>> (i - 1)) & 1);
29
37
  }
30
38
  class LzmaEncoder extends lzma_coder_1.LzmaCoder {
31
39
  rc;
32
40
  lz;
33
- niceLen;
41
+ literalEncoder;
34
42
  matchLenEncoder;
35
43
  repLenEncoder;
44
+ niceLen;
36
45
  distPriceCount = 0;
37
46
  alignPriceCount = 0;
38
- /** Whether a distance or align bits were encoded since the last reset. */
47
+ /** Whether a distance was encoded since the last reset. */
39
48
  distModelsUsed = false;
49
+ /** Whether align bits were encoded since the last reset. */
40
50
  alignModelUsed = false;
41
51
  distSlotPricesSize;
42
- /** Price of each distance slot per distance state, `[distState << 6 | slot]`. */
43
- distSlotPrices = new Uint32Array(lzma_coder_1.DIST_STATES << lzma_coder_1.DIST_SLOT_BITS);
44
- /** Price of each distance below `FULL_DISTANCES` per distance state, `[distState << 7 | dist]`. */
45
- fullDistPrices = new Uint32Array(lzma_coder_1.DIST_STATES * lzma_coder_1.FULL_DISTANCES);
46
- alignPrices = new Uint32Array(lzma_coder_1.ALIGN_SIZE);
52
+ distSlotPrices;
53
+ fullDistPrices = newPriceArray(lzma_coder_1.DIST_STATES, lzma_coder_1.FULL_DISTANCES);
54
+ alignPrices = new Int32Array(lzma_coder_1.ALIGN_SIZE);
47
55
  /**
48
56
  * Symbol chosen by `getNextSymbol()`:
49
57
  * -1 = literal, 0-3 = rep match, 4+ = match with distance `back - REPS`.
50
58
  */
51
59
  back = 0;
52
- /** Bytes the match finder is ahead of the encoder. */
60
+ /** Bytes the match finder is ahead of the encoder. Package-private in Java. */
53
61
  readAhead = -1;
54
62
  constructor(rc, lz, config) {
55
63
  super(config.lc, config.lp, config.pb);
56
64
  this.rc = rc;
57
65
  this.lz = lz;
58
66
  this.niceLen = config.niceLen;
67
+ this.literalEncoder = new LiteralEncoder(this, config.lc, config.lp);
59
68
  this.matchLenEncoder = new LengthEncoder(this.probs, lzma_coder_1.MATCH_LEN, config.pb, config.niceLen);
60
69
  this.repLenEncoder = new LengthEncoder(this.probs, lzma_coder_1.REP_LEN, config.pb, config.niceLen);
61
70
  this.distSlotPricesSize = getDistSlot(config.dictSize - 1) + 1;
71
+ this.distSlotPrices = newPriceArray(lzma_coder_1.DIST_STATES, this.distSlotPricesSize);
62
72
  this.reset();
63
73
  }
64
- /** Prepares for a new, independent input written to `rc`. */
74
+ /**
75
+ * Prepares for a new, independent input written to `rc` (contract
76
+ * adaptation: lets a pooled encoder be reused by a later call).
77
+ */
65
78
  restart(rc) {
66
79
  this.rc = rc;
67
80
  this.lz.reset();
@@ -77,7 +90,7 @@ class LzmaEncoder extends lzma_coder_1.LzmaCoder {
77
90
  this.alignModelUsed = false;
78
91
  this.readAhead = -1;
79
92
  }
80
- /** Encodes as much of the buffered input as the lookahead allows. */
93
+ /** Compress for LZMA1. */
81
94
  encode() {
82
95
  if (!this.lz.isStarted() && !this.encodeInit()) {
83
96
  return;
@@ -86,21 +99,26 @@ class LzmaEncoder extends lzma_coder_1.LzmaCoder {
86
99
  // Each call encodes one symbol.
87
100
  }
88
101
  }
89
- /** Encodes the end marker: a match with distance 0xFFFFFFFF. */
90
102
  encodeEndMarker() {
103
+ // End of stream marker is encoded as a match with the maximum
104
+ // possible distance. The length is ignored by the decoder,
105
+ // but the minimum length has been used by the LZMA SDK.
106
+ //
107
+ // Distance is a 32-bit unsigned integer in LZMA.
108
+ // As an int32, UINT32_MAX becomes -1.
91
109
  const posState = (this.lz.getPos() - this.readAhead) & this.posMask;
92
- this.rc.encodeBit(this.probs, lzma_coder_1.IS_MATCH + (this.state << 4) + posState, 1);
93
- this.rc.encodeBit(this.probs, lzma_coder_1.IS_REP + this.state, 0);
110
+ this.rc.encodeBit(this.probs, lzma_coder_1.IS_MATCH + (this.state.get() << 4) + posState, 1);
111
+ this.rc.encodeBit(this.probs, lzma_coder_1.IS_REP + this.state.get(), 0);
94
112
  this.encodeMatch(-1, lzma_coder_1.MATCH_LEN_MIN, posState);
95
113
  }
96
- /** The first symbol is always a literal with no previous byte. */
97
114
  encodeInit() {
98
115
  if (!this.lz.hasEnoughData(0)) {
99
116
  return false;
100
117
  }
118
+ // The first symbol must be a literal.
101
119
  this.skip(1);
102
- this.rc.encodeBit(this.probs, lzma_coder_1.IS_MATCH + (this.state << 4), 0);
103
- this.encodeLiteral(this.literalOffset(0, 0));
120
+ this.rc.encodeBit(this.probs, lzma_coder_1.IS_MATCH + (this.state.get() << 4), 0);
121
+ this.literalEncoder.encodeInit(this.rc);
104
122
  --this.readAhead;
105
123
  return true;
106
124
  }
@@ -109,105 +127,86 @@ class LzmaEncoder extends lzma_coder_1.LzmaCoder {
109
127
  return false;
110
128
  }
111
129
  const len = this.getNextSymbol();
112
- const lz = this.lz;
113
- const rc = this.rc;
114
- const probs = this.probs;
115
- const pos = lz.getPos() - this.readAhead;
116
- const posState = pos & this.posMask;
117
- const back = this.back;
118
- if (back === -1) {
119
- rc.encodeBit(probs, lzma_coder_1.IS_MATCH + (this.state << 4) + posState, 0);
120
- this.encodeLiteral(this.literalOffset(lz.getByte(1 + this.readAhead), pos));
130
+ const posState = (this.lz.getPos() - this.readAhead) & this.posMask;
131
+ if (this.back === -1) {
132
+ // Literal i.e. eight-bit byte
133
+ this.rc.encodeBit(this.probs, lzma_coder_1.IS_MATCH + (this.state.get() << 4) + posState, 0);
134
+ this.literalEncoder.encode(this.rc);
121
135
  }
122
136
  else {
123
- rc.encodeBit(probs, lzma_coder_1.IS_MATCH + (this.state << 4) + posState, 1);
124
- if (back < lzma_coder_1.REPS) {
125
- rc.encodeBit(probs, lzma_coder_1.IS_REP + this.state, 1);
126
- this.encodeRepMatch(back, len, posState);
137
+ // Some type of match
138
+ this.rc.encodeBit(this.probs, lzma_coder_1.IS_MATCH + (this.state.get() << 4) + posState, 1);
139
+ if (this.back < lzma_coder_1.REPS) {
140
+ // Repeated match i.e. the same distance
141
+ // has been used earlier.
142
+ this.rc.encodeBit(this.probs, lzma_coder_1.IS_REP + this.state.get(), 1);
143
+ this.encodeRepMatch(this.back, len, posState);
127
144
  }
128
145
  else {
129
- rc.encodeBit(probs, lzma_coder_1.IS_REP + this.state, 0);
130
- this.encodeMatch(back - lzma_coder_1.REPS, len, posState);
146
+ // Normal match
147
+ this.rc.encodeBit(this.probs, lzma_coder_1.IS_REP + this.state.get(), 0);
148
+ this.encodeMatch(this.back - lzma_coder_1.REPS, len, posState);
131
149
  }
132
150
  }
133
151
  this.readAhead -= len;
134
152
  return true;
135
153
  }
136
- encodeLiteral(offset) {
137
- const symbol = this.lz.getByte(this.readAhead);
138
- if ((0, lzma_coder_1.isLiteralState)(this.state)) {
139
- this.rc.encodeLiteral(this.probs, offset, symbol);
140
- }
141
- else {
142
- const matchByte = this.lz.getByte(this.reps[0] + 1 + this.readAhead);
143
- this.rc.encodeMatchedLiteral(this.probs, offset, symbol, matchByte);
144
- }
145
- this.state = (0, lzma_coder_1.stateAfterLiteral)(this.state);
146
- }
147
154
  encodeMatch(dist, len, posState) {
148
- const rc = this.rc;
149
- const probs = this.probs;
150
- const reps = this.reps;
151
- this.state = (0, lzma_coder_1.stateAfterMatch)(this.state);
152
- this.matchLenEncoder.encode(rc, len, posState);
155
+ this.state.updateMatch();
156
+ this.matchLenEncoder.encode(this.rc, len, posState);
153
157
  const distSlot = getDistSlot(dist);
154
- rc.encodeBitTree(probs, lzma_coder_1.DIST_SLOTS + ((0, lzma_coder_1.getDistState)(len) << lzma_coder_1.DIST_SLOT_BITS), lzma_coder_1.DIST_SLOT_BITS, distSlot);
158
+ this.rc.encodeBitTree(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, distSlot);
155
159
  this.distModelsUsed = true;
156
160
  if (distSlot >= lzma_coder_1.DIST_MODEL_START) {
157
161
  const footerBits = (distSlot >>> 1) - 1;
158
162
  const base = (2 | (distSlot & 1)) << footerBits;
159
163
  const distReduced = dist - base;
160
164
  if (distSlot < lzma_coder_1.DIST_MODEL_END) {
161
- rc.encodeReverseBitTree(probs, (0, lzma_coder_1.distSpecialOffset)(distSlot, base), footerBits, distReduced);
165
+ this.rc.encodeReverseBitTree(this.probs, (0, lzma_coder_1.distSpecialOffset)(distSlot, base), footerBits, distReduced);
162
166
  }
163
167
  else {
164
- rc.encodeDirectBits(distReduced >>> lzma_coder_1.ALIGN_BITS, footerBits - lzma_coder_1.ALIGN_BITS);
165
- rc.encodeReverseBitTree(probs, lzma_coder_1.DIST_ALIGN, lzma_coder_1.ALIGN_BITS, distReduced & lzma_coder_1.ALIGN_MASK);
168
+ this.rc.encodeDirectBits(distReduced >>> lzma_coder_1.ALIGN_BITS, footerBits - lzma_coder_1.ALIGN_BITS);
169
+ this.rc.encodeReverseBitTree(this.probs, lzma_coder_1.DIST_ALIGN, lzma_coder_1.ALIGN_BITS, distReduced & lzma_coder_1.ALIGN_MASK);
166
170
  this.alignModelUsed = true;
167
171
  --this.alignPriceCount;
168
172
  }
169
173
  }
170
- reps[3] = reps[2];
171
- reps[2] = reps[1];
172
- reps[1] = reps[0];
173
- reps[0] = dist;
174
+ this.reps[3] = this.reps[2];
175
+ this.reps[2] = this.reps[1];
176
+ this.reps[1] = this.reps[0];
177
+ this.reps[0] = dist;
174
178
  --this.distPriceCount;
175
179
  }
176
180
  encodeRepMatch(rep, len, posState) {
177
- const rc = this.rc;
178
- const probs = this.probs;
179
- const reps = this.reps;
180
- const state = this.state;
181
181
  if (rep === 0) {
182
- rc.encodeBit(probs, lzma_coder_1.IS_REP0 + state, 0);
183
- rc.encodeBit(probs, lzma_coder_1.IS_REP0_LONG + (state << 4) + posState, len === 1 ? 0 : 1);
182
+ this.rc.encodeBit(this.probs, lzma_coder_1.IS_REP0 + this.state.get(), 0);
183
+ this.rc.encodeBit(this.probs, lzma_coder_1.IS_REP0_LONG + (this.state.get() << 4) + posState, len === 1 ? 0 : 1);
184
184
  }
185
185
  else {
186
- const dist = reps[rep];
187
- rc.encodeBit(probs, lzma_coder_1.IS_REP0 + state, 1);
186
+ const dist = this.reps[rep];
187
+ this.rc.encodeBit(this.probs, lzma_coder_1.IS_REP0 + this.state.get(), 1);
188
188
  if (rep === 1) {
189
- rc.encodeBit(probs, lzma_coder_1.IS_REP1 + state, 0);
189
+ this.rc.encodeBit(this.probs, lzma_coder_1.IS_REP1 + this.state.get(), 0);
190
190
  }
191
191
  else {
192
- rc.encodeBit(probs, lzma_coder_1.IS_REP1 + state, 1);
193
- rc.encodeBit(probs, lzma_coder_1.IS_REP2 + state, rep - 2);
192
+ this.rc.encodeBit(this.probs, lzma_coder_1.IS_REP1 + this.state.get(), 1);
193
+ this.rc.encodeBit(this.probs, lzma_coder_1.IS_REP2 + this.state.get(), rep - 2);
194
194
  if (rep === 3) {
195
- reps[3] = reps[2];
195
+ this.reps[3] = this.reps[2];
196
196
  }
197
- reps[2] = reps[1];
197
+ this.reps[2] = this.reps[1];
198
198
  }
199
- reps[1] = reps[0];
200
- reps[0] = dist;
199
+ this.reps[1] = this.reps[0];
200
+ this.reps[0] = dist;
201
201
  }
202
202
  if (len === 1) {
203
- this.state = (0, lzma_coder_1.stateAfterShortRep)(state);
203
+ this.state.updateShortRep();
204
204
  }
205
205
  else {
206
- this.repLenEncoder.encode(rc, len, posState);
207
- this.state = (0, lzma_coder_1.stateAfterLongRep)(state);
206
+ this.repLenEncoder.encode(this.rc, len, posState);
207
+ this.state.updateLongRep();
208
208
  }
209
209
  }
210
- // -- Match finder access --
211
210
  getMatches() {
212
211
  ++this.readAhead;
213
212
  return this.lz.getMatches();
@@ -216,13 +215,6 @@ class LzmaEncoder extends lzma_coder_1.LzmaCoder {
216
215
  this.readAhead += len;
217
216
  this.lz.skip(len);
218
217
  }
219
- // -- Prices --
220
- getLiteralPrice(curByte, matchByte, prevByte, pos, state) {
221
- const probs = this.probs;
222
- const offset = this.literalOffset(prevByte, pos);
223
- const price = (0, range_encoder_1.getBitPrice)(probs[lzma_coder_1.IS_MATCH + (state << 4) + (pos & this.posMask)], 0);
224
- return price + ((0, lzma_coder_1.isLiteralState)(state) ? getLiteralNormalPrice(probs, offset, curByte) : getLiteralMatchedPrice(probs, offset, curByte, matchByte));
225
- }
226
218
  getAnyMatchPrice(state, posState) {
227
219
  return (0, range_encoder_1.getBitPrice)(this.probs[lzma_coder_1.IS_MATCH + (state << 4) + posState], 1);
228
220
  }
@@ -233,22 +225,20 @@ class LzmaEncoder extends lzma_coder_1.LzmaCoder {
233
225
  return anyMatchPrice + (0, range_encoder_1.getBitPrice)(this.probs[lzma_coder_1.IS_REP + state], 1);
234
226
  }
235
227
  getShortRepPrice(anyRepPrice, state, posState) {
236
- const probs = this.probs;
237
- return anyRepPrice + (0, range_encoder_1.getBitPrice)(probs[lzma_coder_1.IS_REP0 + state], 0) + (0, range_encoder_1.getBitPrice)(probs[lzma_coder_1.IS_REP0_LONG + (state << 4) + posState], 0);
228
+ return anyRepPrice + (0, range_encoder_1.getBitPrice)(this.probs[lzma_coder_1.IS_REP0 + state], 0) + (0, range_encoder_1.getBitPrice)(this.probs[lzma_coder_1.IS_REP0_LONG + (state << 4) + posState], 0);
238
229
  }
239
230
  getLongRepPrice(anyRepPrice, rep, state, posState) {
240
- const probs = this.probs;
241
231
  let price = anyRepPrice;
242
232
  if (rep === 0) {
243
- price += (0, range_encoder_1.getBitPrice)(probs[lzma_coder_1.IS_REP0 + state], 0) + (0, range_encoder_1.getBitPrice)(probs[lzma_coder_1.IS_REP0_LONG + (state << 4) + posState], 1);
233
+ price += (0, range_encoder_1.getBitPrice)(this.probs[lzma_coder_1.IS_REP0 + state], 0) + (0, range_encoder_1.getBitPrice)(this.probs[lzma_coder_1.IS_REP0_LONG + (state << 4) + posState], 1);
244
234
  }
245
235
  else {
246
- price += (0, range_encoder_1.getBitPrice)(probs[lzma_coder_1.IS_REP0 + state], 1);
236
+ price += (0, range_encoder_1.getBitPrice)(this.probs[lzma_coder_1.IS_REP0 + state], 1);
247
237
  if (rep === 1) {
248
- price += (0, range_encoder_1.getBitPrice)(probs[lzma_coder_1.IS_REP1 + state], 0);
238
+ price += (0, range_encoder_1.getBitPrice)(this.probs[lzma_coder_1.IS_REP1 + state], 0);
249
239
  }
250
240
  else {
251
- price += (0, range_encoder_1.getBitPrice)(probs[lzma_coder_1.IS_REP1 + state], 1) + (0, range_encoder_1.getBitPrice)(probs[lzma_coder_1.IS_REP2 + state], rep - 2);
241
+ price += (0, range_encoder_1.getBitPrice)(this.probs[lzma_coder_1.IS_REP1 + state], 1) + (0, range_encoder_1.getBitPrice)(this.probs[lzma_coder_1.IS_REP2 + state], rep - 2);
252
242
  }
253
243
  }
254
244
  return price;
@@ -259,27 +249,17 @@ class LzmaEncoder extends lzma_coder_1.LzmaCoder {
259
249
  const longRepPrice = this.getLongRepPrice(anyRepPrice, rep, state, posState);
260
250
  return longRepPrice + this.repLenEncoder.getPrice(len, posState);
261
251
  }
262
- getMatchAndLenPrice(normalMatchPrice, dist, len, posState) {
263
- return normalMatchPrice + this.matchLenEncoder.getPrice(len, posState) + this.getDistPrice((0, lzma_coder_1.getDistState)(len), dist);
264
- }
265
- /** Price of coding `dist` in distance state `distState`. */
266
252
  getDistPrice(distState, dist) {
267
253
  if (dist < lzma_coder_1.FULL_DISTANCES) {
268
- return this.fullDistPrices[distState * lzma_coder_1.FULL_DISTANCES + dist];
254
+ return this.fullDistPrices[distState][dist];
269
255
  }
270
- // distSlotPrices includes the price of the direct bits.
271
- return this.distSlotPrices[(distState << lzma_coder_1.DIST_SLOT_BITS) + getDistSlot(dist)] + this.alignPrices[dist & lzma_coder_1.ALIGN_MASK];
256
+ // Note that distSlotPrices includes also
257
+ // the price of direct bits.
258
+ const distSlot = getDistSlot(dist);
259
+ return this.distSlotPrices[distState][distSlot] + this.alignPrices[dist & lzma_coder_1.ALIGN_MASK];
272
260
  }
273
- /** Refreshes the price tables that are due for an update. */
274
- updatePrices() {
275
- if (this.distPriceCount <= 0) {
276
- this.updateDistPrices();
277
- }
278
- if (this.alignPriceCount <= 0) {
279
- this.updateAlignPrices();
280
- }
281
- this.matchLenEncoder.updatePrices();
282
- this.repLenEncoder.updatePrices();
261
+ getMatchAndLenPrice(normalMatchPrice, dist, len, posState) {
262
+ return normalMatchPrice + this.matchLenEncoder.getPrice(len, posState) + this.getDistPrice((0, lzma_coder_1.getDistState)(len), dist);
283
263
  }
284
264
  updateDistPrices() {
285
265
  this.distPriceCount = DIST_PRICE_UPDATE_INTERVAL;
@@ -289,8 +269,10 @@ class LzmaEncoder extends lzma_coder_1.LzmaCoder {
289
269
  else {
290
270
  // The models still have their initial probabilities.
291
271
  const initial = getInitialPrices();
292
- this.distSlotPrices.set(initial.distSlots);
293
- this.fullDistPrices.set(initial.fullDists);
272
+ for (let distState = 0; distState < lzma_coder_1.DIST_STATES; ++distState) {
273
+ this.distSlotPrices[distState].set(initial.distSlotPrices[distState].subarray(0, this.distSlotPricesSize));
274
+ this.fullDistPrices[distState].set(initial.fullDistPrices[distState]);
275
+ }
294
276
  }
295
277
  }
296
278
  updateAlignPrices() {
@@ -299,40 +281,49 @@ class LzmaEncoder extends lzma_coder_1.LzmaCoder {
299
281
  computeAlignPrices(this.probs, this.alignPrices);
300
282
  }
301
283
  else {
302
- this.alignPrices.set(getInitialPrices().align);
284
+ this.alignPrices.set(getInitialPrices().alignPrices);
285
+ }
286
+ }
287
+ /**
288
+ * Updates the lookup tables used for calculating match distance
289
+ * and length prices. The updating is skipped for performance reasons
290
+ * if the tables haven't changed much since the previous update.
291
+ */
292
+ updatePrices() {
293
+ if (this.distPriceCount <= 0) {
294
+ this.updateDistPrices();
303
295
  }
296
+ if (this.alignPriceCount <= 0) {
297
+ this.updateAlignPrices();
298
+ }
299
+ this.matchLenEncoder.updatePrices();
300
+ this.repLenEncoder.updatePrices();
304
301
  }
305
302
  }
306
303
  exports.LzmaEncoder = LzmaEncoder;
307
- /**
308
- * Prices of the distance slots `[distState << 6 | slot]` (including the
309
- * direct bits) and of the distances below `FULL_DISTANCES`
310
- * `[distState * FULL_DISTANCES + dist]`.
311
- */
312
- function computeDistPrices(probs, slotCount, slotPrices, fullPrices) {
304
+ function computeDistPrices(probs, distSlotPricesSize, distSlotPrices, fullDistPrices) {
313
305
  for (let distState = 0; distState < lzma_coder_1.DIST_STATES; ++distState) {
314
- const slots = distState << lzma_coder_1.DIST_SLOT_BITS;
315
- const tree = lzma_coder_1.DIST_SLOTS + slots;
316
- for (let distSlot = 0; distSlot < slotCount; ++distSlot) {
317
- slotPrices[slots + distSlot] = (0, range_encoder_1.getBitTreePrice)(probs, tree, lzma_coder_1.DIST_SLOT_BITS, distSlot);
306
+ for (let distSlot = 0; distSlot < distSlotPricesSize; ++distSlot) {
307
+ distSlotPrices[distState][distSlot] = (0, range_encoder_1.getBitTreePrice)(probs, lzma_coder_1.DIST_SLOT_OFFSET + (distState << lzma_coder_1.DIST_SLOT_BITS), lzma_coder_1.DIST_SLOT_BITS, distSlot);
318
308
  }
319
- for (let distSlot = lzma_coder_1.DIST_MODEL_END; distSlot < slotCount; ++distSlot) {
309
+ for (let distSlot = lzma_coder_1.DIST_MODEL_END; distSlot < distSlotPricesSize; ++distSlot) {
320
310
  const count = (distSlot >>> 1) - 1 - lzma_coder_1.ALIGN_BITS;
321
- slotPrices[slots + distSlot] += (0, range_encoder_1.getDirectBitsPrice)(count);
311
+ distSlotPrices[distState][distSlot] += (0, range_encoder_1.getDirectBitsPrice)(count);
322
312
  }
323
313
  for (let dist = 0; dist < lzma_coder_1.DIST_MODEL_START; ++dist) {
324
- fullPrices[distState * lzma_coder_1.FULL_DISTANCES + dist] = slotPrices[slots + dist];
314
+ fullDistPrices[distState][dist] = distSlotPrices[distState][dist];
325
315
  }
326
316
  }
327
317
  let dist = lzma_coder_1.DIST_MODEL_START;
328
318
  for (let distSlot = lzma_coder_1.DIST_MODEL_START; distSlot < lzma_coder_1.DIST_MODEL_END; ++distSlot) {
329
319
  const footerBits = (distSlot >>> 1) - 1;
330
320
  const base = (2 | (distSlot & 1)) << footerBits;
331
- const tree = (0, lzma_coder_1.distSpecialOffset)(distSlot, base);
332
- for (let i = 0; i < 1 << footerBits; ++i) {
333
- const price = (0, range_encoder_1.getReverseBitTreePrice)(probs, tree, footerBits, dist - base);
321
+ const limit = 1 << footerBits;
322
+ for (let i = 0; i < limit; ++i) {
323
+ const distReduced = dist - base;
324
+ const price = (0, range_encoder_1.getReverseBitTreePrice)(probs, (0, lzma_coder_1.distSpecialOffset)(distSlot, base), footerBits, distReduced);
334
325
  for (let distState = 0; distState < lzma_coder_1.DIST_STATES; ++distState) {
335
- fullPrices[distState * lzma_coder_1.FULL_DISTANCES + dist] = slotPrices[(distState << lzma_coder_1.DIST_SLOT_BITS) + distSlot] + price;
326
+ fullDistPrices[distState][dist] = distSlotPrices[distState][distSlot] + price;
336
327
  }
337
328
  ++dist;
338
329
  }
@@ -343,155 +334,221 @@ function computeAlignPrices(probs, alignPrices) {
343
334
  alignPrices[i] = (0, range_encoder_1.getReverseBitTreePrice)(probs, lzma_coder_1.DIST_ALIGN, lzma_coder_1.ALIGN_BITS, i);
344
335
  }
345
336
  }
346
- /**
347
- * Prices of `count` lengths for `posState` with the length coder at
348
- * `coder`, written to `prices` from `start`.
349
- */
350
- function computeLengthPrices(probs, coder, posState, prices, start, count) {
351
- const end = start + count;
352
- let i = 0;
353
- let choice0Price = (0, range_encoder_1.getBitPrice)(probs[coder + lzma_coder_1.LEN_CHOICE], 0);
354
- const low = coder + lzma_coder_1.LEN_LOW + posState * lzma_coder_1.LOW_SYMBOLS;
355
- for (; i < lzma_coder_1.LOW_SYMBOLS; ++i) {
356
- prices[start + i] = choice0Price + (0, range_encoder_1.getBitTreePrice)(probs, low, 3, i);
337
+ function newPriceArray(count, size) {
338
+ return Array.from({ length: count }, () => new Int32Array(size));
339
+ }
340
+ class LiteralEncoder extends lzma_coder_1.LiteralCoder {
341
+ encoder;
342
+ subencoders;
343
+ constructor(encoder, lc, lp) {
344
+ super(lc, lp);
345
+ this.encoder = encoder;
346
+ this.subencoders = Array.from({ length: 1 << (lc + lp) }, (_, i) => new LiteralSubencoder(encoder, lzma_coder_1.LITERAL + 0x300 * i));
347
+ }
348
+ encodeInit(rc) {
349
+ // When encoding the first byte of the stream, there is
350
+ // no previous byte in the dictionary so the encode function
351
+ // wouldn't work.
352
+ this.subencoders[0].encode(rc);
353
+ }
354
+ encode(rc) {
355
+ const encoder = this.encoder;
356
+ const i = this.getSubcoderIndex(encoder.lz.getByte(1 + encoder.readAhead), encoder.lz.getPos() - encoder.readAhead);
357
+ this.subencoders[i].encode(rc);
358
+ }
359
+ getPrice(curByte, matchByte, prevByte, pos, state) {
360
+ const encoder = this.encoder;
361
+ let price = (0, range_encoder_1.getBitPrice)(encoder.probs[lzma_coder_1.IS_MATCH + (state << 4) + (pos & encoder.posMask)], 0);
362
+ const i = this.getSubcoderIndex(prevByte, pos);
363
+ price += (0, lzma_coder_1.isLiteralState)(state) ? this.subencoders[i].getNormalPrice(curByte) : this.subencoders[i].getMatchedPrice(curByte, matchByte);
364
+ return price;
357
365
  }
358
- choice0Price = (0, range_encoder_1.getBitPrice)(probs[coder + lzma_coder_1.LEN_CHOICE], 1);
359
- let choice1Price = (0, range_encoder_1.getBitPrice)(probs[coder + lzma_coder_1.LEN_CHOICE2], 0);
360
- const mid = coder + lzma_coder_1.LEN_MID + posState * lzma_coder_1.MID_SYMBOLS;
361
- for (; i < lzma_coder_1.LOW_SYMBOLS + lzma_coder_1.MID_SYMBOLS; ++i) {
362
- prices[start + i] = choice0Price + choice1Price + (0, range_encoder_1.getBitTreePrice)(probs, mid, 3, i - lzma_coder_1.LOW_SYMBOLS);
366
+ }
367
+ exports.LiteralEncoder = LiteralEncoder;
368
+ class LiteralSubencoder extends lzma_coder_1.LiteralSubcoder {
369
+ encoder;
370
+ constructor(encoder, literalOffset) {
371
+ super(encoder.probs, literalOffset);
372
+ this.encoder = encoder;
373
+ }
374
+ encode(rc) {
375
+ const encoder = this.encoder;
376
+ const probs = this.probs;
377
+ let symbol = encoder.lz.getByte(encoder.readAhead) | 0x100;
378
+ if (encoder.state.isLiteral()) {
379
+ let subencoderIndex;
380
+ let bit;
381
+ do {
382
+ subencoderIndex = symbol >>> 8;
383
+ bit = (symbol >>> 7) & 1;
384
+ rc.encodeBit(probs, this.literalOffset + subencoderIndex, bit);
385
+ symbol <<= 1;
386
+ } while (symbol < 0x10000);
387
+ }
388
+ else {
389
+ let matchByte = encoder.lz.getByte(encoder.reps[0] + 1 + encoder.readAhead);
390
+ let offset = 0x100;
391
+ let subencoderIndex;
392
+ let matchBit;
393
+ let bit;
394
+ do {
395
+ matchByte <<= 1;
396
+ matchBit = matchByte & offset;
397
+ subencoderIndex = offset + matchBit + (symbol >>> 8);
398
+ bit = (symbol >>> 7) & 1;
399
+ rc.encodeBit(probs, this.literalOffset + subencoderIndex, bit);
400
+ symbol <<= 1;
401
+ offset &= ~(matchByte ^ symbol);
402
+ } while (symbol < 0x10000);
403
+ }
404
+ encoder.state.updateLiteral();
363
405
  }
364
- choice1Price = (0, range_encoder_1.getBitPrice)(probs[coder + lzma_coder_1.LEN_CHOICE2], 1);
365
- for (; start + i < end; ++i) {
366
- prices[start + i] = choice0Price + choice1Price + (0, range_encoder_1.getBitTreePrice)(probs, coder + lzma_coder_1.LEN_HIGH, 8, i - lzma_coder_1.LOW_SYMBOLS - lzma_coder_1.MID_SYMBOLS);
406
+ getNormalPrice(symbolIn) {
407
+ let symbol = symbolIn;
408
+ const probs = this.probs;
409
+ let price = 0;
410
+ let subencoderIndex;
411
+ let bit;
412
+ symbol |= 0x100;
413
+ do {
414
+ subencoderIndex = symbol >>> 8;
415
+ bit = (symbol >>> 7) & 1;
416
+ price += (0, range_encoder_1.getBitPrice)(probs[this.literalOffset + subencoderIndex], bit);
417
+ symbol <<= 1;
418
+ } while (symbol < 0x100 << 8);
419
+ return price;
367
420
  }
368
- }
369
- let initialPrices;
370
- /**
371
- * Price tables for models that still have their initial probabilities.
372
- * They are the same for every encoder, so they are computed once. Copying
373
- * them saves about a quarter of the time of compressing a small input.
374
- */
375
- function getInitialPrices() {
376
- if (initialPrices === undefined) {
377
- const probs = new Uint16Array(lzma_coder_1.LITERAL);
378
- (0, range_coder_1.initProbs)(probs);
379
- const distSlots = new Uint32Array(lzma_coder_1.DIST_STATES << lzma_coder_1.DIST_SLOT_BITS);
380
- const fullDists = new Uint32Array(lzma_coder_1.DIST_STATES * lzma_coder_1.FULL_DISTANCES);
381
- computeDistPrices(probs, lzma_coder_1.DIST_SLOT_COUNT, distSlots, fullDists);
382
- const align = new Uint32Array(lzma_coder_1.ALIGN_SIZE);
383
- computeAlignPrices(probs, align);
384
- const lengths = new Uint32Array(lzma_coder_1.MATCH_LEN_MAX - lzma_coder_1.MATCH_LEN_MIN + 1);
385
- computeLengthPrices(probs, lzma_coder_1.MATCH_LEN, 0, lengths, 0, lengths.length);
386
- initialPrices = { distSlots, fullDists, align, lengths };
421
+ getMatchedPrice(symbolIn, matchByteIn) {
422
+ let symbol = symbolIn;
423
+ let matchByte = matchByteIn;
424
+ const probs = this.probs;
425
+ let price = 0;
426
+ let offset = 0x100;
427
+ let subencoderIndex;
428
+ let matchBit;
429
+ let bit;
430
+ symbol |= 0x100;
431
+ do {
432
+ matchByte <<= 1;
433
+ matchBit = matchByte & offset;
434
+ subencoderIndex = offset + matchBit + (symbol >>> 8);
435
+ bit = (symbol >>> 7) & 1;
436
+ price += (0, range_encoder_1.getBitPrice)(probs[this.literalOffset + subencoderIndex], bit);
437
+ symbol <<= 1;
438
+ offset &= ~(matchByte ^ symbol);
439
+ } while (symbol < 0x100 << 8);
440
+ return price;
387
441
  }
388
- return initialPrices;
389
- }
390
- function getLiteralNormalPrice(probs, offset, symbolIn) {
391
- let symbol = symbolIn;
392
- let price = 0;
393
- symbol |= 0x100;
394
- do {
395
- price += (0, range_encoder_1.getBitPrice)(probs[offset + (symbol >>> 8)], (symbol >>> 7) & 1);
396
- symbol <<= 1;
397
- } while (symbol < 0x10000);
398
- return price;
399
442
  }
400
- function getLiteralMatchedPrice(probs, offset, symbolIn, matchByteIn) {
401
- let symbol = symbolIn;
402
- let matchByte = matchByteIn;
403
- let price = 0;
404
- let matchOffset = 0x100;
405
- symbol |= 0x100;
406
- do {
407
- matchByte <<= 1;
408
- const matchBit = matchByte & matchOffset;
409
- price += (0, range_encoder_1.getBitPrice)(probs[offset + matchOffset + matchBit + (symbol >>> 8)], (symbol >>> 7) & 1);
410
- symbol <<= 1;
411
- matchOffset &= ~(matchByte ^ symbol);
412
- } while (symbol < 0x10000);
413
- return price;
414
- }
415
- /**
416
- * Length encoder with cached prices. Prices of each position state are
417
- * recalculated after every `LEN_PRICE_UPDATE_INTERVAL` encoded lengths.
418
- */
419
- class LengthEncoder {
420
- probs;
421
- /** Offset of this length coder in `probs`. */
422
- coder;
443
+ class LengthEncoder extends lzma_coder_1.LengthCoder {
444
+ /**
445
+ * The prices are updated after at least
446
+ * `PRICE_UPDATE_INTERVAL` many lengths
447
+ * have been encoded with the same posState.
448
+ */
449
+ static PRICE_UPDATE_INTERVAL = 32;
423
450
  counters;
451
+ prices;
424
452
  /** Whether a length was encoded since the last reset. */
425
453
  used = false;
426
- /** Prices per position state, `[posState * lenSymbols + len - MATCH_LEN_MIN]`. */
427
- prices;
428
- lenSymbols;
429
454
  constructor(probs, coder, pb, niceLen) {
430
- this.probs = probs;
431
- this.coder = coder;
455
+ super(probs, coder);
432
456
  const posStates = 1 << pb;
433
457
  this.counters = new Int32Array(posStates);
434
- // Always allocate at least LOW_SYMBOLS + MID_SYMBOLS entries to keep
435
- // updatePrices() simple.
436
- this.lenSymbols = Math.max(niceLen - lzma_coder_1.MATCH_LEN_MIN + 1, lzma_coder_1.LOW_SYMBOLS + lzma_coder_1.MID_SYMBOLS);
437
- this.prices = new Uint32Array(posStates * this.lenSymbols);
458
+ // Always allocate at least LOW_SYMBOLS + MID_SYMBOLS because
459
+ // it makes updatePrices slightly simpler. The prices aren't
460
+ // usually needed anyway if niceLen < 18.
461
+ const lenSymbols = Math.max(niceLen - lzma_coder_1.MATCH_LEN_MIN + 1, lzma_coder_1.LOW_SYMBOLS + lzma_coder_1.MID_SYMBOLS);
462
+ this.prices = newPriceArray(posStates, lenSymbols);
438
463
  }
439
464
  reset() {
440
- // Zero counters force a price update before the prices are needed.
465
+ // Reset counters to zero to force price update before
466
+ // the prices are needed.
441
467
  this.counters.fill(0);
442
468
  this.used = false;
443
469
  }
444
470
  encode(rc, lenIn, posState) {
445
471
  let len = lenIn;
446
- const probs = this.probs;
447
- const coder = this.coder;
448
472
  len -= lzma_coder_1.MATCH_LEN_MIN;
449
473
  if (len < lzma_coder_1.LOW_SYMBOLS) {
450
- rc.encodeBit(probs, coder + lzma_coder_1.LEN_CHOICE, 0);
451
- rc.encodeBitTree(probs, coder + lzma_coder_1.LEN_LOW + posState * lzma_coder_1.LOW_SYMBOLS, 3, len);
474
+ rc.encodeBit(this.probs, this.coder + lzma_coder_1.LEN_CHOICE, 0);
475
+ rc.encodeBitTree(this.probs, this.coder + lzma_coder_1.LEN_LOW + posState * lzma_coder_1.LOW_SYMBOLS, 3, len);
452
476
  }
453
477
  else {
454
- rc.encodeBit(probs, coder + lzma_coder_1.LEN_CHOICE, 1);
478
+ rc.encodeBit(this.probs, this.coder + lzma_coder_1.LEN_CHOICE, 1);
455
479
  len -= lzma_coder_1.LOW_SYMBOLS;
456
480
  if (len < lzma_coder_1.MID_SYMBOLS) {
457
- rc.encodeBit(probs, coder + lzma_coder_1.LEN_CHOICE2, 0);
458
- rc.encodeBitTree(probs, coder + lzma_coder_1.LEN_MID + posState * lzma_coder_1.MID_SYMBOLS, 3, len);
481
+ rc.encodeBit(this.probs, this.coder + lzma_coder_1.LEN_CHOICE2, 0);
482
+ rc.encodeBitTree(this.probs, this.coder + lzma_coder_1.LEN_MID + posState * lzma_coder_1.MID_SYMBOLS, 3, len);
459
483
  }
460
484
  else {
461
- rc.encodeBit(probs, coder + lzma_coder_1.LEN_CHOICE2, 1);
462
- rc.encodeBitTree(probs, coder + lzma_coder_1.LEN_HIGH, 8, len - lzma_coder_1.MID_SYMBOLS);
485
+ rc.encodeBit(this.probs, this.coder + lzma_coder_1.LEN_CHOICE2, 1);
486
+ rc.encodeBitTree(this.probs, this.coder + lzma_coder_1.LEN_HIGH, 8, len - lzma_coder_1.MID_SYMBOLS);
463
487
  }
464
488
  }
465
489
  --this.counters[posState];
466
490
  this.used = true;
467
491
  }
468
492
  getPrice(len, posState) {
469
- return this.prices[posState * this.lenSymbols + len - lzma_coder_1.MATCH_LEN_MIN];
493
+ return this.prices[posState][len - lzma_coder_1.MATCH_LEN_MIN];
470
494
  }
471
- /** Offset in `prices` such that `prices[offset + len]` is the price of `len`. */
472
- priceOffset(posState) {
473
- return posState * this.lenSymbols - lzma_coder_1.MATCH_LEN_MIN;
495
+ getPriceRow(posState) {
496
+ return this.prices[posState];
474
497
  }
475
498
  updatePrices() {
476
499
  for (let posState = 0; posState < this.counters.length; ++posState) {
477
500
  if (this.counters[posState] <= 0) {
478
- this.counters[posState] = LEN_PRICE_UPDATE_INTERVAL;
501
+ this.counters[posState] = LengthEncoder.PRICE_UPDATE_INTERVAL;
479
502
  this.updatePosStatePrices(posState);
480
503
  }
481
504
  }
482
505
  }
483
506
  updatePosStatePrices(posState) {
484
- const start = posState * this.lenSymbols;
485
507
  if (this.used) {
486
- computeLengthPrices(this.probs, this.coder, posState, this.prices, start, this.lenSymbols);
508
+ computeLengthPrices(this.probs, this.coder, posState, this.prices[posState]);
487
509
  }
488
510
  else {
489
511
  // The model still has its initial probabilities.
490
- const initial = getInitialPrices().lengths;
491
- for (let i = 0; i < this.lenSymbols; ++i) {
492
- this.prices[start + i] = initial[i];
493
- }
512
+ const prices = this.prices[posState];
513
+ prices.set(getInitialPrices().lengthPrices.subarray(0, prices.length));
494
514
  }
495
515
  }
496
516
  }
497
517
  exports.LengthEncoder = LengthEncoder;
518
+ function computeLengthPrices(probs, coder, posState, prices) {
519
+ let choice0Price = (0, range_encoder_1.getBitPrice)(probs[coder + lzma_coder_1.LEN_CHOICE], 0);
520
+ let i = 0;
521
+ for (; i < lzma_coder_1.LOW_SYMBOLS; ++i) {
522
+ prices[i] = choice0Price + (0, range_encoder_1.getBitTreePrice)(probs, coder + lzma_coder_1.LEN_LOW + posState * lzma_coder_1.LOW_SYMBOLS, 3, i);
523
+ }
524
+ choice0Price = (0, range_encoder_1.getBitPrice)(probs[coder + lzma_coder_1.LEN_CHOICE], 1);
525
+ let choice1Price = (0, range_encoder_1.getBitPrice)(probs[coder + lzma_coder_1.LEN_CHOICE2], 0);
526
+ for (; i < lzma_coder_1.LOW_SYMBOLS + lzma_coder_1.MID_SYMBOLS; ++i) {
527
+ prices[i] = choice0Price + choice1Price + (0, range_encoder_1.getBitTreePrice)(probs, coder + lzma_coder_1.LEN_MID + posState * lzma_coder_1.MID_SYMBOLS, 3, i - lzma_coder_1.LOW_SYMBOLS);
528
+ }
529
+ choice1Price = (0, range_encoder_1.getBitPrice)(probs[coder + lzma_coder_1.LEN_CHOICE2], 1);
530
+ for (; i < prices.length; ++i) {
531
+ prices[i] = choice0Price + choice1Price + (0, range_encoder_1.getBitTreePrice)(probs, coder + lzma_coder_1.LEN_HIGH, 8, i - lzma_coder_1.LOW_SYMBOLS - lzma_coder_1.MID_SYMBOLS);
532
+ }
533
+ }
534
+ let initialPrices;
535
+ /**
536
+ * Price tables for models that still have their initial probabilities.
537
+ * They are the same for every encoder, so they are computed once, by the
538
+ * same functions the encoders use, on an array of initial probabilities.
539
+ */
540
+ function getInitialPrices() {
541
+ if (initialPrices === undefined) {
542
+ const probs = new Uint16Array(lzma_coder_1.LITERAL);
543
+ (0, range_coder_1.initProbs)(probs);
544
+ const distSlotPrices = newPriceArray(lzma_coder_1.DIST_STATES, lzma_coder_1.DIST_SLOTS);
545
+ const fullDistPrices = newPriceArray(lzma_coder_1.DIST_STATES, lzma_coder_1.FULL_DISTANCES);
546
+ computeDistPrices(probs, lzma_coder_1.DIST_SLOTS, distSlotPrices, fullDistPrices);
547
+ const alignPrices = new Int32Array(lzma_coder_1.ALIGN_SIZE);
548
+ computeAlignPrices(probs, alignPrices);
549
+ const lengthPrices = new Int32Array(lzma_coder_1.MATCH_LEN_MAX - lzma_coder_1.MATCH_LEN_MIN + 1);
550
+ computeLengthPrices(probs, lzma_coder_1.MATCH_LEN, 0, lengthPrices);
551
+ initialPrices = { distSlotPrices, fullDistPrices, alignPrices, lengthPrices };
552
+ }
553
+ return initialPrices;
554
+ }