mirror of
https://github.com/zxing/zxing.git
synced 2024-09-20 05:27:32 -07: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;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue