brotli-lib 0.0.1

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.
Files changed (74) hide show
  1. package/LICENSE +22 -0
  2. package/LICENSE_THIRD_PARTY +88 -0
  3. package/README.md +112 -0
  4. package/dist/decode/bit-reader.d.ts +31 -0
  5. package/dist/decode/bit-reader.d.ts.map +1 -0
  6. package/dist/decode/decode.d.ts +7 -0
  7. package/dist/decode/decode.d.ts.map +1 -0
  8. package/dist/decode/dictionary-bin.d.ts +2 -0
  9. package/dist/decode/dictionary-bin.d.ts.map +1 -0
  10. package/dist/decode/dictionary.d.ts +8 -0
  11. package/dist/decode/dictionary.d.ts.map +1 -0
  12. package/dist/decode/engine.d.ts +93 -0
  13. package/dist/decode/engine.d.ts.map +1 -0
  14. package/dist/decode/index.d.ts +3 -0
  15. package/dist/decode/index.d.ts.map +1 -0
  16. package/dist/decode/streams.d.ts +13 -0
  17. package/dist/decode/streams.d.ts.map +1 -0
  18. package/dist/decode.cjs +2138 -0
  19. package/dist/decode.d.ts +3 -0
  20. package/dist/decode.d.ts.map +1 -0
  21. package/dist/decode.js +2135 -0
  22. package/dist/encode/backward-references-hq.d.ts +13 -0
  23. package/dist/encode/backward-references-hq.d.ts.map +1 -0
  24. package/dist/encode/backward-references.d.ts +14 -0
  25. package/dist/encode/backward-references.d.ts.map +1 -0
  26. package/dist/encode/bit-cost.d.ts +11 -0
  27. package/dist/encode/bit-cost.d.ts.map +1 -0
  28. package/dist/encode/bit-writer.d.ts +25 -0
  29. package/dist/encode/bit-writer.d.ts.map +1 -0
  30. package/dist/encode/block-splitter.d.ts +12 -0
  31. package/dist/encode/block-splitter.d.ts.map +1 -0
  32. package/dist/encode/cluster.d.ts +25 -0
  33. package/dist/encode/cluster.d.ts.map +1 -0
  34. package/dist/encode/command.d.ts +28 -0
  35. package/dist/encode/command.d.ts.map +1 -0
  36. package/dist/encode/context-map.d.ts +13 -0
  37. package/dist/encode/context-map.d.ts.map +1 -0
  38. package/dist/encode/context.d.ts +14 -0
  39. package/dist/encode/context.d.ts.map +1 -0
  40. package/dist/encode/enc-constants.d.ts +92 -0
  41. package/dist/encode/enc-constants.d.ts.map +1 -0
  42. package/dist/encode/encode.d.ts +39 -0
  43. package/dist/encode/encode.d.ts.map +1 -0
  44. package/dist/encode/entropy-encode.d.ts +20 -0
  45. package/dist/encode/entropy-encode.d.ts.map +1 -0
  46. package/dist/encode/fast-log.d.ts +7 -0
  47. package/dist/encode/fast-log.d.ts.map +1 -0
  48. package/dist/encode/hash-binary-tree.d.ts +23 -0
  49. package/dist/encode/hash-binary-tree.d.ts.map +1 -0
  50. package/dist/encode/hash-chains.d.ts +20 -0
  51. package/dist/encode/hash-chains.d.ts.map +1 -0
  52. package/dist/encode/hash-simple.d.ts +19 -0
  53. package/dist/encode/hash-simple.d.ts.map +1 -0
  54. package/dist/encode/histogram.d.ts +61 -0
  55. package/dist/encode/histogram.d.ts.map +1 -0
  56. package/dist/encode/index.d.ts +4 -0
  57. package/dist/encode/index.d.ts.map +1 -0
  58. package/dist/encode/match.d.ts +31 -0
  59. package/dist/encode/match.d.ts.map +1 -0
  60. package/dist/encode/metablock.d.ts +48 -0
  61. package/dist/encode/metablock.d.ts.map +1 -0
  62. package/dist/encode/static-dict.d.ts +26 -0
  63. package/dist/encode/static-dict.d.ts.map +1 -0
  64. package/dist/encode/zopfli-cost-model.d.ts +21 -0
  65. package/dist/encode/zopfli-cost-model.d.ts.map +1 -0
  66. package/dist/encode.cjs +2426 -0
  67. package/dist/encode.d.ts +4 -0
  68. package/dist/encode.d.ts.map +1 -0
  69. package/dist/encode.js +2422 -0
  70. package/dist/index.cjs +4562 -0
  71. package/dist/index.d.ts +6 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/dist/index.js +4556 -0
  74. package/package.json +66 -0
@@ -0,0 +1,2426 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ //#region src/encode/bit-writer.ts
4
+ var BitWriter = class {
5
+ constructor(initialSize = 4096) {
6
+ this.buffer = new Uint8Array(initialSize);
7
+ this.pos = 0;
8
+ this.flushedBytePos = 0;
9
+ }
10
+ ensureCapacity(bits) {
11
+ const bytesNeeded = (this.pos + bits + 7 >>> 3) + 1;
12
+ if (bytesNeeded > this.buffer.length) {
13
+ const newSize = Math.max(this.buffer.length * 2, bytesNeeded);
14
+ const newBuffer = new Uint8Array(newSize);
15
+ newBuffer.set(this.buffer);
16
+ this.buffer = newBuffer;
17
+ }
18
+ }
19
+ writeBits(nBits, value) {
20
+ this.ensureCapacity(nBits);
21
+ const bytePos = this.pos >>> 3;
22
+ const bitOffset = this.pos & 7;
23
+ let v = this.buffer[bytePos] | 0;
24
+ v |= value << bitOffset;
25
+ this.buffer[bytePos] = v & 255;
26
+ let bitsWritten = 8 - bitOffset;
27
+ let remaining = value >>> bitsWritten;
28
+ let pos = bytePos + 1;
29
+ while (bitsWritten < nBits) {
30
+ this.buffer[pos++] = remaining & 255;
31
+ remaining >>>= 8;
32
+ bitsWritten += 8;
33
+ }
34
+ this.pos += nBits;
35
+ }
36
+ writeBitsLong(nBits, value) {
37
+ if (nBits <= 25) {
38
+ this.writeBits(nBits, Number(value));
39
+ return;
40
+ }
41
+ this.ensureCapacity(nBits);
42
+ const bytePos = this.pos >>> 3;
43
+ const bitOffset = this.pos & 7;
44
+ let v = value << BigInt(bitOffset);
45
+ const bytesToWrite = nBits + bitOffset + 7 >>> 3;
46
+ this.buffer[bytePos] |= Number(v & 255n);
47
+ v >>= 8n;
48
+ for (let i = 1; i < bytesToWrite; i++) {
49
+ this.buffer[bytePos + i] = Number(v & 255n);
50
+ v >>= 8n;
51
+ }
52
+ this.pos += nBits;
53
+ }
54
+ writeBit(bit) {
55
+ this.writeBits(1, bit & 1);
56
+ }
57
+ writeByte(byte) {
58
+ if ((this.pos & 7) !== 0) throw new Error("BitWriter not byte-aligned");
59
+ this.ensureCapacity(8);
60
+ this.buffer[this.pos >>> 3] = byte & 255;
61
+ this.pos += 8;
62
+ }
63
+ writeBytes(bytes) {
64
+ if ((this.pos & 7) !== 0) throw new Error("BitWriter not byte-aligned");
65
+ this.ensureCapacity(bytes.length * 8);
66
+ this.buffer.set(bytes, this.pos >>> 3);
67
+ this.pos += bytes.length * 8;
68
+ }
69
+ alignToByte() {
70
+ const padding = 8 - (this.pos & 7) & 7;
71
+ if (padding > 0) this.writeBits(padding, 0);
72
+ return padding;
73
+ }
74
+ get bytePos() {
75
+ return this.pos >>> 3;
76
+ }
77
+ get bitOffset() {
78
+ return this.pos & 7;
79
+ }
80
+ reset() {
81
+ this.pos = 0;
82
+ this.flushedBytePos = 0;
83
+ this.buffer.fill(0);
84
+ }
85
+ takeBytes() {
86
+ const end = this.pos >>> 3;
87
+ if (end <= this.flushedBytePos) return new Uint8Array(0);
88
+ const out = this.buffer.slice(this.flushedBytePos, end);
89
+ this.flushedBytePos = end;
90
+ return out;
91
+ }
92
+ finish() {
93
+ const byteLength = this.pos + 7 >>> 3;
94
+ return this.buffer.slice(0, byteLength);
95
+ }
96
+ prepareStorage() {
97
+ if ((this.pos & 7) !== 0) throw new Error("prepareStorage requires byte alignment");
98
+ this.ensureCapacity(8);
99
+ this.buffer[this.pos >>> 3] = 0;
100
+ }
101
+ };
102
+ function encodeWindowBits(lgwin, largeWindow) {
103
+ if (largeWindow) return {
104
+ value: (lgwin & 63) << 8 | 17,
105
+ bits: 14
106
+ };
107
+ if (lgwin === 16) return {
108
+ value: 0,
109
+ bits: 1
110
+ };
111
+ else if (lgwin === 17) return {
112
+ value: 1,
113
+ bits: 7
114
+ };
115
+ else if (lgwin > 17 && lgwin <= 24) return {
116
+ value: lgwin - 17 << 1 | 1,
117
+ bits: 4
118
+ };
119
+ else return {
120
+ value: lgwin - 8 << 4 | 1,
121
+ bits: 7
122
+ };
123
+ }
124
+
125
+ //#endregion
126
+ //#region src/encode/enc-constants.ts
127
+ const FAST_ONE_PASS_COMPRESSION_QUALITY = 0;
128
+ const FAST_TWO_PASS_COMPRESSION_QUALITY = 1;
129
+ const ZOPFLIFICATION_QUALITY = 10;
130
+ const HQ_ZOPFLIFICATION_QUALITY = 11;
131
+ const MIN_QUALITY = 0;
132
+ const MAX_QUALITY = 11;
133
+ const DEFAULT_QUALITY = 11;
134
+ const MAX_QUALITY_FOR_STATIC_ENTROPY_CODES = 2;
135
+ const MIN_QUALITY_FOR_BLOCK_SPLIT = 4;
136
+ const MIN_WINDOW_BITS = 10;
137
+ const MAX_WINDOW_BITS = 24;
138
+ const LARGE_MAX_WINDOW_BITS = 30;
139
+ const DEFAULT_WINDOW_BITS = 22;
140
+ const MIN_INPUT_BLOCK_BITS = 16;
141
+ const MAX_INPUT_BLOCK_BITS = 24;
142
+ const MAX_ZOPFLI_LEN_QUALITY_10 = 150;
143
+ const MAX_ZOPFLI_LEN_QUALITY_11 = 325;
144
+ let HasherType = /* @__PURE__ */ function(HasherType) {
145
+ HasherType[HasherType["NONE"] = 0] = "NONE";
146
+ HasherType[HasherType["H01"] = 1] = "H01";
147
+ HasherType[HasherType["H02"] = 2] = "H02";
148
+ HasherType[HasherType["H03"] = 3] = "H03";
149
+ HasherType[HasherType["H04"] = 4] = "H04";
150
+ HasherType[HasherType["H05"] = 5] = "H05";
151
+ HasherType[HasherType["H06"] = 6] = "H06";
152
+ HasherType[HasherType["H10"] = 10] = "H10";
153
+ HasherType[HasherType["H35"] = 35] = "H35";
154
+ HasherType[HasherType["H40"] = 40] = "H40";
155
+ HasherType[HasherType["H41"] = 41] = "H41";
156
+ HasherType[HasherType["H42"] = 42] = "H42";
157
+ HasherType[HasherType["H54"] = 54] = "H54";
158
+ HasherType[HasherType["H55"] = 55] = "H55";
159
+ HasherType[HasherType["H58"] = 58] = "H58";
160
+ HasherType[HasherType["H65"] = 65] = "H65";
161
+ HasherType[HasherType["H68"] = 68] = "H68";
162
+ return HasherType;
163
+ }({});
164
+ let EncoderMode = /* @__PURE__ */ function(EncoderMode) {
165
+ EncoderMode[EncoderMode["GENERIC"] = 0] = "GENERIC";
166
+ EncoderMode[EncoderMode["TEXT"] = 1] = "TEXT";
167
+ EncoderMode[EncoderMode["FONT"] = 2] = "FONT";
168
+ return EncoderMode;
169
+ }({});
170
+ const NUM_COMMAND_CODES = 704;
171
+ const NUM_LITERAL_CODES = 256;
172
+ const NUM_DISTANCE_SHORT_CODES = 16;
173
+ function maxZopfliLen(quality) {
174
+ return quality <= 10 ? MAX_ZOPFLI_LEN_QUALITY_10 : MAX_ZOPFLI_LEN_QUALITY_11;
175
+ }
176
+ function maxZopfliCandidates(quality) {
177
+ return quality <= 10 ? 1 : 5;
178
+ }
179
+ function sanitizeParams(params) {
180
+ params.quality = Math.max(MIN_QUALITY, Math.min(MAX_QUALITY, params.quality));
181
+ if (params.quality <= MAX_QUALITY_FOR_STATIC_ENTROPY_CODES) params.largeWindow = false;
182
+ const maxLgwin = params.largeWindow ? LARGE_MAX_WINDOW_BITS : MAX_WINDOW_BITS;
183
+ params.lgwin = Math.max(MIN_WINDOW_BITS, Math.min(maxLgwin, params.lgwin));
184
+ }
185
+ function computeLgBlock(params) {
186
+ let lgblock = params.lgblock;
187
+ if (params.quality === FAST_ONE_PASS_COMPRESSION_QUALITY || params.quality === FAST_TWO_PASS_COMPRESSION_QUALITY) lgblock = params.lgwin;
188
+ else if (params.quality < MIN_QUALITY_FOR_BLOCK_SPLIT) lgblock = 14;
189
+ else if (lgblock === 0) {
190
+ lgblock = 16;
191
+ if (params.quality >= 9 && params.lgwin > lgblock) lgblock = Math.min(18, params.lgwin);
192
+ } else lgblock = Math.max(MIN_INPUT_BLOCK_BITS, Math.min(MAX_INPUT_BLOCK_BITS, lgblock));
193
+ return lgblock;
194
+ }
195
+ function createDefaultParams() {
196
+ return {
197
+ mode: EncoderMode.GENERIC,
198
+ quality: DEFAULT_QUALITY,
199
+ lgwin: DEFAULT_WINDOW_BITS,
200
+ lgblock: 0,
201
+ streamOffset: 0,
202
+ sizeHint: 0,
203
+ disableLiteralContextModeling: false,
204
+ largeWindow: false,
205
+ hasher: {
206
+ type: HasherType.H10,
207
+ bucketBits: 17,
208
+ blockBits: 0,
209
+ numLastDistancesToCheck: 16
210
+ },
211
+ dist: {
212
+ distancePostfixBits: 0,
213
+ numDirectDistanceCodes: 0,
214
+ alphabetSizeMax: 0,
215
+ alphabetSizeLimit: 0,
216
+ maxDistance: 0
217
+ }
218
+ };
219
+ }
220
+
221
+ //#endregion
222
+ //#region src/encode/fast-log.ts
223
+ const kLog2Table = new Float64Array([
224
+ 0,
225
+ 0,
226
+ 1,
227
+ 1.5849625007211563,
228
+ 2,
229
+ 2.321928094887362,
230
+ 2.584962500721156,
231
+ 2.807354922057604,
232
+ 3,
233
+ 3.1699250014423126,
234
+ 3.3219280948873626,
235
+ 3.4594316186372978,
236
+ 3.5849625007211565,
237
+ 3.700439718141092,
238
+ 3.8073549220576037,
239
+ 3.9068905956085187,
240
+ 4,
241
+ 4.08746284125034,
242
+ 4.169925001442312,
243
+ 4.247927513443585,
244
+ 4.321928094887363,
245
+ 4.392317422778761,
246
+ 4.459431618637297,
247
+ 4.523561956057013,
248
+ 4.584962500721157,
249
+ 4.643856189774724,
250
+ 4.700439718141093,
251
+ 4.754887502163469,
252
+ 4.807354922057604,
253
+ 4.857980995127573,
254
+ 4.906890595608519,
255
+ 4.954196310386876,
256
+ 5,
257
+ 5.044394119358453,
258
+ 5.08746284125034,
259
+ 5.129283016944966,
260
+ 5.169925001442312,
261
+ 5.20945336562895,
262
+ 5.247927513443585,
263
+ 5.285402218862249,
264
+ 5.321928094887363,
265
+ 5.357552004618084,
266
+ 5.392317422778761,
267
+ 5.426264754702098,
268
+ 5.459431618637297,
269
+ 5.491853096329675,
270
+ 5.523561956057013,
271
+ 5.554588851677638,
272
+ 5.584962500721157,
273
+ 5.614709844115208,
274
+ 5.643856189774724,
275
+ 5.672425341971496,
276
+ 5.700439718141093,
277
+ 5.7279204545632,
278
+ 5.754887502163469,
279
+ 5.78135971352466,
280
+ 5.807354922057605,
281
+ 5.832890014164742,
282
+ 5.857980995127572,
283
+ 5.882643049361842,
284
+ 5.906890595608519,
285
+ 5.930737337562887,
286
+ 5.954196310386876,
287
+ 5.977279923499917,
288
+ 6,
289
+ 6.022367813028454,
290
+ 6.044394119358453,
291
+ 6.066089190457772,
292
+ 6.08746284125034,
293
+ 6.10852445677817,
294
+ 6.129283016944967,
295
+ 6.149747119504682,
296
+ 6.169925001442312,
297
+ 6.189824558880018,
298
+ 6.209453365628951,
299
+ 6.22881869049588,
300
+ 6.247927513443586,
301
+ 6.266786540694902,
302
+ 6.285402218862249,
303
+ 6.303780748177103,
304
+ 6.321928094887362,
305
+ 6.339850002884625,
306
+ 6.357552004618085,
307
+ 6.375039431346925,
308
+ 6.39231742277876,
309
+ 6.409390936137703,
310
+ 6.426264754702098,
311
+ 6.442943495848729,
312
+ 6.459431618637298,
313
+ 6.475733430966398,
314
+ 6.491853096329675,
315
+ 6.507794640198696,
316
+ 6.523561956057013,
317
+ 6.539158811108032,
318
+ 6.554588851677638,
319
+ 6.569855608330948,
320
+ 6.584962500721156,
321
+ 6.599912842187128,
322
+ 6.614709844115209,
323
+ 6.6293566200796095,
324
+ 6.643856189774725,
325
+ 6.6582114827517955,
326
+ 6.672425341971495,
327
+ 6.6865005271832185,
328
+ 6.700439718141092,
329
+ 6.714245517666122,
330
+ 6.727920454563199,
331
+ 6.7414669864011465,
332
+ 6.754887502163469,
333
+ 6.768184324776926,
334
+ 6.78135971352466,
335
+ 6.794415866350106,
336
+ 6.807354922057604,
337
+ 6.820178962415189,
338
+ 6.832890014164742,
339
+ 6.845490050944376,
340
+ 6.857980995127572,
341
+ 6.870364719583405,
342
+ 6.882643049361842,
343
+ 6.894817763307944,
344
+ 6.906890595608519,
345
+ 6.9188632372745955,
346
+ 6.930737337562887,
347
+ 6.94251450533924,
348
+ 6.954196310386876,
349
+ 6.965784284662088,
350
+ 6.977279923499917,
351
+ 6.988684686772166,
352
+ 7,
353
+ 7.011227255423254,
354
+ 7.022367813028454,
355
+ 7.03342300153745,
356
+ 7.044394119358453,
357
+ 7.05528243550119,
358
+ 7.066089190457772,
359
+ 7.076815597050832,
360
+ 7.08746284125034,
361
+ 7.098032082960527,
362
+ 7.10852445677817,
363
+ 7.118941072723508,
364
+ 7.129283016944966,
365
+ 7.139551352398794,
366
+ 7.149747119504682,
367
+ 7.159871336778389,
368
+ 7.169925001442313,
369
+ 7.1799090900149345,
370
+ 7.189824558880018,
371
+ 7.199672344836364,
372
+ 7.209453365628949,
373
+ 7.219168520462162,
374
+ 7.22881869049588,
375
+ 7.238404739325079,
376
+ 7.247927513443586,
377
+ 7.257387842692652,
378
+ 7.266786540694902,
379
+ 7.276124405274238,
380
+ 7.285402218862249,
381
+ 7.294620748891627,
382
+ 7.303780748177103,
383
+ 7.312882955284356,
384
+ 7.321928094887362,
385
+ 7.330916878114618,
386
+ 7.339850002884624,
387
+ 7.348728154231078,
388
+ 7.357552004618085,
389
+ 7.366322214245815,
390
+ 7.375039431346925,
391
+ 7.383704292474053,
392
+ 7.392317422778761,
393
+ 7.400879436282184,
394
+ 7.409390936137703,
395
+ 7.417852514885899,
396
+ 7.426264754702098,
397
+ 7.4346282276367255,
398
+ 7.442943495848729,
399
+ 7.45121111183233,
400
+ 7.459431618637297,
401
+ 7.467605550082998,
402
+ 7.475733430966398,
403
+ 7.483815777264256,
404
+ 7.491853096329675,
405
+ 7.499845887083206,
406
+ 7.507794640198696,
407
+ 7.515699838284044,
408
+ 7.523561956057013,
409
+ 7.531381460516312,
410
+ 7.539158811108032,
411
+ 7.546894459887637,
412
+ 7.554588851677638,
413
+ 7.562242424221073,
414
+ 7.569855608330948,
415
+ 7.577428828035749,
416
+ 7.584962500721156,
417
+ 7.592457037268081,
418
+ 7.599912842187128,
419
+ 7.607330313749611,
420
+ 7.6147098441152075,
421
+ 7.622051819456376,
422
+ 7.6293566200796095,
423
+ 7.636624620543649,
424
+ 7.643856189774724,
425
+ 7.651051691178929,
426
+ 7.6582114827517955,
427
+ 7.6653359171851765,
428
+ 7.672425341971495,
429
+ 7.679480099505446,
430
+ 7.6865005271832185,
431
+ 7.693486957499325,
432
+ 7.700439718141093,
433
+ 7.7073591320808825,
434
+ 7.714245517666122,
435
+ 7.721099188707186,
436
+ 7.7279204545632,
437
+ 7.734709620225839,
438
+ 7.7414669864011465,
439
+ 7.74819284958946,
440
+ 7.754887502163469,
441
+ 7.7615512324444795,
442
+ 7.768184324776926,
443
+ 7.774787059601174,
444
+ 7.781359713524661,
445
+ 7.787902559391432,
446
+ 7.794415866350106,
447
+ 7.800899899920305,
448
+ 7.807354922057604,
449
+ 7.813781191217037,
450
+ 7.820178962415189,
451
+ 7.826548487290916,
452
+ 7.832890014164742,
453
+ 7.8392037880969445,
454
+ 7.845490050944376,
455
+ 7.851749041416057,
456
+ 7.857980995127572,
457
+ 7.86418614465428,
458
+ 7.870364719583405,
459
+ 7.876516946565,
460
+ 7.8826430493618425,
461
+ 7.88874324889826,
462
+ 7.894817763307945,
463
+ 7.90086680798075,
464
+ 7.906890595608519,
465
+ 7.912889336229962,
466
+ 7.9188632372745955,
467
+ 7.924812503605781,
468
+ 7.930737337562887,
469
+ 7.936637939002572,
470
+ 7.94251450533924,
471
+ 7.948367231584678,
472
+ 7.954196310386876,
473
+ 7.960001932068081,
474
+ 7.965784284662087,
475
+ 7.971543553950772,
476
+ 7.977279923499917,
477
+ 7.98299357469431,
478
+ 7.988684686772166,
479
+ 7.994353436858858
480
+ ]);
481
+ const LOG2_TABLE_SIZE = 256;
482
+ const LOG_2_INV = 1.4426950408889634;
483
+ function log2FloorNonZero(n) {
484
+ return 31 - Math.clz32(n | 0);
485
+ }
486
+ function fastLog2(v) {
487
+ if (v < LOG2_TABLE_SIZE) return kLog2Table[v];
488
+ return Math.log(v) * LOG_2_INV;
489
+ }
490
+
491
+ //#endregion
492
+ //#region src/encode/match.ts
493
+ const LITERAL_BYTE_SCORE = 135;
494
+ const DISTANCE_BIT_PENALTY = 30;
495
+ const SCORE_BASE = DISTANCE_BIT_PENALTY * 8 * 4;
496
+ function backwardReferenceScore(copyLength, backwardDistance) {
497
+ return SCORE_BASE + LITERAL_BYTE_SCORE * copyLength - DISTANCE_BIT_PENALTY * log2FloorNonZero(backwardDistance);
498
+ }
499
+ function backwardReferenceScoreUsingLastDistance(copyLength) {
500
+ return LITERAL_BYTE_SCORE * copyLength + SCORE_BASE + 15;
501
+ }
502
+ function findMatchLength(data, s1, s2, limit) {
503
+ let matched = 0;
504
+ while (matched + 4 <= limit) {
505
+ if (data[s1 + matched] !== data[s2 + matched] || data[s1 + matched + 1] !== data[s2 + matched + 1] || data[s1 + matched + 2] !== data[s2 + matched + 2] || data[s1 + matched + 3] !== data[s2 + matched + 3]) break;
506
+ matched += 4;
507
+ }
508
+ while (matched < limit && data[s1 + matched] === data[s2 + matched]) matched++;
509
+ return matched;
510
+ }
511
+ function createBackwardMatch(distance, length) {
512
+ return {
513
+ distance,
514
+ length,
515
+ score: backwardReferenceScore(length, distance),
516
+ lenCodeDelta: 0
517
+ };
518
+ }
519
+ function createSearchResult() {
520
+ return {
521
+ len: 0,
522
+ distance: 0,
523
+ score: 0,
524
+ lenCodeDelta: 0
525
+ };
526
+ }
527
+ function prepareDistanceCache(distanceCache, numDistances) {
528
+ if (numDistances > 4) {
529
+ const lastDistance = distanceCache[0];
530
+ distanceCache[4] = lastDistance - 1;
531
+ distanceCache[5] = lastDistance + 1;
532
+ distanceCache[6] = lastDistance - 2;
533
+ distanceCache[7] = lastDistance + 2;
534
+ distanceCache[8] = lastDistance - 3;
535
+ distanceCache[9] = lastDistance + 3;
536
+ if (numDistances > 10) {
537
+ const nextLastDistance = distanceCache[1];
538
+ distanceCache[10] = nextLastDistance - 1;
539
+ distanceCache[11] = nextLastDistance + 1;
540
+ distanceCache[12] = nextLastDistance - 2;
541
+ distanceCache[13] = nextLastDistance + 2;
542
+ distanceCache[14] = nextLastDistance - 3;
543
+ distanceCache[15] = nextLastDistance + 3;
544
+ }
545
+ }
546
+ }
547
+ const HASH_MUL_32 = 506832829;
548
+ const HASH_MUL_64 = 506832829n;
549
+ function hashBytes4(data, pos, bucketBits) {
550
+ const b0 = pos < data.length ? data[pos] : 0;
551
+ const b1 = pos + 1 < data.length ? data[pos + 1] : 0;
552
+ const b2 = pos + 2 < data.length ? data[pos + 2] : 0;
553
+ const b3 = pos + 3 < data.length ? data[pos + 3] : 0;
554
+ const h32 = (b0 | b1 << 8 | b2 << 16 | b3 << 24) >>> 0;
555
+ return Math.imul(h32, HASH_MUL_32) >>> 0 >>> 32 - bucketBits;
556
+ }
557
+ function hashBytes8(data, pos, hashLen, bucketBits) {
558
+ let h64 = 0n;
559
+ for (let i = 0; i < 8; i++) {
560
+ const byte = pos + i < data.length ? data[pos + i] : 0;
561
+ h64 |= BigInt(byte) << BigInt(i * 8);
562
+ }
563
+ const shift = BigInt(64 - 8 * hashLen);
564
+ h64 = (h64 << shift) * HASH_MUL_64;
565
+ return Number(h64 >> BigInt(64 - bucketBits));
566
+ }
567
+
568
+ //#endregion
569
+ //#region src/encode/hash-simple.ts
570
+ const Q2_BUCKET_BITS = 16;
571
+ const Q3_BUCKET_BITS = 17;
572
+ const HASH_LEN = 5;
573
+ const MIN_MATCH_LEN$1 = 4;
574
+ var SimpleHasher = class {
575
+ constructor(bucketBits, _lgwin) {
576
+ this.bucketBits = bucketBits;
577
+ const bucketSize = 1 << bucketBits;
578
+ this.buckets = new Uint32Array(bucketSize);
579
+ }
580
+ reset() {
581
+ this.buckets.fill(0);
582
+ }
583
+ prepare(data, inputSize) {
584
+ if (inputSize <= this.buckets.length >> 5) for (let i = 0; i < inputSize; i++) {
585
+ const key = this.hashBytes(data, i);
586
+ this.buckets[key] = 0;
587
+ }
588
+ else this.buckets.fill(0);
589
+ }
590
+ hashBytes(data, pos) {
591
+ return hashBytes8(data, pos, HASH_LEN, this.bucketBits);
592
+ }
593
+ store(data, mask, ix) {
594
+ const key = this.hashBytes(data, ix & mask);
595
+ this.buckets[key] = ix;
596
+ }
597
+ storeRange(data, mask, ixStart, ixEnd) {
598
+ for (let i = ixStart; i < ixEnd; i++) this.store(data, mask, i);
599
+ }
600
+ findLongestMatch(data, ringBufferMask, distanceCache, curIx, maxLength, maxBackward, out) {
601
+ const curIxMasked = curIx & ringBufferMask;
602
+ let bestLen = out.len;
603
+ const key = this.hashBytes(data, curIxMasked);
604
+ let bestScore = out.score;
605
+ out.lenCodeDelta = 0;
606
+ const cachedBackward = distanceCache[0];
607
+ if (cachedBackward > 0 && cachedBackward <= maxBackward) {
608
+ let prevIx = curIx - cachedBackward;
609
+ prevIx &= ringBufferMask;
610
+ if (data[prevIx + bestLen] === data[curIxMasked + bestLen]) {
611
+ const len = findMatchLength(data, prevIx, curIxMasked, maxLength);
612
+ if (len >= MIN_MATCH_LEN$1) {
613
+ const score = backwardReferenceScoreUsingLastDistance(len);
614
+ if (score > bestScore) {
615
+ bestLen = len;
616
+ out.len = len;
617
+ out.distance = cachedBackward;
618
+ out.score = score;
619
+ bestScore = score;
620
+ }
621
+ }
622
+ }
623
+ }
624
+ let prevIx = this.buckets[key];
625
+ this.buckets[key] = curIx;
626
+ const backward = curIx - prevIx;
627
+ if (backward === 0 || backward > maxBackward) return;
628
+ prevIx &= ringBufferMask;
629
+ if (data[prevIx + bestLen] !== data[curIxMasked + bestLen]) return;
630
+ const len = findMatchLength(data, prevIx, curIxMasked, maxLength);
631
+ if (len >= MIN_MATCH_LEN$1) {
632
+ const score = backwardReferenceScore(len, backward);
633
+ if (score > bestScore) {
634
+ out.len = len;
635
+ out.distance = backward;
636
+ out.score = score;
637
+ }
638
+ }
639
+ }
640
+ };
641
+ function createSimpleHasher(quality, lgwin) {
642
+ return new SimpleHasher(quality === 2 ? Q2_BUCKET_BITS : Q3_BUCKET_BITS, lgwin);
643
+ }
644
+
645
+ //#endregion
646
+ //#region src/encode/hash-chains.ts
647
+ const MIN_MATCH_LEN = 4;
648
+ var HashChainHasher = class {
649
+ constructor(bucketBits, blockBits, lgwin, numLastDistancesToCheck = 4) {
650
+ this.bucketBits = bucketBits;
651
+ this.blockBits = blockBits;
652
+ this.windowMask = (1 << lgwin) - 1;
653
+ this.numLastDistancesToCheck = numLastDistancesToCheck;
654
+ this.buckets = new Uint32Array(1 << bucketBits);
655
+ this.chains = new Uint32Array(1 << lgwin);
656
+ }
657
+ reset() {
658
+ this.buckets.fill(0);
659
+ }
660
+ hashBytes(data, pos) {
661
+ return hashBytes4(data, pos, this.bucketBits);
662
+ }
663
+ store(data, mask, ix) {
664
+ const maskedIx = ix & mask;
665
+ const key = this.hashBytes(data, maskedIx);
666
+ const minorKey = ix & this.windowMask;
667
+ this.chains[minorKey] = this.buckets[key];
668
+ this.buckets[key] = ix;
669
+ }
670
+ storeRange(data, mask, ixStart, ixEnd) {
671
+ for (let i = ixStart; i < ixEnd; i++) this.store(data, mask, i);
672
+ }
673
+ findLongestMatch(data, ringBufferMask, distanceCache, curIx, maxLength, maxBackward, out) {
674
+ const curIxMasked = curIx & ringBufferMask;
675
+ let bestLen = out.len;
676
+ let bestScore = out.score;
677
+ const key = this.hashBytes(data, curIxMasked);
678
+ const minorKey = curIx & this.windowMask;
679
+ out.lenCodeDelta = 0;
680
+ prepareDistanceCache(distanceCache, this.numLastDistancesToCheck);
681
+ for (let i = 0; i < this.numLastDistancesToCheck; i++) {
682
+ const cachedBackward = distanceCache[i];
683
+ if (cachedBackward <= 0 || cachedBackward > maxBackward) continue;
684
+ let prevIx = curIx - cachedBackward;
685
+ prevIx &= ringBufferMask;
686
+ if (data[prevIx + bestLen] !== data[curIxMasked + bestLen]) continue;
687
+ const len = findMatchLength(data, prevIx, curIxMasked, maxLength);
688
+ if (len >= MIN_MATCH_LEN) {
689
+ const score = backwardReferenceScoreUsingLastDistance(len);
690
+ if (score > bestScore) {
691
+ bestLen = len;
692
+ out.len = len;
693
+ out.distance = cachedBackward;
694
+ out.score = score;
695
+ bestScore = score;
696
+ }
697
+ }
698
+ }
699
+ this.chains[minorKey] = this.buckets[key];
700
+ this.buckets[key] = curIx;
701
+ const maxChainLength = 1 << this.blockBits;
702
+ let prevIx = this.chains[minorKey];
703
+ for (let chainLen = 0; chainLen < maxChainLength; chainLen++) {
704
+ const backward = curIx - prevIx;
705
+ if (backward === 0 || backward > maxBackward) break;
706
+ const prevIxMasked = prevIx & ringBufferMask;
707
+ if (data[prevIxMasked + bestLen] !== data[curIxMasked + bestLen]) {
708
+ prevIx = this.chains[prevIx & this.windowMask];
709
+ continue;
710
+ }
711
+ const len = findMatchLength(data, prevIxMasked, curIxMasked, maxLength);
712
+ if (len >= MIN_MATCH_LEN) {
713
+ const score = backwardReferenceScore(len, backward);
714
+ if (score > bestScore) {
715
+ bestLen = len;
716
+ out.len = len;
717
+ out.distance = backward;
718
+ out.score = score;
719
+ bestScore = score;
720
+ }
721
+ }
722
+ prevIx = this.chains[prevIx & this.windowMask];
723
+ }
724
+ }
725
+ findAllMatches(data, ringBufferMask, distanceCache, curIx, maxLength, maxBackward) {
726
+ const curIxMasked = curIx & ringBufferMask;
727
+ const matches = [];
728
+ const key = this.hashBytes(data, curIxMasked);
729
+ const minorKey = curIx & this.windowMask;
730
+ let bestLen = 0;
731
+ prepareDistanceCache(distanceCache, this.numLastDistancesToCheck);
732
+ for (let i = 0; i < this.numLastDistancesToCheck; i++) {
733
+ const cachedBackward = distanceCache[i];
734
+ if (cachedBackward <= 0 || cachedBackward > maxBackward) continue;
735
+ let prevIx = curIx - cachedBackward;
736
+ prevIx &= ringBufferMask;
737
+ const len = findMatchLength(data, prevIx, curIxMasked, maxLength);
738
+ if (len >= MIN_MATCH_LEN && len > bestLen) {
739
+ bestLen = len;
740
+ matches.push({
741
+ distance: cachedBackward,
742
+ length: len,
743
+ score: backwardReferenceScoreUsingLastDistance(len),
744
+ lenCodeDelta: 0
745
+ });
746
+ }
747
+ }
748
+ this.chains[minorKey] = this.buckets[key];
749
+ this.buckets[key] = curIx;
750
+ const maxChainLength = 1 << this.blockBits;
751
+ let prevIx = this.chains[minorKey];
752
+ for (let chainLen = 0; chainLen < maxChainLength; chainLen++) {
753
+ const backward = curIx - prevIx;
754
+ if (backward === 0 || backward > maxBackward) break;
755
+ const len = findMatchLength(data, prevIx & ringBufferMask, curIxMasked, maxLength);
756
+ if (len >= MIN_MATCH_LEN && len > bestLen) {
757
+ bestLen = len;
758
+ matches.push({
759
+ distance: backward,
760
+ length: len,
761
+ score: backwardReferenceScore(len, backward),
762
+ lenCodeDelta: 0
763
+ });
764
+ }
765
+ prevIx = this.chains[prevIx & this.windowMask];
766
+ }
767
+ matches.sort((a, b) => a.length - b.length);
768
+ return matches;
769
+ }
770
+ };
771
+ function createHashChainHasher(quality, lgwin) {
772
+ let bucketBits;
773
+ let blockBits;
774
+ let numLastDistancesToCheck;
775
+ if (quality < 7) {
776
+ bucketBits = 14;
777
+ blockBits = quality - 1;
778
+ numLastDistancesToCheck = 4;
779
+ } else if (quality < 9) {
780
+ bucketBits = 15;
781
+ blockBits = quality - 1;
782
+ numLastDistancesToCheck = 10;
783
+ } else {
784
+ bucketBits = 15;
785
+ blockBits = quality - 1;
786
+ numLastDistancesToCheck = 16;
787
+ }
788
+ return new HashChainHasher(bucketBits, blockBits, lgwin, numLastDistancesToCheck);
789
+ }
790
+
791
+ //#endregion
792
+ //#region src/encode/hash-binary-tree.ts
793
+ const BUCKET_BITS = 17;
794
+ const MAX_TREE_COMP_LENGTH = 128;
795
+ const MAX_TREE_SEARCH_DEPTH = 64;
796
+ const WINDOW_GAP = 16;
797
+ var BinaryTreeHasher = class {
798
+ constructor(lgwin, inputSize) {
799
+ this.windowMask = (1 << lgwin) - 1;
800
+ this.invalidPos = 0 - this.windowMask >>> 0;
801
+ this.bucketSize = 1 << BUCKET_BITS;
802
+ this.buckets = new Uint32Array(this.bucketSize);
803
+ const numNodes = inputSize !== void 0 ? Math.min(inputSize, 1 << lgwin) : 1 << lgwin;
804
+ this.forest = new Uint32Array(2 * numNodes);
805
+ this.forest.fill(this.invalidPos);
806
+ }
807
+ reset() {
808
+ this.buckets.fill(this.invalidPos);
809
+ this.forest.fill(this.invalidPos);
810
+ }
811
+ leftChildIndex(pos) {
812
+ return 2 * (pos & this.windowMask);
813
+ }
814
+ rightChildIndex(pos) {
815
+ return 2 * (pos & this.windowMask) + 1;
816
+ }
817
+ storeAndFindMatches(data, curIx, ringBufferMask, maxLength, maxBackward, matches) {
818
+ const curIxMasked = curIx & ringBufferMask;
819
+ const maxCompLen = Math.min(maxLength, MAX_TREE_COMP_LENGTH);
820
+ const shouldRerootTree = maxLength >= MAX_TREE_COMP_LENGTH;
821
+ const key = hashBytes4(data, curIxMasked, BUCKET_BITS);
822
+ let prevIx = this.buckets[key];
823
+ let nodeLeft = this.leftChildIndex(curIx);
824
+ let nodeRight = this.rightChildIndex(curIx);
825
+ let bestLenLeft = 0;
826
+ let bestLenRight = 0;
827
+ let bestLen = matches ? 1 : 0;
828
+ const result = matches || [];
829
+ if (shouldRerootTree) this.buckets[key] = curIx;
830
+ for (let depthRemaining = MAX_TREE_SEARCH_DEPTH; depthRemaining > 0; depthRemaining--) {
831
+ if (prevIx === this.invalidPos) {
832
+ if (shouldRerootTree) {
833
+ this.forest[nodeLeft] = this.invalidPos;
834
+ this.forest[nodeRight] = this.invalidPos;
835
+ }
836
+ break;
837
+ }
838
+ const backward = curIx - prevIx;
839
+ const prevIxMasked = prevIx & ringBufferMask;
840
+ if (backward <= 0 || backward > maxBackward) {
841
+ if (shouldRerootTree) {
842
+ this.forest[nodeLeft] = this.invalidPos;
843
+ this.forest[nodeRight] = this.invalidPos;
844
+ }
845
+ break;
846
+ }
847
+ const curLen = Math.min(bestLenLeft, bestLenRight);
848
+ const len = curLen + findMatchLength(data, curIxMasked + curLen, prevIxMasked + curLen, maxLength - curLen);
849
+ if (matches && len > bestLen) {
850
+ bestLen = len;
851
+ result.push(createBackwardMatch(backward, len));
852
+ }
853
+ if (len >= maxCompLen) {
854
+ if (shouldRerootTree) {
855
+ this.forest[nodeLeft] = this.forest[this.leftChildIndex(prevIx)];
856
+ this.forest[nodeRight] = this.forest[this.rightChildIndex(prevIx)];
857
+ }
858
+ break;
859
+ }
860
+ if (data[curIxMasked + len] > data[prevIxMasked + len]) {
861
+ bestLenLeft = len;
862
+ if (shouldRerootTree) this.forest[nodeLeft] = prevIx;
863
+ nodeLeft = this.rightChildIndex(prevIx);
864
+ prevIx = this.forest[nodeLeft];
865
+ } else {
866
+ bestLenRight = len;
867
+ if (shouldRerootTree) this.forest[nodeRight] = prevIx;
868
+ nodeRight = this.leftChildIndex(prevIx);
869
+ prevIx = this.forest[nodeRight];
870
+ }
871
+ }
872
+ return result;
873
+ }
874
+ findAllMatches(data, ringBufferMask, curIx, maxLength, maxBackward) {
875
+ const curIxMasked = curIx & ringBufferMask;
876
+ const matches = [];
877
+ let bestLen = 1;
878
+ const shortMatchMaxBackward = 64;
879
+ const stop = curIx > shortMatchMaxBackward ? curIx - shortMatchMaxBackward : 0;
880
+ for (let i = curIx - 1; i > stop && bestLen <= 2; i--) {
881
+ const backward = curIx - i;
882
+ if (backward > maxBackward) break;
883
+ const prevIxMasked = i & ringBufferMask;
884
+ if (data[curIxMasked] !== data[prevIxMasked] || data[curIxMasked + 1] !== data[prevIxMasked + 1]) continue;
885
+ const len = findMatchLength(data, prevIxMasked, curIxMasked, maxLength);
886
+ if (len > bestLen) {
887
+ bestLen = len;
888
+ matches.push(createBackwardMatch(backward, len));
889
+ }
890
+ }
891
+ if (bestLen < maxLength) {
892
+ const treeMatches = this.storeAndFindMatches(data, curIx, ringBufferMask, maxLength, maxBackward, []);
893
+ for (const m of treeMatches) if (m.length > bestLen) {
894
+ bestLen = m.length;
895
+ matches.push(m);
896
+ }
897
+ } else this.storeAndFindMatches(data, curIx, ringBufferMask, maxLength, maxBackward, null);
898
+ matches.sort((a, b) => a.length - b.length);
899
+ return matches;
900
+ }
901
+ store(data, mask, ix) {
902
+ const maxBackward = this.windowMask - WINDOW_GAP + 1;
903
+ this.storeAndFindMatches(data, ix, mask, MAX_TREE_COMP_LENGTH, maxBackward, null);
904
+ }
905
+ storeRange(data, mask, ixStart, ixEnd) {
906
+ let i = ixStart;
907
+ let j = ixStart;
908
+ if (ixStart + 63 <= ixEnd) i = ixEnd - 63;
909
+ if (ixStart + 512 <= i) for (; j < i; j += 8) this.store(data, mask, j);
910
+ for (; i < ixEnd; i++) this.store(data, mask, i);
911
+ }
912
+ stitchToPreviousBlock(numBytes, position, ringBuffer, ringBufferMask) {
913
+ if (numBytes >= 3 && position >= MAX_TREE_COMP_LENGTH) {
914
+ const iStart = position - MAX_TREE_COMP_LENGTH + 1;
915
+ const iEnd = Math.min(position, iStart + numBytes);
916
+ for (let i = iStart; i < iEnd; i++) {
917
+ const maxBackward = this.windowMask - Math.max(WINDOW_GAP - 1, position - i);
918
+ this.storeAndFindMatches(ringBuffer, i, ringBufferMask, MAX_TREE_COMP_LENGTH, maxBackward, null);
919
+ }
920
+ }
921
+ }
922
+ };
923
+ function createBinaryTreeHasher(lgwin, inputSize) {
924
+ return new BinaryTreeHasher(lgwin, inputSize);
925
+ }
926
+
927
+ //#endregion
928
+ //#region src/encode/command.ts
929
+ const INSERT_LENGTH_BASE = new Uint32Array([
930
+ 0,
931
+ 1,
932
+ 2,
933
+ 3,
934
+ 4,
935
+ 5,
936
+ 6,
937
+ 8,
938
+ 10,
939
+ 14,
940
+ 18,
941
+ 26,
942
+ 34,
943
+ 50,
944
+ 66,
945
+ 98,
946
+ 130,
947
+ 194,
948
+ 322,
949
+ 578,
950
+ 1090,
951
+ 2114,
952
+ 6210,
953
+ 22594
954
+ ]);
955
+ const INSERT_LENGTH_EXTRA = new Uint32Array([
956
+ 0,
957
+ 0,
958
+ 0,
959
+ 0,
960
+ 0,
961
+ 0,
962
+ 1,
963
+ 1,
964
+ 2,
965
+ 2,
966
+ 3,
967
+ 3,
968
+ 4,
969
+ 4,
970
+ 5,
971
+ 5,
972
+ 6,
973
+ 7,
974
+ 8,
975
+ 9,
976
+ 10,
977
+ 12,
978
+ 14,
979
+ 24
980
+ ]);
981
+ const COPY_LENGTH_BASE = new Uint32Array([
982
+ 2,
983
+ 3,
984
+ 4,
985
+ 5,
986
+ 6,
987
+ 7,
988
+ 8,
989
+ 9,
990
+ 10,
991
+ 12,
992
+ 14,
993
+ 18,
994
+ 22,
995
+ 30,
996
+ 38,
997
+ 54,
998
+ 70,
999
+ 102,
1000
+ 134,
1001
+ 198,
1002
+ 326,
1003
+ 582,
1004
+ 1094,
1005
+ 2118
1006
+ ]);
1007
+ const COPY_LENGTH_EXTRA = new Uint32Array([
1008
+ 0,
1009
+ 0,
1010
+ 0,
1011
+ 0,
1012
+ 0,
1013
+ 0,
1014
+ 0,
1015
+ 0,
1016
+ 1,
1017
+ 1,
1018
+ 2,
1019
+ 2,
1020
+ 3,
1021
+ 3,
1022
+ 4,
1023
+ 4,
1024
+ 5,
1025
+ 5,
1026
+ 6,
1027
+ 7,
1028
+ 8,
1029
+ 9,
1030
+ 10,
1031
+ 24
1032
+ ]);
1033
+ function getInsertLengthCode(insertLen) {
1034
+ if (insertLen < 6) return insertLen;
1035
+ else if (insertLen < 130) {
1036
+ const nbits = log2FloorNonZero(insertLen - 2) - 1;
1037
+ return (nbits << 1) + (insertLen - 2 >>> nbits) + 2;
1038
+ } else if (insertLen < 2114) return log2FloorNonZero(insertLen - 66) + 10;
1039
+ else if (insertLen < 6210) return 21;
1040
+ else if (insertLen < 22594) return 22;
1041
+ else return 23;
1042
+ }
1043
+ function getCopyLengthCode(copyLen) {
1044
+ if (copyLen < 10) return copyLen - 2;
1045
+ else if (copyLen < 134) {
1046
+ const nbits = log2FloorNonZero(copyLen - 6) - 1;
1047
+ return (nbits << 1) + (copyLen - 6 >>> nbits) + 4;
1048
+ } else if (copyLen < 2118) return log2FloorNonZero(copyLen - 70) + 12;
1049
+ else return 23;
1050
+ }
1051
+ function combineLengthCodes(insCode, copyCode, useLastDistance) {
1052
+ const bits64 = copyCode & 7 | (insCode & 7) << 3;
1053
+ if (useLastDistance && insCode < 8 && copyCode < 16) return copyCode < 8 ? bits64 : bits64 | 64;
1054
+ else {
1055
+ let offset = 2 * ((copyCode >>> 3) + 3 * (insCode >>> 3));
1056
+ offset = (offset << 5) + 64 + (5377344 >>> offset & 192);
1057
+ return offset | bits64;
1058
+ }
1059
+ }
1060
+ function getLengthCode(insertLen, copyLen, useLastDistance) {
1061
+ return combineLengthCodes(getInsertLengthCode(insertLen), getCopyLengthCode(copyLen), useLastDistance);
1062
+ }
1063
+ function getInsertBase(insCode) {
1064
+ return INSERT_LENGTH_BASE[insCode];
1065
+ }
1066
+ function getInsertExtra(insCode) {
1067
+ return INSERT_LENGTH_EXTRA[insCode];
1068
+ }
1069
+ function getCopyBase(copyCode) {
1070
+ return COPY_LENGTH_BASE[copyCode];
1071
+ }
1072
+ function getCopyExtra(copyCode) {
1073
+ return COPY_LENGTH_EXTRA[copyCode];
1074
+ }
1075
+ function prefixEncodeCopyDistance(distanceCode, numDirectCodes, postfixBits) {
1076
+ if (distanceCode < NUM_DISTANCE_SHORT_CODES + numDirectCodes) return [
1077
+ distanceCode,
1078
+ 0,
1079
+ 0
1080
+ ];
1081
+ else {
1082
+ const dist = (1 << postfixBits + 2) + (distanceCode - NUM_DISTANCE_SHORT_CODES - numDirectCodes);
1083
+ const bucket = log2FloorNonZero(dist) - 1;
1084
+ const postfix = dist & (1 << postfixBits) - 1;
1085
+ const prefix = dist >>> bucket & 1;
1086
+ const offset = 2 + prefix << bucket;
1087
+ const nbits = bucket - postfixBits;
1088
+ return [
1089
+ nbits << 10 | NUM_DISTANCE_SHORT_CODES + numDirectCodes + (2 * (nbits - 1) + prefix << postfixBits) + postfix,
1090
+ dist - offset >>> postfixBits,
1091
+ nbits
1092
+ ];
1093
+ }
1094
+ }
1095
+ function createCommand(insertLen, copyLen, copyLenCodeDelta, distanceCode, numDirectCodes = 0, postfixBits = 0) {
1096
+ const copyLenEncoded = copyLen | (copyLenCodeDelta & 127) << 25;
1097
+ const [distCode, distExtra, distNbits] = prefixEncodeCopyDistance(distanceCode, numDirectCodes, postfixBits);
1098
+ const distPrefix = distCode | distNbits << 10;
1099
+ const useLastDistance = (distCode & 1023) === 0;
1100
+ return {
1101
+ insertLen,
1102
+ copyLen: copyLenEncoded,
1103
+ distExtra,
1104
+ cmdPrefix: getLengthCode(insertLen, copyLen + copyLenCodeDelta, useLastDistance),
1105
+ distPrefix
1106
+ };
1107
+ }
1108
+ function createInsertCommand(insertLen) {
1109
+ const copyLenCode = 2;
1110
+ const insCode = getInsertLengthCode(insertLen);
1111
+ let cmdPrefix;
1112
+ if (insCode < 8) cmdPrefix = getLengthCode(insertLen, copyLenCode, true);
1113
+ else cmdPrefix = getLengthCode(insertLen, copyLenCode, false);
1114
+ return {
1115
+ insertLen,
1116
+ copyLen: 67108864,
1117
+ distExtra: 0,
1118
+ cmdPrefix,
1119
+ distPrefix: 0
1120
+ };
1121
+ }
1122
+ function commandCopyLen(cmd) {
1123
+ return cmd.copyLen & 33554431;
1124
+ }
1125
+ function commandCopyLenCode(cmd) {
1126
+ const modifier = cmd.copyLen >>> 25;
1127
+ const delta = modifier & 64 ? modifier | 4294967168 : modifier;
1128
+ return (cmd.copyLen & 33554431) + delta;
1129
+ }
1130
+
1131
+ //#endregion
1132
+ //#region src/encode/backward-references.ts
1133
+ function createBackwardReferences(numBytes, position, ringbuffer, ringbufferMask, hasher, distCache, lastInsertLen, _quality) {
1134
+ const commands = [];
1135
+ let numLiterals = 0;
1136
+ let insertLen = lastInsertLen;
1137
+ let pos = position;
1138
+ const posEnd = position + numBytes;
1139
+ const maxWindowBackward = (1 << 22) - 16;
1140
+ while (pos < posEnd) {
1141
+ const maxLen = posEnd - pos;
1142
+ if (maxLen < 4) {
1143
+ insertLen += maxLen;
1144
+ pos += maxLen;
1145
+ break;
1146
+ }
1147
+ const maxBackward = Math.min(pos, maxWindowBackward);
1148
+ const result = createSearchResult();
1149
+ hasher.findLongestMatch(ringbuffer, ringbufferMask, distCache, pos, Math.min(maxLen, 128), maxBackward, result);
1150
+ if (result.len >= 4 && result.score > 0 && result.distance > 0) {
1151
+ const distance = result.distance;
1152
+ const matchLen = result.len;
1153
+ if (distance > pos) {
1154
+ hasher.store(ringbuffer, ringbufferMask, pos);
1155
+ insertLen++;
1156
+ pos++;
1157
+ continue;
1158
+ }
1159
+ const distCode = distanceToCode(distance, distCache);
1160
+ const cmd = createCommand(insertLen, matchLen, result.lenCodeDelta, distCode);
1161
+ commands.push(cmd);
1162
+ numLiterals += insertLen;
1163
+ if (distCode > 0) {
1164
+ distCache[3] = distCache[2];
1165
+ distCache[2] = distCache[1];
1166
+ distCache[1] = distCache[0];
1167
+ distCache[0] = distance;
1168
+ }
1169
+ const storeEnd = Math.min(pos + matchLen, posEnd - 4);
1170
+ for (let i = pos + 1; i < storeEnd; i++) hasher.store(ringbuffer, ringbufferMask, i);
1171
+ pos += matchLen;
1172
+ insertLen = 0;
1173
+ } else {
1174
+ hasher.store(ringbuffer, ringbufferMask, pos);
1175
+ insertLen++;
1176
+ pos++;
1177
+ }
1178
+ }
1179
+ if (insertLen > 0) {
1180
+ const cmd = createInsertCommand(insertLen);
1181
+ commands.push(cmd);
1182
+ numLiterals += insertLen;
1183
+ insertLen = 0;
1184
+ }
1185
+ return [
1186
+ commands,
1187
+ numLiterals,
1188
+ insertLen
1189
+ ];
1190
+ }
1191
+ const DISTANCE_CACHE_INDEX$1 = new Uint8Array([
1192
+ 0,
1193
+ 1,
1194
+ 2,
1195
+ 3,
1196
+ 0,
1197
+ 0,
1198
+ 0,
1199
+ 0,
1200
+ 0,
1201
+ 0,
1202
+ 1,
1203
+ 1,
1204
+ 1,
1205
+ 1,
1206
+ 1,
1207
+ 1
1208
+ ]);
1209
+ const DISTANCE_CACHE_OFFSET$1 = new Int8Array([
1210
+ 0,
1211
+ 0,
1212
+ 0,
1213
+ 0,
1214
+ -1,
1215
+ 1,
1216
+ -2,
1217
+ 2,
1218
+ -3,
1219
+ 3,
1220
+ -1,
1221
+ 1,
1222
+ -2,
1223
+ 2,
1224
+ -3,
1225
+ 3
1226
+ ]);
1227
+ function distanceToCode(distance, distCache) {
1228
+ for (let i = 0; i < NUM_DISTANCE_SHORT_CODES; i++) {
1229
+ const cached = distCache[DISTANCE_CACHE_INDEX$1[i]] + DISTANCE_CACHE_OFFSET$1[i];
1230
+ if (distance === cached && cached > 0) return i;
1231
+ }
1232
+ return distance + NUM_DISTANCE_SHORT_CODES - 1;
1233
+ }
1234
+ function backwardMatchLength(match) {
1235
+ return match.length;
1236
+ }
1237
+
1238
+ //#endregion
1239
+ //#region src/encode/zopfli-cost-model.ts
1240
+ const INFINITY_COST = 17e37;
1241
+ var ZopfliCostModel = class {
1242
+ constructor(numBytes, distanceAlphabetSize) {
1243
+ this.minCostCmd = INFINITY_COST;
1244
+ this.numBytes = numBytes;
1245
+ this.distanceHistogramSize = distanceAlphabetSize;
1246
+ this.costCmd = new Float32Array(NUM_COMMAND_CODES);
1247
+ this.costDist = new Float32Array(distanceAlphabetSize);
1248
+ this.literalCosts = new Float32Array(numBytes + 2);
1249
+ }
1250
+ setFromLiteralCosts(position, ringbuffer, ringbufferMask) {
1251
+ const literalHistograms = new Float64Array(3 * 256);
1252
+ this.estimateBitCostsForLiterals(position, this.numBytes, ringbufferMask, ringbuffer, literalHistograms);
1253
+ this.literalCosts[0] = 0;
1254
+ let literalCarry = 0;
1255
+ for (let i = 0; i < this.numBytes; i++) {
1256
+ const byte = ringbuffer[position + i & ringbufferMask];
1257
+ literalCarry += literalHistograms[byte];
1258
+ this.literalCosts[i + 1] = this.literalCosts[i] + literalCarry;
1259
+ literalCarry -= this.literalCosts[i + 1] - this.literalCosts[i];
1260
+ }
1261
+ for (let i = 0; i < NUM_COMMAND_CODES; i++) this.costCmd[i] = fastLog2(11 + i);
1262
+ for (let i = 0; i < this.distanceHistogramSize; i++) this.costDist[i] = fastLog2(20 + i);
1263
+ this.minCostCmd = fastLog2(11);
1264
+ }
1265
+ setFromCommands(position, ringbuffer, ringbufferMask, commands, lastInsertLen) {
1266
+ const histogramLiteral = new Uint32Array(NUM_LITERAL_CODES);
1267
+ const histogramCmd = new Uint32Array(NUM_COMMAND_CODES);
1268
+ const histogramDist = new Uint32Array(this.distanceHistogramSize);
1269
+ const costLiteral = new Float32Array(NUM_LITERAL_CODES);
1270
+ let pos = position - lastInsertLen;
1271
+ for (const cmd of commands) {
1272
+ const insLen = cmd.insertLen;
1273
+ const copyLen = commandCopyLen(cmd);
1274
+ const distCode = cmd.distPrefix & 1023;
1275
+ const cmdCode = cmd.cmdPrefix;
1276
+ histogramCmd[cmdCode]++;
1277
+ if (cmdCode >= 128) histogramDist[distCode]++;
1278
+ for (let j = 0; j < insLen; j++) histogramLiteral[ringbuffer[pos + j & ringbufferMask]]++;
1279
+ pos += insLen + copyLen;
1280
+ }
1281
+ this.setCostFromHistogram(histogramLiteral, true, costLiteral);
1282
+ this.setCostFromHistogram(histogramCmd, false, this.costCmd);
1283
+ this.setCostFromHistogram(histogramDist, false, this.costDist);
1284
+ this.minCostCmd = INFINITY_COST;
1285
+ for (let i = 0; i < NUM_COMMAND_CODES; i++) if (this.costCmd[i] < this.minCostCmd) this.minCostCmd = this.costCmd[i];
1286
+ this.literalCosts[0] = 0;
1287
+ let literalCarry = 0;
1288
+ for (let i = 0; i < this.numBytes; i++) {
1289
+ const byte = ringbuffer[position + i & ringbufferMask];
1290
+ literalCarry += costLiteral[byte];
1291
+ this.literalCosts[i + 1] = this.literalCosts[i] + literalCarry;
1292
+ literalCarry -= this.literalCosts[i + 1] - this.literalCosts[i];
1293
+ }
1294
+ }
1295
+ setCostFromHistogram(histogram, isLiteralHistogram, cost) {
1296
+ let sum = 0;
1297
+ for (let i = 0; i < histogram.length; i++) sum += histogram[i];
1298
+ const log2sum = fastLog2(sum);
1299
+ let missingSymbolSum = sum;
1300
+ if (!isLiteralHistogram) {
1301
+ for (let i = 0; i < histogram.length; i++) if (histogram[i] === 0) missingSymbolSum++;
1302
+ }
1303
+ const missingSymbolCost = fastLog2(missingSymbolSum) + 2;
1304
+ for (let i = 0; i < histogram.length; i++) if (histogram[i] === 0) cost[i] = missingSymbolCost;
1305
+ else {
1306
+ cost[i] = log2sum - fastLog2(histogram[i]);
1307
+ if (cost[i] < 1) cost[i] = 1;
1308
+ }
1309
+ }
1310
+ estimateBitCostsForLiterals(position, numBytes, ringbufferMask, ringbuffer, costs) {
1311
+ const histogram = new Uint32Array(256);
1312
+ for (let i = 0; i < numBytes; i++) histogram[ringbuffer[position + i & ringbufferMask]]++;
1313
+ const log2total = fastLog2(numBytes);
1314
+ for (let i = 0; i < 256; i++) if (histogram[i] === 0) costs[i] = log2total + 2;
1315
+ else {
1316
+ costs[i] = log2total - fastLog2(histogram[i]);
1317
+ if (costs[i] < 1) costs[i] = 1;
1318
+ }
1319
+ }
1320
+ getCommandCost(cmdCode) {
1321
+ return this.costCmd[cmdCode];
1322
+ }
1323
+ getDistanceCost(distCode) {
1324
+ return this.costDist[distCode];
1325
+ }
1326
+ getLiteralCosts(from, to) {
1327
+ return this.literalCosts[to] - this.literalCosts[from];
1328
+ }
1329
+ getMinCostCmd() {
1330
+ return this.minCostCmd;
1331
+ }
1332
+ };
1333
+
1334
+ //#endregion
1335
+ //#region src/encode/backward-references-hq.ts
1336
+ const DISTANCE_CACHE_INDEX = new Uint8Array([
1337
+ 0,
1338
+ 1,
1339
+ 2,
1340
+ 3,
1341
+ 0,
1342
+ 0,
1343
+ 0,
1344
+ 0,
1345
+ 0,
1346
+ 0,
1347
+ 1,
1348
+ 1,
1349
+ 1,
1350
+ 1,
1351
+ 1,
1352
+ 1
1353
+ ]);
1354
+ const DISTANCE_CACHE_OFFSET = new Int8Array([
1355
+ 0,
1356
+ 0,
1357
+ 0,
1358
+ 0,
1359
+ -1,
1360
+ 1,
1361
+ -2,
1362
+ 2,
1363
+ -3,
1364
+ 3,
1365
+ -1,
1366
+ 1,
1367
+ -2,
1368
+ 2,
1369
+ -3,
1370
+ 3
1371
+ ]);
1372
+ const LONG_COPY_QUICK_STEP = 16384;
1373
+ function createZopfliNodes(length) {
1374
+ const nodes = new Array(length);
1375
+ for (let i = 0; i < length; i++) nodes[i] = {
1376
+ length: 1,
1377
+ distance: 0,
1378
+ dcodeInsertLength: 0,
1379
+ cost: INFINITY_COST,
1380
+ shortcut: 0
1381
+ };
1382
+ return nodes;
1383
+ }
1384
+ function zopfliNodeCopyLength(node) {
1385
+ return node.length & 33554431;
1386
+ }
1387
+ function zopfliNodeLengthCode(node) {
1388
+ const modifier = node.length >>> 25;
1389
+ return zopfliNodeCopyLength(node) + 9 - modifier;
1390
+ }
1391
+ function zopfliNodeCopyDistance(node) {
1392
+ return node.distance;
1393
+ }
1394
+ function zopfliNodeDistanceCode(node) {
1395
+ const shortCode = node.dcodeInsertLength >>> 27;
1396
+ return shortCode === 0 ? zopfliNodeCopyDistance(node) + NUM_DISTANCE_SHORT_CODES - 1 : shortCode - 1;
1397
+ }
1398
+ function zopfliNodeCommandLength(node) {
1399
+ return zopfliNodeCopyLength(node) + (node.dcodeInsertLength & 134217727);
1400
+ }
1401
+ function zopfliNodeInsertLength(node) {
1402
+ return node.dcodeInsertLength & 134217727;
1403
+ }
1404
+ var StartPosQueue = class {
1405
+ constructor() {
1406
+ this.q = [];
1407
+ this.idx = 0;
1408
+ }
1409
+ push(posdata) {
1410
+ const offset = ~this.idx++ & 7;
1411
+ while (this.q.length < 8) this.q.push({
1412
+ pos: 0,
1413
+ distanceCache: new Int32Array(4),
1414
+ costdiff: INFINITY_COST,
1415
+ cost: INFINITY_COST
1416
+ });
1417
+ this.q[offset] = {
1418
+ pos: posdata.pos,
1419
+ distanceCache: posdata.distanceCache.slice(),
1420
+ costdiff: posdata.costdiff,
1421
+ cost: posdata.cost
1422
+ };
1423
+ const len = this.size();
1424
+ for (let i = 1; i < len; i++) {
1425
+ const a = offset + i - 1 & 7;
1426
+ const b = offset + i & 7;
1427
+ if (this.q[a].costdiff > this.q[b].costdiff) {
1428
+ const tmp = this.q[a];
1429
+ this.q[a] = this.q[b];
1430
+ this.q[b] = tmp;
1431
+ }
1432
+ }
1433
+ }
1434
+ size() {
1435
+ return Math.min(this.idx, 8);
1436
+ }
1437
+ at(k) {
1438
+ return this.q[k - this.idx & 7];
1439
+ }
1440
+ reset() {
1441
+ this.idx = 0;
1442
+ }
1443
+ };
1444
+ function updateZopfliNode(nodes, pos, startPos, len, lenCode, dist, shortCode, cost) {
1445
+ const next = nodes[pos + len];
1446
+ next.length = len | len + 9 - lenCode << 25;
1447
+ next.distance = dist;
1448
+ next.dcodeInsertLength = shortCode << 27 | pos - startPos;
1449
+ next.cost = cost;
1450
+ }
1451
+ function computeMinimumCopyLength(startCost, nodes, numBytes, pos) {
1452
+ let minCost = startCost;
1453
+ let len = 2;
1454
+ let nextLenBucket = 4;
1455
+ let nextLenOffset = 10;
1456
+ while (pos + len <= numBytes && nodes[pos + len].cost <= minCost) {
1457
+ len++;
1458
+ if (len === nextLenOffset) {
1459
+ minCost += 1;
1460
+ nextLenOffset += nextLenBucket;
1461
+ nextLenBucket *= 2;
1462
+ }
1463
+ }
1464
+ return len;
1465
+ }
1466
+ function computeDistanceShortcut(blockStart, pos, maxBackwardLimit, gap, nodes) {
1467
+ if (pos === 0) return 0;
1468
+ const cLen = zopfliNodeCopyLength(nodes[pos]);
1469
+ const iLen = zopfliNodeInsertLength(nodes[pos]);
1470
+ const dist = zopfliNodeCopyDistance(nodes[pos]);
1471
+ if (dist + cLen <= blockStart + pos + gap && dist <= maxBackwardLimit + gap && zopfliNodeDistanceCode(nodes[pos]) > 0) return pos;
1472
+ else return nodes[pos - cLen - iLen].shortcut;
1473
+ }
1474
+ function computeDistanceCache(pos, startingDistCache, nodes, distCache) {
1475
+ let idx = 0;
1476
+ let p = nodes[pos].shortcut;
1477
+ while (idx < 4 && p > 0) {
1478
+ const iLen = zopfliNodeInsertLength(nodes[p]);
1479
+ const cLen = zopfliNodeCopyLength(nodes[p]);
1480
+ const dist = zopfliNodeCopyDistance(nodes[p]);
1481
+ distCache[idx++] = dist;
1482
+ p = nodes[p - cLen - iLen].shortcut;
1483
+ }
1484
+ for (; idx < 4; idx++) distCache[idx] = startingDistCache[idx - (4 - idx)];
1485
+ }
1486
+ function evaluateNode(blockStart, pos, maxBackwardLimit, gap, startingDistCache, model, queue, nodes) {
1487
+ const nodeCost = nodes[pos].cost;
1488
+ nodes[pos].shortcut = computeDistanceShortcut(blockStart, pos, maxBackwardLimit, gap, nodes);
1489
+ if (nodeCost <= model.getLiteralCosts(0, pos)) {
1490
+ const distanceCache = new Int32Array(4);
1491
+ computeDistanceCache(pos, startingDistCache, nodes, distanceCache);
1492
+ queue.push({
1493
+ pos,
1494
+ cost: nodeCost,
1495
+ costdiff: nodeCost - model.getLiteralCosts(0, pos),
1496
+ distanceCache
1497
+ });
1498
+ }
1499
+ }
1500
+ function updateNodes(numBytes, blockStart, pos, ringbuffer, ringbufferMask, quality, maxBackwardLimit, startingDistCache, numMatches, matches, model, queue, nodes) {
1501
+ const curIx = blockStart + pos;
1502
+ const curIxMasked = curIx & ringbufferMask;
1503
+ const maxDistance = Math.min(curIx, maxBackwardLimit);
1504
+ const maxLen = numBytes - pos;
1505
+ const maxZopfliLenVal = maxZopfliLen(quality);
1506
+ const maxIters = maxZopfliCandidates(quality);
1507
+ evaluateNode(blockStart, pos, maxBackwardLimit, 0, startingDistCache, model, queue, nodes);
1508
+ const posdata0 = queue.at(0);
1509
+ let minLen = computeMinimumCopyLength(posdata0.cost + model.getMinCostCmd() + model.getLiteralCosts(posdata0.pos, pos), nodes, numBytes, pos);
1510
+ let result = 0;
1511
+ for (let k = 0; k < maxIters && k < queue.size(); k++) {
1512
+ const posdata = queue.at(k);
1513
+ const start = posdata.pos;
1514
+ const insCode = getInsertLengthCode(pos - start);
1515
+ const baseCost = posdata.costdiff + getInsertExtra(insCode) + model.getLiteralCosts(0, pos);
1516
+ let bestLen = minLen - 1;
1517
+ for (let j = 0; j < NUM_DISTANCE_SHORT_CODES && bestLen < maxLen; j++) {
1518
+ const idx = DISTANCE_CACHE_INDEX[j];
1519
+ const backward = posdata.distanceCache[idx] + DISTANCE_CACHE_OFFSET[j];
1520
+ if (backward <= 0 || backward > maxDistance) continue;
1521
+ let prevIx = curIx - backward;
1522
+ prevIx &= ringbufferMask;
1523
+ if (curIxMasked + bestLen > ringbufferMask) break;
1524
+ if (ringbuffer[prevIx + bestLen] !== ringbuffer[curIxMasked + bestLen]) continue;
1525
+ const len = findMatchLength(ringbuffer, prevIx, curIxMasked, maxLen);
1526
+ if (len >= 4) {
1527
+ const distCost = baseCost + model.getDistanceCost(j);
1528
+ for (let l = bestLen + 1; l <= len; l++) {
1529
+ const copyCode = getCopyLengthCode(l);
1530
+ const cmdCode = combineLengthCodes(insCode, copyCode, j === 0);
1531
+ const cost = (cmdCode < 128 ? baseCost : distCost) + getCopyExtra(copyCode) + model.getCommandCost(cmdCode);
1532
+ if (cost < nodes[pos + l].cost) {
1533
+ updateZopfliNode(nodes, pos, start, l, l, backward, j + 1, cost);
1534
+ result = Math.max(result, l);
1535
+ }
1536
+ bestLen = l;
1537
+ }
1538
+ }
1539
+ }
1540
+ if (k >= 2) continue;
1541
+ let matchLen = minLen;
1542
+ for (let j = 0; j < numMatches; j++) {
1543
+ const match = matches[j];
1544
+ const dist = match.distance;
1545
+ const isDictionaryMatch = dist > maxDistance;
1546
+ const distCode = dist + NUM_DISTANCE_SHORT_CODES - 1;
1547
+ const distCost = baseCost + (distCode < NUM_DISTANCE_SHORT_CODES ? 0 : log2FloorNonZero(dist) - 1) + model.getDistanceCost(distCode & 1023);
1548
+ let maxMatchLen = backwardMatchLength(match);
1549
+ if (matchLen < maxMatchLen && (isDictionaryMatch || maxMatchLen > maxZopfliLenVal)) matchLen = maxMatchLen;
1550
+ for (; matchLen <= maxMatchLen; matchLen++) {
1551
+ const lenCode = isDictionaryMatch ? match.length + match.lenCodeDelta : matchLen;
1552
+ const copyCode = getCopyLengthCode(lenCode);
1553
+ const cmdCode = combineLengthCodes(insCode, copyCode, false);
1554
+ const cost = distCost + getCopyExtra(copyCode) + model.getCommandCost(cmdCode);
1555
+ if (cost < nodes[pos + matchLen].cost) {
1556
+ updateZopfliNode(nodes, pos, start, matchLen, lenCode, dist, 0, cost);
1557
+ result = Math.max(result, matchLen);
1558
+ }
1559
+ }
1560
+ }
1561
+ }
1562
+ return result;
1563
+ }
1564
+ function computeShortestPathFromNodes(numBytes, nodes) {
1565
+ let index = numBytes;
1566
+ let numCommands = 0;
1567
+ while ((nodes[index].dcodeInsertLength & 134217727) === 0 && nodes[index].length === 1) index--;
1568
+ nodes[index].cost = 4294967295;
1569
+ while (index !== 0) {
1570
+ const len = zopfliNodeCommandLength(nodes[index]);
1571
+ index -= len;
1572
+ nodes[index].cost = len;
1573
+ numCommands++;
1574
+ }
1575
+ return numCommands;
1576
+ }
1577
+ function createZopfliBackwardReferences(numBytes, position, ringbuffer, ringbufferMask, quality, hasher, distCache, lastInsertLen) {
1578
+ const maxBackwardLimit = (1 << 22) - 16;
1579
+ const maxZopfliLenVal = maxZopfliLen(quality);
1580
+ const nodes = createZopfliNodes(numBytes + 1);
1581
+ nodes[0].length = 0;
1582
+ nodes[0].cost = 0;
1583
+ const model = new ZopfliCostModel(numBytes, 544);
1584
+ model.setFromLiteralCosts(position, ringbuffer, ringbufferMask);
1585
+ const queue = new StartPosQueue();
1586
+ for (let i = 0; i + 3 < numBytes; i++) {
1587
+ const pos = position + i;
1588
+ const maxDistance = Math.min(pos, maxBackwardLimit);
1589
+ const matches = hasher.findAllMatches(ringbuffer, ringbufferMask, pos, numBytes - i, maxDistance);
1590
+ if (matches.length > 0) {
1591
+ const longestMatch = matches[matches.length - 1];
1592
+ if (backwardMatchLength(longestMatch) > maxZopfliLenVal) {
1593
+ matches.length = 0;
1594
+ matches.push(longestMatch);
1595
+ }
1596
+ }
1597
+ const skip = updateNodes(numBytes, position, i, ringbuffer, ringbufferMask, quality, maxBackwardLimit, distCache, matches.length, matches, model, queue, nodes);
1598
+ if (skip >= LONG_COPY_QUICK_STEP) i += skip - 1;
1599
+ else if (matches.length === 1 && backwardMatchLength(matches[0]) > maxZopfliLenVal) i += backwardMatchLength(matches[0]) - 1;
1600
+ }
1601
+ computeShortestPathFromNodes(numBytes, nodes);
1602
+ return createCommandsFromPath(numBytes, position, nodes, distCache, lastInsertLen);
1603
+ }
1604
+ function createHqZopfliBackwardReferences(numBytes, position, ringbuffer, ringbufferMask, hasher, distCache, lastInsertLen) {
1605
+ const quality = 11;
1606
+ const maxBackwardLimit = (1 << 22) - 16;
1607
+ const maxZopfliLenVal = maxZopfliLen(quality);
1608
+ const allMatches = [];
1609
+ const numMatchesPerPos = [];
1610
+ for (let i = 0; i + 3 < numBytes; i++) {
1611
+ const pos = position + i;
1612
+ const maxDistance = Math.min(pos, maxBackwardLimit);
1613
+ const matches = hasher.findAllMatches(ringbuffer, ringbufferMask, pos, numBytes - i, maxDistance);
1614
+ if (matches.length > 0) {
1615
+ const longestMatch = matches[matches.length - 1];
1616
+ if (backwardMatchLength(longestMatch) > maxZopfliLenVal) {
1617
+ const skip = backwardMatchLength(longestMatch) - 1;
1618
+ allMatches.push([longestMatch]);
1619
+ numMatchesPerPos.push(1);
1620
+ for (let j = 0; j < skip && i + j + 1 < numBytes; j++) {
1621
+ allMatches.push([]);
1622
+ numMatchesPerPos.push(0);
1623
+ }
1624
+ i += skip;
1625
+ continue;
1626
+ }
1627
+ }
1628
+ allMatches.push(matches);
1629
+ numMatchesPerPos.push(matches.length);
1630
+ }
1631
+ while (allMatches.length < numBytes) {
1632
+ allMatches.push([]);
1633
+ numMatchesPerPos.push(0);
1634
+ }
1635
+ const origDistCache = distCache.slice();
1636
+ const origLastInsertLen = lastInsertLen;
1637
+ const model = new ZopfliCostModel(numBytes, 544);
1638
+ let commands = [];
1639
+ let numLiterals = 0;
1640
+ let finalLastInsertLen = lastInsertLen;
1641
+ for (let iteration = 0; iteration < 2; iteration++) {
1642
+ const nodes = createZopfliNodes(numBytes + 1);
1643
+ nodes[0].length = 0;
1644
+ nodes[0].cost = 0;
1645
+ distCache.set(origDistCache);
1646
+ lastInsertLen = origLastInsertLen;
1647
+ if (iteration === 0) model.setFromLiteralCosts(position, ringbuffer, ringbufferMask);
1648
+ else model.setFromCommands(position, ringbuffer, ringbufferMask, commands, origLastInsertLen);
1649
+ const queue = new StartPosQueue();
1650
+ for (let i = 0; i + 3 < numBytes; i++) {
1651
+ const numMatches = numMatchesPerPos[i];
1652
+ const matches = allMatches[i];
1653
+ const skip = updateNodes(numBytes, position, i, ringbuffer, ringbufferMask, quality, maxBackwardLimit, distCache, numMatches, matches, model, queue, nodes);
1654
+ if (skip >= LONG_COPY_QUICK_STEP) i += skip - 1;
1655
+ else if (numMatches === 1 && backwardMatchLength(matches[0]) > maxZopfliLenVal) i += backwardMatchLength(matches[0]) - 1;
1656
+ }
1657
+ computeShortestPathFromNodes(numBytes, nodes);
1658
+ [commands, numLiterals, finalLastInsertLen] = createCommandsFromPath(numBytes, position, nodes, distCache, lastInsertLen);
1659
+ }
1660
+ return [
1661
+ commands,
1662
+ numLiterals,
1663
+ finalLastInsertLen
1664
+ ];
1665
+ }
1666
+ function createCommandsFromPath(numBytes, blockStart, nodes, distCache, lastInsertLen) {
1667
+ const maxBackwardLimit = (1 << 22) - 16;
1668
+ const commands = [];
1669
+ let numLiterals = 0;
1670
+ let pos = 0;
1671
+ let offset = nodes[0].cost;
1672
+ let isFirst = true;
1673
+ while (offset !== 4294967295 && offset !== 0) {
1674
+ const next = nodes[pos + offset];
1675
+ const copyLen = zopfliNodeCopyLength(next);
1676
+ let insertLen = zopfliNodeInsertLength(next);
1677
+ pos += insertLen;
1678
+ if (isFirst) {
1679
+ insertLen += lastInsertLen;
1680
+ isFirst = false;
1681
+ }
1682
+ const distance = zopfliNodeCopyDistance(next);
1683
+ const lenCode = zopfliNodeLengthCode(next);
1684
+ const distCode = zopfliNodeDistanceCode(next);
1685
+ const cmd = createCommand(insertLen, copyLen, lenCode - copyLen, distCode);
1686
+ commands.push(cmd);
1687
+ if (!(distance > Math.min(blockStart + pos, maxBackwardLimit)) && distCode > 0) {
1688
+ distCache[3] = distCache[2];
1689
+ distCache[2] = distCache[1];
1690
+ distCache[1] = distCache[0];
1691
+ distCache[0] = distance;
1692
+ }
1693
+ numLiterals += insertLen;
1694
+ pos += copyLen;
1695
+ offset = next.cost;
1696
+ }
1697
+ const finalInsertLen = numBytes - pos;
1698
+ return [
1699
+ commands,
1700
+ numLiterals,
1701
+ finalInsertLen
1702
+ ];
1703
+ }
1704
+
1705
+ //#endregion
1706
+ //#region src/encode/histogram.ts
1707
+ const NUM_DISTANCE_HISTOGRAM_SYMBOLS = 544;
1708
+ function createHistogramLiteral() {
1709
+ return {
1710
+ data: new Uint32Array(NUM_LITERAL_CODES),
1711
+ totalCount: 0,
1712
+ bitCost: Infinity
1713
+ };
1714
+ }
1715
+ function createHistogramCommand() {
1716
+ return {
1717
+ data: new Uint32Array(NUM_COMMAND_CODES),
1718
+ totalCount: 0,
1719
+ bitCost: Infinity
1720
+ };
1721
+ }
1722
+ function createHistogramDistance() {
1723
+ return {
1724
+ data: new Uint32Array(NUM_DISTANCE_HISTOGRAM_SYMBOLS),
1725
+ totalCount: 0,
1726
+ bitCost: Infinity
1727
+ };
1728
+ }
1729
+ function histogramAdd(histogram, symbol) {
1730
+ histogram.data[symbol]++;
1731
+ histogram.totalCount++;
1732
+ }
1733
+
1734
+ //#endregion
1735
+ //#region src/encode/entropy-encode.ts
1736
+ const MAX_HUFFMAN_BITS = 15;
1737
+ const SHELL_GAPS = [
1738
+ 132,
1739
+ 57,
1740
+ 23,
1741
+ 10,
1742
+ 4,
1743
+ 1
1744
+ ];
1745
+ function createHuffmanTree(histogram, treeLimit = MAX_HUFFMAN_BITS) {
1746
+ const length = histogram.length;
1747
+ const depths = new Uint8Array(length);
1748
+ const bits = new Uint16Array(length);
1749
+ let nonZeroCount = 0;
1750
+ let lastNonZero = 0;
1751
+ for (let i = 0; i < length; i++) if (histogram[i] > 0) {
1752
+ nonZeroCount++;
1753
+ lastNonZero = i;
1754
+ }
1755
+ if (nonZeroCount === 0) return {
1756
+ depths,
1757
+ bits
1758
+ };
1759
+ if (nonZeroCount === 1) {
1760
+ depths[lastNonZero] = 1;
1761
+ bits[lastNonZero] = 0;
1762
+ return {
1763
+ depths,
1764
+ bits
1765
+ };
1766
+ }
1767
+ const tree = new Array(2 * length + 2);
1768
+ for (let countLimit = 1;; countLimit *= 2) {
1769
+ let n = 0;
1770
+ for (let i = length - 1; i >= 0; i--) if (histogram[i] > 0) {
1771
+ const count = Math.max(histogram[i], countLimit);
1772
+ tree[n++] = {
1773
+ totalCount: count,
1774
+ indexLeft: -1,
1775
+ indexRightOrValue: i
1776
+ };
1777
+ }
1778
+ sortHuffmanNodes(tree, n);
1779
+ const sentinel = {
1780
+ totalCount: 4294967295,
1781
+ indexLeft: -1,
1782
+ indexRightOrValue: -1
1783
+ };
1784
+ tree[n] = sentinel;
1785
+ tree[n + 1] = sentinel;
1786
+ let i = 0;
1787
+ let j = n + 1;
1788
+ for (let k = n - 1; k > 0; k--) {
1789
+ let left;
1790
+ if (tree[i].totalCount <= tree[j].totalCount) left = i++;
1791
+ else left = j++;
1792
+ let right;
1793
+ if (tree[i].totalCount <= tree[j].totalCount) right = i++;
1794
+ else right = j++;
1795
+ const jEnd = 2 * n - k;
1796
+ tree[jEnd] = {
1797
+ totalCount: tree[left].totalCount + tree[right].totalCount,
1798
+ indexLeft: left,
1799
+ indexRightOrValue: right
1800
+ };
1801
+ tree[jEnd + 1] = sentinel;
1802
+ }
1803
+ if (setDepth(2 * n - 1, tree, depths, treeLimit)) break;
1804
+ depths.fill(0);
1805
+ }
1806
+ convertBitDepthsToSymbols(depths, bits);
1807
+ return {
1808
+ depths,
1809
+ bits
1810
+ };
1811
+ }
1812
+ function setDepth(root, tree, depths, maxDepth) {
1813
+ const stack = new Int32Array(16);
1814
+ let level = 0;
1815
+ let p = root;
1816
+ stack[0] = -1;
1817
+ while (true) {
1818
+ if (tree[p].indexLeft >= 0) {
1819
+ level++;
1820
+ if (level > maxDepth) return false;
1821
+ stack[level] = tree[p].indexRightOrValue;
1822
+ p = tree[p].indexLeft;
1823
+ continue;
1824
+ } else depths[tree[p].indexRightOrValue] = level;
1825
+ while (level >= 0 && stack[level] === -1) level--;
1826
+ if (level < 0) return true;
1827
+ p = stack[level];
1828
+ stack[level] = -1;
1829
+ }
1830
+ }
1831
+ function sortHuffmanNodes(nodes, n) {
1832
+ if (n < 13) for (let i = 1; i < n; i++) {
1833
+ const tmp = nodes[i];
1834
+ let k = i;
1835
+ let j = i - 1;
1836
+ while (j >= 0 && compareNodes(tmp, nodes[j])) {
1837
+ nodes[k] = nodes[j];
1838
+ k = j;
1839
+ j--;
1840
+ }
1841
+ nodes[k] = tmp;
1842
+ }
1843
+ else {
1844
+ const startGap = n < 57 ? 2 : 0;
1845
+ for (let g = startGap; g < 6; g++) {
1846
+ const gap = SHELL_GAPS[g];
1847
+ for (let i = gap; i < n; i++) {
1848
+ let j = i;
1849
+ const tmp = nodes[i];
1850
+ while (j >= gap && compareNodes(tmp, nodes[j - gap])) {
1851
+ nodes[j] = nodes[j - gap];
1852
+ j -= gap;
1853
+ }
1854
+ nodes[j] = tmp;
1855
+ }
1856
+ }
1857
+ }
1858
+ }
1859
+ function compareNodes(a, b) {
1860
+ if (a.totalCount !== b.totalCount) return a.totalCount < b.totalCount;
1861
+ return a.indexRightOrValue > b.indexRightOrValue;
1862
+ }
1863
+ function reverseBits(numBits, bits) {
1864
+ const LUT = [
1865
+ 0,
1866
+ 8,
1867
+ 4,
1868
+ 12,
1869
+ 2,
1870
+ 10,
1871
+ 6,
1872
+ 14,
1873
+ 1,
1874
+ 9,
1875
+ 5,
1876
+ 13,
1877
+ 3,
1878
+ 11,
1879
+ 7,
1880
+ 15
1881
+ ];
1882
+ let retval = LUT[bits & 15];
1883
+ for (let i = 4; i < numBits; i += 4) {
1884
+ retval <<= 4;
1885
+ bits >>>= 4;
1886
+ retval |= LUT[bits & 15];
1887
+ }
1888
+ retval >>>= -numBits & 3;
1889
+ return retval;
1890
+ }
1891
+ function convertBitDepthsToSymbols(depths, bits) {
1892
+ const len = depths.length;
1893
+ const blCount = new Uint16Array(MAX_HUFFMAN_BITS + 1);
1894
+ const nextCode = new Uint16Array(MAX_HUFFMAN_BITS + 1);
1895
+ for (let i = 0; i < len; i++) blCount[depths[i]]++;
1896
+ blCount[0] = 0;
1897
+ let code = 0;
1898
+ for (let i = 1; i <= MAX_HUFFMAN_BITS; i++) {
1899
+ code = code + blCount[i - 1] << 1;
1900
+ nextCode[i] = code;
1901
+ }
1902
+ for (let i = 0; i < len; i++) if (depths[i] > 0) bits[i] = reverseBits(depths[i], nextCode[depths[i]]++);
1903
+ }
1904
+
1905
+ //#endregion
1906
+ //#region src/encode/context-map.ts
1907
+ function buildAndStoreHuffmanTree(writer, histogram, alphabetSize, depths, bits) {
1908
+ let count = 0;
1909
+ const s4 = [
1910
+ 0,
1911
+ 0,
1912
+ 0,
1913
+ 0
1914
+ ];
1915
+ for (let i = 0; i < alphabetSize; i++) if (histogram[i]) {
1916
+ if (count < 4) s4[count] = i;
1917
+ count++;
1918
+ }
1919
+ let maxBits = 0;
1920
+ let maxBitsCounter = alphabetSize - 1;
1921
+ while (maxBitsCounter) {
1922
+ maxBitsCounter >>>= 1;
1923
+ maxBits++;
1924
+ }
1925
+ if (count <= 1) {
1926
+ writer.writeBits(4, 1);
1927
+ writer.writeBits(maxBits, s4[0]);
1928
+ depths[s4[0]] = 0;
1929
+ bits[s4[0]] = 0;
1930
+ return;
1931
+ }
1932
+ depths.fill(0);
1933
+ const tree = createHuffmanTree(histogram.subarray(0, alphabetSize), 15);
1934
+ depths.set(tree.depths.subarray(0, alphabetSize));
1935
+ convertBitDepthsToSymbols(depths, bits);
1936
+ if (count <= 4) storeSimpleHuffmanTree(writer, depths, s4, count, maxBits);
1937
+ else storeComplexHuffmanTree(writer, depths, alphabetSize);
1938
+ }
1939
+ function storeSimpleHuffmanTree(writer, depths, symbols, numSymbols, maxBits) {
1940
+ const sorted = symbols.slice(0, numSymbols);
1941
+ sorted.sort((a, b) => depths[a] - depths[b]);
1942
+ writer.writeBits(2, 1);
1943
+ writer.writeBits(2, numSymbols - 1);
1944
+ for (let i = 0; i < numSymbols; i++) writer.writeBits(maxBits, sorted[i]);
1945
+ if (numSymbols === 4) writer.writeBits(1, depths[sorted[0]] === 1 ? 1 : 0);
1946
+ }
1947
+ function storeComplexHuffmanTree(writer, depths, length) {
1948
+ const huffmanTree = [];
1949
+ const huffmanTreeExtraBits = [];
1950
+ writeHuffmanTreeRepresentation(depths, length, huffmanTree, huffmanTreeExtraBits);
1951
+ const codeLengthHistogram = new Uint32Array(18);
1952
+ for (const code of huffmanTree) codeLengthHistogram[code]++;
1953
+ let numCodes = 0;
1954
+ let firstCode = 0;
1955
+ for (let i = 0; i < 18; i++) if (codeLengthHistogram[i]) {
1956
+ if (numCodes === 0) firstCode = i;
1957
+ numCodes++;
1958
+ }
1959
+ const codeLengthDepths = new Uint8Array(18);
1960
+ const codeLengthBits = new Uint16Array(18);
1961
+ const tree = createHuffmanTree(codeLengthHistogram, 5);
1962
+ codeLengthDepths.set(tree.depths.subarray(0, 18));
1963
+ convertBitDepthsToSymbols(codeLengthDepths, codeLengthBits);
1964
+ storeHuffmanTreeOfHuffmanTree(writer, numCodes, codeLengthDepths);
1965
+ if (numCodes === 1) codeLengthDepths[firstCode] = 0;
1966
+ for (let i = 0; i < huffmanTree.length; i++) {
1967
+ const code = huffmanTree[i];
1968
+ writer.writeBits(codeLengthDepths[code], codeLengthBits[code]);
1969
+ if (code === 16) writer.writeBits(2, huffmanTreeExtraBits[i]);
1970
+ else if (code === 17) writer.writeBits(3, huffmanTreeExtraBits[i]);
1971
+ }
1972
+ }
1973
+ function writeHuffmanTreeRepresentation(depths, length, tree, extraBits) {
1974
+ const INITIAL_PREV = 8;
1975
+ let newLength = length;
1976
+ while (newLength > 0 && depths[newLength - 1] === 0) newLength--;
1977
+ let prevValue = INITIAL_PREV;
1978
+ let i = 0;
1979
+ while (i < newLength) {
1980
+ const value = depths[i];
1981
+ let reps = 1;
1982
+ while (i + reps < newLength && depths[i + reps] === value) reps++;
1983
+ i += reps;
1984
+ if (value === 0) writeHuffmanTreeRepetitionsZeros(reps, tree, extraBits);
1985
+ else {
1986
+ writeHuffmanTreeRepetitions(prevValue, value, reps, tree, extraBits);
1987
+ prevValue = value;
1988
+ }
1989
+ }
1990
+ }
1991
+ function writeHuffmanTreeRepetitions(prevValue, value, reps, tree, extraBits) {
1992
+ const REPEAT_PREVIOUS = 16;
1993
+ if (prevValue !== value) {
1994
+ tree.push(value);
1995
+ extraBits.push(0);
1996
+ reps--;
1997
+ }
1998
+ if (reps === 7) {
1999
+ tree.push(value);
2000
+ extraBits.push(0);
2001
+ reps--;
2002
+ }
2003
+ if (reps < 3) for (let j = 0; j < reps; j++) {
2004
+ tree.push(value);
2005
+ extraBits.push(0);
2006
+ }
2007
+ else {
2008
+ const startIdx = tree.length;
2009
+ reps -= 3;
2010
+ while (true) {
2011
+ tree.push(REPEAT_PREVIOUS);
2012
+ extraBits.push(reps & 3);
2013
+ reps >>>= 2;
2014
+ if (reps === 0) break;
2015
+ reps--;
2016
+ }
2017
+ reverseArraySlice(tree, startIdx, tree.length);
2018
+ reverseArraySlice(extraBits, startIdx, extraBits.length);
2019
+ }
2020
+ }
2021
+ function writeHuffmanTreeRepetitionsZeros(reps, tree, extraBits) {
2022
+ const REPEAT_ZERO = 17;
2023
+ if (reps === 11) {
2024
+ tree.push(0);
2025
+ extraBits.push(0);
2026
+ reps--;
2027
+ }
2028
+ if (reps < 3) for (let j = 0; j < reps; j++) {
2029
+ tree.push(0);
2030
+ extraBits.push(0);
2031
+ }
2032
+ else {
2033
+ const startIdx = tree.length;
2034
+ reps -= 3;
2035
+ while (true) {
2036
+ tree.push(REPEAT_ZERO);
2037
+ extraBits.push(reps & 7);
2038
+ reps >>>= 3;
2039
+ if (reps === 0) break;
2040
+ reps--;
2041
+ }
2042
+ reverseArraySlice(tree, startIdx, tree.length);
2043
+ reverseArraySlice(extraBits, startIdx, extraBits.length);
2044
+ }
2045
+ }
2046
+ function reverseArraySlice(arr, start, end) {
2047
+ while (start < end - 1) {
2048
+ const tmp = arr[start];
2049
+ arr[start] = arr[end - 1];
2050
+ arr[end - 1] = tmp;
2051
+ start++;
2052
+ end--;
2053
+ }
2054
+ }
2055
+ function storeHuffmanTreeOfHuffmanTree(writer, numCodes, depths) {
2056
+ const storageOrder = [
2057
+ 1,
2058
+ 2,
2059
+ 3,
2060
+ 4,
2061
+ 0,
2062
+ 5,
2063
+ 17,
2064
+ 6,
2065
+ 16,
2066
+ 7,
2067
+ 8,
2068
+ 9,
2069
+ 10,
2070
+ 11,
2071
+ 12,
2072
+ 13,
2073
+ 14,
2074
+ 15
2075
+ ];
2076
+ const symbols = [
2077
+ 0,
2078
+ 7,
2079
+ 3,
2080
+ 2,
2081
+ 1,
2082
+ 15
2083
+ ];
2084
+ const bitLengths = [
2085
+ 2,
2086
+ 4,
2087
+ 3,
2088
+ 2,
2089
+ 2,
2090
+ 4
2091
+ ];
2092
+ let codesToStore = 18;
2093
+ if (numCodes > 1) while (codesToStore > 0 && depths[storageOrder[codesToStore - 1]] === 0) codesToStore--;
2094
+ let skipSome = 0;
2095
+ if (depths[storageOrder[0]] === 0 && depths[storageOrder[1]] === 0) {
2096
+ skipSome = 2;
2097
+ if (depths[storageOrder[2]] === 0) skipSome = 3;
2098
+ }
2099
+ writer.writeBits(2, skipSome);
2100
+ for (let i = skipSome; i < codesToStore; i++) {
2101
+ const len = depths[storageOrder[i]];
2102
+ writer.writeBits(bitLengths[len], symbols[len]);
2103
+ }
2104
+ }
2105
+
2106
+ //#endregion
2107
+ //#region src/encode/metablock.ts
2108
+ function encodeMlen(length) {
2109
+ const lg = length === 1 ? 1 : log2FloorNonZero(length - 1) + 1;
2110
+ const mnibbles = Math.floor((lg < 16 ? 16 : lg + 3) / 4);
2111
+ return {
2112
+ bits: BigInt(length - 1),
2113
+ numBits: mnibbles * 4,
2114
+ nibblesBits: mnibbles - 4
2115
+ };
2116
+ }
2117
+ function storeCompressedMetaBlockHeader(writer, isLast, length) {
2118
+ writer.writeBits(1, isLast ? 1 : 0);
2119
+ if (isLast) writer.writeBits(1, 0);
2120
+ const { bits, numBits, nibblesBits } = encodeMlen(length);
2121
+ writer.writeBits(2, nibblesBits);
2122
+ writer.writeBitsLong(numBits, bits);
2123
+ if (!isLast) writer.writeBits(1, 0);
2124
+ }
2125
+ function storeUncompressedMetaBlockHeader(writer, length) {
2126
+ writer.writeBits(1, 0);
2127
+ const { bits, numBits, nibblesBits } = encodeMlen(length);
2128
+ writer.writeBits(2, nibblesBits);
2129
+ writer.writeBitsLong(numBits, bits);
2130
+ writer.writeBits(1, 1);
2131
+ }
2132
+ function storeCommandExtra(writer, cmd) {
2133
+ const copyLenCode = commandCopyLenCode(cmd);
2134
+ const insCode = getInsertLengthCode(cmd.insertLen);
2135
+ const copyCode = getCopyLengthCode(copyLenCode);
2136
+ const insNumExtra = getInsertExtra(insCode);
2137
+ const insExtraVal = cmd.insertLen - getInsertBase(insCode);
2138
+ const copyExtraVal = copyLenCode - getCopyBase(copyCode);
2139
+ const totalBits = insNumExtra + getCopyExtra(copyCode);
2140
+ const combinedBits = copyExtraVal << insNumExtra | insExtraVal;
2141
+ writer.writeBits(totalBits, combinedBits);
2142
+ }
2143
+ function storeMetaBlockTrivial(writer, input, startPos, length, mask, isLast, commands, distanceAlphabetSize) {
2144
+ storeCompressedMetaBlockHeader(writer, isLast, length);
2145
+ const litHisto = createHistogramLiteral();
2146
+ const cmdHisto = createHistogramCommand();
2147
+ const distHisto = createHistogramDistance();
2148
+ let pos = startPos;
2149
+ for (const cmd of commands) {
2150
+ histogramAdd(cmdHisto, cmd.cmdPrefix);
2151
+ for (let j = 0; j < cmd.insertLen; j++) histogramAdd(litHisto, input[pos + j & mask]);
2152
+ pos += cmd.insertLen;
2153
+ const copyLen = commandCopyLen(cmd);
2154
+ pos += copyLen;
2155
+ if (copyLen && cmd.cmdPrefix >= 128) histogramAdd(distHisto, cmd.distPrefix & 1023);
2156
+ }
2157
+ writer.writeBits(13, 0);
2158
+ const litDepths = new Uint8Array(NUM_LITERAL_CODES);
2159
+ const litBits = new Uint16Array(NUM_LITERAL_CODES);
2160
+ const cmdDepths = new Uint8Array(NUM_COMMAND_CODES);
2161
+ const cmdBits = new Uint16Array(NUM_COMMAND_CODES);
2162
+ const distDepths = new Uint8Array(distanceAlphabetSize);
2163
+ const distBits = new Uint16Array(distanceAlphabetSize);
2164
+ buildAndStoreHuffmanTree(writer, litHisto.data, NUM_LITERAL_CODES, litDepths, litBits);
2165
+ buildAndStoreHuffmanTree(writer, cmdHisto.data, NUM_COMMAND_CODES, cmdDepths, cmdBits);
2166
+ buildAndStoreHuffmanTree(writer, distHisto.data, distanceAlphabetSize, distDepths, distBits);
2167
+ pos = startPos;
2168
+ for (const cmd of commands) {
2169
+ writer.writeBits(cmdDepths[cmd.cmdPrefix], cmdBits[cmd.cmdPrefix]);
2170
+ storeCommandExtra(writer, cmd);
2171
+ for (let j = 0; j < cmd.insertLen; j++) {
2172
+ const literal = input[pos + j & mask];
2173
+ writer.writeBits(litDepths[literal], litBits[literal]);
2174
+ }
2175
+ pos += cmd.insertLen;
2176
+ const copyLen = commandCopyLen(cmd);
2177
+ pos += copyLen;
2178
+ if (copyLen && cmd.cmdPrefix >= 128) {
2179
+ const distCode = cmd.distPrefix & 1023;
2180
+ const distNumExtra = cmd.distPrefix >>> 10;
2181
+ const distExtra = cmd.distExtra;
2182
+ writer.writeBits(distDepths[distCode], distBits[distCode]);
2183
+ writer.writeBits(distNumExtra, distExtra);
2184
+ }
2185
+ }
2186
+ if (isLast) writer.alignToByte();
2187
+ }
2188
+ function storeUncompressedMetaBlock(writer, input, position, mask, length, isFinal) {
2189
+ storeUncompressedMetaBlockHeader(writer, length);
2190
+ writer.alignToByte();
2191
+ let maskedPos = position & mask;
2192
+ if (maskedPos + length > mask + 1) {
2193
+ const len1 = mask + 1 - maskedPos;
2194
+ writer.writeBytes(input.subarray(maskedPos, maskedPos + len1));
2195
+ length -= len1;
2196
+ maskedPos = 0;
2197
+ }
2198
+ writer.writeBytes(input.subarray(maskedPos, maskedPos + length));
2199
+ writer.prepareStorage();
2200
+ if (isFinal) {
2201
+ writer.writeBits(1, 1);
2202
+ writer.writeBits(1, 1);
2203
+ writer.alignToByte();
2204
+ }
2205
+ }
2206
+
2207
+ //#endregion
2208
+ //#region src/encode/encode.ts
2209
+ function brotliEncode(input, options = {}) {
2210
+ const params = createDefaultParams();
2211
+ if (options.quality !== void 0) params.quality = Math.max(0, Math.min(11, options.quality));
2212
+ if (options.lgwin !== void 0) params.lgwin = Math.max(10, Math.min(24, options.lgwin));
2213
+ if (options.mode !== void 0) params.mode = options.mode;
2214
+ if (options.sizeHint !== void 0) params.sizeHint = options.sizeHint;
2215
+ sanitizeParams(params);
2216
+ params.lgblock = computeLgBlock(params);
2217
+ if (input.length === 0) return encodeEmptyInput();
2218
+ if (params.quality === 0 || input.length < 64) return encodeUncompressed(input);
2219
+ if (params.quality === 1) return encodeFast(input, params);
2220
+ return encodeStandard(input, params);
2221
+ }
2222
+ function encodeEmptyInput() {
2223
+ const writer = new BitWriter(16);
2224
+ const windowBits = encodeWindowBits(10, false);
2225
+ writer.writeBits(windowBits.bits, windowBits.value);
2226
+ writer.writeBits(1, 1);
2227
+ writer.writeBits(1, 1);
2228
+ writer.alignToByte();
2229
+ return writer.finish();
2230
+ }
2231
+ function encodeUncompressed(input) {
2232
+ const writer = new BitWriter(input.length + 32);
2233
+ const windowBits = encodeWindowBits(Math.max(10, Math.min(24, input.length <= 1 ? 10 : Math.ceil(Math.log2(input.length)) + 1)), false);
2234
+ writer.writeBits(windowBits.bits, windowBits.value);
2235
+ const maxBlockSize = (1 << 24) - 1;
2236
+ let pos = 0;
2237
+ while (pos < input.length) {
2238
+ const blockSize = Math.min(input.length - pos, maxBlockSize);
2239
+ if (pos + blockSize >= input.length) storeUncompressedMetaBlock(writer, input, pos, input.length - 1, blockSize, true);
2240
+ else storeUncompressedMetaBlock(writer, input, pos, input.length - 1, blockSize, false);
2241
+ pos += blockSize;
2242
+ }
2243
+ return writer.finish();
2244
+ }
2245
+ function encodeFast(input, params) {
2246
+ const writer = new BitWriter(input.length);
2247
+ const windowBits = encodeWindowBits(params.lgwin, false);
2248
+ writer.writeBits(windowBits.bits, windowBits.value);
2249
+ const hasher = createSimpleHasher(params.quality, params.lgwin);
2250
+ const distCache = new Int32Array([
2251
+ 4,
2252
+ 11,
2253
+ 15,
2254
+ 16
2255
+ ]);
2256
+ const ringBufferMask = (1 << params.lgwin) - 1;
2257
+ const blockSize = 1 << params.lgblock;
2258
+ let pos = 0;
2259
+ while (pos < input.length) {
2260
+ const blockLen = Math.min(input.length - pos, blockSize);
2261
+ const isLast = pos + blockLen >= input.length;
2262
+ const [commands] = createBackwardReferences(blockLen, pos, input, ringBufferMask, hasher, distCache, 0, params.quality);
2263
+ const distAlphabetSize = 16 + (48 << params.dist.distancePostfixBits);
2264
+ storeMetaBlockTrivial(writer, input, pos, blockLen, ringBufferMask, isLast, commands, distAlphabetSize);
2265
+ pos += blockLen;
2266
+ }
2267
+ return writer.finish();
2268
+ }
2269
+ function encodeStandard(input, params) {
2270
+ const writer = new BitWriter(Math.max(1024, Math.floor(input.length * 1.2)));
2271
+ const windowBits = encodeWindowBits(params.lgwin, params.largeWindow);
2272
+ writer.writeBits(windowBits.bits, windowBits.value);
2273
+ let hasher;
2274
+ if (params.quality <= 4) hasher = createSimpleHasher(params.quality, params.lgwin);
2275
+ else if (params.quality <= 9) hasher = createHashChainHasher(params.quality, params.lgwin);
2276
+ else hasher = createBinaryTreeHasher(params.lgwin, input.length);
2277
+ const distCache = new Int32Array([
2278
+ 4,
2279
+ 11,
2280
+ 15,
2281
+ 16
2282
+ ]);
2283
+ const ringBufferMask = (1 << params.lgwin) - 1;
2284
+ const maxMetablockSize = 1 << 24;
2285
+ let pos = 0;
2286
+ while (pos < input.length) {
2287
+ const metablockLen = Math.min(input.length - pos, maxMetablockSize);
2288
+ const isLast = pos + metablockLen >= input.length;
2289
+ let commands;
2290
+ let lastInsertLen = 0;
2291
+ if (params.quality >= HQ_ZOPFLIFICATION_QUALITY && hasher instanceof BinaryTreeHasher) [commands, , lastInsertLen] = createHqZopfliBackwardReferences(metablockLen, pos, input, ringBufferMask, hasher, distCache, 0);
2292
+ else if (params.quality >= ZOPFLIFICATION_QUALITY && hasher instanceof BinaryTreeHasher) [commands, , lastInsertLen] = createZopfliBackwardReferences(metablockLen, pos, input, ringBufferMask, params.quality, hasher, distCache, 0);
2293
+ else if (hasher instanceof HashChainHasher) [commands, , lastInsertLen] = createBackwardReferences(metablockLen, pos, input, ringBufferMask, hasher, distCache, 0, params.quality);
2294
+ else if (hasher instanceof SimpleHasher) [commands, , lastInsertLen] = createBackwardReferences(metablockLen, pos, input, ringBufferMask, hasher, distCache, 0, params.quality);
2295
+ else commands = [createInsertCommand(metablockLen)];
2296
+ if (lastInsertLen > 0) if (commands.length === 0) commands = [createInsertCommand(metablockLen)];
2297
+ else {
2298
+ const lastCmd = commands[commands.length - 1];
2299
+ if (commandCopyLen(lastCmd) === 0) lastCmd.insertLen += lastInsertLen;
2300
+ else commands.push(createInsertCommand(lastInsertLen));
2301
+ }
2302
+ else if (commands.length === 0) commands = [createInsertCommand(metablockLen)];
2303
+ const distAlphabetSize = calculateDistanceAlphabetSize(params);
2304
+ storeMetaBlockTrivial(writer, input, pos, metablockLen, ringBufferMask, isLast, commands, distAlphabetSize);
2305
+ pos += metablockLen;
2306
+ }
2307
+ return writer.finish();
2308
+ }
2309
+ function calculateDistanceAlphabetSize(params) {
2310
+ const npostfix = params.dist.distancePostfixBits;
2311
+ return 16 + params.dist.numDirectDistanceCodes + (48 << npostfix);
2312
+ }
2313
+ var BrotliEncoder = class {
2314
+ constructor(options = {}) {
2315
+ const params = createDefaultParams();
2316
+ if (options.quality !== void 0) params.quality = Math.max(0, Math.min(11, options.quality));
2317
+ if (options.lgwin !== void 0) params.lgwin = Math.max(10, Math.min(24, options.lgwin));
2318
+ if (options.mode !== void 0) params.mode = options.mode;
2319
+ if (options.sizeHint !== void 0) params.sizeHint = options.sizeHint;
2320
+ sanitizeParams(params);
2321
+ params.lgblock = computeLgBlock(params);
2322
+ const ringBufferSize = 1 << params.lgwin;
2323
+ this.state = {
2324
+ params,
2325
+ hasher: null,
2326
+ distCache: new Int32Array([
2327
+ 4,
2328
+ 11,
2329
+ 15,
2330
+ 16
2331
+ ]),
2332
+ lastInsertLen: 0,
2333
+ commands: [],
2334
+ numLiterals: 0,
2335
+ inputPos: 0,
2336
+ lastProcessedPos: 0,
2337
+ ringBuffer: new Uint8Array(ringBufferSize),
2338
+ ringBufferMask: ringBufferSize - 1,
2339
+ prevByte: 0,
2340
+ prevByte2: 0,
2341
+ isInitialized: false,
2342
+ isLastBlockEmitted: false,
2343
+ writer: new BitWriter()
2344
+ };
2345
+ }
2346
+ initialize() {
2347
+ if (this.state.isInitialized) return;
2348
+ const { params, writer } = this.state;
2349
+ const windowBits = encodeWindowBits(params.lgwin, params.largeWindow);
2350
+ writer.writeBits(windowBits.bits, windowBits.value);
2351
+ if (params.quality <= 4) this.state.hasher = createSimpleHasher(params.quality, params.lgwin);
2352
+ else if (params.quality <= 9) this.state.hasher = createHashChainHasher(params.quality, params.lgwin);
2353
+ else this.state.hasher = createBinaryTreeHasher(params.lgwin);
2354
+ this.state.isInitialized = true;
2355
+ }
2356
+ update(input) {
2357
+ this.initialize();
2358
+ const { ringBuffer, ringBufferMask } = this.state;
2359
+ for (let i = 0; i < input.length; i++) ringBuffer[this.state.inputPos + i & ringBufferMask] = input[i];
2360
+ this.state.inputPos += input.length;
2361
+ const blockSize = 1 << this.state.params.lgblock;
2362
+ const output = [];
2363
+ while (this.state.inputPos - this.state.lastProcessedPos >= blockSize) {
2364
+ const chunk = this.processBlock(blockSize, false);
2365
+ if (chunk.length > 0) output.push(chunk);
2366
+ }
2367
+ if (output.length === 0) return new Uint8Array(0);
2368
+ if (output.length === 1) return output[0];
2369
+ const totalLen = output.reduce((sum, arr) => sum + arr.length, 0);
2370
+ const result = new Uint8Array(totalLen);
2371
+ let offset = 0;
2372
+ for (const chunk of output) {
2373
+ result.set(chunk, offset);
2374
+ offset += chunk.length;
2375
+ }
2376
+ return result;
2377
+ }
2378
+ finish() {
2379
+ this.initialize();
2380
+ const remaining = this.state.inputPos - this.state.lastProcessedPos;
2381
+ if (remaining > 0) return this.processBlock(remaining, true);
2382
+ if (!this.state.isLastBlockEmitted) {
2383
+ const { writer } = this.state;
2384
+ writer.writeBits(1, 1);
2385
+ writer.writeBits(1, 1);
2386
+ writer.alignToByte();
2387
+ this.state.isLastBlockEmitted = true;
2388
+ }
2389
+ return this.state.writer.takeBytes();
2390
+ }
2391
+ processBlock(blockLen, isLast) {
2392
+ const { params, ringBuffer, ringBufferMask, distCache, hasher, writer } = this.state;
2393
+ const pos = this.state.lastProcessedPos;
2394
+ if (!hasher) throw new Error("Encoder not initialized");
2395
+ let commands;
2396
+ let numLiterals;
2397
+ let lastInsertLen;
2398
+ if (hasher instanceof SimpleHasher || hasher instanceof HashChainHasher) [commands, numLiterals, lastInsertLen] = createBackwardReferences(blockLen, pos, ringBuffer, ringBufferMask, hasher, distCache, this.state.lastInsertLen, params.quality);
2399
+ else if (hasher instanceof BinaryTreeHasher) if (params.quality >= HQ_ZOPFLIFICATION_QUALITY) [commands, numLiterals, lastInsertLen] = createHqZopfliBackwardReferences(blockLen, pos, ringBuffer, ringBufferMask, hasher, distCache, this.state.lastInsertLen);
2400
+ else [commands, numLiterals, lastInsertLen] = createZopfliBackwardReferences(blockLen, pos, ringBuffer, ringBufferMask, params.quality, hasher, distCache, this.state.lastInsertLen);
2401
+ else {
2402
+ commands = [createInsertCommand(blockLen)];
2403
+ numLiterals = blockLen;
2404
+ lastInsertLen = 0;
2405
+ }
2406
+ if (lastInsertLen > 0) if (commands.length === 0) commands = [createInsertCommand(blockLen)];
2407
+ else {
2408
+ const lastCmd = commands[commands.length - 1];
2409
+ if (commandCopyLen(lastCmd) === 0) lastCmd.insertLen += lastInsertLen;
2410
+ else commands.push(createInsertCommand(lastInsertLen));
2411
+ }
2412
+ else if (commands.length === 0) commands = [createInsertCommand(blockLen)];
2413
+ const distAlphabetSize = calculateDistanceAlphabetSize(params);
2414
+ storeMetaBlockTrivial(writer, ringBuffer, pos, blockLen, ringBufferMask, isLast, commands, distAlphabetSize);
2415
+ this.state.lastProcessedPos += blockLen;
2416
+ this.state.lastInsertLen = 0;
2417
+ this.state.numLiterals += numLiterals;
2418
+ if (isLast) this.state.isLastBlockEmitted = true;
2419
+ return writer.takeBytes();
2420
+ }
2421
+ };
2422
+
2423
+ //#endregion
2424
+ exports.BrotliEncoder = BrotliEncoder;
2425
+ exports.EncoderMode = EncoderMode;
2426
+ exports.brotliEncode = brotliEncode;