mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 04:12:34 +00:00
Start port of client result types
This commit is contained in:
@@ -9,9 +9,10 @@ exclude = [
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
regex = "1"
|
regex = "1.6"
|
||||||
encoding = "0.2"
|
encoding = "0.2"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
urlencoding = "2.1.2"
|
||||||
image = {version = "0.24.3", optional = true}
|
image = {version = "0.24.3", optional = true}
|
||||||
imageproc = {version = "0.23.0", optional = true}
|
imageproc = {version = "0.23.0", optional = true}
|
||||||
|
|
||||||
|
|||||||
1
src/client/mod.rs
Normal file
1
src/client/mod.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
mod result;
|
||||||
@@ -14,7 +14,9 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.google.zxing.client.result;
|
// package com.google.zxing.client.result;
|
||||||
|
|
||||||
|
use super::ParsedRXingResultType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Abstract class representing the result of decoding a barcode, as more than
|
* <p>Abstract class representing the result of decoding a barcode, as more than
|
||||||
@@ -27,39 +29,33 @@ package com.google.zxing.client.result;
|
|||||||
*
|
*
|
||||||
* @author Sean Owen
|
* @author Sean Owen
|
||||||
*/
|
*/
|
||||||
public abstract class ParsedRXingResult {
|
pub trait ParsedRXingResult {
|
||||||
|
|
||||||
private final ParsedRXingResultType type;
|
// private final ParsedRXingResultType type;
|
||||||
|
|
||||||
protected ParsedRXingResult(ParsedRXingResultType type) {
|
// protected ParsedRXingResult(ParsedRXingResultType type) {
|
||||||
this.type = type;
|
// this.type = type;
|
||||||
}
|
// }
|
||||||
|
|
||||||
public final ParsedRXingResultType getType() {
|
fn getType(&self) -> ParsedRXingResultType;
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract String getDisplayRXingResult();
|
fn getDisplayRXingResult(&self) -> String;
|
||||||
|
|
||||||
@Override
|
fn maybe_append(&self, value :&str, result:&mut String) {
|
||||||
public final String toString() {
|
if !value.is_empty() {
|
||||||
return getDisplayRXingResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void maybeAppend(String value, StringBuilder result) {
|
|
||||||
if (value != null && !value.isEmpty()) {
|
|
||||||
// Don't add a newline before the first value
|
// Don't add a newline before the first value
|
||||||
if (result.length() > 0) {
|
if result.len() > 0 {
|
||||||
result.append('\n');
|
result.push('\n');
|
||||||
}
|
}
|
||||||
result.append(value);
|
result.push_str(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void maybeAppend(String[] values, StringBuilder result) {
|
fn maybe_append_multiple(&self, values:&[&str], result:&mut String) {
|
||||||
if (values != null) {
|
if !values.is_empty() {
|
||||||
for (String value : values) {
|
for value in values {
|
||||||
maybeAppend(value, result);
|
// for (String value : values) {
|
||||||
|
self.maybe_append(value, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.google.zxing.client.result;
|
// package com.google.zxing.client.result;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the type of data encoded by a barcode -- from plain text, to a
|
* Represents the type of data encoded by a barcode -- from plain text, to a
|
||||||
@@ -22,7 +22,7 @@ package com.google.zxing.client.result;
|
|||||||
*
|
*
|
||||||
* @author Sean Owen
|
* @author Sean Owen
|
||||||
*/
|
*/
|
||||||
public enum ParsedRXingResultType {
|
pub enum ParsedRXingResultType {
|
||||||
|
|
||||||
ADDRESSBOOK,
|
ADDRESSBOOK,
|
||||||
EMAIL_ADDRESS,
|
EMAIL_ADDRESS,
|
||||||
@@ -1,261 +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.RXingResult;
|
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.URLDecoder;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Abstract class representing the result of decoding a barcode, as more than
|
|
||||||
* a String -- as some type of structured data. This might be a subclass which represents
|
|
||||||
* a URL, or an e-mail address. {@link #parseRXingResult(RXingResult)} will turn a raw
|
|
||||||
* decoded string into the most appropriate type of structured representation.</p>
|
|
||||||
*
|
|
||||||
* <p>Thanks to Jeff Griffin for proposing rewrite of these classes that relies less
|
|
||||||
* on exception-based mechanisms during parsing.</p>
|
|
||||||
*
|
|
||||||
* @author Sean Owen
|
|
||||||
*/
|
|
||||||
public abstract class RXingResultParser {
|
|
||||||
|
|
||||||
private static final RXingResultParser[] PARSERS = {
|
|
||||||
new BookmarkDoCoMoRXingResultParser(),
|
|
||||||
new AddressBookDoCoMoRXingResultParser(),
|
|
||||||
new EmailDoCoMoRXingResultParser(),
|
|
||||||
new AddressBookAURXingResultParser(),
|
|
||||||
new VCardRXingResultParser(),
|
|
||||||
new BizcardRXingResultParser(),
|
|
||||||
new VEventRXingResultParser(),
|
|
||||||
new EmailAddressRXingResultParser(),
|
|
||||||
new SMTPRXingResultParser(),
|
|
||||||
new TelRXingResultParser(),
|
|
||||||
new SMSMMSRXingResultParser(),
|
|
||||||
new SMSTOMMSTORXingResultParser(),
|
|
||||||
new GeoRXingResultParser(),
|
|
||||||
new WifiRXingResultParser(),
|
|
||||||
new URLTORXingResultParser(),
|
|
||||||
new URIRXingResultParser(),
|
|
||||||
new ISBNRXingResultParser(),
|
|
||||||
new ProductRXingResultParser(),
|
|
||||||
new ExpandedProductRXingResultParser(),
|
|
||||||
new VINRXingResultParser(),
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final Pattern DIGITS = Pattern.compile("\\d+");
|
|
||||||
private static final Pattern AMPERSAND = Pattern.compile("&");
|
|
||||||
private static final Pattern EQUALS = Pattern.compile("=");
|
|
||||||
private static final String BYTE_ORDER_MARK = "\ufeff";
|
|
||||||
|
|
||||||
static final String[] EMPTY_STR_ARRAY = new String[0];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
public abstract ParsedRXingResult parse(RXingResult theRXingResult);
|
|
||||||
|
|
||||||
protected static String getMassagedText(RXingResult result) {
|
|
||||||
String text = result.getText();
|
|
||||||
if (text.startsWith(BYTE_ORDER_MARK)) {
|
|
||||||
text = text.substring(1);
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ParsedRXingResult parseRXingResult(RXingResult theRXingResult) {
|
|
||||||
for (RXingResultParser parser : PARSERS) {
|
|
||||||
ParsedRXingResult result = parser.parse(theRXingResult);
|
|
||||||
if (result != null) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new TextParsedRXingResult(theRXingResult.getText(), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static void maybeAppend(String value, StringBuilder result) {
|
|
||||||
if (value != null) {
|
|
||||||
result.append('\n');
|
|
||||||
result.append(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static void maybeAppend(String[] value, StringBuilder result) {
|
|
||||||
if (value != null) {
|
|
||||||
for (String s : value) {
|
|
||||||
result.append('\n');
|
|
||||||
result.append(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static String[] maybeWrap(String value) {
|
|
||||||
return value == null ? null : new String[] { value };
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static String unescapeBackslash(String escaped) {
|
|
||||||
int backslash = escaped.indexOf('\\');
|
|
||||||
if (backslash < 0) {
|
|
||||||
return escaped;
|
|
||||||
}
|
|
||||||
int max = escaped.length();
|
|
||||||
StringBuilder unescaped = new StringBuilder(max - 1);
|
|
||||||
unescaped.append(escaped.toCharArray(), 0, backslash);
|
|
||||||
boolean nextIsEscaped = false;
|
|
||||||
for (int i = backslash; i < max; i++) {
|
|
||||||
char c = escaped.charAt(i);
|
|
||||||
if (nextIsEscaped || c != '\\') {
|
|
||||||
unescaped.append(c);
|
|
||||||
nextIsEscaped = false;
|
|
||||||
} else {
|
|
||||||
nextIsEscaped = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return unescaped.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static int parseHexDigit(char c) {
|
|
||||||
if (c >= '0' && c <= '9') {
|
|
||||||
return c - '0';
|
|
||||||
}
|
|
||||||
if (c >= 'a' && c <= 'f') {
|
|
||||||
return 10 + (c - 'a');
|
|
||||||
}
|
|
||||||
if (c >= 'A' && c <= 'F') {
|
|
||||||
return 10 + (c - 'A');
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static boolean isStringOfDigits(CharSequence value, int length) {
|
|
||||||
return value != null && length > 0 && length == value.length() && DIGITS.matcher(value).matches();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static boolean isSubstringOfDigits(CharSequence value, int offset, int length) {
|
|
||||||
if (value == null || length <= 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int max = offset + length;
|
|
||||||
return value.length() >= max && DIGITS.matcher(value.subSequence(offset, max)).matches();
|
|
||||||
}
|
|
||||||
|
|
||||||
static Map<String,String> parseNameValuePairs(String uri) {
|
|
||||||
int paramStart = uri.indexOf('?');
|
|
||||||
if (paramStart < 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Map<String,String> result = new HashMap<>(3);
|
|
||||||
for (String keyValue : AMPERSAND.split(uri.substring(paramStart + 1))) {
|
|
||||||
appendKeyValue(keyValue, result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void appendKeyValue(CharSequence keyValue, Map<String,String> result) {
|
|
||||||
String[] keyValueTokens = EQUALS.split(keyValue, 2);
|
|
||||||
if (keyValueTokens.length == 2) {
|
|
||||||
String key = keyValueTokens[0];
|
|
||||||
String value = keyValueTokens[1];
|
|
||||||
try {
|
|
||||||
value = urlDecode(value);
|
|
||||||
result.put(key, value);
|
|
||||||
} catch (IllegalArgumentException iae) {
|
|
||||||
// continue; invalid data such as an escape like %0t
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static String urlDecode(String encoded) {
|
|
||||||
try {
|
|
||||||
return URLDecoder.decode(encoded, "UTF-8");
|
|
||||||
} catch (UnsupportedEncodingException uee) {
|
|
||||||
throw new IllegalStateException(uee); // can't happen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static String[] matchPrefixedField(String prefix, String rawText, char endChar, boolean trim) {
|
|
||||||
List<String> matches = null;
|
|
||||||
int i = 0;
|
|
||||||
int max = rawText.length();
|
|
||||||
while (i < max) {
|
|
||||||
i = rawText.indexOf(prefix, i);
|
|
||||||
if (i < 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i += prefix.length(); // Skip past this prefix we found to start
|
|
||||||
int start = i; // Found the start of a match here
|
|
||||||
boolean more = true;
|
|
||||||
while (more) {
|
|
||||||
i = rawText.indexOf(endChar, i);
|
|
||||||
if (i < 0) {
|
|
||||||
// No terminating end character? uh, done. Set i such that loop terminates and break
|
|
||||||
i = rawText.length();
|
|
||||||
more = false;
|
|
||||||
} else if (countPrecedingBackslashes(rawText, i) % 2 != 0) {
|
|
||||||
// semicolon was escaped (odd count of preceding backslashes) so continue
|
|
||||||
i++;
|
|
||||||
} else {
|
|
||||||
// found a match
|
|
||||||
if (matches == null) {
|
|
||||||
matches = new ArrayList<>(3); // lazy init
|
|
||||||
}
|
|
||||||
String element = unescapeBackslash(rawText.substring(start, i));
|
|
||||||
if (trim) {
|
|
||||||
element = element.trim();
|
|
||||||
}
|
|
||||||
if (!element.isEmpty()) {
|
|
||||||
matches.add(element);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
more = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (matches == null || matches.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return matches.toArray(EMPTY_STR_ARRAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int countPrecedingBackslashes(CharSequence s, int pos) {
|
|
||||||
int count = 0;
|
|
||||||
for (int i = pos - 1; i >= 0; i--) {
|
|
||||||
if (s.charAt(i) == '\\') {
|
|
||||||
count++;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static String matchSinglePrefixedField(String prefix, String rawText, char endChar, boolean trim) {
|
|
||||||
String[] matches = matchPrefixedField(prefix, rawText, endChar, trim);
|
|
||||||
return matches == null ? null : matches[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
345
src/client/result/ResultParser.rs
Normal file
345
src/client/result/ResultParser.rs
Normal file
@@ -0,0 +1,345 @@
|
|||||||
|
/*
|
||||||
|
* 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.RXingResult;
|
||||||
|
|
||||||
|
// import java.io.UnsupportedEncodingException;
|
||||||
|
// import java.net.URLDecoder;
|
||||||
|
// import java.util.ArrayList;
|
||||||
|
// import java.util.HashMap;
|
||||||
|
// import java.util.List;
|
||||||
|
// import java.util.Map;
|
||||||
|
// import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use regex::Regex;
|
||||||
|
use urlencoding::decode;
|
||||||
|
|
||||||
|
use crate::{exceptions::Exceptions, RXingResult};
|
||||||
|
|
||||||
|
use super::ParsedRXingResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Abstract class representing the result of decoding a barcode, as more than
|
||||||
|
* a String -- as some type of structured data. This might be a subclass which represents
|
||||||
|
* a URL, or an e-mail address. {@link #parseRXingResult(RXingResult)} will turn a raw
|
||||||
|
* decoded string into the most appropriate type of structured representation.</p>
|
||||||
|
*
|
||||||
|
* <p>Thanks to Jeff Griffin for proposing rewrite of these classes that relies less
|
||||||
|
* on exception-based mechanisms during parsing.</p>
|
||||||
|
*
|
||||||
|
* @author Sean Owen
|
||||||
|
*/
|
||||||
|
pub trait RXingResultParser {
|
||||||
|
// private static final RXingResultParser[] PARSERS = {
|
||||||
|
// new BookmarkDoCoMoRXingResultParser(),
|
||||||
|
// new AddressBookDoCoMoRXingResultParser(),
|
||||||
|
// new EmailDoCoMoRXingResultParser(),
|
||||||
|
// new AddressBookAURXingResultParser(),
|
||||||
|
// new VCardRXingResultParser(),
|
||||||
|
// new BizcardRXingResultParser(),
|
||||||
|
// new VEventRXingResultParser(),
|
||||||
|
// new EmailAddressRXingResultParser(),
|
||||||
|
// new SMTPRXingResultParser(),
|
||||||
|
// new TelRXingResultParser(),
|
||||||
|
// new SMSMMSRXingResultParser(),
|
||||||
|
// new SMSTOMMSTORXingResultParser(),
|
||||||
|
// new GeoRXingResultParser(),
|
||||||
|
// new WifiRXingResultParser(),
|
||||||
|
// new URLTORXingResultParser(),
|
||||||
|
// new URIRXingResultParser(),
|
||||||
|
// new ISBNRXingResultParser(),
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/client/result/mod.rs
Normal file
7
src/client/result/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
mod ParsedResult;
|
||||||
|
pub use ParsedResult::*;
|
||||||
|
mod ResultParser;
|
||||||
|
|
||||||
|
mod ParsedResultType;
|
||||||
|
pub use ParsedResultType::*;
|
||||||
|
pub use ResultParser::*;
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
mod common;
|
mod common;
|
||||||
mod exceptions;
|
mod exceptions;
|
||||||
|
mod client;
|
||||||
|
|
||||||
#[cfg(feature="image")]
|
#[cfg(feature="image")]
|
||||||
mod BufferedImageLuminanceSource;
|
mod BufferedImageLuminanceSource;
|
||||||
|
|||||||
Reference in New Issue
Block a user