Initial commit
This commit is contained in:
237
lib/src/main/java/com/king/zxing/DecodeHintManager.java
Normal file
237
lib/src/main/java/com/king/zxing/DecodeHintManager.java
Normal file
@@ -0,0 +1,237 @@
|
||||
package com.king.zxing;
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 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.
|
||||
*/
|
||||
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.zxing.DecodeHintType;
|
||||
|
||||
/**
|
||||
* @author Lachezar Dobrev
|
||||
*/
|
||||
final class DecodeHintManager {
|
||||
|
||||
private static final String TAG = DecodeHintManager.class.getSimpleName();
|
||||
|
||||
// This pattern is used in decoding integer arrays.
|
||||
private static final Pattern COMMA = Pattern.compile(",");
|
||||
|
||||
private DecodeHintManager() {}
|
||||
|
||||
/**
|
||||
* <p>Split a query string into a list of name-value pairs.</p>
|
||||
*
|
||||
* <p>This is an alternative to the {@link Uri#getQueryParameterNames()} and
|
||||
* {@link Uri#getQueryParameters(String)}, which are quirky and not suitable
|
||||
* for exist-only Uri parameters.</p>
|
||||
*
|
||||
* <p>This method ignores multiple parameters with the same name and returns the
|
||||
* first one only. This is technically incorrect, but should be acceptable due
|
||||
* to the method of processing Hints: no multiple values for a hint.</p>
|
||||
*
|
||||
* @param query query to split
|
||||
* @return name-value pairs
|
||||
*/
|
||||
private static Map<String,String> splitQuery(String query) {
|
||||
Map<String,String> map = new HashMap<>();
|
||||
int pos = 0;
|
||||
while (pos < query.length()) {
|
||||
if (query.charAt(pos) == '&') {
|
||||
// Skip consecutive ampersand separators.
|
||||
pos ++;
|
||||
continue;
|
||||
}
|
||||
int amp = query.indexOf('&', pos);
|
||||
int equ = query.indexOf('=', pos);
|
||||
if (amp < 0) {
|
||||
// This is the last element in the query, no more ampersand elements.
|
||||
String name;
|
||||
String text;
|
||||
if (equ < 0) {
|
||||
// No equal sign
|
||||
name = query.substring(pos);
|
||||
name = name.replace('+', ' '); // Preemptively decode +
|
||||
name = Uri.decode(name);
|
||||
text = "";
|
||||
} else {
|
||||
// Split name and text.
|
||||
name = query.substring(pos, equ);
|
||||
name = name.replace('+', ' '); // Preemptively decode +
|
||||
name = Uri.decode(name);
|
||||
text = query.substring(equ + 1);
|
||||
text = text.replace('+', ' '); // Preemptively decode +
|
||||
text = Uri.decode(text);
|
||||
}
|
||||
if (!map.containsKey(name)) {
|
||||
map.put(name, text);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (equ < 0 || equ > amp) {
|
||||
// No equal sign until the &: this is a simple parameter with no value.
|
||||
String name = query.substring(pos, amp);
|
||||
name = name.replace('+', ' '); // Preemptively decode +
|
||||
name = Uri.decode(name);
|
||||
if (!map.containsKey(name)) {
|
||||
map.put(name, "");
|
||||
}
|
||||
pos = amp + 1;
|
||||
continue;
|
||||
}
|
||||
String name = query.substring(pos, equ);
|
||||
name = name.replace('+', ' '); // Preemptively decode +
|
||||
name = Uri.decode(name);
|
||||
String text = query.substring(equ + 1, amp);
|
||||
text = text.replace('+', ' '); // Preemptively decode +
|
||||
text = Uri.decode(text);
|
||||
if (!map.containsKey(name)) {
|
||||
map.put(name, text);
|
||||
}
|
||||
pos = amp + 1;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
static Map<DecodeHintType,?> parseDecodeHints(Uri inputUri) {
|
||||
String query = inputUri.getEncodedQuery();
|
||||
if (query == null || query.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Extract parameters
|
||||
Map<String, String> parameters = splitQuery(query);
|
||||
|
||||
Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);
|
||||
|
||||
for (DecodeHintType hintType: DecodeHintType.values()) {
|
||||
|
||||
if (hintType == DecodeHintType.CHARACTER_SET ||
|
||||
hintType == DecodeHintType.NEED_RESULT_POINT_CALLBACK ||
|
||||
hintType == DecodeHintType.POSSIBLE_FORMATS) {
|
||||
continue; // This hint is specified in another way
|
||||
}
|
||||
|
||||
String parameterName = hintType.name();
|
||||
String parameterText = parameters.get(parameterName);
|
||||
if (parameterText == null) {
|
||||
continue;
|
||||
}
|
||||
if (hintType.getValueType().equals(Object.class)) {
|
||||
// This is an unspecified type of hint content. Use the value as is.
|
||||
// TODO: Can we make a different assumption on this?
|
||||
hints.put(hintType, parameterText);
|
||||
continue;
|
||||
}
|
||||
if (hintType.getValueType().equals(Void.class)) {
|
||||
// Void hints are just flags: use the constant specified by DecodeHintType
|
||||
hints.put(hintType, Boolean.TRUE);
|
||||
continue;
|
||||
}
|
||||
if (hintType.getValueType().equals(String.class)) {
|
||||
// A string hint: use the decoded value.
|
||||
hints.put(hintType, parameterText);
|
||||
continue;
|
||||
}
|
||||
if (hintType.getValueType().equals(Boolean.class)) {
|
||||
// A boolean hint: a few values for false, everything else is true.
|
||||
// An empty parameter is simply a flag-style parameter, assuming true
|
||||
if (parameterText.isEmpty()) {
|
||||
hints.put(hintType, Boolean.TRUE);
|
||||
} else if ("0".equals(parameterText) ||
|
||||
"false".equalsIgnoreCase(parameterText) ||
|
||||
"no".equalsIgnoreCase(parameterText)) {
|
||||
hints.put(hintType, Boolean.FALSE);
|
||||
} else {
|
||||
hints.put(hintType, Boolean.TRUE);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
if (hintType.getValueType().equals(int[].class)) {
|
||||
// An integer array. Used to specify valid lengths.
|
||||
// Strip a trailing comma as in Java style array initialisers.
|
||||
if (!parameterText.isEmpty() && parameterText.charAt(parameterText.length() - 1) == ',') {
|
||||
parameterText = parameterText.substring(0, parameterText.length() - 1);
|
||||
}
|
||||
String[] values = COMMA.split(parameterText);
|
||||
int[] array = new int[values.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
try {
|
||||
array[i] = Integer.parseInt(values[i]);
|
||||
} catch (NumberFormatException ignored) {
|
||||
Log.w(TAG, "Skipping array of integers hint " + hintType + " due to invalid numeric value: '" + values[i] + '\'');
|
||||
array = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (array != null) {
|
||||
hints.put(hintType, array);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
Log.w(TAG, "Unsupported hint type '" + hintType + "' of type " + hintType.getValueType());
|
||||
}
|
||||
|
||||
Log.i(TAG, "Hints from the URI: " + hints);
|
||||
return hints;
|
||||
}
|
||||
|
||||
static Map<DecodeHintType, Object> parseDecodeHints(Intent intent) {
|
||||
Bundle extras = intent.getExtras();
|
||||
if (extras == null || extras.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Map<DecodeHintType,Object> hints = new EnumMap<>(DecodeHintType.class);
|
||||
|
||||
for (DecodeHintType hintType: DecodeHintType.values()) {
|
||||
|
||||
if (hintType == DecodeHintType.CHARACTER_SET ||
|
||||
hintType == DecodeHintType.NEED_RESULT_POINT_CALLBACK ||
|
||||
hintType == DecodeHintType.POSSIBLE_FORMATS) {
|
||||
continue; // This hint is specified in another way
|
||||
}
|
||||
|
||||
String hintName = hintType.name();
|
||||
if (extras.containsKey(hintName)) {
|
||||
if (hintType.getValueType().equals(Void.class)) {
|
||||
// Void hints are just flags: use the constant specified by the DecodeHintType
|
||||
hints.put(hintType, Boolean.TRUE);
|
||||
} else {
|
||||
Object hintData = extras.get(hintName);
|
||||
if (hintType.getValueType().isInstance(hintData)) {
|
||||
hints.put(hintType, hintData);
|
||||
} else {
|
||||
Log.w(TAG, "Ignoring hint " + hintType + " because it is not assignable from " + hintData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Log.i(TAG, "Hints from the Intent: " + hints);
|
||||
return hints;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user