/* * ReedSolomonDecoder.cpp * zxing * * Created by Christian Brunschen on 05/05/2008. * Copyright 2008 Google UK. All rights reserved. * * 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. */ #include #include #include #include #include using namespace std; namespace zxing { ReedSolomonDecoder::ReedSolomonDecoder(Ref fld) : field(fld) { } ReedSolomonDecoder::~ReedSolomonDecoder() { } void ReedSolomonDecoder::decode(ArrayRef received, int twoS) { Ref poly(new GenericGFPoly(field, received)); #ifdef DEBUG cout << "decoding with poly " << *poly << "\n"; #endif ArrayRef syndromeCoefficients(new Array (twoS)); #ifdef DEBUG cout << "syndromeCoefficients array = " << syndromeCoefficients.array_ << "\n"; #endif bool dataMatrix = (field.object_ == GenericGF::DATA_MATRIX_FIELD_256.object_); bool noError = true; for (int i = 0; i < twoS; i++) { int eval = poly->evaluateAt(field->exp(dataMatrix ? i + 1 : i)); syndromeCoefficients[syndromeCoefficients->size() - 1 - i] = eval; if (eval != 0) { noError = false; } } if (noError) { return; } Ref syndrome(new GenericGFPoly(field, syndromeCoefficients)); Ref monomial = field->buildMonomial(twoS, 1); vector > sigmaOmega = runEuclideanAlgorithm(monomial, syndrome, twoS); ArrayRef errorLocations = findErrorLocations(sigmaOmega[0]); ArrayRef errorMagitudes = findErrorMagnitudes(sigmaOmega[1], errorLocations, dataMatrix); for (unsigned i = 0; i < errorLocations->size(); i++) { int position = received->size() - 1 - field->log(errorLocations[i]); //TODO: check why the position would be invalid if (position < 0 || (size_t)position >= received.size()) throw IllegalArgumentException("Invalid position (ReedSolomonDecoder)"); received[position] = GenericGF::addOrSubtract(received[position], errorMagitudes[i]); } } vector > ReedSolomonDecoder::runEuclideanAlgorithm(Ref a, Ref b, int R) { // Assume a's degree is >= b's if (a->getDegree() < b->getDegree()) { Ref tmp = a; a = b; b = tmp; } Ref rLast(a); Ref r(b); Ref sLast(field->getOne()); Ref s(field->getZero()); Ref tLast(field->getZero()); Ref t(field->getOne()); // Run Euclidean algorithm until r's degree is less than R/2 while (r->getDegree() >= R / 2) { Ref rLastLast(rLast); Ref sLastLast(sLast); Ref tLastLast(tLast); rLast = r; sLast = s; tLast = t; // Divide rLastLast by rLast, with quotient q and remainder r if (rLast->isZero()) { // Oops, Euclidean algorithm already terminated? throw ReedSolomonException("r_{i-1} was zero"); } r = rLastLast; Ref q(field->getZero()); int denominatorLeadingTerm = rLast->getCoefficient(rLast->getDegree()); int dltInverse = field->inverse(denominatorLeadingTerm); while (r->getDegree() >= rLast->getDegree() && !r->isZero()) { int degreeDiff = r->getDegree() - rLast->getDegree(); int scale = field->multiply(r->getCoefficient(r->getDegree()), dltInverse); q = q->addOrSubtract(field->buildMonomial(degreeDiff, scale)); r = r->addOrSubtract(rLast->multiplyByMonomial(degreeDiff, scale)); } s = q->multiply(sLast)->addOrSubtract(sLastLast); t = q->multiply(tLast)->addOrSubtract(tLastLast); } int sigmaTildeAtZero = t->getCoefficient(0); if (sigmaTildeAtZero == 0) { throw ReedSolomonException("sigmaTilde(0) was zero"); } int inverse = field->inverse(sigmaTildeAtZero); Ref sigma(t->multiply(inverse)); Ref omega(r->multiply(inverse)); #ifdef DEBUG cout << "t = " << *t << "\n"; cout << "r = " << *r << "\n"; cout << "sigma = " << *sigma << "\n"; cout << "omega = " << *omega << "\n"; #endif vector > result(2); result[0] = sigma; result[1] = omega; return result; } ArrayRef ReedSolomonDecoder::findErrorLocations(Ref errorLocator) { // This is a direct application of Chien's search int numErrors = errorLocator->getDegree(); if (numErrors == 1) { // shortcut ArrayRef result(new Array(1)); result[0] = errorLocator->getCoefficient(1); return result; } ArrayRef result(new Array(numErrors)); int e = 0; for (int i = 1; i < field->getSize() && e < numErrors; i++) { // cout << "errorLocator(" << i << ") == " << errorLocator->evaluateAt(i) << "\n"; if (errorLocator->evaluateAt(i) == 0) { result[e] = field->inverse(i); e++; } } if (e != numErrors) { throw ReedSolomonException("Error locator degree does not match number of roots"); } return result; } ArrayRef ReedSolomonDecoder::findErrorMagnitudes(Ref errorEvaluator, ArrayRef errorLocations, bool dataMatrix) { // This is directly applying Forney's Formula int s = errorLocations.size(); ArrayRef result(new Array(s)); for (int i = 0; i < s; i++) { int xiInverse = field->inverse(errorLocations[i]); int denominator = 1; for (int j = 0; j < s; j++) { if (i != j) { denominator = field->multiply(denominator, GenericGF::addOrSubtract(1, field->multiply(errorLocations[j], xiInverse))); } } result[i] = field->multiply(errorEvaluator->evaluateAt(xiInverse), field->inverse(denominator)); if (dataMatrix) { result[i] = field->multiply(result[i], xiInverse); } } return result; } }