2 * Copyright 2007 ZXing authors
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.google.zxing.client.result;
19 import com.google.zxing.Result;
21 import java.util.Hashtable;
24 * <p>Abstract class representing the result of decoding a barcode, as more than
25 * a String -- as some type of structured data. This might be a subclass which represents
26 * a URL, or an e-mail address. {@link #parseReaderResult(com.google.zxing.Result)} will turn a raw
27 * decoded string into the most appropriate type of structured representation.</p>
29 * <p>Thanks to Jeff Griffin for proposing rewrite of these classes that relies less
30 * on exception-based mechanisms during parsing.</p>
32 * @author srowen@google.com (Sean Owen)
34 public abstract class ResultParser {
36 public static ParsedResult parseReaderResult(Result theResult) {
37 // This is a bit messy, but given limited options in MIDP / CLDC, this may well be the simplest
38 // way to go about this. For example, we have no reflection available, really.
39 // Order is important here.
41 if ((result = BookmarkDoCoMoResultParser.parse(theResult)) != null) {
43 } else if ((result = AddressBookDoCoMoResultParser.parse(theResult)) != null) {
45 } else if ((result = EmailDoCoMoResultParser.parse(theResult)) != null) {
47 } else if ((result = EmailAddressResultParser.parse(theResult)) != null) {
49 } else if ((result = AddressBookAUResultParser.parse(theResult)) != null) {
51 } else if ((result = TelResultParser.parse(theResult)) != null) {
53 } else if ((result = SMSResultParser.parse(theResult)) != null) {
55 } else if ((result = SMSTOResultParser.parse(theResult)) != null) {
57 } else if ((result = GeoResultParser.parse(theResult)) != null) {
59 } else if ((result = URLTOResultParser.parse(theResult)) != null) {
61 } else if ((result = URIResultParser.parse(theResult)) != null) {
63 } else if ((result = UPCResultParser.parse(theResult)) != null) {
66 return new TextParsedResult(theResult.getText(), null);
69 protected static void maybeAppend(String value, StringBuffer result) {
76 protected static void maybeAppend(String[] value, StringBuffer result) {
78 for (int i = 0; i < value.length; i++) {
80 result.append(value[i]);
85 protected static String unescapeBackslash(String escaped) {
86 if (escaped != null) {
87 int backslash = escaped.indexOf((int) '\\');
89 int max = escaped.length();
90 StringBuffer unescaped = new StringBuffer(max - 1);
91 unescaped.append(escaped.toCharArray(), 0, backslash);
92 boolean nextIsEscaped = false;
93 for (int i = backslash; i < max; i++) {
94 char c = escaped.charAt(i);
95 if (nextIsEscaped || c != '\\') {
97 nextIsEscaped = false;
102 return unescaped.toString();
108 protected static String urlDecode(String escaped) {
110 // No we can't use java.net.URLDecoder here. JavaME doesn't have it.
111 if (escaped == null) {
114 char[] escapedArray = escaped.toCharArray();
116 int first = findFirstEscape(escapedArray);
121 int max = escapedArray.length;
122 // final length is at most 2 less than original due to at least 1 unescaping
123 StringBuffer unescaped = new StringBuffer(max - 2);
124 // Can append everything up to first escape character
125 unescaped.append(escapedArray, 0, first);
127 for (int i = first; i < max; i++) {
128 char c = escapedArray[i];
130 // + is translated directly into a space
131 unescaped.append(' ');
132 } else if (c == '%') {
133 // Are there even two more chars? if not we will just copy the escaped sequence and be done
135 unescaped.append('%'); // append that % and move on
137 int firstDigitValue = parseHexDigit(escapedArray[++i]);
138 int secondDigitValue = parseHexDigit(escapedArray[++i]);
139 if (firstDigitValue < 0 || secondDigitValue < 0) {
140 // bad digit, just move on
141 unescaped.append('%');
142 unescaped.append(escapedArray[i-1]);
143 unescaped.append(escapedArray[i]);
145 unescaped.append((char) ((firstDigitValue << 4) + secondDigitValue));
151 return unescaped.toString();
154 private static int findFirstEscape(char[] escapedArray) {
155 int max = escapedArray.length;
156 for (int i = 0; i < max; i++) {
157 char c = escapedArray[i];
158 if (c == '+' || c == '%') {
165 private static int parseHexDigit(char c) {
168 return 10 + (c - 'a');
170 } else if (c >= 'A') {
172 return 10 + (c - 'A');
174 } else if (c >= '0') {
182 protected static Hashtable parseNameValuePairs(String uri) {
183 int paramStart = uri.indexOf('?');
184 if (paramStart < 0) {
187 Hashtable result = new Hashtable(3);
190 while ((paramEnd = uri.indexOf('&', paramStart)) >= 0) {
191 appendKeyValue(uri, paramStart, paramEnd, result);
192 paramStart = paramEnd + 1;
194 appendKeyValue(uri, paramStart, uri.length(), result);
198 private static void appendKeyValue(String uri, int paramStart, int paramEnd, Hashtable result) {
199 int separator = uri.indexOf('=', paramStart);
200 if (separator >= 0) {
202 String key = uri.substring(paramStart, separator);
203 String value = uri.substring(separator + 1, paramEnd);
204 value = urlDecode(value);
205 result.put(key, value);
208 String key = uri.substring(paramStart, paramEnd);
209 result.put(key, null);