diff --git a/src/client/result/ParsedResult.rs b/src/client/result/ParsedResult.rs index 97477d1..755192d 100644 --- a/src/client/result/ParsedResult.rs +++ b/src/client/result/ParsedResult.rs @@ -16,6 +16,8 @@ // package com.google.zxing.client.result; +use std::any::Any; + use super::ParsedRXingResultType; /** @@ -30,34 +32,33 @@ use super::ParsedRXingResultType; * @author Sean Owen */ pub trait ParsedRXingResult { + // private final ParsedRXingResultType type; - // private final ParsedRXingResultType type; + // protected ParsedRXingResult(ParsedRXingResultType type) { + // this.type = type; + // } - // protected ParsedRXingResult(ParsedRXingResultType type) { - // this.type = type; - // } + fn getType(&self) -> ParsedRXingResultType; + // fn as_any(&self) -> &dyn Any; - fn getType(&self) -> ParsedRXingResultType; + fn getDisplayRXingResult(&self) -> String; - fn getDisplayRXingResult(&self) -> String; - - fn maybe_append(&self, value :&str, result:&mut String) { - if !value.is_empty() { - // Don't add a newline before the first value - if result.len() > 0 { - result.push('\n'); - } - result.push_str(value); + fn maybe_append(&self, value: &str, result: &mut String) { + if !value.is_empty() { + // Don't add a newline before the first value + if result.len() > 0 { + result.push('\n'); + } + result.push_str(value); + } } - } - fn maybe_append_multiple(&self, values:&[&str], result:&mut String) { - if !values.is_empty() { - for value in values { - // for (String value : values) { - self.maybe_append(value, result); - } + fn maybe_append_multiple(&self, values: &[&str], result: &mut String) { + if !values.is_empty() { + for value in values { + // for (String value : values) { + self.maybe_append(value, result); + } + } } - } - } diff --git a/src/client/result/ParsedResultType.rs b/src/client/result/ParsedResultType.rs index 53c9f87..ba6f2bf 100644 --- a/src/client/result/ParsedResultType.rs +++ b/src/client/result/ParsedResultType.rs @@ -22,6 +22,7 @@ * * @author Sean Owen */ +#[derive(Debug,PartialEq, Eq,Hash)] pub enum ParsedRXingResultType { ADDRESSBOOK, diff --git a/src/client/result/ResultParser.rs b/src/client/result/ResultParser.rs index 6b5bea2..ea36c61 100644 --- a/src/client/result/ResultParser.rs +++ b/src/client/result/ResultParser.rs @@ -33,7 +33,7 @@ use urlencoding::decode; use crate::{exceptions::Exceptions, RXingResult}; -use super::ParsedRXingResult; +use super::{ParsedClientResult, ParsedRXingResult, TextParsedRXingResult, TelRXingResultParser}; /** *

Abstract class representing the result of decoding a barcode, as more than @@ -47,7 +47,58 @@ use super::ParsedRXingResult; * @author Sean Owen */ pub trait RXingResultParser { - // private static final RXingResultParser[] PARSERS = { + + // const PARSERS: [&'static str; 20] = [ + // "BookmarkDoCoMoRXingResultParser", + // "AddressBookDoCoMoRXingResultParser", + // "EmailDoCoMoRXingResultParser", + // "AddressBookAURXingResultParser", + // "VCardRXingResultParser", + // "BizcardRXingResultParser", + // "VEventRXingResultParser", + // "EmailAddressRXingResultParser", + // "SMTPRXingResultParser", + // "TelRXingResultParser", + // "SMSMMSRXingResultParser", + // "SMSTOMMSTORXingResultParser", + // "GeoRXingResultParser", + // "WifiRXingResultParser", + // "URLTORXingResultParser", + // "URIRXingResultParser", + // "ISBNRXingResultParser", + // "ProductRXingResultParser", + // "ExpandedProductRXingResultParser", + // "VINRXingResultParser", + // ]; + + /** + * Attempts to parse the raw {@link RXingResult}'s contents as a particular type + * of information (email, URL, etc.) and return a {@link ParsedRXingResult} encapsulating + * the result of parsing. + * + * @param theRXingResult the raw {@link RXingResult} to parse + * @return {@link ParsedRXingResult} encapsulating the parsing result + */ + fn parse(&self, theRXingResult: &RXingResult) -> Option; +} + +const DIGITS: &'static str = "\\d+"; //= Pattern.compile("\\d+"); +const AMPERSAND: &'static str = "&"; // private static final Pattern AMPERSAND = Pattern.compile("&"); +const EQUALS: &'static str = "="; //private static final Pattern EQUALS = Pattern.compile("="); +const BYTE_ORDER_MARK: &'static str = "\u{feff}"; //private static final String BYTE_ORDER_MARK = "\ufeff"; + +const EMPTY_STR_ARRAY: &'static str = ""; + +pub fn getMassagedText(result: &RXingResult) -> String { + let mut text = result.getText().clone(); + if text.starts_with(BYTE_ORDER_MARK) { + text = text[1..].to_owned(); + } + return text; +} + +pub fn parseRXingResult(theRXingResult: &RXingResult) -> ParsedClientResult { +let PARSERS = [ // new BookmarkDoCoMoRXingResultParser(), // new AddressBookDoCoMoRXingResultParser(), // new EmailDoCoMoRXingResultParser(), @@ -57,7 +108,7 @@ pub trait RXingResultParser { // new VEventRXingResultParser(), // new EmailAddressRXingResultParser(), // new SMTPRXingResultParser(), - // new TelRXingResultParser(), + TelRXingResultParser{}, // new SMSMMSRXingResultParser(), // new SMSTOMMSTORXingResultParser(), // new GeoRXingResultParser(), @@ -68,278 +119,233 @@ pub trait RXingResultParser { // new ProductRXingResultParser(), // new ExpandedProductRXingResultParser(), // new VINRXingResultParser(), - // }; +]; - const DIGITS: &'static str = "\\d+"; //= Pattern.compile("\\d+"); - const AMPERSAND: &'static str = "&"; // private static final Pattern AMPERSAND = Pattern.compile("&"); - const EQUALS: &'static str = "="; //private static final Pattern EQUALS = Pattern.compile("="); - const BYTE_ORDER_MARK: &'static str = "\u{feff}"; //private static final String BYTE_ORDER_MARK = "\ufeff"; - - const EMPTY_STR_ARRAY: &'static str = ""; - - const PARSERS: [&'static str; 20] = [ - "BookmarkDoCoMoRXingResultParser", - "AddressBookDoCoMoRXingResultParser", - "EmailDoCoMoRXingResultParser", - "AddressBookAURXingResultParser", - "VCardRXingResultParser", - "BizcardRXingResultParser", - "VEventRXingResultParser", - "EmailAddressRXingResultParser", - "SMTPRXingResultParser", - "TelRXingResultParser", - "SMSMMSRXingResultParser", - "SMSTOMMSTORXingResultParser", - "GeoRXingResultParser", - "WifiRXingResultParser", - "URLTORXingResultParser", - "URIRXingResultParser", - "ISBNRXingResultParser", - "ProductRXingResultParser", - "ExpandedProductRXingResultParser", - "VINRXingResultParser", - ]; - - /** - * Attempts to parse the raw {@link RXingResult}'s contents as a particular type - * of information (email, URL, etc.) and return a {@link ParsedRXingResult} encapsulating - * the result of parsing. - * - * @param theRXingResult the raw {@link RXingResult} to parse - * @return {@link ParsedRXingResult} encapsulating the parsing result - */ - fn parse(&self, theRXingResult: &RXingResult) -> Self; - - fn getMassagedText(result: &RXingResult) -> String { - let mut text = result.getText().clone(); - if text.starts_with(Self::BYTE_ORDER_MARK) { - text = text[1..].to_owned(); - } - return text; - } - - fn parseRXingResult(theRXingResult: &RXingResult) -> Box { - for parser in Self::PARSERS { - // for (RXingResultParser parser : PARSERS) { - todo!("implement multiple parsers"); - } - // ParsedRXingResult result = parser.parse(theRXingResult); - // if (result != null) { - // return result; - // } - // } - // return new TextParsedRXingResult(theRXingResult.getText(), null); - unimplemented!(); - } - - fn maybe_ppend_string(value: &str, result: &mut String) { - if !value.is_empty() { - result.push('\n'); - result.push_str(value); + for parser in PARSERS { + let result = parser.parse(theRXingResult); + if result.is_some() { + return result.unwrap(); } } + // ParsedRXingResult result = parser.parse(theRXingResult); + // if (result != null) { + // return result; + // } + // } - fn maybe_append_multiple(value: &[&str], result: &mut String) { - if !value.is_empty() { - for s in value { - // for (String s : value) { - result.push('\n'); - result.push_str(s); - } - } - } + ParsedClientResult::TextResult(TextParsedRXingResult::new( + theRXingResult.getText().to_owned(), + "".to_owned(), + )) +} - fn maybeWrap(value: Option<&str>) -> Option> { - if value.is_none() { - None - } else { - Some(vec![value.unwrap().to_owned()]) - } - } - - fn unescapeBackslash(escaped: &str) -> String { - let backslash = escaped.find('\\'); - if backslash.is_none() { - return escaped.to_owned(); - } - let max = escaped.len(); - let mut unescaped = String::with_capacity(max - 1); - let backslash = backslash.unwrap_or(0); - unescaped.push_str(&escaped[0..backslash]); - let mut nextIsEscaped = false; - for i in backslash..max { - // for (int i = backslash; i < max; i++) { - let c = escaped.chars().nth(i).unwrap(); - if nextIsEscaped || c != '\\' { - unescaped.push(c); - nextIsEscaped = false; - } else { - nextIsEscaped = true; - } - } - - unescaped - } - - fn parseHexDigit(c: char) -> i32 { - if c >= '0' && c <= '9' { - return (c as u8 - '0' as u8) as i32; - } - if c >= 'a' && c <= 'f' { - return 10 + (c as u8 - 'a' as u8) as i32; - } - if c >= 'A' && c <= 'F' { - return 10 + (c as u8 - 'A' as u8) as i32; - } - return -1; - } - - fn isStringOfDigits(value: &str, length: usize) -> bool { - let matcher = Regex::new(Self::DIGITS).unwrap(); - !value.is_empty() && length > 0 && length == value.len() && matcher.is_match(value) - } - - fn isSubstringOfDigits(value: &str, offset: i32, length: usize) -> bool { - if value.is_empty() || length <= 0 { - return false; - } - let max = offset as usize + length; - - let matcher = Regex::new(Self::DIGITS).unwrap(); - let sub_seq = &value[offset as usize..offset as usize + max]; - - value.len() >= max && matcher.is_match(sub_seq) - } - - fn parseNameValuePairs(uri: &str) -> Option> { - let paramStart = uri.find('?'); - if paramStart.is_none() { - return None; - } - let mut result = HashMap::with_capacity(3); - let paramStart = paramStart.unwrap_or(0); - - let sub_str = &uri[paramStart + 1..]; - let list = sub_str.split(Self::AMPERSAND); - for keyValue in list { - Self::appendKeyValue(keyValue, &mut result); - } - - // for keyValue in Self::AMPERSAND.split(uri[paramStart + 1..]) { - // // for (String keyValue : AMPERSAND.split(uri.substring(paramStart + 1))) { - // Self::appendKeyValue(keyValue, &mut result); - // } - Some(result) - } - - fn appendKeyValue(keyValue: &str, result: &mut HashMap) { - let keyValueTokens = keyValue.split(Self::EQUALS); //Self::EQUALS.split(keyValue, 2); - - let kvp: Vec<&str> = keyValueTokens.take(2).collect(); - if let [key, value] = kvp[..] { - let p_value = Self::urlDecode(value).unwrap_or("".to_owned()); - result.insert(key.to_owned(), p_value); - } - - // if keyValueTokens.len() == 2 { - // let key = keyValueTokens[0]; - // let value = keyValueTokens[1]; - // try { - // value = Self::urlDecode(value); - // result.put(key, value); - // } catch (IllegalArgumentException iae) { - // // continue; invalid data such as an escape like %0t - // } - // } - } - - fn urlDecode(encoded: &str) -> Result { - if let Ok(decoded) = decode(encoded) { - Ok(decoded.to_string()) - } else { - Err(Exceptions::IllegalStateException( - "UnsupportedEncodingException".to_owned(), - )) - } - } - - fn matchPrefixedField( - prefix: &str, - rawText: &str, - endChar: char, - trim: bool, - ) -> Option> { - let mut matches: Vec = Vec::new(); - let mut i = 0; - let max = rawText.len(); - while i < max { - i = if let Some(loc) = rawText[i..].find(prefix) { - loc //rawText.indexOf(prefix, i); - } else { - break; - }; - // if i < 0 { - // break; - // } - i += prefix.len(); // Skip past this prefix we found to start - let start = i; // Found the start of a match here - let mut more = true; - while more { - let i = if let Some(loc) = rawText[i..].find(endChar) { - if Self::countPrecedingBackslashes(rawText, i) % 2 != 0 { - // semicolon was escaped (odd count of preceding backslashes) so continue - i + 1 - } else { - // found a match - let mut element = Self::unescapeBackslash(&rawText[start..i + start]); - if trim { - element = element.to_string().trim().to_owned(); - } - if !element.is_empty() { - matches.push(element); - } - more = false; - i + 1 - } - } else { - // No terminating end character? uh, done. Set i such that loop terminates and break - //i = rawText.len(); - more = false; - rawText.len() - }; - } - } - if matches.is_empty() { - return None; - } - Some(matches) - } - - fn countPrecedingBackslashes(s: &str, pos: usize) -> u32 { - let mut count = 0; - for i in (0..pos - 1).rev() { - // for (int i = pos - 1; i >= 0; i--) { - if s.chars().nth(i).unwrap() == '\\' { - count += 1; - } else { - break; - } - } - return count; - } - - fn matchSinglePrefixedField( - prefix: &str, - rawText: &str, - endChar: char, - trim: bool, - ) -> Option { - let matches = Self::matchPrefixedField(prefix, rawText, endChar, trim); - if let Some(m) = matches { - Some(m[0].clone()) - } else { - None - } - // return matches == null ? null : matches[0]; +pub fn maybe_ppend_string(value: &str, result: &mut String) { + if !value.is_empty() { + result.push('\n'); + result.push_str(value); } } + +pub fn maybe_append_multiple(value: &[&str], result: &mut String) { + if !value.is_empty() { + for s in value { + // for (String s : value) { + result.push('\n'); + result.push_str(s); + } + } +} + +pub fn maybeWrap(value: Option<&str>) -> Option> { + if value.is_none() { + None + } else { + Some(vec![value.unwrap().to_owned()]) + } +} + +pub fn unescapeBackslash(escaped: &str) -> String { + let backslash = escaped.find('\\'); + if backslash.is_none() { + return escaped.to_owned(); + } + let max = escaped.len(); + let mut unescaped = String::with_capacity(max - 1); + let backslash = backslash.unwrap_or(0); + unescaped.push_str(&escaped[0..backslash]); + let mut nextIsEscaped = false; + for i in backslash..max { + // for (int i = backslash; i < max; i++) { + let c = escaped.chars().nth(i).unwrap(); + if nextIsEscaped || c != '\\' { + unescaped.push(c); + nextIsEscaped = false; + } else { + nextIsEscaped = true; + } + } + + unescaped +} + +pub fn parseHexDigit(c: char) -> i32 { + if c >= '0' && c <= '9' { + return (c as u8 - '0' as u8) as i32; + } + if c >= 'a' && c <= 'f' { + return 10 + (c as u8 - 'a' as u8) as i32; + } + if c >= 'A' && c <= 'F' { + return 10 + (c as u8 - 'A' as u8) as i32; + } + return -1; +} + +pub fn isStringOfDigits(value: &str, length: usize) -> bool { + let matcher = Regex::new(DIGITS).unwrap(); + !value.is_empty() && length > 0 && length == value.len() && matcher.is_match(value) +} + +pub fn isSubstringOfDigits(value: &str, offset: i32, length: usize) -> bool { + if value.is_empty() || length <= 0 { + return false; + } + let max = offset as usize + length; + + let matcher = Regex::new(DIGITS).unwrap(); + let sub_seq = &value[offset as usize..offset as usize + max]; + + value.len() >= max && matcher.is_match(sub_seq) +} + +pub fn parseNameValuePairs(uri: &str) -> Option> { + let paramStart = uri.find('?'); + if paramStart.is_none() { + return None; + } + let mut result = HashMap::with_capacity(3); + let paramStart = paramStart.unwrap_or(0); + + let sub_str = &uri[paramStart + 1..]; + let list = sub_str.split(AMPERSAND); + for keyValue in list { + appendKeyValue(keyValue, &mut result); + } + + // for keyValue in Self::AMPERSAND.split(uri[paramStart + 1..]) { + // // for (String keyValue : AMPERSAND.split(uri.substring(paramStart + 1))) { + // Self::appendKeyValue(keyValue, &mut result); + // } + Some(result) +} + +pub fn appendKeyValue(keyValue: &str, result: &mut HashMap) { + let keyValueTokens = keyValue.split(EQUALS); //Self::EQUALS.split(keyValue, 2); + + let kvp: Vec<&str> = keyValueTokens.take(2).collect(); + if let [key, value] = kvp[..] { + let p_value = urlDecode(value).unwrap_or("".to_owned()); + result.insert(key.to_owned(), p_value); + } + + // if keyValueTokens.len() == 2 { + // let key = keyValueTokens[0]; + // let value = keyValueTokens[1]; + // try { + // value = Self::urlDecode(value); + // result.put(key, value); + // } catch (IllegalArgumentException iae) { + // // continue; invalid data such as an escape like %0t + // } + // } +} + +pub fn urlDecode(encoded: &str) -> Result { + if let Ok(decoded) = decode(encoded) { + Ok(decoded.to_string()) + } else { + Err(Exceptions::IllegalStateException( + "UnsupportedEncodingException".to_owned(), + )) + } +} + +pub fn matchPrefixedField( + prefix: &str, + rawText: &str, + endChar: char, + trim: bool, +) -> Option> { + let mut matches: Vec = Vec::new(); + let mut i = 0; + let max = rawText.len(); + while i < max { + i = if let Some(loc) = rawText[i..].find(prefix) { + loc //rawText.indexOf(prefix, i); + } else { + break; + }; + // if i < 0 { + // break; + // } + i += prefix.len(); // Skip past this prefix we found to start + let start = i; // Found the start of a match here + let mut more = true; + while more { + let i = if let Some(loc) = rawText[i..].find(endChar) { + if countPrecedingBackslashes(rawText, i) % 2 != 0 { + // semicolon was escaped (odd count of preceding backslashes) so continue + i + 1 + } else { + // found a match + let mut element = unescapeBackslash(&rawText[start..i + start]); + if trim { + element = element.to_string().trim().to_owned(); + } + if !element.is_empty() { + matches.push(element); + } + more = false; + i + 1 + } + } else { + // No terminating end character? uh, done. Set i such that loop terminates and break + //i = rawText.len(); + more = false; + rawText.len() + }; + } + } + if matches.is_empty() { + return None; + } + Some(matches) +} + +pub fn countPrecedingBackslashes(s: &str, pos: usize) -> u32 { + let mut count = 0; + for i in (0..pos - 1).rev() { + // for (int i = pos - 1; i >= 0; i--) { + if s.chars().nth(i).unwrap() == '\\' { + count += 1; + } else { + break; + } + } + return count; +} + +pub fn matchSinglePrefixedField( + prefix: &str, + rawText: &str, + endChar: char, + trim: bool, +) -> Option { + let matches = matchPrefixedField(prefix, rawText, endChar, trim); + if let Some(m) = matches { + Some(m[0].clone()) + } else { + None + } + // return matches == null ? null : matches[0]; +} diff --git a/src/client/result/TelParsedResult.java b/src/client/result/TelParsedResult.java deleted file mode 100644 index d5f2ac8..0000000 --- a/src/client/result/TelParsedResult.java +++ /dev/null @@ -1,57 +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.client.result; - -/** - * Represents a parsed result that encodes a telephone number. - * - * @author Sean Owen - */ -public final class TelParsedRXingResult extends ParsedRXingResult { - - private final String number; - private final String telURI; - private final String title; - - public TelParsedRXingResult(String number, String telURI, String title) { - super(ParsedRXingResultType.TEL); - this.number = number; - this.telURI = telURI; - this.title = title; - } - - public String getNumber() { - return number; - } - - public String getTelURI() { - return telURI; - } - - public String getTitle() { - return title; - } - - @Override - public String getDisplayRXingResult() { - StringBuilder result = new StringBuilder(20); - maybeAppend(number, result); - maybeAppend(title, result); - return result.toString(); - } - -} \ No newline at end of file diff --git a/src/client/result/TelParsedResult.rs b/src/client/result/TelParsedResult.rs new file mode 100644 index 0000000..f8bfddd --- /dev/null +++ b/src/client/result/TelParsedResult.rs @@ -0,0 +1,64 @@ +/* + * 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.client.result; + +use super::{ParsedRXingResult, ParsedRXingResultType}; + +/** + * Represents a parsed result that encodes a telephone number. + * + * @author Sean Owen + */ +pub struct TelParsedRXingResult { + number: String, + telURI: String, + title: String, +} + +impl ParsedRXingResult for TelParsedRXingResult { + fn getType(&self) -> super::ParsedRXingResultType { + ParsedRXingResultType::TEL + } + + fn getDisplayRXingResult(&self) -> String { + let mut result = String::with_capacity(20); + self.maybe_append(&self.number, &mut result); + self.maybe_append(&self.title, &mut result); + result + } +} +impl TelParsedRXingResult { + pub fn new(number: String, telURI: String, title: String) -> Self { + Self { + number, + telURI, + title, + } + } + + pub fn getNumber(&self) -> &str { + &self.number + } + + pub fn getTelURI(&self) -> &str { + &self.telURI + } + + pub fn getTitle(&self) -> &str { + &&self.title + } +} diff --git a/src/client/result/TelParsedResultTestCase.java b/src/client/result/TelParsedResultTestCase.java deleted file mode 100644 index a558da2..0000000 --- a/src/client/result/TelParsedResultTestCase.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2007 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.zxing.client.result; - -import com.google.zxing.BarcodeFormat; -import com.google.zxing.RXingResult; -import org.junit.Assert; -import org.junit.Test; - -/** - * Tests {@link TelParsedRXingResult}. - * - * @author Sean Owen - */ -public final class TelParsedRXingResultTestCase extends Assert { - - @Test - public void testTel() { - doTest("tel:+15551212", "+15551212", null); - doTest("tel:2125551212", "2125551212", null); - } - - private static void doTest(String contents, String number, String title) { - RXingResult fakeRXingResult = new RXingResult(contents, null, null, BarcodeFormat.QR_CODE); - ParsedRXingResult result = RXingResultParser.parseRXingResult(fakeRXingResult); - assertSame(ParsedRXingResultType.TEL, result.getType()); - TelParsedRXingResult telRXingResult = (TelParsedRXingResult) result; - assertEquals(number, telRXingResult.getNumber()); - assertEquals(title, telRXingResult.getTitle()); - assertEquals("tel:" + number, telRXingResult.getTelURI()); - } - -} \ No newline at end of file diff --git a/src/client/result/TelParsedResultTestCase.rs b/src/client/result/TelParsedResultTestCase.rs new file mode 100644 index 0000000..487bd27 --- /dev/null +++ b/src/client/result/TelParsedResultTestCase.rs @@ -0,0 +1,63 @@ +/* + * Copyright 2007 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// package com.google.zxing.client.result; + +// import com.google.zxing.BarcodeFormat; +// import com.google.zxing.RXingResult; +// import org.junit.Assert; +// import org.junit.Test; + +/** + * Tests {@link TelParsedRXingResult}. + * + * @author Sean Owen + */ +// public final class TelParsedRXingResultTestCase extends Assert { +use std::any::Any; + +use crate::{ + client::result::{ + ParsedClientResult, ParsedRXingResult, ParsedRXingResultType, RXingResultParser, + TelParsedRXingResult, + }, + BarcodeFormat, RXingResult, +}; + +use super::ResultParser; + +#[test] +fn testTel() { + doTest("tel:+15551212", "+15551212", ""); + doTest("tel:2125551212", "2125551212", ""); +} + +fn doTest(contents: &str, number: &str, title: &str) { + let fakeRXingResult = + RXingResult::new(contents, Vec::new(), Vec::new(), BarcodeFormat::QR_CODE); + let result = ResultParser::parseRXingResult(&fakeRXingResult); + + if let ParsedClientResult::TelResult(telRXingResult) = result { + assert_eq!(ParsedRXingResultType::TEL, telRXingResult.getType()); + assert_eq!(number, telRXingResult.getNumber()); + assert_eq!(title, telRXingResult.getTitle()); + assert_eq!(format!("tel:{}", number), telRXingResult.getTelURI()); + } else { + panic!("wrong return type, expected TelResult"); + } +} + +// } diff --git a/src/client/result/TelResultParser.java b/src/client/result/TelResultParser.java deleted file mode 100644 index ab83723..0000000 --- a/src/client/result/TelResultParser.java +++ /dev/null @@ -1,42 +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.client.result; - -import com.google.zxing.RXingResult; - -/** - * Parses a "tel:" URI result, which specifies a phone number. - * - * @author Sean Owen - */ -public final class TelRXingResultParser extends RXingResultParser { - - @Override - public TelParsedRXingResult parse(RXingResult result) { - String rawText = getMassagedText(result); - if (!rawText.startsWith("tel:") && !rawText.startsWith("TEL:")) { - return null; - } - // Normalize "TEL:" to "tel:" - String telURI = rawText.startsWith("TEL:") ? "tel:" + rawText.substring(4) : rawText; - // Drop tel, query portion - int queryStart = rawText.indexOf('?', 4); - String number = queryStart < 0 ? rawText.substring(4) : rawText.substring(4, queryStart); - return new TelParsedRXingResult(number, telURI, null); - } - -} \ No newline at end of file diff --git a/src/client/result/TelResultParser.rs b/src/client/result/TelResultParser.rs new file mode 100644 index 0000000..027b54f --- /dev/null +++ b/src/client/result/TelResultParser.rs @@ -0,0 +1,49 @@ +/* + * 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.client.result; + +// import com.google.zxing.RXingResult; + +use super::{RXingResultParser, TelParsedRXingResult, ParsedRXingResult, ParsedClientResult, ResultParser}; + +/** + * Parses a "tel:" URI result, which specifies a phone number. + * + * @author Sean Owen + */ +pub struct TelRXingResultParser {} + +impl RXingResultParser for TelRXingResultParser { + + fn parse(&self, theRXingResult: &crate::RXingResult) -> Option { + let rawText = ResultParser::getMassagedText(theRXingResult); + if !rawText.starts_with("tel:") && !rawText.starts_with("TEL:") { + return None; + } + // Normalize "TEL:" to "tel:" + let telURI = if rawText.starts_with("TEL:") {format!("tel:{}", &rawText[4..])} else {rawText.clone()}; + // Drop tel, query portion + let queryStart = rawText[4..].find('?'); + let number = if let Some(v) = queryStart { + &rawText[4..v+4] + }else { + &rawText[4..] + }; + // let number = queryStart < 0 ? : ; + Some(ParsedClientResult::TelResult(TelParsedRXingResult::new(number.to_owned(), telURI.to_owned(), "".to_owned()))) + } +} \ No newline at end of file diff --git a/src/client/result/TextParsedResult.java b/src/client/result/TextParsedResult.rs similarity index 52% rename from src/client/result/TextParsedResult.java rename to src/client/result/TextParsedResult.rs index 5b1e214..8306f2b 100644 --- a/src/client/result/TextParsedResult.java +++ b/src/client/result/TextParsedResult.rs @@ -14,36 +14,41 @@ * limitations under the License. */ -package com.google.zxing.client.result; +// package com.google.zxing.client.result; + +use super::{ParsedRXingResult, ParsedRXingResultType}; /** * A simple result type encapsulating a string that has no further * interpretation. - * + * * @author Sean Owen */ -public final class TextParsedRXingResult extends ParsedRXingResult { - - private final String text; - private final String language; - - public TextParsedRXingResult(String text, String language) { - super(ParsedRXingResultType.TEXT); - this.text = text; - this.language = language; - } - - public String getText() { - return text; - } - - public String getLanguage() { - return language; - } - - @Override - public String getDisplayRXingResult() { - return text; - } - +pub struct TextParsedRXingResult { + text: String, + language: String, +} + +impl ParsedRXingResult for TextParsedRXingResult { + fn getType(&self) -> ParsedRXingResultType { + ParsedRXingResultType::TEXT + } + + fn getDisplayRXingResult(&self) -> String { + self.text.clone() + } +} + +impl TextParsedRXingResult { + pub fn new(text: String, language: String) -> Self { + Self { text, language } + } + + pub fn getText(&self) -> &str { + &self.text + } + + pub fn getLanguage(&self) -> &str { + &self.language + } } diff --git a/src/client/result/mod.rs b/src/client/result/mod.rs index b35a02f..a18b5bc 100644 --- a/src/client/result/mod.rs +++ b/src/client/result/mod.rs @@ -1,7 +1,21 @@ mod ParsedResult; -pub use ParsedResult::*; mod ResultParser; - +mod TelParsedResult; +mod TextParsedResult; mod ParsedResultType; +mod TelResultParser; + pub use ParsedResultType::*; -pub use ResultParser::*; \ No newline at end of file +pub use ResultParser::*; +pub use TelParsedResult::*; +pub use TextParsedResult::*; +pub use ParsedResult::*; +pub use TelResultParser::*; + +#[cfg(test)] +mod TelParsedResultTestCase; + +pub enum ParsedClientResult { + TextResult(TextParsedRXingResult), + TelResult(TelParsedRXingResult) +} \ No newline at end of file