Aztec encoder

git-svn-id: https://zxing.googlecode.com/svn/trunk@2577 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
srowen@gmail.com 2013-02-25 12:34:50 +00:00
parent 01e43af170
commit d5342e8e7f
14 changed files with 1642 additions and 334 deletions

View file

@ -82,6 +82,7 @@ Rasmus Schrøder Sørensen
Richard Hřivňák Richard Hřivňák
Romain Pechayre Romain Pechayre
Roman Nurik (Google) Roman Nurik (Google)
Rustam Abdullaev
Ryan Alford Ryan Alford
Sanford Squires Sanford Squires
Shachar Shemesh Shachar Shemesh

View file

@ -16,6 +16,7 @@
package com.google.zxing; package com.google.zxing;
import com.google.zxing.aztec.encoder.AztecWriter;
import com.google.zxing.common.BitMatrix; import com.google.zxing.common.BitMatrix;
import com.google.zxing.datamatrix.DataMatrixWriter; import com.google.zxing.datamatrix.DataMatrixWriter;
import com.google.zxing.oned.CodaBarWriter; import com.google.zxing.oned.CodaBarWriter;
@ -83,6 +84,8 @@ public final class MultiFormatWriter implements Writer {
break; break;
case DATA_MATRIX: case DATA_MATRIX:
writer = new DataMatrixWriter(); writer = new DataMatrixWriter();
case AZTEC:
writer = new AztecWriter();
break; break;
default: default:
throw new IllegalArgumentException("No encoder available for format " + format); throw new IllegalArgumentException("No encoder available for format " + format);

View file

@ -0,0 +1,89 @@
/*
* Copyright 2013 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.aztec.encoder;
import com.google.zxing.common.BitMatrix;
/**
* Aztec 2D code representation
*
* @author Rustam Abdullaev
*/
public final class AztecCode {
private boolean compact;
private int size;
private int layers;
private int codeWords;
private BitMatrix matrix;
/**
* Compact or full symbol indicator
*/
public boolean isCompact() {
return compact;
}
public void setCompact(boolean compact) {
this.compact = compact;
}
/**
* Size in pixels (width and height)
*/
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
/**
* Number of levels
*/
public int getLayers() {
return layers;
}
public void setLayers(int layers) {
this.layers = layers;
}
/**
* Number of data codewords
*/
public int getCodeWords() {
return codeWords;
}
public void setCodeWords(int codeWords) {
this.codeWords = codeWords;
}
/**
* The symbol image
*/
public BitMatrix getMatrix() {
return matrix;
}
public void setMatrix(BitMatrix matrix) {
this.matrix = matrix;
}
}

View file

@ -0,0 +1,44 @@
/*
* Copyright 2013 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.aztec.encoder;
import java.nio.charset.Charset;
import java.util.Map;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.Writer;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
public final class AztecWriter implements Writer {
private static final Charset LATIN_1 = Charset.forName("ISO-8859-1");
@Override
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height) throws WriterException {
AztecCode aztec = Encoder.encode(contents.getBytes(LATIN_1), 30);
return aztec.getMatrix();
}
@Override
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height, Map<EncodeHintType, ?> hints)
throws WriterException {
return encode(contents, format, width, height);
}
}

View file

@ -0,0 +1,598 @@
/*
* Copyright 2013 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.aztec.encoder;
import java.util.Arrays;
import com.google.zxing.common.BitArray;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.reedsolomon.GenericGF;
import com.google.zxing.common.reedsolomon.ReedSolomonEncoder;
/**
* Generates Aztec 2D barcodes.
*
* @author Rustam Abdullaev
*/
public final class Encoder {
public static final int DEFAULT_EC_PERCENT = 33; // default minimal percentage of error check words
private static final int TABLE_UPPER = 0; // 5 bits
private static final int TABLE_LOWER = 1; // 5 bits
private static final int TABLE_DIGIT = 2; // 4 bits
private static final int TABLE_MIXED = 3; // 5 bits
private static final int TABLE_PUNCT = 4; // 5 bits
private static final int TABLE_BINARY = 5; // 8 bits
private static final int[][] CHAR_MAP = new int[5][256]; // reverse mapping ASCII -> table offset, per table
private static final int[][] SHIFT_TABLE = new int[6][6]; // mode shift codes, per table
private static final int[][] LATCH_TABLE = new int[6][6]; // mode latch codes, per table
private static final int[] NB_BITS; // total bits per compact symbol for a given number of layers
private static final int[] NB_BITS_COMPACT; // total bits per full symbol for a given number of layers
static {
CHAR_MAP[TABLE_UPPER][' '] = 1;
for (int c = 'A'; c <= 'Z'; c++) {
CHAR_MAP[TABLE_UPPER][c] = c - 'A' + 2;
}
CHAR_MAP[TABLE_LOWER][' '] = 1;
for (int c = 'a'; c <= 'z'; c++) {
CHAR_MAP[TABLE_LOWER][c] = c - 'a' + 2;
}
CHAR_MAP[TABLE_DIGIT][' '] = 1;
for (int c = '0'; c <= '9'; c++) {
CHAR_MAP[TABLE_DIGIT][c] = c - '0' + 2;
}
CHAR_MAP[TABLE_DIGIT][','] = 12;
CHAR_MAP[TABLE_DIGIT]['.'] = 13;
int[] mixedTable = {
'\0', ' ', '\1', '\2', '\3', '\4', '\5', '\6', '\7', '\b', '\t', '\n', '\13', '\f', '\r',
'\33', '\34', '\35', '\36', '\37', '@', '\\', '^', '_', '`', '|', '~', '\177'
};
for (int i = 0; i < mixedTable.length; i++) {
CHAR_MAP[TABLE_MIXED][mixedTable[i]] = i;
}
int[] punctTable = {
'\0', '\r', '\0', '\0', '\0', '\0', '!', '\'', '#', '$', '%', '&', '\'', '(', ')', '*', '+',
',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', ']', '{', '}'
};
for (int i = 0; i < punctTable.length; i++) {
if (punctTable[i] > 0) {
CHAR_MAP[TABLE_PUNCT][punctTable[i]] = i;
}
}
for (int[] table : SHIFT_TABLE) {
Arrays.fill(table, -1);
}
for (int[] table : LATCH_TABLE) {
Arrays.fill(table, -1);
}
SHIFT_TABLE[TABLE_UPPER][TABLE_PUNCT] = 0;
LATCH_TABLE[TABLE_UPPER][TABLE_LOWER] = 28;
LATCH_TABLE[TABLE_UPPER][TABLE_MIXED] = 29;
LATCH_TABLE[TABLE_UPPER][TABLE_DIGIT] = 30;
SHIFT_TABLE[TABLE_UPPER][TABLE_BINARY] = 31;
SHIFT_TABLE[TABLE_LOWER][TABLE_PUNCT] = 0;
SHIFT_TABLE[TABLE_LOWER][TABLE_UPPER] = 28;
LATCH_TABLE[TABLE_LOWER][TABLE_MIXED] = 29;
LATCH_TABLE[TABLE_LOWER][TABLE_DIGIT] = 30;
SHIFT_TABLE[TABLE_LOWER][TABLE_BINARY] = 31;
SHIFT_TABLE[TABLE_MIXED][TABLE_PUNCT] = 0;
LATCH_TABLE[TABLE_MIXED][TABLE_LOWER] = 28;
LATCH_TABLE[TABLE_MIXED][TABLE_UPPER] = 29;
LATCH_TABLE[TABLE_MIXED][TABLE_PUNCT] = 30;
SHIFT_TABLE[TABLE_MIXED][TABLE_BINARY] = 31;
LATCH_TABLE[TABLE_PUNCT][TABLE_UPPER] = 31;
SHIFT_TABLE[TABLE_DIGIT][TABLE_PUNCT] = 0;
LATCH_TABLE[TABLE_DIGIT][TABLE_UPPER] = 30;
SHIFT_TABLE[TABLE_DIGIT][TABLE_UPPER] = 31;
NB_BITS_COMPACT = new int[5];
for (int i = 1; i < NB_BITS_COMPACT.length; i++) {
NB_BITS_COMPACT[i] = (88 + 16 * i) * i;
}
NB_BITS = new int[33];
for (int i = 1; i < NB_BITS.length; i++) {
NB_BITS[i] = (112 + 16 * i) * i;
}
}
private static final int[] WORD_SIZE = {
4, 6, 6, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12
};
private Encoder() {
}
/**
* Encodes the given binary content as an Aztec symbol
*
* @param data input data string
* @return Aztec symbol matrix with metadata
*/
public static AztecCode encode(byte[] data) {
return encode(data, DEFAULT_EC_PERCENT);
}
/**
* Encodes the given binary content as an Aztec symbol
*
* @param data input data string
* @param minECCPercent minimal percentange of error check words (According to ISO/IEC 24778:2008,
* a minimum of 23% + 3 words is recommended)
* @return Aztec symbol matrix with metadata
*/
public static AztecCode encode(byte[] data, int minECCPercent) {
AztecCode aztec = new AztecCode();
// High-level encode
BitArray bits = highLevelEncode(data);
// stuff bits and choose symbol size
int eccBits = bits.getSize() * minECCPercent / 100 + 11;
int totalSizeBits = bits.getSize() + eccBits;
int layers;
int wordSize = 0;
int totalSymbolBits = 0;
BitArray stuffedBits = null;
for (layers = 1; layers < NB_BITS_COMPACT.length; layers++) {
if (NB_BITS_COMPACT[layers] >= totalSizeBits) {
if (wordSize != WORD_SIZE[layers]) {
wordSize = WORD_SIZE[layers];
stuffedBits = stuffBits(bits, wordSize);
}
totalSymbolBits = NB_BITS_COMPACT[layers];
if (stuffedBits.getSize() + eccBits <= NB_BITS_COMPACT[layers]) {
break;
}
}
}
boolean compact = true;
if (layers == NB_BITS_COMPACT.length) {
compact = false;
for (layers = 1; layers < NB_BITS.length; layers++) {
if (NB_BITS[layers] >= totalSizeBits) {
if (wordSize != WORD_SIZE[layers]) {
wordSize = WORD_SIZE[layers];
stuffedBits = stuffBits(bits, wordSize);
}
totalSymbolBits = NB_BITS[layers];
if (stuffedBits.getSize() + eccBits <= NB_BITS[layers]) {
break;
}
}
}
}
if (layers == NB_BITS.length) {
throw new IllegalArgumentException("Data too large for an Aztec code");
}
// pad the end
int messageSizeInWords = (stuffedBits.getSize() + wordSize - 1) / wordSize;
for (int i = messageSizeInWords * wordSize - stuffedBits.getSize(); i > 0; i--) {
stuffedBits.appendBit(true);
}
// generate check words
ReedSolomonEncoder rs = new ReedSolomonEncoder(getGF(wordSize));
int totalSizeInFullWords = totalSymbolBits / wordSize;
int[] messageWords = bitsToWords(stuffedBits, wordSize, totalSizeInFullWords);
rs.encode(messageWords, totalSizeInFullWords - messageSizeInWords);
// convert to bit array and pad in the beginning
int startPad = totalSymbolBits % wordSize;
BitArray messageBits = new BitArray();
messageBits.appendBits(0, startPad);
for (int messageWord : messageWords) {
messageBits.appendBits(messageWord, wordSize);
}
// generate mode message
BitArray modeMessage = generateModeMessage(compact, layers, messageSizeInWords);
// allocate symbol
int baseMatrixSize = compact ? 11 + layers * 4 : 14 + layers * 4; // not including alignment lines
int[] alignmentMap = new int[baseMatrixSize];
int matrixSize;
if (compact) {
// no alignment marks in compact mode, alignmentMap is a no-op
matrixSize = baseMatrixSize;
for (int i = 0; i < alignmentMap.length; i++) {
alignmentMap[i] = i;
}
} else {
matrixSize = baseMatrixSize + 1 + 2 * ((baseMatrixSize / 2 - 1) / 15);
int origCenter = baseMatrixSize / 2;
int center = matrixSize / 2;
for (int i = 0; i < origCenter; i++) {
int newOffset = i + i / 15;
alignmentMap[origCenter - i - 1] = center - newOffset - 1;
alignmentMap[origCenter + i] = center + newOffset + 1;
}
}
BitMatrix matrix = new BitMatrix(matrixSize);
// draw mode and data bits
for (int i = 0, rowOffset = 0; i < layers; i++) {
int rowSize = compact ? (layers - i) * 4 + 9 : (layers - i) * 4 + 12;
for (int j = 0; j < rowSize; j++) {
int columnOffset = j * 2;
for (int k = 0; k < 2; k++) {
if (messageBits.get(rowOffset + columnOffset + k)) {
matrix.set(alignmentMap[i * 2 + k], alignmentMap[i * 2 + j]);
}
if (messageBits.get(rowOffset + rowSize * 2 + columnOffset + k)) {
matrix.set(alignmentMap[i * 2 + j], alignmentMap[baseMatrixSize - 1 - i * 2 - k]);
}
if (messageBits.get(rowOffset + rowSize * 4 + columnOffset + k)) {
matrix.set(alignmentMap[baseMatrixSize - 1 - i * 2 - k], alignmentMap[baseMatrixSize - 1 - i * 2 - j]);
}
if (messageBits.get(rowOffset + rowSize * 6 + columnOffset + k)) {
matrix.set(alignmentMap[baseMatrixSize - 1 - i * 2 - j], alignmentMap[i * 2 + k]);
}
}
}
rowOffset += rowSize * 8;
}
drawModeMessage(matrix, compact, matrixSize, modeMessage);
// draw alignment marks
if (compact) {
drawBullsEye(matrix, matrixSize / 2, 5);
} else {
drawBullsEye(matrix, matrixSize / 2, 7);
for (int i = 0, j = 0; i < baseMatrixSize / 2 - 1; i += 15, j += 16) {
for (int k = (matrixSize / 2) & 1; k < matrixSize; k += 2) {
matrix.set(matrixSize / 2 - j, k);
matrix.set(matrixSize / 2 + j, k);
matrix.set(k, matrixSize / 2 - j);
matrix.set(k, matrixSize / 2 + j);
}
}
}
aztec.setCompact(compact);
aztec.setSize(matrixSize);
aztec.setLayers(layers);
aztec.setCodeWords(messageSizeInWords);
aztec.setMatrix(matrix);
return aztec;
}
static void drawBullsEye(BitMatrix matrix, int center, int size) {
for (int i = 0; i < size; i += 2) {
for (int j = center - i; j <= center + i; j++) {
matrix.set(j, center - i);
matrix.set(j, center + i);
matrix.set(center - i, j);
matrix.set(center + i, j);
}
}
matrix.set(center - size, center - size);
matrix.set(center - size + 1, center - size);
matrix.set(center - size, center - size + 1);
matrix.set(center + size, center - size);
matrix.set(center + size, center - size + 1);
matrix.set(center + size, center + size - 1);
}
static BitArray generateModeMessage(boolean compact, int layers, int messageSizeInWords) {
BitArray modeMessage = new BitArray();
if (compact) {
modeMessage.appendBits(layers - 1, 2);
modeMessage.appendBits(messageSizeInWords - 1, 6);
modeMessage = generateCheckWords(modeMessage, 28, 4);
} else {
modeMessage.appendBits(layers - 1, 5);
modeMessage.appendBits(messageSizeInWords - 1, 11);
modeMessage = generateCheckWords(modeMessage, 40, 4);
}
return modeMessage;
}
static void drawModeMessage(BitMatrix matrix, boolean compact, int matrixSize, BitArray modeMessage) {
if (compact) {
for (int i = 0; i < 7; i++) {
if (modeMessage.get(i)) {
matrix.set(matrixSize / 2 - 3 + i, matrixSize / 2 - 5);
}
if (modeMessage.get(i + 7)) {
matrix.set(matrixSize / 2 + 5, matrixSize / 2 - 3 + i);
}
if (modeMessage.get(20 - i)) {
matrix.set(matrixSize / 2 - 3 + i, matrixSize / 2 + 5);
}
if (modeMessage.get(27 - i)) {
matrix.set(matrixSize / 2 - 5, matrixSize / 2 - 3 + i);
}
}
} else {
for (int i = 0; i < 10; i++) {
if (modeMessage.get(i)) {
matrix.set(matrixSize / 2 - 5 + i + i / 5, matrixSize / 2 - 7);
}
if (modeMessage.get(i + 10)) {
matrix.set(matrixSize / 2 + 7, matrixSize / 2 - 5 + i + i / 5);
}
if (modeMessage.get(29 - i)) {
matrix.set(matrixSize / 2 - 5 + i + i / 5, matrixSize / 2 + 7);
}
if (modeMessage.get(39 - i)) {
matrix.set(matrixSize / 2 - 7, matrixSize / 2 - 5 + i + i / 5);
}
}
}
}
static BitArray generateCheckWords(BitArray stuffedBits, int totalSymbolBits, int wordSize) {
int messageSizeInWords = (stuffedBits.getSize() + wordSize - 1) / wordSize;
for (int i = messageSizeInWords * wordSize - stuffedBits.getSize(); i > 0; i--) {
stuffedBits.appendBit(true);
}
ReedSolomonEncoder rs = new ReedSolomonEncoder(getGF(wordSize));
int totalSizeInFullWords = totalSymbolBits / wordSize;
int[] messageWords = bitsToWords(stuffedBits, wordSize, totalSizeInFullWords);
rs.encode(messageWords, totalSizeInFullWords - messageSizeInWords);
int startPad = totalSymbolBits % wordSize;
BitArray messageBits = new BitArray();
messageBits.appendBits(0, startPad);
for (int messageWord : messageWords) {
messageBits.appendBits(messageWord, wordSize);
}
return messageBits;
}
static int[] bitsToWords(BitArray stuffedBits, int wordSize, int totalWords) {
int[] message = new int[totalWords];
int i;
int n;
for (i = 0, n = stuffedBits.getSize() / wordSize; i < n; i++) {
int value = 0;
for (int j = 0; j < wordSize; j++) {
value |= stuffedBits.get(i * wordSize + j) ? (1 << wordSize - j - 1) : 0;
}
message[i] = value;
}
return message;
}
static GenericGF getGF(int wordSize) {
switch (wordSize) {
case 4:
return GenericGF.AZTEC_PARAM;
case 6:
return GenericGF.AZTEC_DATA_6;
case 8:
return GenericGF.AZTEC_DATA_8;
case 10:
return GenericGF.AZTEC_DATA_10;
case 12:
return GenericGF.AZTEC_DATA_12;
default:
return null;
}
}
static BitArray stuffBits(BitArray bits, int wordSize) {
BitArray out = new BitArray();
// 1. stuff the bits
int n = bits.getSize();
int mask = (1 << wordSize) - 2;
for (int i = 0; i < n; i += wordSize) {
int word = 0;
for (int j = 0; j < wordSize; j++) {
if (i + j >= n || bits.get(i + j)) {
word |= 1 << (wordSize - 1 - j);
}
}
if ((word & mask) == mask) {
out.appendBits(word & mask, wordSize);
i--;
} else if ((word & mask) == 0) {
out.appendBits(word | 1, wordSize);
i--;
} else {
out.appendBits(word, wordSize);
}
}
// 2. pad last word to wordSize
n = out.getSize();
int remainder = n % wordSize;
if (remainder != 0) {
int j = 1;
for (int i = 0; i < remainder; i++) {
if (!out.get(n - 1 - i)) {
j = 0;
}
}
for (int i = remainder; i < wordSize - 1; i++) {
out.appendBit(true);
}
out.appendBit(j == 0);
}
return out;
}
static BitArray highLevelEncode(byte[] data) {
BitArray bits = new BitArray();
int mode = TABLE_UPPER;
int[] idx = new int[5];
int[] idxnext = new int[5];
for (int i = 0; i < data.length; i++) {
int c = data[i] & 0xFF;
int next = i < data.length - 1 ? data[i + 1] & 0xFF : 0;
int punctWord = 0;
// special case: double-character codes
if (c == '\r' && next == '\n') {
punctWord = 2;
} else if (c == '.' && next == ' ') {
punctWord = 3;
} else if (c == ',' && next == ' ') {
punctWord = 4;
} else if (c == ':' && next == ' ') {
punctWord = 5;
}
if (punctWord > 0) {
if (mode == TABLE_PUNCT) {
outputWord(bits, TABLE_PUNCT, punctWord);
i++;
continue;
} else if (SHIFT_TABLE[mode][TABLE_PUNCT] >= 0) {
outputWord(bits, mode, SHIFT_TABLE[mode][TABLE_PUNCT]);
outputWord(bits, TABLE_PUNCT, punctWord);
i++;
continue;
} else if (LATCH_TABLE[mode][TABLE_PUNCT] >= 0) {
outputWord(bits, mode, LATCH_TABLE[mode][TABLE_PUNCT]);
outputWord(bits, TABLE_PUNCT, punctWord);
mode = TABLE_PUNCT;
i++;
continue;
}
}
// find the best matching table, taking current mode and next character into account
int firstMatch = -1;
int shiftMode = -1;
int latchMode = -1;
int j;
for (j = 0; j < TABLE_BINARY; j++) {
idx[j] = CHAR_MAP[j][c];
if (idx[j] > 0 && firstMatch < 0) {
firstMatch = j;
}
if (shiftMode < 0 && idx[j] > 0 && SHIFT_TABLE[mode][j] >= 0) {
shiftMode = j;
}
idxnext[j] = CHAR_MAP[j][next];
if (latchMode < 0 && idx[j] > 0 && (next == 0 || idxnext[j] > 0) && LATCH_TABLE[mode][j] >= 0) {
latchMode = j;
}
}
if (shiftMode < 0 && latchMode < 0) {
for (j = 0; j < TABLE_BINARY; j++) {
if (idx[j] > 0 && LATCH_TABLE[mode][j] >= 0) {
latchMode = j;
break;
}
}
}
if (idx[mode] > 0) {
// found character in current table - stay in current table
outputWord(bits, mode, idx[mode]);
} else {
if (latchMode >= 0) {
// latch into mode latchMode
outputWord(bits, mode, LATCH_TABLE[mode][latchMode]);
outputWord(bits, latchMode, idx[latchMode]);
mode = latchMode;
} else if (shiftMode >= 0) {
// shift into shiftMode
outputWord(bits, mode, SHIFT_TABLE[mode][shiftMode]);
outputWord(bits, shiftMode, idx[shiftMode]);
} else {
if (firstMatch >= 0) {
// can't switch into this mode from current mode - switch in two steps
if (mode == TABLE_PUNCT) {
outputWord(bits, TABLE_PUNCT, LATCH_TABLE[TABLE_PUNCT][TABLE_UPPER]);
mode = TABLE_UPPER;
i--;
continue;
} else if (mode == TABLE_DIGIT) {
outputWord(bits, TABLE_DIGIT, LATCH_TABLE[TABLE_DIGIT][TABLE_UPPER]);
mode = TABLE_UPPER;
i--;
continue;
}
}
// use binary table
// find the binary string length
int k;
int lookahead;
for (k = i + 1, lookahead = 0; k < data.length; k++) {
next = data[k] & 0xFF;
boolean binary = true;
for (j = 0; j < TABLE_BINARY; j++) {
if (CHAR_MAP[j][next] > 0) {
binary = false;
break;
}
}
if (binary) {
lookahead = 0;
} else {
// skip over single character in between binary bytes
if (lookahead >= 1) {
k -= lookahead;
break;
}
lookahead++;
}
}
k -= i;
// switch into binary table
switch (mode) {
case TABLE_UPPER:
case TABLE_LOWER:
case TABLE_MIXED:
outputWord(bits, mode, SHIFT_TABLE[mode][TABLE_BINARY]);
break;
case TABLE_DIGIT:
outputWord(bits, mode, LATCH_TABLE[mode][TABLE_UPPER]);
mode = TABLE_UPPER;
outputWord(bits, mode, SHIFT_TABLE[mode][TABLE_BINARY]);
break;
case TABLE_PUNCT:
outputWord(bits, mode, LATCH_TABLE[mode][TABLE_UPPER]);
mode = TABLE_UPPER;
outputWord(bits, mode, SHIFT_TABLE[mode][TABLE_BINARY]);
break;
}
if (k >= 32 && k < 63) { // optimization: split one long form into two short forms, saves 1 bit
k = 31;
}
if (k > 542) { // maximum encodable binary length in long form is 511 + 31
k = 542;
}
if (k < 32) {
bits.appendBits(k, 5);
} else {
bits.appendBits(k - 31, 16);
}
for (; k > 0; k--, i++) {
bits.appendBits(data[i], 8);
}
i--;
}
}
}
return bits;
}
static void outputWord(BitArray bits, int mode, int value) {
if (mode == TABLE_DIGIT) {
bits.appendBits(value, 4);
} else if (mode < TABLE_BINARY) {
bits.appendBits(value, 5);
} else {
bits.appendBits(value, 8);
}
}
}

View file

@ -29,12 +29,12 @@ package com.google.zxing.common.reedsolomon;
*/ */
public final class GenericGF { public final class GenericGF {
public static final GenericGF AZTEC_DATA_12 = new GenericGF(0x1069, 4096); // x^12 + x^6 + x^5 + x^3 + 1 public static final GenericGF AZTEC_DATA_12 = new GenericGF(0x1069, 4096, 1); // x^12 + x^6 + x^5 + x^3 + 1
public static final GenericGF AZTEC_DATA_10 = new GenericGF(0x409, 1024); // x^10 + x^3 + 1 public static final GenericGF AZTEC_DATA_10 = new GenericGF(0x409, 1024, 1); // x^10 + x^3 + 1
public static final GenericGF AZTEC_DATA_6 = new GenericGF(0x43, 64); // x^6 + x + 1 public static final GenericGF AZTEC_DATA_6 = new GenericGF(0x43, 64, 1); // x^6 + x + 1
public static final GenericGF AZTEC_PARAM = new GenericGF(0x13, 16); // x^4 + x + 1 public static final GenericGF AZTEC_PARAM = new GenericGF(0x13, 16, 1); // x^4 + x + 1
public static final GenericGF QR_CODE_FIELD_256 = new GenericGF(0x011D, 256); // x^8 + x^4 + x^3 + x^2 + 1 public static final GenericGF QR_CODE_FIELD_256 = new GenericGF(0x011D, 256, 0); // x^8 + x^4 + x^3 + x^2 + 1
public static final GenericGF DATA_MATRIX_FIELD_256 = new GenericGF(0x012D, 256); // x^8 + x^5 + x^3 + x^2 + 1 public static final GenericGF DATA_MATRIX_FIELD_256 = new GenericGF(0x012D, 256, 1); // x^8 + x^5 + x^3 + x^2 + 1
public static final GenericGF AZTEC_DATA_8 = DATA_MATRIX_FIELD_256; public static final GenericGF AZTEC_DATA_8 = DATA_MATRIX_FIELD_256;
public static final GenericGF MAXICODE_FIELD_64 = AZTEC_DATA_6; public static final GenericGF MAXICODE_FIELD_64 = AZTEC_DATA_6;
@ -46,6 +46,7 @@ public final class GenericGF {
private GenericGFPoly one; private GenericGFPoly one;
private final int size; private final int size;
private final int primitive; private final int primitive;
private final int generatorBase;
private boolean initialized = false; private boolean initialized = false;
/** /**
@ -54,17 +55,22 @@ public final class GenericGF {
* @param primitive irreducible polynomial whose coefficients are represented by * @param primitive irreducible polynomial whose coefficients are represented by
* the bits of an int, where the least-significant bit represents the constant * the bits of an int, where the least-significant bit represents the constant
* coefficient * coefficient
* @param size the size of the field
* @param b the factor b in the generator polynomial can be 0- or 1-based
* (g(x) = (x+a^b)(x+a^(b+1))...(x+a^(b+2t-1))).
* In most cases it should be 1, but for QR code it is 0.
*/ */
public GenericGF(int primitive, int size) { public GenericGF(int primitive, int size, int b) {
this.primitive = primitive; this.primitive = primitive;
this.size = size; this.size = size;
this.generatorBase = b;
if (size <= INITIALIZATION_THRESHOLD){ if (size <= INITIALIZATION_THRESHOLD) {
initialize(); initialize();
} }
} }
private void initialize(){ private void initialize() {
expTable = new int[size]; expTable = new int[size];
logTable = new int[size]; logTable = new int[size];
int x = 1; int x = 1;
@ -85,7 +91,7 @@ public final class GenericGF {
initialized = true; initialized = true;
} }
private void checkInit(){ private void checkInit() {
if (!initialized) { if (!initialized) {
initialize(); initialize();
} }
@ -178,4 +184,13 @@ public final class GenericGF {
return size; return size;
} }
public int getGeneratorBase() {
return generatorBase;
}
@Override
public String toString() {
return "GF(0x" + Integer.toHexString(primitive) + ',' + size + ')';
}
} }

View file

@ -58,11 +58,9 @@ public final class ReedSolomonDecoder {
public void decode(int[] received, int twoS) throws ReedSolomonException { public void decode(int[] received, int twoS) throws ReedSolomonException {
GenericGFPoly poly = new GenericGFPoly(field, received); GenericGFPoly poly = new GenericGFPoly(field, received);
int[] syndromeCoefficients = new int[twoS]; int[] syndromeCoefficients = new int[twoS];
boolean dataMatrix = field.equals(GenericGF.DATA_MATRIX_FIELD_256);
boolean noError = true; boolean noError = true;
for (int i = 0; i < twoS; i++) { for (int i = 0; i < twoS; i++) {
// Thanks to sanfordsquires for this fix: int eval = poly.evaluateAt(field.exp(i + field.getGeneratorBase()));
int eval = poly.evaluateAt(field.exp(dataMatrix ? i + 1 : i));
syndromeCoefficients[syndromeCoefficients.length - 1 - i] = eval; syndromeCoefficients[syndromeCoefficients.length - 1 - i] = eval;
if (eval != 0) { if (eval != 0) {
noError = false; noError = false;
@ -77,7 +75,7 @@ public final class ReedSolomonDecoder {
GenericGFPoly sigma = sigmaOmega[0]; GenericGFPoly sigma = sigmaOmega[0];
GenericGFPoly omega = sigmaOmega[1]; GenericGFPoly omega = sigmaOmega[1];
int[] errorLocations = findErrorLocations(sigma); int[] errorLocations = findErrorLocations(sigma);
int[] errorMagnitudes = findErrorMagnitudes(omega, errorLocations, dataMatrix); int[] errorMagnitudes = findErrorMagnitudes(omega, errorLocations);
for (int i = 0; i < errorLocations.length; i++) { for (int i = 0; i < errorLocations.length; i++) {
int position = received.length - 1 - field.log(errorLocations[i]); int position = received.length - 1 - field.log(errorLocations[i]);
if (position < 0) { if (position < 0) {
@ -158,9 +156,7 @@ public final class ReedSolomonDecoder {
return result; return result;
} }
private int[] findErrorMagnitudes(GenericGFPoly errorEvaluator, private int[] findErrorMagnitudes(GenericGFPoly errorEvaluator, int[] errorLocations) {
int[] errorLocations,
boolean dataMatrix) {
// This is directly applying Forney's Formula // This is directly applying Forney's Formula
int s = errorLocations.length; int s = errorLocations.length;
int[] result = new int[s]; int[] result = new int[s];
@ -180,8 +176,7 @@ public final class ReedSolomonDecoder {
} }
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: if (field.getGeneratorBase() != 0) {
if (dataMatrix) {
result[i] = field.multiply(result[i], xiInverse); result[i] = field.multiply(result[i], xiInverse);
} }
} }

View file

@ -31,9 +31,6 @@ public final class ReedSolomonEncoder {
private final List<GenericGFPoly> cachedGenerators; private final List<GenericGFPoly> cachedGenerators;
public ReedSolomonEncoder(GenericGF field) { public ReedSolomonEncoder(GenericGF field) {
if (!GenericGF.QR_CODE_FIELD_256.equals(field)) {
throw new IllegalArgumentException("Only QR Code is supported at this time");
}
this.field = field; this.field = field;
this.cachedGenerators = new ArrayList<GenericGFPoly>(); this.cachedGenerators = new ArrayList<GenericGFPoly>();
cachedGenerators.add(new GenericGFPoly(field, new int[]{1})); cachedGenerators.add(new GenericGFPoly(field, new int[]{1}));
@ -43,7 +40,8 @@ public final class ReedSolomonEncoder {
if (degree >= cachedGenerators.size()) { if (degree >= cachedGenerators.size()) {
GenericGFPoly lastGenerator = cachedGenerators.get(cachedGenerators.size() - 1); GenericGFPoly lastGenerator = cachedGenerators.get(cachedGenerators.size() - 1);
for (int d = cachedGenerators.size(); d <= degree; d++) { for (int d = cachedGenerators.size(); d <= degree; d++) {
GenericGFPoly nextGenerator = lastGenerator.multiply(new GenericGFPoly(field, new int[] { 1, field.exp(d - 1) })); GenericGFPoly nextGenerator = lastGenerator.multiply(
new GenericGFPoly(field, new int[] { 1, field.exp(d - 1 + field.getGeneratorBase()) }));
cachedGenerators.add(nextGenerator); cachedGenerators.add(nextGenerator);
lastGenerator = nextGenerator; lastGenerator = nextGenerator;
} }

View file

@ -0,0 +1,369 @@
/*
* Copyright 2013 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.aztec.encoder;
import java.io.File;
import java.nio.charset.Charset;
import java.security.SecureRandom;
import java.util.Random;
import java.util.regex.Pattern;
import org.junit.Assert;
import org.junit.Test;
import com.google.zxing.ResultPoint;
import com.google.zxing.aztec.AztecDetectorResult;
import com.google.zxing.aztec.decoder.Decoder;
import com.google.zxing.common.BitArray;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.DecoderResult;
/**
* Aztec 2D generator unit tests.
*
* @author Rustam Abdullaev
*/
public final class EncoderTest extends Assert {
private static final Charset LATIN_1 = Charset.forName("ISO-8859-1");
private static final Pattern DOTX = Pattern.compile("[^.X]");
public static final ResultPoint[] NO_POINTS = new ResultPoint[0];
// real life tests
@Test
public void testEncode1() throws Exception {
testEncode("This is an example Aztec symbol for Wikipedia.", true, 3,
"X X X X X X X X \n" +
"X X X X X X X X X X \n" +
"X X X X X X X X X X X \n" +
"X X X X X X X X X X X \n" +
" X X X X X X X X X X X \n" +
" X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X \n" +
"X X X X X X X X X X X X X X X X \n" +
"X X X X X X X X X X X \n" +
"X X X X X X X X X X X X X X X X \n" +
"X X X X X X X X X X \n" +
"X X X X X X X X X X \n" +
" X X X X X X X X X X \n" +
" X X X X X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X \n" +
" X X X X X X X X \n" +
" X X X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X \n" +
" X X X \n" +
" X X X X X X X X X X \n" +
" X X X X X X X X X X \n");
}
@Test
public void testEncode2() throws Exception {
testEncode("Aztec Code is a public domain 2D matrix barcode symbology" +
" of nominally square symbols built on a square grid with a " +
"distinctive square bullseye pattern at their center.", false, 6,
" X X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X X X X X X X X \n" +
"X X X X X X X X X X X X X X \n" +
"X X X X X X X X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X X X X X \n" +
"X X X X X X X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X X X \n" +
"X X X X X X X X X X X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X X X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X X X X X X X \n" +
"X X X X X X X X X X X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X X \n" +
"X X X X X X X X X X X X X X X X X X X X X X \n" +
"X X X X X X X X X X X X X X X X X X X X X \n" +
"X X X X X X X X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X \n" +
" X X X X X X X X X X X X X X X X X X X X X \n" +
"X X X X X X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X X X X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X X X X X X X X \n" +
"X X X X X X X X X X X X X X X X X X X \n" +
"X X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X X X X X X X X X X X \n" +
"X X X X X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X X X X \n" +
"X X X X X X X X X X X X X X X X X \n" +
"X X X X X X X X X X X X X X X X X X X X X X X \n" +
"X X X X X X X X X X X X X X X X X X X X X \n" +
"X X X X X X X X X X X X X X X X \n" +
"X X X X X X X X X X X X X X X X X X X X X \n" +
" X X X X X X X X X X X X X X X X \n" +
"X X X X X X X X X X X X X \n");
}
// synthetic tests (encode-decode round-trip)
@Test
public void testEncodeDecode1() throws Exception {
testEncodeDecode("Abc123!", true, 1);
}
@Test
public void testEncodeDecode2() throws Exception {
testEncodeDecode("Lorem ipsum. http://test/", true, 2);
}
@Test
public void testEncodeDecode3() throws Exception {
testEncodeDecode("AAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAAN", true, 3);
}
@Test
public void testEncodeDecode4() throws Exception {
testEncodeDecode("http://test/~!@#*^%&)__ ;:'\"[]{}\\|-+-=`1029384", true, 4);
}
@Test
public void testEncodeDecode5() throws Exception {
testEncodeDecode("http://test/~!@#*^%&)__ ;:'\"[]{}\\|-+-=`1029384756<>/?abc", false, 5);
}
@Test
public void testEncodeDecode10() throws Exception {
testEncodeDecode("In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam" +
" cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum" +
" est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue" +
" auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla" +
" ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar nisi, id" +
" elementum sapien dolor et diam.", false, 10);
}
@Test
public void testEncodeDecode23() throws Exception {
testEncodeDecode("In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam" +
" cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum" +
" est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue" +
" auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla" +
" ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar nisi, id" +
" elementum sapien dolor et diam. Donec ac nunc sodales elit placerat eleifend." +
" Sed ornare luctus ornare. Vestibulum vehicula, massa at pharetra fringilla, risus" +
" justo faucibus erat, nec porttitor nibh tellus sed est. Ut justo diam, lobortis eu" +
" tristique ac, p.In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus" +
" quis diam cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec" +
" laoreet rutrum est, nec convallis mauris condimentum sit amet. Phasellus gravida," +
" justo et congue auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec" +
" lorem. Nulla ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar" +
" nisi, id elementum sapien dolor et diam. Donec ac nunc sodales elit placerat" +
" eleifend. Sed ornare luctus ornare. Vestibulum vehicula, massa at pharetra" +
" fringilla, risus justo faucibus erat, nec porttitor nibh tellus sed est. Ut justo" +
" diam, lobortis eu tristique ac, p. In ut magna vel mauris malesuada dictum. Nulla" +
" ullamcorper metus quis diam cursus facilisis. Sed mollis quam id justo rutrum" +
" sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum sit amet." +
" Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat, eget hendrerit" +
" felis turpis nec lorem. Nulla ultrices, elit pellentesque aliquet laoreet, justo" +
" erat pulvinar nisi, id elementum sapien dolor et diam.", false, 23);
}
@Test
public void testEncodeDecode31() throws Exception {
testEncodeDecode("In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam" +
" cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum" +
" est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue" +
" auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla" +
" ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar nisi, id" +
" elementum sapien dolor et diam. Donec ac nunc sodales elit placerat eleifend." +
" Sed ornare luctus ornare. Vestibulum vehicula, massa at pharetra fringilla, risus" +
" justo faucibus erat, nec porttitor nibh tellus sed est. Ut justo diam, lobortis eu" +
" tristique ac, p.In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus" +
" quis diam cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec" +
" laoreet rutrum est, nec convallis mauris condimentum sit amet. Phasellus gravida," +
" justo et congue auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec" +
" lorem. Nulla ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar" +
" nisi, id elementum sapien dolor et diam. Donec ac nunc sodales elit placerat" +
" eleifend. Sed ornare luctus ornare. Vestibulum vehicula, massa at pharetra" +
" fringilla, risus justo faucibus erat, nec porttitor nibh tellus sed est. Ut justo" +
" diam, lobortis eu tristique ac, p. In ut magna vel mauris malesuada dictum. Nulla" +
" ullamcorper metus quis diam cursus facilisis. Sed mollis quam id justo rutrum" +
" sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum sit amet." +
" Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat, eget hendrerit" +
" felis turpis nec lorem. Nulla ultrices, elit pellentesque aliquet laoreet, justo" +
" erat pulvinar nisi, id elementum sapien dolor et diam. Donec ac nunc sodales elit" +
" placerat eleifend. Sed ornare luctus ornare. Vestibulum vehicula, massa at" +
" pharetra fringilla, risus justo faucibus erat, nec porttitor nibh tellus sed est." +
" Ut justo diam, lobortis eu tristique ac, p.In ut magna vel mauris malesuada" +
" dictum. Nulla ullamcorper metus quis diam cursus facilisis. Sed mollis quam id" +
" justo rutrum sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum" +
" sit amet. Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat," +
" eget hendrerit felis turpis nec lorem. Nulla ultrices, elit pellentesque aliquet" +
" laoreet, justo erat pulvinar nisi, id elementum sapien dolor et diam. Donec ac" +
" nunc sodales elit placerat eleifend. Sed ornare luctus ornare. Vestibulum vehicula," +
" massa at pharetra fringilla, risus justo faucibus erat, nec porttitor nibh tellus" +
" sed est. Ut justo diam, lobortis eu tris. In ut magna vel mauris malesuada dictum." +
" Nulla ullamcorper metus quis diam cursus facilisis. Sed mollis quam id justo rutrum" +
" sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum sit amet." +
" Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat, eget" +
" hendrerit felis turpis nec lorem.", false, 31);
}
@Test
public void testGenerateModeMessage() {
testModeMessage(true, 2, 29, ".X .XXX.. ...X XX.. ..X .XX. .XX.X");
testModeMessage(true, 4, 64, "XX XXXXXX .X.. ...X ..XX .X.. XX..");
testModeMessage(false, 21, 660, "X.X.. .X.X..X..XX .XXX ..X.. .XXX. .X... ..XXX");
testModeMessage(false, 32, 4096, "XXXXX XXXXXXXXXXX X.X. ..... XXX.X ..X.. X.XXX");
}
@Test
public void testStuffBits() {
testStuffBits(5, ".X.X. X.X.X .X.X.",
".X.X. X.X.X .X.X.");
testStuffBits(5, ".X.X. ..... .X.X",
".X.X. ....X ..X.X");
testStuffBits(3, "XX. ... ... ..X XXX .X. ..",
"XX. ..X ..X ..X ..X .XX XX. .X. ..X");
testStuffBits(6, ".X.X.. ...... ..X.XX",
".X.X.. .....X. ..X.XX XXXX.");
testStuffBits(6, ".X.X.. ...... ...... ..X.X.",
".X.X.. .....X .....X ....X. X.XXXX");
testStuffBits(6, ".X.X.. XXXXXX ...... ..X.XX",
".X.X.. XXXXX. X..... ...X.X XXXXX.");
testStuffBits(6,
"...... ..XXXX X..XX. .X.... .X.X.X .....X .X.... ...X.X .....X ....XX ..X... ....X. X..XXX X.XX.X",
".....X ...XXX XX..XX ..X... ..X.X. X..... X.X... ....X. X..... X....X X..X.. .....X X.X..X XXX.XX .XXXXX");
}
@Test
public void testHighLevelEncode() throws Exception {
testHighLevelEncodeString("A. b.",
"...X. ..... ...XX XXX.. ...XX XXXX. XX.X");
testHighLevelEncodeString("Lorem ipsum.",
".XX.X XXX.. X.... X..XX ..XX. .XXX. ....X .X.X. X...X X.X.. X.XX. .XXX. XXXX. XX.X");
testHighLevelEncodeString("Lo. Test 123.",
".XX.X XXX.. X.... ..... ...XX XXX.. X.X.X ..XX. X.X.. X.X.X ....X XXXX. ..XX .X.. .X.X XX.X");
testHighLevelEncodeString("Lo...x",
".XX.X XXX.. X.... XXXX. XX.X XX.X XX.X XXX. XXX.. XX..X");
testHighLevelEncodeString(". x://abc/.",
"..... ...XX XXX.. XX..X ..... X.X.X ..... X.X.. ..... X.X.. ...X. ...XX ..X.. ..... X.X.. XXXX. XX.X");
}
@Test
public void testHighLevelEncodeBinary() throws Exception {
// binary short form single byte
testHighLevelEncodeString("N\0N",
".XXXX XXXXX ...X. ........ .X..XXX.");
// binary short form consecutive bytes
testHighLevelEncodeString("N\0\u0080 A",
".XXXX XXXXX ...X. ........ X....... ....X ...X.");
// binary skipping over single character
testHighLevelEncodeString("\0a\u00FF\u0080 A",
"XXXXX ..X.. ........ .XX....X XXXXXXXX X....... ....X ...X.");
// binary long form optimization into 2 short forms (saves 1 bit)
testHighLevelEncodeString("\0\0\0\0 \0\0\0\0 \0\0\0\0 \0\0\0\0 \0\0\0\0 \0\0\0\0 \u0082\u0084\u0088\0 \0\0\0\0 \0\0\0\0 ",
"XXXXX XXXXX ........ ........ ........ ........ ..X....." +
" ........ ........ ........ ........ ..X....." +
" ........ ........ ........ ........ ..X....." +
" ........ ........ ........ ........ ..X....." +
" ........ ........ ........ ........ ..X....." +
" ........ ........ ........ ........ ..X....." +
" X.....X. XXXXX .XXX. X....X.. X...X... ........ ..X....." +
" ........ ........ ........ ........ ..X....." +
" ........ ........ ........ ........ ..X.....");
// binary long form
testHighLevelEncodeString("\0\0\0\0 \0\0\1\0 \0\0\2\0 \0\0\3\0 \0\0\4\0 \0\0\5\0 \0\0\6\0 \0\0\7\0 \0\0\u0008\0 \0\0\u0009\0 \0\0\u00F0\0 \0\0\u00F1\0 \0\0\u00F2\0A",
"XXXXX ..... .....X...X. ........ ........ ........ ........ ..X....." +
" ........ ........ .......X ........ ..X....." +
" ........ ........ ......X. ........ ..X....." +
" ........ ........ ......XX ........ ..X....." +
" ........ ........ .....X.. ........ ..X....." +
" ........ ........ .....X.X ........ ..X....." +
" ........ ........ .....XX. ........ ..X....." +
" ........ ........ .....XXX ........ ..X....." +
" ........ ........ ....X... ........ ..X....." +
" ........ ........ ....X..X ........ ..X....." +
" ........ ........ XXXX.... ........ ..X....." +
" ........ ........ XXXX...X ........ ..X....." +
" ........ ........ XXXX..X. ........ .X.....X");
}
// Helper routines
private static void testEncode(String data, boolean compact, int layers, String expected) throws Exception {
AztecCode aztec = Encoder.encode(data.getBytes(LATIN_1), 33);
assertEquals("Unexpected symbol format (compact)", compact, aztec.isCompact());
assertEquals("Unexpected nr. of layers", layers, aztec.getLayers());
BitMatrix matrix = aztec.getMatrix();
assertEquals("encode() failed", expected, matrix.toString());
}
private static void testEncodeDecode(String data, boolean compact, int layers) throws Exception {
AztecCode aztec = Encoder.encode(data.getBytes(LATIN_1), 25);
assertEquals("Unexpected symbol format (compact)", compact, aztec.isCompact());
assertEquals("Unexpected nr. of layers", layers, aztec.getLayers());
BitMatrix matrix = aztec.getMatrix();
new File("target/tmp").mkdirs();
//ImageWriter.saveAsBWImageFile(matrix, new File("target/tmp/aztec-out-" + (compact ? "c-" : "f-") + layers + ".png"));
AztecDetectorResult r = new AztecDetectorResult(matrix, NO_POINTS, aztec.isCompact(), aztec.getCodeWords(), aztec.getLayers());
DecoderResult res = new Decoder().decode(r);
assertEquals(data, res.getText());
// Check error correction by introducing a few minor errors
Random random = getPseudoRandom();
matrix.flip(random.nextInt(matrix.getWidth()), random.nextInt(2));
matrix.flip(random.nextInt(matrix.getWidth()), matrix.getHeight() - 2 + random.nextInt(2));
matrix.flip(random.nextInt(2), random.nextInt(matrix.getHeight()));
matrix.flip(matrix.getWidth() - 2 + random.nextInt(2), random.nextInt(matrix.getHeight()));
r = new AztecDetectorResult(matrix, NO_POINTS, aztec.isCompact(), aztec.getCodeWords(), aztec.getLayers());
res = new Decoder().decode(r);
assertEquals(data, res.getText());
}
static Random getPseudoRandom() {
return new SecureRandom(new byte[] {(byte) 0xDE, (byte) 0xAD, (byte) 0xBE, (byte) 0xEF});
}
private static void testModeMessage(boolean compact, int layers, int words, String expected) {
BitArray in = Encoder.generateModeMessage(compact, layers, words);
assertEquals("generateModeMessage() failed", expected.replace(" ", ""), in.toString().replace(" ", ""));
}
private static void testStuffBits(int wordSize, String bits, String expected) {
BitArray in = toBitArray(bits);
BitArray stuffed = Encoder.stuffBits(in, wordSize);
assertEquals("stuffBits() failed for input string: " + bits, expected.replace(" ", ""), stuffed.toString().replace(" ", ""));
}
private static BitArray toBitArray(CharSequence bits) {
BitArray in = new BitArray();
char[] str = DOTX.matcher(bits).replaceAll("").toCharArray();
for (char aStr : str) {
in.appendBit(aStr == 'X');
}
return in;
}
private static void testHighLevelEncodeString(String s, String expectedBits) {
BitArray bits = Encoder.highLevelEncode(s.getBytes(LATIN_1));
String receivedBits = bits.toString().replace(" ", "");
assertEquals("highLevelEncode() failed for input string: " + s, expectedBits.replace(" ", ""), receivedBits);
}
}

View file

@ -1,65 +0,0 @@
/*
* 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 org.junit.Assert;
import java.security.SecureRandom;
import java.util.BitSet;
import java.util.Random;
/**
* @author Sean Owen
*/
abstract class AbstractReedSolomonTestCase extends Assert {
static void corrupt(int[] received, int howMany, Random random) {
BitSet corrupted = new BitSet(received.length);
for (int j = 0; j < howMany; j++) {
int location = random.nextInt(received.length);
if (corrupted.get(location)) {
j--;
} else {
corrupted.set(location);
received[location] = (received[location] + 1 + random.nextInt(255)) & 0xFF;
}
}
}
static void doTestQRCodeEncoding(int[] dataBytes, int[] expectedECBytes) {
int[] toEncode = new int[dataBytes.length + expectedECBytes.length];
System.arraycopy(dataBytes, 0, toEncode, 0, dataBytes.length);
new ReedSolomonEncoder(GenericGF.QR_CODE_FIELD_256).encode(toEncode, expectedECBytes.length);
assertArraysEqual(dataBytes, 0, toEncode, 0, dataBytes.length);
assertArraysEqual(expectedECBytes, 0, toEncode, dataBytes.length, expectedECBytes.length);
}
static Random getRandom() {
return new SecureRandom(new byte[] {(byte) 0xDE, (byte) 0xAD, (byte) 0xBE, (byte) 0xEF});
}
static void assertArraysEqual(int[] expected,
int expectedOffset,
int[] actual,
int actualOffset,
int length) {
for (int i = 0; i < length; i++) {
assertEquals(expected[expectedOffset + i], actual[actualOffset + i]);
}
}
}

View file

@ -1,87 +0,0 @@
/*
* 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 org.junit.Test;
import java.util.Random;
/**
* @author Sean Owen
* @author sanfordsquires
*/
public final class ReedSolomonDecoderDataMatrixTestCase extends AbstractReedSolomonTestCase {
private static final int[] DM_CODE_TEST = { 142, 164, 186 };
private static final int[] DM_CODE_TEST_WITH_EC = { 142, 164, 186, 114, 25, 5, 88, 102 };
private static final int DM_CODE_ECC_BYTES = DM_CODE_TEST_WITH_EC.length - DM_CODE_TEST.length;
private static final int DM_CODE_CORRECTABLE = DM_CODE_ECC_BYTES / 2;
private final ReedSolomonDecoder dmRSDecoder = new ReedSolomonDecoder(GenericGF.DATA_MATRIX_FIELD_256);
@Test
public void testNoError() throws ReedSolomonException {
int[] received = new int[DM_CODE_TEST_WITH_EC.length];
System.arraycopy(DM_CODE_TEST_WITH_EC, 0, received, 0, received.length);
// no errors
checkQRRSDecode(received);
}
@Test
public void testOneError() throws ReedSolomonException {
int[] received = new int[DM_CODE_TEST_WITH_EC.length];
Random random = getRandom();
for (int i = 0; i < received.length; i++) {
System.arraycopy(DM_CODE_TEST_WITH_EC, 0, received, 0, received.length);
received[i] = random.nextInt(256);
checkQRRSDecode(received);
}
}
@Test
public void testMaxErrors() throws ReedSolomonException {
int[] received = new int[DM_CODE_TEST_WITH_EC.length];
Random random = getRandom();
for (int test : DM_CODE_TEST) { // # iterations is kind of arbitrary
System.arraycopy(DM_CODE_TEST_WITH_EC, 0, received, 0, received.length);
corrupt(received, DM_CODE_CORRECTABLE, random);
checkQRRSDecode(received);
}
}
@Test
public void testTooManyErrors() {
int[] received = new int[DM_CODE_TEST_WITH_EC.length];
System.arraycopy(DM_CODE_TEST_WITH_EC, 0, received, 0, received.length);
Random random = getRandom();
corrupt(received, DM_CODE_CORRECTABLE + 1, random);
try {
checkQRRSDecode(received);
fail("Should not have decoded");
} catch (ReedSolomonException rse) {
// good
}
}
private void checkQRRSDecode(int[] received) throws ReedSolomonException {
dmRSDecoder.decode(received, DM_CODE_ECC_BYTES);
for (int i = 0; i < DM_CODE_TEST.length; i++) {
assertEquals(received[i], DM_CODE_TEST[i]);
}
}
}

View file

@ -1,92 +0,0 @@
/*
* 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 org.junit.Test;
import java.util.Random;
/**
* @author Sean Owen
*/
public final class ReedSolomonDecoderQRCodeTestCase extends AbstractReedSolomonTestCase {
/** See ISO 18004, Appendix I, from which this example is taken. */
private static final int[] QR_CODE_TEST =
{ 0x10, 0x20, 0x0C, 0x56, 0x61, 0x80, 0xEC, 0x11, 0xEC,
0x11, 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11 };
private static final int[] QR_CODE_TEST_WITH_EC =
{ 0x10, 0x20, 0x0C, 0x56, 0x61, 0x80, 0xEC, 0x11, 0xEC,
0x11, 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11, 0xA5, 0x24,
0xD4, 0xC1, 0xED, 0x36, 0xC7, 0x87, 0x2C, 0x55 };
private static final int QR_CODE_ECC_BYTES = QR_CODE_TEST_WITH_EC.length - QR_CODE_TEST.length;
private static final int QR_CODE_CORRECTABLE = QR_CODE_ECC_BYTES / 2;
private final ReedSolomonDecoder qrRSDecoder = new ReedSolomonDecoder(GenericGF.QR_CODE_FIELD_256);
@Test
public void testNoError() throws ReedSolomonException {
int[] received = new int[QR_CODE_TEST_WITH_EC.length];
System.arraycopy(QR_CODE_TEST_WITH_EC, 0, received, 0, received.length);
// no errors
checkQRRSDecode(received);
}
@Test
public void testOneError() throws ReedSolomonException {
int[] received = new int[QR_CODE_TEST_WITH_EC.length];
Random random = getRandom();
for (int i = 0; i < received.length; i++) {
System.arraycopy(QR_CODE_TEST_WITH_EC, 0, received, 0, received.length);
received[i] = random.nextInt(256);
checkQRRSDecode(received);
}
}
@Test
public void testMaxErrors() throws ReedSolomonException {
int[] received = new int[QR_CODE_TEST_WITH_EC.length];
Random random = getRandom();
for (int test : QR_CODE_TEST) { // # iterations is kind of arbitrary
System.arraycopy(QR_CODE_TEST_WITH_EC, 0, received, 0, received.length);
corrupt(received, QR_CODE_CORRECTABLE, random);
checkQRRSDecode(received);
}
}
@Test
public void testTooManyErrors() {
int[] received = new int[QR_CODE_TEST_WITH_EC.length];
System.arraycopy(QR_CODE_TEST_WITH_EC, 0, received, 0, received.length);
Random random = getRandom();
corrupt(received, QR_CODE_CORRECTABLE + 1, random);
try {
checkQRRSDecode(received);
fail("Should not have decoded");
} catch (ReedSolomonException rse) {
// good
}
}
private void checkQRRSDecode(int[] received) throws ReedSolomonException {
qrRSDecoder.decode(received, QR_CODE_ECC_BYTES);
for (int i = 0; i < QR_CODE_TEST.length; i++) {
assertEquals(received[i], QR_CODE_TEST[i]);
}
}
}

View file

@ -1,67 +0,0 @@
/*
* 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 org.junit.Test;
import java.util.Random;
/**
* @author Sean Owen
*/
public final class ReedSolomonEncoderQRCodeTestCase extends AbstractReedSolomonTestCase {
/**
* Tests example given in ISO 18004, Annex I
*/
@Test
public void testISO18004Example() {
int[] dataBytes = {
0x10, 0x20, 0x0C, 0x56, 0x61, 0x80, 0xEC, 0x11,
0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11 };
int[] expectedECBytes = {
0xA5, 0x24, 0xD4, 0xC1, 0xED, 0x36, 0xC7, 0x87,
0x2C, 0x55 };
doTestQRCodeEncoding(dataBytes, expectedECBytes);
}
@Test
public void testQRCodeVersusDecoder() throws Exception {
Random random = getRandom();
ReedSolomonEncoder encoder = new ReedSolomonEncoder(GenericGF.QR_CODE_FIELD_256);
ReedSolomonDecoder decoder = new ReedSolomonDecoder(GenericGF.QR_CODE_FIELD_256);
for (int i = 0; i < 100; i++) {
int size = 2 + random.nextInt(254);
int[] toEncode = new int[size];
int ecBytes = 1 + random.nextInt(2 * (1 + size / 8));
ecBytes = Math.min(ecBytes, size - 1);
int dataBytes = size - ecBytes;
for (int j = 0; j < dataBytes; j++) {
toEncode[j] = random.nextInt(256);
}
int[] original = new int[dataBytes];
System.arraycopy(toEncode, 0, original, 0, dataBytes);
encoder.encode(toEncode, ecBytes);
corrupt(toEncode, ecBytes / 2, random);
decoder.decode(toEncode, ecBytes);
assertArraysEqual(original, 0, toEncode, 0, dataBytes);
}
}
// Need more tests I am sure
}

View file

@ -0,0 +1,507 @@
/*
* Copyright 2013 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 org.junit.Assert;
import org.junit.Test;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Random;
/**
* @author Rustam Abdullaev
*/
public final class ReedSolomonTestCase extends Assert {
private static final int DECODER_RANDOM_TEST_ITERATIONS = 3;
private static final int DECODER_TEST_ITERATIONS = 10;
@Test
public void testDataMatrix() {
// real life test cases
testEncodeDecode(GenericGF.DATA_MATRIX_FIELD_256,
new int[] { 142, 164, 186 }, new int[] { 114, 25, 5, 88, 102 });
testEncodeDecode(GenericGF.DATA_MATRIX_FIELD_256, new int[] {
0x69, 0x75, 0x75, 0x71, 0x3B, 0x30, 0x30, 0x64,
0x70, 0x65, 0x66, 0x2F, 0x68, 0x70, 0x70, 0x68,
0x6D, 0x66, 0x2F, 0x64, 0x70, 0x6E, 0x30, 0x71,
0x30, 0x7B, 0x79, 0x6A, 0x6F, 0x68, 0x30, 0x81,
0xF0, 0x88, 0x1F, 0xB5 },
new int[] {
0x1C, 0x64, 0xEE, 0xEB, 0xD0, 0x1D, 0x00, 0x03,
0xF0, 0x1C, 0xF1, 0xD0, 0x6D, 0x00, 0x98, 0xDA,
0x80, 0x88, 0xBE, 0xFF, 0xB7, 0xFA, 0xA9, 0x95 });
// synthetic test cases
testEncodeDecodeRandom(GenericGF.DATA_MATRIX_FIELD_256, 10, 240);
testEncodeDecodeRandom(GenericGF.DATA_MATRIX_FIELD_256, 128, 127);
testEncodeDecodeRandom(GenericGF.DATA_MATRIX_FIELD_256, 220, 35);
}
@Test
public void testQRCode() {
// Test case from example given in ISO 18004, Annex I
testEncodeDecode(GenericGF.QR_CODE_FIELD_256, new int[] {
0x10, 0x20, 0x0C, 0x56, 0x61, 0x80, 0xEC, 0x11,
0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11 },
new int[] {
0xA5, 0x24, 0xD4, 0xC1, 0xED, 0x36, 0xC7, 0x87,
0x2C, 0x55 });
testEncodeDecode(GenericGF.QR_CODE_FIELD_256, new int[] {
0x72, 0x67, 0x2F, 0x77, 0x69, 0x6B, 0x69, 0x2F,
0x4D, 0x61, 0x69, 0x6E, 0x5F, 0x50, 0x61, 0x67,
0x65, 0x3B, 0x3B, 0x00, 0xEC, 0x11, 0xEC, 0x11,
0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11, 0xEC, 0x11 },
new int[] {
0xD8, 0xB8, 0xEF, 0x14, 0xEC, 0xD0, 0xCC, 0x85,
0x73, 0x40, 0x0B, 0xB5, 0x5A, 0xB8, 0x8B, 0x2E,
0x08, 0x62 });
// real life test cases
// synthetic test cases
testEncodeDecodeRandom(GenericGF.QR_CODE_FIELD_256, 10, 240);
testEncodeDecodeRandom(GenericGF.QR_CODE_FIELD_256, 128, 127);
testEncodeDecodeRandom(GenericGF.QR_CODE_FIELD_256, 220, 35);
}
@Test
public void testAztec() {
// real life test cases
testEncodeDecode(GenericGF.AZTEC_PARAM,
new int[] { 0x5, 0x6 }, new int[] { 0x3, 0x2, 0xB, 0xB, 0x7 });
testEncodeDecode(GenericGF.AZTEC_PARAM,
new int[] { 0x0, 0x0, 0x0, 0x9 }, new int[] { 0xA, 0xD, 0x8, 0x6, 0x5, 0x6 });
testEncodeDecode(GenericGF.AZTEC_PARAM,
new int[] { 0x2, 0x8, 0x8, 0x7 }, new int[] { 0xE, 0xC, 0xA, 0x9, 0x6, 0x8 });
testEncodeDecode(GenericGF.AZTEC_DATA_6, new int[] {
0x9, 0x32, 0x1, 0x29, 0x2F, 0x2, 0x27, 0x25, 0x1, 0x1B },
new int[] {
0x2C, 0x2, 0xD, 0xD, 0xA, 0x16, 0x28, 0x9, 0x22, 0xA, 0x14 });
testEncodeDecode(GenericGF.AZTEC_DATA_8, new int[] {
0xE0, 0x86, 0x42, 0x98, 0xE8, 0x4A, 0x96, 0xC6,
0xB9, 0xF0, 0x8C, 0xA7, 0x4A, 0xDA, 0xF8, 0xCE,
0xB7, 0xDE, 0x88, 0x64, 0x29, 0x8E, 0x84, 0xA9,
0x6C, 0x6B, 0x9F, 0x08, 0xCA, 0x74, 0xAD, 0xAF,
0x8C, 0xEB, 0x7C, 0x10, 0xC8, 0x53, 0x1D, 0x09,
0x52, 0xD8, 0xD7, 0x3E, 0x11, 0x94, 0xE9, 0x5B,
0x5F, 0x19, 0xD6, 0xFB, 0xD1, 0x0C, 0x85, 0x31,
0xD0, 0x95, 0x2D, 0x8D, 0x73, 0xE1, 0x19, 0x4E,
0x95, 0xB5, 0xF1, 0x9D, 0x6F },
new int[] {
0x31, 0xD7, 0x04, 0x46, 0xB2, 0xC1, 0x06, 0x94,
0x17, 0xE5, 0x0C, 0x2B, 0xA3, 0x99, 0x15, 0x7F,
0x16, 0x3C, 0x66, 0xBA, 0x33, 0xD9, 0xE8, 0x87,
0x86, 0xBB, 0x4B, 0x15, 0x4E, 0x4A, 0xDE, 0xD4,
0xED, 0xA1, 0xF8, 0x47, 0x2A, 0x50, 0xA6, 0xBC,
0x53, 0x7D, 0x29, 0xFE, 0x06, 0x49, 0xF3, 0x73,
0x9F, 0xC1, 0x75 });
testEncodeDecode(GenericGF.AZTEC_DATA_10, new int[] {
0x15C, 0x1E1, 0x2D5, 0x02E, 0x048, 0x1E2, 0x037, 0x0CD,
0x02E, 0x056, 0x26A, 0x281, 0x1C2, 0x1A6, 0x296, 0x045,
0x041, 0x0AA, 0x095, 0x2CE, 0x003, 0x38F, 0x2CD, 0x1A2,
0x036, 0x1AD, 0x04E, 0x090, 0x271, 0x0D3, 0x02E, 0x0D5,
0x2D4, 0x032, 0x2CA, 0x281, 0x0AA, 0x04E, 0x024, 0x2D3,
0x296, 0x281, 0x0E2, 0x08A, 0x1AA, 0x28A, 0x280, 0x07C,
0x286, 0x0A1, 0x1D0, 0x1AD, 0x154, 0x032, 0x2C2, 0x1C1,
0x145, 0x02B, 0x2D4, 0x2B0, 0x033, 0x2D5, 0x276, 0x1C1,
0x282, 0x10A, 0x2B5, 0x154, 0x003, 0x385, 0x20F, 0x0C4,
0x02D, 0x050, 0x266, 0x0D5, 0x033, 0x2D5, 0x276, 0x1C1,
0x0D4, 0x2A0, 0x08F, 0x0C4, 0x024, 0x20F, 0x2E2, 0x1AD,
0x154, 0x02E, 0x056, 0x26A, 0x281, 0x090, 0x1E5, 0x14E,
0x0CF, 0x2B6, 0x1C1, 0x28A, 0x2A1, 0x04E, 0x0D5, 0x003,
0x391, 0x122, 0x286, 0x1AD, 0x2D4, 0x028, 0x262, 0x2EA,
0x0A2, 0x004, 0x176, 0x295, 0x201, 0x0D5, 0x024, 0x20F,
0x116, 0x0C1, 0x056, 0x095, 0x213, 0x004, 0x1EA, 0x28A,
0x02A, 0x234, 0x2CE, 0x037, 0x157, 0x0D3, 0x262, 0x026,
0x262, 0x2A0, 0x086, 0x106, 0x2A1, 0x126, 0x1E5, 0x266,
0x26A, 0x2A1, 0x0E6, 0x1AA, 0x281, 0x2B6, 0x271, 0x154,
0x02F, 0x0C4, 0x02D, 0x213, 0x0CE, 0x003, 0x38F, 0x2CD,
0x1A2, 0x036, 0x1B5, 0x26A, 0x086, 0x280, 0x086, 0x1AA,
0x2A1, 0x226, 0x1AD, 0x0CF, 0x2A6, 0x292, 0x2C6, 0x022,
0x1AA, 0x256, 0x0D5, 0x02D, 0x050, 0x266, 0x0D5, 0x004,
0x176, 0x295, 0x201, 0x0D3, 0x055, 0x031, 0x2CD, 0x2EA,
0x1E2, 0x261, 0x1EA, 0x28A, 0x004, 0x145, 0x026, 0x1A6,
0x1C6, 0x1F5, 0x2CE, 0x034, 0x051, 0x146, 0x1E1, 0x0B0,
0x1B0, 0x261, 0x0D5, 0x025, 0x142, 0x1C0, 0x07C, 0x0B0,
0x1E6, 0x081, 0x044, 0x02F, 0x2CF, 0x081, 0x290, 0x0A2,
0x1A6, 0x281, 0x0CD, 0x155, 0x031, 0x1A2, 0x086, 0x262,
0x2A1, 0x0CD, 0x0CA, 0x0E6, 0x1E5, 0x003, 0x394, 0x0C5,
0x030, 0x26F, 0x053, 0x0C1, 0x1B6, 0x095, 0x2D4, 0x030,
0x26F, 0x053, 0x0C0, 0x07C, 0x2E6, 0x295, 0x143, 0x2CD,
0x2CE, 0x037, 0x0C9, 0x144, 0x2CD, 0x040, 0x08E, 0x054,
0x282, 0x022, 0x2A1, 0x229, 0x053, 0x0D5, 0x262, 0x027,
0x26A, 0x1E8, 0x14D, 0x1A2, 0x004, 0x26A, 0x296, 0x281,
0x176, 0x295, 0x201, 0x0E2, 0x2C4, 0x143, 0x2D4, 0x026,
0x262, 0x2A0, 0x08F, 0x0C4, 0x031, 0x213, 0x2B5, 0x155,
0x213, 0x02F, 0x143, 0x121, 0x2A6, 0x1AD, 0x2D4, 0x034,
0x0C5, 0x026, 0x295, 0x003, 0x396, 0x2A1, 0x176, 0x295,
0x201, 0x0AA, 0x04E, 0x004, 0x1B0, 0x070, 0x275, 0x154,
0x026, 0x2C1, 0x2B3, 0x154, 0x2AA, 0x256, 0x0C1, 0x044,
0x004, 0x23F },
new int[] {
0x379, 0x099, 0x348, 0x010, 0x090, 0x196, 0x09C, 0x1FF,
0x1B0, 0x32D, 0x244, 0x0DE, 0x201, 0x386, 0x163, 0x11F,
0x39B, 0x344, 0x3FE, 0x02F, 0x188, 0x113, 0x3D9, 0x102,
0x04A, 0x2E1, 0x1D1, 0x18E, 0x077, 0x262, 0x241, 0x20D,
0x1B8, 0x11D, 0x0D0, 0x0A5, 0x29C, 0x24D, 0x3E7, 0x006,
0x2D0, 0x1B7, 0x337, 0x178, 0x0F1, 0x1E0, 0x00B, 0x01E,
0x0DA, 0x1C6, 0x2D9, 0x00D, 0x28B, 0x34A, 0x252, 0x27A,
0x057, 0x0CA, 0x2C2, 0x2E4, 0x3A6, 0x0E3, 0x22B, 0x307,
0x174, 0x292, 0x10C, 0x1ED, 0x2FD, 0x2D4, 0x0A7, 0x051,
0x34F, 0x07A, 0x1D5, 0x01D, 0x22E, 0x2C2, 0x1DF, 0x08F,
0x105, 0x3FE, 0x286, 0x2A2, 0x3B1, 0x131, 0x285, 0x362,
0x315, 0x13C, 0x0F9, 0x1A2, 0x28D, 0x246, 0x1B3, 0x12C,
0x2AD, 0x0F8, 0x222, 0x0EC, 0x39F, 0x358, 0x014, 0x229,
0x0C8, 0x360, 0x1C2, 0x031, 0x098, 0x041, 0x3E4, 0x046,
0x332, 0x318, 0x2E3, 0x24E, 0x3E2, 0x1E1, 0x0BE, 0x239,
0x306, 0x3A5, 0x352, 0x351, 0x275, 0x0ED, 0x045, 0x229,
0x0BF, 0x05D, 0x253, 0x1BE, 0x02E, 0x35A, 0x0E4, 0x2E9,
0x17A, 0x166, 0x03C, 0x007 });
testEncodeDecode(GenericGF.AZTEC_DATA_12, new int[] {
0x571, 0xE1B, 0x542, 0xE12, 0x1E2, 0x0DC, 0xCD0, 0xB85,
0x69A, 0xA81, 0x709, 0xA6A, 0x584, 0x510, 0x4AA, 0x256,
0xCE0, 0x0F8, 0xFB3, 0x5A2, 0x0D9, 0xAD1, 0x389, 0x09C,
0x4D3, 0x0B8, 0xD5B, 0x503, 0x2B2, 0xA81, 0x2A8, 0x4E0,
0x92D, 0x3A5, 0xA81, 0x388, 0x8A6, 0xAA8, 0xAA0, 0x07C,
0xA18, 0xA17, 0x41A, 0xD55, 0x032, 0xB09, 0xC15, 0x142,
0xBB5, 0x2B0, 0x0CE, 0xD59, 0xD9C, 0x1A0, 0x90A, 0xAD5,
0x540, 0x0F8, 0x583, 0xCC4, 0x0B4, 0x509, 0x98D, 0x50C,
0xED5, 0x9D9, 0xC13, 0x52A, 0x023, 0xCC4, 0x092, 0x0FB,
0x89A, 0xD55, 0x02E, 0x15A, 0x6AA, 0x049, 0x079, 0x54E,
0x33E, 0xB67, 0x068, 0xAA8, 0x44E, 0x354, 0x03E, 0x452,
0x2A1, 0x9AD, 0xB50, 0x289, 0x8AE, 0xA28, 0x804, 0x5DA,
0x958, 0x04D, 0x509, 0x20F, 0x458, 0xC11, 0x589, 0x584,
0xC04, 0x7AA, 0x8A0, 0xAA3, 0x4B3, 0x837, 0x55C, 0xD39,
0x882, 0x698, 0xAA0, 0x219, 0x06A, 0x852, 0x679, 0x666,
0x9AA, 0xA13, 0x99A, 0xAA0, 0x6B6, 0x9C5, 0x540, 0xBCC,
0x40B, 0x613, 0x338, 0x03E, 0x3EC, 0xD68, 0x836, 0x6D6,
0x6A2, 0x1A8, 0x021, 0x9AA, 0xA86, 0x266, 0xB4C, 0xFA9,
0xA92, 0xB18, 0x226, 0xAA5, 0x635, 0x42D, 0x142, 0x663,
0x540, 0x45D, 0xA95, 0x804, 0xD31, 0x543, 0x1B3, 0x6EA,
0x78A, 0x617, 0xAA8, 0xA01, 0x145, 0x099, 0xA67, 0x19F,
0x5B3, 0x834, 0x145, 0x467, 0x84B, 0x06C, 0x261, 0x354,
0x255, 0x09C, 0x01F, 0x0B0, 0x798, 0x811, 0x102, 0xFB3,
0xC81, 0xA40, 0xA26, 0x9A8, 0x133, 0x555, 0x0C5, 0xA22,
0x1A6, 0x2A8, 0x4CD, 0x328, 0xE67, 0x940, 0x3E5, 0x0C5,
0x0C2, 0x6F1, 0x4CC, 0x16D, 0x895, 0xB50, 0x309, 0xBC5,
0x330, 0x07C, 0xB9A, 0x955, 0x0EC, 0xDB3, 0x837, 0x325,
0x44B, 0x344, 0x023, 0x854, 0xA08, 0x22A, 0x862, 0x914,
0xCD5, 0x988, 0x279, 0xA9E, 0x853, 0x5A2, 0x012, 0x6AA,
0x5A8, 0x15D, 0xA95, 0x804, 0xE2B, 0x114, 0x3B5, 0x026,
0x98A, 0xA02, 0x3CC, 0x40C, 0x613, 0xAD5, 0x558, 0x4C2,
0xF50, 0xD21, 0xA99, 0xADB, 0x503, 0x431, 0x426, 0xA54,
0x03E, 0x5AA, 0x15D, 0xA95, 0x804, 0xAA1, 0x380, 0x46C,
0x070, 0x9D5, 0x540, 0x9AC, 0x1AC, 0xD54, 0xAAA, 0x563,
0x044, 0x401, 0x220, 0x9F1, 0x4F0, 0xDAA, 0x170, 0x90F,
0x106, 0xE66, 0x85C, 0x2B4, 0xD54, 0x0B8, 0x4D3, 0x52C,
0x228, 0x825, 0x512, 0xB67, 0x007, 0xC7D, 0x9AD, 0x106,
0xCD6, 0x89C, 0x484, 0xE26, 0x985, 0xC6A, 0xDA8, 0x195,
0x954, 0x095, 0x427, 0x049, 0x69D, 0x2D4, 0x09C, 0x445,
0x355, 0x455, 0x003, 0xE50, 0xC50, 0xBA0, 0xD6A, 0xA81,
0x958, 0x4E0, 0xA8A, 0x15D, 0xA95, 0x806, 0x76A, 0xCEC,
0xE0D, 0x048, 0x556, 0xAAA, 0x007, 0xC2C, 0x1E6, 0x205,
0xA28, 0x4CC, 0x6A8, 0x676, 0xACE, 0xCE0, 0x9A9, 0x501,
0x1E6, 0x204, 0x907, 0xDC4, 0xD6A, 0xA81, 0x70A, 0xD35,
0x502, 0x483, 0xCAA, 0x719, 0xF5B, 0x383, 0x455, 0x422,
0x71A, 0xA01, 0xF22, 0x915, 0x0CD, 0x6DA, 0x814, 0x4C5,
0x751, 0x440, 0x22E, 0xD4A, 0xC02, 0x6A8, 0x490, 0x7A2,
0xC60, 0x8AC, 0x4AC, 0x260, 0x23D, 0x545, 0x055, 0x1A5,
0x9C1, 0xBAA, 0xE69, 0xCC4, 0x134, 0xC55, 0x010, 0xC83,
0x542, 0x933, 0xCB3, 0x34D, 0x550, 0x9CC, 0xD55, 0x035,
0xB4E, 0x2AA, 0x05E, 0x620, 0x5B0, 0x999, 0xC01, 0xF1F,
0x66B, 0x441, 0xB36, 0xB35, 0x10D, 0x401, 0x0CD, 0x554,
0x313, 0x35A, 0x67D, 0x4D4, 0x958, 0xC11, 0x355, 0x2B1,
0xAA1, 0x68A, 0x133, 0x1AA, 0x022, 0xED4, 0xAC0, 0x269,
0x8AA, 0x18D, 0x9B7, 0x53C, 0x530, 0xBD5, 0x450, 0x08A,
0x284, 0xCD3, 0x38C, 0xFAD, 0x9C1, 0xA0A, 0x2A3, 0x3C2,
0x583, 0x613, 0x09A, 0xA12, 0xA84, 0xE00, 0xF85, 0x83C,
0xC40, 0x888, 0x17D, 0x9E4, 0x0D2, 0x051, 0x34D, 0x409,
0x9AA, 0xA86, 0x2D1, 0x10D, 0x315, 0x426, 0x699, 0x473,
0x3CA, 0x01F, 0x286, 0x286, 0x137, 0x8A6, 0x60B, 0x6C4,
0xADA, 0x818, 0x4DE, 0x299, 0x803, 0xE5C, 0xD4A, 0xA87,
0x66D, 0x9C1, 0xB99, 0x2A2, 0x59A, 0x201, 0x1C2, 0xA50,
0x411, 0x543, 0x148, 0xA66, 0xACC, 0x413, 0xCD4, 0xF42,
0x9AD, 0x100, 0x935, 0x52D, 0x40A, 0xED4, 0xAC0, 0x271,
0x588, 0xA1D, 0xA81, 0x34C, 0x550, 0x11E, 0x620, 0x630,
0x9D6, 0xAAA, 0xC26, 0x17A, 0x869, 0x0D4, 0xCD6, 0xDA8,
0x1A1, 0x8A1, 0x352, 0xA01, 0xF2D, 0x50A, 0xED4, 0xAC0,
0x255, 0x09C, 0x023, 0x603, 0x84E, 0xAAA, 0x04D, 0x60D,
0x66A, 0xA55, 0x52B, 0x182, 0x220, 0x091, 0x00F, 0x8A7,
0x86D, 0x50B, 0x848, 0x788, 0x373, 0x342, 0xE15, 0xA6A,
0xA05, 0xC26, 0x9A9, 0x611, 0x441, 0x2A8, 0x95B, 0x380,
0x3E3, 0xECD, 0x688, 0x366, 0xB44, 0xE24, 0x271, 0x34C,
0x2E3, 0x56D, 0x40C, 0xACA, 0xA04, 0xAA1, 0x382, 0x4B4,
0xE96, 0xA04, 0xE22, 0x29A, 0xAA2, 0xA80, 0x1F2, 0x862,
0x85D, 0x06B, 0x554, 0x0CA, 0xC27, 0x054, 0x50A, 0xED4,
0xAC0, 0x33B, 0x567, 0x670, 0x682, 0x42A, 0xB55, 0x500,
0x3E1, 0x60F, 0x310, 0x2D1, 0x426, 0x635, 0x433, 0xB56,
0x767, 0x04D, 0x4A8, 0x08F, 0x310, 0x248, 0x3EE, 0x26B,
0x554, 0x0B8, 0x569, 0xAA8, 0x124, 0x1E5, 0x538, 0xCFA,
0xD9C, 0x1A2, 0xAA1, 0x138, 0xD50, 0x0F9, 0x148, 0xA86,
0x6B6, 0xD40, 0xA26, 0x2BA, 0x8A2, 0x011, 0x76A, 0x560,
0x135, 0x424, 0x83D, 0x163, 0x045, 0x625, 0x613, 0x011,
0xEAA, 0x282, 0xA8D, 0x2CE, 0x0DD, 0x573, 0x4E6, 0x209,
0xA62, 0xA80, 0x864, 0x1AA, 0x149, 0x9E5, 0x99A, 0x6AA,
0x84E, 0x66A, 0xA81, 0xADA, 0x715, 0x502, 0xF31, 0x02D,
0x84C, 0xCE0, 0x0F8, 0xFB3, 0x5A2, 0x0D9, 0xB59, 0xA88,
0x6A0, 0x086, 0x6AA, 0xA18, 0x99A, 0xD33, 0xEA6, 0xA4A,
0xC60, 0x89A, 0xA95, 0x8D5, 0x0B4, 0x509, 0x98D, 0x501,
0x176, 0xA56, 0x013, 0x4C5, 0x50C, 0x6CD, 0xBA9, 0xE29,
0x85E, 0xAA2, 0x804, 0x514, 0x266, 0x99C, 0x67D, 0x6CE,
0x0D0, 0x515, 0x19E, 0x12C, 0x1B0, 0x984, 0xD50, 0x954,
0x270, 0x07C, 0x2C1, 0xE62, 0x044, 0x40B, 0xECF, 0x206,
0x902, 0x89A, 0x6A0, 0x4CD, 0x554, 0x316, 0x888, 0x698,
0xAA1, 0x334, 0xCA3, 0x99E, 0x500, 0xF94, 0x314, 0x309,
0xBC5, 0x330, 0x5B6, 0x256, 0xD40, 0xC26, 0xF14, 0xCC0,
0x1F2, 0xE6A, 0x554, 0x3B3, 0x6CE, 0x0DC, 0xC95, 0x12C,
0xD10, 0x08E, 0x152, 0x820, 0x8AA, 0x18A, 0x453, 0x356,
0x620, 0x9E6, 0xA7A, 0x14D, 0x688, 0x049, 0xAA9, 0x6A0,
0x576, 0xA56, 0x013, 0x8AC, 0x450, 0xED4, 0x09A, 0x62A,
0x808, 0xF31, 0x031, 0x84E, 0xB55, 0x561, 0x30B, 0xD43,
0x486, 0xA66, 0xB6D, 0x40D, 0x0C5, 0x09A, 0x950, 0x0F9,
0x6A8, 0x576, 0xA56, 0x012, 0xA84, 0xE01, 0x1B0, 0x1C2,
0x755, 0x502, 0x6B0, 0x6B3, 0x552, 0xAA9, 0x58C, 0x111,
0x004, 0x882, 0x7C5, 0x3C3, 0x6A8, 0x5C2, 0x43C, 0x41B,
0x99A, 0x170, 0xAD3, 0x550, 0x2E1, 0x34D, 0x4B0, 0x8A2,
0x095, 0x44A, 0xD9C, 0x01F, 0x1F6, 0x6B4, 0x41B, 0x35A,
0x271, 0x213, 0x89A, 0x617, 0x1AB, 0x6A0, 0x656, 0x550,
0x255, 0x09C, 0x125, 0xA74, 0xB50, 0x271, 0x114, 0xD55,
0x154, 0x00F, 0x943, 0x142, 0xE83, 0x5AA, 0xA06, 0x561,
0x382, 0xA28, 0x576, 0xA56, 0x019, 0xDAB, 0x3B3, 0x834,
0x121, 0x55A, 0xAA8, 0x01F, 0x0B0, 0x798, 0x816, 0x8A1,
0x331, 0xAA1, 0x9DA, 0xB3B, 0x382, 0x6A5, 0x404, 0x798,
0x812, 0x41F, 0x713, 0x5AA, 0xA05, 0xC2B, 0x4D5, 0x409,
0x20F, 0x2A9, 0xC67, 0xD6C, 0xE0D, 0x155, 0x089, 0xC6A,
0x807, 0xC8A, 0x454, 0x335, 0xB6A, 0x051, 0x315, 0xD45,
0x100, 0x8BB, 0x52B, 0x009, 0xAA1, 0x241, 0xE8B, 0x182,
0x2B1, 0x2B0, 0x980, 0x8F5, 0x514, 0x154, 0x696, 0x706,
0xEAB, 0x9A7, 0x310, 0x4D3, 0x154, 0x043, 0x20D, 0x50A,
0x4CF, 0x2CC, 0xD35, 0x542, 0x733, 0x554, 0x0D6, 0xD38,
0xAA8, 0x179, 0x881, 0x6C2, 0x667, 0x007, 0xC7D, 0x9AD,
0x106, 0xCDA, 0xCD4, 0x435, 0x004, 0x335, 0x550, 0xC4C,
0xD69, 0x9F5, 0x352, 0x563, 0x044, 0xD54, 0xAC6, 0xA85,
0xA28, 0x4CC, 0x6A8, 0x08B, 0xB52, 0xB00, 0x9A6, 0x2A8,
0x636, 0x6DD, 0x4F1, 0x4C2, 0xF55, 0x140, 0x228, 0xA13,
0x34C, 0xE33, 0xEB6, 0x706, 0x828, 0xA8C, 0xF09, 0x60D,
0x84C, 0x26A, 0x84A, 0xA13, 0x803, 0xE16, 0x0F3, 0x102,
0x220, 0x5F6, 0x790, 0x348, 0x144, 0xD35, 0x026, 0x6AA,
0xA18, 0xB44, 0x434, 0xC55, 0x099, 0xA65, 0x1CC, 0xF28,
0x07C, 0xA18, 0xA18, 0x4DE, 0x299, 0x82D, 0xB12, 0xB6A,
0x061, 0x378, 0xA66, 0x00F, 0x973, 0x52A, 0xA1D, 0x9B6,
0x706, 0xE64, 0xA89, 0x668, 0x804, 0x70A, 0x941, 0x045,
0x50C, 0x522, 0x99A, 0xB31, 0x04F, 0x353, 0xD0A, 0x6B4,
0x402, 0x4D5, 0x4B5, 0x02B, 0xB52, 0xB00, 0x9C5, 0x622,
0x876, 0xA04, 0xD31, 0x540, 0x479, 0x881, 0x8C2, 0x75A,
0xAAB, 0x098, 0x5EA, 0x1A4, 0x353, 0x35B, 0x6A0, 0x686,
0x284, 0xD4A, 0x807, 0xCB5, 0x42B, 0xB52, 0xB00, 0x954,
0x270, 0x08D, 0x80E, 0x13A, 0xAA8, 0x135, 0x835, 0x9AA,
0x801, 0xF14, 0xF0D, 0xAA1, 0x709, 0x0F1, 0x06E, 0x668,
0x5C2, 0xB4D, 0x540, 0xB84, 0xD35, 0x2C2, 0x288, 0x255,
0x12B, 0x670, 0x07C, 0x7D9, 0xAD1, 0x06C, 0xD68, 0x9C4,
0x84E, 0x269, 0x85C, 0x6AD, 0xA81, 0x959, 0x540, 0x954,
0x270, 0x496, 0x9D2, 0xD40, 0x9C4, 0x453, 0x554, 0x550,
0x03E, 0x50C, 0x50B, 0xA0D, 0x6AA, 0x819, 0x584, 0xE0A,
0x8A1, 0x5DA, 0x958, 0x067, 0x6AC, 0xECE, 0x0D0, 0x485,
0x56A, 0xAA0, 0x07C, 0x2C1, 0xE62, 0x05A, 0x284, 0xCC6,
0xA86, 0x76A, 0xCEC, 0xE09, 0xA95, 0x011, 0xE62, 0x049,
0x07D, 0xC4D, 0x6AA, 0x817, 0x0AD, 0x355, 0x024, 0x83C,
0xAA7, 0x19F, 0x5B3, 0x834, 0x554, 0x227, 0x1AA, 0x01F,
0x229, 0x150, 0xCD6, 0xDA8, 0x144, 0xC57, 0x514, 0x402,
0x2ED, 0x4AC, 0x026, 0xA84, 0x907, 0xA2C, 0x608, 0xAC4,
0xAC2, 0x602, 0x3D5, 0x450, 0x551, 0xA59, 0xC1B, 0xAAE,
0x69C, 0xC41, 0x34C, 0x550, 0x10C, 0x835, 0x429, 0x33C,
0xB33, 0x4D5, 0x509, 0xCCD, 0x550, 0x35B, 0x4E2, 0xAA0,
0x5E6, 0x205, 0xB09, 0x99C, 0x09F },
new int[] {
0xD54, 0x221, 0x154, 0x7CD, 0xBF3, 0x112, 0x89B, 0xC5E,
0x9CD, 0x07E, 0xFB6, 0x78F, 0x7FA, 0x16F, 0x377, 0x4B4,
0x62D, 0x475, 0xBC2, 0x861, 0xB72, 0x9D0, 0x76A, 0x5A1,
0x22A, 0xF74, 0xDBA, 0x8B1, 0x139, 0xDCD, 0x012, 0x293,
0x705, 0xA34, 0xDD5, 0x3D2, 0x7F8, 0x0A6, 0x89A, 0x346,
0xCE0, 0x690, 0x40E, 0xFF3, 0xC4D, 0x97F, 0x9C9, 0x016,
0x73A, 0x923, 0xBCE, 0xFA9, 0xE6A, 0xB92, 0x02A, 0x07C,
0x04B, 0x8D5, 0x753, 0x42E, 0x67E, 0x87C, 0xEE6, 0xD7D,
0x2BF, 0xFB2, 0xFF8, 0x42F, 0x4CB, 0x214, 0x779, 0x02D,
0x606, 0xA02, 0x08A, 0xD4F, 0xB87, 0xDDF, 0xC49, 0xB51,
0x0E9, 0xF89, 0xAEF, 0xC92, 0x383, 0x98D, 0x367, 0xBD3,
0xA55, 0x148, 0x9DB, 0x913, 0xC79, 0x6FF, 0x387, 0x6EA,
0x7FA, 0xC1B, 0x12D, 0x303, 0xBCA, 0x503, 0x0FB, 0xB14,
0x0D4, 0xAD1, 0xAFC, 0x9DD, 0x404, 0x145, 0x6E5, 0x8ED,
0xF94, 0xD72, 0x645, 0xA21, 0x1A8, 0xABF, 0xC03, 0x91E,
0xD53, 0x48C, 0x471, 0x4E4, 0x408, 0x33C, 0x5DF, 0x73D,
0xA2A, 0x454, 0xD77, 0xC48, 0x2F5, 0x96A, 0x9CF, 0x047,
0x611, 0xE92, 0xC2F, 0xA98, 0x56D, 0x919, 0x615, 0x535,
0x67A, 0x8C1, 0x2E2, 0xBC4, 0xBE8, 0x328, 0x04F, 0x257,
0x3F9, 0xFA5, 0x477, 0x12E, 0x94B, 0x116, 0xEF7, 0x65F,
0x6B3, 0x915, 0xC64, 0x9AF, 0xB6C, 0x6A2, 0x50D, 0xEA3,
0x26E, 0xC23, 0x817, 0xA42, 0x71A, 0x9DD, 0xDA8, 0x84D,
0x3F3, 0x85B, 0xB00, 0x1FC, 0xB0A, 0xC2F, 0x00C, 0x095,
0xC58, 0x0E3, 0x807, 0x962, 0xC4B, 0x29A, 0x6FC, 0x958,
0xD29, 0x59E, 0xB14, 0x95A, 0xEDE, 0xF3D, 0xFB8, 0x0E5,
0x348, 0x2E7, 0x38E, 0x56A, 0x410, 0x3B1, 0x4B0, 0x793,
0xAB7, 0x0BC, 0x648, 0x719, 0xE3E, 0xFB4, 0x3B4, 0xE5C,
0x950, 0xD2A, 0x50B, 0x76F, 0x8D2, 0x3C7, 0xECC, 0x87C,
0x53A, 0xBA7, 0x4C3, 0x148, 0x437, 0x820, 0xECD, 0x660,
0x095, 0x2F4, 0x661, 0x6A4, 0xB74, 0x5F3, 0x1D2, 0x7EC,
0x8E2, 0xA40, 0xA6F, 0xFC3, 0x3BE, 0x1E9, 0x52C, 0x233,
0x173, 0x4EF, 0xA7C, 0x40B, 0x14C, 0x88D, 0xF30, 0x8D9,
0xBDB, 0x0A6, 0x940, 0xD46, 0xB2B, 0x03E, 0x46A, 0x641,
0xF08, 0xAFF, 0x496, 0x68A, 0x7A4, 0x0BA, 0xD43, 0x515,
0xB26, 0xD8F, 0x05C, 0xD6E, 0xA2C, 0xF25, 0x628, 0x4E5,
0x81D, 0xA2A, 0x1FF, 0x302, 0xFBD, 0x6D9, 0x711, 0xD8B,
0xE5C, 0x5CF, 0x42E, 0x008, 0x863, 0xB6F, 0x1E1, 0x3DA,
0xACE, 0x82B, 0x2DB, 0x7EB, 0xC15, 0x79F, 0xA79, 0xDAF,
0x00D, 0x2F6, 0x0CE, 0x370, 0x7E8, 0x9E6, 0x89F, 0xAE9,
0x175, 0xA95, 0x06B, 0x9DF, 0xAFF, 0x45B, 0x823, 0xAA4,
0xC79, 0x773, 0x886, 0x854, 0x0A5, 0x6D1, 0xE55, 0xEBB,
0x518, 0xE50, 0xF8F, 0x8CC, 0x834, 0x388, 0xCD2, 0xFC1,
0xA55, 0x1F8, 0xD1F, 0xE08, 0xF93, 0x362, 0xA22, 0x9FA,
0xCE5, 0x3C3, 0xDD4, 0xC53, 0xB94, 0xAD0, 0x6EB, 0x68D,
0x660, 0x8FC, 0xBCD, 0x914, 0x16F, 0x4C0, 0x134, 0xE1A,
0x76F, 0x9CB, 0x660, 0xEA0, 0x320, 0x15A, 0xCE3, 0x7E8,
0x03E, 0xB9A, 0xC90, 0xA14, 0x256, 0x1A8, 0x639, 0x7C6,
0xA59, 0xA65, 0x956, 0x9E4, 0x592, 0x6A9, 0xCFF, 0x4DC,
0xAA3, 0xD2A, 0xFDE, 0xA87, 0xBF5, 0x9F0, 0xC32, 0x94F,
0x675, 0x9A6, 0x369, 0x648, 0x289, 0x823, 0x498, 0x574,
0x8D1, 0xA13, 0xD1A, 0xBB5, 0xA19, 0x7F7, 0x775, 0x138,
0x949, 0xA4C, 0xE36, 0x126, 0xC85, 0xE05, 0xFEE, 0x962,
0x36D, 0x08D, 0xC76, 0x1E1, 0x1EC, 0x8D7, 0x231, 0xB68,
0x03C, 0x1DE, 0x7DF, 0x2B1, 0x09D, 0xC81, 0xDA4, 0x8F7,
0x6B9, 0x947, 0x9B0 });
// synthetic test cases
testEncodeDecodeRandom(GenericGF.AZTEC_PARAM, 2, 5); // compact mode message
testEncodeDecodeRandom(GenericGF.AZTEC_PARAM, 4, 6); // full mode message
testEncodeDecodeRandom(GenericGF.AZTEC_DATA_6, 10, 7);
testEncodeDecodeRandom(GenericGF.AZTEC_DATA_6, 20, 12);
testEncodeDecodeRandom(GenericGF.AZTEC_DATA_8, 20, 11);
testEncodeDecodeRandom(GenericGF.AZTEC_DATA_8, 128, 127);
testEncodeDecodeRandom(GenericGF.AZTEC_DATA_10, 128, 128);
testEncodeDecodeRandom(GenericGF.AZTEC_DATA_10, 768, 255);
testEncodeDecodeRandom(GenericGF.AZTEC_DATA_12, 3072, 1023);
}
private static void corrupt(int[] received, int howMany, Random random, int max) {
BitSet corrupted = new BitSet(received.length);
for (int j = 0; j < howMany; j++) {
int location = random.nextInt(received.length);
int value = random.nextInt(max);
if (corrupted.get(location) || received[location] == value) {
j--;
} else {
corrupted.set(location);
received[location] = value;
}
}
}
private static void testEncodeDecodeRandom(GenericGF field, int dataSize, int ecSize) {
assertTrue("Invalid data size for " + field, dataSize > 0 && dataSize <= field.getSize() - 3);
assertTrue("Invalid ECC size for " + field, ecSize > 0 && ecSize + dataSize <= field.getSize());
ReedSolomonEncoder encoder = new ReedSolomonEncoder(field);
int[] message = new int[dataSize + ecSize];
int[] dataWords = new int[dataSize];
int[] ecWords = new int[ecSize];
Random random = getPseudoRandom();
int iterations = field.getSize() > 256 ? 1 : DECODER_RANDOM_TEST_ITERATIONS;
for (int i = 0; i < iterations; i++) {
// generate random data
for (int k = 0; k < dataSize; k++) {
dataWords[k] = random.nextInt(field.getSize());
}
// generate ECC words
System.arraycopy(dataWords, 0, message, 0, dataWords.length);
encoder.encode(message, ecWords.length);
System.arraycopy(message, dataSize, ecWords, 0, ecSize);
// check to see if Decoder can fix up to ecWords/2 random errors
testDecoder(field, dataWords, ecWords);
}
}
private static void testEncodeDecode(GenericGF field, int[] dataWords, int[] ecWords) {
testEncoder(field, dataWords, ecWords);
testDecoder(field, dataWords, ecWords);
}
private static void testEncoder(GenericGF field, int[] dataWords, int[] ecWords) {
ReedSolomonEncoder encoder = new ReedSolomonEncoder(field);
int[] messageExpected = new int[dataWords.length + ecWords.length];
int[] message = new int[dataWords.length + ecWords.length];
System.arraycopy(dataWords, 0, messageExpected, 0, dataWords.length);
System.arraycopy(ecWords, 0, messageExpected, dataWords.length, ecWords.length);
System.arraycopy(dataWords, 0, message, 0, dataWords.length);
encoder.encode(message, ecWords.length);
assertDataEquals("Encode in " + field + " (" + dataWords.length + ',' + ecWords.length + ") failed",
messageExpected, message);
}
private static void testDecoder(GenericGF field, int[] dataWords, int[] ecWords) {
ReedSolomonDecoder decoder = new ReedSolomonDecoder(field);
int[] message = new int[dataWords.length + ecWords.length];
int maxErrors = ecWords.length / 2;
Random random = getPseudoRandom();
int iterations = field.getSize() > 256 ? 1 : DECODER_TEST_ITERATIONS;
for (int j = 0; j < iterations; j++) {
for (int i = 0; i < ecWords.length; i++) {
if (i > 10 && i < ecWords.length / 2 - 10) {
// performance improvement - skip intermediate cases in long-running tests
i += ecWords.length / 10;
}
System.arraycopy(dataWords, 0, message, 0, dataWords.length);
System.arraycopy(ecWords, 0, message, dataWords.length, ecWords.length);
corrupt(message, i, random, field.getSize());
try {
decoder.decode(message, ecWords.length);
} catch (ReedSolomonException e) {
// fail only if maxErrors exceeded
assertTrue("Decode in " + field + " (" + dataWords.length + ',' + ecWords.length + ") failed at " +
i + " errors: " + e,
i > maxErrors);
// else stop
break;
}
if (i < maxErrors) {
assertDataEquals("Decode in " + field + " (" + dataWords.length + ',' + ecWords.length + ") failed at " +
i + " errors",
dataWords,
message);
}
}
}
}
private static void assertDataEquals(String message, int[] expected, int[] received) {
for (int i = 0; i < expected.length; i++) {
if (expected[i] != received[i]) {
fail(message + ". Mismatch at " + i + ". Expected " + arrayToString(expected) + ", got " +
arrayToString(Arrays.copyOf(received, expected.length)));
}
}
}
private static String arrayToString(int[] data) {
StringBuilder sb = new StringBuilder("{");
for (int i=0; i<data.length; i++) {
sb.append(String.format(i > 0 ? ",%X" : "%X", data[i]));
}
return sb.append('}').toString();
}
private static Random getPseudoRandom() {
return new SecureRandom(new byte[] {(byte) 0xDE, (byte) 0xAD, (byte) 0xBE, (byte) 0xEF});
}
}