mirror of
https://github.com/zxing/zxing.git
synced 2024-11-10 13:04:05 -08:00
Generator polynomial for reed-Solomon algorithm can now have coefficients in any Gallois fields rather than GF(256) only
git-svn-id: https://zxing.googlecode.com/svn/trunk@1666 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
29dce2a397
commit
5ec9b84660
186
core/src/com/google/zxing/common/reedsolomon/GenericGF.java
Normal file
186
core/src/com/google/zxing/common/reedsolomon/GenericGF.java
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2007 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.google.zxing.common.reedsolomon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>This class contains utility methods for performing mathematical operations over
|
||||||
|
* the Galois Fields. Operations use a given primitive polynomial in calculations.</p>
|
||||||
|
*
|
||||||
|
* <p>Throughout this package, elements of the GF are represented as an <code>int</code>
|
||||||
|
* for convenience and speed (but at the cost of memory).
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Sean Owen
|
||||||
|
* @author David Olivier
|
||||||
|
*/
|
||||||
|
public final class GenericGF {
|
||||||
|
|
||||||
|
public static final GenericGF AZTEC_DATA_12 = new GenericGF(0x1069, 4096); // x^12 + x^6 + x^5 + x^3 + 1
|
||||||
|
public static final GenericGF AZTEC_DATA_10 = new GenericGF(0x409, 1024); // x^10 + x^3 + 1
|
||||||
|
public static final GenericGF AZTEC_DATA_6 = new GenericGF(0x43, 64); // x^6 + x + 1
|
||||||
|
public static final GenericGF AZTEC_PARAM = new GenericGF(0x13, 16); // x^4 + x + 1
|
||||||
|
public static final GenericGF QR_CODE_FIELD_256 = new GenericGF(0x011D, 256); // x^8 + x^4 + x^3 + x^2 + 1
|
||||||
|
public static final GenericGF DATA_MATRIX_FIELD_256 = new GenericGF(0x012D, 256); // x^8 + x^5 + x^3 + x^2 + 1
|
||||||
|
public static final GenericGF AZTEC_DATA_8 = DATA_MATRIX_FIELD_256;
|
||||||
|
|
||||||
|
private static final int INITIALIZATION_THRESHOLD = 0;
|
||||||
|
|
||||||
|
private int[] expTable;
|
||||||
|
private int[] logTable;
|
||||||
|
private GenericGFPoly zero;
|
||||||
|
private GenericGFPoly one;
|
||||||
|
private final int size;
|
||||||
|
private final int primitive;
|
||||||
|
private boolean initialized = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a representation of GF(size) using the given primitive polynomial.
|
||||||
|
*
|
||||||
|
* @param primitive irreducible polynomial whose coefficients are represented by
|
||||||
|
* the bits of an int, where the least-significant bit represents the constant
|
||||||
|
* coefficient
|
||||||
|
*/
|
||||||
|
public GenericGF(int primitive, int size) {
|
||||||
|
this.primitive = primitive;
|
||||||
|
this.size = size;
|
||||||
|
|
||||||
|
if (size <= INITIALIZATION_THRESHOLD){
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize(){
|
||||||
|
expTable = new int[size];
|
||||||
|
logTable = new int[size];
|
||||||
|
int x = 1;
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
expTable[i] = x;
|
||||||
|
x <<= 1; // x = x * 2; we're assuming the generator alpha is 2
|
||||||
|
if (x >= size) {
|
||||||
|
x ^= primitive;
|
||||||
|
x &= size-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < size-1; i++) {
|
||||||
|
logTable[expTable[i]] = i;
|
||||||
|
}
|
||||||
|
// logTable[0] == 0 but this should never be used
|
||||||
|
zero = new GenericGFPoly(this, new int[]{0});
|
||||||
|
one = new GenericGFPoly(this, new int[]{1});
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkInit(){
|
||||||
|
if (!initialized) initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
GenericGFPoly getZero() {
|
||||||
|
checkInit();
|
||||||
|
|
||||||
|
return zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
GenericGFPoly getOne() {
|
||||||
|
checkInit();
|
||||||
|
|
||||||
|
return one;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the monomial representing coefficient * x^degree
|
||||||
|
*/
|
||||||
|
GenericGFPoly buildMonomial(int degree, int coefficient) {
|
||||||
|
checkInit();
|
||||||
|
|
||||||
|
if (degree < 0) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
if (coefficient == 0) {
|
||||||
|
return zero;
|
||||||
|
}
|
||||||
|
int[] coefficients = new int[degree + 1];
|
||||||
|
coefficients[0] = coefficient;
|
||||||
|
return new GenericGFPoly(this, coefficients);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements both addition and subtraction -- they are the same in GF(size).
|
||||||
|
*
|
||||||
|
* @return sum/difference of a and b
|
||||||
|
*/
|
||||||
|
static int addOrSubtract(int a, int b) {
|
||||||
|
return a ^ b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return 2 to the power of a in GF(size)
|
||||||
|
*/
|
||||||
|
int exp(int a) {
|
||||||
|
checkInit();
|
||||||
|
|
||||||
|
return expTable[a];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return base 2 log of a in GF(size)
|
||||||
|
*/
|
||||||
|
int log(int a) {
|
||||||
|
checkInit();
|
||||||
|
|
||||||
|
if (a == 0) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
return logTable[a];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return multiplicative inverse of a
|
||||||
|
*/
|
||||||
|
int inverse(int a) {
|
||||||
|
checkInit();
|
||||||
|
|
||||||
|
if (a == 0) {
|
||||||
|
throw new ArithmeticException();
|
||||||
|
}
|
||||||
|
return expTable[size - logTable[a] - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param a
|
||||||
|
* @param b
|
||||||
|
* @return product of a and b in GF(size)
|
||||||
|
*/
|
||||||
|
int multiply(int a, int b) {
|
||||||
|
checkInit();
|
||||||
|
|
||||||
|
if (a == 0 || b == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a<0 || b <0 || a>=size || b >=size){
|
||||||
|
a++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int logSum = logTable[a] + logTable[b];
|
||||||
|
return expTable[(logSum % size) + logSum / size];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSize(){
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
263
core/src/com/google/zxing/common/reedsolomon/GenericGFPoly.java
Normal file
263
core/src/com/google/zxing/common/reedsolomon/GenericGFPoly.java
Normal file
|
@ -0,0 +1,263 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2007 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.google.zxing.common.reedsolomon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Represents a polynomial whose coefficients are elements of a GF.
|
||||||
|
* Instances of this class are immutable.</p>
|
||||||
|
*
|
||||||
|
* <p>Much credit is due to William Rucklidge since portions of this code are an indirect
|
||||||
|
* port of his C++ Reed-Solomon implementation.</p>
|
||||||
|
*
|
||||||
|
* @author Sean Owen
|
||||||
|
*/
|
||||||
|
final class GenericGFPoly {
|
||||||
|
|
||||||
|
private final GenericGF field;
|
||||||
|
private final int[] coefficients;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param field the {@link GenericGF} instance representing the field to use
|
||||||
|
* to perform computations
|
||||||
|
* @param coefficients coefficients as ints representing elements of GF(size), arranged
|
||||||
|
* from most significant (highest-power term) coefficient to least significant
|
||||||
|
* @throws IllegalArgumentException if argument is null or empty,
|
||||||
|
* or if leading coefficient is 0 and this is not a
|
||||||
|
* constant polynomial (that is, it is not the monomial "0")
|
||||||
|
*/
|
||||||
|
GenericGFPoly(GenericGF field, int[] coefficients) {
|
||||||
|
if (coefficients == null || coefficients.length == 0) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
this.field = field;
|
||||||
|
int coefficientsLength = coefficients.length;
|
||||||
|
if (coefficientsLength > 1 && coefficients[0] == 0) {
|
||||||
|
// Leading term must be non-zero for anything except the constant polynomial "0"
|
||||||
|
int firstNonZero = 1;
|
||||||
|
while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0) {
|
||||||
|
firstNonZero++;
|
||||||
|
}
|
||||||
|
if (firstNonZero == coefficientsLength) {
|
||||||
|
this.coefficients = field.getZero().coefficients;
|
||||||
|
} else {
|
||||||
|
this.coefficients = new int[coefficientsLength - firstNonZero];
|
||||||
|
System.arraycopy(coefficients,
|
||||||
|
firstNonZero,
|
||||||
|
this.coefficients,
|
||||||
|
0,
|
||||||
|
this.coefficients.length);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.coefficients = coefficients;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] getCoefficients() {
|
||||||
|
return coefficients;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return degree of this polynomial
|
||||||
|
*/
|
||||||
|
int getDegree() {
|
||||||
|
return coefficients.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true iff this polynomial is the monomial "0"
|
||||||
|
*/
|
||||||
|
boolean isZero() {
|
||||||
|
return coefficients[0] == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return coefficient of x^degree term in this polynomial
|
||||||
|
*/
|
||||||
|
int getCoefficient(int degree) {
|
||||||
|
return coefficients[coefficients.length - 1 - degree];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return evaluation of this polynomial at a given point
|
||||||
|
*/
|
||||||
|
int evaluateAt(int a) {
|
||||||
|
if (a == 0) {
|
||||||
|
// Just return the x^0 coefficient
|
||||||
|
return getCoefficient(0);
|
||||||
|
}
|
||||||
|
int size = coefficients.length;
|
||||||
|
if (a == 1) {
|
||||||
|
// Just the sum of the coefficients
|
||||||
|
int result = 0;
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
result = GenericGF.addOrSubtract(result, coefficients[i]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
int result = coefficients[0];
|
||||||
|
for (int i = 1; i < size; i++) {
|
||||||
|
result = GenericGF.addOrSubtract(field.multiply(a, result), coefficients[i]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
GenericGFPoly addOrSubtract(GenericGFPoly other) {
|
||||||
|
if (!field.equals(other.field)) {
|
||||||
|
throw new IllegalArgumentException("GenericGFPolys do not have same GenericGF field");
|
||||||
|
}
|
||||||
|
if (isZero()) {
|
||||||
|
return other;
|
||||||
|
}
|
||||||
|
if (other.isZero()) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] smallerCoefficients = this.coefficients;
|
||||||
|
int[] largerCoefficients = other.coefficients;
|
||||||
|
if (smallerCoefficients.length > largerCoefficients.length) {
|
||||||
|
int[] temp = smallerCoefficients;
|
||||||
|
smallerCoefficients = largerCoefficients;
|
||||||
|
largerCoefficients = temp;
|
||||||
|
}
|
||||||
|
int[] sumDiff = new int[largerCoefficients.length];
|
||||||
|
int lengthDiff = largerCoefficients.length - smallerCoefficients.length;
|
||||||
|
// Copy high-order terms only found in higher-degree polynomial's coefficients
|
||||||
|
System.arraycopy(largerCoefficients, 0, sumDiff, 0, lengthDiff);
|
||||||
|
|
||||||
|
for (int i = lengthDiff; i < largerCoefficients.length; i++) {
|
||||||
|
sumDiff[i] = GenericGF.addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new GenericGFPoly(field, sumDiff);
|
||||||
|
}
|
||||||
|
|
||||||
|
GenericGFPoly multiply(GenericGFPoly other) {
|
||||||
|
if (!field.equals(other.field)) {
|
||||||
|
throw new IllegalArgumentException("GenericGFPolys do not have same GenericGF field");
|
||||||
|
}
|
||||||
|
if (isZero() || other.isZero()) {
|
||||||
|
return field.getZero();
|
||||||
|
}
|
||||||
|
int[] aCoefficients = this.coefficients;
|
||||||
|
int aLength = aCoefficients.length;
|
||||||
|
int[] bCoefficients = other.coefficients;
|
||||||
|
int bLength = bCoefficients.length;
|
||||||
|
int[] product = new int[aLength + bLength - 1];
|
||||||
|
for (int i = 0; i < aLength; i++) {
|
||||||
|
int aCoeff = aCoefficients[i];
|
||||||
|
for (int j = 0; j < bLength; j++) {
|
||||||
|
product[i + j] = GenericGF.addOrSubtract(product[i + j],
|
||||||
|
field.multiply(aCoeff, bCoefficients[j]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new GenericGFPoly(field, product);
|
||||||
|
}
|
||||||
|
|
||||||
|
GenericGFPoly multiply(int scalar) {
|
||||||
|
if (scalar == 0) {
|
||||||
|
return field.getZero();
|
||||||
|
}
|
||||||
|
if (scalar == 1) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
int size = coefficients.length;
|
||||||
|
int[] product = new int[size];
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
product[i] = field.multiply(coefficients[i], scalar);
|
||||||
|
}
|
||||||
|
return new GenericGFPoly(field, product);
|
||||||
|
}
|
||||||
|
|
||||||
|
GenericGFPoly multiplyByMonomial(int degree, int coefficient) {
|
||||||
|
if (degree < 0) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
if (coefficient == 0) {
|
||||||
|
return field.getZero();
|
||||||
|
}
|
||||||
|
int size = coefficients.length;
|
||||||
|
int[] product = new int[size + degree];
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
product[i] = field.multiply(coefficients[i], coefficient);
|
||||||
|
}
|
||||||
|
return new GenericGFPoly(field, product);
|
||||||
|
}
|
||||||
|
|
||||||
|
GenericGFPoly[] divide(GenericGFPoly other) {
|
||||||
|
if (!field.equals(other.field)) {
|
||||||
|
throw new IllegalArgumentException("GenericGFPolys do not have same GenericGF field");
|
||||||
|
}
|
||||||
|
if (other.isZero()) {
|
||||||
|
throw new IllegalArgumentException("Divide by 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
GenericGFPoly quotient = field.getZero();
|
||||||
|
GenericGFPoly remainder = this;
|
||||||
|
|
||||||
|
int denominatorLeadingTerm = other.getCoefficient(other.getDegree());
|
||||||
|
int inverseDenominatorLeadingTerm = field.inverse(denominatorLeadingTerm);
|
||||||
|
|
||||||
|
while (remainder.getDegree() >= other.getDegree() && !remainder.isZero()) {
|
||||||
|
int degreeDifference = remainder.getDegree() - other.getDegree();
|
||||||
|
int scale = field.multiply(remainder.getCoefficient(remainder.getDegree()), inverseDenominatorLeadingTerm);
|
||||||
|
GenericGFPoly term = other.multiplyByMonomial(degreeDifference, scale);
|
||||||
|
GenericGFPoly iterationQuotient = field.buildMonomial(degreeDifference, scale);
|
||||||
|
quotient = quotient.addOrSubtract(iterationQuotient);
|
||||||
|
remainder = remainder.addOrSubtract(term);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new GenericGFPoly[] { quotient, remainder };
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
StringBuffer result = new StringBuffer(8 * getDegree());
|
||||||
|
for (int degree = getDegree(); degree >= 0; degree--) {
|
||||||
|
int coefficient = getCoefficient(degree);
|
||||||
|
if (coefficient != 0) {
|
||||||
|
if (coefficient < 0) {
|
||||||
|
result.append(" - ");
|
||||||
|
coefficient = -coefficient;
|
||||||
|
} else {
|
||||||
|
if (result.length() > 0) {
|
||||||
|
result.append(" + ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (degree == 0 || coefficient != 1) {
|
||||||
|
int alphaPower = field.log(coefficient);
|
||||||
|
if (alphaPower == 0) {
|
||||||
|
result.append('1');
|
||||||
|
} else if (alphaPower == 1) {
|
||||||
|
result.append('a');
|
||||||
|
} else {
|
||||||
|
result.append("a^");
|
||||||
|
result.append(alphaPower);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (degree != 0) {
|
||||||
|
if (degree == 1) {
|
||||||
|
result.append('x');
|
||||||
|
} else {
|
||||||
|
result.append("x^");
|
||||||
|
result.append(degree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -40,9 +40,9 @@ package com.google.zxing.common.reedsolomon;
|
||||||
*/
|
*/
|
||||||
public final class ReedSolomonDecoder {
|
public final class ReedSolomonDecoder {
|
||||||
|
|
||||||
private final GF256 field;
|
private final GenericGF field;
|
||||||
|
|
||||||
public ReedSolomonDecoder(GF256 field) {
|
public ReedSolomonDecoder(GenericGF field) {
|
||||||
this.field = field;
|
this.field = field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,9 +56,9 @@ public final class ReedSolomonDecoder {
|
||||||
* @throws ReedSolomonException if decoding fails for any reason
|
* @throws ReedSolomonException if decoding fails for any reason
|
||||||
*/
|
*/
|
||||||
public void decode(int[] received, int twoS) throws ReedSolomonException {
|
public void decode(int[] received, int twoS) throws ReedSolomonException {
|
||||||
GF256Poly poly = new GF256Poly(field, received);
|
GenericGFPoly poly = new GenericGFPoly(field, received);
|
||||||
int[] syndromeCoefficients = new int[twoS];
|
int[] syndromeCoefficients = new int[twoS];
|
||||||
boolean dataMatrix = field.equals(GF256.DATA_MATRIX_FIELD);
|
boolean dataMatrix = field.equals(GenericGF.DATA_MATRIX_FIELD_256);
|
||||||
boolean noError = true;
|
boolean noError = true;
|
||||||
for (int i = 0; i < twoS; i++) {
|
for (int i = 0; i < twoS; i++) {
|
||||||
// Thanks to sanfordsquires for this fix:
|
// Thanks to sanfordsquires for this fix:
|
||||||
|
@ -71,11 +71,11 @@ public final class ReedSolomonDecoder {
|
||||||
if (noError) {
|
if (noError) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GF256Poly syndrome = new GF256Poly(field, syndromeCoefficients);
|
GenericGFPoly syndrome = new GenericGFPoly(field, syndromeCoefficients);
|
||||||
GF256Poly[] sigmaOmega =
|
GenericGFPoly[] sigmaOmega =
|
||||||
runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS);
|
runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS);
|
||||||
GF256Poly sigma = sigmaOmega[0];
|
GenericGFPoly sigma = sigmaOmega[0];
|
||||||
GF256Poly omega = sigmaOmega[1];
|
GenericGFPoly omega = sigmaOmega[1];
|
||||||
int[] errorLocations = findErrorLocations(sigma);
|
int[] errorLocations = findErrorLocations(sigma);
|
||||||
int[] errorMagnitudes = findErrorMagnitudes(omega, errorLocations, dataMatrix);
|
int[] errorMagnitudes = findErrorMagnitudes(omega, errorLocations, dataMatrix);
|
||||||
for (int i = 0; i < errorLocations.length; i++) {
|
for (int i = 0; i < errorLocations.length; i++) {
|
||||||
|
@ -83,31 +83,31 @@ public final class ReedSolomonDecoder {
|
||||||
if (position < 0) {
|
if (position < 0) {
|
||||||
throw new ReedSolomonException("Bad error location");
|
throw new ReedSolomonException("Bad error location");
|
||||||
}
|
}
|
||||||
received[position] = GF256.addOrSubtract(received[position], errorMagnitudes[i]);
|
received[position] = GenericGF.addOrSubtract(received[position], errorMagnitudes[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private GF256Poly[] runEuclideanAlgorithm(GF256Poly a, GF256Poly b, int R)
|
private GenericGFPoly[] runEuclideanAlgorithm(GenericGFPoly a, GenericGFPoly b, int R)
|
||||||
throws ReedSolomonException {
|
throws ReedSolomonException {
|
||||||
// Assume a's degree is >= b's
|
// Assume a's degree is >= b's
|
||||||
if (a.getDegree() < b.getDegree()) {
|
if (a.getDegree() < b.getDegree()) {
|
||||||
GF256Poly temp = a;
|
GenericGFPoly temp = a;
|
||||||
a = b;
|
a = b;
|
||||||
b = temp;
|
b = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
GF256Poly rLast = a;
|
GenericGFPoly rLast = a;
|
||||||
GF256Poly r = b;
|
GenericGFPoly r = b;
|
||||||
GF256Poly sLast = field.getOne();
|
GenericGFPoly sLast = field.getOne();
|
||||||
GF256Poly s = field.getZero();
|
GenericGFPoly s = field.getZero();
|
||||||
GF256Poly tLast = field.getZero();
|
GenericGFPoly tLast = field.getZero();
|
||||||
GF256Poly t = field.getOne();
|
GenericGFPoly t = field.getOne();
|
||||||
|
|
||||||
// Run Euclidean algorithm until r's degree is less than R/2
|
// Run Euclidean algorithm until r's degree is less than R/2
|
||||||
while (r.getDegree() >= R / 2) {
|
while (r.getDegree() >= R / 2) {
|
||||||
GF256Poly rLastLast = rLast;
|
GenericGFPoly rLastLast = rLast;
|
||||||
GF256Poly sLastLast = sLast;
|
GenericGFPoly sLastLast = sLast;
|
||||||
GF256Poly tLastLast = tLast;
|
GenericGFPoly tLastLast = tLast;
|
||||||
rLast = r;
|
rLast = r;
|
||||||
sLast = s;
|
sLast = s;
|
||||||
tLast = t;
|
tLast = t;
|
||||||
|
@ -118,7 +118,7 @@ public final class ReedSolomonDecoder {
|
||||||
throw new ReedSolomonException("r_{i-1} was zero");
|
throw new ReedSolomonException("r_{i-1} was zero");
|
||||||
}
|
}
|
||||||
r = rLastLast;
|
r = rLastLast;
|
||||||
GF256Poly q = field.getZero();
|
GenericGFPoly q = field.getZero();
|
||||||
int denominatorLeadingTerm = rLast.getCoefficient(rLast.getDegree());
|
int denominatorLeadingTerm = rLast.getCoefficient(rLast.getDegree());
|
||||||
int dltInverse = field.inverse(denominatorLeadingTerm);
|
int dltInverse = field.inverse(denominatorLeadingTerm);
|
||||||
while (r.getDegree() >= rLast.getDegree() && !r.isZero()) {
|
while (r.getDegree() >= rLast.getDegree() && !r.isZero()) {
|
||||||
|
@ -138,12 +138,12 @@ public final class ReedSolomonDecoder {
|
||||||
}
|
}
|
||||||
|
|
||||||
int inverse = field.inverse(sigmaTildeAtZero);
|
int inverse = field.inverse(sigmaTildeAtZero);
|
||||||
GF256Poly sigma = t.multiply(inverse);
|
GenericGFPoly sigma = t.multiply(inverse);
|
||||||
GF256Poly omega = r.multiply(inverse);
|
GenericGFPoly omega = r.multiply(inverse);
|
||||||
return new GF256Poly[]{sigma, omega};
|
return new GenericGFPoly[]{sigma, omega};
|
||||||
}
|
}
|
||||||
|
|
||||||
private int[] findErrorLocations(GF256Poly errorLocator) throws ReedSolomonException {
|
private int[] findErrorLocations(GenericGFPoly errorLocator) throws ReedSolomonException {
|
||||||
// This is a direct application of Chien's search
|
// This is a direct application of Chien's search
|
||||||
int numErrors = errorLocator.getDegree();
|
int numErrors = errorLocator.getDegree();
|
||||||
if (numErrors == 1) { // shortcut
|
if (numErrors == 1) { // shortcut
|
||||||
|
@ -151,7 +151,7 @@ public final class ReedSolomonDecoder {
|
||||||
}
|
}
|
||||||
int[] result = new int[numErrors];
|
int[] result = new int[numErrors];
|
||||||
int e = 0;
|
int e = 0;
|
||||||
for (int i = 1; i < 256 && e < numErrors; i++) {
|
for (int i = 1; i < field.getSize() && e < numErrors; i++) {
|
||||||
if (errorLocator.evaluateAt(i) == 0) {
|
if (errorLocator.evaluateAt(i) == 0) {
|
||||||
result[e] = field.inverse(i);
|
result[e] = field.inverse(i);
|
||||||
e++;
|
e++;
|
||||||
|
@ -163,7 +163,7 @@ public final class ReedSolomonDecoder {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int[] findErrorMagnitudes(GF256Poly errorEvaluator, int[] errorLocations, boolean dataMatrix) {
|
private int[] findErrorMagnitudes(GenericGFPoly errorEvaluator, int[] errorLocations, boolean dataMatrix) {
|
||||||
// This is directly applying Forney's Formula
|
// This is directly applying Forney's Formula
|
||||||
int s = errorLocations.length;
|
int s = errorLocations.length;
|
||||||
int[] result = new int[s];
|
int[] result = new int[s];
|
||||||
|
@ -173,7 +173,7 @@ public final class ReedSolomonDecoder {
|
||||||
for (int j = 0; j < s; j++) {
|
for (int j = 0; j < s; j++) {
|
||||||
if (i != j) {
|
if (i != j) {
|
||||||
//denominator = field.multiply(denominator,
|
//denominator = field.multiply(denominator,
|
||||||
// GF256.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse)));
|
// GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse)));
|
||||||
// Above should work but fails on some Apple and Linux JDKs due to a Hotspot bug.
|
// Above should work but fails on some Apple and Linux JDKs due to a Hotspot bug.
|
||||||
// Below is a funny-looking workaround from Steven Parkes
|
// Below is a funny-looking workaround from Steven Parkes
|
||||||
int term = field.multiply(errorLocations[j], xiInverse);
|
int term = field.multiply(errorLocations[j], xiInverse);
|
||||||
|
|
|
@ -26,28 +26,28 @@ import java.util.Vector;
|
||||||
*/
|
*/
|
||||||
public final class ReedSolomonEncoder {
|
public final class ReedSolomonEncoder {
|
||||||
|
|
||||||
private final GF256 field;
|
private final GenericGF field;
|
||||||
private final Vector cachedGenerators;
|
private final Vector cachedGenerators;
|
||||||
|
|
||||||
public ReedSolomonEncoder(GF256 field) {
|
public ReedSolomonEncoder(GenericGF field) {
|
||||||
if (!GF256.QR_CODE_FIELD.equals(field)) {
|
if (!GenericGF.QR_CODE_FIELD_256.equals(field)) {
|
||||||
throw new IllegalArgumentException("Only QR Code is supported at this time");
|
throw new IllegalArgumentException("Only QR Code is supported at this time");
|
||||||
}
|
}
|
||||||
this.field = field;
|
this.field = field;
|
||||||
this.cachedGenerators = new Vector();
|
this.cachedGenerators = new Vector();
|
||||||
cachedGenerators.addElement(new GF256Poly(field, new int[] { 1 }));
|
cachedGenerators.addElement(new GenericGFPoly(field, new int[] { 1 }));
|
||||||
}
|
}
|
||||||
|
|
||||||
private GF256Poly buildGenerator(int degree) {
|
private GenericGFPoly buildGenerator(int degree) {
|
||||||
if (degree >= cachedGenerators.size()) {
|
if (degree >= cachedGenerators.size()) {
|
||||||
GF256Poly lastGenerator = (GF256Poly) cachedGenerators.elementAt(cachedGenerators.size() - 1);
|
GenericGFPoly lastGenerator = (GenericGFPoly) cachedGenerators.elementAt(cachedGenerators.size() - 1);
|
||||||
for (int d = cachedGenerators.size(); d <= degree; d++) {
|
for (int d = cachedGenerators.size(); d <= degree; d++) {
|
||||||
GF256Poly nextGenerator = lastGenerator.multiply(new GF256Poly(field, new int[] { 1, field.exp(d - 1) }));
|
GenericGFPoly nextGenerator = lastGenerator.multiply(new GenericGFPoly(field, new int[] { 1, field.exp(d - 1) }));
|
||||||
cachedGenerators.addElement(nextGenerator);
|
cachedGenerators.addElement(nextGenerator);
|
||||||
lastGenerator = nextGenerator;
|
lastGenerator = nextGenerator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (GF256Poly) cachedGenerators.elementAt(degree);
|
return (GenericGFPoly) cachedGenerators.elementAt(degree);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void encode(int[] toEncode, int ecBytes) {
|
public void encode(int[] toEncode, int ecBytes) {
|
||||||
|
@ -58,12 +58,12 @@ public final class ReedSolomonEncoder {
|
||||||
if (dataBytes <= 0) {
|
if (dataBytes <= 0) {
|
||||||
throw new IllegalArgumentException("No data bytes provided");
|
throw new IllegalArgumentException("No data bytes provided");
|
||||||
}
|
}
|
||||||
GF256Poly generator = buildGenerator(ecBytes);
|
GenericGFPoly generator = buildGenerator(ecBytes);
|
||||||
int[] infoCoefficients = new int[dataBytes];
|
int[] infoCoefficients = new int[dataBytes];
|
||||||
System.arraycopy(toEncode, 0, infoCoefficients, 0, dataBytes);
|
System.arraycopy(toEncode, 0, infoCoefficients, 0, dataBytes);
|
||||||
GF256Poly info = new GF256Poly(field, infoCoefficients);
|
GenericGFPoly info = new GenericGFPoly(field, infoCoefficients);
|
||||||
info = info.multiplyByMonomial(ecBytes, 1);
|
info = info.multiplyByMonomial(ecBytes, 1);
|
||||||
GF256Poly remainder = info.divide(generator)[1];
|
GenericGFPoly remainder = info.divide(generator)[1];
|
||||||
int[] coefficients = remainder.getCoefficients();
|
int[] coefficients = remainder.getCoefficients();
|
||||||
int numZeroCoefficients = ecBytes - coefficients.length;
|
int numZeroCoefficients = ecBytes - coefficients.length;
|
||||||
for (int i = 0; i < numZeroCoefficients; i++) {
|
for (int i = 0; i < numZeroCoefficients; i++) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ import com.google.zxing.ChecksumException;
|
||||||
import com.google.zxing.FormatException;
|
import com.google.zxing.FormatException;
|
||||||
import com.google.zxing.common.BitMatrix;
|
import com.google.zxing.common.BitMatrix;
|
||||||
import com.google.zxing.common.DecoderResult;
|
import com.google.zxing.common.DecoderResult;
|
||||||
import com.google.zxing.common.reedsolomon.GF256;
|
import com.google.zxing.common.reedsolomon.GenericGF;
|
||||||
import com.google.zxing.common.reedsolomon.ReedSolomonDecoder;
|
import com.google.zxing.common.reedsolomon.ReedSolomonDecoder;
|
||||||
import com.google.zxing.common.reedsolomon.ReedSolomonException;
|
import com.google.zxing.common.reedsolomon.ReedSolomonException;
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ public final class Decoder {
|
||||||
private final ReedSolomonDecoder rsDecoder;
|
private final ReedSolomonDecoder rsDecoder;
|
||||||
|
|
||||||
public Decoder() {
|
public Decoder() {
|
||||||
rsDecoder = new ReedSolomonDecoder(GF256.DATA_MATRIX_FIELD);
|
rsDecoder = new ReedSolomonDecoder(GenericGF.DATA_MATRIX_FIELD_256);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -21,7 +21,7 @@ import com.google.zxing.FormatException;
|
||||||
import com.google.zxing.NotFoundException;
|
import com.google.zxing.NotFoundException;
|
||||||
import com.google.zxing.common.BitMatrix;
|
import com.google.zxing.common.BitMatrix;
|
||||||
import com.google.zxing.common.DecoderResult;
|
import com.google.zxing.common.DecoderResult;
|
||||||
import com.google.zxing.common.reedsolomon.GF256;
|
import com.google.zxing.common.reedsolomon.GenericGF;
|
||||||
import com.google.zxing.common.reedsolomon.ReedSolomonDecoder;
|
import com.google.zxing.common.reedsolomon.ReedSolomonDecoder;
|
||||||
import com.google.zxing.common.reedsolomon.ReedSolomonException;
|
import com.google.zxing.common.reedsolomon.ReedSolomonException;
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ public final class Decoder {
|
||||||
private final ReedSolomonDecoder rsDecoder;
|
private final ReedSolomonDecoder rsDecoder;
|
||||||
|
|
||||||
public Decoder() {
|
public Decoder() {
|
||||||
rsDecoder = new ReedSolomonDecoder(GF256.QR_CODE_FIELD);
|
rsDecoder = new ReedSolomonDecoder(GenericGF.QR_CODE_FIELD_256);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DecoderResult decode(boolean[][] image)
|
public DecoderResult decode(boolean[][] image)
|
||||||
|
|
|
@ -21,7 +21,7 @@ import com.google.zxing.WriterException;
|
||||||
import com.google.zxing.common.BitArray;
|
import com.google.zxing.common.BitArray;
|
||||||
import com.google.zxing.common.CharacterSetECI;
|
import com.google.zxing.common.CharacterSetECI;
|
||||||
import com.google.zxing.common.ECI;
|
import com.google.zxing.common.ECI;
|
||||||
import com.google.zxing.common.reedsolomon.GF256;
|
import com.google.zxing.common.reedsolomon.GenericGF;
|
||||||
import com.google.zxing.common.reedsolomon.ReedSolomonEncoder;
|
import com.google.zxing.common.reedsolomon.ReedSolomonEncoder;
|
||||||
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
|
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
|
||||||
import com.google.zxing.qrcode.decoder.Mode;
|
import com.google.zxing.qrcode.decoder.Mode;
|
||||||
|
@ -414,7 +414,7 @@ public final class Encoder {
|
||||||
for (int i = 0; i < numDataBytes; i++) {
|
for (int i = 0; i < numDataBytes; i++) {
|
||||||
toEncode[i] = dataBytes[i] & 0xFF;
|
toEncode[i] = dataBytes[i] & 0xFF;
|
||||||
}
|
}
|
||||||
new ReedSolomonEncoder(GF256.QR_CODE_FIELD).encode(toEncode, numEcBytesInBlock);
|
new ReedSolomonEncoder(GenericGF.QR_CODE_FIELD_256).encode(toEncode, numEcBytesInBlock);
|
||||||
|
|
||||||
byte[] ecBytes = new byte[numEcBytesInBlock];
|
byte[] ecBytes = new byte[numEcBytesInBlock];
|
||||||
for (int i = 0; i < numEcBytesInBlock; i++) {
|
for (int i = 0; i < numEcBytesInBlock; i++) {
|
||||||
|
|
|
@ -42,7 +42,7 @@ abstract class AbstractReedSolomonTestCase extends Assert {
|
||||||
static void doTestQRCodeEncoding(int[] dataBytes, int[] expectedECBytes) {
|
static void doTestQRCodeEncoding(int[] dataBytes, int[] expectedECBytes) {
|
||||||
int[] toEncode = new int[dataBytes.length + expectedECBytes.length];
|
int[] toEncode = new int[dataBytes.length + expectedECBytes.length];
|
||||||
System.arraycopy(dataBytes, 0, toEncode, 0, dataBytes.length);
|
System.arraycopy(dataBytes, 0, toEncode, 0, dataBytes.length);
|
||||||
new ReedSolomonEncoder(GF256.QR_CODE_FIELD).encode(toEncode, expectedECBytes.length);
|
new ReedSolomonEncoder(GenericGF.QR_CODE_FIELD_256).encode(toEncode, expectedECBytes.length);
|
||||||
assertArraysEqual(dataBytes, 0, toEncode, 0, dataBytes.length);
|
assertArraysEqual(dataBytes, 0, toEncode, 0, dataBytes.length);
|
||||||
assertArraysEqual(expectedECBytes, 0, toEncode, dataBytes.length, expectedECBytes.length);
|
assertArraysEqual(expectedECBytes, 0, toEncode, dataBytes.length, expectedECBytes.length);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ public final class ReedSolomonDecoderDataMatrixTestCase extends AbstractReedSolo
|
||||||
private static final int DM_CODE_ECC_BYTES = DM_CODE_TEST_WITH_EC.length - DM_CODE_TEST.length;
|
private static final int DM_CODE_ECC_BYTES = DM_CODE_TEST_WITH_EC.length - DM_CODE_TEST.length;
|
||||||
private static final int DM_CODE_CORRECTABLE = DM_CODE_ECC_BYTES / 2;
|
private static final int DM_CODE_CORRECTABLE = DM_CODE_ECC_BYTES / 2;
|
||||||
|
|
||||||
private final ReedSolomonDecoder dmRSDecoder = new ReedSolomonDecoder(GF256.DATA_MATRIX_FIELD);
|
private final ReedSolomonDecoder dmRSDecoder = new ReedSolomonDecoder(GenericGF.DATA_MATRIX_FIELD_256);
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoError() throws ReedSolomonException {
|
public void testNoError() throws ReedSolomonException {
|
||||||
|
|
|
@ -36,7 +36,7 @@ public final class ReedSolomonDecoderQRCodeTestCase extends AbstractReedSolomonT
|
||||||
private static final int QR_CODE_ECC_BYTES = QR_CODE_TEST_WITH_EC.length - QR_CODE_TEST.length;
|
private static final int QR_CODE_ECC_BYTES = QR_CODE_TEST_WITH_EC.length - QR_CODE_TEST.length;
|
||||||
private static final int QR_CODE_CORRECTABLE = QR_CODE_ECC_BYTES / 2;
|
private static final int QR_CODE_CORRECTABLE = QR_CODE_ECC_BYTES / 2;
|
||||||
|
|
||||||
private final ReedSolomonDecoder qrRSDecoder = new ReedSolomonDecoder(GF256.QR_CODE_FIELD);
|
private final ReedSolomonDecoder qrRSDecoder = new ReedSolomonDecoder(GenericGF.QR_CODE_FIELD_256);
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoError() throws ReedSolomonException {
|
public void testNoError() throws ReedSolomonException {
|
||||||
|
|
|
@ -42,8 +42,8 @@ public final class ReedSolomonEncoderQRCodeTestCase extends AbstractReedSolomonT
|
||||||
@Test
|
@Test
|
||||||
public void testQRCodeVersusDecoder() throws Exception {
|
public void testQRCodeVersusDecoder() throws Exception {
|
||||||
Random random = getRandom();
|
Random random = getRandom();
|
||||||
ReedSolomonEncoder encoder = new ReedSolomonEncoder(GF256.QR_CODE_FIELD);
|
ReedSolomonEncoder encoder = new ReedSolomonEncoder(GenericGF.QR_CODE_FIELD_256);
|
||||||
ReedSolomonDecoder decoder = new ReedSolomonDecoder(GF256.QR_CODE_FIELD);
|
ReedSolomonDecoder decoder = new ReedSolomonDecoder(GenericGF.QR_CODE_FIELD_256);
|
||||||
for (int i = 0; i < 100; i++) {
|
for (int i = 0; i < 100; i++) {
|
||||||
int size = random.nextInt(1000);
|
int size = random.nextInt(1000);
|
||||||
int[] toEncode = new int[size];
|
int[] toEncode = new int[size];
|
||||||
|
|
Loading…
Reference in a new issue