From cf14fb6742c84b5ccaf0dc66c8c20da7264178b8 Mon Sep 17 00:00:00 2001 From: Henry Schimke Date: Thu, 8 Sep 2022 17:08:18 -0500 Subject: [PATCH] progress on vin, does not build --- ...INParsedResult.java => VINParsedResult.rs} | 7 +- ...stCase.java => VINParsedResultTestCase.rs} | 0 src/client/result/VINResultParser.java | 209 ------------------ src/client/result/VINResultParser.rs | 183 +++++++++++++++ src/client/result/mod.rs | 8 + 5 files changed, 196 insertions(+), 211 deletions(-) rename src/client/result/{VINParsedResult.java => VINParsedResult.rs} (95%) rename src/client/result/{VINParsedResultTestCase.java => VINParsedResultTestCase.rs} (100%) delete mode 100644 src/client/result/VINResultParser.java create mode 100644 src/client/result/VINResultParser.rs diff --git a/src/client/result/VINParsedResult.java b/src/client/result/VINParsedResult.rs similarity index 95% rename from src/client/result/VINParsedResult.java rename to src/client/result/VINParsedResult.rs index 56392ae..4a244e2 100644 --- a/src/client/result/VINParsedResult.java +++ b/src/client/result/VINParsedResult.rs @@ -15,12 +15,12 @@ */ -package com.google.zxing.client.result; +// package com.google.zxing.client.result; /** * Represents a parsed result that encodes a Vehicle Identification Number (VIN). */ -public final class VINParsedRXingResult extends ParsedRXingResult { +pub struct VINParsedRXingResult { private final String vin; private final String worldManufacturerID; @@ -32,6 +32,9 @@ public final class VINParsedRXingResult extends ParsedRXingResult { private final char plantCode; private final String sequentialNumber; + impl ParsedRXingResult for VINParsedRXingResult {} + impl VINParsedRXingResult{ + public VINParsedRXingResult(String vin, String worldManufacturerID, String vehicleDescriptorSection, diff --git a/src/client/result/VINParsedResultTestCase.java b/src/client/result/VINParsedResultTestCase.rs similarity index 100% rename from src/client/result/VINParsedResultTestCase.java rename to src/client/result/VINParsedResultTestCase.rs diff --git a/src/client/result/VINResultParser.java b/src/client/result/VINResultParser.java deleted file mode 100644 index 77aaf2b..0000000 --- a/src/client/result/VINResultParser.java +++ /dev/null @@ -1,209 +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.client.result; - -import com.google.zxing.BarcodeFormat; -import com.google.zxing.RXingResult; - -import java.util.regex.Pattern; - -/** - * Detects a result that is likely a vehicle identification number. - * - * @author Sean Owen - */ -public final class VINRXingResultParser extends RXingResultParser { - - private static final Pattern IOQ = Pattern.compile("[IOQ]"); - private static final Pattern AZ09 = Pattern.compile("[A-Z0-9]{17}"); - - @Override - public VINParsedRXingResult parse(RXingResult result) { - if (result.getBarcodeFormat() != BarcodeFormat.CODE_39) { - return null; - } - String rawText = result.getText(); - rawText = IOQ.matcher(rawText).replaceAll("").trim(); - if (!AZ09.matcher(rawText).matches()) { - return null; - } - try { - if (!checkChecksum(rawText)) { - return null; - } - String wmi = rawText.substring(0, 3); - return new VINParsedRXingResult(rawText, - wmi, - rawText.substring(3, 9), - rawText.substring(9, 17), - countryCode(wmi), - rawText.substring(3, 8), - modelYear(rawText.charAt(9)), - rawText.charAt(10), - rawText.substring(11)); - } catch (IllegalArgumentException iae) { - return null; - } - } - - private static boolean checkChecksum(CharSequence vin) { - int sum = 0; - for (int i = 0; i < vin.length(); i++) { - sum += vinPositionWeight(i + 1) * vinCharValue(vin.charAt(i)); - } - char checkChar = vin.charAt(8); - char expectedCheckChar = checkChar(sum % 11); - return checkChar == expectedCheckChar; - } - - private static int vinCharValue(char c) { - if (c >= 'A' && c <= 'I') { - return (c - 'A') + 1; - } - if (c >= 'J' && c <= 'R') { - return (c - 'J') + 1; - } - if (c >= 'S' && c <= 'Z') { - return (c - 'S') + 2; - } - if (c >= '0' && c <= '9') { - return c - '0'; - } - throw new IllegalArgumentException(); - } - - private static int vinPositionWeight(int position) { - if (position >= 1 && position <= 7) { - return 9 - position; - } - if (position == 8) { - return 10; - } - if (position == 9) { - return 0; - } - if (position >= 10 && position <= 17) { - return 19 - position; - } - throw new IllegalArgumentException(); - } - - private static char checkChar(int remainder) { - if (remainder < 10) { - return (char) ('0' + remainder); - } - if (remainder == 10) { - return 'X'; - } - throw new IllegalArgumentException(); - } - - private static int modelYear(char c) { - if (c >= 'E' && c <= 'H') { - return (c - 'E') + 1984; - } - if (c >= 'J' && c <= 'N') { - return (c - 'J') + 1988; - } - if (c == 'P') { - return 1993; - } - if (c >= 'R' && c <= 'T') { - return (c - 'R') + 1994; - } - if (c >= 'V' && c <= 'Y') { - return (c - 'V') + 1997; - } - if (c >= '1' && c <= '9') { - return (c - '1') + 2001; - } - if (c >= 'A' && c <= 'D') { - return (c - 'A') + 2010; - } - throw new IllegalArgumentException(); - } - - private static String countryCode(CharSequence wmi) { - char c1 = wmi.charAt(0); - char c2 = wmi.charAt(1); - switch (c1) { - case '1': - case '4': - case '5': - return "US"; - case '2': - return "CA"; - case '3': - if (c2 >= 'A' && c2 <= 'W') { - return "MX"; - } - break; - case '9': - if ((c2 >= 'A' && c2 <= 'E') || (c2 >= '3' && c2 <= '9')) { - return "BR"; - } - break; - case 'J': - if (c2 >= 'A' && c2 <= 'T') { - return "JP"; - } - break; - case 'K': - if (c2 >= 'L' && c2 <= 'R') { - return "KO"; - } - break; - case 'L': - return "CN"; - case 'M': - if (c2 >= 'A' && c2 <= 'E') { - return "IN"; - } - break; - case 'S': - if (c2 >= 'A' && c2 <= 'M') { - return "UK"; - } - if (c2 >= 'N' && c2 <= 'T') { - return "DE"; - } - break; - case 'V': - if (c2 >= 'F' && c2 <= 'R') { - return "FR"; - } - if (c2 >= 'S' && c2 <= 'W') { - return "ES"; - } - break; - case 'W': - return "DE"; - case 'X': - if (c2 == '0' || (c2 >= '3' && c2 <= '9')) { - return "RU"; - } - break; - case 'Z': - if (c2 >= 'A' && c2 <= 'R') { - return "IT"; - } - break; - } - return null; - } - -} diff --git a/src/client/result/VINResultParser.rs b/src/client/result/VINResultParser.rs new file mode 100644 index 0000000..4640fd4 --- /dev/null +++ b/src/client/result/VINResultParser.rs @@ -0,0 +1,183 @@ +/* + * 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.client.result; + +// import com.google.zxing.BarcodeFormat; +// import com.google.zxing.RXingResult; + +// import java.util.regex.Pattern; + +use regex::Regex; + +use crate::{RXingResult, BarcodeFormat, exceptions::Exceptions}; + +use super::ParsedClientResult; + +/** + * Detects a result that is likely a vehicle identification number. + * + * @author Sean Owen + */ +pub fn parse(result: &RXingResult) -> Option { + if result.getBarcodeFormat() != &BarcodeFormat::CODE_39 { + return None; + } + let ioq_matcher = Regex::new(IOQ).unwrap(); + let az09_matcher = Regex::new(AZ09).unwrap(); + let rawText = result.getText(); + ioq_matcher.replace_all(result.getText(), "").trim(); + // rawText = IOQ.matcher(rawText).replaceAll("").trim(); + if let None = az09_matcher.find(rawText){ + return None; + } + // if !AZ09.matcher(rawText).matches() { + // return null; + // } + let check_cs = checkChecksum(rawText); + if !check_cs { + return None; + } + let wmi = &rawText[..3]; + try { + // if (!checkChecksum(rawText)) { + // return null; + // } + // String wmi = rawText.substring(0, 3); + return new VINParsedRXingResult(rawText, + wmi, + rawText.substring(3, 9), + rawText.substring(9, 17), + countryCode(wmi), + rawText.substring(3, 8), + modelYear(rawText.charAt(9)), + rawText.charAt(10), + rawText.substring(11)); + } catch (IllegalArgumentException iae) { + return null; + } +} + + const IOQ : &'static str = "[IOQ]"; + const AZ09 :&'static str = "[A-Z0-9]{17}"; + + fn checkChecksum( vin: &str) -> Result { + let mut sum = 0; + for i in 0..vin.len() { + // for (int i = 0; i < vin.length(); i++) { + sum += vinPositionWeight(i + 1)? * vinCharValue(vin.chars().nth(i).unwrap())?; + } + let checkToChar = vin.chars().nth(8).unwrap(); + let expectedCheckChar = checkChar((sum % 11) as u8)?; + Ok( checkToChar == expectedCheckChar) + } + + fn vinCharValue( c:char)->Result { + if c >= 'A' && c <= 'I' { + return Ok((c as u8 as u32 - 'A' as u8 as u32) + 1); + } + if c >= 'J' && c <= 'R' { + return Ok((c as u8 as u32 - 'J' as u8 as u32) + 1); + } + if c >= 'S' && c <= 'Z' { + return Ok((c as u8 as u32- 'S' as u8 as u32) + 2); + } + if c >= '0' && c <= '9' { + return Ok(c as u8 as u32 - '0' as u8 as u32); + } + Err( Exceptions::IllegalArgumentException("vin char out of range".to_owned())) + } + + fn vinPositionWeight( position:usize) -> Result{ + match position { + 1..=7 => Ok(9-position), + 8 => Ok(10), + 9 => Ok(0), + 10..=17 => Ok(19-position), + _ => Err(Exceptions::IllegalArgumentException("vin position weight out of bounds".to_owned())), + } + // if position >= 1 && position <= 7 { + // return 9 - position; + // } + // if position == 8 { + // return 10; + // } + // if position == 9 { + // return 0; + // } + // if position >= 10 && position <= 17 { + // return 19 - position; + // } + // throw new IllegalArgumentException(); + } + + fn checkChar( remainder:u8) -> Result { + if remainder < 10 { + return Ok( ('0' as u8 + remainder) as char ); + } + if remainder == 10 { + return Ok('X'); + } + Err(Exceptions::IllegalArgumentException("remainder too high".to_owned())) + } + + fn modelYear( c:char) -> Result { + if (c >= 'E' && c <= 'H') { + return (c - 'E') + 1984; + } + if (c >= 'J' && c <= 'N') { + return (c - 'J') + 1988; + } + if (c == 'P') { + return 1993; + } + if (c >= 'R' && c <= 'T') { + return (c - 'R') + 1994; + } + if (c >= 'V' && c <= 'Y') { + return (c - 'V') + 1997; + } + if (c >= '1' && c <= '9') { + return (c - '1') + 2001; + } + if (c >= 'A' && c <= 'D') { + return (c - 'A') + 2010; + } + throw new IllegalArgumentException(); + } + + fn countryCode( wmi : &str) -> Option<&'static str> { + let c1 = wmi.chars().nth(0).unwrap(); + let c2 = wmi.chars().nth(1).unwrap(); + match c1 { + '1' | '4'| '5' => Some("US"), + '2' => Some("CA"), + '3' if c2 >= 'A' && c2 <= 'W' => Some("MX"), + '9' if ((c2 >= 'A' && c2 <= 'E') || (c2 >= '3' && c2 <= '9')) => Some("BR"), +'J' if (c2 >= 'A' && c2 <= 'T') => Some("JP"), +'K' if (c2 >= 'L' && c2 <= 'R') => Some("KO"), +'L' => Some("CN"), +'M' if (c2 >= 'A' && c2 <= 'E') => Some("IN"), +'S' if (c2 >= 'A' && c2 <= 'M') => Some("UK"), +'S' if (c2 >= 'N' && c2 <= 'T') => Some("DE"), +'V' if (c2 >= 'F' && c2 <= 'R') => Some("FR"), +'V' if (c2 >= 'S' && c2 <= 'W') => Some("ES"), +'W' => Some("DE"), +'X' if (c2 == '0' || (c2 >= '3' && c2 <= '9')) => Some("RU"), +'Z' if (c2 >= 'A' && c2 <= 'R') => Some("IT"), +_ => None + } + } \ No newline at end of file diff --git a/src/client/result/mod.rs b/src/client/result/mod.rs index b815c72..6ba74e7 100644 --- a/src/client/result/mod.rs +++ b/src/client/result/mod.rs @@ -24,6 +24,8 @@ mod EmailAddressParsedResult; mod EmailAddressResultParser; mod EmailDoCoMoResultParser; mod SMTPResultParser; +mod VINParsedResult; +mod VINResultParser; use std::fmt; @@ -43,6 +45,7 @@ pub use SMSParsedResult::*; pub use ProductParsedResult::*; pub use URIParsedResult::*; pub use EmailAddressParsedResult::*; +pub use VINParsedResult::*; #[cfg(test)] mod TelParsedResultTestCase; @@ -60,6 +63,8 @@ mod ProductParsedResultTestCase; mod URIParsedResultTestCase; #[cfg(test)] mod EmailAddressParsedResultTestCase; +#[cfg(test)] +mod VINParsedResultTestCase; pub enum ParsedClientResult { TextResult(TextParsedRXingResult), @@ -71,6 +76,7 @@ pub enum ParsedClientResult { ProductResult(ProductParsedRXingResult), URIResult(URIParsedRXingResult), EmailResult(EmailAddressParsedRXingResult), + VINResult(VINParsedRXingResult), } impl ParsedRXingResult for ParsedClientResult { @@ -85,6 +91,7 @@ impl ParsedRXingResult for ParsedClientResult { ParsedClientResult::ProductResult(a) => a.getType(), ParsedClientResult::URIResult(a) => a.getType(), ParsedClientResult::EmailResult(a) => a.getType(), + ParsedClientResult::VINResult(a) => a.getType(), } @@ -101,6 +108,7 @@ impl ParsedRXingResult for ParsedClientResult { ParsedClientResult::ProductResult(a) => a.getDisplayRXingResult(), ParsedClientResult::URIResult(a) => a.getDisplayRXingResult(), ParsedClientResult::EmailResult(a) => a.getDisplayRXingResult(), + ParsedClientResult::VINResult(a) => a.getDisplayRXingResult(),