rxing/pdf417/decoder/ec/
error_correction.rs1use crate::{
18 common::Result,
19 pdf417::{decoder::ec::ModulusGF, pdf_417_common::NUMBER_OF_CODEWORDS},
20 Exceptions,
21};
22
23use super::ModulusPoly;
24
25use once_cell::sync::Lazy;
26
27static FLD_INTERIOR: Lazy<ModulusGF> = Lazy::new(|| ModulusGF::new(NUMBER_OF_CODEWORDS, 3));
29
30pub fn decode(received: &mut [u32], numECCodewords: u32, erasures: &mut [u32]) -> Result<usize> {
48 let field: &'static ModulusGF = &FLD_INTERIOR;
49 let poly = ModulusPoly::new(field, received.to_vec())?;
50 let mut S = vec![0u32; numECCodewords as usize];
51 let mut error = false;
52 for i in (1..=numECCodewords).rev() {
53 let eval = poly.evaluateAt(field.exp(i));
55 S[(numECCodewords - i) as usize] = eval;
56 if eval != 0 {
57 error = true;
58 }
59 }
60
61 if !error {
62 return Ok(0);
63 }
64
65 let mut knownErrors: ModulusPoly = ModulusPoly::getOne(field);
66 let mut b;
67 let mut term;
68 let mut kE: ModulusPoly;
69 if !erasures.is_empty() {
70 for erasure in erasures {
71 b = field.exp(received.len() as u32 - 1 - *erasure);
73 term = ModulusPoly::new(field, vec![field.subtract(0, b), 1])?;
75 kE = knownErrors.clone();
76 knownErrors = kE.multiply(term)?;
77 }
78 }
79
80 let syndrome = ModulusPoly::new(field, S)?;
81 let sigmaOmega = runEuclideanAlgorithm(
84 ModulusPoly::buildMonomial(field, numECCodewords as usize, 1),
85 syndrome,
86 numECCodewords,
87 field,
88 )?;
89 let sigma = sigmaOmega[0].clone();
90 let omega = sigmaOmega[1].clone();
91
92 let mut errorLocations = findErrorLocations(sigma.clone(), field)?;
95 let errorMagnitudes = findErrorMagnitudes(omega, sigma, &mut errorLocations, field);
96
97 for i in 0..errorLocations.len() {
98 let position = received.len() as isize - 1 - field.log(errorLocations[i])? as isize;
100 if position < 0 {
101 return Err(Exceptions::checksum_with(file!()));
102 }
103 received[position as usize] =
104 field.subtract(received[position as usize], errorMagnitudes[i]);
105 }
106
107 Ok(errorLocations.len())
108}
109
110fn runEuclideanAlgorithm(
111 a: ModulusPoly,
112 b: ModulusPoly,
113 R: u32,
114 field: &'static ModulusGF,
115) -> Result<[ModulusPoly; 2]> {
116 let mut a = a;
118 let mut b = b;
119 if a.getDegree() < b.getDegree() {
120 std::mem::swap(&mut a, &mut b);
121 }
122
123 let mut rLast = a;
124 let mut r = b;
125 let mut tLast = ModulusPoly::getZero(field);
126 let mut t = ModulusPoly::getOne(field);
127
128 while r.getDegree() >= R / 2 {
130 let rLastLast = rLast.clone();
131 let tLastLast = tLast.clone();
132 rLast = r;
133 tLast = t;
134
135 if rLast.isZero() {
137 return Err(Exceptions::checksum_with(file!()));
139 }
140 r = rLastLast;
141 let mut q = ModulusPoly::getZero(field); let denominatorLeadingTerm = rLast.getCoefficient(rLast.getDegree() as usize);
143 let dltInverse = field.inverse(denominatorLeadingTerm)?;
144 while r.getDegree() >= rLast.getDegree() && !r.isZero() {
145 let degreeDiff = r.getDegree() - rLast.getDegree();
146 let scale = field.multiply(r.getCoefficient(r.getDegree() as usize), dltInverse);
147 q = q.add(ModulusPoly::buildMonomial(
148 field,
149 degreeDiff as usize,
150 scale,
151 ))?;
152 r = r.subtract(rLast.multiplyByMonomial(degreeDiff as usize, scale))?;
153 }
154
155 t = q.multiply(tLast.clone())?.subtract(tLastLast)?.negative();
156 }
157
158 let sigmaTildeAtZero = t.getCoefficient(0);
159 if sigmaTildeAtZero == 0 {
160 return Err(Exceptions::checksum_with(file!()));
161 }
162
163 let inverse = field.inverse(sigmaTildeAtZero)?;
164 let sigma = t.multiplyByScaler(inverse);
165 let omega = r.multiplyByScaler(inverse);
166
167 Ok([sigma, omega])
168}
169
170fn findErrorLocations(errorLocator: ModulusPoly, field: &ModulusGF) -> Result<Vec<u32>> {
171 let numErrors = errorLocator.getDegree();
173 let mut result = vec![0u32; numErrors as usize];
174 let mut e = 0;
175 let mut i = 1;
176 while i < field.getSize() && e < numErrors {
177 if errorLocator.evaluateAt(i) == 0 {
179 result[e as usize] = field.inverse(i)?;
180 e += 1;
181 }
182 i += 1;
183 }
184 if e != numErrors {
185 return Err(Exceptions::checksum_with(file!()));
186 }
187 Ok(result)
188}
189
190fn findErrorMagnitudes(
191 errorEvaluator: ModulusPoly,
192 errorLocator: ModulusPoly,
193 errorLocations: &mut [u32],
194 field: &'static ModulusGF,
195) -> Vec<u32> {
196 let errorLocatorDegree = errorLocator.getDegree();
197 if errorLocatorDegree < 1 {
198 return vec![0; 0];
199 }
200 let mut formalDerivativeCoefficients = vec![0u32; errorLocatorDegree as usize];
201 for i in 1..=errorLocatorDegree {
202 formalDerivativeCoefficients[errorLocatorDegree as usize - i as usize] =
204 field.multiply(i, errorLocator.getCoefficient(i as usize));
205 }
206 let formalDerivative =
207 ModulusPoly::new(field, formalDerivativeCoefficients).expect("should generate good poly");
208
209 let s = errorLocations.len();
211 let mut result = vec![0u32; s];
212 for i in 0..s {
213 let xiInverse = field.inverse(errorLocations[i]).expect("must invert");
215 let numerator = field.subtract(0, errorEvaluator.evaluateAt(xiInverse));
216 let denominator = field
217 .inverse(formalDerivative.evaluateAt(xiInverse))
218 .expect("must invert");
219 result[i] = field.multiply(numerator, denominator);
220 }
221
222 result
223}