@sythos/js_barcode_universal 1.5.8 → 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 +17 -13
- package/bundle/sythos-barcode.esm.js +11658 -11244
- package/bundle/sythos-barcode.js +11658 -11244
- package/package.json +10 -3
- package/src/index.d.ts +1 -1
- package/src/index.js +508 -516
- package/src/js/aztec/decoder.js +208 -199
- package/src/js/aztec/detector.js +153 -126
- package/src/js/aztec/encoder.js +172 -153
- package/src/js/aztec/high-level.js +106 -101
- package/src/js/aztec/index.js +1 -12
- package/src/js/aztec/tables.js +106 -120
- package/src/js/aztecrune/decoder.js +76 -85
- package/src/js/aztecrune/detector.js +107 -93
- package/src/js/aztecrune/encoder.js +50 -68
- package/src/js/aztecrune/index.js +1 -16
- package/src/js/aztecrune/tables.js +59 -54
- package/src/js/compactpdf417/decoder.js +69 -74
- package/src/js/compactpdf417/detector.js +74 -75
- package/src/js/compactpdf417/encoder.js +68 -81
- package/src/js/compactpdf417/index.js +1 -13
- package/src/js/compactpdf417/tables.js +71 -80
- package/src/js/core/bit-buffer.js +106 -122
- package/src/js/core/bit-matrix.js +196 -194
- package/src/js/core/errors.js +13 -15
- package/src/js/core/galois-field.js +119 -133
- package/src/js/core/index.js +2 -19
- package/src/js/core/reed-solomon.js +195 -204
- package/src/js/databar/codec.js +93 -108
- package/src/js/databar/decoder.js +149 -140
- package/src/js/databar/encoder.js +47 -55
- package/src/js/databar/gs1.js +122 -123
- package/src/js/databar/index.js +4 -36
- package/src/js/databar/patterns.js +81 -85
- package/src/js/databar/tables.js +51 -52
- package/src/js/datamatrix/decoder.js +216 -182
- package/src/js/datamatrix/detector.js +161 -132
- package/src/js/datamatrix/encoder.js +192 -133
- package/src/js/datamatrix/index.js +1 -9
- package/src/js/datamatrix/tables.js +68 -69
- package/src/js/frameqr/decoder.js +102 -125
- package/src/js/frameqr/detector.js +101 -94
- package/src/js/frameqr/encoder.js +67 -80
- package/src/js/frameqr/index.js +1 -10
- package/src/js/frameqr/tables.js +145 -163
- package/src/js/image/binarizer.js +146 -162
- package/src/js/image/grid-sampler.js +63 -79
- package/src/js/image/index.js +0 -2
- package/src/js/image/luminance.js +129 -140
- package/src/js/image/perspective.js +112 -149
- package/src/js/micropdf417/compaction.js +64 -65
- package/src/js/micropdf417/decoder.js +106 -109
- package/src/js/micropdf417/detector.js +73 -70
- package/src/js/micropdf417/encoder.js +129 -154
- package/src/js/micropdf417/error-correction.js +6 -11
- package/src/js/micropdf417/index.js +2 -16
- package/src/js/micropdf417/tables.js +112 -99
- package/src/js/microqr/decoder.js +177 -182
- package/src/js/microqr/detector.js +240 -256
- package/src/js/microqr/encoder.js +239 -194
- package/src/js/microqr/index.js +0 -2
- package/src/js/microqr/tables.js +208 -200
- package/src/js/oned/addons.js +167 -191
- package/src/js/oned/index.js +27 -58
- package/src/js/oned/patterns.js +194 -213
- package/src/js/oned/reader.js +1003 -984
- package/src/js/oned/writers.js +411 -466
- package/src/js/pdf417/compaction.js +315 -222
- package/src/js/pdf417/decoder.js +71 -36
- package/src/js/pdf417/detector.js +377 -361
- package/src/js/pdf417/encoder.js +57 -46
- package/src/js/pdf417/error-correction.js +5 -8
- package/src/js/pdf417/tables.js +248 -250
- package/src/js/qr/decoder.js +311 -347
- package/src/js/qr/detector.js +378 -395
- package/src/js/qr/encoder.js +514 -599
- package/src/js/qr/index.js +0 -2
- package/src/js/qr/tables.js +375 -422
- package/src/js/render/image-data.js +57 -62
- package/src/js/render/index.js +21 -23
- package/src/js/render/options.js +82 -90
- package/src/js/render/png.js +144 -169
- package/src/js/render/svg.js +41 -44
- package/src/js/render/webgl.js +103 -109
- package/src/js/render/webgpu.js +205 -217
- package/src/js/rmqr/decoder.js +161 -53
- package/src/js/rmqr/detector.js +73 -41
- package/src/js/rmqr/encoder.js +253 -104
- package/src/js/rmqr/index.js +1 -5
- package/src/js/rmqr/tables.js +108 -85
- package/src/ts/aztec/decoder.ts +317 -0
- package/src/ts/aztec/detector.ts +224 -0
- package/src/ts/aztec/encoder.ts +257 -0
- package/src/ts/aztec/high-level.ts +211 -0
- package/src/ts/aztec/index.ts +45 -0
- package/src/ts/aztec/tables.ts +210 -0
- package/src/ts/aztecrune/decoder.ts +155 -0
- package/src/ts/aztecrune/detector.ts +166 -0
- package/src/ts/aztecrune/encoder.ts +121 -0
- package/src/ts/aztecrune/index.ts +49 -0
- package/src/ts/aztecrune/tables.ts +137 -0
- package/src/ts/compactpdf417/decoder.ts +128 -0
- package/src/ts/compactpdf417/detector.ts +139 -0
- package/src/ts/compactpdf417/encoder.ts +140 -0
- package/src/ts/compactpdf417/index.ts +17 -0
- package/src/ts/compactpdf417/tables.ts +173 -0
- package/src/ts/core/bit-buffer.ts +174 -0
- package/src/ts/core/bit-matrix.ts +241 -0
- package/src/ts/core/errors.ts +61 -0
- package/src/ts/core/galois-field.ts +207 -0
- package/src/ts/core/index.ts +56 -0
- package/src/ts/core/reed-solomon.ts +327 -0
- package/src/ts/databar/codec.ts +181 -0
- package/src/ts/databar/decoder.ts +215 -0
- package/src/ts/databar/encoder.ts +96 -0
- package/src/ts/databar/gs1.ts +177 -0
- package/src/ts/databar/index.ts +68 -0
- package/src/ts/databar/patterns.ts +143 -0
- package/src/ts/databar/tables.ts +124 -0
- package/src/ts/datamatrix/decoder.ts +262 -0
- package/src/ts/datamatrix/detector.ts +225 -0
- package/src/ts/datamatrix/encoder.ts +191 -0
- package/src/ts/datamatrix/index.ts +42 -0
- package/src/ts/datamatrix/tables.ts +123 -0
- package/src/ts/frameqr/decoder.ts +239 -0
- package/src/ts/frameqr/detector.ts +192 -0
- package/src/ts/frameqr/encoder.ts +156 -0
- package/src/ts/frameqr/index.ts +42 -0
- package/src/ts/frameqr/tables.ts +270 -0
- package/src/ts/image/binarizer.ts +270 -0
- package/src/ts/image/grid-sampler.ts +164 -0
- package/src/ts/image/index.ts +40 -0
- package/src/ts/image/luminance.ts +196 -0
- package/src/ts/image/perspective.ts +195 -0
- package/src/ts/index.d.ts +1 -1
- package/src/ts/index.ts +790 -0
- package/src/ts/micropdf417/compaction.ts +116 -0
- package/src/ts/micropdf417/decoder.ts +183 -0
- package/src/ts/micropdf417/detector.ts +149 -0
- package/src/ts/micropdf417/encoder.ts +209 -0
- package/src/ts/micropdf417/error-correction.ts +55 -0
- package/src/ts/micropdf417/index.ts +49 -0
- package/src/ts/micropdf417/tables.ts +184 -0
- package/src/ts/microqr/decoder.ts +245 -0
- package/src/ts/microqr/detector.ts +355 -0
- package/src/ts/microqr/encoder.ts +269 -0
- package/src/ts/microqr/index.ts +36 -0
- package/src/ts/microqr/tables.ts +316 -0
- package/src/ts/oned/addons.ts +420 -0
- package/src/ts/oned/index.ts +106 -0
- package/src/ts/oned/patterns.ts +384 -0
- package/src/ts/oned/reader.ts +1364 -0
- package/src/ts/oned/writers.ts +746 -0
- package/src/ts/pdf417/compaction.ts +298 -0
- package/src/ts/pdf417/decoder.ts +75 -0
- package/src/ts/pdf417/detector.ts +468 -0
- package/src/ts/pdf417/encoder.ts +91 -0
- package/src/ts/pdf417/error-correction.ts +47 -0
- package/src/ts/pdf417/index.ts +6 -0
- package/src/ts/pdf417/tables.ts +317 -0
- package/src/ts/qr/decoder.ts +575 -0
- package/src/ts/qr/detector.ts +630 -0
- package/src/ts/qr/encoder.ts +958 -0
- package/src/ts/qr/index.ts +44 -0
- package/src/ts/qr/tables.ts +737 -0
- package/src/ts/render/image-data.ts +125 -0
- package/src/ts/render/index.ts +130 -0
- package/src/ts/render/options.ts +160 -0
- package/src/ts/render/png.ts +295 -0
- package/src/ts/render/svg.ts +120 -0
- package/src/ts/render/webgl.ts +206 -0
- package/src/ts/render/webgpu.ts +369 -0
- package/src/ts/rmqr/decoder.ts +101 -0
- package/src/ts/rmqr/detector.ts +90 -0
- package/src/ts/rmqr/encoder.ts +172 -0
- package/src/ts/rmqr/index.ts +37 -0
- package/src/ts/rmqr/tables.ts +154 -0
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
*
|
|
28
28
|
* Original work. No code from any other barcode implementation.
|
|
29
29
|
*/
|
|
30
|
-
|
|
31
30
|
/**
|
|
32
31
|
* Reed-Solomon encoding and decoding over an arbitrary finite field.
|
|
33
32
|
*
|
|
@@ -48,9 +47,7 @@
|
|
|
48
47
|
*
|
|
49
48
|
* @module core/reed-solomon
|
|
50
49
|
*/
|
|
51
|
-
|
|
52
50
|
import { ChecksumError } from './errors.js';
|
|
53
|
-
|
|
54
51
|
/**
|
|
55
52
|
* Build the generator polynomial for `eccLen` parity symbols.
|
|
56
53
|
*
|
|
@@ -64,22 +61,20 @@ import { ChecksumError } from './errors.js';
|
|
|
64
61
|
* @returns {number[]} Monic, degree-descending, length eccLen + 1.
|
|
65
62
|
*/
|
|
66
63
|
export function generatorPoly(eccLen, field, base = 0) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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;
|
|
75
74
|
}
|
|
76
|
-
g
|
|
77
|
-
}
|
|
78
|
-
return g;
|
|
75
|
+
return g;
|
|
79
76
|
}
|
|
80
|
-
|
|
81
77
|
const generatorCache = new Map();
|
|
82
|
-
|
|
83
78
|
/**
|
|
84
79
|
* Cached {@link generatorPoly}. Encoding the same format repeatedly is the
|
|
85
80
|
* common case and rebuilding the polynomial each time is pure waste.
|
|
@@ -90,15 +85,14 @@ const generatorCache = new Map();
|
|
|
90
85
|
* @returns {number[]}
|
|
91
86
|
*/
|
|
92
87
|
function cachedGenerator(eccLen, field, base) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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;
|
|
100
95
|
}
|
|
101
|
-
|
|
102
96
|
/**
|
|
103
97
|
* Compute `eccLen` parity symbols for `data`.
|
|
104
98
|
*
|
|
@@ -109,34 +103,34 @@ function cachedGenerator(eccLen, field, base) {
|
|
|
109
103
|
* @returns {number[]} The parity symbols alone, length eccLen.
|
|
110
104
|
*/
|
|
111
105
|
export function rsEncode(data, eccLen, field, base = 0) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
+
}
|
|
124
121
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
return remainder;
|
|
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;
|
|
138
133
|
}
|
|
139
|
-
|
|
140
134
|
/**
|
|
141
135
|
* Evaluate a degree-descending polynomial at x (Horner).
|
|
142
136
|
*
|
|
@@ -146,51 +140,57 @@ export function rsEncode(data, eccLen, field, base = 0) {
|
|
|
146
140
|
* @returns {number}
|
|
147
141
|
*/
|
|
148
142
|
function evalPoly(poly, x, field) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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;
|
|
154
148
|
}
|
|
155
|
-
|
|
156
149
|
function multiplyAscending(left, right, field, limit) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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;
|
|
162
156
|
}
|
|
163
|
-
|
|
164
157
|
function berlekampMassey(syndromes, field) {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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++;
|
|
183
191
|
}
|
|
184
|
-
|
|
185
|
-
errorCount = step + 1 - errorCount;
|
|
186
|
-
for (let i = 0; i <= limit; i++) previous[i] = temporary[i];
|
|
187
|
-
lastDiscrepancy = discrepancy;
|
|
188
|
-
shift = 1;
|
|
189
|
-
} else shift++;
|
|
190
|
-
}
|
|
191
|
-
return { locator: lambda.slice(0, errorCount + 1), errorCount };
|
|
192
|
+
return { locator: lambda.slice(0, errorCount + 1), errorCount };
|
|
192
193
|
}
|
|
193
|
-
|
|
194
194
|
/**
|
|
195
195
|
* Correct errors in a received codeword, in place.
|
|
196
196
|
*
|
|
@@ -203,125 +203,116 @@ function berlekampMassey(syndromes, field) {
|
|
|
203
203
|
* @throws {ChecksumError} If the damage exceeds the correction capacity.
|
|
204
204
|
*/
|
|
205
205
|
export function rsDecode(received, eccLen, field, base = 0, erasures = []) {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
if (erasures.length > eccLen) throw new ChecksumError(`Reed-Solomon: ${erasures.length} erasures exceeds correction capacity ${eccLen} (${field.name})`);
|
|
211
|
-
|
|
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) damaged = true;
|
|
219
|
-
}
|
|
220
|
-
if (!damaged) return 0;
|
|
221
|
-
|
|
222
|
-
// Remove the known roots before locating unknown errors. The leading
|
|
223
|
-
// erasureCount terms contain only the known-location transient and are not
|
|
224
|
-
// part of the error-only recurrence.
|
|
225
|
-
let erasureLocator = [1];
|
|
226
|
-
for (const index of erasures) {
|
|
227
|
-
const location = field.exp(n - 1 - index);
|
|
228
|
-
erasureLocator = multiplyAscending(erasureLocator, [1, field.neg(location)], field, eccLen + 1);
|
|
229
|
-
}
|
|
230
|
-
const modified = multiplyAscending(syn, erasureLocator, field, eccLen).slice(erasures.length);
|
|
231
|
-
const { locator: errorLocator, errorCount } = berlekampMassey(modified, field);
|
|
232
|
-
if (2 * errorCount + erasures.length > eccLen) {
|
|
233
|
-
throw new ChecksumError(
|
|
234
|
-
`Reed-Solomon: ${errorCount} errors and ${erasures.length} erasures exceed correction capacity ` +
|
|
235
|
-
`${eccLen} (${field.name})`
|
|
236
|
-
);
|
|
237
|
-
}
|
|
238
|
-
const lambda = multiplyAscending(erasureLocator, errorLocator, field, eccLen + 1);
|
|
239
|
-
const totalCount = errorCount + erasures.length;
|
|
240
|
-
|
|
241
|
-
// --- Chien search. Position p (counted from the low-order end) is in error
|
|
242
|
-
// when lambda(a^-p) == 0.
|
|
243
|
-
const positions = [];
|
|
244
|
-
for (let p = 0; p < n; p++) {
|
|
245
|
-
const xInv = field.exp(-p);
|
|
246
|
-
let acc = 0;
|
|
247
|
-
let term = 1;
|
|
248
|
-
for (let i = 0; i <= totalCount; i++) {
|
|
249
|
-
acc = field.add(acc, field.mul(lambda[i], term));
|
|
250
|
-
term = field.mul(term, xInv);
|
|
251
|
-
}
|
|
252
|
-
if (acc === 0) positions.push(p);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (positions.length !== totalCount) {
|
|
256
|
-
throw new ChecksumError(
|
|
257
|
-
`Reed-Solomon: located ${positions.length} of ${totalCount} error positions`
|
|
258
|
-
);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// --- Error evaluator. omega(x) = [S(x) * lambda(x)] mod x^eccLen,
|
|
262
|
-
// with S degree-ascending.
|
|
263
|
-
const omega = new Array(eccLen).fill(0);
|
|
264
|
-
for (let i = 0; i < eccLen; i++) {
|
|
265
|
-
let acc = 0;
|
|
266
|
-
for (let j = 0; j <= i && j <= totalCount; j++) {
|
|
267
|
-
acc = field.add(acc, field.mul(lambda[j], syn[i - j]));
|
|
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');
|
|
268
209
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
// The sign is a no-op in binary fields and load-bearing in GF(929).
|
|
275
|
-
let corrected = 0;
|
|
276
|
-
for (const p of positions) {
|
|
277
|
-
const xInv = field.exp(-p);
|
|
278
|
-
|
|
279
|
-
let num = 0;
|
|
280
|
-
let term = 1;
|
|
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;
|
|
281
215
|
for (let i = 0; i < eccLen; i++) {
|
|
282
|
-
|
|
283
|
-
|
|
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);
|
|
284
230
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
for (let i = 1; i <= totalCount; i++) {
|
|
291
|
-
if (field.prime) {
|
|
292
|
-
// i * lambda[i] * x^(i-1), where `i` is repeated addition.
|
|
293
|
-
let mult = 0;
|
|
294
|
-
const t = field.mul(lambda[i], term);
|
|
295
|
-
for (let k = 0; k < i; k++) mult = field.add(mult, t);
|
|
296
|
-
den = field.add(den, mult);
|
|
297
|
-
} else if (i % 2 === 1) {
|
|
298
|
-
den = field.add(den, field.mul(lambda[i], term));
|
|
299
|
-
}
|
|
300
|
-
term = field.mul(term, xInv);
|
|
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})`);
|
|
301
236
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
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);
|
|
305
252
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
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
|
+
}
|
|
323
316
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
return corrected;
|
|
317
|
+
return corrected;
|
|
327
318
|
}
|