diff --git a/src/oned/UPCEReader.java b/src/oned/UPCEReader.java
deleted file mode 100644
index ab8e39c..0000000
--- a/src/oned/UPCEReader.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright 2008 ZXing authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.zxing.oned;
-
-import com.google.zxing.BarcodeFormat;
-import com.google.zxing.FormatException;
-import com.google.zxing.NotFoundException;
-import com.google.zxing.common.BitArray;
-
-/**
- *
Implements decoding of the UPC-E format.
- * This is a great reference for
- * UPC-E information.
- *
- * @author Sean Owen
- */
-public final class UPCEReader extends UPCEANReader {
-
- /**
- * The pattern that marks the middle, and end, of a UPC-E pattern.
- * There is no "second half" to a UPC-E barcode.
- */
- private static final int[] MIDDLE_END_PATTERN = {1, 1, 1, 1, 1, 1};
-
- // For an UPC-E barcode, the final digit is represented by the parities used
- // to encode the middle six digits, according to the table below.
- //
- // Parity of next 6 digits
- // Digit 0 1 2 3 4 5
- // 0 Even Even Even Odd Odd Odd
- // 1 Even Even Odd Even Odd Odd
- // 2 Even Even Odd Odd Even Odd
- // 3 Even Even Odd Odd Odd Even
- // 4 Even Odd Even Even Odd Odd
- // 5 Even Odd Odd Even Even Odd
- // 6 Even Odd Odd Odd Even Even
- // 7 Even Odd Even Odd Even Odd
- // 8 Even Odd Even Odd Odd Even
- // 9 Even Odd Odd Even Odd Even
- //
- // The encoding is represented by the following array, which is a bit pattern
- // using Odd = 0 and Even = 1. For example, 5 is represented by:
- //
- // Odd Even Even Odd Odd Even
- // in binary:
- // 0 1 1 0 0 1 == 0x19
- //
-
- /**
- * See {@link #L_AND_G_PATTERNS}; these values similarly represent patterns of
- * even-odd parity encodings of digits that imply both the number system (0 or 1)
- * used, and the check digit.
- */
- static final int[][] NUMSYS_AND_CHECK_DIGIT_PATTERNS = {
- {0x38, 0x34, 0x32, 0x31, 0x2C, 0x26, 0x23, 0x2A, 0x29, 0x25},
- {0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A}
- };
-
- private final int[] decodeMiddleCounters;
-
- public UPCEReader() {
- decodeMiddleCounters = new int[4];
- }
-
- @Override
- protected int decodeMiddle(BitArray row, int[] startRange, StringBuilder result)
- throws NotFoundException {
- int[] counters = decodeMiddleCounters;
- counters[0] = 0;
- counters[1] = 0;
- counters[2] = 0;
- counters[3] = 0;
- int end = row.getSize();
- int rowOffset = startRange[1];
-
- int lgPatternFound = 0;
-
- for (int x = 0; x < 6 && rowOffset < end; x++) {
- int bestMatch = decodeDigit(row, counters, rowOffset, L_AND_G_PATTERNS);
- result.append((char) ('0' + bestMatch % 10));
- for (int counter : counters) {
- rowOffset += counter;
- }
- if (bestMatch >= 10) {
- lgPatternFound |= 1 << (5 - x);
- }
- }
-
- determineNumSysAndCheckDigit(result, lgPatternFound);
-
- return rowOffset;
- }
-
- @Override
- protected int[] decodeEnd(BitArray row, int endStart) throws NotFoundException {
- return findGuardPattern(row, endStart, true, MIDDLE_END_PATTERN);
- }
-
- @Override
- protected boolean checkChecksum(String s) throws FormatException {
- return super.checkChecksum(convertUPCEtoUPCA(s));
- }
-
- private static void determineNumSysAndCheckDigit(StringBuilder resultString, int lgPatternFound)
- throws NotFoundException {
-
- for (int numSys = 0; numSys <= 1; numSys++) {
- for (int d = 0; d < 10; d++) {
- if (lgPatternFound == NUMSYS_AND_CHECK_DIGIT_PATTERNS[numSys][d]) {
- resultString.insert(0, (char) ('0' + numSys));
- resultString.append((char) ('0' + d));
- return;
- }
- }
- }
- throw NotFoundException.getNotFoundInstance();
- }
-
- @Override
- BarcodeFormat getBarcodeFormat() {
- return BarcodeFormat.UPC_E;
- }
-
- /**
- * Expands a UPC-E value back into its full, equivalent UPC-A code value.
- *
- * @param upce UPC-E code as string of digits
- * @return equivalent UPC-A code as string of digits
- */
- public static String convertUPCEtoUPCA(String upce) {
- char[] upceChars = new char[6];
- upce.getChars(1, 7, upceChars, 0);
- StringBuilder result = new StringBuilder(12);
- result.append(upce.charAt(0));
- char lastChar = upceChars[5];
- switch (lastChar) {
- case '0':
- case '1':
- case '2':
- result.append(upceChars, 0, 2);
- result.append(lastChar);
- result.append("0000");
- result.append(upceChars, 2, 3);
- break;
- case '3':
- result.append(upceChars, 0, 3);
- result.append("00000");
- result.append(upceChars, 3, 2);
- break;
- case '4':
- result.append(upceChars, 0, 4);
- result.append("00000");
- result.append(upceChars[4]);
- break;
- default:
- result.append(upceChars, 0, 5);
- result.append("0000");
- result.append(lastChar);
- break;
- }
- // Only append check digit in conversion if supplied
- if (upce.length() >= 8) {
- result.append(upce.charAt(7));
- }
- return result.toString();
- }
-
-}
diff --git a/src/oned/mod.rs b/src/oned/mod.rs
index df85e96..4a4fc3e 100644
--- a/src/oned/mod.rs
+++ b/src/oned/mod.rs
@@ -43,3 +43,6 @@ pub use ean_13_reader::*;
mod upc_a_reader;
pub use upc_a_reader::*;
+
+mod upc_e_reader;
+pub use upc_e_reader::*;
diff --git a/src/oned/upc_e_reader.rs b/src/oned/upc_e_reader.rs
new file mode 100644
index 0000000..1c7a185
--- /dev/null
+++ b/src/oned/upc_e_reader.rs
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2008 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use super::{OneDReader, UPCEANReader, L_AND_G_PATTERNS};
+use crate::{BarcodeFormat, Exceptions};
+use one_d_reader_derive::{EANReader, OneDReader};
+
+/**
+ * Implements decoding of the UPC-E format.
+ * This is a great reference for
+ * UPC-E information.
+ *
+ * @author Sean Owen
+ */
+#[derive(OneDReader, EANReader)]
+pub struct UPCEReader;
+
+impl UPCEANReader for UPCEReader {
+ fn getBarcodeFormat(&self) -> crate::BarcodeFormat {
+ BarcodeFormat::UPC_E
+ }
+
+ fn decodeMiddle(
+ &self,
+ row: &crate::common::BitArray,
+ startRange: &[usize; 2],
+ resultString: &mut String,
+ ) -> Result {
+ let mut counters = [0_u32; 4]; //decodeMiddleCounters;
+ // counters[0] = 0;
+ // counters[1] = 0;
+ // counters[2] = 0;
+ // counters[3] = 0;
+ let end = row.getSize();
+ let mut rowOffset = startRange[1];
+
+ let mut lgPatternFound = 0;
+
+ let mut x = 0;
+ while x < 6 && rowOffset < end {
+ // for (int x = 0; x < 6 && rowOffset < end; x++) {
+ let bestMatch = Self::decodeDigit(row, &mut counters, rowOffset, &L_AND_G_PATTERNS)?;
+ resultString.push(char::from_u32('0' as u32 + bestMatch as u32 % 10).unwrap());
+ // for (int counter : counters) {
+ // rowOffset += counter;
+ // }
+ rowOffset += counters.iter().sum::() as usize;
+
+ if bestMatch >= 10 {
+ lgPatternFound |= 1 << (5 - x);
+ }
+
+ x += 1;
+ }
+
+ Self::determineNumSysAndCheckDigit(resultString, lgPatternFound)?;
+
+ Ok(rowOffset)
+ }
+
+ fn checkChecksum(&self, s: &str) -> Result {
+ Self::checkStandardUPCEANChecksum(&convertUPCEtoUPCA(s))
+ }
+
+ fn decodeEnd(row: &crate::common::BitArray, endStart: usize) -> Result<[usize; 2], Exceptions>
+ where
+ Self: Sized,
+ {
+ Self::findGuardPattern(row, endStart, true, &Self::MIDDLE_END_PATTERN)
+ }
+}
+
+impl Default for UPCEReader {
+ fn default() -> Self {
+ Self {}
+ }
+}
+
+impl UPCEReader {
+ /**
+ * The pattern that marks the middle, and end, of a UPC-E pattern.
+ * There is no "second half" to a UPC-E barcode.
+ */
+ const MIDDLE_END_PATTERN: [u32; 6] = [1, 1, 1, 1, 1, 1];
+
+ // For an UPC-E barcode, the final digit is represented by the parities used
+ // to encode the middle six digits, according to the table below.
+ //
+ // Parity of next 6 digits
+ // Digit 0 1 2 3 4 5
+ // 0 Even Even Even Odd Odd Odd
+ // 1 Even Even Odd Even Odd Odd
+ // 2 Even Even Odd Odd Even Odd
+ // 3 Even Even Odd Odd Odd Even
+ // 4 Even Odd Even Even Odd Odd
+ // 5 Even Odd Odd Even Even Odd
+ // 6 Even Odd Odd Odd Even Even
+ // 7 Even Odd Even Odd Even Odd
+ // 8 Even Odd Even Odd Odd Even
+ // 9 Even Odd Odd Even Odd Even
+ //
+ // The encoding is represented by the following array, which is a bit pattern
+ // using Odd = 0 and Even = 1. For example, 5 is represented by:
+ //
+ // Odd Even Even Odd Odd Even
+ // in binary:
+ // 0 1 1 0 0 1 == 0x19
+ //
+
+ /**
+ * See {@link #L_AND_G_PATTERNS}; these values similarly represent patterns of
+ * even-odd parity encodings of digits that imply both the number system (0 or 1)
+ * used, and the check digit.
+ */
+ const NUMSYS_AND_CHECK_DIGIT_PATTERNS: [[usize; 10]; 2] = [
+ [0x38, 0x34, 0x32, 0x31, 0x2C, 0x26, 0x23, 0x2A, 0x29, 0x25],
+ [0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A],
+ ];
+
+ fn determineNumSysAndCheckDigit(
+ resultString: &mut String,
+ lgPatternFound: usize,
+ ) -> Result<(), Exceptions> {
+ for numSys in 0..=1 {
+ // for (int numSys = 0; numSys <= 1; numSys++) {
+ for d in 0..10 {
+ // for (int d = 0; d < 10; d++) {
+ if lgPatternFound == Self::NUMSYS_AND_CHECK_DIGIT_PATTERNS[numSys][d] {
+ resultString.insert(0, char::from_u32('0' as u32 + numSys as u32).unwrap());
+ resultString.push(char::from_u32('0' as u32 + d as u32).unwrap());
+ return Ok(());
+ }
+ }
+ }
+ return Err(Exceptions::NotFoundException("".to_owned()));
+ }
+}
+
+/**
+ * Expands a UPC-E value back into its full, equivalent UPC-A code value.
+ *
+ * @param upce UPC-E code as string of digits
+ * @return equivalent UPC-A code as string of digits
+ */
+pub fn convertUPCEtoUPCA(upce: &str) -> String {
+ let upceChars = &upce[1..8]; //['0';6];//new char[6];
+ //upce.getChars(1, 7, upceChars, 0);
+ let mut result = String::with_capacity(12); //new StringBuilder(12);
+ result.push(upce.chars().nth(0).unwrap());
+ let lastChar = upceChars.chars().nth(5).unwrap();
+ match lastChar {
+ '0' | '1' | '2' => {
+ result.push_str(&upceChars[0..2]);
+ // result.push(upceChars, 0, 2);
+ result.push(lastChar);
+ result.push_str("0000");
+ result.push_str(&upceChars[2..3 + 2]);
+ }
+ '3' => {
+ result.push_str(&upceChars[0..3]);
+ result.push_str("00000");
+ result.push_str(&upceChars[3..2 + 3]);
+ }
+ '4' => {
+ result.push_str(&upceChars[0..4]);
+ result.push_str("00000");
+ result.push(upceChars.chars().nth(4).unwrap());
+ }
+ _ => {
+ result.push_str(&upceChars[0..5]);
+ result.push_str("0000");
+ result.push(lastChar);
+ }
+ }
+ // Only append check digit in conversion if supplied
+ if upce.chars().count() >= 8 {
+ result.push(upce.chars().nth(7).unwrap());
+ }
+
+ result
+}
diff --git a/tests/UPCEANExtensionBlackBox1TestCase.java b/tests/UPCEANExtensionBlackBox1TestCase.java
deleted file mode 100644
index 020bba1..0000000
--- a/tests/UPCEANExtensionBlackBox1TestCase.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2008 ZXing authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.zxing.oned;
-
-import com.google.zxing.BarcodeFormat;
-import com.google.zxing.MultiFormatReader;
-import com.google.zxing.common.AbstractBlackBoxTestCase;
-
-/**
- * @author Sean Owen
- */
-public final class UPCEANExtensionBlackBox1TestCase extends AbstractBlackBoxTestCase {
-
- public UPCEANExtensionBlackBox1TestCase() {
- super("src/test/resources/blackbox/upcean-extension-1", new MultiFormatReader(), BarcodeFormat.EAN_13);
- addTest(2, 2, 0.0f);
- }
-
-}
\ No newline at end of file
diff --git a/tests/UPCEBlackBox1TestCase.java b/tests/UPCEBlackBox1TestCase.java
deleted file mode 100644
index a36fa0b..0000000
--- a/tests/UPCEBlackBox1TestCase.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2008 ZXing authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.zxing.oned;
-
-import com.google.zxing.BarcodeFormat;
-import com.google.zxing.MultiFormatReader;
-import com.google.zxing.common.AbstractBlackBoxTestCase;
-
-/**
- * @author Sean Owen
- */
-public final class UPCEBlackBox1TestCase extends AbstractBlackBoxTestCase {
-
- public UPCEBlackBox1TestCase() {
- super("src/test/resources/blackbox/upce-1", new MultiFormatReader(), BarcodeFormat.UPC_E);
- addTest(3, 3, 0.0f);
- addTest(3, 3, 180.0f);
- }
-
-}
\ No newline at end of file
diff --git a/tests/UPCEBlackBox2TestCase.java b/tests/UPCEBlackBox2TestCase.java
deleted file mode 100644
index 49d7c17..0000000
--- a/tests/UPCEBlackBox2TestCase.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2008 ZXing authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.zxing.oned;
-
-import com.google.zxing.BarcodeFormat;
-import com.google.zxing.MultiFormatReader;
-import com.google.zxing.common.AbstractBlackBoxTestCase;
-
-/**
- * @author dswitkin@google.com (Daniel Switkin)
- */
-public final class UPCEBlackBox2TestCase extends AbstractBlackBoxTestCase {
-
- public UPCEBlackBox2TestCase() {
- super("src/test/resources/blackbox/upce-2", new MultiFormatReader(), BarcodeFormat.UPC_E);
- addTest(31, 35, 0, 1, 0.0f);
- addTest(31, 35, 1, 1, 180.0f);
- }
-
-}
diff --git a/tests/UPCEBlackBox3ReflectiveTestCase.java b/tests/UPCEBlackBox3ReflectiveTestCase.java
deleted file mode 100644
index bbf522a..0000000
--- a/tests/UPCEBlackBox3ReflectiveTestCase.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2008 ZXing authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.zxing.oned;
-
-import com.google.zxing.BarcodeFormat;
-import com.google.zxing.MultiFormatReader;
-import com.google.zxing.common.AbstractBlackBoxTestCase;
-
-/**
- * @author dswitkin@google.com (Daniel Switkin)
- */
-public final class UPCEBlackBox3ReflectiveTestCase extends AbstractBlackBoxTestCase {
-
- public UPCEBlackBox3ReflectiveTestCase() {
- super("src/test/resources/blackbox/upce-3", new MultiFormatReader(), BarcodeFormat.UPC_E);
- addTest(6, 8, 0.0f);
- addTest(6, 8, 180.0f);
- }
-
-}
diff --git a/tests/upc_e_blackbox_tests.rs b/tests/upc_e_blackbox_tests.rs
new file mode 100644
index 0000000..e6266e0
--- /dev/null
+++ b/tests/upc_e_blackbox_tests.rs
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2008 ZXing authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use rxing::{
+ oned::{EAN13Reader, UPCEReader},
+ BarcodeFormat, MultiFormatReader,
+};
+
+mod common;
+
+/**
+ * @author Sean Owen
+ */
+#[test]
+fn upceblack_box1_test_case() {
+ let mut tester = common::AbstractBlackBoxTestCase::new(
+ "test_resources/blackbox/upce-1",
+ // MultiFormatReader::default(),
+ UPCEReader::default(),
+ BarcodeFormat::UPC_E,
+ );
+
+ // super("src/test/resources/blackbox/upce-1", new MultiFormatReader(), BarcodeFormat.UPC_E);
+ tester.add_test(3, 3, 0.0);
+ tester.add_test(3, 3, 180.0);
+
+ tester.test_black_box()
+}
+
+/**
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+#[test]
+fn upceblack_box2_test_case() {
+ let mut tester = common::AbstractBlackBoxTestCase::new(
+ "test_resources/blackbox/upce-2",
+ // MultiFormatReader::default(),
+ UPCEReader::default(),
+ BarcodeFormat::UPC_E,
+ );
+
+ // super("src/test/resources/blackbox/upce-2", new MultiFormatReader(), BarcodeFormat.UPC_E);
+ tester.add_test_complex(31, 35, 0, 1, 0.0);
+ tester.add_test_complex(31, 35, 1, 1, 180.0);
+
+ tester.test_black_box()
+}
+
+/**
+ * @author dswitkin@google.com (Daniel Switkin)
+ */
+#[test]
+fn upceblack_box3_reflective_test_case() {
+ let mut tester = common::AbstractBlackBoxTestCase::new(
+ "test_resources/blackbox/upce-3",
+ // MultiFormatReader::default(),
+ UPCEReader::default(),
+ BarcodeFormat::UPC_E,
+ );
+
+ // super("src/test/resources/blackbox/upce-3", new MultiFormatReader(), BarcodeFormat.UPC_E);
+ tester.add_test(6, 8, 0.0);
+ tester.add_test(6, 8, 180.0);
+
+ tester.test_black_box()
+}