diff --git a/src/decode_hints.rs b/src/decode_hints.rs index dbc2885..9359915 100644 --- a/src/decode_hints.rs +++ b/src/decode_hints.rs @@ -121,6 +121,12 @@ pub enum DecodeHintType { */ #[cfg(feature = "allow_forced_iso_ied_18004_compliance")] QR_ASSUME_SPEC_CONFORM_INPUT, + + /* + * Will translate the ASCII values parsed by the Telepen reader into the Telepen Numeric form. + */ + TELEPEN_AS_NUMERIC, + /* * Data type the hint is expecting. * Among the possible values the {@link Void} stands out as being used for @@ -231,4 +237,9 @@ pub enum DecodeHintValue { */ #[cfg(feature = "allow_forced_iso_ied_18004_compliance")] QrAssumeSpecConformInput(bool), + + /** + * Translate the ASCII values parsed by the Telepen reader into the Telepen Numeric form; use {@link Boolean#TRUE}. + */ + TelepenAsNumeric(bool), } diff --git a/src/oned/telepen_common.rs b/src/oned/telepen_common.rs index 70a3e41..bd5ac4a 100644 --- a/src/oned/telepen_common.rs +++ b/src/oned/telepen_common.rs @@ -1,6 +1,7 @@ -pub struct TelepenCommon; +pub mod TelepenCommon { + use crate::Exceptions; + use crate::common::Result; -impl TelepenCommon { pub fn calculate_checksum(contents: &str) -> char { let mut sum = 0; @@ -17,4 +18,49 @@ impl TelepenCommon { 0 as char }; } + + pub fn ascii_to_numeric(contents: &str) -> String { + let mut number = String::new(); + + for i in 0 .. contents.len() { + let temp = contents.chars().nth(i).unwrap() as u32; + + if temp >= 27 { + number.push_str(&(temp - 27).to_string()); + } + else { + number.push_str(&(temp - 17).to_string()); + } + } + + return number; + } + + pub fn numeric_to_ascii(contents: &str) -> Result { + if contents.len() % 2 != 0 { + return Err(Exceptions::illegal_argument_with("Input must contain an even number of characters.")); + } + + let mut ascii = String::new(); + let mut i = 0; + + while i < contents.len() { + let first = contents.chars().nth(i).unwrap() as u8; + let second = contents.chars().nth(i + 1).unwrap() as u8; + + if second == 88 && first >= 48 && first <= 57 { + ascii.push((17 + first - 48) as char); + } + else if second >= 48 && second <= 57 && first >= 48 && first <= 57 { + ascii.push((27 + (first - 48) * 10 + (second - 48)) as char); + } + else { + return Err(Exceptions::illegal_argument_with(format!("Input contains an invalid character around position {}.", i.to_string()))); + } + + i += 2; + } + + return Ok(ascii); + } } \ No newline at end of file diff --git a/src/oned/telepen_reader.rs b/src/oned/telepen_reader.rs index 895c10b..c3a04ba 100644 --- a/src/oned/telepen_reader.rs +++ b/src/oned/telepen_reader.rs @@ -19,8 +19,9 @@ use rxing_one_d_proc_derive::OneDReader; use crate::common::{BitArray, Result}; use crate::Exceptions; use crate::RXingResult; +use crate::DecodeHintValue; use crate::{point_f, BarcodeFormat}; -use crate::oned::telepen_common::TelepenCommon; +use crate::oned::TelepenCommon; use bit_reverse::ParallelReverse; use super::OneDReader; @@ -51,7 +52,7 @@ impl OneDReader for TelepenReader { &mut self, rowNumber: u32, row: &crate::common::BitArray, - _hints: &crate::DecodingHintDictionary, + hints: &crate::DecodingHintDictionary, ) -> Result { self.counters.fill(0); self.setCounters(row, (row.get_size() as f32 * 0.001) as u32)?; @@ -214,7 +215,7 @@ impl OneDReader for TelepenReader { // Content bytes let contentBytes = bytes[1 .. byteLength - 2].to_vec(); - let contentString = String::from_utf8_lossy(&contentBytes); + let mut contentString = String::from_utf8_lossy(&contentBytes).to_string(); // Penultimate byte is a block check character. let check = bytes[byteLength - 2]; @@ -226,6 +227,13 @@ impl OneDReader for TelepenReader { return Err(Exceptions::NOT_FOUND); } + if matches!( + hints.get(&DecodeHintType::TELEPEN_AS_NUMERIC), + Some(DecodeHintValue::TelepenAsNumeric(true)) + ) { + contentString = TelepenCommon::ascii_to_numeric(&contentString); + } + let mut runningCount = 0; runningCount += self.counters.iter().take(startOffset).sum::(); let left: f32 = runningCount as f32; diff --git a/src/oned/telepen_writer.rs b/src/oned/telepen_writer.rs index 88bd777..3f9dae1 100644 --- a/src/oned/telepen_writer.rs +++ b/src/oned/telepen_writer.rs @@ -18,7 +18,7 @@ use rxing_one_d_proc_derive::OneDWriter; use regex::Regex; use crate::common::Result; use crate::BarcodeFormat; -use crate::oned::telepen_common::TelepenCommon; +use crate::oned::TelepenCommon; use super::OneDimensionalCodeWriter; @@ -43,7 +43,7 @@ impl OneDimensionalCodeWriter for TelepenWriter { // Content for c in contents.chars() { - if c as u8 > 127 { + if c as u32 > 127 { return Err(Exceptions::illegal_argument_with(format!( "Telepen only supports ASCII characters." ))); @@ -198,6 +198,12 @@ mod TelepenWriterTestCase { use super::TelepenWriter; + #[test] + #[should_panic] + fn testAsciiOnly() { + encode("АБВГДЕЁЖ"); + } + #[test] fn testEncode() { doTest( diff --git a/test_resources/blackbox/telepen-2/01.png b/test_resources/blackbox/telepen-2/01.png new file mode 100644 index 0000000..4204cac Binary files /dev/null and b/test_resources/blackbox/telepen-2/01.png differ diff --git a/test_resources/blackbox/telepen-2/01.txt b/test_resources/blackbox/telepen-2/01.txt new file mode 100644 index 0000000..6a537b5 --- /dev/null +++ b/test_resources/blackbox/telepen-2/01.txt @@ -0,0 +1 @@ +1234567890 \ No newline at end of file diff --git a/tests/telepen_blackbox_1_test_case.rs b/tests/telepen_blackbox_1_test_case.rs index e61d57c..6591b94 100644 --- a/tests/telepen_blackbox_1_test_case.rs +++ b/tests/telepen_blackbox_1_test_case.rs @@ -14,7 +14,7 @@ * limitations under the License. */ -use rxing::{oned::TelepenReader, BarcodeFormat}; +use rxing::{oned::TelepenReader, BarcodeFormat, oned::TelepenCommon}; mod common; @@ -22,7 +22,7 @@ mod common; * @author Chris Wood */ #[test] -fn telepen_black_box1_test_case() { +fn telepen_alpha_test_case() { const NUMTESTS: u32 = 5; let mut tester = common::AbstractBlackBoxTestCase::new( @@ -36,3 +36,46 @@ fn telepen_black_box1_test_case() { tester.test_black_box(); } + +#[test] +fn telepen_numeric_test_case() { + let mut tester = common::AbstractBlackBoxTestCase::new( + "test_resources/blackbox/telepen-2", + TelepenReader::new(), + BarcodeFormat::TELEPEN, + ); + + tester.add_test_complex(1, 1, 0, 0, 0.0); + tester.add_hint(rxing::DecodeHintType::TELEPEN_AS_NUMERIC, rxing::DecodeHintValue::TelepenAsNumeric(true)); + tester.ignore_pure = true; + + tester.test_black_box(); +} + +#[test] +fn telepen_checksum_test1() { + let contents = "Hello world!"; + let checksum = TelepenCommon::calculate_checksum(contents); + assert_eq!('\u{1a}', checksum); +} + +#[test] +fn telepen_checksum_test2() { + let contents = "ABC123456"; + let checksum = TelepenCommon::calculate_checksum(contents); + assert_eq!('\u{1}', checksum); +} + +#[test] +fn telepen_alpha_to_numeric_test() { + let ascii = "'=Siu"; + let result = TelepenCommon::ascii_to_numeric(ascii); + assert_eq!("1234567890", result); +} + +#[test] +fn telepen_numeric_to_ascii_test() { + let numeric = "1234567890"; + let result = TelepenCommon::numeric_to_ascii(numeric).unwrap(); + assert_eq!("'=Siu", result); +} \ No newline at end of file