mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
updated all actionscript files in accordance with the core library revision 1901
git-svn-id: https://zxing.googlecode.com/svn/trunk@2112 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
aa33b1cd04
commit
9f032621f9
|
@ -0,0 +1,199 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
{
|
||||||
|
|
||||||
|
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <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 class GenericGF
|
||||||
|
{
|
||||||
|
|
||||||
|
public static var AZTEC_DATA_12:GenericGF = new GenericGF(0x1069, 4096); // x^12 + x^6 + x^5 + x^3 + 1
|
||||||
|
public static var AZTEC_DATA_10:GenericGF = new GenericGF(0x409, 1024); // x^10 + x^3 + 1
|
||||||
|
public static var AZTEC_DATA_6:GenericGF = new GenericGF(0x43, 64); // x^6 + x + 1
|
||||||
|
public static var AZTEC_PARAM:GenericGF = new GenericGF(0x13, 16); // x^4 + x + 1
|
||||||
|
public static var QR_CODE_FIELD_256:GenericGF = new GenericGF(0x011D, 256); // x^8 + x^4 + x^3 + x^2 + 1
|
||||||
|
public static var DATA_MATRIX_FIELD_256:GenericGF = new GenericGF(0x012D, 256); // x^8 + x^5 + x^3 + x^2 + 1
|
||||||
|
public static var AZTEC_DATA_8:GenericGF = DATA_MATRIX_FIELD_256;
|
||||||
|
|
||||||
|
private static var INITIALIZATION_THRESHOLD:int = 0;
|
||||||
|
|
||||||
|
private var expTable:Array;
|
||||||
|
private var logTable:Array;
|
||||||
|
private var zero:GenericGFPoly;
|
||||||
|
private var one:GenericGFPoly;
|
||||||
|
public var size:int;
|
||||||
|
public var primitive:int;
|
||||||
|
private var initialized:Boolean = 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 function GenericGF(primitive:int, size:int) {
|
||||||
|
this.primitive = primitive;
|
||||||
|
this.size = size;
|
||||||
|
|
||||||
|
if (size <= INITIALIZATION_THRESHOLD){
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function initialize():void{
|
||||||
|
expTable = new Array(size);
|
||||||
|
logTable = new Array(size);
|
||||||
|
var x:int = 1;
|
||||||
|
for (var i:int = 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 (var ii:int = 0; ii < size-1; ii++) {
|
||||||
|
logTable[expTable[ii]] = ii;
|
||||||
|
}
|
||||||
|
// logTable[0] == 0 but this should never be used
|
||||||
|
zero = new GenericGFPoly(this, [0]);
|
||||||
|
one = new GenericGFPoly(this, [1]);
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkInit():void{
|
||||||
|
if (!initialized) {
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getZero():GenericGFPoly {
|
||||||
|
checkInit();
|
||||||
|
|
||||||
|
return zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOne():GenericGFPoly {
|
||||||
|
checkInit();
|
||||||
|
|
||||||
|
return one;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the monomial representing coefficient * x^degree
|
||||||
|
*/
|
||||||
|
public function buildMonomial(degree:int, coefficient:int):GenericGFPoly {
|
||||||
|
checkInit();
|
||||||
|
|
||||||
|
if (degree < 0) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
if (coefficient == 0) {
|
||||||
|
return zero;
|
||||||
|
}
|
||||||
|
var coefficients:Array = new Array(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
|
||||||
|
*/
|
||||||
|
public static function addOrSubtract(a:int, b:int):int {
|
||||||
|
return a ^ b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return 2 to the power of a in GF(size)
|
||||||
|
*/
|
||||||
|
public function exp(a:int):int {
|
||||||
|
checkInit();
|
||||||
|
|
||||||
|
return expTable[a];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return base 2 log of a in GF(size)
|
||||||
|
*/
|
||||||
|
public function log(a:int):int {
|
||||||
|
checkInit();
|
||||||
|
|
||||||
|
if (a == 0) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
return logTable[a];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return multiplicative inverse of a
|
||||||
|
*/
|
||||||
|
public function inverse(a:int):int {
|
||||||
|
checkInit();
|
||||||
|
|
||||||
|
if (a == 0) {
|
||||||
|
throw new Error("arithmetic exception");
|
||||||
|
}
|
||||||
|
return expTable[size - logTable[a] - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param a
|
||||||
|
* @param b
|
||||||
|
* @return product of a and b in GF(size)
|
||||||
|
*/
|
||||||
|
public function multiply(a:int, b:int):int {
|
||||||
|
checkInit();
|
||||||
|
|
||||||
|
if (a == 0 || b == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a<0 || b <0 || a>=size || b >=size){
|
||||||
|
a++;
|
||||||
|
}
|
||||||
|
|
||||||
|
var logSum:int = logTable[a] + logTable[b];
|
||||||
|
var result:int = expTable[(logSum % size) + Math.floor(logSum / size)];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSize():int{
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function Equals(other:GenericGF):Boolean
|
||||||
|
{
|
||||||
|
return ((this.primitive == other.primitive) && (this.size == other.size));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,295 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
{
|
||||||
|
|
||||||
|
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||||
|
import com.google.zxing.common.flexdatatypes.StringBuilder;
|
||||||
|
import com.google.zxing.common.flexdatatypes.Utils;
|
||||||
|
/**
|
||||||
|
* <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
|
||||||
|
*/
|
||||||
|
public class GenericGFPoly {
|
||||||
|
|
||||||
|
public var field:GenericGF;
|
||||||
|
public var coefficients:Array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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")
|
||||||
|
*/
|
||||||
|
public function GenericGFPoly(field:GenericGF, coefficients:Array) {
|
||||||
|
if (coefficients == null || coefficients.length == 0) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
this.field = field;
|
||||||
|
var coefficientsLength:int = coefficients.length;
|
||||||
|
if (coefficientsLength > 1 && coefficients[0] == 0) {
|
||||||
|
// Leading term must be non-zero for anything except the constant polynomial "0"
|
||||||
|
var firstNonZero:int = 1;
|
||||||
|
while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0) {
|
||||||
|
firstNonZero++;
|
||||||
|
}
|
||||||
|
if (firstNonZero == coefficientsLength) {
|
||||||
|
this.coefficients = field.getZero().coefficients;
|
||||||
|
} else {
|
||||||
|
this.coefficients = new Array(coefficientsLength - firstNonZero);
|
||||||
|
Utils.arraycopy(coefficients,firstNonZero,this.coefficients,0,this.coefficients.length);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
this.coefficients = coefficients;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCoefficients():Array {
|
||||||
|
return coefficients;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return degree of this polynomial
|
||||||
|
*/
|
||||||
|
public function getDegree():int {
|
||||||
|
return coefficients.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true iff this polynomial is the monomial "0"
|
||||||
|
*/
|
||||||
|
public function isZero():Boolean {
|
||||||
|
return coefficients[0] == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return coefficient of x^degree term in this polynomial
|
||||||
|
*/
|
||||||
|
public function getCoefficient(degree:int):int
|
||||||
|
{
|
||||||
|
return coefficients[coefficients.length - 1 - degree];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return evaluation of this polynomial at a given point
|
||||||
|
*/
|
||||||
|
public function evaluateAt(a:int):int {
|
||||||
|
if (a == 0) {
|
||||||
|
// Just return the x^0 coefficient
|
||||||
|
return getCoefficient(0);
|
||||||
|
}
|
||||||
|
var size:int = coefficients.length;
|
||||||
|
if (a == 1) {
|
||||||
|
// Just the sum of the coefficients
|
||||||
|
var result:int = 0;
|
||||||
|
for (var i:int = 0; i < size; i++) {
|
||||||
|
result = GenericGF.addOrSubtract(result, coefficients[i]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = coefficients[0];
|
||||||
|
for (i = 1; i < size; i++) {
|
||||||
|
result = GenericGF.addOrSubtract(field.multiply(a, result), coefficients[i]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addOrSubtract(other:GenericGFPoly):GenericGFPoly {
|
||||||
|
if (!field.Equals(other.field)) {
|
||||||
|
throw new IllegalArgumentException("GenericGFPolys do not have same GenericGF field");
|
||||||
|
}
|
||||||
|
if (isZero()) {
|
||||||
|
return other;
|
||||||
|
}
|
||||||
|
if (other.isZero()) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
var smallerCoefficients:Array = this.coefficients;
|
||||||
|
var largerCoefficients:Array = other.coefficients;
|
||||||
|
if (smallerCoefficients.length > largerCoefficients.length) {
|
||||||
|
var temp:Array = smallerCoefficients;
|
||||||
|
smallerCoefficients = largerCoefficients;
|
||||||
|
largerCoefficients = temp;
|
||||||
|
}
|
||||||
|
var sumDiff:Array = new Array(largerCoefficients.length);
|
||||||
|
var lengthDiff:int = largerCoefficients.length - smallerCoefficients.length;
|
||||||
|
// Copy high-order terms only found in higher-degree polynomial's coefficients
|
||||||
|
Utils.arraycopy(largerCoefficients, 0, sumDiff, 0, lengthDiff);
|
||||||
|
|
||||||
|
for (var i:int = lengthDiff; i < largerCoefficients.length; i++) {
|
||||||
|
sumDiff[i] = GenericGF.addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new GenericGFPoly(field, sumDiff);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function multiply(other:*):GenericGFPoly
|
||||||
|
{
|
||||||
|
if (other is int) { return this.multiply_scalar(other as int);}
|
||||||
|
other = (other as GenericGFPoly);
|
||||||
|
if (!field.Equals(other.field)) {
|
||||||
|
throw new IllegalArgumentException("GenericGFPolys do not have same GenericGF field");
|
||||||
|
}
|
||||||
|
if (isZero() || other.isZero()) {
|
||||||
|
return field.getZero();
|
||||||
|
}
|
||||||
|
var aCoefficients:Array = this.coefficients;
|
||||||
|
var aLength:int = aCoefficients.length;
|
||||||
|
var bCoefficients:Array = other.coefficients;
|
||||||
|
var bLength:int = bCoefficients.length;
|
||||||
|
var product:Array = new Array(aLength + bLength - 1);
|
||||||
|
for (var i:int = 0; i < aLength; i++) {
|
||||||
|
var aCoeff:int = aCoefficients[i];
|
||||||
|
for (var j:int = 0; j < bLength; j++) {
|
||||||
|
product[i + j] = GenericGF.addOrSubtract(product[i + j],
|
||||||
|
field.multiply(aCoeff, bCoefficients[j]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new GenericGFPoly(field, product);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function multiply_scalar(scalar:int):GenericGFPoly {
|
||||||
|
if (scalar == 0) {
|
||||||
|
return field.getZero();
|
||||||
|
}
|
||||||
|
if (scalar == 1) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
var size:int = coefficients.length;
|
||||||
|
var product:Array = new Array(size);
|
||||||
|
for (var i:int = 0; i < size; i++) {
|
||||||
|
product[i] = field.multiply(coefficients[i], scalar);
|
||||||
|
}
|
||||||
|
return new GenericGFPoly(field, product);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function multiplyByMonomial(degree:int, coefficient:int):GenericGFPoly {
|
||||||
|
if (degree < 0) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
if (coefficient == 0) {
|
||||||
|
return field.getZero();
|
||||||
|
}
|
||||||
|
var size:int = coefficients.length;
|
||||||
|
var product:Array = new Array(size + degree);
|
||||||
|
for (var i:int = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
product[i] = field.multiply(coefficients[i], coefficient);
|
||||||
|
}
|
||||||
|
return new GenericGFPoly(field, product);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function divide(other:GenericGFPoly):Array
|
||||||
|
{
|
||||||
|
if (!field.Equals(other.field))
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("GenericGFPolys do not have same GenericGF field");
|
||||||
|
}
|
||||||
|
if (other.isZero())
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Divide by 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
var quotient:GenericGFPoly = field.getZero();
|
||||||
|
var remainder:GenericGFPoly = this;
|
||||||
|
|
||||||
|
var denominatorLeadingTerm:int = other.getCoefficient(other.getDegree());
|
||||||
|
var inverseDenominatorLeadingTerm:int = field.inverse(denominatorLeadingTerm);
|
||||||
|
|
||||||
|
while (remainder.getDegree() >= other.getDegree() && !remainder.isZero()) {
|
||||||
|
var degreeDifference:int = remainder.getDegree() - other.getDegree();
|
||||||
|
var scale:int = field.multiply(remainder.getCoefficient(remainder.getDegree()), inverseDenominatorLeadingTerm);
|
||||||
|
var term:GenericGFPoly = other.multiplyByMonomial(degreeDifference, scale);
|
||||||
|
var iterationQuotient:GenericGFPoly = field.buildMonomial(degreeDifference, scale);
|
||||||
|
quotient = quotient.addOrSubtract(iterationQuotient);
|
||||||
|
remainder = remainder.addOrSubtract(term);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [ quotient, remainder ];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toString():String
|
||||||
|
{
|
||||||
|
var result:StringBuilder = new StringBuilder(8 * getDegree());
|
||||||
|
for (var degree:int = getDegree(); degree >= 0; degree--) {
|
||||||
|
var coefficient:int = getCoefficient(degree);
|
||||||
|
if (coefficient != 0) {
|
||||||
|
if (coefficient < 0) {
|
||||||
|
result.Append(" - ");
|
||||||
|
coefficient = -coefficient;
|
||||||
|
} else {
|
||||||
|
if (result.length > 0) {
|
||||||
|
result.Append(" + ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (degree == 0 || coefficient != 1) {
|
||||||
|
var alphaPower:int = 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function Equals(other:GenericGFPoly):Boolean
|
||||||
|
{
|
||||||
|
|
||||||
|
if (this.field == other.field)
|
||||||
|
{
|
||||||
|
if (this.coefficients.length == other.coefficients.length)
|
||||||
|
{
|
||||||
|
for (var i:int=0;i<this.coefficients.length;i++)
|
||||||
|
{
|
||||||
|
if (other.coefficients.indexOf(this.coefficients[i]) == -1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package com.google.zxing.common.reedsolomon
|
package com.google.zxing.common.reedsolomon
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Implements Reed-Solomon decoding, as the name implies.</p>
|
* <p>Implements Reed-Solomon decoding, as the name implies.</p>
|
||||||
*
|
*
|
||||||
|
@ -38,11 +39,12 @@ package com.google.zxing.common.reedsolomon
|
||||||
* @author William Rucklidge
|
* @author William Rucklidge
|
||||||
* @author sanfordsquires
|
* @author sanfordsquires
|
||||||
*/
|
*/
|
||||||
public class ReedSolomonDecoder
|
public class ReedSolomonDecoder {
|
||||||
{
|
|
||||||
private var field:GF256;
|
|
||||||
|
|
||||||
public function ReedSolomonDecoder(field:GF256) {
|
private var field:GenericGF;
|
||||||
|
|
||||||
|
public function ReedSolomonDecoder(field:GenericGF)
|
||||||
|
{
|
||||||
this.field = field;
|
this.field = field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,10 +57,19 @@ package com.google.zxing.common.reedsolomon
|
||||||
* @param twoS number of error-correction codewords available
|
* @param twoS number of error-correction codewords available
|
||||||
* @throws ReedSolomonException if decoding fails for any reason
|
* @throws ReedSolomonException if decoding fails for any reason
|
||||||
*/
|
*/
|
||||||
public function decode(received:Array, twoS:int):void {
|
public function decode(received:Array, twoS:int):void
|
||||||
var poly:GF256Poly = new GF256Poly(field, received);
|
{
|
||||||
|
/* debug */
|
||||||
|
/*received = [66,102,135,71,71,3,162,242,246,118,246,246,118,198,82,230,54,246,210,246,119,119,66,246,227,
|
||||||
|
247,83,214,38,199,86,86,230,150,198,82,230,54,246,208,236,17,236,17,236,17,236,17,236,17,
|
||||||
|
236,17,236,17,236,69,165,146,99,159,55,25,86,244,208,192,209,50,8,174];
|
||||||
|
twoS = 15;
|
||||||
|
*/
|
||||||
|
/* debug */
|
||||||
|
|
||||||
|
var poly:GenericGFPoly = new GenericGFPoly(field, received);
|
||||||
var syndromeCoefficients:Array = new Array(twoS);
|
var syndromeCoefficients:Array = new Array(twoS);
|
||||||
var dataMatrix:Boolean = (field == GF256.DATA_MATRIX_FIELD);
|
var dataMatrix:Boolean = field.Equals(GenericGF.DATA_MATRIX_FIELD_256);
|
||||||
var noError:Boolean = true;
|
var noError:Boolean = true;
|
||||||
for (var i:int = 0; i < twoS; i++) {
|
for (var i:int = 0; i < twoS; i++) {
|
||||||
// Thanks to sanfordsquires for this fix:
|
// Thanks to sanfordsquires for this fix:
|
||||||
|
@ -71,53 +82,54 @@ package com.google.zxing.common.reedsolomon
|
||||||
if (noError) {
|
if (noError) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var syndrome:GF256Poly = new GF256Poly(field, syndromeCoefficients);
|
var syndrome:GenericGFPoly = new GenericGFPoly(field, syndromeCoefficients);
|
||||||
var sigmaOmega:Array = runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS);
|
var sigmaOmega:Array = runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS);
|
||||||
var sigma:GF256Poly = sigmaOmega[0];
|
var sigma:GenericGFPoly = sigmaOmega[0];
|
||||||
var omega:GF256Poly = sigmaOmega[1];
|
var omega:GenericGFPoly = sigmaOmega[1];
|
||||||
var errorLocations:Array = findErrorLocations(sigma);
|
var errorLocations:Array = findErrorLocations(sigma);
|
||||||
var errorMagnitudes:Array = findErrorMagnitudes(omega, errorLocations, dataMatrix);
|
var errorMagnitudes:Array = findErrorMagnitudes(omega, errorLocations, dataMatrix);
|
||||||
for (var j:int = 0; j < errorLocations.length; j++) {
|
for (i = 0; i < errorLocations.length; i++) {
|
||||||
var position:int = received.length - 1 - field.log(errorLocations[j]);
|
var position:int = received.length - 1 - field.log(errorLocations[i]);
|
||||||
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[j]);
|
received[position] = GenericGF.addOrSubtract(received[position], errorMagnitudes[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function runEuclideanAlgorithm(a:GF256Poly, b:GF256Poly, R:int ):Array
|
private function runEuclideanAlgorithm(a:GenericGFPoly, b:GenericGFPoly, R:int):Array
|
||||||
{
|
{
|
||||||
// Assume a's degree is >= b's
|
// Assume a's degree is >= b's
|
||||||
if (a.getDegree() < b.getDegree()) {
|
if (a.getDegree() < b.getDegree()) {
|
||||||
var temp:GF256Poly = a;
|
var temp:GenericGFPoly = a;
|
||||||
a = b;
|
a = b;
|
||||||
b = temp;
|
b = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
var rLast:GF256Poly = a;
|
var rLast:GenericGFPoly = a;
|
||||||
var r:GF256Poly = b;
|
var r:GenericGFPoly = b;
|
||||||
var sLast:GF256Poly = field.getOne();
|
var sLast:GenericGFPoly = field.getOne();
|
||||||
var s:GF256Poly = field.getZero();
|
var s:GenericGFPoly = field.getZero();
|
||||||
var tLast:GF256Poly = field.getZero();
|
var tLast:GenericGFPoly = field.getZero();
|
||||||
var t:GF256Poly = field.getOne();
|
var t:GenericGFPoly = 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) {
|
||||||
var rLastLast:GF256Poly = rLast;
|
var rLastLast:GenericGFPoly = rLast;
|
||||||
var sLastLast:GF256Poly = sLast;
|
var sLastLast:GenericGFPoly = sLast;
|
||||||
var tLastLast:GF256Poly = tLast;
|
var tLastLast:GenericGFPoly = tLast;
|
||||||
rLast = r;
|
rLast = r;
|
||||||
sLast = s;
|
sLast = s;
|
||||||
tLast = t;
|
tLast = t;
|
||||||
|
|
||||||
// Divide rLastLast by rLast, with quotient in q and remainder in r
|
// Divide rLastLast by rLast, with quotient in q and remainder in r
|
||||||
if (rLast.isZero()) {
|
if (rLast.isZero())
|
||||||
|
{
|
||||||
// Oops, Euclidean algorithm already terminated?
|
// Oops, Euclidean algorithm already terminated?
|
||||||
throw new ReedSolomonException("r_{i-1} was zero");
|
throw new ReedSolomonException("r_{i-1} was zero");
|
||||||
}
|
}
|
||||||
r = rLastLast;
|
r = rLastLast;
|
||||||
var q:GF256Poly = field.getZero();
|
var q:GenericGFPoly = field.getZero();
|
||||||
var denominatorLeadingTerm:int = rLast.getCoefficient(rLast.getDegree());
|
var denominatorLeadingTerm:int = rLast.getCoefficient(rLast.getDegree());
|
||||||
var dltInverse:int = field.inverse(denominatorLeadingTerm);
|
var dltInverse:int = field.inverse(denominatorLeadingTerm);
|
||||||
while (r.getDegree() >= rLast.getDegree() && !r.isZero()) {
|
while (r.getDegree() >= rLast.getDegree() && !r.isZero()) {
|
||||||
|
@ -137,21 +149,24 @@ package com.google.zxing.common.reedsolomon
|
||||||
}
|
}
|
||||||
|
|
||||||
var inverse:int = field.inverse(sigmaTildeAtZero);
|
var inverse:int = field.inverse(sigmaTildeAtZero);
|
||||||
var sigma:GF256Poly = t.multiply(inverse);
|
var sigma:GenericGFPoly = t.multiply(inverse);
|
||||||
var omega:GF256Poly = r.multiply(inverse);
|
var omega:GenericGFPoly = r.multiply(inverse);
|
||||||
return [sigma, omega];
|
return [sigma, omega];
|
||||||
}
|
}
|
||||||
|
|
||||||
private function findErrorLocations(errorLocator:GF256Poly):Array{
|
private function findErrorLocations(errorLocator:GenericGFPoly ) :Array {
|
||||||
// This is a direct application of Chien's search
|
// This is a direct application of Chien's search
|
||||||
var numErrors:int = errorLocator.getDegree();
|
var numErrors:int = errorLocator.getDegree();
|
||||||
if (numErrors == 1) { // shortcut
|
if (numErrors == 1)
|
||||||
|
{ // shortcut
|
||||||
return [errorLocator.getCoefficient(1) ];
|
return [errorLocator.getCoefficient(1) ];
|
||||||
}
|
}
|
||||||
var result:Array = new Array(numErrors);
|
var result:Array = new Array(numErrors);
|
||||||
var e:int = 0;
|
var e:int = 0;
|
||||||
for (var i:int = 1; i < 256 && e < numErrors; i++) {
|
for (var i:int = 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++;
|
||||||
}
|
}
|
||||||
|
@ -162,7 +177,7 @@ package com.google.zxing.common.reedsolomon
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function findErrorMagnitudes(errorEvaluator:GF256Poly , errorLocations:Array, dataMatrix:Boolean):Array {
|
private function findErrorMagnitudes(errorEvaluator:GenericGFPoly, errorLocations:Array, dataMatrix:Boolean):Array {
|
||||||
// This is directly applying Forney's Formula
|
// This is directly applying Forney's Formula
|
||||||
var s:int = errorLocations.length;
|
var s:int = errorLocations.length;
|
||||||
var result:Array = new Array(s);
|
var result:Array = new Array(s);
|
||||||
|
@ -170,15 +185,20 @@ package com.google.zxing.common.reedsolomon
|
||||||
var xiInverse:int = field.inverse(errorLocations[i]);
|
var xiInverse:int = field.inverse(errorLocations[i]);
|
||||||
var denominator:int = 1;
|
var denominator:int = 1;
|
||||||
for (var j:int = 0; j < s; j++) {
|
for (var j:int = 0; j < s; j++) {
|
||||||
if (i != j) {
|
if (i != j)
|
||||||
denominator = field.multiply(denominator,
|
{
|
||||||
GF256.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse)));
|
//denominator = field.multiply(denominator, GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse)));
|
||||||
|
// 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
|
||||||
|
var term:int = field.multiply(errorLocations[j], xiInverse);
|
||||||
|
var termPlus1:int = (term & 0x1) == 0 ? term | 1 : term & ~1;
|
||||||
|
denominator = field.multiply(denominator, termPlus1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result[i] = field.multiply(errorEvaluator.evaluateAt(xiInverse),
|
result[i] = field.multiply(errorEvaluator.evaluateAt(xiInverse),field.inverse(denominator));
|
||||||
field.inverse(denominator));
|
|
||||||
// Thanks to sanfordsquires for this fix:
|
// Thanks to sanfordsquires for this fix:
|
||||||
if (dataMatrix) {
|
if (dataMatrix)
|
||||||
|
{
|
||||||
result[i] = field.multiply(result[i], xiInverse);
|
result[i] = field.multiply(result[i], xiInverse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,5 +206,4 @@ package com.google.zxing.common.reedsolomon
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -13,68 +13,70 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.google.zxing.common.reedsolomon
|
package com.google.zxing.common.reedsolomon
|
||||||
{
|
{
|
||||||
public class ReedSolomonEncoder
|
|
||||||
{
|
|
||||||
import com.google.zxing.common.flexdatatypes.ArrayList;
|
import com.google.zxing.common.flexdatatypes.ArrayList;
|
||||||
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
|
||||||
|
import com.google.zxing.common.flexdatatypes.Utils;
|
||||||
|
/**
|
||||||
|
* <p>Implements Reed-Solomon enbcoding, as the name implies.</p>
|
||||||
|
*
|
||||||
|
* @author Sean Owen
|
||||||
|
* @author William Rucklidge
|
||||||
|
*/
|
||||||
|
public class ReedSolomonEncoder
|
||||||
|
{
|
||||||
|
|
||||||
private var Field:GF256 ;
|
private var field:GenericGF;
|
||||||
private var cachedGenerators:ArrayList;
|
private var cachedGenerators:ArrayList;
|
||||||
|
|
||||||
public function ReedSolomonEncoder(field:GF256 ) {
|
public function ReedSolomonEncoder(field:GenericGF ) {
|
||||||
if (GF256.QR_CODE_FIELD != 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 ArrayList();
|
this.cachedGenerators = new ArrayList();
|
||||||
cachedGenerators.Add(new GF256Poly(field, [ 1 ]));
|
cachedGenerators.addElement(new GenericGFPoly(field, [ 1 ]));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildGenerator(degree:int):GF256Poly {
|
private function buildGenerator(degree:int):GenericGFPoly {
|
||||||
if (degree >= cachedGenerators.Count) {
|
if (degree >= cachedGenerators.size()) {
|
||||||
var lastGenerator:GF256Poly = cachedGenerators.getObjectByIndex(cachedGenerators.Count - 1) as GF256Poly;
|
var lastGenerator:GenericGFPoly= (cachedGenerators.elementAt(cachedGenerators.size() - 1) as GenericGFPoly);
|
||||||
for (var d:int = cachedGenerators.Count; d <= degree; d++)
|
for (var d:int = cachedGenerators.size(); d <= degree; d++) {
|
||||||
{
|
var nextGenerator:GenericGFPoly = lastGenerator.multiply(new GenericGFPoly(field, [ 1, field.exp(d - 1) ]));
|
||||||
var nextGenerator:GF256Poly = lastGenerator.multiply(new GF256Poly(Field, [ 1, Field.exp(d - 1)]));
|
cachedGenerators.addElement(nextGenerator);
|
||||||
cachedGenerators.Add(nextGenerator);
|
|
||||||
lastGenerator = nextGenerator;
|
lastGenerator = nextGenerator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (cachedGenerators.getObjectByIndex(degree) as GF256Poly);
|
return (cachedGenerators.elementAt(degree) as GenericGFPoly)
|
||||||
}
|
}
|
||||||
|
|
||||||
public function encode( toEncode:Array, ecBytes:int) :void{
|
public function encode(toEncode:Array, ecBytes:int):void
|
||||||
if (ecBytes == 0) {
|
{
|
||||||
|
if (ecBytes == 0)
|
||||||
|
{
|
||||||
throw new IllegalArgumentException("No error correction bytes");
|
throw new IllegalArgumentException("No error correction bytes");
|
||||||
}
|
}
|
||||||
var dataBytes:int = toEncode.length - ecBytes;
|
var dataBytes:int = toEncode.length - ecBytes;
|
||||||
if (dataBytes <= 0) {
|
if (dataBytes <= 0)
|
||||||
|
{
|
||||||
throw new IllegalArgumentException("No data bytes provided");
|
throw new IllegalArgumentException("No data bytes provided");
|
||||||
}
|
}
|
||||||
var generator:GF256Poly = buildGenerator(ecBytes);
|
var generator:GenericGFPoly = buildGenerator(ecBytes);
|
||||||
var infoCoefficients:Array = new Array(dataBytes);
|
var infoCoefficients:Array = new Array(dataBytes);
|
||||||
//System.Array.Copy(toEncode, 0, infoCoefficients, 0, dataBytes);
|
Utils.arraycopy(toEncode, 0, infoCoefficients, 0, dataBytes);
|
||||||
for (var ii:int=0;ii<dataBytes;ii++)
|
var info:GenericGFPoly = new GenericGFPoly(field, infoCoefficients);
|
||||||
{
|
|
||||||
infoCoefficients[ii] = toEncode[ii];
|
|
||||||
}
|
|
||||||
|
|
||||||
var info:GF256Poly = new GF256Poly(this.Field, infoCoefficients);
|
|
||||||
info = info.multiplyByMonomial(ecBytes, 1);
|
info = info.multiplyByMonomial(ecBytes, 1);
|
||||||
var remainder:GF256Poly = info.divide(generator)[1];
|
var remainder:GenericGFPoly = info.divide(generator)[1];
|
||||||
var coefficients:Array = remainder.getCoefficients();
|
var coefficients:Array = remainder.getCoefficients();
|
||||||
var numZeroCoefficients:int = ecBytes - coefficients.length;
|
var numZeroCoefficients:int = ecBytes - coefficients.length;
|
||||||
for (var i:int = 0; i < numZeroCoefficients; i++) {
|
for (var i:int = 0; i < numZeroCoefficients; i++)
|
||||||
|
{
|
||||||
toEncode[dataBytes + i] = 0;
|
toEncode[dataBytes + i] = 0;
|
||||||
}
|
}
|
||||||
//System.Array.Copy(coefficients, 0, toEncode, dataBytes + numZeroCoefficients, coefficients.length);
|
Utils.arraycopy(coefficients, 0, toEncode, dataBytes + numZeroCoefficients, coefficients.length);
|
||||||
for(var jj:int=0;jj < coefficients.length;jj++)
|
|
||||||
{
|
|
||||||
toEncode[dataBytes + numZeroCoefficients + jj] = coefficients[jj];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,34 @@
|
||||||
|
/*
|
||||||
|
* 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
|
package com.google.zxing.common.reedsolomon
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Thrown when an exception occurs during Reed-Solomon decoding, such as when
|
||||||
|
* there are too many errors to correct.</p>
|
||||||
|
*
|
||||||
|
* @author Sean Owen
|
||||||
|
*/
|
||||||
public class ReedSolomonException extends Error
|
public class ReedSolomonException extends Error
|
||||||
{
|
{
|
||||||
public function ReedSolomonException(message:String="")
|
public function ReedSolomonException(message:String)
|
||||||
{
|
{
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue