brotli-lib 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -58,38 +58,40 @@ class BrotliEncoder {
58
58
  }
59
59
  ```
60
60
 
61
+ FONT mode uses distance coding parameters optimized for transformed font data. It doesn't improve compression on raw TTF/OTF files - the gains come from WOFF2's font-specific transforms (glyf, loca, hmtx) applied before brotli compression
62
+
61
63
  ## Performance
62
64
 
63
65
  ### Decode
64
66
 
65
- | | brotli-lib | brotli.js | Google brotli |
67
+ | | brotli-lib | brotli.js | Google decode.ts |
66
68
  |--|------------|-----------|---------------|
67
- | Speed (vs Google) | 1.0x | 0.5-0.6x | 1x |
69
+ | Speed (vs Google) | 1.05-1.1x | 0.5-0.6x | 1x |
68
70
  | Custom dictionary | yes | no | yes |
69
71
  | Compressed static dict | yes | yes | no |
70
72
 
71
73
  Decode times (Apple M2 Max, Node 22):
72
74
 
73
- | File | brotli-lib | brotli.js | Google brotli |
75
+ | File | brotli-lib | brotli.js | Google decode.ts |
74
76
  |------|------------|-----------|---------------|
75
- | enc-ttf (305 KB) | 3.0 ms | 5.2 ms | 3.1 ms |
76
- | enc-otf (253 KB) | 3.0 ms | 5.2 ms | 3.1 ms |
77
- | enc-var-ttf (788 KB) | 7.5 ms | 13.8 ms | 7.8 ms |
78
- | noto-tc (7 MB) | 61 ms | 106 ms | 63 ms |
77
+ | enc-ttf (305 KB) | 2.5 ms | 4.5 ms | 2.8 ms |
78
+ | enc-otf (253 KB) | 2.5 ms | 4.3 ms | 2.7 ms |
79
+ | enc-var-ttf (788 KB) | 6.8 ms | 11.8 ms | 7.1 ms |
80
+ | noto-tc (7 MB) | 55 ms | 90 ms | 57 ms |
79
81
 
80
- 1.7x faster than brotli.js, on par with or slightly faster than Google's JS decoder
82
+ 1.7x faster than brotli.js, 5-10% faster than Google's JS decoder
81
83
 
82
84
  ### Encode
83
85
 
84
86
  Encoder vs Node.js native `zlib.brotliCompressSync` (quality 11):
85
87
 
86
- | Input | brotli-lib | node:zlib |
87
- |-------|-----------|-----------|
88
- | 13 B | 0.0004 ms | 0.22 ms |
89
- | 4.5 KB | 0.38 ms | 0.43 ms |
90
- | 45 KB | 3.5 ms | 1.6 ms |
88
+ | Input | brotli-lib | node:zlib | vs native |
89
+ |-------|-----------|-----------|-----------|
90
+ | 13 B | 0.001 ms | 0.16 ms | 160x faster |
91
+ | 4.5 KB | 0.27 ms | 0.33 ms | 1.2x faster |
92
+ | 45 KB | 3.0 ms | 1.4 ms | 2x slower |
91
93
 
92
- Much faster for tiny inputs (no native binding overhead), faster for medium, 2x slower for large
94
+ Much faster for tiny inputs (no native binding overhead), faster for medium, ~2x slower for large
93
95
 
94
96
  Run `npm run bench` to reproduce
95
97
 
@@ -97,11 +99,11 @@ Run `npm run bench` to reproduce
97
99
 
98
100
  | Import | Export size (gzip) |
99
101
  |--------|--------------------|
102
+ | `brotli-lib/encode` | 25 KB |
100
103
  | `brotli-lib/decode` | 66 KB |
101
- | `brotli-lib/encode` | 16 KB |
102
- | `brotli-lib` | 82 KB |
104
+ | `brotli-lib` | 90 KB |
103
105
 
104
- The 122 KB static dictionary is compressed to 52 KB and bootstrapped at runtime (à la Devon Govett's brotli.js)
106
+ The 122 KB static dictionary is compressed to 52 KB and bootstrapped at runtime (à la Devon Govett's brotli.js).
105
107
 
106
108
  ## License
107
109
 
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/decode/engine.ts"],"names":[],"mappings":"AASA,UAAU,mBAAmB;IAC3B,gBAAgB,CAAC,EAAE,UAAU,GAAG,SAAS,GAAG,IAAI,CAAC;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAuGD,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM,CAMlD;AAGD,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM,CAMlD;AAonDD,cAAM,KAAK;IACT,UAAU,EAAE,UAAU,CAAqB;IAC3C,YAAY,yBAAoB;IAChC,UAAU,yBAAoB;IAC9B,cAAc,yBAAoB;IAClC,aAAa,yBAAoB;IACjC,MAAM,EAAE,UAAU,CAAqB;IACvC,UAAU,yBAAoB;IAC9B,YAAY,2BAAsB;IAClC,WAAW,0BAAqB;IAChC,SAAS,0BAAqB;IAC9B,KAAK,0BAAqB;IAC1B,UAAU,0BAAqB;IAC/B,gBAAgB,0BAAqB;IACrC,gBAAgB,0BAAqB;IACrC,iBAAiB,0BAAqB;IACtC,UAAU,0BAAqB;IAC/B,aAAa,SAAK;IAClB,YAAY,SAAK;IACjB,gBAAgB,SAAK;IACrB,aAAa,SAAK;IAClB,SAAS,SAAK;IACd,UAAU,SAAK;IACf,SAAS,SAAK;IACd,kBAAkB,SAAK;IACvB,eAAe,SAAK;IACpB,QAAQ,SAAK;IACb,cAAc,SAAK;IACnB,UAAU,SAAK;IACf,kBAAkB,SAAK;IACvB,oBAAoB,SAAK;IACzB,kBAAkB,SAAK;IACvB,oBAAoB,SAAK;IACzB,mBAAmB,SAAK;IACxB,qBAAqB,SAAK;IAC1B,GAAG,SAAK;IACR,WAAW,SAAK;IAChB,SAAS,SAAK;IACd,qBAAqB,SAAK;IAC1B,cAAc,SAAK;IACnB,cAAc,SAAK;IACnB,CAAC,SAAK;IACN,YAAY,SAAK;IACjB,eAAe,SAAK;IACpB,mBAAmB,SAAK;IACxB,oBAAoB,SAAK;IACzB,oBAAoB,SAAK;IACzB,YAAY,SAAK;IACjB,sBAAsB,SAAK;IAC3B,mBAAmB,SAAK;IACxB,QAAQ,SAAK;IACb,UAAU,SAAK;IACf,mBAAmB,SAAK;IACxB,iBAAiB,SAAK;IACtB,cAAc,SAAK;IACnB,iBAAiB,SAAK;IACtB,YAAY,SAAK;IACjB,YAAY,SAAK;IACjB,UAAU,SAAK;IACf,sBAAsB,SAAK;IAC3B,oBAAoB,SAAK;IACzB,OAAO,SAAK;IACZ,aAAa,SAAK;IAClB,WAAW,SAAK;IAChB,WAAW,SAAK;IAChB,SAAS,SAAK;IACd,UAAU,SAAK;IACf,UAAU,SAAK;IACf,UAAU,SAAK;IACf,QAAQ,QAAgB;IACxB,cAAc,0BAAqB;IACnC,WAAW,SAAK;IAChB,UAAU,yBAAoB;IAC9B,KAAK,cAAqC;;CAS3C;AAmDD,cAAM,WAAW;IACf,IAAI,EAAE,UAAU,GAAG,SAAS,CAAqB;IACjD,MAAM,SAAK;gBACE,IAAI,EAAE,UAAU,GAAG,SAAS;CAG1C;AAuCD;;GAEG;AACH,wBAAgB,YAAY,CACxB,KAAK,EAAE,UAAU,GAAG,SAAS,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,UAAU,CAsD5E"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/decode/engine.ts"],"names":[],"mappings":"AASA,UAAU,mBAAmB;IAC3B,gBAAgB,CAAC,EAAE,UAAU,GAAG,SAAS,GAAG,IAAI,CAAC;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAiHD,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM,CAMlD;AAGD,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM,CAMlD;AAurDD,cAAM,KAAK;IACT,UAAU,EAAE,UAAU,CAAqB;IAC3C,YAAY,yBAAoB;IAChC,UAAU,yBAAoB;IAC9B,cAAc,yBAAoB;IAClC,aAAa,yBAAoB;IACjC,MAAM,EAAE,UAAU,CAAqB;IACvC,UAAU,yBAAoB;IAC9B,YAAY,2BAAsB;IAClC,WAAW,0BAAqB;IAChC,SAAS,0BAAqB;IAC9B,KAAK,0BAAqB;IAC1B,UAAU,0BAAqB;IAC/B,gBAAgB,0BAAqB;IACrC,gBAAgB,0BAAqB;IACrC,iBAAiB,0BAAqB;IACtC,UAAU,0BAAqB;IAC/B,aAAa,SAAK;IAClB,YAAY,SAAK;IACjB,gBAAgB,SAAK;IACrB,aAAa,SAAK;IAClB,SAAS,SAAK;IACd,UAAU,SAAK;IACf,SAAS,SAAK;IACd,kBAAkB,SAAK;IACvB,eAAe,SAAK;IACpB,QAAQ,SAAK;IACb,cAAc,SAAK;IACnB,UAAU,SAAK;IACf,kBAAkB,SAAK;IACvB,oBAAoB,SAAK;IACzB,kBAAkB,SAAK;IACvB,oBAAoB,SAAK;IACzB,mBAAmB,SAAK;IACxB,qBAAqB,SAAK;IAC1B,GAAG,SAAK;IACR,WAAW,SAAK;IAChB,SAAS,SAAK;IACd,qBAAqB,SAAK;IAC1B,cAAc,SAAK;IACnB,cAAc,SAAK;IACnB,CAAC,SAAK;IACN,YAAY,SAAK;IACjB,eAAe,SAAK;IACpB,mBAAmB,SAAK;IACxB,oBAAoB,SAAK;IACzB,oBAAoB,SAAK;IACzB,YAAY,SAAK;IACjB,sBAAsB,SAAK;IAC3B,mBAAmB,SAAK;IACxB,QAAQ,SAAK;IACb,UAAU,SAAK;IACf,mBAAmB,SAAK;IACxB,iBAAiB,SAAK;IACtB,cAAc,SAAK;IACnB,iBAAiB,SAAK;IACtB,YAAY,SAAK;IACjB,YAAY,SAAK;IACjB,UAAU,SAAK;IACf,sBAAsB,SAAK;IAC3B,oBAAoB,SAAK;IACzB,OAAO,SAAK;IACZ,aAAa,SAAK;IAClB,WAAW,SAAK;IAChB,WAAW,SAAK;IAChB,SAAS,SAAK;IACd,UAAU,SAAK;IACf,UAAU,SAAK;IACf,UAAU,SAAK;IACf,QAAQ,QAAgB;IACxB,cAAc,0BAAqB;IACnC,WAAW,SAAK;IAChB,UAAU,yBAAoB;IAC9B,KAAK,cAAqC;;CAS3C;AAmDD,cAAM,WAAW;IACf,IAAI,EAAE,UAAU,GAAG,SAAS,CAAqB;IACjD,MAAM,SAAK;gBACE,IAAI,EAAE,UAAU,GAAG,SAAS;CAG1C;AAuCD;;GAEG;AACH,wBAAgB,YAAY,CACxB,KAAK,EAAE,UAAU,GAAG,SAAS,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,UAAU,CA2D5E"}
package/dist/decode.cjs CHANGED
@@ -478,6 +478,15 @@ const COPY_LENGTH_N_BITS = Int16Array.from([
478
478
  const CMD_LOOKUP = new Int16Array(2816);
479
479
  unpackCommandLookupTable(CMD_LOOKUP);
480
480
  const IS_LITTLE_ENDIAN = new Uint16Array(new Uint8Array([1, 0]).buffer)[0] === 1;
481
+ const _scratchCount = new Int32Array(16);
482
+ const _scratchOffset = new Int32Array(16);
483
+ const _scratchSorted = new Int32Array(1080);
484
+ const _scratchHCLTable = new Int32Array(33);
485
+ const _scratchCLCL = new Int32Array(18);
486
+ const _scratchCodeLengths = new Int32Array(1080);
487
+ const _scratchSymbols = new Int32Array(4);
488
+ const _scratchMtf = new Int32Array(256);
489
+ const _scratchCtxMapTable = new Int32Array(1081);
481
490
  function log2floor(i) {
482
491
  let result = -1;
483
492
  let step = 16;
@@ -667,16 +676,12 @@ function readBlockLength(tableGroup, tableIdx, s) {
667
676
  return BLOCK_LENGTH_OFFSET[code] + (n <= 16 ? readFewBits(s, n) : readManyBits(s, n));
668
677
  }
669
678
  function moveToFront(v, index) {
670
- let i = index;
671
- const value = v[i];
672
- while (i > 0) {
673
- v[i] = v[i - 1];
674
- i--;
675
- }
679
+ const value = v[index];
680
+ v.copyWithin(1, 0, index);
676
681
  v[0] = value;
677
682
  }
678
683
  function inverseMoveToFrontTransform(v, vLen) {
679
- const mtf = new Int32Array(256);
684
+ const mtf = _scratchMtf;
680
685
  for (let i = 0; i < 256; ++i) mtf[i] = i;
681
686
  for (let i = 0; i < vLen; ++i) {
682
687
  const index = v[i] & 255;
@@ -690,8 +695,8 @@ function readHuffmanCodeLengths(codeLengthCodeLengths, numSymbols, codeLengths,
690
695
  let repeat = 0;
691
696
  let repeatCodeLen = 0;
692
697
  let space = 32768;
693
- const table = new Int32Array(33);
694
- buildHuffmanTable(table, table.length - 1, 5, codeLengthCodeLengths, 18);
698
+ const table = _scratchHCLTable;
699
+ buildHuffmanTable(table, 32, 5, codeLengthCodeLengths, 18);
695
700
  while (symbol < numSymbols && space > 0) {
696
701
  if (s.halfOffset > 2030) {
697
702
  const result = readMoreInput(s);
@@ -731,7 +736,8 @@ function readHuffmanCodeLengths(codeLengthCodeLengths, numSymbols, codeLengths,
731
736
  repeat += readFewBits(s, extraBits) + 3;
732
737
  const repeatDelta = repeat - oldRepeat;
733
738
  if (symbol + repeatDelta > numSymbols) return makeError(s, -2);
734
- for (let i = 0; i < repeatDelta; ++i) codeLengths[symbol++] = repeatCodeLen;
739
+ codeLengths.fill(repeatCodeLen, symbol, symbol + repeatDelta);
740
+ symbol += repeatDelta;
735
741
  if (repeatCodeLen !== 0) space -= repeatDelta << 15 - repeatCodeLen;
736
742
  }
737
743
  }
@@ -744,8 +750,9 @@ function checkDupes(s, symbols, length) {
744
750
  return 0;
745
751
  }
746
752
  function readSimpleHuffmanCode(alphabetSizeMax, alphabetSizeLimit, tableGroup, tableIdx, s) {
747
- const codeLengths = new Int32Array(alphabetSizeLimit);
748
- const symbols = new Int32Array(4);
753
+ const codeLengths = _scratchCodeLengths;
754
+ codeLengths.fill(0, 0, alphabetSizeLimit);
755
+ const symbols = _scratchSymbols;
749
756
  const maxBits = 1 + log2floor(alphabetSizeMax - 1);
750
757
  const numSymbols = readFewBits(s, 2) + 1;
751
758
  for (let i = 0; i < numSymbols; ++i) {
@@ -791,8 +798,10 @@ function readSimpleHuffmanCode(alphabetSizeMax, alphabetSizeLimit, tableGroup, t
791
798
  return buildHuffmanTable(tableGroup, tableIdx, 8, codeLengths, alphabetSizeLimit);
792
799
  }
793
800
  function readComplexHuffmanCode(alphabetSizeLimit, skip, tableGroup, tableIdx, s) {
794
- const codeLengths = new Int32Array(alphabetSizeLimit);
795
- const codeLengthCodeLengths = new Int32Array(18);
801
+ const codeLengths = _scratchCodeLengths;
802
+ codeLengths.fill(0, 0, alphabetSizeLimit);
803
+ const codeLengthCodeLengths = _scratchCLCL;
804
+ codeLengthCodeLengths.fill(0);
796
805
  let space = 32;
797
806
  let numCodes = 0;
798
807
  for (let i = skip; i < 18; ++i) {
@@ -849,8 +858,8 @@ function decodeContextMap(contextMapSize, contextMap, s) {
849
858
  if (useRleForZeros !== 0) maxRunLengthPrefix = readFewBits(s, 4) + 1;
850
859
  const alphabetSize = numTrees + maxRunLengthPrefix;
851
860
  const tableSize = MAX_HUFFMAN_TABLE_SIZE[alphabetSize + 31 >> 5];
852
- const table = new Int32Array(tableSize + 1);
853
- const tableIdx = table.length - 1;
861
+ const table = _scratchCtxMapTable;
862
+ const tableIdx = tableSize;
854
863
  result = readHuffmanCode(alphabetSize, alphabetSize, table, tableIdx, s);
855
864
  if (result < 0) return result;
856
865
  let i = 0;
@@ -873,12 +882,9 @@ function decodeContextMap(contextMapSize, contextMap, s) {
873
882
  s.bitOffset -= 16;
874
883
  }
875
884
  let reps = (1 << code) + readFewBits(s, code);
876
- while (reps !== 0) {
877
- if (i >= contextMapSize) return makeError(s, -3);
878
- contextMap[i] = 0;
879
- i++;
880
- reps--;
881
- }
885
+ if (i + reps > contextMapSize) return makeError(s, -3);
886
+ contextMap.fill(0, i, i + reps);
887
+ i += reps;
882
888
  } else {
883
889
  contextMap[i] = code - maxRunLengthPrefix;
884
890
  i++;
@@ -1296,55 +1302,136 @@ function decompress(s) {
1296
1302
  s.runningState = 7;
1297
1303
  continue;
1298
1304
  case 7:
1299
- if (s.trivialLiteralContext !== 0) while (s.j < s.insertLength) {
1300
- if (s.halfOffset > 2030) {
1301
- result = readMoreInput(s);
1302
- if (result < 0) return result;
1303
- }
1304
- if (s.literalBlockLength === 0) decodeLiteralBlockSwitch(s);
1305
- s.literalBlockLength--;
1306
- if (s.bitOffset >= 16) {
1307
- s.accumulator32 = s.shortBuffer[s.halfOffset++] << 16 | s.accumulator32 >>> 16;
1308
- s.bitOffset -= 16;
1309
- }
1310
- ringBuffer[s.pos] = readSymbol(s.literalTreeGroup, s.literalTreeIdx, s);
1311
- s.pos++;
1312
- s.j++;
1313
- if (s.pos >= fence) {
1314
- s.nextRunningState = 7;
1315
- s.runningState = 12;
1316
- break;
1317
- }
1318
- }
1319
- else {
1320
- let prevByte1 = ringBuffer[s.pos - 1 & ringBufferMask];
1321
- let prevByte2 = ringBuffer[s.pos - 2 & ringBufferMask];
1322
- while (s.j < s.insertLength) {
1323
- if (s.halfOffset > 2030) {
1324
- result = readMoreInput(s);
1325
- if (result < 0) return result;
1326
- }
1327
- if (s.literalBlockLength === 0) decodeLiteralBlockSwitch(s);
1328
- const literalContext = LOOKUP[s.contextLookupOffset1 + prevByte1] | LOOKUP[s.contextLookupOffset2 + prevByte2];
1329
- const literalTreeIdx = s.contextMap[s.contextMapSlice + literalContext] & 255;
1330
- s.literalBlockLength--;
1331
- prevByte2 = prevByte1;
1332
- if (s.bitOffset >= 16) {
1333
- s.accumulator32 = s.shortBuffer[s.halfOffset++] << 16 | s.accumulator32 >>> 16;
1334
- s.bitOffset -= 16;
1305
+ {
1306
+ let _bo = s.bitOffset;
1307
+ let _ac = s.accumulator32;
1308
+ let _ho = s.halfOffset;
1309
+ let _pos = s.pos;
1310
+ let _j = s.j;
1311
+ let _lbl = s.literalBlockLength;
1312
+ const _sb = s.shortBuffer;
1313
+ const _ltg = s.literalTreeGroup;
1314
+ const _il = s.insertLength;
1315
+ if (s.trivialLiteralContext !== 0) {
1316
+ let _lti = s.literalTreeIdx;
1317
+ while (_j < _il) {
1318
+ if (_ho > 2030) {
1319
+ s.halfOffset = _ho;
1320
+ result = readMoreInput(s);
1321
+ if (result < 0) return result;
1322
+ _ho = s.halfOffset;
1323
+ }
1324
+ if (_lbl === 0) {
1325
+ s.bitOffset = _bo;
1326
+ s.accumulator32 = _ac;
1327
+ s.halfOffset = _ho;
1328
+ decodeLiteralBlockSwitch(s);
1329
+ _bo = s.bitOffset;
1330
+ _ac = s.accumulator32;
1331
+ _ho = s.halfOffset;
1332
+ _lbl = s.literalBlockLength;
1333
+ _lti = s.literalTreeIdx;
1334
+ }
1335
+ _lbl--;
1336
+ if (_bo >= 16) {
1337
+ _ac = _sb[_ho++] << 16 | _ac >>> 16;
1338
+ _bo -= 16;
1339
+ }
1340
+ let _rsOff = _ltg[_lti];
1341
+ const _rsV = _ac >>> _bo;
1342
+ _rsOff += _rsV & 255;
1343
+ const _rsE0 = _ltg[_rsOff];
1344
+ const _rsBits = _rsE0 >> 16;
1345
+ if (_rsBits <= 8) {
1346
+ _bo += _rsBits;
1347
+ ringBuffer[_pos] = _rsE0 & 65535;
1348
+ } else {
1349
+ _rsOff += _rsE0 & 65535;
1350
+ _rsOff += (_rsV & (1 << _rsBits) - 1) >>> 8;
1351
+ const _rsE1 = _ltg[_rsOff];
1352
+ _bo += (_rsE1 >> 16) + 8;
1353
+ ringBuffer[_pos] = _rsE1 & 65535;
1354
+ }
1355
+ _pos++;
1356
+ _j++;
1357
+ if (_pos >= fence) {
1358
+ s.nextRunningState = 7;
1359
+ s.runningState = 12;
1360
+ break;
1361
+ }
1335
1362
  }
1336
- prevByte1 = readSymbol(s.literalTreeGroup, literalTreeIdx, s);
1337
- ringBuffer[s.pos] = prevByte1;
1338
- s.pos++;
1339
- s.j++;
1340
- if (s.pos >= fence) {
1341
- s.nextRunningState = 7;
1342
- s.runningState = 12;
1343
- break;
1363
+ } else {
1364
+ let prevByte1 = ringBuffer[_pos - 1 & ringBufferMask];
1365
+ let prevByte2 = ringBuffer[_pos - 2 & ringBufferMask];
1366
+ let _cms = s.contextMapSlice;
1367
+ let _clo1 = s.contextLookupOffset1;
1368
+ let _clo2 = s.contextLookupOffset2;
1369
+ const _cm = s.contextMap;
1370
+ while (_j < _il) {
1371
+ if (_ho > 2030) {
1372
+ s.halfOffset = _ho;
1373
+ result = readMoreInput(s);
1374
+ if (result < 0) return result;
1375
+ _ho = s.halfOffset;
1376
+ }
1377
+ if (_lbl === 0) {
1378
+ s.bitOffset = _bo;
1379
+ s.accumulator32 = _ac;
1380
+ s.halfOffset = _ho;
1381
+ s.contextMapSlice = _cms;
1382
+ decodeLiteralBlockSwitch(s);
1383
+ _bo = s.bitOffset;
1384
+ _ac = s.accumulator32;
1385
+ _ho = s.halfOffset;
1386
+ _lbl = s.literalBlockLength;
1387
+ _cms = s.contextMapSlice;
1388
+ _clo1 = s.contextLookupOffset1;
1389
+ _clo2 = s.contextLookupOffset2;
1390
+ }
1391
+ const literalContext = LOOKUP[_clo1 + prevByte1] | LOOKUP[_clo2 + prevByte2];
1392
+ const literalTreeIdx = _cm[_cms + literalContext] & 255;
1393
+ _lbl--;
1394
+ prevByte2 = prevByte1;
1395
+ if (_bo >= 16) {
1396
+ _ac = _sb[_ho++] << 16 | _ac >>> 16;
1397
+ _bo -= 16;
1398
+ }
1399
+ {
1400
+ let _rsOff = _ltg[literalTreeIdx];
1401
+ const _rsV = _ac >>> _bo;
1402
+ _rsOff += _rsV & 255;
1403
+ const _rsE0 = _ltg[_rsOff];
1404
+ const _rsBits = _rsE0 >> 16;
1405
+ if (_rsBits <= 8) {
1406
+ _bo += _rsBits;
1407
+ prevByte1 = _rsE0 & 65535;
1408
+ } else {
1409
+ _rsOff += _rsE0 & 65535;
1410
+ _rsOff += (_rsV & (1 << _rsBits) - 1) >>> 8;
1411
+ const _rsE1 = _ltg[_rsOff];
1412
+ _bo += (_rsE1 >> 16) + 8;
1413
+ prevByte1 = _rsE1 & 65535;
1414
+ }
1415
+ }
1416
+ ringBuffer[_pos] = prevByte1;
1417
+ _pos++;
1418
+ _j++;
1419
+ if (_pos >= fence) {
1420
+ s.nextRunningState = 7;
1421
+ s.runningState = 12;
1422
+ break;
1423
+ }
1344
1424
  }
1425
+ s.contextMapSlice = _cms;
1345
1426
  }
1427
+ s.bitOffset = _bo;
1428
+ s.accumulator32 = _ac;
1429
+ s.halfOffset = _ho;
1430
+ s.pos = _pos;
1431
+ s.j = _j;
1432
+ s.literalBlockLength = _lbl;
1433
+ if (s.runningState !== 7) continue;
1346
1434
  }
1347
- if (s.runningState !== 7) continue;
1348
1435
  s.metaBlockLength -= s.insertLength;
1349
1436
  if (s.metaBlockLength <= 0) {
1350
1437
  s.runningState = 4;
@@ -1404,7 +1491,8 @@ function decompress(s) {
1404
1491
  const srcEnd = src + copyLength;
1405
1492
  const dstEnd = dst + copyLength;
1406
1493
  if (srcEnd < ringBufferMask && dstEnd < ringBufferMask) {
1407
- if (s.distance === 4 && copyLength >= 8) {
1494
+ if (s.distance === 1) ringBuffer.fill(ringBuffer[src], dst, dstEnd);
1495
+ else if (s.distance === 4 && copyLength >= 8) {
1408
1496
  ringBuffer[dst] = ringBuffer[src];
1409
1497
  ringBuffer[dst + 1] = ringBuffer[src + 1];
1410
1498
  ringBuffer[dst + 2] = ringBuffer[src + 2];
@@ -1642,9 +1730,11 @@ function nextTableBitSize(count, len, rootBits) {
1642
1730
  }
1643
1731
  function buildHuffmanTable(tableGroup, tableIdx, rootBits, codeLengths, codeLengthsSize) {
1644
1732
  const tableOffset = tableGroup[tableIdx];
1645
- const sorted = new Int32Array(codeLengthsSize);
1646
- const count = new Int32Array(16);
1647
- const offset = new Int32Array(16);
1733
+ const sorted = _scratchSorted;
1734
+ const count = _scratchCount;
1735
+ const offset = _scratchOffset;
1736
+ count.fill(0);
1737
+ offset.fill(0);
1648
1738
  for (let sym = 0; sym < codeLengthsSize; ++sym) count[codeLengths[sym]]++;
1649
1739
  offset[1] = 0;
1650
1740
  for (let len = 1; len < 15; ++len) offset[len + 1] = offset[len] + count[len];
@@ -1653,7 +1743,7 @@ function buildHuffmanTable(tableGroup, tableIdx, rootBits, codeLengths, codeLeng
1653
1743
  let tableSize = 1 << tableBits;
1654
1744
  let totalSize = tableSize;
1655
1745
  if (offset[15] === 1) {
1656
- for (let k = 0; k < totalSize; ++k) tableGroup[tableOffset + k] = sorted[0];
1746
+ tableGroup.fill(sorted[0], tableOffset, tableOffset + totalSize);
1657
1747
  return totalSize;
1658
1748
  }
1659
1749
  let key = 0;
@@ -2037,17 +2127,21 @@ function brotliDecode$1(bytes, options) {
2037
2127
  return result;
2038
2128
  }
2039
2129
  let totalOutput = 0;
2130
+ let chunkSize = 16384;
2040
2131
  const chunks = [];
2132
+ const chunkSizes = [];
2041
2133
  while (true) {
2042
- const chunk = new Uint8Array(16384);
2134
+ const chunk = new Uint8Array(chunkSize);
2043
2135
  chunks.push(chunk);
2136
+ chunkSizes.push(chunkSize);
2044
2137
  s.output = chunk;
2045
2138
  s.outputOffset = 0;
2046
- s.outputLength = 16384;
2139
+ s.outputLength = chunkSize;
2047
2140
  s.outputUsed = 0;
2048
2141
  decompress(s);
2049
2142
  totalOutput += s.outputUsed;
2050
- if (s.outputUsed < 16384) break;
2143
+ if (s.outputUsed < chunkSize) break;
2144
+ if (chunkSize < 4194304) chunkSize *= 2;
2051
2145
  }
2052
2146
  close(s);
2053
2147
  closeInput(s);
@@ -2055,8 +2149,9 @@ function brotliDecode$1(bytes, options) {
2055
2149
  let offset = 0;
2056
2150
  for (let i = 0; i < chunks.length; ++i) {
2057
2151
  const chunk = chunks[i];
2058
- const len = Math.min(totalOutput, offset + 16384) - offset;
2059
- if (len < 16384) result.set(chunk.subarray(0, len), offset);
2152
+ const sz = chunkSizes[i];
2153
+ const len = Math.min(totalOutput, offset + sz) - offset;
2154
+ if (len < sz) result.set(chunk.subarray(0, len), offset);
2060
2155
  else result.set(chunk, offset);
2061
2156
  offset += len;
2062
2157
  }