diff --git a/java_test/java/com/google/zxing/aztec/decoder/DecoderTest.java b/java_test/java/com/google/zxing/aztec/decoder/DecoderTest.java
deleted file mode 100644
index dc4681f..0000000
--- a/java_test/java/com/google/zxing/aztec/decoder/DecoderTest.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright 2014 ZXing authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.google.zxing.aztec.decoder;
-
-import com.google.zxing.aztec.encoder.EncoderTest;
-
-import com.google.zxing.FormatException;
-import com.google.zxing.RXingResultPoint;
-import com.google.zxing.aztec.AztecDetectorRXingResult;
-import com.google.zxing.common.BitArray;
-import com.google.zxing.common.BitMatrix;
-import com.google.zxing.common.DecoderRXingResult;
-import org.junit.Test;
-import org.junit.Assert;
-
-/**
- * Tests {@link Decoder}.
- */
-public final class DecoderTest extends Assert {
-
- private static final RXingResultPoint[] NO_POINTS = new RXingResultPoint[0];
-
- @Test
- public void testHighLevelDecode() throws FormatException {
- // no ECI codes
- testHighLevelDecodeString("A. b.",
- // 'A' P/S '. ' L/L b D/L '.'
- "...X. ..... ...XX XXX.. ...XX XXXX. XX.X");
-
- // initial ECI code 26 (switch to UTF-8)
- testHighLevelDecodeString("Ça",
- // P/S FLG(n) 2 '2' '6' B/S 2 0xc3 0x87 L/L 'a'
- "..... ..... .X. .X.. X... XXXXX ...X. XX....XX X....XXX XXX.. ...X.");
-
- // initial character without ECI (must be interpreted as ISO_8859_1)
- // followed by ECI code 26 (= UTF-8) and UTF-8 text
- testHighLevelDecodeString("±Ça",
- // B/S 1 0xb1 P/S FLG(n) 2 '2' '6' B/S 2 0xc3 0x87 L/L 'a'
- "XXXXX ....X X.XX...X ..... ..... .X. .X.. X... XXXXX ...X. XX....XX X....XXX XXX.. ...X.");
-
- // GS1 data
- testHighLevelDecodeString("101233742",
- // P/S FLG(n) 0 D/L 1 0 1 2 3 P/S FLG(n) 0 3 7 4 2
- "..... ..... ... XXXX. ..XX ..X. ..XX .X.. .X.X .... ..... ... .X.X X..X .XX. .X..");
- }
-
- private static void testHighLevelDecodeString(String expectedString, String b) throws FormatException {
- BitArray bits = EncoderTest.toBitArray(EncoderTest.stripSpace(b));
- assertEquals("highLevelDecode() failed for input bits: " + b,
- expectedString, Decoder.highLevelDecode(EncoderTest.toBooleanArray(bits)));
- }
-
- @Test
- public void testAztecRXingResult() throws FormatException {
- BitMatrix matrix = BitMatrix.parse(
- "X X X X X X X X X X X X X X \n" +
- "X X X X X X X X X X X X X X X \n" +
- " X X X X X X X X X X X X \n" +
- " X X X X X X X X X X \n" +
- " X X X X X X X X \n" +
- " X X X X X X X X X X X X X X X X X X \n" +
- " X X X X X X X X X \n" +
- " X X X X X X X X X X X X X X X X X \n" +
- " X X X X X X X X X \n" +
- " X X X X X X X X X X X X X X X X \n" +
- " X X X X X X X X X X X X \n" +
- " X X X X X X X X X X X \n" +
- " X X X X X X X X X X X X \n" +
- " X X X X X X X X X X X X X X X X X \n" +
- "X X X X X X X X X X X \n" +
- " X X X X X X X X X X X X X X \n" +
- " X X X X X X X X \n" +
- " X X X X X X X X X X X X X X X X X X X \n" +
- "X X X X X X X X X \n" +
- "X X X X X X X X X X X X X X X \n" +
- "X X X X X X X X X X X X \n" +
- "X X X X X X X X X X X X X X \n" +
- " X X X X X X X X X X X X X \n",
- "X ", " ");
- AztecDetectorRXingResult r = new AztecDetectorRXingResult(matrix, NO_POINTS, false, 30, 2);
- DecoderRXingResult result = new Decoder().decode(r);
- assertEquals("88888TTTTTTTTTTTTTTTTTTTTTTTTTTTTTT", result.getText());
- assertArrayEquals(
- new byte[] {-11, 85, 85, 117, 107, 90, -42, -75, -83, 107,
- 90, -42, -75, -83, 107, 90, -42, -75, -83, 107,
- 90, -42, -80},
- result.getRawBytes());
- assertEquals(180, result.getNumBits());
- }
-
- @Test
- public void testAztecRXingResultECI() throws FormatException {
- BitMatrix matrix = BitMatrix.parse(
- " X X X X X X \n" +
- " X X X X X X X X X X X X \n" +
- " X X X X \n" +
- " X X X X X X X X X X X X X X X X X \n" +
- " X X \n" +
- " X X X X X X X X X X X X \n" +
- " X X X X X X X X \n" +
- " X X X X X X X X X X X X \n" +
- " X X X X X X X X \n" +
- " X X X X X X X X X \n" +
- "X X X X X X X X X \n" +
- " X X X X X X X X X X X X \n" +
- " X X X X X X \n" +
- " X X X X X X X X X X X X X \n" +
- " X X X \n" +
- "X X X X X X X X X X X X X X X X X \n" +
- "X X X X X X X X X \n" +
- " X X X X X X X X X X X \n" +
- "X X X X X X X X \n",
- "X ", " ");
- AztecDetectorRXingResult r = new AztecDetectorRXingResult(matrix, NO_POINTS, false, 15, 1);
- DecoderRXingResult result = new Decoder().decode(r);
- assertEquals("Français", result.getText());
- }
-
- @Test(expected = FormatException.class)
- public void testDecodeTooManyErrors() throws FormatException {
- BitMatrix matrix = BitMatrix.parse(""
- + "X X . X . . . X X . . . X . . X X X . X . X X X X X . \n"
- + "X X . . X X . . . . . X X . . . X X . . . X . X . . X \n"
- + "X . . . X X . . X X X . X X . X X X X . X X . . X . . \n"
- + ". . . . X . X X . . X X . X X . X . X X X X . X . . X \n"
- + "X X X . . X X X X X . . . . . X X . . . X . X . X . X \n"
- + "X X . . . . . . . . X . . . X . X X X . X . . X . . . \n"
- + "X X . . X . . . . . X X . . . . . X . . . . X . . X X \n"
- + ". . . X . X . X . . . . . X X X X X X . . . . . . X X \n"
- + "X . . . X . X X X X X X . . X X X . X . X X X X X X . \n"
- + "X . . X X X . X X X X X X X X X X X X X . . . X . X X \n"
- + ". . . . X X . . . X . . . . . . . X X . . . X X . X . \n"
- + ". . . X X X . . X X . X X X X X . X . . X . . . . . . \n"
- + "X . . . . X . X . X . X . . . X . X . X X . X X . X X \n"
- + "X . X . . X . X . X . X . X . X . X . . . . . X . X X \n"
- + "X . X X X . . X . X . X . . . X . X . X X X . . . X X \n"
- + "X X X X X X X X . X . X X X X X . X . X . X . X X X . \n"
- + ". . . . . . . X . X . . . . . . . X X X X . . . X X X \n"
- + "X X . . X . . X . X X X X X X X X X X X X X . . X . X \n"
- + "X X X . X X X X . . X X X X . . X . . . . X . . X X X \n"
- + ". . . . X . X X X . . . . X X X X . . X X X X . . . . \n"
- + ". . X . . X . X . . . X . X X . X X . X . . . X . X . \n"
- + "X X . . X . . X X X X X X X . . X . X X X X X X X . . \n"
- + "X . X X . . X X . . . . . X . . . . . . X X . X X X . \n"
- + "X . . X X . . X X . X . X . . . . X . X . . X . . X . \n"
- + "X . X . X . . X . X X X X X X X X . X X X X . . X X . \n"
- + "X X X X . . . X . . X X X . X X . . X . . . . X X X . \n"
- + "X X . X . X . . . X . X . . . . X X . X . . X X . . . \n",
- "X ", ". ");
- AztecDetectorRXingResult r = new AztecDetectorRXingResult(matrix, NO_POINTS, true, 16, 4);
- new Decoder().decode(r);
- }
-
- @Test(expected = FormatException.class)
- public void testDecodeTooManyErrors2() throws FormatException {
- BitMatrix matrix = BitMatrix.parse(""
- + ". X X . . X . X X . . . X . . X X X . . . X X . X X . \n"
- + "X X . X X . . X . . . X X . . . X X . X X X . X . X X \n"
- + ". . . . X . . . X X X . X X . X X X X . X X . . X . . \n"
- + "X . X X . . X . . . X X . X X . X . X X . . . . . X . \n"
- + "X X . X . . X . X X . . . . . X X . . . . . X . . . X \n"
- + "X . . X . . . . . . X . . . X . X X X X X X X . . . X \n"
- + "X . . X X . . X . . X X . . . . . X . . . . . X X X . \n"
- + ". . X X X X . X . . . . . X X X X X X . . . . . . X X \n"
- + "X . . . X . X X X X X X . . X X X . X . X X X X X X . \n"
- + "X . . X X X . X X X X X X X X X X X X X . . . X . X X \n"
- + ". . . . X X . . . X . . . . . . . X X . . . X X . X . \n"
- + ". . . X X X . . X X . X X X X X . X . . X . . . . . . \n"
- + "X . . . . X . X . X . X . . . X . X . X X . X X . X X \n"
- + "X . X . . X . X . X . X . X . X . X . . . . . X . X X \n"
- + "X . X X X . . X . X . X . . . X . X . X X X . . . X X \n"
- + "X X X X X X X X . X . X X X X X . X . X . X . X X X . \n"
- + ". . . . . . . X . X . . . . . . . X X X X . . . X X X \n"
- + "X X . . X . . X . X X X X X X X X X X X X X . . X . X \n"
- + "X X X . X X X X . . X X X X . . X . . . . X . . X X X \n"
- + ". . X X X X X . X . . . . X X X X . . X X X . X . X . \n"
- + ". . X X . X . X . . . X . X X . X X . . . . X X . . . \n"
- + "X . . . X . X . X X X X X X . . X . X X X X X . X . . \n"
- + ". X . . . X X X . . . . . X . . . . . X X X X X . X . \n"
- + "X . . X . X X X X . X . X . . . . X . X X . X . . X . \n"
- + "X . . . X X . X . X X X X X X X X . X X X X . . X X . \n"
- + ". X X X X . . X . . X X X . X X . . X . . . . X X X . \n"
- + "X X . . . X X . . X . X . . . . X X . X . . X . X . X \n",
- "X ", ". ");
- AztecDetectorRXingResult r = new AztecDetectorRXingResult(matrix, NO_POINTS, true, 16, 4);
- new Decoder().decode(r);
- }
-
- @Test
- public void testRawBytes() {
- boolean[] bool0 = {};
- boolean[] bool1 = { true };
- boolean[] bool7 = { true, false, true, false, true, false, true };
- boolean[] bool8 = { true, false, true, false, true, false, true, false };
- boolean[] bool9 = { true, false, true, false, true, false, true, false,
- true };
- boolean[] bool16 = { false, true, true, false, false, false, true, true,
- true, true, false, false, false, false, false, true };
- byte[] byte0 = {};
- byte[] byte1 = { -128 };
- byte[] byte7 = { -86 };
- byte[] byte8 = { -86 };
- byte[] byte9 = { -86, -128 };
- byte[] byte16 = { 99, -63 };
-
- assertArrayEquals(byte0, Decoder.convertBoolArrayToByteArray(bool0));
- assertArrayEquals(byte1, Decoder.convertBoolArrayToByteArray(bool1));
- assertArrayEquals(byte7, Decoder.convertBoolArrayToByteArray(bool7));
- assertArrayEquals(byte8, Decoder.convertBoolArrayToByteArray(bool8));
- assertArrayEquals(byte9, Decoder.convertBoolArrayToByteArray(bool9));
- assertArrayEquals(byte16, Decoder.convertBoolArrayToByteArray(bool16));
- }
-}
diff --git a/src/aztec/AztecDetectorResult.java b/src/aztec/AztecDetectorResult.java
deleted file mode 100644
index c1c427d..0000000
--- a/src/aztec/AztecDetectorResult.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2010 ZXing authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.zxing.aztec;
-
-import com.google.zxing.RXingResultPoint;
-import com.google.zxing.common.BitMatrix;
-import com.google.zxing.common.DetectorRXingResult;
-
-/**
- *
Extends {@link DetectorRXingResult} with more information specific to the Aztec format,
- * like the number of layers and whether it's compact.
- *
- * @author Sean Owen
- */
-public final class AztecDetectorRXingResult extends DetectorRXingResult {
-
- private final boolean compact;
- private final int nbDatablocks;
- private final int nbLayers;
-
- public AztecDetectorRXingResult(BitMatrix bits,
- RXingResultPoint[] points,
- boolean compact,
- int nbDatablocks,
- int nbLayers) {
- super(bits, points);
- this.compact = compact;
- this.nbDatablocks = nbDatablocks;
- this.nbLayers = nbLayers;
- }
-
- public int getNbLayers() {
- return nbLayers;
- }
-
- public int getNbDatablocks() {
- return nbDatablocks;
- }
-
- public boolean isCompact() {
- return compact;
- }
-
-}
diff --git a/src/aztec/AztecDetectorResult.rs b/src/aztec/AztecDetectorResult.rs
new file mode 100644
index 0000000..3aff5f7
--- /dev/null
+++ b/src/aztec/AztecDetectorResult.rs
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2010 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// package com.google.zxing.aztec;
+
+// import com.google.zxing.RXingResultPoint;
+// import com.google.zxing.common.BitMatrix;
+// import com.google.zxing.common.DetectorRXingResult;
+
+use crate::{
+ common::{BitMatrix, DetectorRXingResult},
+ RXingResultPoint,
+};
+
+/**
+ * Extends {@link DetectorRXingResult} with more information specific to the Aztec format,
+ * like the number of layers and whether it's compact.
+ *
+ * @author Sean Owen
+ */
+pub struct AztecDetectorRXingResult {
+ bits: BitMatrix,
+ points: Vec,
+ compact: bool,
+ nbDatablocks: u32,
+ nbLayers: u32,
+}
+
+impl DetectorRXingResult for AztecDetectorRXingResult {
+ fn getBits(&self) -> &BitMatrix {
+ &self.bits
+ }
+
+ fn getPoints(&self) -> &Vec {
+ &self.points
+ }
+}
+
+impl AztecDetectorRXingResult {
+ pub fn new(
+ bits: BitMatrix,
+ points: Vec,
+ compact: bool,
+ nbDatablocks: u32,
+ nbLayers: u32,
+ ) -> Self {
+ Self {
+ bits,
+ points,
+ compact,
+ nbDatablocks,
+ nbLayers,
+ }
+ }
+
+ pub fn getNbLayers(&self) -> u32 {
+ self.nbLayers
+ }
+
+ pub fn getNbDatablocks(&self) -> u32 {
+ self.nbDatablocks
+ }
+
+ pub fn isCompact(&self) -> bool {
+ self.compact
+ }
+}
diff --git a/src/aztec/DecoderTest.rs b/src/aztec/DecoderTest.rs
new file mode 100644
index 0000000..1542099
--- /dev/null
+++ b/src/aztec/DecoderTest.rs
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2014 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// package com.google.zxing.aztec.decoder;
+
+// import com.google.zxing.aztec.encoder.EncoderTest;
+
+// import com.google.zxing.FormatException;
+// import com.google.zxing.RXingResultPoint;
+// import com.google.zxing.aztec.AztecDetectorRXingResult;
+// import com.google.zxing.common.BitArray;
+// import com.google.zxing.common.BitMatrix;
+// import com.google.zxing.common.DecoderRXingResult;
+// import org.junit.Test;
+// import org.junit.Assert;
+
+use crate::{
+ aztec::shared_test_methods::{stripSpace, toBitArray, toBooleanArray},
+ common::BitMatrix,
+ RXingResultPoint,
+};
+
+use super::{decoder, AztecDetectorResult::AztecDetectorRXingResult};
+
+/**
+ * Tests {@link Decoder}.
+ */
+
+const NO_POINTS: &[RXingResultPoint] = &[RXingResultPoint { x: 0.0, y: 0.0 }; 0];
+
+#[test]
+fn testHighLevelDecode() {
+ // no ECI codes
+ testHighLevelDecodeString(
+ "A. b.",
+ // 'A' P/S '. ' L/L b D/L '.'
+ "...X. ..... ...XX XXX.. ...XX XXXX. XX.X",
+ );
+
+ // initial ECI code 26 (switch to UTF-8)
+ testHighLevelDecodeString(
+ "Ça",
+ // P/S FLG(n) 2 '2' '6' B/S 2 0xc3 0x87 L/L 'a'
+ "..... ..... .X. .X.. X... XXXXX ...X. XX....XX X....XXX XXX.. ...X.",
+ );
+
+ // initial character without ECI (must be interpreted as ISO_8859_1)
+ // followed by ECI code 26 (= UTF-8) and UTF-8 text
+ testHighLevelDecodeString(
+ "±Ça",
+ // B/S 1 0xb1 P/S FLG(n) 2 '2' '6' B/S 2 0xc3 0x87 L/L 'a'
+ "XXXXX ....X X.XX...X ..... ..... .X. .X.. X... XXXXX ...X. XX....XX X....XXX XXX.. ...X.",
+ );
+
+ // GS1 data
+ testHighLevelDecodeString(
+ "101233742",
+ // P/S FLG(n) 0 D/L 1 0 1 2 3 P/S FLG(n) 0 3 7 4 2
+ "..... ..... ... XXXX. ..XX ..X. ..XX .X.. .X.X .... ..... ... .X.X X..X .XX. .X..",
+ );
+}
+
+fn testHighLevelDecodeString(expectedString: &str, b: &str) {
+ let bits = toBitArray(&stripSpace(b));
+ assert_eq!(
+ expectedString,
+ decoder::highLevelDecode(&toBooleanArray(&bits)).expect("highLevelDecode Failed"),
+ "highLevelDecode() failed for input bits: {}",
+ b
+ );
+}
+
+#[test]
+fn testAztecRXingResult() {
+ let matrix = BitMatrix::parse_strings(
+ r"X X X X X X X X X X X X X X
+X X X X X X X X X X X X X X X
+ X X X X X X X X X X X X
+ X X X X X X X X X X
+ X X X X X X X X
+ X X X X X X X X X X X X X X X X X X
+ X X X X X X X X X
+ X X X X X X X X X X X X X X X X X
+ X X X X X X X X X
+ X X X X X X X X X X X X X X X X
+ X X X X X X X X X X X X
+ X X X X X X X X X X X
+ X X X X X X X X X X X X
+ X X X X X X X X X X X X X X X X X
+X X X X X X X X X X X
+ X X X X X X X X X X X X X X
+ X X X X X X X X
+ X X X X X X X X X X X X X X X X X X X
+X X X X X X X X X
+X X X X X X X X X X X X X X X
+X X X X X X X X X X X X
+X X X X X X X X X X X X X X
+ X X X X X X X X X X X X X
+",
+ "X ",
+ " ",
+ )
+ .expect("Bitmatrix should init");
+ let r = AztecDetectorRXingResult::new(matrix, NO_POINTS.to_vec(), false, 30, 2);
+ let result = decoder::decode(&r).expect("decoder should init");
+ assert_eq!("88888TTTTTTTTTTTTTTTTTTTTTTTTTTTTTT", result.getText());
+ assert_eq!(
+ &vec![
+ -11i8 as u8,
+ 85,
+ 85,
+ 117,
+ 107,
+ 90,
+ -42i8 as u8,
+ -75i8 as u8,
+ -83i8 as u8,
+ 107,
+ 90,
+ -42i8 as u8,
+ -75i8 as u8,
+ -83i8 as u8,
+ 107,
+ 90,
+ -42i8 as u8,
+ -75i8 as u8,
+ -83i8 as u8,
+ 107,
+ 90,
+ -42i8 as u8,
+ -80i8 as u8
+ ],
+ result.getRawBytes()
+ );
+ assert_eq!(180, result.getNumBits());
+}
+
+#[test]
+fn testAztecRXingResultECI() {
+ let matrix = BitMatrix::parse_strings(
+ r" X X X X X X
+ X X X X X X X X X X X X
+ X X X X
+ X X X X X X X X X X X X X X X X X
+ X X
+ X X X X X X X X X X X X
+ X X X X X X X X
+ X X X X X X X X X X X X
+ X X X X X X X X
+ X X X X X X X X X
+X X X X X X X X X
+ X X X X X X X X X X X X
+ X X X X X X
+ X X X X X X X X X X X X X
+ X X X
+X X X X X X X X X X X X X X X X X
+X X X X X X X X X
+ X X X X X X X X X X X
+X X X X X X X X ",
+ "X ",
+ " ",
+ )
+ .expect("string parse success");
+ let r = AztecDetectorRXingResult::new(matrix, NO_POINTS.to_vec(), false, 15, 1);
+ let result = decoder::decode(&r).expect("decode success");
+ assert_eq!("Français", result.getText());
+}
+
+#[test]
+#[should_panic]
+fn testDecodeTooManyErrors() {
+ let matrix = BitMatrix::parse_strings(
+ r"
+ X X . X . . . X X . . . X . . X X X . X . X X X X X .
+ X X . . X X . . . . . X X . . . X X . . . X . X . . X
+ X . . . X X . . X X X . X X . X X X X . X X . . X . .
+ . . . . X . X X . . X X . X X . X . X X X X . X . . X
+ X X X . . X X X X X . . . . . X X . . . X . X . X . X
+ X X . . . . . . . . X . . . X . X X X . X . . X . . .
+ X X . . X . . . . . X X . . . . . X . . . . X . . X X \
+ . . . X . X . X . . . . . X X X X X X . . . . . . X X
+ X . . . X . X X X X X X . . X X X . X . X X X X X X .
+ X . . X X X . X X X X X X X X X X X X X . . . X . X X
+ . . . . X X . . . X . . . . . . . X X . . . X X . X .
+ . . . X X X . . X X . X X X X X . X . . X . . . . . .
+ X . . . . X . X . X . X . . . X . X . X X . X X . X X
+ X . X . . X . X . X . X . X . X . X . . . . . X . X X
+ X . X X X . . X . X . X . . . X . X . X X X . . . X X
+ X X X X X X X X . X . X X X X X . X . X . X . X X X .
+ . . . . . . . X . X . . . . . . . X X X X . . . X X X
+ X X . . X . . X . X X X X X X X X X X X X X . . X . X
+ X X X . X X X X . . X X X X . . X . . . . X . . X X X
+ . . . . X . X X X . . . . X X X X . . X X X X . . . .
+ . . X . . X . X . . . X . X X . X X . X . . . X . X .
+ X X . . X . . X X X X X X X . . X . X X X X X X X . .
+ X . X X . . X X . . . . . X . . . . . . X X . X X X .
+ X . . X X . . X X . X . X . . . . X . X . . X . . X .
+ X . X . X . . X . X X X X X X X X . X X X X . . X X .
+ X X X X . . . X . . X X X . X X . . X . . . . X X X .
+ X X . X . X . . . X . X . . . . X X . X . . X X . . . ",
+ "X ",
+ ". ",
+ )
+ .expect("parse string success");
+ let r = AztecDetectorRXingResult::new(matrix, NO_POINTS.to_vec(), true, 16, 4);
+ decoder::decode(&r);
+}
+
+#[test]
+#[should_panic]
+fn testDecodeTooManyErrors2() {
+ let matrix = BitMatrix::parse_strings(
+ r"
+ . X X . . X . X X . . . X . . X X X . . . X X . X X .
+ X X . X X . . X . . . X X . . . X X . X X X . X . X X
+ . . . . X . . . X X X . X X . X X X X . X X . . X . .
+ X . X X . . X . . . X X . X X . X . X X . . . . . X .
+ X X . X . . X . X X . . . . . X X . . . . . X . . . X
+ X . . X . . . . . . X . . . X . X X X X X X X . . . X
+ X . . X X . . X . . X X . . . . . X . . . . . X X X .
+ . . X X X X . X . . . . . X X X X X X . . . . . . X X
+ X . . . X . X X X X X X . . X X X . X . X X X X X X .
+ X . . X X X . X X X X X X X X X X X X X . . . X . X X
+ . . . . X X . . . X . . . . . . . X X . . . X X . X .
+ . . . X X X . . X X . X X X X X . X . . X . . . . . .
+ X . . . . X . X . X . X . . . X . X . X X . X X . X X
+ X . X . . X . X . X . X . X . X . X . . . . . X . X X
+ X . X X X . . X . X . X . . . X . X . X X X . . . X X
+ X X X X X X X X . X . X X X X X . X . X . X . X X X .
+ . . . . . . . X . X . . . . . . . X X X X . . . X X X
+ X X . . X . . X . X X X X X X X X X X X X X . . X . X
+ X X X . X X X X . . X X X X . . X . . . . X . . X X X
+ . . X X X X X . X . . . . X X X X . . X X X . X . X .
+ . . X X . X . X . . . X . X X . X X . . . . X X . . .
+ X . . . X . X . X X X X X X . . X . X X X X X . X . .
+ . X . . . X X X . . . . . X . . . . . X X X X X . X .
+ X . . X . X X X X . X . X . . . . X . X X . X . . X .
+ X . . . X X . X . X X X X X X X X . X X X X . . X X .
+ . X X X X . . X . . X X X . X X . . X . . . . X X X .
+ X X . . . X X . . X . X . . . . X X . X . . X . X . X ",
+ "X ",
+ ". ",
+ )
+ .expect("String Parse OK");
+ let r = AztecDetectorRXingResult::new(matrix, NO_POINTS.to_vec(), true, 16, 4);
+ decoder::decode(&r);
+}
+
+#[test]
+fn testRawBytes() {
+ let bool0 = vec![false; 0];
+ let bool1 = vec![true];
+ let bool7 = vec![true, false, true, false, true, false, true];
+ let bool8 = vec![true, false, true, false, true, false, true, false];
+ let bool9 = vec![true, false, true, false, true, false, true, false, true];
+ let bool16 = vec![
+ false, true, true, false, false, false, true, true, true, true, false, false, false, false,
+ false, true,
+ ];
+ let byte0 = vec![0u8; 0];
+ let byte1 = vec![-128i8 as u8];
+ let byte7 = vec![-86i8 as u8];
+ let byte8 = vec![-86i8 as u8];
+ let byte9 = vec![-86i8 as u8, -128i8 as u8];
+ let byte16 = vec![99, -63i8 as u8];
+
+ assert_eq!(byte0, decoder::convertBoolArrayToByteArray(&bool0));
+ assert_eq!(byte1, decoder::convertBoolArrayToByteArray(&bool1));
+ assert_eq!(byte7, decoder::convertBoolArrayToByteArray(&bool7));
+ assert_eq!(byte8, decoder::convertBoolArrayToByteArray(&bool8));
+ assert_eq!(byte9, decoder::convertBoolArrayToByteArray(&bool9));
+ assert_eq!(byte16, decoder::convertBoolArrayToByteArray(&bool16));
+}
diff --git a/java_test/java/com/google/zxing/aztec/detector/DetectorTest.java b/src/aztec/DetectorTest.java
similarity index 100%
rename from java_test/java/com/google/zxing/aztec/detector/DetectorTest.java
rename to src/aztec/DetectorTest.java
diff --git a/java_test/java/com/google/zxing/aztec/encoder/EncoderTest.java b/src/aztec/EncoderTest.rs
similarity index 83%
rename from java_test/java/com/google/zxing/aztec/encoder/EncoderTest.java
rename to src/aztec/EncoderTest.rs
index 5952f0a..b269af4 100644
--- a/java_test/java/com/google/zxing/aztec/encoder/EncoderTest.java
+++ b/src/aztec/EncoderTest.rs
@@ -14,27 +14,29 @@
* limitations under the License.
*/
-package com.google.zxing.aztec.encoder;
+// package com.google.zxing.aztec.encoder;
-import com.google.zxing.BarcodeFormat;
-import com.google.zxing.EncodeHintType;
-import com.google.zxing.FormatException;
-import com.google.zxing.RXingResultPoint;
-import com.google.zxing.aztec.AztecDetectorRXingResult;
-import com.google.zxing.aztec.AztecWriter;
-import com.google.zxing.aztec.decoder.Decoder;
-import com.google.zxing.common.BitArray;
-import com.google.zxing.common.BitMatrix;
-import com.google.zxing.common.DecoderRXingResult;
-import org.junit.Assert;
-import org.junit.Test;
+// import com.google.zxing.BarcodeFormat;
+// import com.google.zxing.EncodeHintType;
+// import com.google.zxing.FormatException;
+// import com.google.zxing.RXingResultPoint;
+// import com.google.zxing.aztec.AztecDetectorRXingResult;
+// import com.google.zxing.aztec.AztecWriter;
+// import com.google.zxing.aztec.decoder.Decoder;
+// import com.google.zxing.common.BitArray;
+// import com.google.zxing.common.BitMatrix;
+// import com.google.zxing.common.DecoderRXingResult;
+// import org.junit.Assert;
+// import org.junit.Test;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.EnumMap;
-import java.util.Map;
-import java.util.Random;
-import java.util.regex.Pattern;
+// import java.nio.charset.Charset;
+// import java.nio.charset.StandardCharsets;
+// import java.util.EnumMap;
+// import java.util.Map;
+// import java.util.Random;
+// import java.util.regex.Pattern;
+
+use crate::common::BitArray;
/**
* Aztec 2D generator unit tests.
@@ -42,22 +44,21 @@ import java.util.regex.Pattern;
* @author Rustam Abdullaev
* @author Frank Yellin
*/
-public final class EncoderTest extends Assert {
- private static final Charset ISO_8859_1 = StandardCharsets.ISO_8859_1;
- private static final Charset UTF_8 = StandardCharsets.UTF_8;
- private static final Charset SHIFT_JIS = Charset.forName("Shift_JIS");
- private static final Charset ISO_8859_15 = Charset.forName("ISO-8859-15");
- private static final Charset WINDOWS_1252 = Charset.forName("Windows-1252");
+ const ISO_8859_1:&'static encoding::Encoding = StandardCharsets.ISO_8859_1;
+ const UTF_8 :&'static encoding::Encoding= StandardCharsets.UTF_8;
+ const SHIFT_JIS:&'static encoding::Encoding = Charset.forName("Shift_JIS");
+ const ISO_8859_15:&'static encoding::Encoding = Charset.forName("ISO-8859-15");
+ const WINDOWS_1252 :&'static encoding::Encoding= Charset.forName("Windows-1252");
- private static final Pattern DOTX = Pattern.compile("[^.X]");
- private static final Pattern SPACES = Pattern.compile("\\s+");
- private static final RXingResultPoint[] NO_POINTS = new RXingResultPoint[0];
+ const DOTX : &str = "[^.X]";
+ const SPACES :&str= "\\s+";
+ const NO_POINTS:Vec = Vec::new();
// real life tests
- @Test
- public void testEncode1() {
+ #[test]
+ fn testEncode1() {
testEncode("This is an example Aztec symbol for Wikipedia.", true, 3,
"X X X X X X X X \n" +
"X X X X X X X X X X \n" +
@@ -84,8 +85,8 @@ public final class EncoderTest extends Assert {
" X X X X X X X X X X \n");
}
- @Test
- public void testEncode2() {
+ #[test]
+ fn testEncode2() {
testEncode("Aztec Code is a public domain 2D matrix barcode symbology" +
" of nominally square symbols built on a square grid with a " +
"distinctive square bullseye pattern at their center.", false, 6,
@@ -132,57 +133,57 @@ public final class EncoderTest extends Assert {
"X X X X X X X X X X X X X \n");
}
- @Test
- public void testAztecWriter() throws Exception {
- testWriter("Espa\u00F1ol", null, 25, true, 1); // Without ECI (implicit ISO-8859-1)
- testWriter("Espa\u00F1ol", ISO_8859_1, 25, true, 1); // Explicit ISO-8859-1
- testWriter("\u20AC 1 sample data.", WINDOWS_1252, 25, true, 2); // ISO-8859-1 can't encode Euro; Windows-1252 can
- testWriter("\u20AC 1 sample data.", ISO_8859_15, 25, true, 2);
- testWriter("\u20AC 1 sample data.", UTF_8, 25, true, 2);
- testWriter("\u20AC 1 sample data.", UTF_8, 100, true, 3);
- testWriter("\u20AC 1 sample data.", UTF_8, 300, true, 4);
- testWriter("\u20AC 1 sample data.", UTF_8, 500, false, 5);
- testWriter("The capital of Japan is named \u6771\u4EAC.", SHIFT_JIS, 25, true, 3);
+
+ fn testAztecWriter() {
+ testWriter("Espa\u{00F1}ol", null, 25, true, 1); // Without ECI (implicit ISO-8859-1)
+ testWriter("Espa\u{00F1}ol", ISO_8859_1, 25, true, 1); // Explicit ISO-8859-1
+ testWriter("\u{20AC} 1 sample data.", WINDOWS_1252, 25, true, 2); // ISO-8859-1 can't encode Euro; Windows-1252 can
+ testWriter("\u{20AC} 1 sample data.", ISO_8859_15, 25, true, 2);
+ testWriter("\u{20AC} 1 sample data.", UTF_8, 25, true, 2);
+ testWriter("\u{20AC} 1 sample data.", UTF_8, 100, true, 3);
+ testWriter("\u{20AC} 1 sample data.", UTF_8, 300, true, 4);
+ testWriter("\u{20AC} 1 sample data.", UTF_8, 500, false, 5);
+ testWriter("The capital of Japan is named \u{6771}\u{4EAC}.", SHIFT_JIS, 25, true, 3);
// Test AztecWriter defaults
- String data = "In ut magna vel mauris malesuada";
- AztecWriter writer = new AztecWriter();
- BitMatrix matrix = writer.encode(data, BarcodeFormat.AZTEC, 0, 0);
- AztecCode aztec = Encoder.encode(data,
+ let data = "In ut magna vel mauris malesuada";
+ let writer = AztecWriter::new();
+ let matrix = writer.encode(data, BarcodeFormat.AZTEC, 0, 0);
+ let aztec = Encoder.encode(data,
Encoder.DEFAULT_EC_PERCENT, Encoder.DEFAULT_AZTEC_LAYERS);
- BitMatrix expectedMatrix = aztec.getMatrix();
+ let expectedMatrix = aztec.getMatrix();
assertEquals(matrix, expectedMatrix);
}
// synthetic tests (encode-decode round-trip)
- @Test
- public void testEncodeDecode1() throws Exception {
+ #[test]
+ fn testEncodeDecode1() {
testEncodeDecode("Abc123!", true, 1);
}
- @Test
- public void testEncodeDecode2() throws Exception {
+ #[test]
+ fn testEncodeDecode2() {
testEncodeDecode("Lorem ipsum. http://test/", true, 2);
}
- @Test
- public void testEncodeDecode3() throws Exception {
+ #[test]
+ fn testEncodeDecode3() {
testEncodeDecode("AAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAAN", true, 3);
}
- @Test
- public void testEncodeDecode4() throws Exception {
+ #[test]
+ fn testEncodeDecode4() {
testEncodeDecode("http://test/~!@#*^%&)__ ;:'\"[]{}\\|-+-=`1029384", true, 4);
}
- @Test
- public void testEncodeDecode5() throws Exception {
+ #[test]
+ fn testEncodeDecode5() {
testEncodeDecode("http://test/~!@#*^%&)__ ;:'\"[]{}\\|-+-=`1029384756<>/?abc"
+ "Four score and seven our forefathers brought forth", false, 5);
}
- @Test
- public void testEncodeDecode10() throws Exception {
+ #[test]
+ fn testEncodeDecode10() {
testEncodeDecode("In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam" +
" cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum" +
" est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue" +
@@ -191,8 +192,8 @@ public final class EncoderTest extends Assert {
" elementum sapien dolor et diam.", false, 10);
}
- @Test
- public void testEncodeDecode23() throws Exception {
+ #[test]
+ fn testEncodeDecode23() {
testEncodeDecode("In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam" +
" cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum" +
" est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue" +
@@ -217,8 +218,8 @@ public final class EncoderTest extends Assert {
" erat pulvinar nisi, id elementum sapien dolor et diam.", false, 23);
}
- @Test
- public void testEncodeDecode31() throws Exception {
+ #[test]
+ fn testEncodeDecode31() {
testEncodeDecode("In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam" +
" cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum" +
" est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue" +
@@ -258,16 +259,16 @@ public final class EncoderTest extends Assert {
" hendrerit felis turpis nec lorem.", false, 31);
}
- @Test
- public void testGenerateModeMessage() {
+ #[test]
+ fn testGenerateModeMessage() {
testModeMessage(true, 2, 29, ".X .XXX.. ...X XX.. ..X .XX. .XX.X");
testModeMessage(true, 4, 64, "XX XXXXXX .X.. ...X ..XX .X.. XX..");
testModeMessage(false, 21, 660, "X.X.. .X.X..X..XX .XXX ..X.. .XXX. .X... ..XXX");
testModeMessage(false, 32, 4096, "XXXXX XXXXXXXXXXX X.X. ..... XXX.X ..X.. X.XXX");
}
- @Test
- public void testStuffBits() {
+ #[test]
+ fn testStuffBits() {
testStuffBits(5, ".X.X. X.X.X .X.X.",
".X.X. X.X.X .X.X.");
testStuffBits(5, ".X.X. ..... .X.X",
@@ -285,8 +286,8 @@ public final class EncoderTest extends Assert {
".....X ...XXX XX..XX ..X... ..X.X. X..... X.X... ....X. X..... X....X X..X.. .....X X.X..X XXX.XX .XXXXX");
}
- @Test
- public void testHighLevelEncode() throws FormatException {
+ #[test]
+ fn testHighLevelEncode() {
testHighLevelEncodeString("A. b.",
// 'A' P/S '. ' L/L b D/L '.'
"...X. ..... ...XX XXX.. ...XX XXXX. XX.X");
@@ -315,8 +316,8 @@ public final class EncoderTest extends Assert {
823);
}
- @Test
- public void testHighLevelEncodeBinary() throws FormatException {
+ #[test]
+ fn testHighLevelEncodeBinary() {
// binary short form single byte
testHighLevelEncodeString("N\0N",
// 'N' B/S =1 '\0' N
@@ -327,12 +328,12 @@ public final class EncoderTest extends Assert {
".XXXX XXXXX ...X. ........ .XX.XXX."); // Encode "n" in BINARY
// binary short form consecutive bytes
- testHighLevelEncodeString("N\0\u0080 A",
+ testHighLevelEncodeString("N\0\u{0080} A",
// 'N' B/S =2 '\0' \u0080 ' ' 'A'
".XXXX XXXXX ...X. ........ X....... ....X ...X.");
// binary skipping over single character
- testHighLevelEncodeString("\0a\u00FF\u0080 A",
+ testHighLevelEncodeString("\0a\u{00FF}\u{0080} A",
// B/S =4 '\0' 'a' '\3ff' '\200' ' ' 'A'
"XXXXX ..X.. ........ .XX....X XXXXXXXX X....... ....X ...X.");
@@ -343,7 +344,7 @@ public final class EncoderTest extends Assert {
);
// Create a string in which every character requires binary
- StringBuilder sb = new StringBuilder();
+ let sb = String::new();
for (int i = 0; i <= 3000; i++) {
sb.append((char) (128 + (i % 30)));
}
@@ -402,8 +403,8 @@ public final class EncoderTest extends Assert {
testHighLevelEncodeString(sb.toString(), 21 + 64 * 8);
}
- @Test
- public void testHighLevelEncodePairs() throws FormatException {
+ #[test]
+ fn testHighLevelEncodePairs() {
// Typical usage
testHighLevelEncodeString("ABC. DEF\r\n",
// A B C P/S . D E F P/S \r\n
@@ -424,17 +425,19 @@ public final class EncoderTest extends Assert {
"...X. XXXXX ..X.. X....... ..X.XXX. ..X..... X.......");
}
- @Test(expected = IllegalArgumentException.class)
- public void testUserSpecifiedLayers() {
+ #[test]
+ #[should_panic]
+ fn testUserSpecifiedLayers() {
doTestUserSpecifiedLayers(33);
}
- @Test(expected = IllegalArgumentException.class)
- public void testUserSpecifiedLayers2() {
+ #[test]
+ #[should_panic]
+ fn testUserSpecifiedLayers2() {
doTestUserSpecifiedLayers(-1);
}
- private void doTestUserSpecifiedLayers(int userSpecifiedLayers) {
+ fn doTestUserSpecifiedLayers( userSpecifiedLayers:usize) {
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
AztecCode aztec = Encoder.encode(alphabet, 25, -2);
assertEquals(2, aztec.getLayers());
@@ -447,8 +450,9 @@ public final class EncoderTest extends Assert {
Encoder.encode(alphabet, 25, userSpecifiedLayers);
}
- @Test(expected = IllegalArgumentException.class)
- public void testBorderCompact4CaseFailed() {
+ #[test]
+ #[should_panic]
+ fn testBorderCompact4CaseFailed() {
// Compact(4) con hold 608 bits of information, but at most 504 can be data. Rest must
// be error correction
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
@@ -457,8 +461,8 @@ public final class EncoderTest extends Assert {
Encoder.encode(alphabet4, 0, -4);
}
- @Test
- public void testBorderCompact4Case() {
+ #[test]
+ fn testBorderCompact4Case() {
// Compact(4) con hold 608 bits of information, but at most 504 can be data. Rest must
// be error correction
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
@@ -479,7 +483,7 @@ public final class EncoderTest extends Assert {
// Helper routines
- private static void testEncode(String data, boolean compact, int layers, String expected) {
+ fn testEncode( data:&str, compact:bool, layers:usize, expected:&str) {
AztecCode aztec = Encoder.encode(data, 33, Encoder.DEFAULT_AZTEC_LAYERS);
assertEquals("Unexpected symbol format (compact)", compact, aztec.isCompact());
assertEquals("Unexpected nr. of layers", layers, aztec.getLayers());
@@ -487,7 +491,7 @@ public final class EncoderTest extends Assert {
assertEquals("encode() failed", expected, matrix.toString());
}
- private static void testEncodeDecode(String data, boolean compact, int layers) throws Exception {
+ fn testEncodeDecode( data:&str, compact:bool, layers:usize) {
AztecCode aztec = Encoder.encode(data, 25, Encoder.DEFAULT_AZTEC_LAYERS);
assertEquals("Unexpected symbol format (compact)", compact, aztec.isCompact());
assertEquals("Unexpected nr. of layers", layers, aztec.getLayers());
@@ -507,11 +511,11 @@ public final class EncoderTest extends Assert {
assertEquals(data, res.getText());
}
- private static void testWriter(String data,
- Charset charset,
- int eccPercent,
- boolean compact,
- int layers) throws FormatException {
+ fn testWriter( data:&str,
+ charset:&'static dyn encoding::Encoding,
+ eccPercent:u32,
+ compact:bool,
+ layers:usize) throws FormatException {
// Perform an encode-decode round-trip because it can be lossy.
Map hints = new EnumMap<>(EncodeHintType.class);
if (null != charset) {
@@ -548,56 +552,35 @@ public final class EncoderTest extends Assert {
assertEquals(data, res.getText());
}
- private static Random getPseudoRandom() {
+ fn getPseudoRandom() -> rand::Rng{
return new Random(0xDEADBEEF);
}
- private static void testModeMessage(boolean compact, int layers, int words, String expected) {
+ fn testModeMessage( compact:bool, layers:usize, words:usize, expected:&str) {
BitArray in = Encoder.generateModeMessage(compact, layers, words);
assertEquals("generateModeMessage() failed", stripSpace(expected), stripSpace(in.toString()));
}
- private static void testStuffBits(int wordSize, String bits, String expected) {
+ fn testStuffBits( wordSize:usize, bits:&str, expected:&str) {
BitArray in = toBitArray(bits);
BitArray stuffed = Encoder.stuffBits(in, wordSize);
assertEquals("stuffBits() failed for input string: " + bits,
stripSpace(expected), stripSpace(stuffed.toString()));
}
- public static BitArray toBitArray(CharSequence bits) {
- BitArray in = new BitArray();
- char[] str = DOTX.matcher(bits).replaceAll("").toCharArray();
- for (char aStr : str) {
- in.appendBit(aStr == 'X');
- }
- return in;
- }
+
- public static boolean[] toBooleanArray(BitArray bitArray) {
- boolean[] result = new boolean[bitArray.getSize()];
- for (int i = 0; i < result.length; i++) {
- result[i] = bitArray.get(i);
- }
- return result;
- }
-
- private static void testHighLevelEncodeString(String s, String expectedBits) throws FormatException {
+ fn testHighLevelEncodeString( s:&str, expectedBits:&str) {
BitArray bits = new HighLevelEncoder(s.getBytes(StandardCharsets.ISO_8859_1)).encode();
String receivedBits = stripSpace(bits.toString());
assertEquals("highLevelEncode() failed for input string: " + s, stripSpace(expectedBits), receivedBits);
assertEquals(s, Decoder.highLevelDecode(toBooleanArray(bits)));
}
- private static void testHighLevelEncodeString(String s, int expectedReceivedBits) throws FormatException {
+ fn testHighLevelEncodeString( s:&str, expectedReceivedBits:u32) {
BitArray bits = new HighLevelEncoder(s.getBytes(StandardCharsets.ISO_8859_1)).encode();
int receivedBitCount = stripSpace(bits.toString()).length();
assertEquals("highLevelEncode() failed for input string: " + s,
expectedReceivedBits, receivedBitCount);
assertEquals(s, Decoder.highLevelDecode(toBooleanArray(bits)));
}
-
- public static String stripSpace(String s) {
- return SPACES.matcher(s).replaceAll("");
- }
-
-}
diff --git a/src/aztec/decoder.rs b/src/aztec/decoder.rs
new file mode 100644
index 0000000..95f1367
--- /dev/null
+++ b/src/aztec/decoder.rs
@@ -0,0 +1,572 @@
+/*
+ * Copyright 2010 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// package com.google.zxing.aztec.decoder;
+
+// import com.google.zxing.FormatException;
+// import com.google.zxing.aztec.AztecDetectorRXingResult;
+// import com.google.zxing.common.BitMatrix;
+// import com.google.zxing.common.CharacterSetECI;
+// 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;
+
+// import java.io.ByteArrayOutputStream;
+// import java.io.UnsupportedEncodingException;
+// import java.nio.charset.Charset;
+// import java.nio.charset.StandardCharsets;
+// import java.util.Arrays;
+
+use encoding::Encoding;
+
+use crate::{
+ common::{
+ self,
+ reedsolomon::{
+ get_predefined_genericgf, GenericGF, PredefinedGenericGF, ReedSolomonDecoder,
+ },
+ BitMatrix, CharacterSetECI, DecoderRXingResult, DetectorRXingResult,
+ },
+ exceptions::Exceptions,
+};
+
+use super::AztecDetectorResult::AztecDetectorRXingResult;
+
+/**
+ * The main class which implements Aztec Code decoding -- as opposed to locating and extracting
+ * the Aztec Code from an image.
+ *
+ * @author David Olivier
+ */
+
+#[derive(PartialEq, Eq,Copy,Clone)]
+enum Table {
+ UPPER,
+ LOWER,
+ MIXED,
+ DIGIT,
+ PUNCT,
+ BINARY,
+}
+
+const UPPER_TABLE: [&str; 32] = [
+ "CTRL_PS", " ", "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", "CTRL_LL", "CTRL_ML", "CTRL_DL", "CTRL_BS",
+];
+
+const LOWER_TABLE: [&str; 32] = [
+ "CTRL_PS", " ", "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", "CTRL_US", "CTRL_ML", "CTRL_DL", "CTRL_BS",
+];
+
+const MIXED_TABLE: [&str; 32] = [
+ "CTRL_PS", " ", "\u{1}", "\u{2}", "\u{3}", "\u{4}", "\u{5}", "\u{6}", "\u{7}", "\u{8}", "\t",
+ "\n", "\u{13}", "\u{0c}", "\r", "\u{33}", "\u{34}", "\u{35}", "\u{36}", "\u{37}", "@", "\\",
+ "^", "_", "`", "|", "~", "\u{177}", "CTRL_LL", "CTRL_UL", "CTRL_PL", "CTRL_BS",
+];
+
+const PUNCT_TABLE: [&str; 32] = [
+ "FLG(n)", "\r", "\r\n", ". ", ", ", ": ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*",
+ "+", ",", "-", ".", "/", ":", ";", "<", "=", ">", "?", "[", "]", "{", "}", "CTRL_UL",
+];
+
+const DIGIT_TABLE: [&str; 16] = [
+ "CTRL_PS", " ", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ",", ".", "CTRL_UL",
+ "CTRL_US",
+];
+
+// private static final Charset DEFAULT_ENCODING = StandardCharsets.ISO_8859_1;
+
+// private AztecDetectorRXingResult ddata;
+
+pub fn decode(
+ detectorRXingResult: &AztecDetectorRXingResult,
+) -> Result {
+ //let mut detectorRXingResult = detectorRXingResult.clone();
+ let matrix = detectorRXingResult.getBits();
+ let rawbits = extractBits(&detectorRXingResult, matrix);
+ let correctedBits = correctBits(&detectorRXingResult, &rawbits)?;
+ let rawBytes = convertBoolArrayToByteArray(&correctedBits.correctBits);
+ let result = getEncodedData(&correctedBits.correctBits);
+ let mut decoderRXingResult = DecoderRXingResult::new(
+ rawBytes,
+ result?,
+ Vec::new(),
+ format!("{}%", correctedBits.ecLevel),
+ );
+ decoderRXingResult.setNumBits(correctedBits.correctBits.len());
+
+ Ok(decoderRXingResult)
+}
+
+/// This method is used for testing the high-level encoder
+pub fn highLevelDecode(correctedBits: &[bool]) -> Result {
+ getEncodedData(correctedBits)
+}
+
+/**
+ * Gets the string encoded in the aztec code bits
+ *
+ * @return the decoded string
+ */
+fn getEncodedData(correctedBits: &[bool]) -> Result {
+ let endIndex = correctedBits.len();
+ let mut latchTable = Table::UPPER; // table most recently latched to
+ let mut shiftTable = Table::UPPER; // table to use for the next read
+
+ // Final decoded string result
+ // (correctedBits-5) / 4 is an upper bound on the size (all-digit result)
+ let mut result = String::with_capacity((correctedBits.len() - 5) / 4);
+
+ // Intermediary buffer of decoded bytes, which is decoded into a string and flushed
+ // when character encoding changes (ECI) or input ends.
+ let mut decodedBytes: Vec = Vec::new();
+ let mut encdr: &'static dyn encoding::Encoding = encoding::all::UTF_8;
+
+ let mut index = 0;
+ while index < endIndex {
+ if shiftTable == Table::BINARY {
+ if endIndex - index < 5 {
+ break;
+ }
+ let mut length = readCode(correctedBits, index, 5);
+ index += 5;
+ if length == 0 {
+ if endIndex - index < 11 {
+ break;
+ }
+ length = readCode(correctedBits, index, 11) + 31;
+ index += 11;
+ }
+ for _charCount in 0..length {
+ // for (int charCount = 0; charCount < length; charCount++) {
+ if endIndex - index < 8 {
+ index = endIndex; // Force outer loop to exit
+ break;
+ }
+ let code = readCode(correctedBits, index, 8);
+ decodedBytes.push(code as u8);
+ index += 8;
+ }
+ // Go back to whatever mode we had been in
+ shiftTable = latchTable;
+ } else {
+ let size = if shiftTable == Table::DIGIT { 4 } else { 5 };
+ if endIndex - index < size {
+ break;
+ }
+ let code = readCode(correctedBits, index, size);
+ index += size;
+ let str = getCharacter(shiftTable, code)?;
+ if "FLG(n)" == str {
+ if endIndex - index < 3 {
+ break;
+ }
+ let mut n = readCode(correctedBits, index, 3);
+ index += 3;
+ // flush bytes, FLG changes state
+ // try {
+ result.push_str(&String::from_utf8(decodedBytes.clone()).unwrap());
+ // result.append(decodedBytes.toString(encoding.name()));
+ // } catch (UnsupportedEncodingException uee) {
+ // throw new IllegalStateException(uee);
+ // }
+ decodedBytes.clear();
+ match n {
+ 0 => result.push(29 as char), // translate FNC1 as ASCII 29
+ 7 => {
+ return Err(Exceptions::FormatException(
+ "FLG(7) is reserved and illegal".to_owned(),
+ ))
+ } // FLG(7) is reserved and illegal
+ _ => {
+ // ECI is decimal integer encoded as 1-6 codes in DIGIT mode
+ let mut eci = 0;
+ if endIndex - index < 4 * (n as usize) {
+ break;
+ }
+ while n > 0 {
+ //while (n-- > 0) {
+ let nextDigit = readCode(correctedBits, index, 4);
+ index += 4;
+ if nextDigit < 2 || nextDigit > 11 {
+ return Err(Exceptions::FormatException(
+ "Not a decimal digit".to_owned(),
+ )); // Not a decimal digit
+ }
+ eci = eci * 10 + (nextDigit - 2);
+ n -= 1;
+ }
+ let charsetECI = CharacterSetECI::getCharacterSetECIByValue(eci);
+ if charsetECI.is_err() {
+ return Err(Exceptions::FormatException(
+ "Charset must exist".to_owned(),
+ ));
+ }
+ encdr = CharacterSetECI::getCharset(&charsetECI?);
+ // encdr = charsetECI?::getCharset();
+ }
+ }
+ // switch (n) {
+ // case 0:
+ // result.append(29 as char); // translate FNC1 as ASCII 29
+ // break;
+ // case 7:
+ // throw FormatException.getFormatInstance(); // FLG(7) is reserved and illegal
+ // default:
+ // // ECI is decimal integer encoded as 1-6 codes in DIGIT mode
+ // int eci = 0;
+ // if (endIndex - index < 4 * n) {
+ // break;
+ // }
+ // while (n-- > 0) {
+ // int nextDigit = readCode(correctedBits, index, 4);
+ // index += 4;
+ // if (nextDigit < 2 || nextDigit > 11) {
+ // throw FormatException.getFormatInstance(); // Not a decimal digit
+ // }
+ // eci = eci * 10 + (nextDigit - 2);
+ // }
+ // CharacterSetECI charsetECI = CharacterSetECI.getCharacterSetECIByValue(eci);
+ // if (charsetECI == null) {
+ // throw FormatException.getFormatInstance();
+ // }
+ // encoding = charsetECI.getCharset();
+ // }
+ // Go back to whatever mode we had been in
+ shiftTable = latchTable;
+ } else if str.starts_with("CTRL_") {
+ // Table changes
+ // ISO/IEC 24778:2008 prescribes ending a shift sequence in the mode from which it was invoked.
+ // That's including when that mode is a shift.
+ // Our test case dlusbs.png for issue #642 exercises that.
+ latchTable = shiftTable; // Latch the current mode, so as to return to Upper after U/S B/S
+ shiftTable = getTable(str.chars().nth(5).unwrap());
+ if str.chars().nth(6).unwrap() == 'L' {
+ latchTable = shiftTable;
+ }
+ } else {
+ // Though stored as a table of strings for convenience, codes actually represent 1 or 2 *bytes*.
+ let b = str.as_bytes();
+ //let b = str.getBytes(StandardCharsets.US_ASCII);
+ //decodedBytes.write(b, 0, b.length);
+ for bt in b {
+ decodedBytes.push(*bt);
+ }
+ // Go back to whatever mode we had been in
+ shiftTable = latchTable;
+ }
+ }
+ }
+ //try {
+ if let Ok(str) = encdr.decode(&decodedBytes, encoding::DecoderTrap::Strict) {
+ result.push_str(&str);
+ } else {
+ return Err(Exceptions::IllegalStateException("bad encoding".to_owned()));
+ }
+ // result.push_str(decodedBytes.toString(encoding.name()));
+ //} catch (UnsupportedEncodingException uee) {
+ // can't happen
+ //throw new IllegalStateException(uee);
+ //}
+ Ok(result)
+}
+
+/**
+ * gets the table corresponding to the char passed
+ */
+fn getTable(t: char) -> Table {
+ match t {
+ 'L' => Table::LOWER,
+ 'P' => Table::PUNCT,
+ 'M' => Table::MIXED,
+ 'D' => Table::DIGIT,
+ 'B' => Table::BINARY,
+ _ => Table::UPPER,
+ }
+ // switch (t) {
+ // case 'L':
+ // return Table.LOWER;
+ // case 'P':
+ // return Table.PUNCT;
+ // case 'M':
+ // return Table.MIXED;
+ // case 'D':
+ // return Table.DIGIT;
+ // case 'B':
+ // return Table.BINARY;
+ // case 'U':
+ // default:
+ // return Table.UPPER;
+ // }
+}
+
+/**
+ * Gets the character (or string) corresponding to the passed code in the given table
+ *
+ * @param table the table used
+ * @param code the code of the character
+ */
+fn getCharacter(table: Table, code: u32) -> Result<&'static str, Exceptions> {
+ match table {
+ Table::UPPER => Ok(UPPER_TABLE[code as usize]),
+ Table::LOWER => Ok(LOWER_TABLE[code as usize]),
+ Table::MIXED => Ok(MIXED_TABLE[code as usize]),
+ Table::DIGIT => Ok(DIGIT_TABLE[code as usize]),
+ Table::PUNCT => Ok(PUNCT_TABLE[code as usize]),
+ _ => Err(Exceptions::IllegalStateException("Bad table".to_owned())),
+ }
+ // switch (table) {
+ // case UPPER:
+ // return UPPER_TABLE[code];
+ // case LOWER:
+ // return LOWER_TABLE[code];
+ // case MIXED:
+ // return MIXED_TABLE[code];
+ // case PUNCT:
+ // return PUNCT_TABLE[code];
+ // case DIGIT:
+ // return DIGIT_TABLE[code];
+ // default:
+ // // Should not reach here.
+ // throw new IllegalStateException("Bad table");
+}
+
+struct CorrectedBitsRXingResult {
+ correctBits: Vec,
+ ecLevel: u32,
+}
+impl CorrectedBitsRXingResult {
+ pub fn new(correctBits: Vec, ecLevel: u32) -> Self {
+ Self {
+ correctBits,
+ ecLevel,
+ }
+ }
+}
+
+/**
+ * Performs RS error correction on an array of bits.
+ *
+ * @return the corrected array
+ * @throws FormatException if the input contains too many errors
+ */
+fn correctBits(
+ ddata: &&AztecDetectorRXingResult,
+ rawbits: &[bool],
+) -> Result {
+ let gf: GenericGF;
+ let codewordSize;
+
+ if ddata.getNbLayers() <= 2 {
+ codewordSize = 6;
+ gf = get_predefined_genericgf(PredefinedGenericGF::AztecData6); //GenericGF.AZTEC_DATA_6;
+ } else if ddata.getNbLayers() <= 8 {
+ codewordSize = 8;
+ gf = get_predefined_genericgf(PredefinedGenericGF::AztecData8); //GenericGF.AZTEC_DATA_8;
+ } else if ddata.getNbLayers() <= 22 {
+ codewordSize = 10;
+ gf = get_predefined_genericgf(PredefinedGenericGF::AztecData10); //GenericGF.AZTEC_DATA_10;
+ } else {
+ codewordSize = 12;
+ gf = get_predefined_genericgf(PredefinedGenericGF::AztecData12); //GenericGF.AZTEC_DATA_12;
+ }
+
+ let numDataCodewords = ddata.getNbDatablocks();
+ let numCodewords = rawbits.len() / codewordSize;
+ if numCodewords < numDataCodewords as usize {
+ return Err(Exceptions::FormatException(format!(
+ "numCodewords {}< numDataCodewords{}",
+ numCodewords, numDataCodewords
+ )));
+ }
+ let mut offset = rawbits.len() % codewordSize;
+
+ let mut dataWords = vec![0i32; numCodewords];
+ for i in 0..numCodewords {
+ // for (int i = 0; i < numCodewords; i++, offset += codewordSize) {
+ dataWords[i] = readCode(rawbits, offset, codewordSize) as i32;
+ offset += codewordSize;
+ }
+
+ //try {
+ let rsDecoder = ReedSolomonDecoder::new(gf);
+ rsDecoder.decode(
+ &mut dataWords,
+ (numCodewords - numDataCodewords as usize) as i32,
+ );
+ //} catch (ReedSolomonException ex) {
+ //throw FormatException.getFormatInstance(ex);
+ //}
+
+ // Now perform the unstuffing operation.
+ // First, count how many bits are going to be thrown out as stuffing
+ let mask = (1 << codewordSize) - 1;
+ let mut stuffedBits = 0;
+ for i in 0..numDataCodewords as usize {
+ // for (int i = 0; i < numDataCodewords; i++) {
+ let dataWord = dataWords[i];
+ if dataWord == 0 || dataWord == mask {
+ return Err(Exceptions::FormatException(
+ "dataWord == 0 || dataWord == mask".to_owned(),
+ ));
+ //throw FormatException.getFormatInstance();
+ } else if dataWord == 1 || dataWord == mask - 1 {
+ stuffedBits += 1;
+ }
+ }
+ // Now, actually unpack the bits and remove the stuffing
+ let mut correctedBits =
+ vec![false; (numDataCodewords * codewordSize as u32 - stuffedBits) as usize];
+ let mut index = 0;
+ for i in 0..numDataCodewords as usize {
+ // for (int i = 0; i < numDataCodewords; i++) {
+ let dataWord = dataWords[i];
+ if dataWord == 1 || dataWord == mask - 1 {
+ // next codewordSize-1 bits are all zeros or all ones
+ correctedBits.splice(
+ index..index + codewordSize - 1,
+ vec![dataWord > 1; codewordSize],
+ );
+ // Arrays.fill(correctedBits, index, index + codewordSize - 1, dataWord > 1);
+ index += codewordSize - 1;
+ } else {
+ for bit in (0..codewordSize).rev() {
+ // for (int bit = codewordSize - 1; bit >= 0; --bit) {
+ correctedBits[index] = (dataWord & (1 << bit)) != 0;
+ index += 1;
+ }
+ }
+ }
+
+ Ok(CorrectedBitsRXingResult::new(
+ correctedBits,
+ (100 * (numCodewords - numDataCodewords as usize) / numCodewords) as u32,
+ ))
+}
+
+/**
+ * Gets the array of bits from an Aztec Code matrix
+ *
+ * @return the array of bits
+ */
+fn extractBits(ddata: &AztecDetectorRXingResult, matrix: &BitMatrix) -> Vec {
+ let compact = ddata.isCompact();
+ let layers = ddata.getNbLayers();
+ let baseMatrixSize = ((if compact { 11 } else { 14 }) + layers * 4) as usize; // not including alignment lines
+ let mut alignmentMap = vec![0u32; baseMatrixSize];
+ let mut rawbits = vec![false; totalBitsInLayer(layers as usize, compact)];
+
+ if compact {
+ for i in 0..alignmentMap.len() {
+ // for (int i = 0; i < alignmentMap.length; i++) {
+ alignmentMap[i] = i as u32;
+ }
+ } else {
+ let matrixSize = baseMatrixSize + 1 + 2 * ((baseMatrixSize / 2 - 1) / 15);
+ let origCenter = baseMatrixSize / 2;
+ let center = matrixSize / 2;
+ for i in 0..origCenter {
+ // for (int i = 0; i < origCenter; i++) {
+ let newOffset = i + i / 15;
+ alignmentMap[origCenter - i - 1] = (center - newOffset - 1) as u32;
+ alignmentMap[origCenter + i] = (center + newOffset + 1) as u32;
+ }
+ }
+ let mut rowOffset = 0;
+ for i in 0..layers {
+ // for (int i = 0, rowOffset = 0; i < layers; i++) {
+ let rowSize = (layers - i) * 4 + (if compact { 9 } else { 12 });
+ // The top-left most point of this layer is (not including alignment lines)
+ let low = i * 2;
+ // The bottom-right most point of this layer is (not including alignment lines)
+ let high = baseMatrixSize as u32 - 1 - low;
+ // We pull bits from the two 2 x rowSize columns and two rowSize x 2 rows
+ for j in 0..rowSize {
+ // for (int j = 0; j < rowSize; j++) {
+ let columnOffset = j * 2;
+ for k in 0..2 {
+ // for (int k = 0; k < 2; k++) {
+ // left column
+ rawbits[(rowOffset + columnOffset + k) as usize] = matrix.get(
+ alignmentMap[(low + k) as usize],
+ alignmentMap[(low + j) as usize],
+ );
+ // bottom row
+ rawbits[(rowOffset + 2 * rowSize + columnOffset + k) as usize] = matrix.get(
+ alignmentMap[(low + j) as usize],
+ alignmentMap[(high - k) as usize],
+ );
+ // right column
+ rawbits[(rowOffset + 4 * rowSize + columnOffset + k) as usize] = matrix.get(
+ alignmentMap[(high - k) as usize],
+ alignmentMap[(high - j) as usize],
+ );
+ // top row
+ rawbits[(rowOffset + 6 * rowSize + columnOffset + k) as usize] = matrix.get(
+ alignmentMap[(high - j) as usize],
+ alignmentMap[(low + k) as usize],
+ );
+ }
+ }
+ rowOffset += rowSize * 8;
+ }
+ return rawbits;
+}
+
+/**
+ * Reads a code of given length and at given index in an array of bits
+ */
+fn readCode(rawbits: &[bool], startIndex: usize, length: usize) -> u32 {
+ let mut res = 0;
+ for i in startIndex..length {
+ // for (int i = startIndex; i < startIndex + length; i++) {
+ res <<= 1;
+ if rawbits[i] {
+ res |= 0x01;
+ }
+ }
+ return res;
+}
+
+/**
+ * Reads a code of length 8 in an array of bits, padding with zeros
+ */
+fn readByte(rawbits: &[bool], startIndex: usize) -> u8 {
+ let n = rawbits.len() - startIndex;
+ if n >= 8 {
+ return readCode(rawbits, startIndex, 8) as u8;
+ }
+ return (readCode(rawbits, startIndex, n) << (8 - n)) as u8;
+}
+
+/**
+ * Packs a bit array into bytes, most significant bit first
+ */
+pub fn convertBoolArrayToByteArray(boolArr: &[bool]) -> Vec {
+ let mut byteArr = vec![0u8; (boolArr.len() + 7) / 8];
+ for i in 0..byteArr.len() {
+ // for (int i = 0; i < byteArr.length; i++) {
+ byteArr[i] = readByte(boolArr, 8 * i);
+ }
+ return byteArr;
+}
+
+fn totalBitsInLayer(layers: usize, compact: bool) -> usize {
+ (if compact { 88 } else { 112 } + 16 * layers) * layers
+ // return ((compact ? 88 : 112) + 16 * layers) * layers;
+}
diff --git a/src/aztec/decoder/Decoder.java b/src/aztec/decoder/Decoder.java
deleted file mode 100644
index 92a5033..0000000
--- a/src/aztec/decoder/Decoder.java
+++ /dev/null
@@ -1,443 +0,0 @@
-/*
- * Copyright 2010 ZXing authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.zxing.aztec.decoder;
-
-import com.google.zxing.FormatException;
-import com.google.zxing.aztec.AztecDetectorRXingResult;
-import com.google.zxing.common.BitMatrix;
-import com.google.zxing.common.CharacterSetECI;
-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;
-
-import java.io.ByteArrayOutputStream;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-
-/**
- * The main class which implements Aztec Code decoding -- as opposed to locating and extracting
- * the Aztec Code from an image.
- *
- * @author David Olivier
- */
-public final class Decoder {
-
- private enum Table {
- UPPER,
- LOWER,
- MIXED,
- DIGIT,
- PUNCT,
- BINARY
- }
-
- private static final String[] UPPER_TABLE = {
- "CTRL_PS", " ", "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", "CTRL_LL", "CTRL_ML", "CTRL_DL", "CTRL_BS"
- };
-
- private static final String[] LOWER_TABLE = {
- "CTRL_PS", " ", "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", "CTRL_US", "CTRL_ML", "CTRL_DL", "CTRL_BS"
- };
-
- private static final String[] MIXED_TABLE = {
- "CTRL_PS", " ", "\1", "\2", "\3", "\4", "\5", "\6", "\7", "\b", "\t", "\n",
- "\13", "\f", "\r", "\33", "\34", "\35", "\36", "\37", "@", "\\", "^", "_",
- "`", "|", "~", "\177", "CTRL_LL", "CTRL_UL", "CTRL_PL", "CTRL_BS"
- };
-
- private static final String[] PUNCT_TABLE = {
- "FLG(n)", "\r", "\r\n", ". ", ", ", ": ", "!", "\"", "#", "$", "%", "&", "'", "(", ")",
- "*", "+", ",", "-", ".", "/", ":", ";", "<", "=", ">", "?", "[", "]", "{", "}", "CTRL_UL"
- };
-
- private static final String[] DIGIT_TABLE = {
- "CTRL_PS", " ", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ",", ".", "CTRL_UL", "CTRL_US"
- };
-
- private static final Charset DEFAULT_ENCODING = StandardCharsets.ISO_8859_1;
-
- private AztecDetectorRXingResult ddata;
-
- public DecoderRXingResult decode(AztecDetectorRXingResult detectorRXingResult) throws FormatException {
- ddata = detectorRXingResult;
- BitMatrix matrix = detectorRXingResult.getBits();
- boolean[] rawbits = extractBits(matrix);
- CorrectedBitsRXingResult correctedBits = correctBits(rawbits);
- byte[] rawBytes = convertBoolArrayToByteArray(correctedBits.correctBits);
- String result = getEncodedData(correctedBits.correctBits);
- DecoderRXingResult decoderRXingResult =
- new DecoderRXingResult(rawBytes, result, null, String.format("%d%%", correctedBits.ecLevel));
- decoderRXingResult.setNumBits(correctedBits.correctBits.length);
- return decoderRXingResult;
- }
-
- // This method is used for testing the high-level encoder
- public static String highLevelDecode(boolean[] correctedBits) throws FormatException {
- return getEncodedData(correctedBits);
- }
-
- /**
- * Gets the string encoded in the aztec code bits
- *
- * @return the decoded string
- */
- private static String getEncodedData(boolean[] correctedBits) throws FormatException {
- int endIndex = correctedBits.length;
- Table latchTable = Table.UPPER; // table most recently latched to
- Table shiftTable = Table.UPPER; // table to use for the next read
-
- // Final decoded string result
- // (correctedBits-5) / 4 is an upper bound on the size (all-digit result)
- StringBuilder result = new StringBuilder((correctedBits.length - 5) / 4);
-
- // Intermediary buffer of decoded bytes, which is decoded into a string and flushed
- // when character encoding changes (ECI) or input ends.
- ByteArrayOutputStream decodedBytes = new ByteArrayOutputStream();
- Charset encoding = DEFAULT_ENCODING;
-
- int index = 0;
- while (index < endIndex) {
- if (shiftTable == Table.BINARY) {
- if (endIndex - index < 5) {
- break;
- }
- int length = readCode(correctedBits, index, 5);
- index += 5;
- if (length == 0) {
- if (endIndex - index < 11) {
- break;
- }
- length = readCode(correctedBits, index, 11) + 31;
- index += 11;
- }
- for (int charCount = 0; charCount < length; charCount++) {
- if (endIndex - index < 8) {
- index = endIndex; // Force outer loop to exit
- break;
- }
- int code = readCode(correctedBits, index, 8);
- decodedBytes.write((byte) code);
- index += 8;
- }
- // Go back to whatever mode we had been in
- shiftTable = latchTable;
- } else {
- int size = shiftTable == Table.DIGIT ? 4 : 5;
- if (endIndex - index < size) {
- break;
- }
- int code = readCode(correctedBits, index, size);
- index += size;
- String str = getCharacter(shiftTable, code);
- if ("FLG(n)".equals(str)) {
- if (endIndex - index < 3) {
- break;
- }
- int n = readCode(correctedBits, index, 3);
- index += 3;
- // flush bytes, FLG changes state
- try {
- result.append(decodedBytes.toString(encoding.name()));
- } catch (UnsupportedEncodingException uee) {
- throw new IllegalStateException(uee);
- }
- decodedBytes.reset();
- switch (n) {
- case 0:
- result.append((char) 29); // translate FNC1 as ASCII 29
- break;
- case 7:
- throw FormatException.getFormatInstance(); // FLG(7) is reserved and illegal
- default:
- // ECI is decimal integer encoded as 1-6 codes in DIGIT mode
- int eci = 0;
- if (endIndex - index < 4 * n) {
- break;
- }
- while (n-- > 0) {
- int nextDigit = readCode(correctedBits, index, 4);
- index += 4;
- if (nextDigit < 2 || nextDigit > 11) {
- throw FormatException.getFormatInstance(); // Not a decimal digit
- }
- eci = eci * 10 + (nextDigit - 2);
- }
- CharacterSetECI charsetECI = CharacterSetECI.getCharacterSetECIByValue(eci);
- if (charsetECI == null) {
- throw FormatException.getFormatInstance();
- }
- encoding = charsetECI.getCharset();
- }
- // Go back to whatever mode we had been in
- shiftTable = latchTable;
- } else if (str.startsWith("CTRL_")) {
- // Table changes
- // ISO/IEC 24778:2008 prescribes ending a shift sequence in the mode from which it was invoked.
- // That's including when that mode is a shift.
- // Our test case dlusbs.png for issue #642 exercises that.
- latchTable = shiftTable; // Latch the current mode, so as to return to Upper after U/S B/S
- shiftTable = getTable(str.charAt(5));
- if (str.charAt(6) == 'L') {
- latchTable = shiftTable;
- }
- } else {
- // Though stored as a table of strings for convenience, codes actually represent 1 or 2 *bytes*.
- byte[] b = str.getBytes(StandardCharsets.US_ASCII);
- decodedBytes.write(b, 0, b.length);
- // Go back to whatever mode we had been in
- shiftTable = latchTable;
- }
- }
- }
- try {
- result.append(decodedBytes.toString(encoding.name()));
- } catch (UnsupportedEncodingException uee) {
- // can't happen
- throw new IllegalStateException(uee);
- }
- return result.toString();
- }
-
- /**
- * gets the table corresponding to the char passed
- */
- private static Table getTable(char t) {
- switch (t) {
- case 'L':
- return Table.LOWER;
- case 'P':
- return Table.PUNCT;
- case 'M':
- return Table.MIXED;
- case 'D':
- return Table.DIGIT;
- case 'B':
- return Table.BINARY;
- case 'U':
- default:
- return Table.UPPER;
- }
- }
-
- /**
- * Gets the character (or string) corresponding to the passed code in the given table
- *
- * @param table the table used
- * @param code the code of the character
- */
- private static String getCharacter(Table table, int code) {
- switch (table) {
- case UPPER:
- return UPPER_TABLE[code];
- case LOWER:
- return LOWER_TABLE[code];
- case MIXED:
- return MIXED_TABLE[code];
- case PUNCT:
- return PUNCT_TABLE[code];
- case DIGIT:
- return DIGIT_TABLE[code];
- default:
- // Should not reach here.
- throw new IllegalStateException("Bad table");
- }
- }
-
- static final class CorrectedBitsRXingResult {
- private final boolean[] correctBits;
- private final int ecLevel;
-
- CorrectedBitsRXingResult(boolean[] correctBits, int ecLevel) {
- this.correctBits = correctBits;
- this.ecLevel = ecLevel;
- }
- }
-
- /**
- * Performs RS error correction on an array of bits.
- *
- * @return the corrected array
- * @throws FormatException if the input contains too many errors
- */
- private CorrectedBitsRXingResult correctBits(boolean[] rawbits) throws FormatException {
- GenericGF gf;
- int codewordSize;
-
- if (ddata.getNbLayers() <= 2) {
- codewordSize = 6;
- gf = GenericGF.AZTEC_DATA_6;
- } else if (ddata.getNbLayers() <= 8) {
- codewordSize = 8;
- gf = GenericGF.AZTEC_DATA_8;
- } else if (ddata.getNbLayers() <= 22) {
- codewordSize = 10;
- gf = GenericGF.AZTEC_DATA_10;
- } else {
- codewordSize = 12;
- gf = GenericGF.AZTEC_DATA_12;
- }
-
- int numDataCodewords = ddata.getNbDatablocks();
- int numCodewords = rawbits.length / codewordSize;
- if (numCodewords < numDataCodewords) {
- throw FormatException.getFormatInstance();
- }
- int offset = rawbits.length % codewordSize;
-
- int[] dataWords = new int[numCodewords];
- for (int i = 0; i < numCodewords; i++, offset += codewordSize) {
- dataWords[i] = readCode(rawbits, offset, codewordSize);
- }
-
- try {
- ReedSolomonDecoder rsDecoder = new ReedSolomonDecoder(gf);
- rsDecoder.decode(dataWords, numCodewords - numDataCodewords);
- } catch (ReedSolomonException ex) {
- throw FormatException.getFormatInstance(ex);
- }
-
- // Now perform the unstuffing operation.
- // First, count how many bits are going to be thrown out as stuffing
- int mask = (1 << codewordSize) - 1;
- int stuffedBits = 0;
- for (int i = 0; i < numDataCodewords; i++) {
- int dataWord = dataWords[i];
- if (dataWord == 0 || dataWord == mask) {
- throw FormatException.getFormatInstance();
- } else if (dataWord == 1 || dataWord == mask - 1) {
- stuffedBits++;
- }
- }
- // Now, actually unpack the bits and remove the stuffing
- boolean[] correctedBits = new boolean[numDataCodewords * codewordSize - stuffedBits];
- int index = 0;
- for (int i = 0; i < numDataCodewords; i++) {
- int dataWord = dataWords[i];
- if (dataWord == 1 || dataWord == mask - 1) {
- // next codewordSize-1 bits are all zeros or all ones
- Arrays.fill(correctedBits, index, index + codewordSize - 1, dataWord > 1);
- index += codewordSize - 1;
- } else {
- for (int bit = codewordSize - 1; bit >= 0; --bit) {
- correctedBits[index++] = (dataWord & (1 << bit)) != 0;
- }
- }
- }
-
- return new CorrectedBitsRXingResult(correctedBits, 100 * (numCodewords - numDataCodewords) / numCodewords);
- }
-
- /**
- * Gets the array of bits from an Aztec Code matrix
- *
- * @return the array of bits
- */
- private boolean[] extractBits(BitMatrix matrix) {
- boolean compact = ddata.isCompact();
- int layers = ddata.getNbLayers();
- int baseMatrixSize = (compact ? 11 : 14) + layers * 4; // not including alignment lines
- int[] alignmentMap = new int[baseMatrixSize];
- boolean[] rawbits = new boolean[totalBitsInLayer(layers, compact)];
-
- if (compact) {
- for (int i = 0; i < alignmentMap.length; i++) {
- alignmentMap[i] = i;
- }
- } else {
- int matrixSize = baseMatrixSize + 1 + 2 * ((baseMatrixSize / 2 - 1) / 15);
- int origCenter = baseMatrixSize / 2;
- int center = matrixSize / 2;
- for (int i = 0; i < origCenter; i++) {
- int newOffset = i + i / 15;
- alignmentMap[origCenter - i - 1] = center - newOffset - 1;
- alignmentMap[origCenter + i] = center + newOffset + 1;
- }
- }
- for (int i = 0, rowOffset = 0; i < layers; i++) {
- int rowSize = (layers - i) * 4 + (compact ? 9 : 12);
- // The top-left most point of this layer is (not including alignment lines)
- int low = i * 2;
- // The bottom-right most point of this layer is (not including alignment lines)
- int high = baseMatrixSize - 1 - low;
- // We pull bits from the two 2 x rowSize columns and two rowSize x 2 rows
- for (int j = 0; j < rowSize; j++) {
- int columnOffset = j * 2;
- for (int k = 0; k < 2; k++) {
- // left column
- rawbits[rowOffset + columnOffset + k] =
- matrix.get(alignmentMap[low + k], alignmentMap[low + j]);
- // bottom row
- rawbits[rowOffset + 2 * rowSize + columnOffset + k] =
- matrix.get(alignmentMap[low + j], alignmentMap[high - k]);
- // right column
- rawbits[rowOffset + 4 * rowSize + columnOffset + k] =
- matrix.get(alignmentMap[high - k], alignmentMap[high - j]);
- // top row
- rawbits[rowOffset + 6 * rowSize + columnOffset + k] =
- matrix.get(alignmentMap[high - j], alignmentMap[low + k]);
- }
- }
- rowOffset += rowSize * 8;
- }
- return rawbits;
- }
-
- /**
- * Reads a code of given length and at given index in an array of bits
- */
- private static int readCode(boolean[] rawbits, int startIndex, int length) {
- int res = 0;
- for (int i = startIndex; i < startIndex + length; i++) {
- res <<= 1;
- if (rawbits[i]) {
- res |= 0x01;
- }
- }
- return res;
- }
-
- /**
- * Reads a code of length 8 in an array of bits, padding with zeros
- */
- private static byte readByte(boolean[] rawbits, int startIndex) {
- int n = rawbits.length - startIndex;
- if (n >= 8) {
- return (byte) readCode(rawbits, startIndex, 8);
- }
- return (byte) (readCode(rawbits, startIndex, n) << (8 - n));
- }
-
- /**
- * Packs a bit array into bytes, most significant bit first
- */
- static byte[] convertBoolArrayToByteArray(boolean[] boolArr) {
- byte[] byteArr = new byte[(boolArr.length + 7) / 8];
- for (int i = 0; i < byteArr.length; i++) {
- byteArr[i] = readByte(boolArr, 8 * i);
- }
- return byteArr;
- }
-
- private static int totalBitsInLayer(int layers, boolean compact) {
- return ((compact ? 88 : 112) + 16 * layers) * layers;
- }
-}
diff --git a/src/aztec/detector/Detector.java b/src/aztec/detector.rs
similarity index 94%
rename from src/aztec/detector/Detector.java
rename to src/aztec/detector.rs
index b5e5dbd..3bf829b 100644
--- a/src/aztec/detector/Detector.java
+++ b/src/aztec/detector.rs
@@ -14,18 +14,27 @@
* limitations under the License.
*/
-package com.google.zxing.aztec.detector;
+// package com.google.zxing.aztec.detector;
-import com.google.zxing.NotFoundException;
-import com.google.zxing.RXingResultPoint;
-import com.google.zxing.aztec.AztecDetectorRXingResult;
-import com.google.zxing.common.BitMatrix;
-import com.google.zxing.common.GridSampler;
-import com.google.zxing.common.detector.MathUtils;
-import com.google.zxing.common.detector.WhiteRectangleDetector;
-import com.google.zxing.common.reedsolomon.GenericGF;
-import com.google.zxing.common.reedsolomon.ReedSolomonDecoder;
-import com.google.zxing.common.reedsolomon.ReedSolomonException;
+// import com.google.zxing.NotFoundException;
+// import com.google.zxing.RXingResultPoint;
+// import com.google.zxing.aztec.AztecDetectorRXingResult;
+// import com.google.zxing.common.BitMatrix;
+// import com.google.zxing.common.GridSampler;
+// import com.google.zxing.common.detector.MathUtils;
+// import com.google.zxing.common.detector.WhiteRectangleDetector;
+// import com.google.zxing.common.reedsolomon.GenericGF;
+// import com.google.zxing.common.reedsolomon.ReedSolomonDecoder;
+// import com.google.zxing.common.reedsolomon.ReedSolomonException;
+
+use crate::common::BitMatrix;
+
+const EXPECTED_CORNER_BITS : [u16;4]= [
+ 0xee0, // 07340 XXX .XX X.. ...
+ 0x1dc, // 00734 ... XXX .XX X..
+ 0x83b, // 04073 X.. ... XXX .XX
+ 0x707, // 03407 .XX X.. ... XXX
+];
/**
* Encapsulates logic that can detect an Aztec Code in an image, even if the Aztec Code
@@ -34,25 +43,27 @@ import com.google.zxing.common.reedsolomon.ReedSolomonException;
* @author David Olivier
* @author Frank Yellin
*/
-public final class Detector {
+pub struct Detector {
+ image:BitMatrix,
- private static final int[] EXPECTED_CORNER_BITS = {
- 0xee0, // 07340 XXX .XX X.. ...
- 0x1dc, // 00734 ... XXX .XX X..
- 0x83b, // 04073 X.. ... XXX .XX
- 0x707, // 03407 .XX X.. ... XXX
- };
+ compact:bool,
+ nbLayers:u32,
+ nbDataBlocks:u32,
+ nbCenterLayers:u32,
+ shift:u32,
+}
- private final BitMatrix image;
+impl Detector {
- private boolean compact;
- private int nbLayers;
- private int nbDataBlocks;
- private int nbCenterLayers;
- private int shift;
-
- public Detector(BitMatrix image) {
- this.image = image;
+ pub fn new( image:BitMatrix) -> Self{
+ Self{
+ image,
+ compact: false,
+ nbLayers: 0,
+ nbDataBlocks: 0,
+ nbCenterLayers: 0,
+ shift: 0,
+ }
}
public AztecDetectorRXingResult detect() throws NotFoundException {
diff --git a/src/aztec/mod.rs b/src/aztec/mod.rs
new file mode 100644
index 0000000..5017799
--- /dev/null
+++ b/src/aztec/mod.rs
@@ -0,0 +1,10 @@
+mod AztecDetectorResult;
+pub mod decoder;
+// pub mod detector;
+
+#[cfg(test)]
+mod DecoderTest;
+// #[cfg(test)]
+// mod EncoderTest;
+
+mod shared_test_methods;
\ No newline at end of file
diff --git a/src/aztec/shared_test_methods.rs b/src/aztec/shared_test_methods.rs
new file mode 100644
index 0000000..1ba5823
--- /dev/null
+++ b/src/aztec/shared_test_methods.rs
@@ -0,0 +1,32 @@
+use regex::Regex;
+
+use crate::common::BitArray;
+
+const SPACES :&str= "\\s+";
+const DOTX : &str = "[^.X]";
+
+pub fn toBitArray( bits:&str) -> BitArray{
+ let mut ba_in = BitArray::new();
+ let replacer_regex = Regex::new(DOTX).unwrap();
+ let str = replacer_regex.replace_all(bits, "");
+ for aStr in str.chars() {
+ // for (char aStr : str) {
+ ba_in.appendBit(aStr == 'X');
+ }
+
+ ba_in
+ }
+
+ pub fn toBooleanArray( bitArray:&BitArray) ->Vec{
+ let mut result = vec![false;bitArray.getSize()];
+ for i in 0..result.len() {
+ // for (int i = 0; i < result.length; i++) {
+ result[i] = bitArray.get(i);
+ }
+ result
+ }
+
+ pub fn stripSpace( s:&str) -> String{
+ let replacer_regex = Regex::new(SPACES).unwrap();
+ replacer_regex.replace_all(s, "").to_string()
+ }
\ No newline at end of file
diff --git a/src/common/mod.rs b/src/common/mod.rs
index 2beb92e..02eab35 100644
--- a/src/common/mod.rs
+++ b/src/common/mod.rs
@@ -719,27 +719,17 @@ impl fmt::Display for BitArray {
*
* @author Sean Owen
*/
-pub struct DetectorRXingResult {
- bits: BitMatrix,
- points: Vec,
+pub trait DetectorRXingResult {
+
+ fn getBits(&self) -> &BitMatrix;
+
+ fn getPoints(&self) -> &Vec;
}
-impl DetectorRXingResult {
- pub fn new(bits: BitMatrix, points: Vec) -> Self {
- Self {
- bits: bits,
- points: points,
- }
- }
-
- pub fn getBits(&self) -> &BitMatrix {
- return &self.bits;
- }
-
- pub fn getPoints(&self) -> &Vec {
- return &self.points;
- }
-}
+// pub struct DetectorRXingResult {
+// bits: BitMatrix,
+// points: Vec,
+// }
/*
* Copyright 2007 ZXing authors
diff --git a/src/lib.rs b/src/lib.rs
index 9218d5f..2661ab4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,6 +1,7 @@
mod common;
mod exceptions;
mod client;
+mod aztec;
#[cfg(feature="image")]
mod BufferedImageLuminanceSource;
@@ -840,7 +841,7 @@ impl PartialEq for RXingResultPoint {
}
impl Eq for RXingResultPoint {}
impl RXingResultPoint {
- pub fn new(x: f32, y: f32) -> Self {
+ pub const fn new(x: f32, y: f32) -> Self {
Self { x, y }
}