From 8573212ef6782a4657be2b3528c5673112057d62 Mon Sep 17 00:00:00 2001 From: Henry Schimke Date: Sun, 13 Nov 2022 17:24:45 -0600 Subject: [PATCH] incomplete port of decoder --- src/datamatrix/decoder/BitMatrixParser.java | 443 ---------------- src/datamatrix/decoder/bit_matrix_parser.rs | 495 ++++++++++++++++++ ...rser.java => decoded_bit_stream_parser.rs} | 422 +++++++-------- .../decoder/{Decoder.java => decoder.rs} | 92 ++-- src/datamatrix/decoder/mod.rs | 8 +- src/datamatrix/decoder/version.rs | 2 + 6 files changed, 765 insertions(+), 697 deletions(-) delete mode 100644 src/datamatrix/decoder/BitMatrixParser.java create mode 100644 src/datamatrix/decoder/bit_matrix_parser.rs rename src/datamatrix/decoder/{DecodedBitStreamParser.java => decoded_bit_stream_parser.rs} (57%) rename src/datamatrix/decoder/{Decoder.java => decoder.rs} (53%) diff --git a/src/datamatrix/decoder/BitMatrixParser.java b/src/datamatrix/decoder/BitMatrixParser.java deleted file mode 100644 index 225df65..0000000 --- a/src/datamatrix/decoder/BitMatrixParser.java +++ /dev/null @@ -1,443 +0,0 @@ -/* - * 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; - } - - /** - *

Creates the version object based on the dimension of the original bit matrix from - * the datamatrix code.

- * - *

See ISO 16022:2006 Table 7 - ECC 200 symbol attributes

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

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.

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

Reads a bit of the mapping matrix accounting for boundary wrapping.

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

Reads the 8 bits of the standard Utah-shaped pattern.

- * - *

See ISO 16022:2006, 5.8.1 Figure 6

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

Reads the 8 bits of the special corner condition 1.

- * - *

See ISO 16022:2006, Figure F.3

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

Reads the 8 bits of the special corner condition 2.

- * - *

See ISO 16022:2006, Figure F.4

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

Reads the 8 bits of the special corner condition 3.

- * - *

See ISO 16022:2006, Figure F.5

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

Reads the 8 bits of the special corner condition 4.

- * - *

See ISO 16022:2006, Figure F.6

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

Extracts the data region from a {@link BitMatrix} that contains - * alignment patterns.

- * - * @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; - } - -} diff --git a/src/datamatrix/decoder/bit_matrix_parser.rs b/src/datamatrix/decoder/bit_matrix_parser.rs new file mode 100644 index 0000000..9f88587 --- /dev/null +++ b/src/datamatrix/decoder/bit_matrix_parser.rs @@ -0,0 +1,495 @@ +/* + * 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. + */ + +use crate::{common::BitMatrix, Exceptions}; + +use super::{Version, VersionRef}; + +/** + * @author bbrown@google.com (Brian Brown) + */ +pub struct BitMatrixParser { + mappingBitMatrix: BitMatrix, + readMappingMatrix: BitMatrix, + version: VersionRef, +} +impl BitMatrixParser { + /** + * @param bitMatrix {@link BitMatrix} to parse + * @throws FormatException if dimension is < 8 or > 144 or not 0 mod 2 + */ + pub fn new(bitMatrix: &BitMatrix) -> Result { + let dimension = bitMatrix.getHeight(); + if dimension < 8 || dimension > 144 || (dimension & 0x01) != 0 { + return Err(Exceptions::FormatException("".to_owned())); + } + + let version = Self::readVersion(bitMatrix)?; + let mappingBitMatrix = Self::extractDataRegion(bitMatrix, version)?; + let readMappingMatrix = + BitMatrix::new(mappingBitMatrix.getWidth(), mappingBitMatrix.getHeight())?; + + Ok(Self { + mappingBitMatrix, + readMappingMatrix, + version, + }) + } + + pub fn getVersion(&self) -> &Version { + &self.version + } + + /** + *

Creates the version object based on the dimension of the original bit matrix from + * the datamatrix code.

+ * + *

See ISO 16022:2006 Table 7 - ECC 200 symbol attributes

+ * + * @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. + */ + fn readVersion(bitMatrix: &BitMatrix) -> Result { + let numRows = bitMatrix.getHeight(); + let numColumns = bitMatrix.getWidth(); + Version::getVersionForDimensions(numRows, numColumns) + } + + /** + *

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.

+ * + * @return bytes encoded within the Data Matrix Code + * @throws FormatException if the exact number of bytes expected is not read + */ + pub fn readCodewords(&self) -> Result, Exceptions> { + let result = vec![0u8; self.version.getTotalCodewords() as usize]; + let resultOffset = 0; + + let row = 4; + let column = 0_usize; + + let numRows = self.mappingBitMatrix.getHeight() as usize; + let numColumns = self.mappingBitMatrix.getWidth() as usize; + + let corner1Read = false; + let corner2Read = false; + let corner3Read = false; + let corner4Read = false; + + // Read all of the codewords + loop { + // Check the four corner cases + if (row == numRows) && (column == 0) && !corner1Read { + result[resultOffset] = self.readCorner1(numRows, numColumns) as u8; + resultOffset += 1; + row -= 2; + column += 2; + corner1Read = true; + } else if (row == numRows - 2) + && (column == 0) + && ((numColumns & 0x03) != 0) + && !corner2Read + { + result[resultOffset] = self.readCorner2(numRows, numColumns) as u8; + resultOffset += 1; + row -= 2; + column += 2; + corner2Read = true; + } else if (row == numRows + 4) + && (column == 2) + && ((numColumns & 0x07) == 0) + && !corner3Read + { + result[resultOffset] = self.readCorner3(numRows, numColumns) as u8; + resultOffset += 1; + row -= 2; + column += 2; + corner3Read = true; + } else if (row == numRows - 2) + && (column == 0) + && ((numColumns & 0x07) == 4) + && !corner4Read + { + result[resultOffset] = self.readCorner4(numRows, numColumns) as u8; + resultOffset += 1; + row -= 2; + column += 2; + corner4Read = true; + } else { + // Sweep upward diagonally to the right + loop { + if (row < numRows) + && (column >= 0) + && !self.readMappingMatrix.get(column as u32, row as u32) + { + result[resultOffset] = + self.readUtah(row, column, numRows, numColumns) as u8; + resultOffset += 1; + } + row -= 2; + column += 2; + if !((row >= 0) && (column < numColumns)) { + break; + } + } + row += 1; + column += 3; + + // Sweep downward diagonally to the left + loop { + if (row >= 0) + && (column < numColumns) + && !self.readMappingMatrix.get(column as u32, row as u32) + { + result[resultOffset] = + self.readUtah(row, column, numRows, numColumns) as u8; + resultOffset += 1; + } + row += 2; + column -= 2; + + if !((row < numRows) && (column >= 0)) { + break; + } + } + row += 3; + column += 1; + } + if !((row < numRows) || (column < numColumns)) { + break; + } + } + + if resultOffset != self.version.getTotalCodewords() as usize { + return Err(Exceptions::FormatException("".to_owned())); + } + + Ok(result) + } + + /** + *

Reads a bit of the mapping matrix accounting for boundary wrapping.

+ * + * @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 + */ + fn readModule(&self, row: usize, column: usize, numRows: usize, numColumns: usize) -> bool { + // 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; + } + self.readMappingMatrix.set(column as u32, row as u32); + + self.mappingBitMatrix.get(column as u32, row as u32) + } + + /** + *

Reads the 8 bits of the standard Utah-shaped pattern.

+ * + *

See ISO 16022:2006, 5.8.1 Figure 6

+ * + * @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 + */ + fn readUtah(&self, row: usize, column: usize, numRows: usize, numColumns: usize) -> u32 { + let mut currentByte = 0; + if self.readModule(row - 2, column - 2, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(row - 2, column - 1, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(row - 1, column - 2, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(row - 1, column - 1, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(row - 1, column, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(row, column - 2, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(row, column - 1, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(row, column, numRows, numColumns) { + currentByte |= 1; + } + return currentByte; + } + + /** + *

Reads the 8 bits of the special corner condition 1.

+ * + *

See ISO 16022:2006, Figure F.3

+ * + * @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 + */ + fn readCorner1(&self, numRows: usize, numColumns: usize) -> u32 { + let mut currentByte = 0; + if self.readModule(numRows - 1, 0, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(numRows - 1, 1, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(numRows - 1, 2, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(0, numColumns - 2, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(0, numColumns - 1, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(1, numColumns - 1, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(2, numColumns - 1, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(3, numColumns - 1, numRows, numColumns) { + currentByte |= 1; + } + return currentByte; + } + + /** + *

Reads the 8 bits of the special corner condition 2.

+ * + *

See ISO 16022:2006, Figure F.4

+ * + * @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 + */ + fn readCorner2(&self, numRows: usize, numColumns: usize) -> u32 { + let mut currentByte = 0; + if self.readModule(numRows - 3, 0, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(numRows - 2, 0, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(numRows - 1, 0, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(0, numColumns - 4, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(0, numColumns - 3, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(0, numColumns - 2, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(0, numColumns - 1, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(1, numColumns - 1, numRows, numColumns) { + currentByte |= 1; + } + return currentByte; + } + + /** + *

Reads the 8 bits of the special corner condition 3.

+ * + *

See ISO 16022:2006, Figure F.5

+ * + * @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 + */ + fn readCorner3(&self, numRows: usize, numColumns: usize) -> u32 { + let mut currentByte = 0; + if self.readModule(numRows - 1, 0, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(numRows - 1, numColumns - 1, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(0, numColumns - 3, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(0, numColumns - 2, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(0, numColumns - 1, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(1, numColumns - 3, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(1, numColumns - 2, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(1, numColumns - 1, numRows, numColumns) { + currentByte |= 1; + } + return currentByte; + } + + /** + *

Reads the 8 bits of the special corner condition 4.

+ * + *

See ISO 16022:2006, Figure F.6

+ * + * @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 + */ + fn readCorner4(&self, numRows: usize, numColumns: usize) -> u32 { + let mut currentByte = 0; + if self.readModule(numRows - 3, 0, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(numRows - 2, 0, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(numRows - 1, 0, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(0, numColumns - 2, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(0, numColumns - 1, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(1, numColumns - 1, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(2, numColumns - 1, numRows, numColumns) { + currentByte |= 1; + } + currentByte <<= 1; + if self.readModule(3, numColumns - 1, numRows, numColumns) { + currentByte |= 1; + } + return currentByte; + } + + /** + *

Extracts the data region from a {@link BitMatrix} that contains + * alignment patterns.

+ * + * @param bitMatrix Original {@link BitMatrix} with alignment patterns + * @return BitMatrix that has the alignment patterns removed + */ + fn extractDataRegion( + bitMatrix: &BitMatrix, + version: VersionRef, + ) -> Result { + let symbolSizeRows = version.getSymbolSizeRows(); + let symbolSizeColumns = version.getSymbolSizeColumns(); + + if bitMatrix.getHeight() != symbolSizeRows { + return Err(Exceptions::IllegalArgumentException( + "Dimension of bitMatrix must match the version size".to_owned(), + )); + } + + let dataRegionSizeRows = version.getDataRegionSizeRows(); + let dataRegionSizeColumns = version.getDataRegionSizeColumns(); + + let numDataRegionsRow = symbolSizeRows / dataRegionSizeRows; + let numDataRegionsColumn = symbolSizeColumns / dataRegionSizeColumns; + + let sizeDataRegionRow = numDataRegionsRow * dataRegionSizeRows; + let sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns; + + let bitMatrixWithoutAlignment = BitMatrix::new(sizeDataRegionColumn, sizeDataRegionRow)?; + for dataRegionRow in 0..numDataRegionsRow { + // for (int dataRegionRow = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow) { + let dataRegionRowOffset = dataRegionRow * dataRegionSizeRows; + for dataRegionColumn in 0..numDataRegionsColumn { + // for (int dataRegionColumn = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn) { + let dataRegionColumnOffset = dataRegionColumn * dataRegionSizeColumns; + for i in 0..dataRegionSizeRows { + // for (int i = 0; i < dataRegionSizeRows; ++i) { + let readRowOffset = dataRegionRow * (dataRegionSizeRows + 2) + 1 + i; + let writeRowOffset = dataRegionRowOffset + i; + for j in 0..dataRegionSizeColumns { + // for (int j = 0; j < dataRegionSizeColumns; ++j) { + let readColumnOffset = + dataRegionColumn * (dataRegionSizeColumns + 2) + 1 + j; + if bitMatrix.get(readColumnOffset, readRowOffset) { + let writeColumnOffset = dataRegionColumnOffset + j; + bitMatrixWithoutAlignment.set(writeColumnOffset, writeRowOffset); + } + } + } + } + } + Ok(bitMatrixWithoutAlignment) + } +} diff --git a/src/datamatrix/decoder/DecodedBitStreamParser.java b/src/datamatrix/decoder/decoded_bit_stream_parser.rs similarity index 57% rename from src/datamatrix/decoder/DecodedBitStreamParser.java rename to src/datamatrix/decoder/decoded_bit_stream_parser.rs index 37fb692..0e67ac6 100644 --- a/src/datamatrix/decoder/DecodedBitStreamParser.java +++ b/src/datamatrix/decoder/decoded_bit_stream_parser.rs @@ -14,19 +14,10 @@ * limitations under the License. */ -package com.google.zxing.datamatrix.decoder; +use encoding::Encoding; -import com.google.zxing.FormatException; -import com.google.zxing.common.BitSource; -import com.google.zxing.common.DecoderRXingResult; -import com.google.zxing.common.ECIStringBuilder; +use crate::{Exceptions, common::{BitSource, ECIStringBuilder, DecoderRXingResult}}; -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; /** *

Data Matrix Codes can encode text as bits in one of several modes, and can use multiple modes @@ -37,9 +28,9 @@ import java.util.Set; * @author bbrown@google.com (Brian Brown) * @author Sean Owen */ -final class DecodedBitStreamParser { - private enum Mode { + #[derive(Debug,PartialEq, Eq,Clone, Copy)] + enum Mode { PAD_ENCODE, // Not really a mode ASCII_ENCODE, C40_ENCODE, @@ -54,78 +45,71 @@ final class DecodedBitStreamParser { * 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 = { + const C40_BASIC_SET_CHARS : [char;40]= [ '*', '*', '*', ' ', '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 = { + const C40_SHIFT2_SET_CHARS :[char;27] = [ '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_' - }; + ]; /** * 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', + const TEXT_BASIC_SET_CHARS : [char;40]= + ['*', '*', '*', ' ', '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; + const TEXT_SHIFT2_SET_CHARS : [char;27]= C40_SHIFT2_SET_CHARS; - private static final char[] TEXT_SHIFT3_SET_CHARS = { + const TEXT_SHIFT3_SET_CHARS : [char;32]= [ '`', '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 - }; + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', 127 as char + ]; - private DecodedBitStreamParser() { - } - - static DecoderRXingResult decode(byte[] bytes) throws FormatException { - BitSource bits = new BitSource(bytes); - ECIStringBuilder result = new ECIStringBuilder(100); - StringBuilder resultTrailer = new StringBuilder(0); - List byteSegments = new ArrayList<>(1); - Mode mode = Mode.ASCII_ENCODE; + pub fn decode( bytes: &[u8]) -> Result { + let bits = BitSource::new(bytes); + let result = ECIStringBuilder::with_capacity(100); + let resultTrailer = String::new(); + let byteSegments = Vec::new();//new ArrayList<>(1); + let mode = Mode::ASCII_ENCODE; // Could look directly at 'bytes', if we're sure of not having to account for multi byte values - Set fnc1Positions = new HashSet<>(); - int symbologyModifier; - boolean isECIencoded = false; - do { - if (mode == Mode.ASCII_ENCODE) { + let fnc1Positions = Vec::new(); + let symbologyModifier; + let isECIencoded = false; + loop { + 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: + match mode { + Mode::C40_ENCODE=> + decodeC40Segment(bits, result, fnc1Positions), + Mode::TEXT_ENCODE=> + decodeTextSegment(bits, result, fnc1Positions), + Mode::ANSIX12_ENCODE=> + decodeAnsiX12Segment(bits, result), + Mode::EDIFACT_ENCODE=> + decodeEdifactSegment(bits, result), + Mode::BASE256_ENCODE=> + decodeBase256Segment(bits, result, byteSegments), + Mode::ECI_ENCODE=>{ decodeECISegment(bits, result); isECIencoded = true; // ECI detection only, atm continue decoding as ASCII - break; - default: - throw FormatException.getFormatInstance(); + }, + _=> + return Err(Exceptions::FormatException("".to_owned())), } - mode = Mode.ASCII_ENCODE; + mode = Mode::ASCII_ENCODE; } - } while (mode != Mode.PAD_ENCODE && bits.available() > 0); + if ! (mode != Mode::PAD_ENCODE && bits.available() > 0) { break } + } //while (mode != Mode.PAD_ENCODE && bits.available() > 0); if (resultTrailer.length() > 0) { result.appendCharacters(resultTrailer); } @@ -159,10 +143,10 @@ final class DecodedBitStreamParser { /** * See ISO 16022:2006, 5.2.3 and Annex C, Table C.2 */ - private static Mode decodeAsciiSegment(BitSource bits, - ECIStringBuilder result, - StringBuilder resultTrailer, - Set fnc1positions) throws FormatException { + fn decodeAsciiSegment( bits:&BitSource, + result:&ECIStringBuilder, + resultTrailer:&String, + fnc1positions:&[usize]) -> Result { boolean upperShift = false; do { int oneByte = bits.readBits(8); @@ -233,8 +217,8 @@ final class DecodedBitStreamParser { /** * See ISO 16022:2006, 5.2.5 and Annex C, Table C.1 */ - private static void decodeC40Segment(BitSource bits, ECIStringBuilder result, Set fnc1positions) - throws FormatException { + fn decodeC40Segment( bits:&BitSource, result:&ECIStringBuilder, fnc1positions:&[usize]) + -> Result<(),Exceptions> { // 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 @@ -325,153 +309,158 @@ final class DecodedBitStreamParser { /** * See ISO 16022:2006, 5.2.6 and Annex C, Table C.2 */ - private static void decodeTextSegment(BitSource bits, ECIStringBuilder result, Set fnc1positions) - throws FormatException { + fn decodeTextSegment( bits:&BitSource, result:&ECIStringBuilder, fnc1positions:&[usize]) + -> Result<(),Exceptions> { // 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; + let upperShift = false; - int[] cValues = new int[3]; - int shift = 0; - do { + let cValues = [0;3];//new int[3]; + let shift = 0; + loop { // If there is only one byte left then it will be encoded as ASCII - if (bits.available() == 8) { - return; + if bits.available() == 8 { + return Ok(()) } - int firstByte = bits.readBits(8); - if (firstByte == 254) { // Unlatch codeword - return; + let firstByte = bits.readBits(8)?; + if firstByte == 254 { // Unlatch codeword + return Ok(()) } - parseTwoBytes(firstByte, bits.readBits(8), cValues); + parseTwoBytes(firstByte, bits.readBits(8)?, &cValues); - for (int i = 0; i < 3; i++) { - int cValue = cValues[i]; - switch (shift) { - case 0: - if (cValue < 3) { + for cValue in cValues { + // for (int i = 0; i < 3; i++) { + // int cValue = cValues[i]; + match shift { + 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)); + } else if cValue < TEXT_BASIC_SET_CHARS.len() { + let 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)); + return Err(Exceptions::FormatException("".to_owned())); + }, + 1=> + {if upperShift { + result.append_char( (cValue + 128)); upperShift = false; } else { - result.append((char) cValue); + 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)); + shift = 0;}, + + 2=> + {// Shift 2 for Text is the same encoding as C40 + if cValue < TEXT_SHIFT2_SET_CHARS.len() { + let textChar = TEXT_SHIFT2_SET_CHARS[cValue]; + if upperShift { + result.append_char( (textChar + 128)); upperShift = false; } else { - result.append(textChar); + result.append_char(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(); + match cValue { + 27=>{ // FNC1 + fnc1positions.push(result.length()); + result.append_char( 29); // translate as ASCII 29 + }, + 30=> // Upper Shift + upperShift = true, + + _=> + return Err(Exceptions::FormatException("".to_owned())), } } - 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)); + shift = 0;}, + 3=> + if cValue < TEXT_SHIFT3_SET_CHARS.len() { + let textChar = TEXT_SHIFT3_SET_CHARS[cValue]; + if upperShift { + result.append_char( (textChar + 128)); upperShift = false; } else { - result.append(textChar); + result.append_char(textChar); } shift = 0; } else { - throw FormatException.getFormatInstance(); - } - break; - default: - throw FormatException.getFormatInstance(); + return Err(Exceptions::FormatException("".to_owned())); + }, + + _=> + return Err(Exceptions::FormatException("".to_owned())), } } - } while (bits.available() > 0); + if !(bits.available() > 0){break} + } //while (bits.available() > 0); + + Ok(()) } /** * See ISO 16022:2006, 5.2.7 */ - private static void decodeAnsiX12Segment(BitSource bits, - ECIStringBuilder result) throws FormatException { + fn decodeAnsiX12Segment( bits:&BitSource, + result:&ECIStringBuilder) -> Result<(),Exceptions> { // Three ANSI X12 values are encoded in a 16-bit value as // (1600 * C1) + (40 * C2) + C3 + 1 - int[] cValues = new int[3]; - do { + let cValues = [0;3];//new int[3]; + loop { // If there is only one byte left then it will be encoded as ASCII - if (bits.available() == 8) { - return; + if bits.available() == 8 { + return Ok(()) } - int firstByte = bits.readBits(8); - if (firstByte == 254) { // Unlatch codeword - return; + let firstByte = bits.readBits(8)?; + if firstByte == 254 { // Unlatch codeword + return Ok(()) } - parseTwoBytes(firstByte, bits.readBits(8), cValues); + parseTwoBytes(firstByte, bits.readBits(8)?, &cValues); - for (int i = 0; i < 3; i++) { - int cValue = cValues[i]; - switch (cValue) { - case 0: // X12 segment terminator - 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)); + for cValue in cValues { + // for (int i = 0; i < 3; i++) { + // int cValue = cValues[i]; + match cValue { + 0=> // X12 segment terminator + result.append_char('\r'), + + 1=> // X12 segment separator * + result.append_char('*'), + + 2=> // X12 sub-element separator > + result.append_char('>'), + + 3=> // space + result.append_char(' '), + + _=> + if cValue < 14 { // 0 - 9 + result.append_char( char::from_u32(cValue + 44).unwrap()); + } else if cValue < 40 { // A - Z + result.append_char( char::from_u32(cValue + 51).unwrap()); } else { - throw FormatException.getFormatInstance(); - } - break; + return Err(Exceptions::FormatException("".to_owned())) + }, } } - } while (bits.available() > 0); + if ! (bits.available() > 0) { break } + } //while (bits.available() > 0); + + Ok(()) } - private static void parseTwoBytes(int firstByte, int secondByte, int[] result) { - int fullBitValue = (firstByte << 8) + secondByte - 1; - int temp = fullBitValue / 1600; + fn parseTwoBytes( firstByte:u32, secondByte:u32, result:&[u32]) { + let fullBitValue = (firstByte << 8) + secondByte - 1; + let temp = fullBitValue / 1600; result[0] = temp; fullBitValue -= temp * 1600; temp = fullBitValue / 40; @@ -482,84 +471,97 @@ final class DecodedBitStreamParser { /** * See ISO 16022:2006, 5.2.8 and Annex C Table C.3 */ - private static void decodeEdifactSegment(BitSource bits, ECIStringBuilder result) { - do { + fn decodeEdifactSegment( bits:&BitSource, result:&ECIStringBuilder) -> Result<(),Exceptions>{ + loop { // If there is only two or less bytes left then it will be encoded as ASCII - if (bits.available() <= 16) { - return; + if bits.available() <= 16 { + return Ok(()); } - for (int i = 0; i < 4; i++) { - int edifactValue = bits.readBits(6); + for i in 0..4 { + // for (int i = 0; i < 4; i++) { + let edifactValue = bits.readBits(6)?; // Check for the unlatch character - if (edifactValue == 0x1F) { // 011111 + if edifactValue == 0x1F { // 011111 // Read rest of byte, which should be 0, and stop - int bitsLeft = 8 - bits.getBitOffset(); - if (bitsLeft != 8) { + let bitsLeft = 8 - bits.getBitOffset(); + if bitsLeft != 8 { bits.readBits(bitsLeft); } - return; + return Ok(()); } - if ((edifactValue & 0x20) == 0) { // no 1 in the leading (6th) bit + 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); + result.append_char( char::from_u32(edifactValue).unwrap()); } - } while (bits.available() > 0); + + if ! (bits.available() > 0) { break } + } + + Ok(()) } /** * See ISO 16022:2006, 5.2.9 and Annex B, B.2 */ - private static void decodeBase256Segment(BitSource bits, - ECIStringBuilder result, - Collection byteSegments) - throws FormatException { + fn decodeBase256Segment( bits:&BitSource, + result:&ECIStringBuilder, + byteSegments:&Vec>) + -> Result<(),Exceptions> { // 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) { + let codewordPosition = 1 + bits.getByteOffset(); // position is 1-indexed + let d1 = unrandomize255State(bits.readBits(8)?, codewordPosition); + codewordPosition +=1; + let count; + if d1 == 0 { // Read the remainder of the symbol + count = bits.available() as u32 / 8; + } else if d1 < 250 { count = d1; } else { - count = 250 * (d1 - 249) + unrandomize255State(bits.readBits(8), codewordPosition++); + count = 250 * (d1 - 249) + unrandomize255State(bits.readBits(8)?, codewordPosition); + codewordPosition +=1; } // We're seeing NegativeArraySizeException errors from users. if (count < 0) { - throw FormatException.getFormatInstance(); + return Err(Exceptions::FormatException("".to_owned())) } - byte[] bytes = new byte[count]; - for (int i = 0; i < count; i++) { + let bytes = vec![0u8;count as usize]; + for i in 0..count as usize { + // 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(); + if bits.available() < 8 { + return Err(Exceptions::FormatException("".to_owned())) } - bytes[i] = (byte) unrandomize255State(bits.readBits(8), codewordPosition++); + bytes[i] = unrandomize255State(bits.readBits(8)?, codewordPosition) as u8; + codewordPosition+=1; } - byteSegments.add(bytes); - result.append(new String(bytes, StandardCharsets.ISO_8859_1)); + byteSegments.push(bytes); + result.append_string(&encoding::all::ISO_8859_1.decode(&bytes, encoding::DecoderTrap::Strict).expect("decode")); + + Ok(()) } /** * See ISO 16022:2007, 5.4.1 */ - private static void decodeECISegment(BitSource bits, - ECIStringBuilder result) - throws FormatException { - if (bits.available() < 8) { - throw FormatException.getFormatInstance(); + fn decodeECISegment( bits:&BitSource, + result:&ECIStringBuilder) + -> Result<(),Exceptions> { + if bits.available() < 8 { + return Err(Exceptions::FormatException("".to_owned())) } - int c1 = bits.readBits(8); - if (c1 <= 127) { - result.appendECI(c1 - 1); + let c1 = bits.readBits(8)?; + if c1 <= 127 { + result.appendECI(c1 - 1)?; } + + Ok(()) //currently we only support character set ECIs /*} else { if (bits.available() < 8) { @@ -580,11 +582,11 @@ final class DecodedBitStreamParser { /** * 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; + fn unrandomize255State( randomizedBase256Codeword:u32, + base256CodewordPosition:usize) -> u32{ + let pseudoRandomNumber = ((149 * base256CodewordPosition as u32) % 255) + 1; + let tempVariable = randomizedBase256Codeword - pseudoRandomNumber; + + if tempVariable >= 0 {tempVariable} else {tempVariable + 256} } -} diff --git a/src/datamatrix/decoder/Decoder.java b/src/datamatrix/decoder/decoder.rs similarity index 53% rename from src/datamatrix/decoder/Decoder.java rename to src/datamatrix/decoder/decoder.rs index 0a62d28..bb3be0e 100644 --- a/src/datamatrix/decoder/Decoder.java +++ b/src/datamatrix/decoder/decoder.rs @@ -14,15 +14,10 @@ * limitations under the License. */ -package com.google.zxing.datamatrix.decoder; +use crate::{common::{reedsolomon::{ReedSolomonDecoder, get_predefined_genericgf, PredefinedGenericGF}, DecoderRXingResult, BitMatrix}, Exceptions}; + +use super::{DataBlock, BitMatrixParser, decoded_bit_stream_parser}; -import com.google.zxing.ChecksumException; -import com.google.zxing.FormatException; -import com.google.zxing.common.BitMatrix; -import com.google.zxing.common.DecoderRXingResult; -import com.google.zxing.common.reedsolomon.GenericGF; -import com.google.zxing.common.reedsolomon.ReedSolomonDecoder; -import com.google.zxing.common.reedsolomon.ReedSolomonException; /** *

The main class which implements Data Matrix Code decoding -- as opposed to locating and extracting @@ -30,12 +25,14 @@ import com.google.zxing.common.reedsolomon.ReedSolomonException; * * @author bbrown@google.com (Brian Brown) */ -public final class Decoder { +pub struct Decoder(ReedSolomonDecoder); - private final ReedSolomonDecoder rsDecoder; +impl Decoder { - public Decoder() { - rsDecoder = new ReedSolomonDecoder(GenericGF.DATA_MATRIX_FIELD_256); + pub fn new() -> Self { + + Self(ReedSolomonDecoder::new(get_predefined_genericgf(PredefinedGenericGF::DataMatrixField256))) + // rsDecoder = new ReedSolomonDecoder(GenericGF.DATA_MATRIX_FIELD_256); } /** @@ -47,8 +44,8 @@ public final class Decoder { * @throws FormatException if the Data Matrix Code cannot be decoded * @throws ChecksumException if error correction fails */ - public DecoderRXingResult decode(boolean[][] image) throws FormatException, ChecksumException { - return decode(BitMatrix.parse(image)); + pub fn decode_bools(&self, image:&Vec>) -> Result { + self.decode(&BitMatrix::parse_bools(&image)) } /** @@ -60,39 +57,42 @@ public final class Decoder { * @throws FormatException if the Data Matrix Code cannot be decoded * @throws ChecksumException if error correction fails */ - public DecoderRXingResult decode(BitMatrix bits) throws FormatException, ChecksumException { + pub fn decode(&self, bits:&BitMatrix) -> Result { // Construct a parser and read version, error-correction level - BitMatrixParser parser = new BitMatrixParser(bits); - Version version = parser.getVersion(); + let parser = BitMatrixParser::new(bits)?; + let version = parser.getVersion(); + // Read codewords - byte[] codewords = parser.readCodewords(); + let codewords = parser.readCodewords()?; // Separate into data blocks - DataBlock[] dataBlocks = DataBlock.getDataBlocks(codewords, version); + let dataBlocks = DataBlock::getDataBlocks(&codewords, version)?; // Count total number of data bytes - int totalBytes = 0; - for (DataBlock db : dataBlocks) { + let totalBytes = 0; + for db in dataBlocks { totalBytes += db.getNumDataCodewords(); } - byte[] resultBytes = new byte[totalBytes]; + let resultBytes = vec![0u8;totalBytes as usize]; - int dataBlocksCount = dataBlocks.length; + let dataBlocksCount = dataBlocks.len(); // 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++) { + for j in 0..dataBlocksCount { + // for (int j = 0; j < dataBlocksCount; j++) { + let dataBlock = dataBlocks[j]; + let codewordBytes = dataBlock.getCodewords(); + let numDataCodewords = dataBlock.getNumDataCodewords() as usize; + self.correctErrors(codewordBytes, numDataCodewords as u32); + for i in 0..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); + decoded_bit_stream_parser::decode(&resultBytes) } /** @@ -103,23 +103,29 @@ public final class Decoder { * @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; + fn correctErrors(&self, codewordBytes:&[u8], numDataCodewords:u32) -> Result<(),Exceptions> { + let numCodewords = codewordBytes.len(); // 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(); - } + // let codewordsInts = vec![0i32;numCodewords]; + // for i in 0..numCodewords { + // // for (int i = 0; i < numCodewords; i++) { + // codewordsInts[i] = codewordBytes[i]; + // } + let codewordsInts : Vec = codewordBytes.iter().map(|x| *x as i32).collect(); + + //try { + self.0.decode(&mut codewordsInts, codewordBytes.len() as i32- numDataCodewords as i32)?; + //} 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]; + for i in 0..numDataCodewords as usize { + // for (int i = 0; i < numDataCodewords; i++) { + codewordBytes[i] = codewordsInts[i] as u8; } + // codewordsInts.into_iter().take(numDataCodewords as usize).map(|x| x as u8).collect::>() + Ok(()) } } diff --git a/src/datamatrix/decoder/mod.rs b/src/datamatrix/decoder/mod.rs index d4c68f7..4cb3261 100644 --- a/src/datamatrix/decoder/mod.rs +++ b/src/datamatrix/decoder/mod.rs @@ -1,6 +1,12 @@ mod version; mod data_block; +mod decoder; +mod bit_matrix_parser; pub use version::*; -pub use data_block::*; \ No newline at end of file +pub use data_block::*; +pub use decoder::*; +pub use bit_matrix_parser::*; + +pub mod decoded_bit_stream_parser; \ No newline at end of file diff --git a/src/datamatrix/decoder/version.rs b/src/datamatrix/decoder/version.rs index 4014bfe..7940f8a 100644 --- a/src/datamatrix/decoder/version.rs +++ b/src/datamatrix/decoder/version.rs @@ -23,6 +23,8 @@ lazy_static! { static ref VERSIONS: Vec = Version::buildVersions(); } +pub type VersionRef = &'static Version; + /** * The Version object encapsulates attributes about a particular * size Data Matrix Code.