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.
- package/LICENSE +21 -0
- package/README.md +95 -0
- package/dist/bitstream/bitReader.d.ts +26 -0
- package/dist/bitstream/bitReader.js +86 -0
- package/dist/bitstream/bitReader.js.map +1 -0
- package/dist/bitstream/bitReader.test.d.ts +1 -0
- package/dist/bitstream/bitReader.test.js +47 -0
- package/dist/bitstream/bitReader.test.js.map +1 -0
- package/dist/bitstream/bitReaderReverse.d.ts +23 -0
- package/dist/bitstream/bitReaderReverse.js +84 -0
- package/dist/bitstream/bitReaderReverse.js.map +1 -0
- package/dist/bitstream/bitReaderReverse.test.d.ts +1 -0
- package/dist/bitstream/bitReaderReverse.test.js +49 -0
- package/dist/bitstream/bitReaderReverse.test.js.map +1 -0
- package/dist/bitstream/bitWriter.d.ts +15 -0
- package/dist/bitstream/bitWriter.js +47 -0
- package/dist/bitstream/bitWriter.js.map +1 -0
- package/dist/bitstream/index.d.ts +4 -0
- package/dist/bitstream/index.js +5 -0
- package/dist/bitstream/index.js.map +1 -0
- package/dist/bitstream/littleEndian.d.ts +7 -0
- package/dist/bitstream/littleEndian.js +45 -0
- package/dist/bitstream/littleEndian.js.map +1 -0
- package/dist/bitstream/littleEndian.test.d.ts +1 -0
- package/dist/bitstream/littleEndian.test.js +21 -0
- package/dist/bitstream/littleEndian.test.js.map +1 -0
- package/dist/bitstream/varint.d.ts +9 -0
- package/dist/bitstream/varint.js +40 -0
- package/dist/bitstream/varint.js.map +1 -0
- package/dist/bitstream/varint.test.d.ts +1 -0
- package/dist/bitstream/varint.test.js +25 -0
- package/dist/bitstream/varint.test.js.map +1 -0
- package/dist/compress.d.ts +9 -0
- package/dist/compress.js +74 -0
- package/dist/compress.js.map +1 -0
- package/dist/decode/block.d.ts +11 -0
- package/dist/decode/block.js +28 -0
- package/dist/decode/block.js.map +1 -0
- package/dist/decode/block.test.d.ts +1 -0
- package/dist/decode/block.test.js +26 -0
- package/dist/decode/block.test.js.map +1 -0
- package/dist/decode/decompressFrame.d.ts +9 -0
- package/dist/decode/decompressFrame.js +147 -0
- package/dist/decode/decompressFrame.js.map +1 -0
- package/dist/decode/literals.corruption.test.d.ts +1 -0
- package/dist/decode/literals.corruption.test.js +26 -0
- package/dist/decode/literals.corruption.test.js.map +1 -0
- package/dist/decode/literals.d.ts +49 -0
- package/dist/decode/literals.js +300 -0
- package/dist/decode/literals.js.map +1 -0
- package/dist/decode/literals.test.d.ts +1 -0
- package/dist/decode/literals.test.js +52 -0
- package/dist/decode/literals.test.js.map +1 -0
- package/dist/decode/reconstruct.d.ts +13 -0
- package/dist/decode/reconstruct.js +80 -0
- package/dist/decode/reconstruct.js.map +1 -0
- package/dist/decode/reconstruct.test.d.ts +1 -0
- package/dist/decode/reconstruct.test.js +42 -0
- package/dist/decode/reconstruct.test.js.map +1 -0
- package/dist/decode/sequences.corruption.test.d.ts +1 -0
- package/dist/decode/sequences.corruption.test.js +32 -0
- package/dist/decode/sequences.corruption.test.js.map +1 -0
- package/dist/decode/sequences.d.ts +21 -0
- package/dist/decode/sequences.js +222 -0
- package/dist/decode/sequences.js.map +1 -0
- package/dist/decode/sequences.level1.test.d.ts +1 -0
- package/dist/decode/sequences.level1.test.js +35 -0
- package/dist/decode/sequences.level1.test.js.map +1 -0
- package/dist/decompress.d.ts +11 -0
- package/dist/decompress.js +59 -0
- package/dist/decompress.js.map +1 -0
- package/dist/dictionary/decoderDictionary.d.ts +15 -0
- package/dist/dictionary/decoderDictionary.js +116 -0
- package/dist/dictionary/decoderDictionary.js.map +1 -0
- package/dist/dictionary/decoderDictionary.test.d.ts +1 -0
- package/dist/dictionary/decoderDictionary.test.js +87 -0
- package/dist/dictionary/decoderDictionary.test.js.map +1 -0
- package/dist/encode/blockWriter.d.ts +5 -0
- package/dist/encode/blockWriter.js +27 -0
- package/dist/encode/blockWriter.js.map +1 -0
- package/dist/encode/blockWriter.test.d.ts +1 -0
- package/dist/encode/blockWriter.test.js +31 -0
- package/dist/encode/blockWriter.test.js.map +1 -0
- package/dist/encode/compressedBlock.d.ts +3 -0
- package/dist/encode/compressedBlock.js +449 -0
- package/dist/encode/compressedBlock.js.map +1 -0
- package/dist/encode/compressedBlock.test.d.ts +1 -0
- package/dist/encode/compressedBlock.test.js +63 -0
- package/dist/encode/compressedBlock.test.js.map +1 -0
- package/dist/encode/frameWriter.d.ts +4 -0
- package/dist/encode/frameWriter.js +34 -0
- package/dist/encode/frameWriter.js.map +1 -0
- package/dist/encode/frameWriter.test.d.ts +1 -0
- package/dist/encode/frameWriter.test.js +38 -0
- package/dist/encode/frameWriter.test.js.map +1 -0
- package/dist/encode/greedySequences.d.ts +7 -0
- package/dist/encode/greedySequences.js +82 -0
- package/dist/encode/greedySequences.js.map +1 -0
- package/dist/encode/greedySequences.test.d.ts +1 -0
- package/dist/encode/greedySequences.test.js +33 -0
- package/dist/encode/greedySequences.test.js.map +1 -0
- package/dist/entropy/fse.d.ts +33 -0
- package/dist/entropy/fse.js +217 -0
- package/dist/entropy/fse.js.map +1 -0
- package/dist/entropy/fse.test.d.ts +1 -0
- package/dist/entropy/fse.test.js +41 -0
- package/dist/entropy/fse.test.js.map +1 -0
- package/dist/entropy/huffman.d.ts +24 -0
- package/dist/entropy/huffman.js +70 -0
- package/dist/entropy/huffman.js.map +1 -0
- package/dist/entropy/huffman.test.d.ts +1 -0
- package/dist/entropy/huffman.test.js +22 -0
- package/dist/entropy/huffman.test.js.map +1 -0
- package/dist/entropy/index.d.ts +6 -0
- package/dist/entropy/index.js +5 -0
- package/dist/entropy/index.js.map +1 -0
- package/dist/entropy/predefined.d.ts +10 -0
- package/dist/entropy/predefined.js +18 -0
- package/dist/entropy/predefined.js.map +1 -0
- package/dist/entropy/weights.d.ts +20 -0
- package/dist/entropy/weights.js +108 -0
- package/dist/entropy/weights.js.map +1 -0
- package/dist/entropy/weights.test.d.ts +1 -0
- package/dist/entropy/weights.test.js +38 -0
- package/dist/entropy/weights.test.js.map +1 -0
- package/dist/errors.d.ts +7 -0
- package/dist/errors.js +13 -0
- package/dist/errors.js.map +1 -0
- package/dist/errors.test.d.ts +1 -0
- package/dist/errors.test.js +16 -0
- package/dist/errors.test.js.map +1 -0
- package/dist/frame/checksum.d.ts +17 -0
- package/dist/frame/checksum.js +94 -0
- package/dist/frame/checksum.js.map +1 -0
- package/dist/frame/checksum.test.d.ts +1 -0
- package/dist/frame/checksum.test.js +28 -0
- package/dist/frame/checksum.test.js.map +1 -0
- package/dist/frame/frameHeader.d.ts +26 -0
- package/dist/frame/frameHeader.js +127 -0
- package/dist/frame/frameHeader.js.map +1 -0
- package/dist/frame/frameHeader.test.d.ts +1 -0
- package/dist/frame/frameHeader.test.js +83 -0
- package/dist/frame/frameHeader.test.js.map +1 -0
- package/dist/frame/index.d.ts +4 -0
- package/dist/frame/index.js +4 -0
- package/dist/frame/index.js.map +1 -0
- package/dist/frame/skippable.d.ts +12 -0
- package/dist/frame/skippable.js +27 -0
- package/dist/frame/skippable.js.map +1 -0
- package/dist/frame/skippable.test.d.ts +1 -0
- package/dist/frame/skippable.test.js +35 -0
- package/dist/frame/skippable.test.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +38 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"huffman.test.js","sourceRoot":"","sources":["../../src/entropy/huffman.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAE5E,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC;IACxB,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE,CAAC;QACtD,MAAM,KAAK,GAAG,uBAAuB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACpD,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC1D,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAAA,CAC5D,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE,CAAC;QAC3D,MAAM,KAAK,GAAG,uBAAuB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACpD,2EAA2E;QAC3E,0EAA0E;QAC1E,0DAA0D;QAC1D,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACxE,MAAM,CAAC,WAAW,EAAE,CAAC;QACrB,MAAM,MAAM,GAAG,mBAAmB,CAAC,KAAK,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;QACrD,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACvB,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAAA,CACpC,CAAC,CAAC;AAAA,CACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type { FSEDecodeRow } from './fse.js';
|
|
2
|
+
export { buildFSEDecodeTable, decodeFSESymbol, readNCount } from './fse.js';
|
|
3
|
+
export type { HuffmanDecodeRow } from './huffman.js';
|
|
4
|
+
export { buildHuffmanDecodeTable, decodeHuffmanSymbol, weightsToNumBits, } from './huffman.js';
|
|
5
|
+
export { LITERALS_LENGTH_DEFAULT_DISTRIBUTION, LITERALS_LENGTH_TABLE_LOG, MATCH_LENGTH_DEFAULT_DISTRIBUTION, MATCH_LENGTH_TABLE_LOG, OFFSET_CODE_DEFAULT_DISTRIBUTION, OFFSET_CODE_TABLE_LOG, } from './predefined.js';
|
|
6
|
+
export { readWeightsDirect, readWeightsFSE } from './weights.js';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { buildFSEDecodeTable, decodeFSESymbol, readNCount } from './fse.js';
|
|
2
|
+
export { buildHuffmanDecodeTable, decodeHuffmanSymbol, weightsToNumBits, } from './huffman.js';
|
|
3
|
+
export { LITERALS_LENGTH_DEFAULT_DISTRIBUTION, LITERALS_LENGTH_TABLE_LOG, MATCH_LENGTH_DEFAULT_DISTRIBUTION, MATCH_LENGTH_TABLE_LOG, OFFSET_CODE_DEFAULT_DISTRIBUTION, OFFSET_CODE_TABLE_LOG, } from './predefined.js';
|
|
4
|
+
export { readWeightsDirect, readWeightsFSE } from './weights.js';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/entropy/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAE5E,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,oCAAoC,EACpC,yBAAyB,EACzB,iCAAiC,EACjC,sBAAsB,EACtB,gCAAgC,EAChC,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Predefined FSE distributions from RFC 8878 / zstd spec.
|
|
3
|
+
* Used when Predefined_Mode is selected for a symbol type.
|
|
4
|
+
*/
|
|
5
|
+
export declare const LITERALS_LENGTH_DEFAULT_DISTRIBUTION: readonly number[];
|
|
6
|
+
export declare const MATCH_LENGTH_DEFAULT_DISTRIBUTION: readonly number[];
|
|
7
|
+
export declare const OFFSET_CODE_DEFAULT_DISTRIBUTION: readonly number[];
|
|
8
|
+
export declare const LITERALS_LENGTH_TABLE_LOG = 6;
|
|
9
|
+
export declare const MATCH_LENGTH_TABLE_LOG = 6;
|
|
10
|
+
export declare const OFFSET_CODE_TABLE_LOG = 5;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Predefined FSE distributions from RFC 8878 / zstd spec.
|
|
3
|
+
* Used when Predefined_Mode is selected for a symbol type.
|
|
4
|
+
*/
|
|
5
|
+
export const LITERALS_LENGTH_DEFAULT_DISTRIBUTION = [
|
|
6
|
+
4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1, -1, -1, -1, -1,
|
|
7
|
+
];
|
|
8
|
+
export const MATCH_LENGTH_DEFAULT_DISTRIBUTION = [
|
|
9
|
+
1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
10
|
+
1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1,
|
|
11
|
+
];
|
|
12
|
+
export const OFFSET_CODE_DEFAULT_DISTRIBUTION = [
|
|
13
|
+
1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
|
|
14
|
+
];
|
|
15
|
+
export const LITERALS_LENGTH_TABLE_LOG = 6;
|
|
16
|
+
export const MATCH_LENGTH_TABLE_LOG = 6;
|
|
17
|
+
export const OFFSET_CODE_TABLE_LOG = 5;
|
|
18
|
+
//# sourceMappingURL=predefined.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"predefined.js","sourceRoot":"","sources":["../../src/entropy/predefined.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,CAAC,MAAM,oCAAoC,GAAsB;IACrE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;CAC/G,CAAC;AAEF,MAAM,CAAC,MAAM,iCAAiC,GAAsB;IAClE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IACnH,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;CAChD,CAAC;AAEF,MAAM,CAAC,MAAM,gCAAgC,GAAsB;IACjE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;CAC3F,CAAC;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC;AAC3C,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AACxC,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read compressed weight streams for Huffman tree description.
|
|
3
|
+
* Weights can be FSE-compressed or direct (4 bits per weight).
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Read Huffman weights from direct representation (headerByte >= 128).
|
|
7
|
+
* Each weight is 4 bits, 2 per byte, first weight in high nibble.
|
|
8
|
+
*/
|
|
9
|
+
export declare function readWeightsDirect(data: Uint8Array, offset: number, numWeights: number): {
|
|
10
|
+
weights: number[];
|
|
11
|
+
bytesRead: number;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Read Huffman weights from FSE-compressed stream.
|
|
15
|
+
* Uses 2 interleaved FSE states decoding weight symbols (0-11).
|
|
16
|
+
*/
|
|
17
|
+
export declare function readWeightsFSE(data: Uint8Array, offset: number, compressedSize: number): {
|
|
18
|
+
weights: number[];
|
|
19
|
+
bytesRead: number;
|
|
20
|
+
};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read compressed weight streams for Huffman tree description.
|
|
3
|
+
* Weights can be FSE-compressed or direct (4 bits per weight).
|
|
4
|
+
*/
|
|
5
|
+
import { ZstdError } from '../errors.js';
|
|
6
|
+
import { buildFSEDecodeTable, readNCount } from './fse.js';
|
|
7
|
+
/**
|
|
8
|
+
* Read Huffman weights from direct representation (headerByte >= 128).
|
|
9
|
+
* Each weight is 4 bits, 2 per byte, first weight in high nibble.
|
|
10
|
+
*/
|
|
11
|
+
export function readWeightsDirect(data, offset, numWeights) {
|
|
12
|
+
const bytesNeeded = Math.ceil(numWeights / 2);
|
|
13
|
+
if (offset + bytesNeeded > data.length) {
|
|
14
|
+
throw new ZstdError('Huffman weights truncated', 'corruption_detected');
|
|
15
|
+
}
|
|
16
|
+
const weights = [];
|
|
17
|
+
for (let i = 0; i < numWeights; i++) {
|
|
18
|
+
const byteIdx = Math.floor(i / 2);
|
|
19
|
+
const byte = data[offset + byteIdx];
|
|
20
|
+
if (byte === undefined)
|
|
21
|
+
throw new ZstdError('Huffman weights truncated', 'corruption_detected');
|
|
22
|
+
const nibble = (i & 1) === 0 ? (byte >> 4) & 0xf : byte & 0xf;
|
|
23
|
+
weights.push(nibble);
|
|
24
|
+
}
|
|
25
|
+
return { weights, bytesRead: bytesNeeded };
|
|
26
|
+
}
|
|
27
|
+
const MAX_WEIGHT_SYMBOL = 11;
|
|
28
|
+
const MAX_WEIGHT_TABLE_LOG = 7;
|
|
29
|
+
/**
|
|
30
|
+
* Read Huffman weights from FSE-compressed stream.
|
|
31
|
+
* Uses 2 interleaved FSE states decoding weight symbols (0-11).
|
|
32
|
+
*/
|
|
33
|
+
export function readWeightsFSE(data, offset, compressedSize) {
|
|
34
|
+
if (compressedSize < 2) {
|
|
35
|
+
throw new ZstdError('FSE-compressed weights: need at least 2 bytes', 'corruption_detected');
|
|
36
|
+
}
|
|
37
|
+
if (offset + compressedSize > data.length) {
|
|
38
|
+
throw new ZstdError('FSE-compressed weights truncated', 'corruption_detected');
|
|
39
|
+
}
|
|
40
|
+
const header = data.subarray(offset, offset + compressedSize);
|
|
41
|
+
const { normalizedCounter, tableLog, bytesRead: ncountBytes, } = readNCount(header, 0, MAX_WEIGHT_SYMBOL, MAX_WEIGHT_TABLE_LOG);
|
|
42
|
+
const table = buildFSEDecodeTable(normalizedCounter, tableLog);
|
|
43
|
+
const streamStart = ncountBytes;
|
|
44
|
+
const streamLength = compressedSize - ncountBytes;
|
|
45
|
+
if (streamLength <= 0) {
|
|
46
|
+
throw new ZstdError('FSE-compressed weights: no stream after header', 'corruption_detected');
|
|
47
|
+
}
|
|
48
|
+
const stream = header.subarray(streamStart, streamStart + streamLength);
|
|
49
|
+
const lastByte = stream[stream.length - 1] ?? 0;
|
|
50
|
+
if (lastByte === 0) {
|
|
51
|
+
throw new ZstdError('FSE-compressed weights: invalid end marker', 'corruption_detected');
|
|
52
|
+
}
|
|
53
|
+
const highestSetBit = 31 - Math.clz32(lastByte);
|
|
54
|
+
const paddingBits = 8 - highestSetBit;
|
|
55
|
+
let bitOffset = streamLength * 8 - paddingBits;
|
|
56
|
+
const readBitsZeroExtended = (numBits) => {
|
|
57
|
+
if (numBits <= 0)
|
|
58
|
+
return 0;
|
|
59
|
+
bitOffset -= numBits;
|
|
60
|
+
let value = 0;
|
|
61
|
+
for (let i = 0; i < numBits; i++) {
|
|
62
|
+
const abs = bitOffset + i;
|
|
63
|
+
if (abs < 0)
|
|
64
|
+
continue;
|
|
65
|
+
const byteIndex = abs >>> 3;
|
|
66
|
+
const bitInByte = abs & 7;
|
|
67
|
+
const bit = ((stream[byteIndex] ?? 0) >>> bitInByte) & 1;
|
|
68
|
+
value |= bit << i;
|
|
69
|
+
}
|
|
70
|
+
return value;
|
|
71
|
+
};
|
|
72
|
+
const weights = [];
|
|
73
|
+
const state1 = { value: readBitsZeroExtended(tableLog) };
|
|
74
|
+
const state2 = { value: readBitsZeroExtended(tableLog) };
|
|
75
|
+
while (weights.length < 255) {
|
|
76
|
+
const row1 = table[state1.value];
|
|
77
|
+
if (!row1)
|
|
78
|
+
throw new ZstdError('FSE-compressed weights: invalid state', 'corruption_detected');
|
|
79
|
+
weights.push(row1.symbol);
|
|
80
|
+
state1.value = row1.baseline + readBitsZeroExtended(row1.numBits);
|
|
81
|
+
if (bitOffset < 0) {
|
|
82
|
+
const tail = table[state2.value];
|
|
83
|
+
if (!tail)
|
|
84
|
+
throw new ZstdError('FSE-compressed weights: invalid state', 'corruption_detected');
|
|
85
|
+
weights.push(tail.symbol);
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
if (weights.length >= 255)
|
|
89
|
+
break;
|
|
90
|
+
const row2 = table[state2.value];
|
|
91
|
+
if (!row2)
|
|
92
|
+
throw new ZstdError('FSE-compressed weights: invalid state', 'corruption_detected');
|
|
93
|
+
weights.push(row2.symbol);
|
|
94
|
+
state2.value = row2.baseline + readBitsZeroExtended(row2.numBits);
|
|
95
|
+
if (bitOffset < 0) {
|
|
96
|
+
const tail = table[state1.value];
|
|
97
|
+
if (!tail)
|
|
98
|
+
throw new ZstdError('FSE-compressed weights: invalid state', 'corruption_detected');
|
|
99
|
+
weights.push(tail.symbol);
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (weights.length < 2) {
|
|
104
|
+
throw new ZstdError('FSE-compressed weights: need at least 2 weights', 'corruption_detected');
|
|
105
|
+
}
|
|
106
|
+
return { weights, bytesRead: compressedSize };
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=weights.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"weights.js","sourceRoot":"","sources":["../../src/entropy/weights.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { readWeightsDirect, readWeightsFSE } from './weights.js';
|
|
3
|
+
describe('weights', () => {
|
|
4
|
+
describe('readWeightsDirect', () => {
|
|
5
|
+
it('throws when data is truncated', () => {
|
|
6
|
+
// numWeights=4 -> bytesNeeded=2; buffer length 1
|
|
7
|
+
expect(() => readWeightsDirect(new Uint8Array([0x00]), 0, 4)).toThrow(/Huffman weights truncated/i);
|
|
8
|
+
});
|
|
9
|
+
it('returns weights for valid direct input', () => {
|
|
10
|
+
// 2 weights in 1 byte: high nibble and low nibble
|
|
11
|
+
const { weights, bytesRead } = readWeightsDirect(new Uint8Array([0x12]), 0, 2);
|
|
12
|
+
expect(weights).toEqual([1, 2]);
|
|
13
|
+
expect(bytesRead).toBe(1);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
describe('readWeightsFSE', () => {
|
|
17
|
+
it('throws when compressed size < 2', () => {
|
|
18
|
+
expect(() => readWeightsFSE(new Uint8Array(10), 0, 1)).toThrow(/FSE-compressed weights: need at least 2 bytes/i);
|
|
19
|
+
});
|
|
20
|
+
it('throws when input is truncated', () => {
|
|
21
|
+
expect(() => readWeightsFSE(new Uint8Array([0x00, 0x00]), 0, 5)).toThrow(/FSE-compressed weights truncated/i);
|
|
22
|
+
});
|
|
23
|
+
it('throws when there is no stream after header', () => {
|
|
24
|
+
// From fse.test: [0x10, 0x3f, 0x01] gives readNCount bytesRead=2. Use compressedSize=2
|
|
25
|
+
// so streamLength = 2 - 2 = 0 (no stream bytes after header).
|
|
26
|
+
const buf = new Uint8Array([0x10, 0x3f]);
|
|
27
|
+
expect(() => readWeightsFSE(buf, 0, 2)).toThrow(/no stream after header/i);
|
|
28
|
+
});
|
|
29
|
+
it('throws when stream has invalid end marker (last byte zero)', () => {
|
|
30
|
+
// 3 bytes: 2-byte ncount header + 1 stream byte. If stream last byte is 0, invalid.
|
|
31
|
+
// We need readNCount to read exactly 2 bytes. Example from fse.test: [0x10, 0x3f, 0x01] gives bytesRead 2.
|
|
32
|
+
// So [0x10, 0x3f, 0x00] = 2 byte header + stream [0x00], lastByte=0 -> invalid end marker
|
|
33
|
+
const buf = new Uint8Array([0x10, 0x3f, 0x00]);
|
|
34
|
+
expect(() => readWeightsFSE(buf, 0, 3)).toThrow(/invalid end marker/i);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
//# sourceMappingURL=weights.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"weights.test.js","sourceRoot":"","sources":["../../src/entropy/weights.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEjE,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC;IACxB,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE,CAAC;QAClC,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE,CAAC;YACxC,iDAAiD;YACjD,MAAM,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,4BAA4B,CAAC,CAAC;QAAA,CACrG,CAAC,CAAC;QAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE,CAAC;YACjD,kDAAkD;YAClD,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,iBAAiB,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAC/E,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAChC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAAA,CAC3B,CAAC,CAAC;IAAA,CACJ,CAAC,CAAC;IAEH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE,CAAC;QAC/B,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE,CAAC;YAC1C,MAAM,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,gDAAgD,CAAC,CAAC;QAAA,CAClH,CAAC,CAAC;QAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE,CAAC;YACzC,MAAM,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,mCAAmC,CAAC,CAAC;QAAA,CAC/G,CAAC,CAAC;QAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE,CAAC;YACtD,uFAAuF;YACvF,8DAA8D;YAC9D,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;YACzC,MAAM,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;QAAA,CAC5E,CAAC,CAAC;QAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE,CAAC;YACrE,oFAAoF;YACpF,2GAA2G;YAC3G,0FAA0F;YAC1F,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;YAC/C,MAAM,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC;QAAA,CACxE,CAAC,CAAC;IAAA,CACJ,CAAC,CAAC;AAAA,CACJ,CAAC,CAAC"}
|
package/dist/errors.d.ts
ADDED
package/dist/errors.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic error type for zstd operations.
|
|
3
|
+
*/
|
|
4
|
+
export class ZstdError extends Error {
|
|
5
|
+
code;
|
|
6
|
+
constructor(message, code) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.name = 'ZstdError';
|
|
10
|
+
Object.setPrototypeOf(this, ZstdError.prototype);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,SAAU,SAAQ,KAAK;IAGhB,IAAI;IAFtB,YACE,OAAe,EACC,IAAY,EAC5B;QACA,KAAK,CAAC,OAAO,CAAC,CAAC;oBAFC,IAAI;QAGpB,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;QACxB,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAAA,CAClD;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { ZstdError } from './errors.js';
|
|
3
|
+
describe('ZstdError', () => {
|
|
4
|
+
it('has correct name, message, and code', () => {
|
|
5
|
+
const e = new ZstdError('test message', 'corruption_detected');
|
|
6
|
+
expect(e.name).toBe('ZstdError');
|
|
7
|
+
expect(e.message).toBe('test message');
|
|
8
|
+
expect(e.code).toBe('corruption_detected');
|
|
9
|
+
});
|
|
10
|
+
it('is instanceof Error and ZstdError', () => {
|
|
11
|
+
const e = new ZstdError('x', 'parameter_unsupported');
|
|
12
|
+
expect(e).toBeInstanceOf(Error);
|
|
13
|
+
expect(e).toBeInstanceOf(ZstdError);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
//# sourceMappingURL=errors.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.test.js","sourceRoot":"","sources":["../src/errors.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC;IAC1B,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE,CAAC;QAC9C,MAAM,CAAC,GAAG,IAAI,SAAS,CAAC,cAAc,EAAE,qBAAqB,CAAC,CAAC;QAC/D,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACjC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACvC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IAAA,CAC5C,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE,CAAC;QAC5C,MAAM,CAAC,GAAG,IAAI,SAAS,CAAC,GAAG,EAAE,uBAAuB,CAAC,CAAC;QACtD,MAAM,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;IAAA,CACrC,CAAC,CAAC;AAAA,CACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XXH64 checksum for zstd content validation.
|
|
3
|
+
* Pure TypeScript implementation, seed=0 for frame checksum.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Compute XXH64 hash of data with given seed.
|
|
7
|
+
* Returns full 64-bit hash as bigint.
|
|
8
|
+
*/
|
|
9
|
+
export declare function xxh64(data: Uint8Array, seed?: bigint): bigint;
|
|
10
|
+
/**
|
|
11
|
+
* Validate content checksum: low 4 bytes of XXH64(data, 0) must match stored.
|
|
12
|
+
*/
|
|
13
|
+
export declare function validateContentChecksum(data: Uint8Array, storedChecksum: number): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Compute the 32-bit frame content checksum (low 32 bits of XXH64).
|
|
16
|
+
*/
|
|
17
|
+
export declare function computeContentChecksum32(data: Uint8Array): number;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XXH64 checksum for zstd content validation.
|
|
3
|
+
* Pure TypeScript implementation, seed=0 for frame checksum.
|
|
4
|
+
*/
|
|
5
|
+
import { readU32LE, readU64LE } from '../bitstream/littleEndian.js';
|
|
6
|
+
const PRIME64_1 = 0x9e3779b185ebca87n;
|
|
7
|
+
const PRIME64_2 = 0xc2b2ae3d27d4eb4fn;
|
|
8
|
+
const PRIME64_3 = 0x165667b19e3779f9n;
|
|
9
|
+
const PRIME64_4 = 0x85ebca77c2b2ae63n;
|
|
10
|
+
const PRIME64_5 = 0x27d4eb2f165667c5n;
|
|
11
|
+
const MASK64 = 0xffffffffffffffffn;
|
|
12
|
+
function rotl64(x, r) {
|
|
13
|
+
r = r & 63;
|
|
14
|
+
return ((x << BigInt(r)) | (x >> BigInt(64 - r))) & MASK64;
|
|
15
|
+
}
|
|
16
|
+
function round64(acc, input) {
|
|
17
|
+
acc = (acc + input * PRIME64_2) & MASK64;
|
|
18
|
+
acc = rotl64(acc, 31);
|
|
19
|
+
return (acc * PRIME64_1) & MASK64;
|
|
20
|
+
}
|
|
21
|
+
function mergeRound64(acc, val) {
|
|
22
|
+
val = round64(0n, val);
|
|
23
|
+
acc ^= val;
|
|
24
|
+
acc = (acc * PRIME64_1 + PRIME64_4) & MASK64;
|
|
25
|
+
return acc;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Compute XXH64 hash of data with given seed.
|
|
29
|
+
* Returns full 64-bit hash as bigint.
|
|
30
|
+
*/
|
|
31
|
+
export function xxh64(data, seed = 0n) {
|
|
32
|
+
let acc;
|
|
33
|
+
const len = data.length;
|
|
34
|
+
let offset = 0;
|
|
35
|
+
if (len >= 32) {
|
|
36
|
+
let v1 = (seed + PRIME64_1 + PRIME64_2) & MASK64;
|
|
37
|
+
let v2 = (seed + PRIME64_2) & MASK64;
|
|
38
|
+
let v3 = seed & MASK64;
|
|
39
|
+
let v4 = (seed - PRIME64_1) & MASK64;
|
|
40
|
+
const limit = len - 32;
|
|
41
|
+
while (offset <= limit) {
|
|
42
|
+
v1 = round64(v1, readU64LE(data, offset));
|
|
43
|
+
v2 = round64(v2, readU64LE(data, offset + 8));
|
|
44
|
+
v3 = round64(v3, readU64LE(data, offset + 16));
|
|
45
|
+
v4 = round64(v4, readU64LE(data, offset + 24));
|
|
46
|
+
offset += 32;
|
|
47
|
+
}
|
|
48
|
+
acc = (rotl64(v1, 1) + rotl64(v2, 7) + rotl64(v3, 12) + rotl64(v4, 18)) & MASK64;
|
|
49
|
+
acc = mergeRound64(acc, v1);
|
|
50
|
+
acc = mergeRound64(acc, v2);
|
|
51
|
+
acc = mergeRound64(acc, v3);
|
|
52
|
+
acc = mergeRound64(acc, v4);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
acc = (seed + PRIME64_5) & MASK64;
|
|
56
|
+
}
|
|
57
|
+
acc = (acc + BigInt(len)) & MASK64;
|
|
58
|
+
while (offset + 8 <= len) {
|
|
59
|
+
acc ^= round64(0n, readU64LE(data, offset));
|
|
60
|
+
acc = rotl64(acc, 27) * PRIME64_1 + PRIME64_4;
|
|
61
|
+
acc &= MASK64;
|
|
62
|
+
offset += 8;
|
|
63
|
+
}
|
|
64
|
+
if (offset + 4 <= len) {
|
|
65
|
+
acc ^= (BigInt(readU32LE(data, offset)) * PRIME64_1) & 0xffffffffffffffffn;
|
|
66
|
+
acc = (rotl64(acc, 23) * PRIME64_2 + PRIME64_3) & MASK64;
|
|
67
|
+
offset += 4;
|
|
68
|
+
}
|
|
69
|
+
while (offset < len) {
|
|
70
|
+
acc ^= (BigInt(data[offset] ?? 0) * PRIME64_5) & MASK64;
|
|
71
|
+
acc = (rotl64(acc, 11) * PRIME64_1) & MASK64;
|
|
72
|
+
offset++;
|
|
73
|
+
}
|
|
74
|
+
acc ^= acc >> 33n;
|
|
75
|
+
acc = (acc * PRIME64_2) & MASK64;
|
|
76
|
+
acc ^= acc >> 29n;
|
|
77
|
+
acc = (acc * PRIME64_3) & MASK64;
|
|
78
|
+
acc ^= acc >> 32n;
|
|
79
|
+
return acc & MASK64;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Validate content checksum: low 4 bytes of XXH64(data, 0) must match stored.
|
|
83
|
+
*/
|
|
84
|
+
export function validateContentChecksum(data, storedChecksum) {
|
|
85
|
+
return computeContentChecksum32(data) === storedChecksum >>> 0;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Compute the 32-bit frame content checksum (low 32 bits of XXH64).
|
|
89
|
+
*/
|
|
90
|
+
export function computeContentChecksum32(data) {
|
|
91
|
+
const hash = xxh64(data, 0n);
|
|
92
|
+
return Number(hash & 0xffffffffn) >>> 0;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=checksum.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checksum.js","sourceRoot":"","sources":["../../src/frame/checksum.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { computeContentChecksum32, validateContentChecksum, xxh64 } from './checksum.js';
|
|
3
|
+
describe('xxh64', () => {
|
|
4
|
+
it('hashes empty input', () => {
|
|
5
|
+
const h = xxh64(new Uint8Array(0));
|
|
6
|
+
expect(typeof h).toBe('bigint');
|
|
7
|
+
expect(h).toBeGreaterThanOrEqual(0n);
|
|
8
|
+
});
|
|
9
|
+
it('hashes consistently', () => {
|
|
10
|
+
const data = new TextEncoder().encode('hello');
|
|
11
|
+
const h1 = xxh64(data);
|
|
12
|
+
const h2 = xxh64(data);
|
|
13
|
+
expect(h1).toBe(h2);
|
|
14
|
+
expect(typeof h1).toBe('bigint');
|
|
15
|
+
});
|
|
16
|
+
it('validateContentChecksum matches low 32 bits', () => {
|
|
17
|
+
const data = new TextEncoder().encode('test');
|
|
18
|
+
const hash = xxh64(data);
|
|
19
|
+
const low32 = Number(hash & 0xffffffffn);
|
|
20
|
+
expect(validateContentChecksum(data, low32)).toBe(true);
|
|
21
|
+
expect(validateContentChecksum(data, low32 + 1)).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
it('matches zstd checksum vector', () => {
|
|
24
|
+
const data = new TextEncoder().encode('checksum interoperability payload');
|
|
25
|
+
expect(computeContentChecksum32(data)).toBe(0x1be3054d);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
//# sourceMappingURL=checksum.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checksum.test.js","sourceRoot":"","sources":["../../src/frame/checksum.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEzF,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC;IACtB,EAAE,CAAC,oBAAoB,EAAE,GAAG,EAAE,CAAC;QAC7B,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChC,MAAM,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC;IAAA,CACtC,CAAC,CAAC;IAEH,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC/C,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QACvB,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QACvB,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACpB,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAAA,CAClC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE,CAAC;QACtD,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC9C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QACzB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,GAAG,WAAW,CAAC,CAAC;QACzC,MAAM,CAAC,uBAAuB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxD,MAAM,CAAC,uBAAuB,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAAA,CAC9D,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,mCAAmC,CAAC,CAAC;QAC3E,MAAM,CAAC,wBAAwB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAAA,CACzD,CAAC,CAAC;AAAA,CACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zstandard frame header parser.
|
|
3
|
+
* Parses magic, frame descriptor, window descriptor, content size.
|
|
4
|
+
*/
|
|
5
|
+
export declare const ZSTD_MAGIC = 4247762216;
|
|
6
|
+
export declare const ZSTD_FRAMEHEADER_SIZE_MIN = 2;
|
|
7
|
+
export declare const ZSTD_FRAMEHEADER_SIZE_MAX = 14;
|
|
8
|
+
export interface FrameHeader {
|
|
9
|
+
/** Total header size in bytes */
|
|
10
|
+
headerSize: number;
|
|
11
|
+
/** Window size (minimum buffer for decompression) */
|
|
12
|
+
windowSize: number;
|
|
13
|
+
/** Decompressed content size, or null if unknown */
|
|
14
|
+
contentSize: number | null;
|
|
15
|
+
/** Whether content checksum is present at end of frame */
|
|
16
|
+
hasContentChecksum: boolean;
|
|
17
|
+
/** Dictionary ID if present, else null */
|
|
18
|
+
dictionaryId: number | null;
|
|
19
|
+
/** Single segment mode (no window descriptor) */
|
|
20
|
+
singleSegment: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare function parseFrameHeader(data: Uint8Array, offset: number): FrameHeader;
|
|
23
|
+
export declare function parseZstdFrame(data: Uint8Array, offset: number): {
|
|
24
|
+
magic: number;
|
|
25
|
+
header: FrameHeader;
|
|
26
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zstandard frame header parser.
|
|
3
|
+
* Parses magic, frame descriptor, window descriptor, content size.
|
|
4
|
+
*/
|
|
5
|
+
import { readU32LE } from '../bitstream/littleEndian.js';
|
|
6
|
+
import { ZstdError } from '../errors.js';
|
|
7
|
+
export const ZSTD_MAGIC = 0xfd2fb528;
|
|
8
|
+
export const ZSTD_FRAMEHEADER_SIZE_MIN = 2;
|
|
9
|
+
export const ZSTD_FRAMEHEADER_SIZE_MAX = 14;
|
|
10
|
+
export function parseFrameHeader(data, offset) {
|
|
11
|
+
if (offset + 2 > data.length) {
|
|
12
|
+
throw new ZstdError('Frame header truncated', 'corruption_detected');
|
|
13
|
+
}
|
|
14
|
+
const fhd = data[offset];
|
|
15
|
+
offset++;
|
|
16
|
+
const frameContentSizeFlag = (fhd >> 6) & 3;
|
|
17
|
+
const singleSegment = ((fhd >> 5) & 1) === 1;
|
|
18
|
+
const contentChecksumFlag = ((fhd >> 2) & 1) === 1;
|
|
19
|
+
const dictionaryIdFlag = fhd & 3;
|
|
20
|
+
if ((fhd & 0x10) !== 0) {
|
|
21
|
+
throw new ZstdError('Unused bit set in frame header', 'corruption_detected');
|
|
22
|
+
}
|
|
23
|
+
if ((fhd & 0x08) !== 0) {
|
|
24
|
+
throw new ZstdError('Reserved bit set in frame header', 'corruption_detected');
|
|
25
|
+
}
|
|
26
|
+
let windowSize = 0; // set below: from window descriptor (non-single) or from content size (single)
|
|
27
|
+
let contentSize = null;
|
|
28
|
+
let headerSize = 1;
|
|
29
|
+
// Order per spec: Frame_Header_Descriptor | [Window_Descriptor] | [Dictionary_ID] | [Frame_Content_Size]
|
|
30
|
+
if (singleSegment) {
|
|
31
|
+
// No Window_Descriptor; next is Dictionary_ID then Frame_Content_Size; windowSize set from FCS below
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
if (offset + 1 > data.length) {
|
|
35
|
+
throw new ZstdError('Frame header truncated (window descriptor)', 'corruption_detected');
|
|
36
|
+
}
|
|
37
|
+
const wd = data[offset];
|
|
38
|
+
offset++;
|
|
39
|
+
headerSize++;
|
|
40
|
+
const exponent = (wd >> 3) & 0x1f;
|
|
41
|
+
const mantissa = wd & 7;
|
|
42
|
+
const windowLog = 10 + exponent;
|
|
43
|
+
const windowBase = 1 << windowLog;
|
|
44
|
+
const windowAdd = (windowBase / 8) * mantissa;
|
|
45
|
+
windowSize = windowBase + windowAdd;
|
|
46
|
+
}
|
|
47
|
+
// Dictionary_ID (before Frame_Content_Size per spec)
|
|
48
|
+
let dictionaryId = null;
|
|
49
|
+
const didFieldSize = [0, 1, 2, 4][dictionaryIdFlag];
|
|
50
|
+
if (didFieldSize > 0) {
|
|
51
|
+
if (offset + didFieldSize > data.length) {
|
|
52
|
+
throw new ZstdError('Frame header truncated (dictionary ID)', 'corruption_detected');
|
|
53
|
+
}
|
|
54
|
+
let did = 0;
|
|
55
|
+
if (didFieldSize === 1)
|
|
56
|
+
did = data[offset];
|
|
57
|
+
else if (didFieldSize === 2)
|
|
58
|
+
did = data[offset] | (data[offset + 1] << 8);
|
|
59
|
+
else
|
|
60
|
+
did = readU32LE(data, offset);
|
|
61
|
+
dictionaryId = did !== 0 ? did : null;
|
|
62
|
+
offset += didFieldSize;
|
|
63
|
+
headerSize += didFieldSize;
|
|
64
|
+
}
|
|
65
|
+
// Frame_Content_Size
|
|
66
|
+
const fcsFieldSize = frameContentSizeFlag === 0
|
|
67
|
+
? singleSegment
|
|
68
|
+
? 1
|
|
69
|
+
: 0
|
|
70
|
+
: frameContentSizeFlag === 1
|
|
71
|
+
? 2
|
|
72
|
+
: frameContentSizeFlag === 2
|
|
73
|
+
? 4
|
|
74
|
+
: 8;
|
|
75
|
+
if (fcsFieldSize > 0) {
|
|
76
|
+
if (offset + fcsFieldSize > data.length) {
|
|
77
|
+
throw new ZstdError('Frame header truncated (content size)', 'corruption_detected');
|
|
78
|
+
}
|
|
79
|
+
contentSize = readFrameContentSize(data, offset, fcsFieldSize);
|
|
80
|
+
offset += fcsFieldSize;
|
|
81
|
+
headerSize += fcsFieldSize;
|
|
82
|
+
if (singleSegment) {
|
|
83
|
+
windowSize = contentSize;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
headerSize,
|
|
88
|
+
windowSize,
|
|
89
|
+
contentSize,
|
|
90
|
+
hasContentChecksum: contentChecksumFlag,
|
|
91
|
+
dictionaryId: dictionaryId !== 0 ? dictionaryId : null,
|
|
92
|
+
singleSegment,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function readFrameContentSize(data, offset, size) {
|
|
96
|
+
if (size === 1) {
|
|
97
|
+
return data[offset];
|
|
98
|
+
}
|
|
99
|
+
if (size === 2) {
|
|
100
|
+
return 256 + (data[offset] | (data[offset + 1] << 8));
|
|
101
|
+
}
|
|
102
|
+
if (size === 4) {
|
|
103
|
+
return readU32LE(data, offset);
|
|
104
|
+
}
|
|
105
|
+
if (size === 8) {
|
|
106
|
+
const lo = readU32LE(data, offset);
|
|
107
|
+
const hi = readU32LE(data, offset + 4);
|
|
108
|
+
const v = lo + hi * 0x1_0000_0000;
|
|
109
|
+
if (v > Number.MAX_SAFE_INTEGER) {
|
|
110
|
+
throw new ZstdError('Content size exceeds safe integer range', 'parameter_unsupported');
|
|
111
|
+
}
|
|
112
|
+
return v;
|
|
113
|
+
}
|
|
114
|
+
throw new ZstdError(`Invalid FCS field size: ${size}`, 'corruption_detected');
|
|
115
|
+
}
|
|
116
|
+
export function parseZstdFrame(data, offset) {
|
|
117
|
+
if (offset + 4 > data.length) {
|
|
118
|
+
throw new ZstdError('Input too short for magic number', 'corruption_detected');
|
|
119
|
+
}
|
|
120
|
+
const magic = readU32LE(data, offset);
|
|
121
|
+
if (magic !== ZSTD_MAGIC) {
|
|
122
|
+
throw new ZstdError(`Invalid zstd magic: 0x${magic.toString(16)}`, 'corruption_detected');
|
|
123
|
+
}
|
|
124
|
+
const header = parseFrameHeader(data, offset + 4);
|
|
125
|
+
return { magic, header };
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=frameHeader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frameHeader.js","sourceRoot":"","sources":["../../src/frame/frameHeader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|