TelResultParser port with pass

This commit is contained in:
Henry Schimke
2022-09-03 11:42:55 -05:00
parent c66da802b5
commit d80ead1d7b
11 changed files with 526 additions and 469 deletions

View File

@@ -33,7 +33,7 @@ use urlencoding::decode;
use crate::{exceptions::Exceptions, RXingResult};
use super::ParsedRXingResult;
use super::{ParsedClientResult, ParsedRXingResult, TextParsedRXingResult, TelRXingResultParser};
/**
* <p>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<ParsedClientResult>;
}
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<dyn ParsedRXingResult> {
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<Vec<String>> {
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<HashMap<String, String>> {
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<String, String>) {
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<String, Exceptions> {
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<Vec<String>> {
let mut matches: Vec<String> = 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<String> {
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<Vec<String>> {
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<HashMap<String, String>> {
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<String, String>) {
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<String, Exceptions> {
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<Vec<String>> {
let mut matches: Vec<String> = 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<String> {
let matches = matchPrefixedField(prefix, rawText, endChar, trim);
if let Some(m) = matches {
Some(m[0].clone())
} else {
None
}
// return matches == null ? null : matches[0];
}