Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/thirdparty/zxing-cpp/core/src/ReedSolomonDecoder.cpp @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/thirdparty/zxing-cpp/core/src/ReedSolomonDecoder.cpp Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,143 @@ +/* +* Copyright 2016 Nu-book Inc. +* Copyright 2016 ZXing authors +* Copyright 2017 Axel Waggershauser +*/ +// SPDX-License-Identifier: Apache-2.0 + +#include "ReedSolomonDecoder.h" + +#include "GenericGF.h" +#include "ZXConfig.h" + +#include <algorithm> +#include <stdexcept> +#include <utility> + +namespace ZXing { + +static bool +RunEuclideanAlgorithm(const GenericGF& field, std::vector<int>&& rCoefs, GenericGFPoly& sigma, GenericGFPoly& omega) +{ + int R = Size(rCoefs); // == numECCodeWords + GenericGFPoly r(field, std::move(rCoefs)); + GenericGFPoly& tLast = omega.setField(field); + GenericGFPoly& t = sigma.setField(field); + ZX_THREAD_LOCAL GenericGFPoly q, rLast; + + rLast.setField(field); + q.setField(field); + + rLast.setMonomial(1, R); + tLast.setMonomial(0); + t.setMonomial(1); + + // Assume r's degree is < rLast's + if (r.degree() >= rLast.degree()) + swap(r, rLast); + + // Run Euclidean algorithm until r's degree is less than R/2 + while (r.degree() >= R / 2) { + swap(tLast, t); + swap(rLast, r); + + // Divide rLastLast by rLast, with quotient in q and remainder in r + if (rLast.isZero()) + return false; // Oops, Euclidean algorithm already terminated? + + r.divide(rLast, q); + + q.multiply(tLast); + q.addOrSubtract(t); + swap(t, q); // t = q + + if (r.degree() >= rLast.degree()) + throw std::runtime_error("Division algorithm failed to reduce polynomial?"); + } + + int sigmaTildeAtZero = t.constant(); + if (sigmaTildeAtZero == 0) + return false; + + int inverse = field.inverse(sigmaTildeAtZero); + t.multiplyByMonomial(inverse); + r.multiplyByMonomial(inverse); + + // sigma is t + omega = std::move(r); + return true; +} + +static std::vector<int> +FindErrorLocations(const GenericGF& field, const GenericGFPoly& errorLocator) +{ + // This is a direct application of Chien's search + int numErrors = errorLocator.degree(); + std::vector<int> res; + res.reserve(numErrors); + + for (int i = 1; i < field.size() && Size(res) < numErrors; i++) + if (errorLocator.evaluateAt(i) == 0) + res.push_back(field.inverse(i)); + + if (Size(res) != numErrors) + return {}; // Error locator degree does not match number of roots + + return res; +} + +static std::vector<int> +FindErrorMagnitudes(const GenericGF& field, const GenericGFPoly& errorEvaluator, const std::vector<int>& errorLocations) +{ + // This is directly applying Forney's Formula + int s = Size(errorLocations); + std::vector<int> res(s); + for (int i = 0; i < s; ++i) { + int xiInverse = field.inverse(errorLocations[i]); + int denom = 1; + for (int j = 0; j < s; ++j) + if (i != j) + denom = field.multiply(denom, 1 ^ field.multiply(errorLocations[j], xiInverse)); + res[i] = field.multiply(errorEvaluator.evaluateAt(xiInverse), field.inverse(denom)); + if (field.generatorBase() != 0) + res[i] = field.multiply(res[i], xiInverse); + } + return res; +} + +bool +ReedSolomonDecode(const GenericGF& field, std::vector<int>& message, int numECCodeWords) +{ + GenericGFPoly poly(field, message); + + std::vector<int> syndromes(numECCodeWords); + for (int i = 0; i < numECCodeWords; i++) + syndromes[numECCodeWords - 1 - i] = poly.evaluateAt(field.exp(i + field.generatorBase())); + + // if all syndromes are 0 there is no error to correct + if (std::all_of(syndromes.begin(), syndromes.end(), [](int c) { return c == 0; })) + return true; + + ZX_THREAD_LOCAL GenericGFPoly sigma, omega; + + if (!RunEuclideanAlgorithm(field, std::move(syndromes), sigma, omega)) + return false; + + auto errorLocations = FindErrorLocations(field, sigma); + if (errorLocations.empty()) + return false; + + auto errorMagnitudes = FindErrorMagnitudes(field, omega, errorLocations); + + int msgLen = Size(message); + for (int i = 0; i < Size(errorLocations); ++i) { + int position = msgLen - 1 - field.log(errorLocations[i]); + if (position < 0) + return false; + + message[position] ^= errorMagnitudes[i]; + } + return true; +} + +} // namespace ZXing
