@sythos/js_barcode_universal 1.5.7 → 1.5.9
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 +5 -4
- package/NOTICE.md +2 -2
- package/README.md +50 -37
- package/bundle/sythos-barcode.esm.js +12051 -11484
- package/bundle/sythos-barcode.js +12051 -11484
- package/package.json +52 -45
- package/src/index.d.ts +363 -0
- package/src/index.js +573 -428
- package/src/js/aztec/decoder.js +326 -0
- package/src/js/aztec/detector.js +251 -0
- package/src/js/aztec/encoder.js +276 -0
- package/src/js/aztec/high-level.js +216 -0
- package/src/js/aztec/index.js +34 -0
- package/src/js/aztec/tables.js +196 -0
- package/src/js/aztecrune/decoder.js +146 -0
- package/src/js/aztecrune/detector.js +180 -0
- package/src/js/aztecrune/encoder.js +103 -0
- package/src/js/aztecrune/index.js +34 -0
- package/src/js/aztecrune/tables.js +142 -0
- package/src/js/compactpdf417/decoder.js +123 -0
- package/src/js/compactpdf417/detector.js +138 -0
- package/src/js/compactpdf417/encoder.js +127 -0
- package/src/js/compactpdf417/index.js +5 -0
- package/src/js/compactpdf417/tables.js +164 -0
- package/src/js/core/bit-buffer.js +158 -0
- package/src/js/core/bit-matrix.js +243 -0
- package/src/js/core/errors.js +59 -0
- package/src/js/core/galois-field.js +193 -0
- package/src/js/core/index.js +39 -0
- package/src/js/core/reed-solomon.js +318 -0
- package/src/js/databar/codec.js +166 -0
- package/src/js/databar/decoder.js +224 -0
- package/src/js/databar/encoder.js +88 -0
- package/src/js/databar/gs1.js +176 -0
- package/src/js/databar/index.js +36 -0
- package/src/js/databar/patterns.js +139 -0
- package/src/js/databar/tables.js +123 -0
- package/src/js/datamatrix/decoder.js +296 -0
- package/src/js/datamatrix/detector.js +254 -0
- package/src/js/datamatrix/encoder.js +250 -0
- package/src/js/datamatrix/index.js +34 -0
- package/src/js/datamatrix/tables.js +122 -0
- package/src/js/frameqr/decoder.js +216 -0
- package/src/js/frameqr/detector.js +199 -0
- package/src/js/frameqr/encoder.js +143 -0
- package/src/js/frameqr/index.js +33 -0
- package/src/js/frameqr/tables.js +252 -0
- package/src/js/image/binarizer.js +254 -0
- package/src/js/image/grid-sampler.js +148 -0
- package/src/js/image/index.js +38 -0
- package/src/js/image/luminance.js +185 -0
- package/src/js/image/perspective.js +158 -0
- package/src/js/micropdf417/compaction.js +115 -0
- package/src/js/micropdf417/decoder.js +180 -0
- package/src/js/micropdf417/detector.js +152 -0
- package/src/js/micropdf417/encoder.js +184 -0
- package/src/js/micropdf417/error-correction.js +50 -0
- package/src/js/micropdf417/index.js +35 -0
- package/src/js/micropdf417/tables.js +197 -0
- package/src/js/microqr/decoder.js +240 -0
- package/src/js/microqr/detector.js +339 -0
- package/src/js/microqr/encoder.js +314 -0
- package/src/js/microqr/index.js +34 -0
- package/src/js/microqr/tables.js +324 -0
- package/src/js/oned/addons.js +396 -0
- package/src/js/oned/index.js +75 -0
- package/src/js/oned/patterns.js +365 -0
- package/src/js/oned/reader.js +1383 -0
- package/src/js/oned/writers.js +691 -0
- package/src/js/pdf417/compaction.js +391 -0
- package/src/js/pdf417/decoder.js +110 -0
- package/src/js/pdf417/detector.js +484 -0
- package/src/js/pdf417/encoder.js +102 -0
- package/src/js/pdf417/error-correction.js +44 -0
- package/src/{pdf417 → js/pdf417}/index.js +0 -5
- package/src/js/pdf417/tables.js +315 -0
- package/src/js/qr/decoder.js +539 -0
- package/src/js/qr/detector.js +613 -0
- package/src/js/qr/encoder.js +873 -0
- package/src/js/qr/index.js +42 -0
- package/src/js/qr/tables.js +690 -0
- package/src/js/render/image-data.js +120 -0
- package/src/js/render/index.js +128 -0
- package/src/js/render/options.js +152 -0
- package/src/js/render/png.js +270 -0
- package/src/js/render/svg.js +117 -0
- package/src/js/render/webgl.js +200 -0
- package/src/js/render/webgpu.js +357 -0
- package/src/js/rmqr/decoder.js +209 -0
- package/src/js/rmqr/detector.js +122 -0
- package/src/js/rmqr/encoder.js +321 -0
- package/src/js/rmqr/index.js +33 -0
- package/src/js/rmqr/tables.js +177 -0
- package/src/{aztec/decoder.js → ts/aztec/decoder.ts} +0 -1
- package/{typings → src/ts}/aztec/detector.d.ts +2 -2
- package/src/{aztec/detector.js → ts/aztec/detector.ts} +0 -1
- package/src/{aztec/encoder.js → ts/aztec/encoder.ts} +0 -1
- package/src/{aztec/high-level.js → ts/aztec/high-level.ts} +0 -1
- package/src/{aztec/index.js → ts/aztec/index.ts} +0 -1
- package/src/{aztec/tables.js → ts/aztec/tables.ts} +0 -1
- package/src/{aztecrune/decoder.js → ts/aztecrune/decoder.ts} +0 -1
- package/src/{aztecrune/detector.js → ts/aztecrune/detector.ts} +0 -1
- package/src/{aztecrune/encoder.js → ts/aztecrune/encoder.ts} +0 -1
- package/src/{aztecrune/index.js → ts/aztecrune/index.ts} +0 -1
- package/src/{aztecrune/tables.js → ts/aztecrune/tables.ts} +0 -1
- package/src/{compactpdf417/decoder.js → ts/compactpdf417/decoder.ts} +0 -1
- package/src/{compactpdf417/detector.js → ts/compactpdf417/detector.ts} +0 -1
- package/src/{compactpdf417/encoder.js → ts/compactpdf417/encoder.ts} +0 -1
- package/src/{compactpdf417/index.js → ts/compactpdf417/index.ts} +0 -5
- package/src/{compactpdf417/tables.js → ts/compactpdf417/tables.ts} +0 -1
- package/src/{core/bit-buffer.js → ts/core/bit-buffer.ts} +0 -1
- package/src/{core/bit-matrix.js → ts/core/bit-matrix.ts} +0 -1
- package/src/{core/errors.js → ts/core/errors.ts} +0 -1
- package/src/{core/galois-field.js → ts/core/galois-field.ts} +0 -1
- package/src/{core/index.js → ts/core/index.ts} +0 -1
- package/src/{core/reed-solomon.js → ts/core/reed-solomon.ts} +0 -1
- package/src/{databar/codec.js → ts/databar/codec.ts} +0 -1
- package/src/{databar/decoder.js → ts/databar/decoder.ts} +0 -1
- package/src/{databar/encoder.js → ts/databar/encoder.ts} +0 -1
- package/src/{databar/gs1.js → ts/databar/gs1.ts} +0 -1
- package/src/{databar/index.js → ts/databar/index.ts} +0 -1
- package/src/{databar/patterns.js → ts/databar/patterns.ts} +0 -1
- package/src/{databar/tables.js → ts/databar/tables.ts} +0 -1
- package/src/{datamatrix/decoder.js → ts/datamatrix/decoder.ts} +0 -1
- package/{typings → src/ts}/datamatrix/detector.d.ts +2 -2
- package/src/{datamatrix/detector.js → ts/datamatrix/detector.ts} +0 -1
- package/src/{datamatrix/encoder.js → ts/datamatrix/encoder.ts} +0 -1
- package/src/{datamatrix/index.js → ts/datamatrix/index.ts} +0 -1
- package/src/{datamatrix/tables.js → ts/datamatrix/tables.ts} +0 -1
- package/src/{frameqr/decoder.js → ts/frameqr/decoder.ts} +15 -16
- package/src/{frameqr/detector.js → ts/frameqr/detector.ts} +2 -3
- package/src/{frameqr/encoder.js → ts/frameqr/encoder.ts} +7 -8
- package/src/{frameqr/index.js → ts/frameqr/index.ts} +0 -1
- package/src/{frameqr/tables.js → ts/frameqr/tables.ts} +10 -11
- package/src/{image/binarizer.js → ts/image/binarizer.ts} +0 -1
- package/src/{image/grid-sampler.js → ts/image/grid-sampler.ts} +0 -1
- package/src/{image/index.js → ts/image/index.ts} +0 -1
- package/src/{image/luminance.js → ts/image/luminance.ts} +0 -1
- package/src/{image/perspective.js → ts/image/perspective.ts} +0 -1
- package/{typings → src/ts}/index.d.ts +3 -3
- package/src/ts/index.ts +790 -0
- package/src/{micropdf417/compaction.js → ts/micropdf417/compaction.ts} +0 -1
- package/src/{micropdf417/decoder.js → ts/micropdf417/decoder.ts} +0 -1
- package/src/{micropdf417/detector.js → ts/micropdf417/detector.ts} +0 -1
- package/src/{micropdf417/encoder.js → ts/micropdf417/encoder.ts} +0 -1
- package/src/{micropdf417/error-correction.js → ts/micropdf417/error-correction.ts} +0 -1
- package/src/{micropdf417/index.js → ts/micropdf417/index.ts} +0 -1
- package/src/{micropdf417/tables.js → ts/micropdf417/tables.ts} +0 -1
- package/src/{microqr/decoder.js → ts/microqr/decoder.ts} +0 -1
- package/src/{microqr/detector.js → ts/microqr/detector.ts} +0 -1
- package/src/{microqr/encoder.js → ts/microqr/encoder.ts} +0 -1
- package/src/{microqr/index.js → ts/microqr/index.ts} +0 -1
- package/src/{microqr/tables.js → ts/microqr/tables.ts} +0 -1
- package/src/{oned/addons.js → ts/oned/addons.ts} +0 -1
- package/src/{oned/index.js → ts/oned/index.ts} +0 -1
- package/src/{oned/patterns.js → ts/oned/patterns.ts} +0 -1
- package/src/{oned/reader.js → ts/oned/reader.ts} +0 -1
- package/src/{oned/writers.js → ts/oned/writers.ts} +0 -1
- package/src/{pdf417/compaction.js → ts/pdf417/compaction.ts} +0 -1
- package/src/{pdf417/decoder.js → ts/pdf417/decoder.ts} +0 -1
- package/src/{pdf417/detector.js → ts/pdf417/detector.ts} +0 -1
- package/src/{pdf417/encoder.js → ts/pdf417/encoder.ts} +0 -1
- package/src/{pdf417/error-correction.js → ts/pdf417/error-correction.ts} +0 -1
- package/src/ts/pdf417/index.ts +6 -0
- package/src/{pdf417/tables.js → ts/pdf417/tables.ts} +0 -1
- package/src/{qr/decoder.js → ts/qr/decoder.ts} +0 -1
- package/src/{qr/detector.js → ts/qr/detector.ts} +0 -1
- package/src/{qr/encoder.js → ts/qr/encoder.ts} +0 -1
- package/src/{qr/index.js → ts/qr/index.ts} +0 -1
- package/src/{qr/tables.js → ts/qr/tables.ts} +0 -1
- package/src/{render/image-data.js → ts/render/image-data.ts} +0 -1
- package/src/{render/index.js → ts/render/index.ts} +0 -1
- package/src/{render/options.js → ts/render/options.ts} +0 -1
- package/src/{render/png.js → ts/render/png.ts} +0 -1
- package/src/{render/svg.js → ts/render/svg.ts} +0 -1
- package/src/{render/webgl.js → ts/render/webgl.ts} +0 -1
- package/src/{render/webgpu.js → ts/render/webgpu.ts} +0 -1
- package/src/{rmqr/decoder.js → ts/rmqr/decoder.ts} +0 -1
- package/src/{rmqr/detector.js → ts/rmqr/detector.ts} +0 -1
- package/src/{rmqr/encoder.js → ts/rmqr/encoder.ts} +0 -1
- package/src/{rmqr/index.js → ts/rmqr/index.ts} +0 -1
- package/src/{rmqr/tables.js → ts/rmqr/tables.ts} +0 -1
- /package/{typings → src/ts}/aztec/decoder.d.ts +0 -0
- /package/{typings → src/ts}/aztec/encoder.d.ts +0 -0
- /package/{typings → src/ts}/aztec/high-level.d.ts +0 -0
- /package/{typings → src/ts}/aztec/index.d.ts +0 -0
- /package/{typings → src/ts}/aztec/tables.d.ts +0 -0
- /package/{typings → src/ts}/aztecrune/decoder.d.ts +0 -0
- /package/{typings → src/ts}/aztecrune/detector.d.ts +0 -0
- /package/{typings → src/ts}/aztecrune/encoder.d.ts +0 -0
- /package/{typings → src/ts}/aztecrune/index.d.ts +0 -0
- /package/{typings → src/ts}/aztecrune/tables.d.ts +0 -0
- /package/{typings → src/ts}/bundle/sythos-barcode.d.ts +0 -0
- /package/{typings → src/ts}/bundle/sythos-barcode.esm.d.ts +0 -0
- /package/{typings → src/ts}/compactpdf417/decoder.d.ts +0 -0
- /package/{typings → src/ts}/compactpdf417/detector.d.ts +0 -0
- /package/{typings → src/ts}/compactpdf417/encoder.d.ts +0 -0
- /package/{typings → src/ts}/compactpdf417/index.d.ts +0 -0
- /package/{typings → src/ts}/compactpdf417/tables.d.ts +0 -0
- /package/{typings → src/ts}/core/bit-buffer.d.ts +0 -0
- /package/{typings → src/ts}/core/bit-matrix.d.ts +0 -0
- /package/{typings → src/ts}/core/errors.d.ts +0 -0
- /package/{typings → src/ts}/core/galois-field.d.ts +0 -0
- /package/{typings → src/ts}/core/index.d.ts +0 -0
- /package/{typings → src/ts}/core/reed-solomon.d.ts +0 -0
- /package/{typings → src/ts}/databar/codec.d.ts +0 -0
- /package/{typings → src/ts}/databar/decoder.d.ts +0 -0
- /package/{typings → src/ts}/databar/encoder.d.ts +0 -0
- /package/{typings → src/ts}/databar/gs1.d.ts +0 -0
- /package/{typings → src/ts}/databar/index.d.ts +0 -0
- /package/{typings → src/ts}/databar/patterns.d.ts +0 -0
- /package/{typings → src/ts}/databar/tables.d.ts +0 -0
- /package/{typings → src/ts}/datamatrix/decoder.d.ts +0 -0
- /package/{typings → src/ts}/datamatrix/encoder.d.ts +0 -0
- /package/{typings → src/ts}/datamatrix/index.d.ts +0 -0
- /package/{typings → src/ts}/datamatrix/tables.d.ts +0 -0
- /package/{typings → src/ts}/frameqr/decoder.d.ts +0 -0
- /package/{typings → src/ts}/frameqr/detector.d.ts +0 -0
- /package/{typings → src/ts}/frameqr/encoder.d.ts +0 -0
- /package/{typings → src/ts}/frameqr/index.d.ts +0 -0
- /package/{typings → src/ts}/frameqr/tables.d.ts +0 -0
- /package/{typings → src/ts}/image/binarizer.d.ts +0 -0
- /package/{typings → src/ts}/image/grid-sampler.d.ts +0 -0
- /package/{typings → src/ts}/image/index.d.ts +0 -0
- /package/{typings → src/ts}/image/luminance.d.ts +0 -0
- /package/{typings → src/ts}/image/perspective.d.ts +0 -0
- /package/{typings → src/ts}/micropdf417/compaction.d.ts +0 -0
- /package/{typings → src/ts}/micropdf417/decoder.d.ts +0 -0
- /package/{typings → src/ts}/micropdf417/detector.d.ts +0 -0
- /package/{typings → src/ts}/micropdf417/encoder.d.ts +0 -0
- /package/{typings → src/ts}/micropdf417/error-correction.d.ts +0 -0
- /package/{typings → src/ts}/micropdf417/index.d.ts +0 -0
- /package/{typings → src/ts}/micropdf417/tables.d.ts +0 -0
- /package/{typings → src/ts}/microqr/decoder.d.ts +0 -0
- /package/{typings → src/ts}/microqr/detector.d.ts +0 -0
- /package/{typings → src/ts}/microqr/encoder.d.ts +0 -0
- /package/{typings → src/ts}/microqr/index.d.ts +0 -0
- /package/{typings → src/ts}/microqr/tables.d.ts +0 -0
- /package/{typings → src/ts}/oned/addons.d.ts +0 -0
- /package/{typings → src/ts}/oned/index.d.ts +0 -0
- /package/{typings → src/ts}/oned/patterns.d.ts +0 -0
- /package/{typings → src/ts}/oned/reader.d.ts +0 -0
- /package/{typings → src/ts}/oned/writers.d.ts +0 -0
- /package/{typings → src/ts}/pdf417/compaction.d.ts +0 -0
- /package/{typings → src/ts}/pdf417/decoder.d.ts +0 -0
- /package/{typings → src/ts}/pdf417/detector.d.ts +0 -0
- /package/{typings → src/ts}/pdf417/encoder.d.ts +0 -0
- /package/{typings → src/ts}/pdf417/error-correction.d.ts +0 -0
- /package/{typings → src/ts}/pdf417/index.d.ts +0 -0
- /package/{typings → src/ts}/pdf417/tables.d.ts +0 -0
- /package/{typings → src/ts}/qr/decoder.d.ts +0 -0
- /package/{typings → src/ts}/qr/detector.d.ts +0 -0
- /package/{typings → src/ts}/qr/encoder.d.ts +0 -0
- /package/{typings → src/ts}/qr/index.d.ts +0 -0
- /package/{typings → src/ts}/qr/tables.d.ts +0 -0
- /package/{typings → src/ts}/render/image-data.d.ts +0 -0
- /package/{typings → src/ts}/render/index.d.ts +0 -0
- /package/{typings → src/ts}/render/options.d.ts +0 -0
- /package/{typings → src/ts}/render/png.d.ts +0 -0
- /package/{typings → src/ts}/render/svg.d.ts +0 -0
- /package/{typings → src/ts}/render/webgl.d.ts +0 -0
- /package/{typings → src/ts}/render/webgpu.d.ts +0 -0
- /package/{typings → src/ts}/rmqr/decoder.d.ts +0 -0
- /package/{typings → src/ts}/rmqr/detector.d.ts +0 -0
- /package/{typings → src/ts}/rmqr/encoder.d.ts +0 -0
- /package/{typings → src/ts}/rmqr/index.d.ts +0 -0
- /package/{typings → src/ts}/rmqr/tables.d.ts +0 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Sythos Barcode Suite
|
|
3
|
+
*
|
|
4
|
+
* MIT License
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2026 Sythos
|
|
7
|
+
*
|
|
8
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
10
|
+
* in the Software without restriction, including without limitation the rights
|
|
11
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
12
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
13
|
+
* furnished to do so, subject to the following conditions:
|
|
14
|
+
*
|
|
15
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
16
|
+
* copies or substantial portions of the Software.
|
|
17
|
+
*
|
|
18
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
21
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
22
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
23
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
|
+
* SOFTWARE.
|
|
25
|
+
*
|
|
26
|
+
* SPDX-License-Identifier: MIT
|
|
27
|
+
*
|
|
28
|
+
* Original work. No code from any other barcode implementation.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Finite field arithmetic.
|
|
32
|
+
*
|
|
33
|
+
* One class serves every field this suite needs:
|
|
34
|
+
*
|
|
35
|
+
* GF(2^4) Aztec, small layer counts
|
|
36
|
+
* GF(2^6) Aztec
|
|
37
|
+
* GF(2^8) QR Code, Data Matrix, Aztec
|
|
38
|
+
* GF(2^10) Aztec
|
|
39
|
+
* GF(2^12) Aztec
|
|
40
|
+
* GF(929) PDF417 <- a PRIME field, not a binary one
|
|
41
|
+
*
|
|
42
|
+
* ## The prime-field trap
|
|
43
|
+
*
|
|
44
|
+
* Multiplication unifies cleanly: exp/log tables work for the multiplicative
|
|
45
|
+
* group of any finite field. Addition does NOT.
|
|
46
|
+
*
|
|
47
|
+
* binary GF(2^m): a + b == a - b == a XOR b (self-inverse)
|
|
48
|
+
* prime GF(p): a + b == (a+b) % p
|
|
49
|
+
* a - b == (a-b+p) % p (NOT self-inverse)
|
|
50
|
+
*
|
|
51
|
+
* So `add`, `sub` and `neg` are methods on the field, never inlined. Any code
|
|
52
|
+
* that writes a bare `^` for field arithmetic works perfectly for every binary
|
|
53
|
+
* field and silently corrupts PDF417 — the failure is invisible until a real
|
|
54
|
+
* scanner rejects the symbol. Route every operation through the field object.
|
|
55
|
+
*
|
|
56
|
+
* @module core/galois-field
|
|
57
|
+
*/
|
|
58
|
+
export class GaloisField {
|
|
59
|
+
/**
|
|
60
|
+
* @param {object} opts
|
|
61
|
+
* @param {number} opts.size Field order: 2^m for binary, p for prime.
|
|
62
|
+
* @param {boolean} [opts.prime] True for a prime field (mod arithmetic).
|
|
63
|
+
* @param {number} [opts.primitive] Primitive polynomial, binary fields only.
|
|
64
|
+
* @param {number} [opts.generator] Multiplicative generator. Defaults to 2
|
|
65
|
+
* for binary fields (x), and must be given explicitly for prime fields.
|
|
66
|
+
* @param {string} [opts.name]
|
|
67
|
+
*/
|
|
68
|
+
constructor({ size, prime = false, primitive = 0, generator = 2, name = '' }) {
|
|
69
|
+
this.size = size;
|
|
70
|
+
this.prime = prime;
|
|
71
|
+
this.primitive = primitive;
|
|
72
|
+
this.generator = generator;
|
|
73
|
+
this.name = name || (prime ? `GF(${size})` : `GF(2^${Math.log2(size)})`);
|
|
74
|
+
/** Multiplicative order: every non-zero element is generator^i for some i < order. */
|
|
75
|
+
this.order = size - 1;
|
|
76
|
+
const exp = new Int32Array(this.order * 2);
|
|
77
|
+
const log = new Int32Array(size).fill(-1);
|
|
78
|
+
let x = 1;
|
|
79
|
+
for (let i = 0; i < this.order; i++) {
|
|
80
|
+
exp[i] = x;
|
|
81
|
+
log[x] = i;
|
|
82
|
+
if (prime) {
|
|
83
|
+
x = (x * generator) % size;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
x <<= 1;
|
|
87
|
+
if (x >= size)
|
|
88
|
+
x ^= primitive;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Wrapped copy lets mul() skip a modulo on the common path.
|
|
92
|
+
for (let i = 0; i < this.order; i++)
|
|
93
|
+
exp[this.order + i] = exp[i];
|
|
94
|
+
// A short cycle still returns to 1 after `order` steps whenever its length
|
|
95
|
+
// divides `order`, so "did we end at 1" does not detect a bad generator.
|
|
96
|
+
// The reliable test is coverage: a true generator visits every non-zero
|
|
97
|
+
// element exactly once, leaving no -1 in the log table.
|
|
98
|
+
for (let v = 1; v < size; v++) {
|
|
99
|
+
if (log[v] === -1) {
|
|
100
|
+
throw new Error(`${this.name}: generator ${generator} does not generate the ` +
|
|
101
|
+
`multiplicative group (element ${v} is unreachable). ` +
|
|
102
|
+
(prime ? 'Choose a primitive root.' : 'Check the primitive polynomial.'));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
this.expTable = exp;
|
|
106
|
+
this.logTable = log;
|
|
107
|
+
}
|
|
108
|
+
/** Additive identity is 0 and multiplicative identity is 1 in every field here. */
|
|
109
|
+
get zero() { return 0; }
|
|
110
|
+
get one() { return 1; }
|
|
111
|
+
/**
|
|
112
|
+
* a + b.
|
|
113
|
+
* @param {number} a @param {number} b @returns {number}
|
|
114
|
+
*/
|
|
115
|
+
add(a, b) {
|
|
116
|
+
return this.prime ? (a + b) % this.size : a ^ b;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* a - b. Distinct from add() in prime fields — see the module note.
|
|
120
|
+
* @param {number} a @param {number} b @returns {number}
|
|
121
|
+
*/
|
|
122
|
+
sub(a, b) {
|
|
123
|
+
return this.prime ? (a - b + this.size) % this.size : a ^ b;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* -a.
|
|
127
|
+
* @param {number} a @returns {number}
|
|
128
|
+
*/
|
|
129
|
+
neg(a) {
|
|
130
|
+
return this.prime ? (this.size - a) % this.size : a;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* a * b.
|
|
134
|
+
* @param {number} a @param {number} b @returns {number}
|
|
135
|
+
*/
|
|
136
|
+
mul(a, b) {
|
|
137
|
+
if (a === 0 || b === 0)
|
|
138
|
+
return 0;
|
|
139
|
+
return this.expTable[this.logTable[a] + this.logTable[b]];
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* a / b.
|
|
143
|
+
* @param {number} a @param {number} b @returns {number}
|
|
144
|
+
*/
|
|
145
|
+
div(a, b) {
|
|
146
|
+
if (b === 0)
|
|
147
|
+
throw new Error(`${this.name}: division by zero`);
|
|
148
|
+
if (a === 0)
|
|
149
|
+
return 0;
|
|
150
|
+
return this.expTable[this.logTable[a] - this.logTable[b] + this.order];
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* 1 / a.
|
|
154
|
+
* @param {number} a @returns {number}
|
|
155
|
+
*/
|
|
156
|
+
inv(a) {
|
|
157
|
+
if (a === 0)
|
|
158
|
+
throw new Error(`${this.name}: zero has no inverse`);
|
|
159
|
+
return this.expTable[this.order - this.logTable[a]];
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* generator^i, for any integer i (negative included).
|
|
163
|
+
* @param {number} i @returns {number}
|
|
164
|
+
*/
|
|
165
|
+
exp(i) {
|
|
166
|
+
let k = i % this.order;
|
|
167
|
+
if (k < 0)
|
|
168
|
+
k += this.order;
|
|
169
|
+
return this.expTable[k];
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Discrete log base generator.
|
|
173
|
+
* @param {number} a @returns {number}
|
|
174
|
+
*/
|
|
175
|
+
log(a) {
|
|
176
|
+
if (a === 0)
|
|
177
|
+
throw new Error(`${this.name}: log of zero`);
|
|
178
|
+
return this.logTable[a];
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/** QR Code, Data Matrix uses its own — see below. x^8 + x^4 + x^3 + x^2 + 1 */
|
|
182
|
+
export const GF256_QR = new GaloisField({ size: 256, primitive: 0x011d, name: 'GF(256)/QR' });
|
|
183
|
+
/** Data Matrix ECC200. x^8 + x^5 + x^3 + x^2 + 1 */
|
|
184
|
+
export const GF256_DM = new GaloisField({ size: 256, primitive: 0x012d, name: 'GF(256)/DataMatrix' });
|
|
185
|
+
/** Aztec's eight-bit data field is algebraically identical to Data Matrix's. */
|
|
186
|
+
export const GF256_AZTEC = GF256_DM;
|
|
187
|
+
/** PDF417. Prime field; 3 is a primitive root modulo 929. */
|
|
188
|
+
export const GF929 = new GaloisField({ size: 929, prime: true, generator: 3, name: 'GF(929)' });
|
|
189
|
+
/** Aztec, by layer count. */
|
|
190
|
+
export const GF16 = new GaloisField({ size: 16, primitive: 0x13, name: 'GF(16)' });
|
|
191
|
+
export const GF64 = new GaloisField({ size: 64, primitive: 0x43, name: 'GF(64)' });
|
|
192
|
+
export const GF1024 = new GaloisField({ size: 1024, primitive: 0x409, name: 'GF(1024)' });
|
|
193
|
+
export const GF4096 = new GaloisField({ size: 4096, primitive: 0x1069, name: 'GF(4096)' });
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Sythos Barcode Suite
|
|
3
|
+
*
|
|
4
|
+
* MIT License
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2026 Sythos
|
|
7
|
+
*
|
|
8
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
10
|
+
* in the Software without restriction, including without limitation the rights
|
|
11
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
12
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
13
|
+
* furnished to do so, subject to the following conditions:
|
|
14
|
+
*
|
|
15
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
16
|
+
* copies or substantial portions of the Software.
|
|
17
|
+
*
|
|
18
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
21
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
22
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
23
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
|
+
* SOFTWARE.
|
|
25
|
+
*
|
|
26
|
+
* SPDX-License-Identifier: MIT
|
|
27
|
+
*
|
|
28
|
+
* Original work. No code from any other barcode implementation.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Core primitives, re-exported.
|
|
32
|
+
*
|
|
33
|
+
* @module core
|
|
34
|
+
*/
|
|
35
|
+
export { BitMatrix } from './bit-matrix.js';
|
|
36
|
+
export { BitWriter, BitReader } from './bit-buffer.js';
|
|
37
|
+
export { GaloisField, GF256_QR, GF256_DM, GF929, GF16, GF64, GF1024, GF4096, } from './galois-field.js';
|
|
38
|
+
export { rsEncode, rsDecode, generatorPoly } from './reed-solomon.js';
|
|
39
|
+
export { BarcodeError, EncodeError, NotFoundError, FormatError, ChecksumError, } from './errors.js';
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Sythos Barcode Suite
|
|
3
|
+
*
|
|
4
|
+
* MIT License
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2026 Sythos
|
|
7
|
+
*
|
|
8
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
10
|
+
* in the Software without restriction, including without limitation the rights
|
|
11
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
12
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
13
|
+
* furnished to do so, subject to the following conditions:
|
|
14
|
+
*
|
|
15
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
16
|
+
* copies or substantial portions of the Software.
|
|
17
|
+
*
|
|
18
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
21
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
22
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
23
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
|
+
* SOFTWARE.
|
|
25
|
+
*
|
|
26
|
+
* SPDX-License-Identifier: MIT
|
|
27
|
+
*
|
|
28
|
+
* Original work. No code from any other barcode implementation.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Reed-Solomon encoding and decoding over an arbitrary finite field.
|
|
32
|
+
*
|
|
33
|
+
* Systematic encoding: the output is the message followed by parity symbols,
|
|
34
|
+
* so the data is readable without decoding when the symbol is undamaged.
|
|
35
|
+
*
|
|
36
|
+
* Decoding is syndromes -> Berlekamp-Massey -> Chien search -> Forney.
|
|
37
|
+
* It corrects up to floor(eccLen / 2) symbol errors at unknown positions.
|
|
38
|
+
*
|
|
39
|
+
* Every arithmetic operation routes through the field object. There is
|
|
40
|
+
* deliberately not a single bare `^` in this file: XOR is correct for binary
|
|
41
|
+
* fields and wrong for GF(929), and the resulting bug is invisible to any test
|
|
42
|
+
* that only exercises QR or Data Matrix. See core/galois-field.js.
|
|
43
|
+
*
|
|
44
|
+
* Polynomial convention in this module: **coefficient index 0 is the highest
|
|
45
|
+
* degree**, matching the wire order of a codeword. The decoder converts to
|
|
46
|
+
* degree-ascending internally where the algorithms are stated that way.
|
|
47
|
+
*
|
|
48
|
+
* @module core/reed-solomon
|
|
49
|
+
*/
|
|
50
|
+
import { ChecksumError } from './errors.js';
|
|
51
|
+
/**
|
|
52
|
+
* Build the generator polynomial for `eccLen` parity symbols.
|
|
53
|
+
*
|
|
54
|
+
* g(x) = product over i of (x - a^(base + i)), i = 0 .. eccLen-1
|
|
55
|
+
*
|
|
56
|
+
* `base` is 0 for QR; 1 for Aztec, Data Matrix and PDF417.
|
|
57
|
+
*
|
|
58
|
+
* @param {number} eccLen
|
|
59
|
+
* @param {import('./galois-field.js').GaloisField} field
|
|
60
|
+
* @param {number} [base]
|
|
61
|
+
* @returns {number[]} Monic, degree-descending, length eccLen + 1.
|
|
62
|
+
*/
|
|
63
|
+
export function generatorPoly(eccLen, field, base = 0) {
|
|
64
|
+
let g = [1];
|
|
65
|
+
for (let i = 0; i < eccLen; i++) {
|
|
66
|
+
const root = field.exp(base + i);
|
|
67
|
+
const next = new Array(g.length + 1).fill(0);
|
|
68
|
+
for (let j = 0; j < g.length; j++) {
|
|
69
|
+
// g[j]*x lands at next[j]; g[j]*(-root) lands at next[j+1].
|
|
70
|
+
next[j] = field.add(next[j], g[j]);
|
|
71
|
+
next[j + 1] = field.sub(next[j + 1], field.mul(g[j], root));
|
|
72
|
+
}
|
|
73
|
+
g = next;
|
|
74
|
+
}
|
|
75
|
+
return g;
|
|
76
|
+
}
|
|
77
|
+
const generatorCache = new Map();
|
|
78
|
+
/**
|
|
79
|
+
* Cached {@link generatorPoly}. Encoding the same format repeatedly is the
|
|
80
|
+
* common case and rebuilding the polynomial each time is pure waste.
|
|
81
|
+
*
|
|
82
|
+
* @param {number} eccLen
|
|
83
|
+
* @param {import('./galois-field.js').GaloisField} field
|
|
84
|
+
* @param {number} [base]
|
|
85
|
+
* @returns {number[]}
|
|
86
|
+
*/
|
|
87
|
+
function cachedGenerator(eccLen, field, base) {
|
|
88
|
+
const key = `${field.name}|${eccLen}|${base}`;
|
|
89
|
+
let g = generatorCache.get(key);
|
|
90
|
+
if (!g) {
|
|
91
|
+
g = generatorPoly(eccLen, field, base);
|
|
92
|
+
generatorCache.set(key, g);
|
|
93
|
+
}
|
|
94
|
+
return g;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Compute `eccLen` parity symbols for `data`.
|
|
98
|
+
*
|
|
99
|
+
* @param {ArrayLike<number>} data
|
|
100
|
+
* @param {number} eccLen
|
|
101
|
+
* @param {import('./galois-field.js').GaloisField} field
|
|
102
|
+
* @param {number} [base]
|
|
103
|
+
* @returns {number[]} The parity symbols alone, length eccLen.
|
|
104
|
+
*/
|
|
105
|
+
export function rsEncode(data, eccLen, field, base = 0) {
|
|
106
|
+
if (eccLen <= 0)
|
|
107
|
+
return [];
|
|
108
|
+
const gen = cachedGenerator(eccLen, field, base);
|
|
109
|
+
const res = new Array(data.length + eccLen).fill(0);
|
|
110
|
+
for (let i = 0; i < data.length; i++)
|
|
111
|
+
res[i] = data[i];
|
|
112
|
+
// Synthetic division by a monic divisor: the leading coefficient is
|
|
113
|
+
// annihilated each step and its multiple subtracted from the tail.
|
|
114
|
+
for (let i = 0; i < data.length; i++) {
|
|
115
|
+
const coef = res[i];
|
|
116
|
+
if (coef === 0)
|
|
117
|
+
continue;
|
|
118
|
+
for (let j = 1; j <= eccLen; j++) {
|
|
119
|
+
res[i + j] = field.sub(res[i + j], field.mul(gen[j], coef));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const remainder = res.slice(data.length);
|
|
123
|
+
// The codeword is data(x)*x^eccLen MINUS the remainder, so the parity
|
|
124
|
+
// symbols are the negated remainder. In a binary field negation is the
|
|
125
|
+
// identity and this is invisible; in GF(929) omitting it produces a
|
|
126
|
+
// codeword that is not divisible by the generator, and every symbol fails
|
|
127
|
+
// to decode. Exactly the class of bug the field abstraction exists to stop.
|
|
128
|
+
if (field.prime) {
|
|
129
|
+
for (let i = 0; i < remainder.length; i++)
|
|
130
|
+
remainder[i] = field.neg(remainder[i]);
|
|
131
|
+
}
|
|
132
|
+
return remainder;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Evaluate a degree-descending polynomial at x (Horner).
|
|
136
|
+
*
|
|
137
|
+
* @param {ArrayLike<number>} poly
|
|
138
|
+
* @param {number} x
|
|
139
|
+
* @param {import('./galois-field.js').GaloisField} field
|
|
140
|
+
* @returns {number}
|
|
141
|
+
*/
|
|
142
|
+
function evalPoly(poly, x, field) {
|
|
143
|
+
let acc = 0;
|
|
144
|
+
for (let i = 0; i < poly.length; i++) {
|
|
145
|
+
acc = field.add(field.mul(acc, x), poly[i]);
|
|
146
|
+
}
|
|
147
|
+
return acc;
|
|
148
|
+
}
|
|
149
|
+
function multiplyAscending(left, right, field, limit) {
|
|
150
|
+
const out = new Array(Math.min(limit, left.length + right.length - 1)).fill(0);
|
|
151
|
+
for (let i = 0; i < left.length; i++)
|
|
152
|
+
for (let j = 0; j < right.length && i + j < out.length; j++) {
|
|
153
|
+
out[i + j] = field.add(out[i + j], field.mul(left[i], right[j]));
|
|
154
|
+
}
|
|
155
|
+
return out;
|
|
156
|
+
}
|
|
157
|
+
function berlekampMassey(syndromes, field) {
|
|
158
|
+
const limit = syndromes.length;
|
|
159
|
+
const lambda = new Array(limit + 1).fill(0);
|
|
160
|
+
const previous = new Array(limit + 1).fill(0);
|
|
161
|
+
const temporary = new Array(limit + 1).fill(0);
|
|
162
|
+
lambda[0] = 1;
|
|
163
|
+
previous[0] = 1;
|
|
164
|
+
let errorCount = 0;
|
|
165
|
+
let shift = 1;
|
|
166
|
+
let lastDiscrepancy = 1;
|
|
167
|
+
for (let step = 0; step < limit; step++) {
|
|
168
|
+
let discrepancy = syndromes[step];
|
|
169
|
+
for (let i = 1; i <= errorCount; i++)
|
|
170
|
+
discrepancy = field.add(discrepancy, field.mul(lambda[i], syndromes[step - i]));
|
|
171
|
+
if (discrepancy === 0) {
|
|
172
|
+
shift++;
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
const scale = field.div(discrepancy, lastDiscrepancy);
|
|
176
|
+
for (let i = 0; i <= limit; i++)
|
|
177
|
+
temporary[i] = lambda[i];
|
|
178
|
+
for (let i = 0; i + shift <= limit; i++)
|
|
179
|
+
if (previous[i] !== 0) {
|
|
180
|
+
lambda[i + shift] = field.sub(lambda[i + shift], field.mul(scale, previous[i]));
|
|
181
|
+
}
|
|
182
|
+
if (2 * errorCount <= step) {
|
|
183
|
+
errorCount = step + 1 - errorCount;
|
|
184
|
+
for (let i = 0; i <= limit; i++)
|
|
185
|
+
previous[i] = temporary[i];
|
|
186
|
+
lastDiscrepancy = discrepancy;
|
|
187
|
+
shift = 1;
|
|
188
|
+
}
|
|
189
|
+
else
|
|
190
|
+
shift++;
|
|
191
|
+
}
|
|
192
|
+
return { locator: lambda.slice(0, errorCount + 1), errorCount };
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Correct errors in a received codeword, in place.
|
|
196
|
+
*
|
|
197
|
+
* @param {number[]} received Data followed by parity, degree-descending.
|
|
198
|
+
* @param {number} eccLen
|
|
199
|
+
* @param {import('./galois-field.js').GaloisField} field
|
|
200
|
+
* @param {number} [base]
|
|
201
|
+
* @param {number[]} [erasures] Known damaged indexes, counted from wire order.
|
|
202
|
+
* @returns {number} Number of symbols corrected.
|
|
203
|
+
* @throws {ChecksumError} If the damage exceeds the correction capacity.
|
|
204
|
+
*/
|
|
205
|
+
export function rsDecode(received, eccLen, field, base = 0, erasures = []) {
|
|
206
|
+
const n = received.length;
|
|
207
|
+
if (!Array.isArray(erasures) || new Set(erasures).size !== erasures.length || erasures.some((index) => !Number.isInteger(index) || index < 0 || index >= n)) {
|
|
208
|
+
throw new ChecksumError('Reed-Solomon: erasure positions must be unique codeword indexes');
|
|
209
|
+
}
|
|
210
|
+
if (erasures.length > eccLen)
|
|
211
|
+
throw new ChecksumError(`Reed-Solomon: ${erasures.length} erasures exceeds correction capacity ${eccLen} (${field.name})`);
|
|
212
|
+
// --- Syndromes. S[i] = R(a^(base+i)); all zero means an intact codeword.
|
|
213
|
+
const syn = new Array(eccLen).fill(0);
|
|
214
|
+
let damaged = false;
|
|
215
|
+
for (let i = 0; i < eccLen; i++) {
|
|
216
|
+
const s = evalPoly(received, field.exp(base + i), field);
|
|
217
|
+
syn[i] = s;
|
|
218
|
+
if (s !== 0)
|
|
219
|
+
damaged = true;
|
|
220
|
+
}
|
|
221
|
+
if (!damaged)
|
|
222
|
+
return 0;
|
|
223
|
+
// Remove the known roots before locating unknown errors. The leading
|
|
224
|
+
// erasureCount terms contain only the known-location transient and are not
|
|
225
|
+
// part of the error-only recurrence.
|
|
226
|
+
let erasureLocator = [1];
|
|
227
|
+
for (const index of erasures) {
|
|
228
|
+
const location = field.exp(n - 1 - index);
|
|
229
|
+
erasureLocator = multiplyAscending(erasureLocator, [1, field.neg(location)], field, eccLen + 1);
|
|
230
|
+
}
|
|
231
|
+
const modified = multiplyAscending(syn, erasureLocator, field, eccLen).slice(erasures.length);
|
|
232
|
+
const { locator: errorLocator, errorCount } = berlekampMassey(modified, field);
|
|
233
|
+
if (2 * errorCount + erasures.length > eccLen) {
|
|
234
|
+
throw new ChecksumError(`Reed-Solomon: ${errorCount} errors and ${erasures.length} erasures exceed correction capacity ` +
|
|
235
|
+
`${eccLen} (${field.name})`);
|
|
236
|
+
}
|
|
237
|
+
const lambda = multiplyAscending(erasureLocator, errorLocator, field, eccLen + 1);
|
|
238
|
+
const totalCount = errorCount + erasures.length;
|
|
239
|
+
// --- Chien search. Position p (counted from the low-order end) is in error
|
|
240
|
+
// when lambda(a^-p) == 0.
|
|
241
|
+
const positions = [];
|
|
242
|
+
for (let p = 0; p < n; p++) {
|
|
243
|
+
const xInv = field.exp(-p);
|
|
244
|
+
let acc = 0;
|
|
245
|
+
let term = 1;
|
|
246
|
+
for (let i = 0; i <= totalCount; i++) {
|
|
247
|
+
acc = field.add(acc, field.mul(lambda[i], term));
|
|
248
|
+
term = field.mul(term, xInv);
|
|
249
|
+
}
|
|
250
|
+
if (acc === 0)
|
|
251
|
+
positions.push(p);
|
|
252
|
+
}
|
|
253
|
+
if (positions.length !== totalCount) {
|
|
254
|
+
throw new ChecksumError(`Reed-Solomon: located ${positions.length} of ${totalCount} error positions`);
|
|
255
|
+
}
|
|
256
|
+
// --- Error evaluator. omega(x) = [S(x) * lambda(x)] mod x^eccLen,
|
|
257
|
+
// with S degree-ascending.
|
|
258
|
+
const omega = new Array(eccLen).fill(0);
|
|
259
|
+
for (let i = 0; i < eccLen; i++) {
|
|
260
|
+
let acc = 0;
|
|
261
|
+
for (let j = 0; j <= i && j <= totalCount; j++) {
|
|
262
|
+
acc = field.add(acc, field.mul(lambda[j], syn[i - j]));
|
|
263
|
+
}
|
|
264
|
+
omega[i] = acc;
|
|
265
|
+
}
|
|
266
|
+
// --- Forney. For an error at position p, with X = a^p:
|
|
267
|
+
// magnitude = -X^(1-base) * omega(X^-1) / lambda'(X^-1)
|
|
268
|
+
// The sign is a no-op in binary fields and load-bearing in GF(929).
|
|
269
|
+
let corrected = 0;
|
|
270
|
+
for (const p of positions) {
|
|
271
|
+
const xInv = field.exp(-p);
|
|
272
|
+
let num = 0;
|
|
273
|
+
let term = 1;
|
|
274
|
+
for (let i = 0; i < eccLen; i++) {
|
|
275
|
+
num = field.add(num, field.mul(omega[i], term));
|
|
276
|
+
term = field.mul(term, xInv);
|
|
277
|
+
}
|
|
278
|
+
// Formal derivative: only odd-index terms survive in a binary field, but
|
|
279
|
+
// in a prime field every term contributes with an integer multiplier.
|
|
280
|
+
let den = 0;
|
|
281
|
+
term = 1;
|
|
282
|
+
for (let i = 1; i <= totalCount; i++) {
|
|
283
|
+
if (field.prime) {
|
|
284
|
+
// i * lambda[i] * x^(i-1), where `i` is repeated addition.
|
|
285
|
+
let mult = 0;
|
|
286
|
+
const t = field.mul(lambda[i], term);
|
|
287
|
+
for (let k = 0; k < i; k++)
|
|
288
|
+
mult = field.add(mult, t);
|
|
289
|
+
den = field.add(den, mult);
|
|
290
|
+
}
|
|
291
|
+
else if (i % 2 === 1) {
|
|
292
|
+
den = field.add(den, field.mul(lambda[i], term));
|
|
293
|
+
}
|
|
294
|
+
term = field.mul(term, xInv);
|
|
295
|
+
}
|
|
296
|
+
if (den === 0) {
|
|
297
|
+
throw new ChecksumError('Reed-Solomon: singular error locator derivative');
|
|
298
|
+
}
|
|
299
|
+
let magnitude = field.div(num, den);
|
|
300
|
+
// X^(1-base): one factor of X when base is 0, none when base is 1.
|
|
301
|
+
if (base === 0)
|
|
302
|
+
magnitude = field.mul(magnitude, field.exp(p));
|
|
303
|
+
else if (base !== 1)
|
|
304
|
+
magnitude = field.mul(magnitude, field.exp(p * (1 - base)));
|
|
305
|
+
magnitude = field.neg(magnitude);
|
|
306
|
+
const idx = n - 1 - p;
|
|
307
|
+
received[idx] = field.sub(received[idx], magnitude);
|
|
308
|
+
corrected++;
|
|
309
|
+
}
|
|
310
|
+
// Verify: a genuine correction zeroes every syndrome. Without this check,
|
|
311
|
+
// damage beyond capacity can produce a plausible-looking wrong answer.
|
|
312
|
+
for (let i = 0; i < eccLen; i++) {
|
|
313
|
+
if (evalPoly(received, field.exp(base + i), field) !== 0) {
|
|
314
|
+
throw new ChecksumError('Reed-Solomon: correction failed verification');
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return corrected;
|
|
318
|
+
}
|