{ * Copyright 2008 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * Original Authors: Sean Owen and William Rucklidge * Delphi Implementation by E. Spelt and K. Gossens } unit ZXing.Common.ReedSolomon.ReedSolomonDecoder; interface uses System.SysUtils, // Hint: ZXing.Common.ReedSolomon.GenericGFPoly is implemented in GenericGF as second class ZXing.Common.ReedSolomon.GenericGF; type /// /// Implements Reed-Solomon encoding, as the name implies. /// TReedSolomonDecoder = class sealed public constructor Create(field: TGenericGF); public function decode(received: TArray; twoS: Integer): boolean; strict private function findErrorLocations(errorLocator: IGenericGFPoly): TArray; strict private function findErrorMagnitudes(errorEvaluator: IGenericGFPoly; errorLocations: TArray): TArray; private function runEuclideanAlgorithm(a: IGenericGFPoly; b: IGenericGFPoly; pR: Integer): TArray; strict private field: TGenericGF; end; implementation { TReedSolomonDecoder } constructor TReedSolomonDecoder.Create(field: TGenericGF); begin self.field := field end; function TReedSolomonDecoder.decode(received: TArray; twoS: Integer): boolean; var i, eval, position: Integer; poly, syndrome, sigma, omega: IGenericGFPoly; sigmaOmega: TArray; errorLocations: TArray; syndromeCoefficients, errorMagnitudes: TArray; noError: boolean; begin poly := TGenericGFPoly.Create(self.field, received); syndromeCoefficients := TArray.Create(); SetLength(syndromeCoefficients, twoS); try noError := true; i := 0; while ((i < twoS)) do begin eval := poly.evaluateAt(self.field.exp((i + self.field.GeneratorBase))); syndromeCoefficients[((Length(syndromeCoefficients) - 1) - i)] := eval; if (eval <> 0) then noError := false; inc(i) end; if (noError) then begin Result := true; Exit; end; syndrome := TGenericGFPoly.Create(self.field, syndromeCoefficients); sigmaOmega := self.runEuclideanAlgorithm(self.field.buildMonomial(twoS, 1), syndrome, twoS); if (sigmaOmega = nil) then begin Result := false; Exit end; sigma := sigmaOmega[0]; errorLocations := self.findErrorLocations(sigma); if (errorLocations = nil) then begin Result := false; Exit end; omega := sigmaOmega[1]; errorMagnitudes := self.findErrorMagnitudes(omega, errorLocations); i := 0; while (i < Length(errorLocations)) do begin position := ((Length(received) - 1) - self.field.log(errorLocations[i])); if (position < 0) then begin Result := false; Exit end; received[position] := TGenericGF.addOrSubtract(received[position], errorMagnitudes[i]); inc(i) end; finally SetLength(sigmaOmega, 0); SetLength(syndromeCoefficients, 0); end; Result := true; end; function TReedSolomonDecoder.findErrorLocations(errorLocator: IGenericGFPoly) : TArray; var numErrors, e, i: Integer; begin numErrors := errorLocator.Degree; if (numErrors = 1) then begin Result := TArray.Create(errorLocator.getCoefficient(1)); Exit end; Result := TArray.Create(); SetLength(Result, numErrors); e := 0; i := 1; while (((i < self.field.Size) and (e < numErrors))) do begin if (errorLocator.evaluateAt(i) = 0) then begin Result[e] := self.field.inverse(i); inc(e) end; inc(i); end; if (e <> numErrors) then begin Result := nil; end; end; function TReedSolomonDecoder.findErrorMagnitudes(errorEvaluator: IGenericGFPoly; errorLocations: TArray): TArray; var s, i, xiInverse, denominator, j, term, termPlus1: Integer; begin s := Length(errorLocations); Result := TArray.Create(); SetLength(Result, s); i := 0; while ((i < s)) do begin xiInverse := self.field.inverse(errorLocations[i]); denominator := 1; j := 0; while ((j < s)) do begin if (i <> j) then begin term := self.field.multiply(errorLocations[j], xiInverse); if ((term and 1) = 0) then begin termPlus1 := (term or 1) end else begin termPlus1 := (term and (not 1)); end; denominator := self.field.multiply(denominator, termPlus1) end; inc(j) end; Result[i] := self.field.multiply(errorEvaluator.evaluateAt(xiInverse), self.field.inverse(denominator)); if (self.field.GeneratorBase <> 0) then Result[i] := self.field.multiply(Result[i], xiInverse); inc(i) end; end; function TReedSolomonDecoder.runEuclideanAlgorithm(a, b: IGenericGFPoly; pR: Integer): TArray; var temp, rLastLast, tLastLast, rLast, tLast, t, q, sigma, omega, R: IGenericGFPoly; denominatorLeadingTerm, dltInverse, degreeDiff, scale, inverse, sigmaTildeAtZero: Integer; begin if (a.Degree < b.Degree) then begin temp := a; a := b; b := temp end; rLast := a; R := b; tLast := self.field.Zero; t := self.field.One; while ((R.Degree >= (pR div 2))) do begin rLastLast := rLast; tLastLast := tLast; rLast := R; tLast := t; if (rLast.isZero) then begin Result := nil; Exit end; R := rLastLast; q := self.field.Zero; denominatorLeadingTerm := rLast.getCoefficient(rLast.Degree); dltInverse := self.field.inverse(denominatorLeadingTerm); while (((R.Degree >= rLast.Degree) and not R.isZero)) do begin degreeDiff := (R.Degree - rLast.Degree); scale := self.field.multiply(R.getCoefficient(R.Degree), dltInverse); q := q.addOrSubtract(self.field.buildMonomial(degreeDiff, scale)); R := R.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale)) end; t := q.multiply(tLast).addOrSubtract(tLastLast); if (R.Degree >= rLast.Degree) then begin Result := nil; Exit end end; sigmaTildeAtZero := t.getCoefficient(0); if (sigmaTildeAtZero = 0) then begin Result := nil; Exit end; inverse := self.field.inverse(sigmaTildeAtZero); sigma := t.multiply(inverse); omega := R.multiply(inverse); Result := TArray.Create(sigma, omega); end; end.