mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
Add ENCODING=QUOTED-PRINTABLE support
git-svn-id: https://zxing.googlecode.com/svn/trunk@1317 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
52ba624795
commit
8a46200c72
|
@ -69,11 +69,14 @@ final class VCardResultParser extends ResultParser {
|
|||
Vector matches = null;
|
||||
int i = 0;
|
||||
int max = rawText.length();
|
||||
|
||||
while (i < max) {
|
||||
|
||||
i = rawText.indexOf(prefix, i);
|
||||
if (i < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (i > 0 && rawText.charAt(i - 1) != '\n') {
|
||||
// then this didn't start a new token, we matched in the middle of something
|
||||
i++;
|
||||
|
@ -83,39 +86,81 @@ final class VCardResultParser extends ResultParser {
|
|||
if (rawText.charAt(i) != ':' && rawText.charAt(i) != ';') {
|
||||
continue;
|
||||
}
|
||||
|
||||
int metadataStart = i;
|
||||
while (rawText.charAt(i) != ':') { // Skip until a colon
|
||||
i++;
|
||||
}
|
||||
|
||||
boolean quotedPrintable = false;
|
||||
if (i > metadataStart) {
|
||||
// There was something after the tag, before colon
|
||||
int j = metadataStart+1;
|
||||
while (j <= i) {
|
||||
if (rawText.charAt(j) == ';' || rawText.charAt(j) == ':') {
|
||||
String metadata = rawText.substring(metadataStart+1, j);
|
||||
int equals = metadata.indexOf('=');
|
||||
if (equals >= 0) {
|
||||
String key = metadata.substring(0, equals);
|
||||
String value = metadata.substring(equals+1);
|
||||
if (key.equalsIgnoreCase("ENCODING")) {
|
||||
if (value.equalsIgnoreCase("QUOTED-PRINTABLE")) {
|
||||
quotedPrintable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
metadataStart = j;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
i++; // skip colon
|
||||
int start = i; // Found the start of a match here
|
||||
while ((i = rawText.indexOf((int) '\n', i)) >= 0 && // Really, ends in \r\n
|
||||
i < rawText.length() - 1 && // But if followed by tab or space,
|
||||
|
||||
int matchStart = i; // Found the start of a match here
|
||||
|
||||
while ((i = rawText.indexOf((int) '\n', i)) >= 0) { // Really, end in \r\n
|
||||
if (i < rawText.length() - 1 && // But if followed by tab or space,
|
||||
(rawText.charAt(i+1) == ' ' || // this is only a continuation
|
||||
rawText.charAt(i+1) == '\t')) {
|
||||
i += 2;
|
||||
i += 2; // Skip \n and continutation whitespace
|
||||
} else if (quotedPrintable && // If preceded by = in quoted printable
|
||||
(rawText.charAt(i-1) == '=' || // this is a continuation
|
||||
rawText.charAt(i-2) == '=')) {
|
||||
i++; // Skip \n
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i < 0) {
|
||||
// No terminating end character? uh, done. Set i such that loop terminates and break
|
||||
i = max;
|
||||
} else if (i > start) {
|
||||
} else if (i > matchStart) {
|
||||
// found a match
|
||||
if (matches == null) {
|
||||
matches = new Vector(3); // lazy init
|
||||
matches = new Vector(1); // lazy init
|
||||
}
|
||||
if (rawText.charAt(i-1) == '\r') {
|
||||
i--; // Back up over \r, which really should be there
|
||||
}
|
||||
String element = rawText.substring(start, i);
|
||||
String element = rawText.substring(matchStart, i);
|
||||
if (trim) {
|
||||
element = element.trim();
|
||||
}
|
||||
if (quotedPrintable) {
|
||||
element = decodeQuotedPrintable(element);
|
||||
} else {
|
||||
element = stripContinuationCRLF(element);
|
||||
}
|
||||
matches.addElement(element);
|
||||
i++;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (matches == null || matches.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
@ -146,6 +191,50 @@ final class VCardResultParser extends ResultParser {
|
|||
return result.toString();
|
||||
}
|
||||
|
||||
private static String decodeQuotedPrintable(String value) {
|
||||
int length = value.length();
|
||||
StringBuffer result = new StringBuffer(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
char c = value.charAt(i);
|
||||
switch (c) {
|
||||
case '\r':
|
||||
case '\n':
|
||||
break;
|
||||
case '=':
|
||||
if (i < length - 2) {
|
||||
char nextChar = value.charAt(i+1);
|
||||
if (nextChar == '\r' || nextChar == '\n') {
|
||||
// Ignore, it's just a continuation symbol
|
||||
} else {
|
||||
char nextNextChar = value.charAt(i+2);
|
||||
try {
|
||||
int encodedChar = 16 * toHexValue(nextChar) + toHexValue(nextNextChar);
|
||||
result.append((char) encodedChar);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
// continue, assume it was incorrectly encoded
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
result.append(c);
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private static int toHexValue(char c) {
|
||||
if (c >= '0' && c <= '9') {
|
||||
return c - '0';
|
||||
} else if (c >= 'A' && c <= 'F') {
|
||||
return c - 'A' + 10;
|
||||
} else if (c >= 'a' && c <= 'f') {
|
||||
return c - 'a' + 10;
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
static String matchSingleVCardPrefixedField(String prefix, String rawText, boolean trim) {
|
||||
String[] values = matchVCardPrefixedField(prefix, rawText, trim);
|
||||
return values == null ? null : values[0];
|
||||
|
|
|
@ -60,6 +60,15 @@ public final class AddressBookParsedResultTestCase extends TestCase {
|
|||
new String[] {"5555555555" }, "Company", null, null, "This is the memo.");
|
||||
}
|
||||
|
||||
public void testQuotedPrintable() {
|
||||
doTest("BEGIN:VCARD\r\nADR;HOME;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;;" +
|
||||
"=35=38=20=4C=79=6E=62=72=6F=6F=6B=0D=0A=43=\r\n" +
|
||||
"=4F=20=36=39=39=\r\n" +
|
||||
"=32=36;;;\r\nEND:VCARD",
|
||||
null, null, null, new String[] {"58 Lynbrook\r\nCO 69926"},
|
||||
null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
private static void doTest(String contents,
|
||||
String title,
|
||||
String[] names,
|
||||
|
|
Loading…
Reference in a new issue