Mercurial > hgrepos > Python2 > PyMuPDF
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /* | |
| 2 * Copyright 2016 Nu-book Inc. | |
| 3 * Copyright 2016 ZXing authors | |
| 4 * Copyright 2017 Axel Waggershauser | |
| 5 */ | |
| 6 // SPDX-License-Identifier: Apache-2.0 | |
| 7 | |
| 8 #include "ReedSolomonDecoder.h" | |
| 9 | |
| 10 #include "GenericGF.h" | |
| 11 #include "ZXConfig.h" | |
| 12 | |
| 13 #include <algorithm> | |
| 14 #include <stdexcept> | |
| 15 #include <utility> | |
| 16 | |
| 17 namespace ZXing { | |
| 18 | |
| 19 static bool | |
| 20 RunEuclideanAlgorithm(const GenericGF& field, std::vector<int>&& rCoefs, GenericGFPoly& sigma, GenericGFPoly& omega) | |
| 21 { | |
| 22 int R = Size(rCoefs); // == numECCodeWords | |
| 23 GenericGFPoly r(field, std::move(rCoefs)); | |
| 24 GenericGFPoly& tLast = omega.setField(field); | |
| 25 GenericGFPoly& t = sigma.setField(field); | |
| 26 ZX_THREAD_LOCAL GenericGFPoly q, rLast; | |
| 27 | |
| 28 rLast.setField(field); | |
| 29 q.setField(field); | |
| 30 | |
| 31 rLast.setMonomial(1, R); | |
| 32 tLast.setMonomial(0); | |
| 33 t.setMonomial(1); | |
| 34 | |
| 35 // Assume r's degree is < rLast's | |
| 36 if (r.degree() >= rLast.degree()) | |
| 37 swap(r, rLast); | |
| 38 | |
| 39 // Run Euclidean algorithm until r's degree is less than R/2 | |
| 40 while (r.degree() >= R / 2) { | |
| 41 swap(tLast, t); | |
| 42 swap(rLast, r); | |
| 43 | |
| 44 // Divide rLastLast by rLast, with quotient in q and remainder in r | |
| 45 if (rLast.isZero()) | |
| 46 return false; // Oops, Euclidean algorithm already terminated? | |
| 47 | |
| 48 r.divide(rLast, q); | |
| 49 | |
| 50 q.multiply(tLast); | |
| 51 q.addOrSubtract(t); | |
| 52 swap(t, q); // t = q | |
| 53 | |
| 54 if (r.degree() >= rLast.degree()) | |
| 55 throw std::runtime_error("Division algorithm failed to reduce polynomial?"); | |
| 56 } | |
| 57 | |
| 58 int sigmaTildeAtZero = t.constant(); | |
| 59 if (sigmaTildeAtZero == 0) | |
| 60 return false; | |
| 61 | |
| 62 int inverse = field.inverse(sigmaTildeAtZero); | |
| 63 t.multiplyByMonomial(inverse); | |
| 64 r.multiplyByMonomial(inverse); | |
| 65 | |
| 66 // sigma is t | |
| 67 omega = std::move(r); | |
| 68 return true; | |
| 69 } | |
| 70 | |
| 71 static std::vector<int> | |
| 72 FindErrorLocations(const GenericGF& field, const GenericGFPoly& errorLocator) | |
| 73 { | |
| 74 // This is a direct application of Chien's search | |
| 75 int numErrors = errorLocator.degree(); | |
| 76 std::vector<int> res; | |
| 77 res.reserve(numErrors); | |
| 78 | |
| 79 for (int i = 1; i < field.size() && Size(res) < numErrors; i++) | |
| 80 if (errorLocator.evaluateAt(i) == 0) | |
| 81 res.push_back(field.inverse(i)); | |
| 82 | |
| 83 if (Size(res) != numErrors) | |
| 84 return {}; // Error locator degree does not match number of roots | |
| 85 | |
| 86 return res; | |
| 87 } | |
| 88 | |
| 89 static std::vector<int> | |
| 90 FindErrorMagnitudes(const GenericGF& field, const GenericGFPoly& errorEvaluator, const std::vector<int>& errorLocations) | |
| 91 { | |
| 92 // This is directly applying Forney's Formula | |
| 93 int s = Size(errorLocations); | |
| 94 std::vector<int> res(s); | |
| 95 for (int i = 0; i < s; ++i) { | |
| 96 int xiInverse = field.inverse(errorLocations[i]); | |
| 97 int denom = 1; | |
| 98 for (int j = 0; j < s; ++j) | |
| 99 if (i != j) | |
| 100 denom = field.multiply(denom, 1 ^ field.multiply(errorLocations[j], xiInverse)); | |
| 101 res[i] = field.multiply(errorEvaluator.evaluateAt(xiInverse), field.inverse(denom)); | |
| 102 if (field.generatorBase() != 0) | |
| 103 res[i] = field.multiply(res[i], xiInverse); | |
| 104 } | |
| 105 return res; | |
| 106 } | |
| 107 | |
| 108 bool | |
| 109 ReedSolomonDecode(const GenericGF& field, std::vector<int>& message, int numECCodeWords) | |
| 110 { | |
| 111 GenericGFPoly poly(field, message); | |
| 112 | |
| 113 std::vector<int> syndromes(numECCodeWords); | |
| 114 for (int i = 0; i < numECCodeWords; i++) | |
| 115 syndromes[numECCodeWords - 1 - i] = poly.evaluateAt(field.exp(i + field.generatorBase())); | |
| 116 | |
| 117 // if all syndromes are 0 there is no error to correct | |
| 118 if (std::all_of(syndromes.begin(), syndromes.end(), [](int c) { return c == 0; })) | |
| 119 return true; | |
| 120 | |
| 121 ZX_THREAD_LOCAL GenericGFPoly sigma, omega; | |
| 122 | |
| 123 if (!RunEuclideanAlgorithm(field, std::move(syndromes), sigma, omega)) | |
| 124 return false; | |
| 125 | |
| 126 auto errorLocations = FindErrorLocations(field, sigma); | |
| 127 if (errorLocations.empty()) | |
| 128 return false; | |
| 129 | |
| 130 auto errorMagnitudes = FindErrorMagnitudes(field, omega, errorLocations); | |
| 131 | |
| 132 int msgLen = Size(message); | |
| 133 for (int i = 0; i < Size(errorLocations); ++i) { | |
| 134 int position = msgLen - 1 - field.log(errorLocations[i]); | |
| 135 if (position < 0) | |
| 136 return false; | |
| 137 | |
| 138 message[position] ^= errorMagnitudes[i]; | |
| 139 } | |
| 140 return true; | |
| 141 } | |
| 142 | |
| 143 } // namespace ZXing |
