moved java files for pre-convert

This commit is contained in:
Henry Schimke
2022-08-20 12:00:19 -05:00
parent 4997291cb8
commit 1901c96559
2757 changed files with 57224 additions and 0 deletions

View File

@@ -0,0 +1,443 @@
/*
* 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.datamatrix.decoder;
import com.google.zxing.FormatException;
import com.google.zxing.common.BitMatrix;
/**
* @author bbrown@google.com (Brian Brown)
*/
final class BitMatrixParser {
private final BitMatrix mappingBitMatrix;
private final BitMatrix readMappingMatrix;
private final Version version;
/**
* @param bitMatrix {@link BitMatrix} to parse
* @throws FormatException if dimension is < 8 or > 144 or not 0 mod 2
*/
BitMatrixParser(BitMatrix bitMatrix) throws FormatException {
int dimension = bitMatrix.getHeight();
if (dimension < 8 || dimension > 144 || (dimension & 0x01) != 0) {
throw FormatException.getFormatInstance();
}
version = readVersion(bitMatrix);
this.mappingBitMatrix = extractDataRegion(bitMatrix);
this.readMappingMatrix = new BitMatrix(this.mappingBitMatrix.getWidth(), this.mappingBitMatrix.getHeight());
}
Version getVersion() {
return version;
}
/**
* <p>Creates the version object based on the dimension of the original bit matrix from
* the datamatrix code.</p>
*
* <p>See ISO 16022:2006 Table 7 - ECC 200 symbol attributes</p>
*
* @param bitMatrix Original {@link BitMatrix} including alignment patterns
* @return {@link Version} encapsulating the Data Matrix Code's "version"
* @throws FormatException if the dimensions of the mapping matrix are not valid
* Data Matrix dimensions.
*/
private static Version readVersion(BitMatrix bitMatrix) throws FormatException {
int numRows = bitMatrix.getHeight();
int numColumns = bitMatrix.getWidth();
return Version.getVersionForDimensions(numRows, numColumns);
}
/**
* <p>Reads the bits in the {@link BitMatrix} representing the mapping matrix (No alignment patterns)
* in the correct order in order to reconstitute the codewords bytes contained within the
* Data Matrix Code.</p>
*
* @return bytes encoded within the Data Matrix Code
* @throws FormatException if the exact number of bytes expected is not read
*/
byte[] readCodewords() throws FormatException {
byte[] result = new byte[version.getTotalCodewords()];
int resultOffset = 0;
int row = 4;
int column = 0;
int numRows = mappingBitMatrix.getHeight();
int numColumns = mappingBitMatrix.getWidth();
boolean corner1Read = false;
boolean corner2Read = false;
boolean corner3Read = false;
boolean corner4Read = false;
// Read all of the codewords
do {
// Check the four corner cases
if ((row == numRows) && (column == 0) && !corner1Read) {
result[resultOffset++] = (byte) readCorner1(numRows, numColumns);
row -= 2;
column += 2;
corner1Read = true;
} else if ((row == numRows - 2) && (column == 0) && ((numColumns & 0x03) != 0) && !corner2Read) {
result[resultOffset++] = (byte) readCorner2(numRows, numColumns);
row -= 2;
column += 2;
corner2Read = true;
} else if ((row == numRows + 4) && (column == 2) && ((numColumns & 0x07) == 0) && !corner3Read) {
result[resultOffset++] = (byte) readCorner3(numRows, numColumns);
row -= 2;
column += 2;
corner3Read = true;
} else if ((row == numRows - 2) && (column == 0) && ((numColumns & 0x07) == 4) && !corner4Read) {
result[resultOffset++] = (byte) readCorner4(numRows, numColumns);
row -= 2;
column += 2;
corner4Read = true;
} else {
// Sweep upward diagonally to the right
do {
if ((row < numRows) && (column >= 0) && !readMappingMatrix.get(column, row)) {
result[resultOffset++] = (byte) readUtah(row, column, numRows, numColumns);
}
row -= 2;
column += 2;
} while ((row >= 0) && (column < numColumns));
row += 1;
column += 3;
// Sweep downward diagonally to the left
do {
if ((row >= 0) && (column < numColumns) && !readMappingMatrix.get(column, row)) {
result[resultOffset++] = (byte) readUtah(row, column, numRows, numColumns);
}
row += 2;
column -= 2;
} while ((row < numRows) && (column >= 0));
row += 3;
column += 1;
}
} while ((row < numRows) || (column < numColumns));
if (resultOffset != version.getTotalCodewords()) {
throw FormatException.getFormatInstance();
}
return result;
}
/**
* <p>Reads a bit of the mapping matrix accounting for boundary wrapping.</p>
*
* @param row Row to read in the mapping matrix
* @param column Column to read in the mapping matrix
* @param numRows Number of rows in the mapping matrix
* @param numColumns Number of columns in the mapping matrix
* @return value of the given bit in the mapping matrix
*/
private boolean readModule(int row, int column, int numRows, int numColumns) {
// Adjust the row and column indices based on boundary wrapping
if (row < 0) {
row += numRows;
column += 4 - ((numRows + 4) & 0x07);
}
if (column < 0) {
column += numColumns;
row += 4 - ((numColumns + 4) & 0x07);
}
if (row >= numRows) {
row -= numRows;
}
readMappingMatrix.set(column, row);
return mappingBitMatrix.get(column, row);
}
/**
* <p>Reads the 8 bits of the standard Utah-shaped pattern.</p>
*
* <p>See ISO 16022:2006, 5.8.1 Figure 6</p>
*
* @param row Current row in the mapping matrix, anchored at the 8th bit (LSB) of the pattern
* @param column Current column in the mapping matrix, anchored at the 8th bit (LSB) of the pattern
* @param numRows Number of rows in the mapping matrix
* @param numColumns Number of columns in the mapping matrix
* @return byte from the utah shape
*/
private int readUtah(int row, int column, int numRows, int numColumns) {
int currentByte = 0;
if (readModule(row - 2, column - 2, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(row - 2, column - 1, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(row - 1, column - 2, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(row - 1, column - 1, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(row - 1, column, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(row, column - 2, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(row, column - 1, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(row, column, numRows, numColumns)) {
currentByte |= 1;
}
return currentByte;
}
/**
* <p>Reads the 8 bits of the special corner condition 1.</p>
*
* <p>See ISO 16022:2006, Figure F.3</p>
*
* @param numRows Number of rows in the mapping matrix
* @param numColumns Number of columns in the mapping matrix
* @return byte from the Corner condition 1
*/
private int readCorner1(int numRows, int numColumns) {
int currentByte = 0;
if (readModule(numRows - 1, 0, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(numRows - 1, 1, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(numRows - 1, 2, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(0, numColumns - 2, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(0, numColumns - 1, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(1, numColumns - 1, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(2, numColumns - 1, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(3, numColumns - 1, numRows, numColumns)) {
currentByte |= 1;
}
return currentByte;
}
/**
* <p>Reads the 8 bits of the special corner condition 2.</p>
*
* <p>See ISO 16022:2006, Figure F.4</p>
*
* @param numRows Number of rows in the mapping matrix
* @param numColumns Number of columns in the mapping matrix
* @return byte from the Corner condition 2
*/
private int readCorner2(int numRows, int numColumns) {
int currentByte = 0;
if (readModule(numRows - 3, 0, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(numRows - 2, 0, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(numRows - 1, 0, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(0, numColumns - 4, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(0, numColumns - 3, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(0, numColumns - 2, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(0, numColumns - 1, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(1, numColumns - 1, numRows, numColumns)) {
currentByte |= 1;
}
return currentByte;
}
/**
* <p>Reads the 8 bits of the special corner condition 3.</p>
*
* <p>See ISO 16022:2006, Figure F.5</p>
*
* @param numRows Number of rows in the mapping matrix
* @param numColumns Number of columns in the mapping matrix
* @return byte from the Corner condition 3
*/
private int readCorner3(int numRows, int numColumns) {
int currentByte = 0;
if (readModule(numRows - 1, 0, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(numRows - 1, numColumns - 1, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(0, numColumns - 3, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(0, numColumns - 2, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(0, numColumns - 1, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(1, numColumns - 3, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(1, numColumns - 2, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(1, numColumns - 1, numRows, numColumns)) {
currentByte |= 1;
}
return currentByte;
}
/**
* <p>Reads the 8 bits of the special corner condition 4.</p>
*
* <p>See ISO 16022:2006, Figure F.6</p>
*
* @param numRows Number of rows in the mapping matrix
* @param numColumns Number of columns in the mapping matrix
* @return byte from the Corner condition 4
*/
private int readCorner4(int numRows, int numColumns) {
int currentByte = 0;
if (readModule(numRows - 3, 0, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(numRows - 2, 0, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(numRows - 1, 0, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(0, numColumns - 2, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(0, numColumns - 1, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(1, numColumns - 1, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(2, numColumns - 1, numRows, numColumns)) {
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(3, numColumns - 1, numRows, numColumns)) {
currentByte |= 1;
}
return currentByte;
}
/**
* <p>Extracts the data region from a {@link BitMatrix} that contains
* alignment patterns.</p>
*
* @param bitMatrix Original {@link BitMatrix} with alignment patterns
* @return BitMatrix that has the alignment patterns removed
*/
private BitMatrix extractDataRegion(BitMatrix bitMatrix) {
int symbolSizeRows = version.getSymbolSizeRows();
int symbolSizeColumns = version.getSymbolSizeColumns();
if (bitMatrix.getHeight() != symbolSizeRows) {
throw new IllegalArgumentException("Dimension of bitMatrix must match the version size");
}
int dataRegionSizeRows = version.getDataRegionSizeRows();
int dataRegionSizeColumns = version.getDataRegionSizeColumns();
int numDataRegionsRow = symbolSizeRows / dataRegionSizeRows;
int numDataRegionsColumn = symbolSizeColumns / dataRegionSizeColumns;
int sizeDataRegionRow = numDataRegionsRow * dataRegionSizeRows;
int sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns;
BitMatrix bitMatrixWithoutAlignment = new BitMatrix(sizeDataRegionColumn, sizeDataRegionRow);
for (int dataRegionRow = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow) {
int dataRegionRowOffset = dataRegionRow * dataRegionSizeRows;
for (int dataRegionColumn = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn) {
int dataRegionColumnOffset = dataRegionColumn * dataRegionSizeColumns;
for (int i = 0; i < dataRegionSizeRows; ++i) {
int readRowOffset = dataRegionRow * (dataRegionSizeRows + 2) + 1 + i;
int writeRowOffset = dataRegionRowOffset + i;
for (int j = 0; j < dataRegionSizeColumns; ++j) {
int readColumnOffset = dataRegionColumn * (dataRegionSizeColumns + 2) + 1 + j;
if (bitMatrix.get(readColumnOffset, readRowOffset)) {
int writeColumnOffset = dataRegionColumnOffset + j;
bitMatrixWithoutAlignment.set(writeColumnOffset, writeRowOffset);
}
}
}
}
}
return bitMatrixWithoutAlignment;
}
}

View File

@@ -0,0 +1,118 @@
/*
* 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.datamatrix.decoder;
/**
* <p>Encapsulates a block of data within a Data Matrix Code. Data Matrix Codes may split their data into
* multiple blocks, each of which is a unit of data and error-correction codewords. Each
* is represented by an instance of this class.</p>
*
* @author bbrown@google.com (Brian Brown)
*/
final class DataBlock {
private final int numDataCodewords;
private final byte[] codewords;
private DataBlock(int numDataCodewords, byte[] codewords) {
this.numDataCodewords = numDataCodewords;
this.codewords = codewords;
}
/**
* <p>When Data Matrix Codes use multiple data blocks, they actually interleave the bytes of each of them.
* That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This
* method will separate the data into original blocks.</p>
*
* @param rawCodewords bytes as read directly from the Data Matrix Code
* @param version version of the Data Matrix Code
* @return DataBlocks containing original bytes, "de-interleaved" from representation in the
* Data Matrix Code
*/
static DataBlock[] getDataBlocks(byte[] rawCodewords,
Version version) {
// Figure out the number and size of data blocks used by this version
Version.ECBlocks ecBlocks = version.getECBlocks();
// First count the total number of data blocks
int totalBlocks = 0;
Version.ECB[] ecBlockArray = ecBlocks.getECBlocks();
for (Version.ECB ecBlock : ecBlockArray) {
totalBlocks += ecBlock.getCount();
}
// Now establish DataBlocks of the appropriate size and number of data codewords
DataBlock[] result = new DataBlock[totalBlocks];
int numResultBlocks = 0;
for (Version.ECB ecBlock : ecBlockArray) {
for (int i = 0; i < ecBlock.getCount(); i++) {
int numDataCodewords = ecBlock.getDataCodewords();
int numBlockCodewords = ecBlocks.getECCodewords() + numDataCodewords;
result[numResultBlocks++] = new DataBlock(numDataCodewords, new byte[numBlockCodewords]);
}
}
// All blocks have the same amount of data, except that the last n
// (where n may be 0) have 1 less byte. Figure out where these start.
// TODO(bbrown): There is only one case where there is a difference for Data Matrix for size 144
int longerBlocksTotalCodewords = result[0].codewords.length;
//int shorterBlocksTotalCodewords = longerBlocksTotalCodewords - 1;
int longerBlocksNumDataCodewords = longerBlocksTotalCodewords - ecBlocks.getECCodewords();
int shorterBlocksNumDataCodewords = longerBlocksNumDataCodewords - 1;
// The last elements of result may be 1 element shorter for 144 matrix
// first fill out as many elements as all of them have minus 1
int rawCodewordsOffset = 0;
for (int i = 0; i < shorterBlocksNumDataCodewords; i++) {
for (int j = 0; j < numResultBlocks; j++) {
result[j].codewords[i] = rawCodewords[rawCodewordsOffset++];
}
}
// Fill out the last data block in the longer ones
boolean specialVersion = version.getVersionNumber() == 24;
int numLongerBlocks = specialVersion ? 8 : numResultBlocks;
for (int j = 0; j < numLongerBlocks; j++) {
result[j].codewords[longerBlocksNumDataCodewords - 1] = rawCodewords[rawCodewordsOffset++];
}
// Now add in error correction blocks
int max = result[0].codewords.length;
for (int i = longerBlocksNumDataCodewords; i < max; i++) {
for (int j = 0; j < numResultBlocks; j++) {
int jOffset = specialVersion ? (j + 8) % numResultBlocks : j;
int iOffset = specialVersion && jOffset > 7 ? i - 1 : i;
result[jOffset].codewords[iOffset] = rawCodewords[rawCodewordsOffset++];
}
}
if (rawCodewordsOffset != rawCodewords.length) {
throw new IllegalArgumentException();
}
return result;
}
int getNumDataCodewords() {
return numDataCodewords;
}
byte[] getCodewords() {
return codewords;
}
}

View File

@@ -0,0 +1,590 @@
/*
* 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.datamatrix.decoder;
import com.google.zxing.FormatException;
import com.google.zxing.common.BitSource;
import com.google.zxing.common.DecoderResult;
import com.google.zxing.common.ECIStringBuilder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* <p>Data Matrix Codes can encode text as bits in one of several modes, and can use multiple modes
* in one Data Matrix Code. This class decodes the bits back into text.</p>
*
* <p>See ISO 16022:2006, 5.2.1 - 5.2.9.2</p>
*
* @author bbrown@google.com (Brian Brown)
* @author Sean Owen
*/
final class DecodedBitStreamParser {
private enum Mode {
PAD_ENCODE, // Not really a mode
ASCII_ENCODE,
C40_ENCODE,
TEXT_ENCODE,
ANSIX12_ENCODE,
EDIFACT_ENCODE,
BASE256_ENCODE,
ECI_ENCODE
}
/**
* See ISO 16022:2006, Annex C Table C.1
* The C40 Basic Character Set (*'s used for placeholders for the shift values)
*/
private static final char[] C40_BASIC_SET_CHARS = {
'*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
};
private static final char[] C40_SHIFT2_SET_CHARS = {
'!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.',
'/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_'
};
/**
* See ISO 16022:2006, Annex C Table C.2
* The Text Basic Character Set (*'s used for placeholders for the shift values)
*/
private static final char[] TEXT_BASIC_SET_CHARS = {
'*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
};
// Shift 2 for Text is the same encoding as C40
private static final char[] TEXT_SHIFT2_SET_CHARS = C40_SHIFT2_SET_CHARS;
private static final char[] TEXT_SHIFT3_SET_CHARS = {
'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', (char) 127
};
private DecodedBitStreamParser() {
}
static DecoderResult decode(byte[] bytes) throws FormatException {
BitSource bits = new BitSource(bytes);
ECIStringBuilder result = new ECIStringBuilder(100);
StringBuilder resultTrailer = new StringBuilder(0);
List<byte[]> byteSegments = new ArrayList<>(1);
Mode mode = Mode.ASCII_ENCODE;
// Could look directly at 'bytes', if we're sure of not having to account for multi byte values
Set<Integer> fnc1Positions = new HashSet<>();
int symbologyModifier;
boolean isECIencoded = false;
do {
if (mode == Mode.ASCII_ENCODE) {
mode = decodeAsciiSegment(bits, result, resultTrailer, fnc1Positions);
} else {
switch (mode) {
case C40_ENCODE:
decodeC40Segment(bits, result, fnc1Positions);
break;
case TEXT_ENCODE:
decodeTextSegment(bits, result, fnc1Positions);
break;
case ANSIX12_ENCODE:
decodeAnsiX12Segment(bits, result);
break;
case EDIFACT_ENCODE:
decodeEdifactSegment(bits, result);
break;
case BASE256_ENCODE:
decodeBase256Segment(bits, result, byteSegments);
break;
case ECI_ENCODE:
decodeECISegment(bits, result);
isECIencoded = true; // ECI detection only, atm continue decoding as ASCII
break;
default:
throw FormatException.getFormatInstance();
}
mode = Mode.ASCII_ENCODE;
}
} while (mode != Mode.PAD_ENCODE && bits.available() > 0);
if (resultTrailer.length() > 0) {
result.appendCharacters(resultTrailer);
}
if (isECIencoded) {
// Examples for this numbers can be found in this documentation of a hardware barcode scanner:
// https://honeywellaidc.force.com/supportppr/s/article/List-of-barcode-symbology-AIM-Identifiers
if (fnc1Positions.contains(0) || fnc1Positions.contains(4)) {
symbologyModifier = 5;
} else if (fnc1Positions.contains(1) || fnc1Positions.contains(5)) {
symbologyModifier = 6;
} else {
symbologyModifier = 4;
}
} else {
if (fnc1Positions.contains(0) || fnc1Positions.contains(4)) {
symbologyModifier = 2;
} else if (fnc1Positions.contains(1) || fnc1Positions.contains(5)) {
symbologyModifier = 3;
} else {
symbologyModifier = 1;
}
}
return new DecoderResult(bytes,
result.toString(),
byteSegments.isEmpty() ? null : byteSegments,
null,
symbologyModifier);
}
/**
* See ISO 16022:2006, 5.2.3 and Annex C, Table C.2
*/
private static Mode decodeAsciiSegment(BitSource bits,
ECIStringBuilder result,
StringBuilder resultTrailer,
Set<Integer> fnc1positions) throws FormatException {
boolean upperShift = false;
do {
int oneByte = bits.readBits(8);
if (oneByte == 0) {
throw FormatException.getFormatInstance();
} else if (oneByte <= 128) { // ASCII data (ASCII value + 1)
if (upperShift) {
oneByte += 128;
//upperShift = false;
}
result.append((char) (oneByte - 1));
return Mode.ASCII_ENCODE;
} else if (oneByte == 129) { // Pad
return Mode.PAD_ENCODE;
} else if (oneByte <= 229) { // 2-digit data 00-99 (Numeric Value + 130)
int value = oneByte - 130;
if (value < 10) { // pad with '0' for single digit values
result.append('0');
}
result.append(value);
} else {
switch (oneByte) {
case 230: // Latch to C40 encodation
return Mode.C40_ENCODE;
case 231: // Latch to Base 256 encodation
return Mode.BASE256_ENCODE;
case 232: // FNC1
fnc1positions.add(result.length());
result.append((char) 29); // translate as ASCII 29
break;
case 233: // Structured Append
case 234: // Reader Programming
// Ignore these symbols for now
//throw ReaderException.getInstance();
break;
case 235: // Upper Shift (shift to Extended ASCII)
upperShift = true;
break;
case 236: // 05 Macro
result.append("[)>\u001E05\u001D");
resultTrailer.insert(0, "\u001E\u0004");
break;
case 237: // 06 Macro
result.append("[)>\u001E06\u001D");
resultTrailer.insert(0, "\u001E\u0004");
break;
case 238: // Latch to ANSI X12 encodation
return Mode.ANSIX12_ENCODE;
case 239: // Latch to Text encodation
return Mode.TEXT_ENCODE;
case 240: // Latch to EDIFACT encodation
return Mode.EDIFACT_ENCODE;
case 241: // ECI Character
return Mode.ECI_ENCODE;
default:
// Not to be used in ASCII encodation
// but work around encoders that end with 254, latch back to ASCII
if (oneByte != 254 || bits.available() != 0) {
throw FormatException.getFormatInstance();
}
break;
}
}
} while (bits.available() > 0);
return Mode.ASCII_ENCODE;
}
/**
* See ISO 16022:2006, 5.2.5 and Annex C, Table C.1
*/
private static void decodeC40Segment(BitSource bits, ECIStringBuilder result, Set<Integer> fnc1positions)
throws FormatException {
// Three C40 values are encoded in a 16-bit value as
// (1600 * C1) + (40 * C2) + C3 + 1
// TODO(bbrown): The Upper Shift with C40 doesn't work in the 4 value scenario all the time
boolean upperShift = false;
int[] cValues = new int[3];
int shift = 0;
do {
// If there is only one byte left then it will be encoded as ASCII
if (bits.available() == 8) {
return;
}
int firstByte = bits.readBits(8);
if (firstByte == 254) { // Unlatch codeword
return;
}
parseTwoBytes(firstByte, bits.readBits(8), cValues);
for (int i = 0; i < 3; i++) {
int cValue = cValues[i];
switch (shift) {
case 0:
if (cValue < 3) {
shift = cValue + 1;
} else if (cValue < C40_BASIC_SET_CHARS.length) {
char c40char = C40_BASIC_SET_CHARS[cValue];
if (upperShift) {
result.append((char) (c40char + 128));
upperShift = false;
} else {
result.append(c40char);
}
} else {
throw FormatException.getFormatInstance();
}
break;
case 1:
if (upperShift) {
result.append((char) (cValue + 128));
upperShift = false;
} else {
result.append((char) cValue);
}
shift = 0;
break;
case 2:
if (cValue < C40_SHIFT2_SET_CHARS.length) {
char c40char = C40_SHIFT2_SET_CHARS[cValue];
if (upperShift) {
result.append((char) (c40char + 128));
upperShift = false;
} else {
result.append(c40char);
}
} else {
switch (cValue) {
case 27: // FNC1
fnc1positions.add(result.length());
result.append((char) 29); // translate as ASCII 29
break;
case 30: // Upper Shift
upperShift = true;
break;
default:
throw FormatException.getFormatInstance();
}
}
shift = 0;
break;
case 3:
if (upperShift) {
result.append((char) (cValue + 224));
upperShift = false;
} else {
result.append((char) (cValue + 96));
}
shift = 0;
break;
default:
throw FormatException.getFormatInstance();
}
}
} while (bits.available() > 0);
}
/**
* See ISO 16022:2006, 5.2.6 and Annex C, Table C.2
*/
private static void decodeTextSegment(BitSource bits, ECIStringBuilder result, Set<Integer> fnc1positions)
throws FormatException {
// Three Text values are encoded in a 16-bit value as
// (1600 * C1) + (40 * C2) + C3 + 1
// TODO(bbrown): The Upper Shift with Text doesn't work in the 4 value scenario all the time
boolean upperShift = false;
int[] cValues = new int[3];
int shift = 0;
do {
// If there is only one byte left then it will be encoded as ASCII
if (bits.available() == 8) {
return;
}
int firstByte = bits.readBits(8);
if (firstByte == 254) { // Unlatch codeword
return;
}
parseTwoBytes(firstByte, bits.readBits(8), cValues);
for (int i = 0; i < 3; i++) {
int cValue = cValues[i];
switch (shift) {
case 0:
if (cValue < 3) {
shift = cValue + 1;
} else if (cValue < TEXT_BASIC_SET_CHARS.length) {
char textChar = TEXT_BASIC_SET_CHARS[cValue];
if (upperShift) {
result.append((char) (textChar + 128));
upperShift = false;
} else {
result.append(textChar);
}
} else {
throw FormatException.getFormatInstance();
}
break;
case 1:
if (upperShift) {
result.append((char) (cValue + 128));
upperShift = false;
} else {
result.append((char) cValue);
}
shift = 0;
break;
case 2:
// Shift 2 for Text is the same encoding as C40
if (cValue < TEXT_SHIFT2_SET_CHARS.length) {
char textChar = TEXT_SHIFT2_SET_CHARS[cValue];
if (upperShift) {
result.append((char) (textChar + 128));
upperShift = false;
} else {
result.append(textChar);
}
} else {
switch (cValue) {
case 27: // FNC1
fnc1positions.add(result.length());
result.append((char) 29); // translate as ASCII 29
break;
case 30: // Upper Shift
upperShift = true;
break;
default:
throw FormatException.getFormatInstance();
}
}
shift = 0;
break;
case 3:
if (cValue < TEXT_SHIFT3_SET_CHARS.length) {
char textChar = TEXT_SHIFT3_SET_CHARS[cValue];
if (upperShift) {
result.append((char) (textChar + 128));
upperShift = false;
} else {
result.append(textChar);
}
shift = 0;
} else {
throw FormatException.getFormatInstance();
}
break;
default:
throw FormatException.getFormatInstance();
}
}
} while (bits.available() > 0);
}
/**
* See ISO 16022:2006, 5.2.7
*/
private static void decodeAnsiX12Segment(BitSource bits,
ECIStringBuilder result) throws FormatException {
// Three ANSI X12 values are encoded in a 16-bit value as
// (1600 * C1) + (40 * C2) + C3 + 1
int[] cValues = new int[3];
do {
// If there is only one byte left then it will be encoded as ASCII
if (bits.available() == 8) {
return;
}
int firstByte = bits.readBits(8);
if (firstByte == 254) { // Unlatch codeword
return;
}
parseTwoBytes(firstByte, bits.readBits(8), cValues);
for (int i = 0; i < 3; i++) {
int cValue = cValues[i];
switch (cValue) {
case 0: // X12 segment terminator <CR>
result.append('\r');
break;
case 1: // X12 segment separator *
result.append('*');
break;
case 2: // X12 sub-element separator >
result.append('>');
break;
case 3: // space
result.append(' ');
break;
default:
if (cValue < 14) { // 0 - 9
result.append((char) (cValue + 44));
} else if (cValue < 40) { // A - Z
result.append((char) (cValue + 51));
} else {
throw FormatException.getFormatInstance();
}
break;
}
}
} while (bits.available() > 0);
}
private static void parseTwoBytes(int firstByte, int secondByte, int[] result) {
int fullBitValue = (firstByte << 8) + secondByte - 1;
int temp = fullBitValue / 1600;
result[0] = temp;
fullBitValue -= temp * 1600;
temp = fullBitValue / 40;
result[1] = temp;
result[2] = fullBitValue - temp * 40;
}
/**
* See ISO 16022:2006, 5.2.8 and Annex C Table C.3
*/
private static void decodeEdifactSegment(BitSource bits, ECIStringBuilder result) {
do {
// If there is only two or less bytes left then it will be encoded as ASCII
if (bits.available() <= 16) {
return;
}
for (int i = 0; i < 4; i++) {
int edifactValue = bits.readBits(6);
// Check for the unlatch character
if (edifactValue == 0x1F) { // 011111
// Read rest of byte, which should be 0, and stop
int bitsLeft = 8 - bits.getBitOffset();
if (bitsLeft != 8) {
bits.readBits(bitsLeft);
}
return;
}
if ((edifactValue & 0x20) == 0) { // no 1 in the leading (6th) bit
edifactValue |= 0x40; // Add a leading 01 to the 6 bit binary value
}
result.append((char) edifactValue);
}
} while (bits.available() > 0);
}
/**
* See ISO 16022:2006, 5.2.9 and Annex B, B.2
*/
private static void decodeBase256Segment(BitSource bits,
ECIStringBuilder result,
Collection<byte[]> byteSegments)
throws FormatException {
// Figure out how long the Base 256 Segment is.
int codewordPosition = 1 + bits.getByteOffset(); // position is 1-indexed
int d1 = unrandomize255State(bits.readBits(8), codewordPosition++);
int count;
if (d1 == 0) { // Read the remainder of the symbol
count = bits.available() / 8;
} else if (d1 < 250) {
count = d1;
} else {
count = 250 * (d1 - 249) + unrandomize255State(bits.readBits(8), codewordPosition++);
}
// We're seeing NegativeArraySizeException errors from users.
if (count < 0) {
throw FormatException.getFormatInstance();
}
byte[] bytes = new byte[count];
for (int i = 0; i < count; i++) {
// Have seen this particular error in the wild, such as at
// http://www.bcgen.com/demo/IDAutomationStreamingDataMatrix.aspx?MODE=3&D=Fred&PFMT=3&PT=F&X=0.3&O=0&LM=0.2
if (bits.available() < 8) {
throw FormatException.getFormatInstance();
}
bytes[i] = (byte) unrandomize255State(bits.readBits(8), codewordPosition++);
}
byteSegments.add(bytes);
result.append(new String(bytes, StandardCharsets.ISO_8859_1));
}
/**
* See ISO 16022:2007, 5.4.1
*/
private static void decodeECISegment(BitSource bits,
ECIStringBuilder result)
throws FormatException {
if (bits.available() < 8) {
throw FormatException.getFormatInstance();
}
int c1 = bits.readBits(8);
if (c1 <= 127) {
result.appendECI(c1 - 1);
}
//currently we only support character set ECIs
/*} else {
if (bits.available() < 8) {
throw FormatException.getFormatInstance();
}
int c2 = bits.readBits(8);
if (c1 >= 128 && c1 <= 191) {
} else {
if (bits.available() < 8) {
throw FormatException.getFormatInstance();
}
int c3 = bits.readBits(8);
}
}*/
}
/**
* See ISO 16022:2006, Annex B, B.2
*/
private static int unrandomize255State(int randomizedBase256Codeword,
int base256CodewordPosition) {
int pseudoRandomNumber = ((149 * base256CodewordPosition) % 255) + 1;
int tempVariable = randomizedBase256Codeword - pseudoRandomNumber;
return tempVariable >= 0 ? tempVariable : tempVariable + 256;
}
}

View File

@@ -0,0 +1,125 @@
/*
* 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.datamatrix.decoder;
import com.google.zxing.ChecksumException;
import com.google.zxing.FormatException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.DecoderResult;
import com.google.zxing.common.reedsolomon.GenericGF;
import com.google.zxing.common.reedsolomon.ReedSolomonDecoder;
import com.google.zxing.common.reedsolomon.ReedSolomonException;
/**
* <p>The main class which implements Data Matrix Code decoding -- as opposed to locating and extracting
* the Data Matrix Code from an image.</p>
*
* @author bbrown@google.com (Brian Brown)
*/
public final class Decoder {
private final ReedSolomonDecoder rsDecoder;
public Decoder() {
rsDecoder = new ReedSolomonDecoder(GenericGF.DATA_MATRIX_FIELD_256);
}
/**
* <p>Convenience method that can decode a Data Matrix Code represented as a 2D array of booleans.
* "true" is taken to mean a black module.</p>
*
* @param image booleans representing white/black Data Matrix Code modules
* @return text and bytes encoded within the Data Matrix Code
* @throws FormatException if the Data Matrix Code cannot be decoded
* @throws ChecksumException if error correction fails
*/
public DecoderResult decode(boolean[][] image) throws FormatException, ChecksumException {
return decode(BitMatrix.parse(image));
}
/**
* <p>Decodes a Data Matrix Code represented as a {@link BitMatrix}. A 1 or "true" is taken
* to mean a black module.</p>
*
* @param bits booleans representing white/black Data Matrix Code modules
* @return text and bytes encoded within the Data Matrix Code
* @throws FormatException if the Data Matrix Code cannot be decoded
* @throws ChecksumException if error correction fails
*/
public DecoderResult decode(BitMatrix bits) throws FormatException, ChecksumException {
// Construct a parser and read version, error-correction level
BitMatrixParser parser = new BitMatrixParser(bits);
Version version = parser.getVersion();
// Read codewords
byte[] codewords = parser.readCodewords();
// Separate into data blocks
DataBlock[] dataBlocks = DataBlock.getDataBlocks(codewords, version);
// Count total number of data bytes
int totalBytes = 0;
for (DataBlock db : dataBlocks) {
totalBytes += db.getNumDataCodewords();
}
byte[] resultBytes = new byte[totalBytes];
int dataBlocksCount = dataBlocks.length;
// Error-correct and copy data blocks together into a stream of bytes
for (int j = 0; j < dataBlocksCount; j++) {
DataBlock dataBlock = dataBlocks[j];
byte[] codewordBytes = dataBlock.getCodewords();
int numDataCodewords = dataBlock.getNumDataCodewords();
correctErrors(codewordBytes, numDataCodewords);
for (int i = 0; i < numDataCodewords; i++) {
// De-interlace data blocks.
resultBytes[i * dataBlocksCount + j] = codewordBytes[i];
}
}
// Decode the contents of that stream of bytes
return DecodedBitStreamParser.decode(resultBytes);
}
/**
* <p>Given data and error-correction codewords received, possibly corrupted by errors, attempts to
* correct the errors in-place using Reed-Solomon error correction.</p>
*
* @param codewordBytes data and error correction codewords
* @param numDataCodewords number of codewords that are data bytes
* @throws ChecksumException if error correction fails
*/
private void correctErrors(byte[] codewordBytes, int numDataCodewords) throws ChecksumException {
int numCodewords = codewordBytes.length;
// First read into an array of ints
int[] codewordsInts = new int[numCodewords];
for (int i = 0; i < numCodewords; i++) {
codewordsInts[i] = codewordBytes[i] & 0xFF;
}
try {
rsDecoder.decode(codewordsInts, codewordBytes.length - numDataCodewords);
} catch (ReedSolomonException ignored) {
throw ChecksumException.getChecksumInstance();
}
// Copy back into array of bytes -- only need to worry about the bytes that were data
// We don't care about errors in the error-correction codewords
for (int i = 0; i < numDataCodewords; i++) {
codewordBytes[i] = (byte) codewordsInts[i];
}
}
}

View File

@@ -0,0 +1,276 @@
/*
* 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.datamatrix.decoder;
import com.google.zxing.FormatException;
/**
* The Version object encapsulates attributes about a particular
* size Data Matrix Code.
*
* @author bbrown@google.com (Brian Brown)
*/
public final class Version {
private static final Version[] VERSIONS = buildVersions();
private final int versionNumber;
private final int symbolSizeRows;
private final int symbolSizeColumns;
private final int dataRegionSizeRows;
private final int dataRegionSizeColumns;
private final ECBlocks ecBlocks;
private final int totalCodewords;
private Version(int versionNumber,
int symbolSizeRows,
int symbolSizeColumns,
int dataRegionSizeRows,
int dataRegionSizeColumns,
ECBlocks ecBlocks) {
this.versionNumber = versionNumber;
this.symbolSizeRows = symbolSizeRows;
this.symbolSizeColumns = symbolSizeColumns;
this.dataRegionSizeRows = dataRegionSizeRows;
this.dataRegionSizeColumns = dataRegionSizeColumns;
this.ecBlocks = ecBlocks;
// Calculate the total number of codewords
int total = 0;
int ecCodewords = ecBlocks.getECCodewords();
ECB[] ecbArray = ecBlocks.getECBlocks();
for (ECB ecBlock : ecbArray) {
total += ecBlock.getCount() * (ecBlock.getDataCodewords() + ecCodewords);
}
this.totalCodewords = total;
}
public int getVersionNumber() {
return versionNumber;
}
public int getSymbolSizeRows() {
return symbolSizeRows;
}
public int getSymbolSizeColumns() {
return symbolSizeColumns;
}
public int getDataRegionSizeRows() {
return dataRegionSizeRows;
}
public int getDataRegionSizeColumns() {
return dataRegionSizeColumns;
}
public int getTotalCodewords() {
return totalCodewords;
}
ECBlocks getECBlocks() {
return ecBlocks;
}
/**
* <p>Deduces version information from Data Matrix dimensions.</p>
*
* @param numRows Number of rows in modules
* @param numColumns Number of columns in modules
* @return Version for a Data Matrix Code of those dimensions
* @throws FormatException if dimensions do correspond to a valid Data Matrix size
*/
public static Version getVersionForDimensions(int numRows, int numColumns) throws FormatException {
if ((numRows & 0x01) != 0 || (numColumns & 0x01) != 0) {
throw FormatException.getFormatInstance();
}
for (Version version : VERSIONS) {
if (version.symbolSizeRows == numRows && version.symbolSizeColumns == numColumns) {
return version;
}
}
throw FormatException.getFormatInstance();
}
/**
* <p>Encapsulates a set of error-correction blocks in one symbol version. Most versions will
* use blocks of differing sizes within one version, so, this encapsulates the parameters for
* each set of blocks. It also holds the number of error-correction codewords per block since it
* will be the same across all blocks within one version.</p>
*/
static final class ECBlocks {
private final int ecCodewords;
private final ECB[] ecBlocks;
private ECBlocks(int ecCodewords, ECB ecBlocks) {
this.ecCodewords = ecCodewords;
this.ecBlocks = new ECB[] { ecBlocks };
}
private ECBlocks(int ecCodewords, ECB ecBlocks1, ECB ecBlocks2) {
this.ecCodewords = ecCodewords;
this.ecBlocks = new ECB[] { ecBlocks1, ecBlocks2 };
}
int getECCodewords() {
return ecCodewords;
}
ECB[] getECBlocks() {
return ecBlocks;
}
}
/**
* <p>Encapsulates the parameters for one error-correction block in one symbol version.
* This includes the number of data codewords, and the number of times a block with these
* parameters is used consecutively in the Data Matrix code version's format.</p>
*/
static final class ECB {
private final int count;
private final int dataCodewords;
private ECB(int count, int dataCodewords) {
this.count = count;
this.dataCodewords = dataCodewords;
}
int getCount() {
return count;
}
int getDataCodewords() {
return dataCodewords;
}
}
@Override
public String toString() {
return String.valueOf(versionNumber);
}
/**
* See ISO 16022:2006 5.5.1 Table 7
*/
private static Version[] buildVersions() {
return new Version[]{
new Version(1, 10, 10, 8, 8,
new ECBlocks(5, new ECB(1, 3))),
new Version(2, 12, 12, 10, 10,
new ECBlocks(7, new ECB(1, 5))),
new Version(3, 14, 14, 12, 12,
new ECBlocks(10, new ECB(1, 8))),
new Version(4, 16, 16, 14, 14,
new ECBlocks(12, new ECB(1, 12))),
new Version(5, 18, 18, 16, 16,
new ECBlocks(14, new ECB(1, 18))),
new Version(6, 20, 20, 18, 18,
new ECBlocks(18, new ECB(1, 22))),
new Version(7, 22, 22, 20, 20,
new ECBlocks(20, new ECB(1, 30))),
new Version(8, 24, 24, 22, 22,
new ECBlocks(24, new ECB(1, 36))),
new Version(9, 26, 26, 24, 24,
new ECBlocks(28, new ECB(1, 44))),
new Version(10, 32, 32, 14, 14,
new ECBlocks(36, new ECB(1, 62))),
new Version(11, 36, 36, 16, 16,
new ECBlocks(42, new ECB(1, 86))),
new Version(12, 40, 40, 18, 18,
new ECBlocks(48, new ECB(1, 114))),
new Version(13, 44, 44, 20, 20,
new ECBlocks(56, new ECB(1, 144))),
new Version(14, 48, 48, 22, 22,
new ECBlocks(68, new ECB(1, 174))),
new Version(15, 52, 52, 24, 24,
new ECBlocks(42, new ECB(2, 102))),
new Version(16, 64, 64, 14, 14,
new ECBlocks(56, new ECB(2, 140))),
new Version(17, 72, 72, 16, 16,
new ECBlocks(36, new ECB(4, 92))),
new Version(18, 80, 80, 18, 18,
new ECBlocks(48, new ECB(4, 114))),
new Version(19, 88, 88, 20, 20,
new ECBlocks(56, new ECB(4, 144))),
new Version(20, 96, 96, 22, 22,
new ECBlocks(68, new ECB(4, 174))),
new Version(21, 104, 104, 24, 24,
new ECBlocks(56, new ECB(6, 136))),
new Version(22, 120, 120, 18, 18,
new ECBlocks(68, new ECB(6, 175))),
new Version(23, 132, 132, 20, 20,
new ECBlocks(62, new ECB(8, 163))),
new Version(24, 144, 144, 22, 22,
new ECBlocks(62, new ECB(8, 156), new ECB(2, 155))),
new Version(25, 8, 18, 6, 16,
new ECBlocks(7, new ECB(1, 5))),
new Version(26, 8, 32, 6, 14,
new ECBlocks(11, new ECB(1, 10))),
new Version(27, 12, 26, 10, 24,
new ECBlocks(14, new ECB(1, 16))),
new Version(28, 12, 36, 10, 16,
new ECBlocks(18, new ECB(1, 22))),
new Version(29, 16, 36, 14, 16,
new ECBlocks(24, new ECB(1, 32))),
new Version(30, 16, 48, 14, 22,
new ECBlocks(28, new ECB(1, 49))),
// extended forms as specified in
// ISO 21471:2020 (DMRE) 5.5.1 Table 7
new Version(31, 8, 48, 6, 22,
new ECBlocks(15, new ECB(1, 18))),
new Version(32, 8, 64, 6, 14,
new ECBlocks(18, new ECB(1, 24))),
new Version(33, 8, 80, 6, 18,
new ECBlocks(22, new ECB(1, 32))),
new Version(34, 8, 96, 6, 22,
new ECBlocks(28, new ECB(1, 38))),
new Version(35, 8, 120, 6, 18,
new ECBlocks(32, new ECB(1, 49))),
new Version(36, 8, 144, 6, 22,
new ECBlocks(36, new ECB(1, 63))),
new Version(37, 12, 64, 10, 14,
new ECBlocks(27, new ECB(1, 43))),
new Version(38, 12, 88, 10, 20,
new ECBlocks(36, new ECB(1, 64))),
new Version(39, 16, 64, 14, 14,
new ECBlocks(36, new ECB(1, 62))),
new Version(40, 20, 36, 18, 16,
new ECBlocks(28, new ECB(1, 44))),
new Version(41, 20, 44, 18, 20,
new ECBlocks(34, new ECB(1, 56))),
new Version(42, 20, 64, 18, 14,
new ECBlocks(42, new ECB(1, 84))),
new Version(43, 22, 48, 20, 22,
new ECBlocks(38, new ECB(1, 72))),
new Version(44, 24, 48, 22, 22,
new ECBlocks(41, new ECB(1, 80))),
new Version(45, 24, 64, 22, 14,
new ECBlocks(46, new ECB(1, 108))),
new Version(46, 26, 40, 24, 18,
new ECBlocks(38, new ECB(1, 70))),
new Version(47, 26, 48, 24, 22,
new ECBlocks(42, new ECB(1, 90))),
new Version(48, 26, 64, 24, 14,
new ECBlocks(50, new ECB(1, 118)))
};
}
}