zstdify 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +95 -0
  3. package/dist/bitstream/bitReader.d.ts +26 -0
  4. package/dist/bitstream/bitReader.js +86 -0
  5. package/dist/bitstream/bitReader.js.map +1 -0
  6. package/dist/bitstream/bitReader.test.d.ts +1 -0
  7. package/dist/bitstream/bitReader.test.js +47 -0
  8. package/dist/bitstream/bitReader.test.js.map +1 -0
  9. package/dist/bitstream/bitReaderReverse.d.ts +23 -0
  10. package/dist/bitstream/bitReaderReverse.js +84 -0
  11. package/dist/bitstream/bitReaderReverse.js.map +1 -0
  12. package/dist/bitstream/bitReaderReverse.test.d.ts +1 -0
  13. package/dist/bitstream/bitReaderReverse.test.js +49 -0
  14. package/dist/bitstream/bitReaderReverse.test.js.map +1 -0
  15. package/dist/bitstream/bitWriter.d.ts +15 -0
  16. package/dist/bitstream/bitWriter.js +47 -0
  17. package/dist/bitstream/bitWriter.js.map +1 -0
  18. package/dist/bitstream/index.d.ts +4 -0
  19. package/dist/bitstream/index.js +5 -0
  20. package/dist/bitstream/index.js.map +1 -0
  21. package/dist/bitstream/littleEndian.d.ts +7 -0
  22. package/dist/bitstream/littleEndian.js +45 -0
  23. package/dist/bitstream/littleEndian.js.map +1 -0
  24. package/dist/bitstream/littleEndian.test.d.ts +1 -0
  25. package/dist/bitstream/littleEndian.test.js +21 -0
  26. package/dist/bitstream/littleEndian.test.js.map +1 -0
  27. package/dist/bitstream/varint.d.ts +9 -0
  28. package/dist/bitstream/varint.js +40 -0
  29. package/dist/bitstream/varint.js.map +1 -0
  30. package/dist/bitstream/varint.test.d.ts +1 -0
  31. package/dist/bitstream/varint.test.js +25 -0
  32. package/dist/bitstream/varint.test.js.map +1 -0
  33. package/dist/compress.d.ts +9 -0
  34. package/dist/compress.js +74 -0
  35. package/dist/compress.js.map +1 -0
  36. package/dist/decode/block.d.ts +11 -0
  37. package/dist/decode/block.js +28 -0
  38. package/dist/decode/block.js.map +1 -0
  39. package/dist/decode/block.test.d.ts +1 -0
  40. package/dist/decode/block.test.js +26 -0
  41. package/dist/decode/block.test.js.map +1 -0
  42. package/dist/decode/decompressFrame.d.ts +9 -0
  43. package/dist/decode/decompressFrame.js +147 -0
  44. package/dist/decode/decompressFrame.js.map +1 -0
  45. package/dist/decode/literals.corruption.test.d.ts +1 -0
  46. package/dist/decode/literals.corruption.test.js +26 -0
  47. package/dist/decode/literals.corruption.test.js.map +1 -0
  48. package/dist/decode/literals.d.ts +49 -0
  49. package/dist/decode/literals.js +300 -0
  50. package/dist/decode/literals.js.map +1 -0
  51. package/dist/decode/literals.test.d.ts +1 -0
  52. package/dist/decode/literals.test.js +52 -0
  53. package/dist/decode/literals.test.js.map +1 -0
  54. package/dist/decode/reconstruct.d.ts +13 -0
  55. package/dist/decode/reconstruct.js +80 -0
  56. package/dist/decode/reconstruct.js.map +1 -0
  57. package/dist/decode/reconstruct.test.d.ts +1 -0
  58. package/dist/decode/reconstruct.test.js +42 -0
  59. package/dist/decode/reconstruct.test.js.map +1 -0
  60. package/dist/decode/sequences.corruption.test.d.ts +1 -0
  61. package/dist/decode/sequences.corruption.test.js +32 -0
  62. package/dist/decode/sequences.corruption.test.js.map +1 -0
  63. package/dist/decode/sequences.d.ts +21 -0
  64. package/dist/decode/sequences.js +222 -0
  65. package/dist/decode/sequences.js.map +1 -0
  66. package/dist/decode/sequences.level1.test.d.ts +1 -0
  67. package/dist/decode/sequences.level1.test.js +35 -0
  68. package/dist/decode/sequences.level1.test.js.map +1 -0
  69. package/dist/decompress.d.ts +11 -0
  70. package/dist/decompress.js +59 -0
  71. package/dist/decompress.js.map +1 -0
  72. package/dist/dictionary/decoderDictionary.d.ts +15 -0
  73. package/dist/dictionary/decoderDictionary.js +116 -0
  74. package/dist/dictionary/decoderDictionary.js.map +1 -0
  75. package/dist/dictionary/decoderDictionary.test.d.ts +1 -0
  76. package/dist/dictionary/decoderDictionary.test.js +87 -0
  77. package/dist/dictionary/decoderDictionary.test.js.map +1 -0
  78. package/dist/encode/blockWriter.d.ts +5 -0
  79. package/dist/encode/blockWriter.js +27 -0
  80. package/dist/encode/blockWriter.js.map +1 -0
  81. package/dist/encode/blockWriter.test.d.ts +1 -0
  82. package/dist/encode/blockWriter.test.js +31 -0
  83. package/dist/encode/blockWriter.test.js.map +1 -0
  84. package/dist/encode/compressedBlock.d.ts +3 -0
  85. package/dist/encode/compressedBlock.js +449 -0
  86. package/dist/encode/compressedBlock.js.map +1 -0
  87. package/dist/encode/compressedBlock.test.d.ts +1 -0
  88. package/dist/encode/compressedBlock.test.js +63 -0
  89. package/dist/encode/compressedBlock.test.js.map +1 -0
  90. package/dist/encode/frameWriter.d.ts +4 -0
  91. package/dist/encode/frameWriter.js +34 -0
  92. package/dist/encode/frameWriter.js.map +1 -0
  93. package/dist/encode/frameWriter.test.d.ts +1 -0
  94. package/dist/encode/frameWriter.test.js +38 -0
  95. package/dist/encode/frameWriter.test.js.map +1 -0
  96. package/dist/encode/greedySequences.d.ts +7 -0
  97. package/dist/encode/greedySequences.js +82 -0
  98. package/dist/encode/greedySequences.js.map +1 -0
  99. package/dist/encode/greedySequences.test.d.ts +1 -0
  100. package/dist/encode/greedySequences.test.js +33 -0
  101. package/dist/encode/greedySequences.test.js.map +1 -0
  102. package/dist/entropy/fse.d.ts +33 -0
  103. package/dist/entropy/fse.js +217 -0
  104. package/dist/entropy/fse.js.map +1 -0
  105. package/dist/entropy/fse.test.d.ts +1 -0
  106. package/dist/entropy/fse.test.js +41 -0
  107. package/dist/entropy/fse.test.js.map +1 -0
  108. package/dist/entropy/huffman.d.ts +24 -0
  109. package/dist/entropy/huffman.js +70 -0
  110. package/dist/entropy/huffman.js.map +1 -0
  111. package/dist/entropy/huffman.test.d.ts +1 -0
  112. package/dist/entropy/huffman.test.js +22 -0
  113. package/dist/entropy/huffman.test.js.map +1 -0
  114. package/dist/entropy/index.d.ts +6 -0
  115. package/dist/entropy/index.js +5 -0
  116. package/dist/entropy/index.js.map +1 -0
  117. package/dist/entropy/predefined.d.ts +10 -0
  118. package/dist/entropy/predefined.js +18 -0
  119. package/dist/entropy/predefined.js.map +1 -0
  120. package/dist/entropy/weights.d.ts +20 -0
  121. package/dist/entropy/weights.js +108 -0
  122. package/dist/entropy/weights.js.map +1 -0
  123. package/dist/entropy/weights.test.d.ts +1 -0
  124. package/dist/entropy/weights.test.js +38 -0
  125. package/dist/entropy/weights.test.js.map +1 -0
  126. package/dist/errors.d.ts +7 -0
  127. package/dist/errors.js +13 -0
  128. package/dist/errors.js.map +1 -0
  129. package/dist/errors.test.d.ts +1 -0
  130. package/dist/errors.test.js +16 -0
  131. package/dist/errors.test.js.map +1 -0
  132. package/dist/frame/checksum.d.ts +17 -0
  133. package/dist/frame/checksum.js +94 -0
  134. package/dist/frame/checksum.js.map +1 -0
  135. package/dist/frame/checksum.test.d.ts +1 -0
  136. package/dist/frame/checksum.test.js +28 -0
  137. package/dist/frame/checksum.test.js.map +1 -0
  138. package/dist/frame/frameHeader.d.ts +26 -0
  139. package/dist/frame/frameHeader.js +127 -0
  140. package/dist/frame/frameHeader.js.map +1 -0
  141. package/dist/frame/frameHeader.test.d.ts +1 -0
  142. package/dist/frame/frameHeader.test.js +83 -0
  143. package/dist/frame/frameHeader.test.js.map +1 -0
  144. package/dist/frame/index.d.ts +4 -0
  145. package/dist/frame/index.js +4 -0
  146. package/dist/frame/index.js.map +1 -0
  147. package/dist/frame/skippable.d.ts +12 -0
  148. package/dist/frame/skippable.js +27 -0
  149. package/dist/frame/skippable.js.map +1 -0
  150. package/dist/frame/skippable.test.d.ts +1 -0
  151. package/dist/frame/skippable.test.js +35 -0
  152. package/dist/frame/skippable.test.js.map +1 -0
  153. package/dist/index.d.ts +2 -0
  154. package/dist/index.js +3 -0
  155. package/dist/index.js.map +1 -0
  156. package/dist/tsconfig.tsbuildinfo +1 -0
  157. package/package.json +38 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"littleEndian.test.js","sourceRoot":"","sources":["../../src/bitstream/littleEndian.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEpE,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE,CAAC;IAC7B,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC;QACpB,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;QACpD,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAAA,CACzC,CAAC,CAAC;IAEH,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC;QACpB,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QACtD,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAAA,CAC7C,CAAC,CAAC;IAEH,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC;QACpB,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QAC9E,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAAA,CACtD,CAAC,CAAC;IAEH,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACvC,MAAM,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;IAAA,CAC5C,CAAC,CAAC;AAAA,CACJ,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Variable-length integer (varint) decode/encode per zstd format.
3
+ * 1-9 bytes, little-endian, 7 bits per byte, high bit = continue.
4
+ */
5
+ export declare function decodeVarint(data: Uint8Array, offset: number): {
6
+ value: number;
7
+ bytesRead: number;
8
+ };
9
+ export declare function encodeVarint(value: number): Uint8Array;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Variable-length integer (varint) decode/encode per zstd format.
3
+ * 1-9 bytes, little-endian, 7 bits per byte, high bit = continue.
4
+ */
5
+ export function decodeVarint(data, offset) {
6
+ let value = 0;
7
+ let shift = 0;
8
+ let pos = offset;
9
+ for (let i = 0; i < 9; i++) {
10
+ if (pos >= data.length) {
11
+ throw new RangeError('decodeVarint: truncated input');
12
+ }
13
+ const byte = data[pos];
14
+ if (byte === undefined)
15
+ throw new RangeError('decodeVarint: truncated input');
16
+ pos++;
17
+ value |= (byte & 0x7f) << shift;
18
+ if ((byte & 0x80) === 0) {
19
+ return { value, bytesRead: pos - offset };
20
+ }
21
+ shift += 7;
22
+ if (shift >= 56) {
23
+ throw new RangeError('decodeVarint: value too large');
24
+ }
25
+ }
26
+ throw new RangeError('decodeVarint: exceeds 9 bytes');
27
+ }
28
+ export function encodeVarint(value) {
29
+ const bytes = [];
30
+ let v = value >>> 0;
31
+ do {
32
+ let byte = v & 0x7f;
33
+ v >>>= 7;
34
+ if (v !== 0)
35
+ byte |= 0x80;
36
+ bytes.push(byte);
37
+ } while (v !== 0);
38
+ return new Uint8Array(bytes);
39
+ }
40
+ //# sourceMappingURL=varint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"varint.js","sourceRoot":"","sources":["../../src/bitstream/varint.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,UAAU,YAAY,CAAC,IAAgB,EAAE,MAAc,EAAwC;IACnG,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,GAAG,GAAG,MAAM,CAAC;IAEjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YACvB,MAAM,IAAI,UAAU,CAAC,+BAA+B,CAAC,CAAC;QACxD,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;QACvB,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,IAAI,UAAU,CAAC,+BAA+B,CAAC,CAAC;QAC9E,GAAG,EAAE,CAAC;QACN,KAAK,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,KAAK,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,GAAG,MAAM,EAAE,CAAC;QAC5C,CAAC;QACD,KAAK,IAAI,CAAC,CAAC;QACX,IAAI,KAAK,IAAI,EAAE,EAAE,CAAC;YAChB,MAAM,IAAI,UAAU,CAAC,+BAA+B,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;IAED,MAAM,IAAI,UAAU,CAAC,+BAA+B,CAAC,CAAC;AAAA,CACvD;AAED,MAAM,UAAU,YAAY,CAAC,KAAa,EAAc;IACtD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC;IAEpB,GAAG,CAAC;QACF,IAAI,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC;QACpB,CAAC,MAAM,CAAC,CAAC;QACT,IAAI,CAAC,KAAK,CAAC;YAAE,IAAI,IAAI,IAAI,CAAC;QAC1B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;IAElB,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;AAAA,CAC9B"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,25 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { decodeVarint, encodeVarint } from './varint.js';
3
+ describe('varint', () => {
4
+ it('encodes and decodes small values', () => {
5
+ for (const v of [0, 1, 127, 128, 255, 256, 16383]) {
6
+ const encoded = encodeVarint(v);
7
+ const { value, bytesRead } = decodeVarint(encoded, 0);
8
+ expect(value).toBe(v);
9
+ expect(bytesRead).toBe(encoded.length);
10
+ }
11
+ });
12
+ it('decodes single-byte varint', () => {
13
+ const data = new Uint8Array([0x7f]); // 127, no continuation
14
+ const { value, bytesRead } = decodeVarint(data, 0);
15
+ expect(value).toBe(127);
16
+ expect(bytesRead).toBe(1);
17
+ });
18
+ it('decodes two-byte varint', () => {
19
+ const data = new Uint8Array([0x80, 0x01]); // 128 = 0x80 | 0x01<<7
20
+ const { value, bytesRead } = decodeVarint(data, 0);
21
+ expect(value).toBe(128);
22
+ expect(bytesRead).toBe(2);
23
+ });
24
+ });
25
+ //# sourceMappingURL=varint.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"varint.test.js","sourceRoot":"","sources":["../../src/bitstream/varint.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEzD,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC;IACvB,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE,CAAC;QAC3C,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC;YAClD,MAAM,OAAO,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;YAChC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YACtD,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACtB,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACzC,CAAC;IAAA,CACF,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,uBAAuB;QAC5D,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACnD,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxB,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAAA,CAC3B,CAAC,CAAC;IAEH,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,uBAAuB;QAClE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACnD,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxB,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAAA,CAC3B,CAAC,CAAC;AAAA,CACJ,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Compress input data using zstd.
3
+ * Level 0: raw blocks only (no compression, fast).
4
+ */
5
+ export type CompressOptions = {
6
+ level?: number;
7
+ checksum?: boolean;
8
+ };
9
+ export declare function compress(input: Uint8Array, options?: CompressOptions): Uint8Array;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Compress input data using zstd.
3
+ * Level 0: raw blocks only (no compression, fast).
4
+ */
5
+ import { writeRawBlock, writeRLEBlock } from './encode/blockWriter.js';
6
+ import { buildCompressedBlockPayload, writeCompressedBlock } from './encode/compressedBlock.js';
7
+ import { writeFrameHeader } from './encode/frameWriter.js';
8
+ import { buildGreedySequences } from './encode/greedySequences.js';
9
+ import { computeContentChecksum32 } from './frame/checksum.js';
10
+ const BLOCK_MAX = 128 * 1024;
11
+ export function compress(input, options) {
12
+ const level = options?.level ?? 0;
13
+ const hasChecksum = options?.checksum ?? false;
14
+ const chunks = [];
15
+ chunks.push(writeFrameHeader(input.length, hasChecksum));
16
+ let offset = 0;
17
+ const blockCount = input.length === 0 ? 1 : Math.ceil(input.length / BLOCK_MAX);
18
+ let blockIndex = 0;
19
+ while (offset < input.length || blockIndex < blockCount) {
20
+ const size = Math.min(BLOCK_MAX, input.length - offset);
21
+ const last = blockIndex === blockCount - 1;
22
+ const block = input.subarray(offset, offset + size);
23
+ if (level > 0 && size > 0) {
24
+ if (level > 1) {
25
+ const plan = buildGreedySequences(block);
26
+ if (plan.sequences.length > 0) {
27
+ const payload = buildCompressedBlockPayload(plan.literals, plan.sequences);
28
+ if (payload) {
29
+ const compressed = writeCompressedBlock(payload, last);
30
+ const raw = writeRawBlock(input, offset, size, last);
31
+ if (compressed.length < raw.length) {
32
+ chunks.push(compressed);
33
+ offset += size;
34
+ blockIndex++;
35
+ continue;
36
+ }
37
+ }
38
+ }
39
+ }
40
+ const first = input[offset] ?? 0;
41
+ let isRLE = true;
42
+ for (let i = offset + 1; i < offset + size; i++) {
43
+ if ((input[i] ?? 0) !== first) {
44
+ isRLE = false;
45
+ break;
46
+ }
47
+ }
48
+ if (isRLE) {
49
+ chunks.push(writeRLEBlock(first, size, last));
50
+ }
51
+ else {
52
+ chunks.push(writeRawBlock(input, offset, size, last));
53
+ }
54
+ }
55
+ else {
56
+ chunks.push(writeRawBlock(input, offset, size, last));
57
+ }
58
+ offset += size;
59
+ blockIndex++;
60
+ }
61
+ if (hasChecksum) {
62
+ const checksum = computeContentChecksum32(input);
63
+ chunks.push(new Uint8Array([checksum & 0xff, (checksum >>> 8) & 0xff, (checksum >>> 16) & 0xff, (checksum >>> 24) & 0xff]));
64
+ }
65
+ const total = chunks.reduce((s, c) => s + c.length, 0);
66
+ const result = new Uint8Array(total);
67
+ let pos = 0;
68
+ for (const chunk of chunks) {
69
+ result.set(chunk, pos);
70
+ pos += chunk.length;
71
+ }
72
+ return result;
73
+ }
74
+ //# sourceMappingURL=compress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compress.js","sourceRoot":"","sources":["../src/compress.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Block header parsing and block type dispatch.
3
+ */
4
+ export declare const BLOCK_HEADER_SIZE = 3;
5
+ export type BlockType = 0 | 1 | 2 | 3;
6
+ export interface BlockHeader {
7
+ lastBlock: boolean;
8
+ blockType: BlockType;
9
+ blockSize: number;
10
+ }
11
+ export declare function parseBlockHeader(data: Uint8Array, offset: number): BlockHeader;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Block header parsing and block type dispatch.
3
+ */
4
+ import { ZstdError } from '../errors.js';
5
+ export const BLOCK_HEADER_SIZE = 3;
6
+ function readU24LE(data, offset) {
7
+ if (offset + 3 > data.length) {
8
+ throw new RangeError(`readU24LE: offset ${offset} + 3 exceeds length ${data.length}`);
9
+ }
10
+ const a = data[offset] ?? 0;
11
+ const b = data[offset + 1] ?? 0;
12
+ const c = data[offset + 2] ?? 0;
13
+ return a | (b << 8) | (c << 16);
14
+ }
15
+ export function parseBlockHeader(data, offset) {
16
+ if (offset + BLOCK_HEADER_SIZE > data.length) {
17
+ throw new ZstdError('Block header truncated', 'corruption_detected');
18
+ }
19
+ const w = readU24LE(data, offset);
20
+ const lastBlock = (w & 1) === 1;
21
+ const blockType = ((w >> 1) & 3);
22
+ const blockSize = w >> 3;
23
+ if (blockType === 3) {
24
+ throw new ZstdError('Reserved block type', 'corruption_detected');
25
+ }
26
+ return { lastBlock, blockType, blockSize };
27
+ }
28
+ //# sourceMappingURL=block.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"block.js","sourceRoot":"","sources":["../../src/decode/block.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAUnC,SAAS,SAAS,CAAC,IAAgB,EAAE,MAAc,EAAU;IAC3D,IAAI,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC7B,MAAM,IAAI,UAAU,CAAC,qBAAqB,MAAM,uBAAuB,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACxF,CAAC;IACD,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5B,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;AAAA,CACjC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAgB,EAAE,MAAc,EAAe;IAC9E,IAAI,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC7C,MAAM,IAAI,SAAS,CAAC,wBAAwB,EAAE,qBAAqB,CAAC,CAAC;IACvE,CAAC;IACD,MAAM,CAAC,GAAG,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAChC,MAAM,SAAS,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAc,CAAC;IAC9C,MAAM,SAAS,GAAG,CAAC,IAAI,CAAC,CAAC;IAEzB,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,SAAS,CAAC,qBAAqB,EAAE,qBAAqB,CAAC,CAAC;IACpE,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;AAAA,CAC5C"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,26 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { parseBlockHeader } from './block.js';
3
+ describe('block', () => {
4
+ it('parses raw block header (last=1, type=0, size=5)', () => {
5
+ // last=1, type=0, size=5 -> (5<<3)|0<<1|1 = 41
6
+ const data = new Uint8Array([0x29, 0x00, 0x00]);
7
+ const block = parseBlockHeader(data, 0);
8
+ expect(block.lastBlock).toBe(true);
9
+ expect(block.blockType).toBe(0);
10
+ expect(block.blockSize).toBe(5);
11
+ });
12
+ it('throws on reserved block type 3', () => {
13
+ // last=0, type=3, size=0
14
+ const data = new Uint8Array([0x06, 0x00, 0x00]);
15
+ expect(() => parseBlockHeader(data, 0)).toThrow(/Reserved block type|corruption/i);
16
+ });
17
+ it('throws when block header is truncated', () => {
18
+ const data = new Uint8Array([0x28, 0xb5]);
19
+ expect(() => parseBlockHeader(data, 0)).toThrow(/Block header truncated|corruption/i);
20
+ });
21
+ it('throws when offset + 3 exceeds data length', () => {
22
+ const data = new Uint8Array([0x29, 0x00]);
23
+ expect(() => parseBlockHeader(data, 0)).toThrow(/truncated|corruption/i);
24
+ });
25
+ });
26
+ //# sourceMappingURL=block.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"block.test.js","sourceRoot":"","sources":["../../src/decode/block.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC;IACtB,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE,CAAC;QAC3D,+CAA+C;QAC/C,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QAChD,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAAA,CACjC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE,CAAC;QAC1C,yBAAyB;QACzB,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QAChD,MAAM,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC;IAAA,CACpF,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE,CAAC;QAChD,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,oCAAoC,CAAC,CAAC;IAAA,CACvF,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE,CAAC;QACrD,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAAA,CAC1E,CAAC,CAAC;AAAA,CACJ,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Decompress a single zstd frame.
3
+ */
4
+ import type { DecoderDictionaryContext } from '../dictionary/decoderDictionary.js';
5
+ import type { FrameHeader } from '../frame/frameHeader.js';
6
+ export declare function decompressFrame(data: Uint8Array, offset: number, header: FrameHeader, dictionary?: DecoderDictionaryContext | null, maxSize?: number): {
7
+ output: Uint8Array;
8
+ bytesConsumed: number;
9
+ };
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Decompress a single zstd frame.
3
+ */
4
+ import { readU32LE } from '../bitstream/littleEndian.js';
5
+ import { ZstdError } from '../errors.js';
6
+ import { validateContentChecksum } from '../frame/checksum.js';
7
+ import { parseBlockHeader } from './block.js';
8
+ import { decodeCompressedLiterals, decodeRawLiterals, decodeRLELiterals, decodeTreelessLiterals, parseLiteralsSectionHeader, } from './literals.js';
9
+ import { executeSequences } from './reconstruct.js';
10
+ import { decodeSequences } from './sequences.js';
11
+ export function decompressFrame(data, offset, header, dictionary, maxSize) {
12
+ let pos = offset + 4 + header.headerSize;
13
+ const chunks = [];
14
+ let totalSize = 0;
15
+ const repOffsets = dictionary?.repOffsets
16
+ ? [dictionary.repOffsets[0], dictionary.repOffsets[1], dictionary.repOffsets[2]]
17
+ : [1, 4, 8];
18
+ let history = new Uint8Array(0);
19
+ if (dictionary?.historyPrefix && dictionary.historyPrefix.length > 0) {
20
+ history = dictionary.historyPrefix.slice();
21
+ }
22
+ let prevHuffmanTable = dictionary?.huffmanTable ?? null;
23
+ let prevSeqTables = dictionary?.sequenceTables ?? null;
24
+ while (true) {
25
+ if (pos + 3 > data.length) {
26
+ throw new ZstdError('Block header truncated', 'corruption_detected');
27
+ }
28
+ const block = parseBlockHeader(data, pos);
29
+ pos += 3;
30
+ if (block.blockType === 0) {
31
+ const literals = decodeRawLiterals(data, pos, block.blockSize);
32
+ chunks.push(literals);
33
+ totalSize += literals.length;
34
+ history = appendToHistory(history, literals, header.windowSize);
35
+ pos += block.blockSize;
36
+ }
37
+ else if (block.blockType === 1) {
38
+ const literals = decodeRLELiterals(data, pos, block.blockSize);
39
+ chunks.push(literals);
40
+ totalSize += literals.length;
41
+ history = appendToHistory(history, literals, header.windowSize);
42
+ pos += 1;
43
+ }
44
+ else if (block.blockType === 2) {
45
+ const blockContent = data.subarray(pos, pos + block.blockSize);
46
+ const { header: litHeader, dataOffset: litDataOffset } = parseLiteralsSectionHeader(blockContent, 0);
47
+ let literals;
48
+ let litBytesConsumed;
49
+ if (litHeader.blockType === 0) {
50
+ literals = decodeRawLiterals(blockContent, litDataOffset, litHeader.regeneratedSize);
51
+ litBytesConsumed = litHeader.headerSize + litHeader.regeneratedSize;
52
+ }
53
+ else if (litHeader.blockType === 1) {
54
+ literals = decodeRLELiterals(blockContent, litDataOffset, litHeader.regeneratedSize);
55
+ litBytesConsumed = litHeader.headerSize + 1;
56
+ }
57
+ else if (litHeader.blockType === 2) {
58
+ const comp = decodeCompressedLiterals(blockContent, litDataOffset, litHeader.compressedSize, litHeader.regeneratedSize, litHeader.numStreams);
59
+ literals = comp.literals;
60
+ prevHuffmanTable = comp.huffmanTable;
61
+ litBytesConsumed = litHeader.headerSize + comp.bytesRead;
62
+ }
63
+ else {
64
+ if (!prevHuffmanTable) {
65
+ throw new ZstdError('Treeless literals without previous Huffman table', 'corruption_detected');
66
+ }
67
+ const comp = decodeTreelessLiterals(blockContent, litDataOffset, litHeader.compressedSize, litHeader.regeneratedSize, litHeader.numStreams, prevHuffmanTable);
68
+ literals = comp.literals;
69
+ litBytesConsumed = litHeader.headerSize + comp.bytesRead;
70
+ }
71
+ const seqSectionSize = block.blockSize - litBytesConsumed;
72
+ let output;
73
+ if (seqSectionSize <= 0) {
74
+ output = literals;
75
+ }
76
+ else {
77
+ const seqResult = decodeSequences(blockContent, litBytesConsumed, seqSectionSize, prevSeqTables);
78
+ prevSeqTables = seqResult.tables;
79
+ if (seqResult.sequences.length === 0) {
80
+ output = literals;
81
+ }
82
+ else {
83
+ output = executeSequences(literals, seqResult.sequences, header.windowSize, repOffsets, history);
84
+ }
85
+ }
86
+ chunks.push(output);
87
+ totalSize += output.length;
88
+ history = appendToHistory(history, output, header.windowSize);
89
+ pos += block.blockSize;
90
+ }
91
+ else {
92
+ throw new ZstdError('Unsupported block type', 'corruption_detected');
93
+ }
94
+ if (maxSize !== undefined && totalSize > maxSize) {
95
+ throw new ZstdError('Decompressed size exceeds maxSize', 'parameter_unsupported');
96
+ }
97
+ if (block.lastBlock)
98
+ break;
99
+ }
100
+ const output = concatenateChunks(chunks);
101
+ if (header.contentSize !== null && output.length !== header.contentSize) {
102
+ throw new ZstdError('Frame content size mismatch', 'corruption_detected');
103
+ }
104
+ if (header.hasContentChecksum) {
105
+ if (pos + 4 > data.length) {
106
+ throw new ZstdError('Content checksum truncated', 'corruption_detected');
107
+ }
108
+ const storedChecksum = readU32LE(data, pos);
109
+ if (!validateContentChecksum(output, storedChecksum)) {
110
+ throw new ZstdError('Content checksum mismatch', 'corruption_detected');
111
+ }
112
+ pos += 4;
113
+ return { output, bytesConsumed: pos - offset };
114
+ }
115
+ return { output, bytesConsumed: pos - offset };
116
+ }
117
+ function appendToHistory(history, chunk, windowSize) {
118
+ if (windowSize <= 0 || chunk.length === 0) {
119
+ return history;
120
+ }
121
+ const maxHistory = Math.max(1, windowSize);
122
+ if (chunk.length >= maxHistory) {
123
+ return new Uint8Array(chunk.subarray(chunk.length - maxHistory));
124
+ }
125
+ const keepFromHistory = Math.min(history.length, maxHistory - chunk.length);
126
+ const next = new Uint8Array(keepFromHistory + chunk.length);
127
+ if (keepFromHistory > 0) {
128
+ next.set(history.subarray(history.length - keepFromHistory), 0);
129
+ }
130
+ next.set(chunk, keepFromHistory);
131
+ return next;
132
+ }
133
+ function concatenateChunks(chunks) {
134
+ if (chunks.length === 0)
135
+ return new Uint8Array(0);
136
+ if (chunks.length === 1)
137
+ return chunks[0];
138
+ const total = chunks.reduce((s, c) => s + c.length, 0);
139
+ const result = new Uint8Array(total);
140
+ let pos = 0;
141
+ for (const chunk of chunks) {
142
+ result.set(chunk, pos);
143
+ pos += chunk.length;
144
+ }
145
+ return result;
146
+ }
147
+ //# sourceMappingURL=decompressFrame.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decompressFrame.js","sourceRoot":"","sources":["../../src/decode/decompressFrame.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,26 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { decodeCompressedLiterals, decodeRawLiterals, decodeRLELiterals, decodeTreelessLiterals, parseLiteralsSectionHeader, } from './literals.js';
3
+ describe('literals corruption handling', () => {
4
+ it('rejects truncated literals section header', () => {
5
+ const data = new Uint8Array([0x24]); // compressed literals sizeFormat=1 requires 3-byte header
6
+ expect(() => parseLiteralsSectionHeader(data, 0)).toThrowError(/header truncated/i);
7
+ });
8
+ it('rejects raw literals overrun', () => {
9
+ const data = new Uint8Array([0x61, 0x62]);
10
+ expect(() => decodeRawLiterals(data, 0, 3)).toThrowError(/Raw literals truncated/i);
11
+ });
12
+ it('rejects rle literals when source byte is missing', () => {
13
+ const data = new Uint8Array([]);
14
+ expect(() => decodeRLELiterals(data, 0, 10)).toThrowError(/RLE literals truncated/i);
15
+ });
16
+ it('rejects invalid compressed literals size', () => {
17
+ const data = new Uint8Array([0x80]); // direct weights header with 1 weight; no stream payload
18
+ expect(() => decodeCompressedLiterals(data, 0, 1, 16, 1)).toThrowError(/truncated|Invalid literals compressed size/i);
19
+ });
20
+ it('rejects treeless 4-stream with compressedSize < 10', () => {
21
+ const table = decodeCompressedLiterals(new Uint8Array([129, 0x10, 0x02]), 0, 3, 1, 1).huffmanTable;
22
+ const data = new Uint8Array(9);
23
+ expect(() => decodeTreelessLiterals(data, 0, 9, 100, 4, table)).toThrowError(/4-stream mode requires at least 10 bytes/i);
24
+ });
25
+ });
26
+ //# sourceMappingURL=literals.corruption.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"literals.corruption.test.js","sourceRoot":"","sources":["../../src/decode/literals.corruption.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,wBAAwB,EACxB,iBAAiB,EACjB,iBAAiB,EACjB,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,eAAe,CAAC;AAEvB,QAAQ,CAAC,8BAA8B,EAAE,GAAG,EAAE,CAAC;IAC7C,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE,CAAC;QACpD,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,0DAA0D;QAC/F,MAAM,CAAC,GAAG,EAAE,CAAC,0BAA0B,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,mBAAmB,CAAC,CAAC;IAAA,CACrF,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,yBAAyB,CAAC,CAAC;IAAA,CACrF,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE,CAAC;QAC3D,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;QAChC,MAAM,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,yBAAyB,CAAC,CAAC;IAAA,CACtF,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE,CAAC;QACnD,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,yDAAyD;QAC9F,MAAM,CAAC,GAAG,EAAE,CAAC,wBAAwB,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CACpE,6CAA6C,CAC9C,CAAC;IAAA,CACH,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE,CAAC;QAC7D,MAAM,KAAK,GAAG,wBAAwB,CAAC,IAAI,UAAU,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC;QACnG,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,GAAG,EAAE,CAAC,sBAAsB,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,YAAY,CAC1E,2CAA2C,CAC5C,CAAC;IAAA,CACH,CAAC,CAAC;AAAA,CACJ,CAAC,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Decode literals section: Raw, RLE, Compressed, Treeless.
3
+ */
4
+ import { buildHuffmanDecodeTable } from '../entropy/huffman.js';
5
+ export type LiteralsBlockType = 0 | 1 | 2 | 3;
6
+ export interface LiteralsSectionHeader {
7
+ blockType: LiteralsBlockType;
8
+ regeneratedSize: number;
9
+ compressedSize?: number;
10
+ numStreams: 1 | 4;
11
+ headerSize: number;
12
+ }
13
+ /**
14
+ * Parse Literals_Section_Header from compressed block.
15
+ * Returns header info and the byte offset after the header.
16
+ */
17
+ export declare function parseLiteralsSectionHeader(data: Uint8Array, offset: number): {
18
+ header: LiteralsSectionHeader;
19
+ dataOffset: number;
20
+ };
21
+ /**
22
+ * Decode raw literals block - direct copy.
23
+ */
24
+ export declare function decodeRawLiterals(data: Uint8Array, offset: number, size: number): Uint8Array;
25
+ /**
26
+ * Decode RLE literals block - single byte repeated.
27
+ */
28
+ export declare function decodeRLELiterals(data: Uint8Array, offset: number, size: number): Uint8Array;
29
+ /**
30
+ * Decode compressed literals (Huffman). Requires Huffman table from tree description.
31
+ */
32
+ export declare function decodeCompressedLiterals(data: Uint8Array, offset: number, compressedSize: number, regeneratedSize: number, numStreams: 1 | 4): {
33
+ literals: Uint8Array;
34
+ huffmanTable: {
35
+ table: ReturnType<typeof buildHuffmanDecodeTable>;
36
+ maxNumBits: number;
37
+ };
38
+ bytesRead: number;
39
+ };
40
+ /**
41
+ * Decode treeless literals (reuse previous Huffman table).
42
+ */
43
+ export declare function decodeTreelessLiterals(data: Uint8Array, offset: number, compressedSize: number, regeneratedSize: number, numStreams: 1 | 4, huffmanTable: {
44
+ table: ReturnType<typeof buildHuffmanDecodeTable>;
45
+ maxNumBits: number;
46
+ }): {
47
+ literals: Uint8Array;
48
+ bytesRead: number;
49
+ };