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:
bas5winkel@gmail.com 2012-01-11 17:08:48 +00:00
parent aa33b1cd04
commit 9f032621f9
5 changed files with 817 additions and 279 deletions

View file

@ -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));
}
}
}

View file

@ -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;
}
}
}

View file

@ -1,190 +1,209 @@
/*
* 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>Implements Reed-Solomon decoding, as the name implies.</p>
*
* <p>The algorithm will not be explained here, but the following references were helpful
* in creating this implementation:</p>
*
* <ul>
* <li>Bruce Maggs.
* <a href="http://www.cs.cmu.edu/afs/cs.cmu.edu/project/pscico-guyb/realworld/www/rs_decode.ps">
* "Decoding Reed-Solomon Codes"</a> (see discussion of Forney's Formula)</li>
* <li>J.I. Hall. <a href="www.mth.msu.edu/~jhall/classes/codenotes/GRS.pdf">
* "Chapter 5. Generalized Reed-Solomon Codes"</a>
* (see discussion of Euclidean algorithm)</li>
* </ul>
*
* <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
* @author William Rucklidge
* @author sanfordsquires
*/
public class ReedSolomonDecoder
{
private var field:GF256;
public function ReedSolomonDecoder(field:GF256) {
this.field = field;
}
/**
* <p>Decodes given set of received codewords, which include both data and error-correction
* codewords. Really, this means it uses Reed-Solomon to detect and correct errors, in-place,
* in the input.</p>
*
* @param received data and error-correction codewords
* @param twoS number of error-correction codewords available
* @throws ReedSolomonException if decoding fails for any reason
*/
public function decode(received:Array, twoS:int):void {
var poly:GF256Poly = new GF256Poly(field, received);
var syndromeCoefficients:Array = new Array(twoS);
var dataMatrix:Boolean = (field == GF256.DATA_MATRIX_FIELD);
var noError:Boolean = true;
for (var i:int = 0; i < twoS; i++) {
// Thanks to sanfordsquires for this fix:
var eval:int = poly.evaluateAt(field.exp(dataMatrix ? i + 1 : i));
syndromeCoefficients[syndromeCoefficients.length - 1 - i] = eval;
if (eval != 0) {
noError = false;
}
}
if (noError) {
return;
}
var syndrome:GF256Poly = new GF256Poly(field, syndromeCoefficients);
var sigmaOmega:Array = runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS);
var sigma:GF256Poly = sigmaOmega[0];
var omega:GF256Poly = sigmaOmega[1];
var errorLocations:Array = findErrorLocations(sigma);
var errorMagnitudes:Array = findErrorMagnitudes(omega, errorLocations, dataMatrix);
for (var j:int = 0; j < errorLocations.length; j++) {
var position:int = received.length - 1 - field.log(errorLocations[j]);
if (position < 0) {
throw new ReedSolomonException("Bad error location");
}
received[position] = GF256.addOrSubtract(received[position], errorMagnitudes[j]);
}
}
private function runEuclideanAlgorithm(a:GF256Poly, b:GF256Poly, R:int ):Array
{
// Assume a's degree is >= b's
if (a.getDegree() < b.getDegree()) {
var temp:GF256Poly = a;
a = b;
b = temp;
}
var rLast:GF256Poly = a;
var r:GF256Poly = b;
var sLast:GF256Poly = field.getOne();
var s:GF256Poly = field.getZero();
var tLast:GF256Poly = field.getZero();
var t:GF256Poly = field.getOne();
// Run Euclidean algorithm until r's degree is less than R/2
while (r.getDegree() >= R / 2) {
var rLastLast:GF256Poly = rLast;
var sLastLast:GF256Poly = sLast;
var tLastLast:GF256Poly = tLast;
rLast = r;
sLast = s;
tLast = t;
// Divide rLastLast by rLast, with quotient in q and remainder in r
if (rLast.isZero()) {
// Oops, Euclidean algorithm already terminated?
throw new ReedSolomonException("r_{i-1} was zero");
}
r = rLastLast;
var q:GF256Poly = field.getZero();
var denominatorLeadingTerm:int = rLast.getCoefficient(rLast.getDegree());
var dltInverse:int = field.inverse(denominatorLeadingTerm);
while (r.getDegree() >= rLast.getDegree() && !r.isZero()) {
var degreeDiff:int = r.getDegree() - rLast.getDegree();
var scale:int = field.multiply(r.getCoefficient(r.getDegree()), dltInverse);
q = q.addOrSubtract(field.buildMonomial(degreeDiff, scale));
r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale));
}
s = q.multiply(sLast).addOrSubtract(sLastLast);
t = q.multiply(tLast).addOrSubtract(tLastLast);
}
var sigmaTildeAtZero:int = t.getCoefficient(0);
if (sigmaTildeAtZero == 0) {
throw new ReedSolomonException("sigmaTilde(0) was zero");
}
var inverse:int = field.inverse(sigmaTildeAtZero);
var sigma:GF256Poly = t.multiply(inverse);
var omega:GF256Poly = r.multiply(inverse);
return [sigma, omega];
}
private function findErrorLocations(errorLocator:GF256Poly):Array{
// This is a direct application of Chien's search
var numErrors:int = errorLocator.getDegree();
if (numErrors == 1) { // shortcut
return [errorLocator.getCoefficient(1)];
}
var result:Array = new Array(numErrors);
var e:int = 0;
for (var i:int = 1; i < 256 && e < numErrors; i++) {
if (errorLocator.evaluateAt(i) == 0) {
result[e] = field.inverse(i);
e++;
}
}
if (e != numErrors) {
throw new ReedSolomonException("Error locator degree does not match number of roots");
}
return result;
}
private function findErrorMagnitudes(errorEvaluator:GF256Poly , errorLocations:Array, dataMatrix:Boolean):Array {
// This is directly applying Forney's Formula
var s:int = errorLocations.length;
var result:Array = new Array(s);
for (var i:int = 0; i < s; i++) {
var xiInverse:int = field.inverse(errorLocations[i]);
var denominator:int = 1;
for (var j:int = 0; j < s; j++) {
if (i != j) {
denominator = field.multiply(denominator,
GF256.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse)));
}
}
result[i] = field.multiply(errorEvaluator.evaluateAt(xiInverse),
field.inverse(denominator));
// Thanks to sanfordsquires for this fix:
if (dataMatrix) {
result[i] = field.multiply(result[i], xiInverse);
}
}
return result;
}
}
/*
* 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>Implements Reed-Solomon decoding, as the name implies.</p>
*
* <p>The algorithm will not be explained here, but the following references were helpful
* in creating this implementation:</p>
*
* <ul>
* <li>Bruce Maggs.
* <a href="http://www.cs.cmu.edu/afs/cs.cmu.edu/project/pscico-guyb/realworld/www/rs_decode.ps">
* "Decoding Reed-Solomon Codes"</a> (see discussion of Forney's Formula)</li>
* <li>J.I. Hall. <a href="www.mth.msu.edu/~jhall/classes/codenotes/GRS.pdf">
* "Chapter 5. Generalized Reed-Solomon Codes"</a>
* (see discussion of Euclidean algorithm)</li>
* </ul>
*
* <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
* @author William Rucklidge
* @author sanfordsquires
*/
public class ReedSolomonDecoder {
private var field:GenericGF;
public function ReedSolomonDecoder(field:GenericGF)
{
this.field = field;
}
/**
* <p>Decodes given set of received codewords, which include both data and error-correction
* codewords. Really, this means it uses Reed-Solomon to detect and correct errors, in-place,
* in the input.</p>
*
* @param received data and error-correction codewords
* @param twoS number of error-correction codewords available
* @throws ReedSolomonException if decoding fails for any reason
*/
public function decode(received:Array, twoS:int):void
{
/* 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 dataMatrix:Boolean = field.Equals(GenericGF.DATA_MATRIX_FIELD_256);
var noError:Boolean = true;
for (var i:int = 0; i < twoS; i++) {
// Thanks to sanfordsquires for this fix:
var eval:int = poly.evaluateAt(field.exp(dataMatrix ? i + 1 : i));
syndromeCoefficients[syndromeCoefficients.length - 1 - i] = eval;
if (eval != 0) {
noError = false;
}
}
if (noError) {
return;
}
var syndrome:GenericGFPoly = new GenericGFPoly(field, syndromeCoefficients);
var sigmaOmega:Array = runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS);
var sigma:GenericGFPoly = sigmaOmega[0];
var omega:GenericGFPoly = sigmaOmega[1];
var errorLocations:Array = findErrorLocations(sigma);
var errorMagnitudes:Array = findErrorMagnitudes(omega, errorLocations, dataMatrix);
for (i = 0; i < errorLocations.length; i++) {
var position:int = received.length - 1 - field.log(errorLocations[i]);
if (position < 0) {
throw new ReedSolomonException("Bad error location");
}
received[position] = GenericGF.addOrSubtract(received[position], errorMagnitudes[i]);
}
}
private function runEuclideanAlgorithm(a:GenericGFPoly, b:GenericGFPoly, R:int):Array
{
// Assume a's degree is >= b's
if (a.getDegree() < b.getDegree()) {
var temp:GenericGFPoly = a;
a = b;
b = temp;
}
var rLast:GenericGFPoly = a;
var r:GenericGFPoly = b;
var sLast:GenericGFPoly = field.getOne();
var s:GenericGFPoly = field.getZero();
var tLast:GenericGFPoly = field.getZero();
var t:GenericGFPoly = field.getOne();
// Run Euclidean algorithm until r's degree is less than R/2
while (r.getDegree() >= R / 2) {
var rLastLast:GenericGFPoly = rLast;
var sLastLast:GenericGFPoly = sLast;
var tLastLast:GenericGFPoly = tLast;
rLast = r;
sLast = s;
tLast = t;
// Divide rLastLast by rLast, with quotient in q and remainder in r
if (rLast.isZero())
{
// Oops, Euclidean algorithm already terminated?
throw new ReedSolomonException("r_{i-1} was zero");
}
r = rLastLast;
var q:GenericGFPoly = field.getZero();
var denominatorLeadingTerm:int = rLast.getCoefficient(rLast.getDegree());
var dltInverse:int = field.inverse(denominatorLeadingTerm);
while (r.getDegree() >= rLast.getDegree() && !r.isZero()) {
var degreeDiff:int = r.getDegree() - rLast.getDegree();
var scale:int = field.multiply(r.getCoefficient(r.getDegree()), dltInverse);
q = q.addOrSubtract(field.buildMonomial(degreeDiff, scale));
r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale));
}
s = q.multiply(sLast).addOrSubtract(sLastLast);
t = q.multiply(tLast).addOrSubtract(tLastLast);
}
var sigmaTildeAtZero:int = t.getCoefficient(0);
if (sigmaTildeAtZero == 0) {
throw new ReedSolomonException("sigmaTilde(0) was zero");
}
var inverse:int = field.inverse(sigmaTildeAtZero);
var sigma:GenericGFPoly = t.multiply(inverse);
var omega:GenericGFPoly = r.multiply(inverse);
return [sigma, omega];
}
private function findErrorLocations(errorLocator:GenericGFPoly ) :Array {
// This is a direct application of Chien's search
var numErrors:int = errorLocator.getDegree();
if (numErrors == 1)
{ // shortcut
return [errorLocator.getCoefficient(1) ];
}
var result:Array = new Array(numErrors);
var e:int = 0;
for (var i:int = 1; i < field.getSize() && e < numErrors; i++)
{
if (errorLocator.evaluateAt(i) == 0)
{
result[e] = field.inverse(i);
e++;
}
}
if (e != numErrors) {
throw new ReedSolomonException("Error locator degree does not match number of roots");
}
return result;
}
private function findErrorMagnitudes(errorEvaluator:GenericGFPoly, errorLocations:Array, dataMatrix:Boolean):Array {
// This is directly applying Forney's Formula
var s:int = errorLocations.length;
var result:Array = new Array(s);
for (var i:int = 0; i < s; i++) {
var xiInverse:int = field.inverse(errorLocations[i]);
var denominator:int = 1;
for (var j:int = 0; j < s; j++) {
if (i != j)
{
//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),field.inverse(denominator));
// Thanks to sanfordsquires for this fix:
if (dataMatrix)
{
result[i] = field.multiply(result[i], xiInverse);
}
}
return result;
}
}
}

View file

@ -1,81 +1,83 @@
/*
* Copyright 2008 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
{
public class ReedSolomonEncoder
{
import com.google.zxing.common.flexdatatypes.ArrayList;
import com.google.zxing.common.flexdatatypes.IllegalArgumentException;
private var Field:GF256 ;
private var cachedGenerators:ArrayList;
public function ReedSolomonEncoder(field:GF256 ) {
if (GF256.QR_CODE_FIELD != field) {
throw new IllegalArgumentException("Only QR Code is supported at this time");
}
this.Field = field;
this.cachedGenerators = new ArrayList();
cachedGenerators.Add(new GF256Poly(field, [ 1 ]));
}
private function buildGenerator(degree:int):GF256Poly {
if (degree >= cachedGenerators.Count) {
var lastGenerator:GF256Poly = cachedGenerators.getObjectByIndex(cachedGenerators.Count - 1) as GF256Poly;
for (var d:int = cachedGenerators.Count; d <= degree; d++)
{
var nextGenerator:GF256Poly = lastGenerator.multiply(new GF256Poly(Field, [ 1, Field.exp(d - 1)]));
cachedGenerators.Add(nextGenerator);
lastGenerator = nextGenerator;
}
}
return (cachedGenerators.getObjectByIndex(degree) as GF256Poly);
}
public function encode( toEncode:Array, ecBytes:int) :void{
if (ecBytes == 0) {
throw new IllegalArgumentException("No error correction bytes");
}
var dataBytes:int = toEncode.length - ecBytes;
if (dataBytes <= 0) {
throw new IllegalArgumentException("No data bytes provided");
}
var generator:GF256Poly = buildGenerator(ecBytes);
var infoCoefficients:Array = new Array(dataBytes);
//System.Array.Copy(toEncode, 0, infoCoefficients, 0, dataBytes);
for (var ii:int=0;ii<dataBytes;ii++)
{
infoCoefficients[ii] = toEncode[ii];
}
var info:GF256Poly = new GF256Poly(this.Field, infoCoefficients);
info = info.multiplyByMonomial(ecBytes, 1);
var remainder:GF256Poly = info.divide(generator)[1];
var coefficients:Array = remainder.getCoefficients();
var numZeroCoefficients:int = ecBytes - coefficients.length;
for (var i:int = 0; i < numZeroCoefficients; i++) {
toEncode[dataBytes + i] = 0;
}
//System.Array.Copy(coefficients, 0, toEncode, dataBytes + numZeroCoefficients, coefficients.length);
for(var jj:int=0;jj < coefficients.length;jj++)
{
toEncode[dataBytes + numZeroCoefficients + jj] = coefficients[jj];
}
}
}
/*
* Copyright 2008 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.ArrayList;
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:GenericGF;
private var cachedGenerators:ArrayList;
public function ReedSolomonEncoder(field:GenericGF ) {
if (!GenericGF.QR_CODE_FIELD_256.Equals(field)) {
throw new IllegalArgumentException("Only QR Code is supported at this time");
}
this.field = field;
this.cachedGenerators = new ArrayList();
cachedGenerators.addElement(new GenericGFPoly(field, [ 1 ]));
}
private function buildGenerator(degree:int):GenericGFPoly {
if (degree >= cachedGenerators.size()) {
var lastGenerator:GenericGFPoly= (cachedGenerators.elementAt(cachedGenerators.size() - 1) as GenericGFPoly);
for (var d:int = cachedGenerators.size(); d <= degree; d++) {
var nextGenerator:GenericGFPoly = lastGenerator.multiply(new GenericGFPoly(field, [ 1, field.exp(d - 1) ]));
cachedGenerators.addElement(nextGenerator);
lastGenerator = nextGenerator;
}
}
return (cachedGenerators.elementAt(degree) as GenericGFPoly)
}
public function encode(toEncode:Array, ecBytes:int):void
{
if (ecBytes == 0)
{
throw new IllegalArgumentException("No error correction bytes");
}
var dataBytes:int = toEncode.length - ecBytes;
if (dataBytes <= 0)
{
throw new IllegalArgumentException("No data bytes provided");
}
var generator:GenericGFPoly = buildGenerator(ecBytes);
var infoCoefficients:Array = new Array(dataBytes);
Utils.arraycopy(toEncode, 0, infoCoefficients, 0, dataBytes);
var info:GenericGFPoly = new GenericGFPoly(field, infoCoefficients);
info = info.multiplyByMonomial(ecBytes, 1);
var remainder:GenericGFPoly = info.divide(generator)[1];
var coefficients:Array = remainder.getCoefficients();
var numZeroCoefficients:int = ecBytes - coefficients.length;
for (var i:int = 0; i < numZeroCoefficients; i++)
{
toEncode[dataBytes + i] = 0;
}
Utils.arraycopy(coefficients, 0, toEncode, dataBytes + numZeroCoefficients, coefficients.length);
}
}
}

View file

@ -1,11 +1,34 @@
package com.google.zxing.common.reedsolomon
{
public class ReedSolomonException extends Error
{
public function ReedSolomonException(message:String="")
{
super(message);
}
}
/*
* 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>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 function ReedSolomonException(message:String)
{
super(message);
}
}
}