rsdecoder.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /*
  2. Ported to JavaScript by Lazar Laszlo 2011
  3. lazarsoft@gmail.com, www.lazarsoft.info
  4. */
  5. /*
  6. *
  7. * Copyright 2007 ZXing authors
  8. *
  9. * Licensed under the Apache License, Version 2.0 (the "License");
  10. * you may not use this file except in compliance with the License.
  11. * You may obtain a copy of the License at
  12. *
  13. * http://www.apache.org/licenses/LICENSE-2.0
  14. *
  15. * Unless required by applicable law or agreed to in writing, software
  16. * distributed under the License is distributed on an "AS IS" BASIS,
  17. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. * See the License for the specific language governing permissions and
  19. * limitations under the License.
  20. */
  21. import GF256 from './gf256';
  22. import GF256Poly from './gf256poly';
  23. export default function ReedSolomonDecoder(field) {
  24. this.field = field;
  25. }
  26. ReedSolomonDecoder.prototype.decode = function(received, twoS) {
  27. var poly = new GF256Poly(this.field, received);
  28. var syndromeCoefficients = new Array(twoS);
  29. for (var i = 0; i < syndromeCoefficients.length; i++)syndromeCoefficients[i] = 0;
  30. var dataMatrix = false;//this.field.Equals(GF256.DATA_MATRIX_FIELD);
  31. var noError = true;
  32. for (var i = 0; i < twoS; i++) {
  33. // Thanks to sanfordsquires for this fix:
  34. var _eval = poly.evaluateAt(this.field.exp(dataMatrix ? i + 1 : i));
  35. syndromeCoefficients[syndromeCoefficients.length - 1 - i] = _eval;
  36. if (_eval != 0) {
  37. noError = false;
  38. }
  39. }
  40. if (noError) {
  41. return;
  42. }
  43. var syndrome = new GF256Poly(this.field, syndromeCoefficients);
  44. var sigmaOmega = this.runEuclideanAlgorithm(this.field.buildMonomial(twoS, 1), syndrome, twoS);
  45. var sigma = sigmaOmega[0];
  46. var omega = sigmaOmega[1];
  47. var errorLocations = this.findErrorLocations(sigma);
  48. var errorMagnitudes = this.findErrorMagnitudes(omega, errorLocations, dataMatrix);
  49. for (var i = 0; i < errorLocations.length; i++) {
  50. var position = received.length - 1 - this.field.log(errorLocations[i]);
  51. if (position < 0) {
  52. throw "ReedSolomonException Bad error location";
  53. }
  54. received[position] = GF256.prototype.addOrSubtract(received[position], errorMagnitudes[i]);
  55. }
  56. };
  57. ReedSolomonDecoder.prototype.runEuclideanAlgorithm = function(a, b, R) {
  58. // Assume a's degree is >= b's
  59. if (a.Degree < b.Degree) {
  60. var temp = a;
  61. a = b;
  62. b = temp;
  63. }
  64. var rLast = a;
  65. var r = b;
  66. var sLast = this.field.One;
  67. var s = this.field.Zero;
  68. var tLast = this.field.Zero;
  69. var t = this.field.One;
  70. // Run Euclidean algorithm until r's degree is less than R/2
  71. while (r.Degree >= Math.floor(R / 2)) {
  72. var rLastLast = rLast;
  73. var sLastLast = sLast;
  74. var tLastLast = tLast;
  75. rLast = r;
  76. sLast = s;
  77. tLast = t;
  78. // Divide rLastLast by rLast, with quotient in q and remainder in r
  79. if (rLast.Zero) {
  80. // Oops, Euclidean algorithm already terminated?
  81. throw "r_{i-1} was zero";
  82. }
  83. r = rLastLast;
  84. var q = this.field.Zero;
  85. var denominatorLeadingTerm = rLast.getCoefficient(rLast.Degree);
  86. var dltInverse = this.field.inverse(denominatorLeadingTerm);
  87. while (r.Degree >= rLast.Degree && !r.Zero) {
  88. var degreeDiff = r.Degree - rLast.Degree;
  89. var scale = this.field.multiply(r.getCoefficient(r.Degree), dltInverse);
  90. q = q.addOrSubtract(this.field.buildMonomial(degreeDiff, scale));
  91. r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale));
  92. }
  93. s = q.multiply1(sLast).addOrSubtract(sLastLast);
  94. t = q.multiply1(tLast).addOrSubtract(tLastLast);
  95. }
  96. var sigmaTildeAtZero = t.getCoefficient(0);
  97. if (sigmaTildeAtZero == 0) {
  98. throw "ReedSolomonException sigmaTilde(0) was zero";
  99. }
  100. var inverse = this.field.inverse(sigmaTildeAtZero);
  101. var sigma = t.multiply2(inverse);
  102. var omega = r.multiply2(inverse);
  103. return [sigma, omega];
  104. };
  105. ReedSolomonDecoder.prototype.findErrorLocations = function(errorLocator) {
  106. // This is a direct application of Chien's search
  107. var numErrors = errorLocator.Degree;
  108. if (numErrors == 1) {
  109. // shortcut
  110. return new Array(errorLocator.getCoefficient(1));
  111. }
  112. var result = new Array(numErrors);
  113. var e = 0;
  114. for (var i = 1; i < 256 && e < numErrors; i++) {
  115. if (errorLocator.evaluateAt(i) == 0) {
  116. result[e] = this.field.inverse(i);
  117. e++;
  118. }
  119. }
  120. if (e != numErrors) {
  121. throw "Error locator degree does not match number of roots";
  122. }
  123. return result;
  124. };
  125. ReedSolomonDecoder.prototype.findErrorMagnitudes = function(errorEvaluator, errorLocations, dataMatrix) {
  126. // This is directly applying Forney's Formula
  127. var s = errorLocations.length;
  128. var result = new Array(s);
  129. for (var i = 0; i < s; i++) {
  130. var xiInverse = this.field.inverse(errorLocations[i]);
  131. var denominator = 1;
  132. for (var j = 0; j < s; j++) {
  133. if (i != j) {
  134. denominator = this.field.multiply(denominator, GF256.prototype.addOrSubtract(1, this.field.multiply(errorLocations[j], xiInverse)));
  135. }
  136. }
  137. result[i] = this.field.multiply(errorEvaluator.evaluateAt(xiInverse), this.field.inverse(denominator));
  138. // Thanks to sanfordsquires for this fix:
  139. if (dataMatrix) {
  140. result[i] = this.field.multiply(result[i], xiInverse);
  141. }
  142. }
  143. return result;
  144. };