Methods Summary |
---|
public void | addInterpreter(VCardInterpreter interpreter)
mInterpreterList.add(interpreter);
|
public final synchronized void | cancel()
Log.i(LOG_TAG, "ParserImpl received cancel operation.");
mCanceled = true;
|
protected VCardProperty | constructPropertyData(java.lang.String line)
final VCardProperty propertyData = new VCardProperty();
final int length = line.length();
if (length > 0 && line.charAt(0) == '#") {
throw new VCardInvalidCommentLineException();
}
int state = STATE_GROUP_OR_PROPERTY_NAME;
int nameIndex = 0;
// This loop is developed so that we don't have to take care of bottle neck here.
// Refactor carefully when you need to do so.
for (int i = 0; i < length; i++) {
final char ch = line.charAt(i);
switch (state) {
case STATE_GROUP_OR_PROPERTY_NAME: {
if (ch == ':") { // End of a property name.
final String propertyName = line.substring(nameIndex, i);
propertyData.setName(propertyName);
propertyData.setRawValue( i < length - 1 ? line.substring(i + 1) : "");
return propertyData;
} else if (ch == '.") { // Each group is followed by the dot.
final String groupName = line.substring(nameIndex, i);
if (groupName.length() == 0) {
Log.w(LOG_TAG, "Empty group found. Ignoring.");
} else {
propertyData.addGroup(groupName);
}
nameIndex = i + 1; // Next should be another group or a property name.
} else if (ch == ';") { // End of property name and beginneng of parameters.
final String propertyName = line.substring(nameIndex, i);
propertyData.setName(propertyName);
nameIndex = i + 1;
state = STATE_PARAMS; // Start parameter parsing.
}
// TODO: comma support (in vCard 3.0 and 4.0).
break;
}
case STATE_PARAMS: {
if (ch == '"") {
if (VCardConstants.VERSION_V21.equalsIgnoreCase(getVersionString())) {
Log.w(LOG_TAG, "Double-quoted params found in vCard 2.1. " +
"Silently allow it");
}
state = STATE_PARAMS_IN_DQUOTE;
} else if (ch == ';") { // Starts another param.
handleParams(propertyData, line.substring(nameIndex, i));
nameIndex = i + 1;
} else if (ch == ':") { // End of param and beginenning of values.
handleParams(propertyData, line.substring(nameIndex, i));
propertyData.setRawValue(i < length - 1 ? line.substring(i + 1) : "");
return propertyData;
}
break;
}
case STATE_PARAMS_IN_DQUOTE: {
if (ch == '"") {
if (VCardConstants.VERSION_V21.equalsIgnoreCase(getVersionString())) {
Log.w(LOG_TAG, "Double-quoted params found in vCard 2.1. " +
"Silently allow it");
}
state = STATE_PARAMS;
}
break;
}
}
}
throw new VCardInvalidLineException("Invalid line: \"" + line + "\"");
|
protected java.util.Set | getAvailableEncodingSet()
return VCardParser_V21.sAvailableEncoding;
|
protected java.lang.String | getBase64(java.lang.String firstString)
final StringBuilder builder = new StringBuilder();
builder.append(firstString);
while (true) {
final String line = peekLine();
if (line == null) {
throw new VCardException("File ended during parsing BASE64 binary");
}
// vCard 2.1 requires two spaces at the end of BASE64 strings, but some vCard doesn't
// have them. We try to detect those cases using colon and semi-colon, given BASE64
// does not contain it.
// E.g.
// TEL;TYPE=WORK:+5555555
// or
// END:VCARD
String propertyName = getPropertyNameUpperCase(line);
if (getKnownPropertyNameSet().contains(propertyName) ||
VCardConstants.PROPERTY_X_ANDROID_CUSTOM.equals(propertyName)) {
Log.w(LOG_TAG, "Found a next property during parsing a BASE64 string, " +
"which must not contain semi-colon or colon. Treat the line as next "
+ "property.");
Log.w(LOG_TAG, "Problematic line: " + line.trim());
break;
}
// Consume the line.
getLine();
if (line.length() == 0) {
break;
}
// Trim off any extraneous whitespace to handle 2.1 implementations
// that use 3.0 style line continuations. This is safe because space
// isn't a Base64 encoding value.
builder.append(line.trim());
}
return builder.toString();
|
protected java.lang.String | getCurrentCharset()
return mCurrentCharset;
|
protected java.lang.String | getDefaultCharset()
return DEFAULT_CHARSET;
|
protected java.lang.String | getDefaultEncoding()
return DEFAULT_ENCODING;
|
protected java.util.Set | getKnownPropertyNameSet()
return VCardParser_V21.sKnownPropertyNameSet;
|
protected java.util.Set | getKnownTypeSet()
return VCardParser_V21.sKnownTypeSet;
|
protected java.util.Set | getKnownValueSet()
return VCardParser_V21.sKnownValueSet;
|
protected java.lang.String | getLine()
return mReader.readLine();
|
protected java.lang.String | getNonEmptyLine()
String line;
while (true) {
line = getLine();
if (line == null) {
throw new VCardException("Reached end of buffer.");
} else if (line.trim().length() > 0) {
return line;
}
}
|
private java.lang.String | getPotentialMultiline(java.lang.String firstString)Given the first line of a property, checks consecutive lines after it and builds a new
multi-line value if it exists.
final StringBuilder builder = new StringBuilder();
builder.append(firstString);
while (true) {
final String line = peekLine();
if (line == null || line.length() == 0) {
break;
}
final String propertyName = getPropertyNameUpperCase(line);
if (propertyName != null) {
break;
}
// vCard 2.1 does not allow multi-line of adr but microsoft vcards may have it.
// We will consider the next line to be a part of a multi-line value if it does not
// contain a property name (i.e. a colon or semi-colon).
// Consume the line.
getLine();
builder.append(" ").append(line);
}
return builder.toString();
|
private java.lang.String | getPropertyNameUpperCase(java.lang.String line)Extracts the property name portion of a given vCard line.
Properties must contain a colon.
E.g.
TEL;TYPE=WORK:+5555555 // returns "TEL"
END:VCARD // returns "END"
TEL; // returns null
final int colonIndex = line.indexOf(":");
if (colonIndex > -1) {
final int semiColonIndex = line.indexOf(";");
// Find the minimum index that is greater than -1.
final int minIndex;
if (colonIndex == -1) {
minIndex = semiColonIndex;
} else if (semiColonIndex == -1) {
minIndex = colonIndex;
} else {
minIndex = Math.min(colonIndex, semiColonIndex);
}
return line.substring(0, minIndex).toUpperCase();
}
return null;
|
private java.lang.String | getQuotedPrintablePart(java.lang.String firstString)
Parses and returns Quoted-Printable.
// Specifically, there may be some padding between = and CRLF.
// See the following:
//
// qp-line := *(qp-segment transport-padding CRLF)
// qp-part transport-padding
// qp-segment := qp-section *(SPACE / TAB) "="
// ; Maximum length of 76 characters
//
// e.g. (from RFC 2045)
// Now's the time =
// for all folk to come=
// to the aid of their country.
if (firstString.trim().endsWith("=")) {
// remove "transport-padding"
int pos = firstString.length() - 1;
while (firstString.charAt(pos) != '=") {
}
StringBuilder builder = new StringBuilder();
builder.append(firstString.substring(0, pos + 1));
builder.append("\r\n");
String line;
while (true) {
line = getLine();
if (line == null) {
throw new VCardException("File ended during parsing a Quoted-Printable String");
}
if (line.trim().endsWith("=")) {
// remove "transport-padding"
pos = line.length() - 1;
while (line.charAt(pos) != '=") {
}
builder.append(line.substring(0, pos + 1));
builder.append("\r\n");
} else {
builder.append(line);
break;
}
}
return builder.toString();
} else {
return firstString;
}
|
protected int | getVersion()
return VCardConfig.VERSION_21;
|
protected java.lang.String | getVersionString()
return VCardConstants.VERSION_V21;
|
private void | handleAdrOrgN(VCardProperty property, java.lang.String propertyRawValue, java.lang.String sourceCharset, java.lang.String targetCharset)
List<String> encodedValueList = new ArrayList<String>();
// vCard 2.1 does not allow QUOTED-PRINTABLE here, but some softwares/devices emit
// such data.
if (mCurrentEncoding.equals(VCardConstants.PARAM_ENCODING_QP)) {
// First we retrieve Quoted-Printable String from vCard entry, which may include
// multiple lines.
final String quotedPrintablePart = getQuotedPrintablePart(propertyRawValue);
// "Raw value" from the view of users should contain all part of QP string.
// TODO: add test for this handling
property.setRawValue(quotedPrintablePart);
// We split Quoted-Printable String using semi-colon before decoding it, as
// the Quoted-Printable may have semi-colon, which confuses splitter.
final List<String> quotedPrintableValueList =
VCardUtils.constructListFromValue(quotedPrintablePart, getVersion());
for (String quotedPrintableValue : quotedPrintableValueList) {
String encoded = VCardUtils.parseQuotedPrintable(quotedPrintableValue,
false, sourceCharset, targetCharset);
encodedValueList.add(encoded);
}
} else {
final String propertyValue = getPotentialMultiline(propertyRawValue);
final List<String> rawValueList =
VCardUtils.constructListFromValue(propertyValue, getVersion());
for (String rawValue : rawValueList) {
encodedValueList.add(VCardUtils.convertStringCharset(
rawValue, sourceCharset, targetCharset));
}
}
property.setValues(encodedValueList);
for (VCardInterpreter interpreter : mInterpreterList) {
interpreter.onPropertyCreated(property);
}
|
protected void | handleAgent(VCardProperty property)
if (!property.getRawValue().toUpperCase().contains("BEGIN:VCARD")) {
// Apparently invalid line seen in Windows Mobile 6.5. Ignore them.
for (VCardInterpreter interpreter : mInterpreterList) {
interpreter.onPropertyCreated(property);
}
return;
} else {
throw new VCardAgentNotSupportedException("AGENT Property is not supported now.");
}
|
protected void | handleAnyParam(VCardProperty propertyData, java.lang.String paramName, java.lang.String paramValue)Mainly for "X-" type. This accepts any kind of type without check.
propertyData.addParameter(paramName, paramValue);
|
protected void | handleCharset(VCardProperty propertyData, java.lang.String charsetval)
vCard 2.1 specification only allows us-ascii and iso-8859-xxx (See RFC 1521),
but recent vCard files often contain other charset like UTF-8, SHIFT_JIS, etc.
We allow any charset.
mCurrentCharset = charsetval;
propertyData.addParameter(VCardConstants.PARAM_CHARSET, charsetval);
|
protected void | handleEncoding(VCardProperty propertyData, java.lang.String pencodingval)
if (getAvailableEncodingSet().contains(pencodingval) ||
pencodingval.startsWith("X-")) {
propertyData.addParameter(VCardConstants.PARAM_ENCODING, pencodingval);
// Update encoding right away, as this is needed to understanding other params.
mCurrentEncoding = pencodingval.toUpperCase();
} else {
throw new VCardException("Unknown encoding \"" + pencodingval + "\"");
}
|
protected void | handleLanguage(VCardProperty propertyData, java.lang.String langval)See also Section 7.1 of RFC 1521
String[] strArray = langval.split("-");
if (strArray.length != 2) {
throw new VCardException("Invalid Language: \"" + langval + "\"");
}
String tmp = strArray[0];
int length = tmp.length();
for (int i = 0; i < length; i++) {
if (!isAsciiLetter(tmp.charAt(i))) {
throw new VCardException("Invalid Language: \"" + langval + "\"");
}
}
tmp = strArray[1];
length = tmp.length();
for (int i = 0; i < length; i++) {
if (!isAsciiLetter(tmp.charAt(i))) {
throw new VCardException("Invalid Language: \"" + langval + "\"");
}
}
propertyData.addParameter(VCardConstants.PARAM_LANGUAGE, langval);
|
private void | handleNest()
for (VCardInterpreter interpreter : mInterpreterList) {
interpreter.onEntryStarted();
}
parseItems();
for (VCardInterpreter interpreter : mInterpreterList) {
interpreter.onEntryEnded();
}
|
protected void | handleParamWithoutName(VCardProperty propertyData, java.lang.String paramValue)vCard 3.0 parser implementation may throw VCardException.
handleType(propertyData, paramValue);
|
protected void | handleParams(VCardProperty propertyData, java.lang.String params)
final String[] strArray = params.split("=", 2);
if (strArray.length == 2) {
final String paramName = strArray[0].trim().toUpperCase();
String paramValue = strArray[1].trim();
if (paramName.equals("TYPE")) {
handleType(propertyData, paramValue);
} else if (paramName.equals("VALUE")) {
handleValue(propertyData, paramValue);
} else if (paramName.equals("ENCODING")) {
handleEncoding(propertyData, paramValue.toUpperCase());
} else if (paramName.equals("CHARSET")) {
handleCharset(propertyData, paramValue);
} else if (paramName.equals("LANGUAGE")) {
handleLanguage(propertyData, paramValue);
} else if (paramName.startsWith("X-")) {
handleAnyParam(propertyData, paramName, paramValue);
} else {
throw new VCardException("Unknown type \"" + paramName + "\"");
}
} else {
handleParamWithoutName(propertyData, strArray[0]);
}
|
protected void | handlePropertyValue(VCardProperty property, java.lang.String propertyName)
final String propertyNameUpper = property.getName().toUpperCase();
String propertyRawValue = property.getRawValue();
final String sourceCharset = VCardConfig.DEFAULT_INTERMEDIATE_CHARSET;
final Collection<String> charsetCollection =
property.getParameters(VCardConstants.PARAM_CHARSET);
String targetCharset =
((charsetCollection != null) ? charsetCollection.iterator().next() : null);
if (TextUtils.isEmpty(targetCharset)) {
targetCharset = VCardConfig.DEFAULT_IMPORT_CHARSET;
}
// TODO: have "separableProperty" which reflects vCard spec..
if (propertyNameUpper.equals(VCardConstants.PROPERTY_ADR)
|| propertyNameUpper.equals(VCardConstants.PROPERTY_ORG)
|| propertyNameUpper.equals(VCardConstants.PROPERTY_N)) {
handleAdrOrgN(property, propertyRawValue, sourceCharset, targetCharset);
return;
}
if (mCurrentEncoding.equals(VCardConstants.PARAM_ENCODING_QP) ||
// If encoding attribute is missing, then attempt to detect QP encoding.
// This is to handle a bug where the android exporter was creating FN properties
// with missing encoding. b/7292017
(propertyNameUpper.equals(VCardConstants.PROPERTY_FN) &&
property.getParameters(VCardConstants.PARAM_ENCODING) == null &&
VCardUtils.appearsLikeAndroidVCardQuotedPrintable(propertyRawValue))
) {
final String quotedPrintablePart = getQuotedPrintablePart(propertyRawValue);
final String propertyEncodedValue =
VCardUtils.parseQuotedPrintable(quotedPrintablePart,
false, sourceCharset, targetCharset);
property.setRawValue(quotedPrintablePart);
property.setValues(propertyEncodedValue);
for (VCardInterpreter interpreter : mInterpreterList) {
interpreter.onPropertyCreated(property);
}
} else if (mCurrentEncoding.equals(VCardConstants.PARAM_ENCODING_BASE64)
|| mCurrentEncoding.equals(VCardConstants.PARAM_ENCODING_B)) {
// It is very rare, but some BASE64 data may be so big that
// OutOfMemoryError occurs. To ignore such cases, use try-catch.
try {
final String base64Property = getBase64(propertyRawValue);
try {
property.setByteValue(Base64.decode(base64Property, Base64.DEFAULT));
} catch (IllegalArgumentException e) {
throw new VCardException("Decode error on base64 photo: " + propertyRawValue);
}
for (VCardInterpreter interpreter : mInterpreterList) {
interpreter.onPropertyCreated(property);
}
} catch (OutOfMemoryError error) {
Log.e(LOG_TAG, "OutOfMemoryError happened during parsing BASE64 data!");
for (VCardInterpreter interpreter : mInterpreterList) {
interpreter.onPropertyCreated(property);
}
}
} else {
if (!(mCurrentEncoding.equals("7BIT") || mCurrentEncoding.equals("8BIT") ||
mCurrentEncoding.startsWith("X-"))) {
Log.w(LOG_TAG,
String.format("The encoding \"%s\" is unsupported by vCard %s",
mCurrentEncoding, getVersionString()));
}
// Some device uses line folding defined in RFC 2425, which is not allowed
// in vCard 2.1 (while needed in vCard 3.0).
//
// e.g.
// BEGIN:VCARD
// VERSION:2.1
// N:;Omega;;;
// EMAIL;INTERNET:"Omega"
// <omega@example.com>
// FN:Omega
// END:VCARD
//
// The vCard above assumes that email address should become:
// "Omega" <omega@example.com>
//
// But vCard 2.1 requires Quote-Printable when a line contains line break(s).
//
// For more information about line folding,
// see "5.8.1. Line delimiting and folding" in RFC 2425.
//
// We take care of this case more formally in vCard 3.0, so we only need to
// do this in vCard 2.1.
if (getVersion() == VCardConfig.VERSION_21) {
StringBuilder builder = null;
while (true) {
final String nextLine = peekLine();
// We don't need to care too much about this exceptional case,
// but we should not wrongly eat up "END:VCARD", since it critically
// breaks this parser's state machine.
// Thus we roughly look over the next line and confirm it is at least not
// "END:VCARD". This extra fee is worth paying. This is exceptional
// anyway.
if (!TextUtils.isEmpty(nextLine) &&
nextLine.charAt(0) == ' " &&
!"END:VCARD".contains(nextLine.toUpperCase())) {
getLine(); // Drop the next line.
if (builder == null) {
builder = new StringBuilder();
builder.append(propertyRawValue);
}
builder.append(nextLine.substring(1));
} else {
break;
}
}
if (builder != null) {
propertyRawValue = builder.toString();
}
}
ArrayList<String> propertyValueList = new ArrayList<String>();
String value = VCardUtils.convertStringCharset(
maybeUnescapeText(propertyRawValue), sourceCharset, targetCharset);
propertyValueList.add(value);
property.setValues(propertyValueList);
for (VCardInterpreter interpreter : mInterpreterList) {
interpreter.onPropertyCreated(property);
}
}
|
protected void | handleType(VCardProperty propertyData, java.lang.String ptypeval)
if (!(getKnownTypeSet().contains(ptypeval.toUpperCase())
|| ptypeval.startsWith("X-"))
&& !mUnknownTypeSet.contains(ptypeval)) {
mUnknownTypeSet.add(ptypeval);
Log.w(LOG_TAG, String.format("TYPE unsupported by %s: ", getVersion(), ptypeval));
}
propertyData.addParameter(VCardConstants.PARAM_TYPE, ptypeval);
|
protected void | handleValue(VCardProperty propertyData, java.lang.String pvalueval)
if (!(getKnownValueSet().contains(pvalueval.toUpperCase())
|| pvalueval.startsWith("X-")
|| mUnknownValueSet.contains(pvalueval))) {
mUnknownValueSet.add(pvalueval);
Log.w(LOG_TAG, String.format(
"The value unsupported by TYPE of %s: ", getVersion(), pvalueval));
}
propertyData.addParameter(VCardConstants.PARAM_VALUE, pvalueval);
|
private boolean | isAsciiLetter(char ch)
if ((ch >= 'a" && ch <= 'z") || (ch >= 'A" && ch <= 'Z")) {
return true;
}
return false;
|
protected boolean | isValidPropertyName(java.lang.String propertyName)
if (!(getKnownPropertyNameSet().contains(propertyName.toUpperCase()) ||
propertyName.startsWith("X-"))
&& !mUnknownTypeSet.contains(propertyName)) {
mUnknownTypeSet.add(propertyName);
Log.w(LOG_TAG, "Property name unsupported by vCard 2.1: " + propertyName);
}
return true;
|
protected java.lang.String | maybeUnescapeCharacter(char ch)Returns unescaped String if the character should be unescaped. Return
null otherwise. e.g. In vCard 2.1, "\;" should be unescaped into ";"
while "\x" should not be.
return unescapeCharacter(ch);
|
protected java.lang.String | maybeUnescapeText(java.lang.String text)For vCard 3.0.
return text;
|
public void | parse(java.io.InputStream is)
if (is == null) {
throw new NullPointerException("InputStream must not be null.");
}
final InputStreamReader tmpReader = new InputStreamReader(is, mIntermediateCharset);
mReader = new CustomBufferedReader(tmpReader);
final long start = System.currentTimeMillis();
for (VCardInterpreter interpreter : mInterpreterList) {
interpreter.onVCardStarted();
}
// vcard_file = [wsls] vcard [wsls]
while (true) {
synchronized (this) {
if (mCanceled) {
Log.i(LOG_TAG, "Cancel request has come. exitting parse operation.");
break;
}
}
if (!parseOneVCard()) {
break;
}
}
for (VCardInterpreter interpreter : mInterpreterList) {
interpreter.onVCardEnded();
}
|
protected boolean | parseItem()
// Reset for an item.
mCurrentEncoding = DEFAULT_ENCODING;
final String line = getNonEmptyLine();
final VCardProperty propertyData = constructPropertyData(line);
final String propertyNameUpper = propertyData.getName().toUpperCase();
final String propertyRawValue = propertyData.getRawValue();
if (propertyNameUpper.equals(VCardConstants.PROPERTY_BEGIN)) {
if (propertyRawValue.equalsIgnoreCase("VCARD")) {
handleNest();
} else {
throw new VCardException("Unknown BEGIN type: " + propertyRawValue);
}
} else if (propertyNameUpper.equals(VCardConstants.PROPERTY_END)) {
if (propertyRawValue.equalsIgnoreCase("VCARD")) {
return true; // Ended.
} else {
throw new VCardException("Unknown END type: " + propertyRawValue);
}
} else {
parseItemInter(propertyData, propertyNameUpper);
}
return false;
|
private void | parseItemInter(VCardProperty property, java.lang.String propertyNameUpper)
String propertyRawValue = property.getRawValue();
if (propertyNameUpper.equals(VCardConstants.PROPERTY_AGENT)) {
handleAgent(property);
} else if (isValidPropertyName(propertyNameUpper)) {
if (propertyNameUpper.equals(VCardConstants.PROPERTY_VERSION) &&
!propertyRawValue.equals(getVersionString())) {
throw new VCardVersionException(
"Incompatible version: " + propertyRawValue + " != " + getVersionString());
}
handlePropertyValue(property, propertyNameUpper);
} else {
throw new VCardException("Unknown property name: \"" + propertyNameUpper + "\"");
}
|
protected void | parseItems()Parses lines other than the first "BEGIN:VCARD". Takes care of "END:VCARD"n and
"BEGIN:VCARD" in nested vCard.
boolean ended = false;
try {
ended = parseItem();
} catch (VCardInvalidCommentLineException e) {
Log.e(LOG_TAG, "Invalid line which looks like some comment was found. Ignored.");
}
while (!ended) {
try {
ended = parseItem();
} catch (VCardInvalidCommentLineException e) {
Log.e(LOG_TAG, "Invalid line which looks like some comment was found. Ignored.");
}
}
|
public void | parseOne(java.io.InputStream is)
if (is == null) {
throw new NullPointerException("InputStream must not be null.");
}
final InputStreamReader tmpReader = new InputStreamReader(is, mIntermediateCharset);
mReader = new CustomBufferedReader(tmpReader);
final long start = System.currentTimeMillis();
for (VCardInterpreter interpreter : mInterpreterList) {
interpreter.onVCardStarted();
}
parseOneVCard();
for (VCardInterpreter interpreter : mInterpreterList) {
interpreter.onVCardEnded();
}
|
private boolean | parseOneVCard()
vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF
items *CRLF
"END" [ws] ":" [ws] "VCARD"
// reset for this entire vCard.
mCurrentEncoding = DEFAULT_ENCODING;
mCurrentCharset = DEFAULT_CHARSET;
boolean allowGarbage = false;
if (!readBeginVCard(allowGarbage)) {
return false;
}
for (VCardInterpreter interpreter : mInterpreterList) {
interpreter.onEntryStarted();
}
parseItems();
for (VCardInterpreter interpreter : mInterpreterList) {
interpreter.onEntryEnded();
}
return true;
|
protected java.lang.String | peekLine()
return mReader.peekLine();
|
protected boolean | readBeginVCard(boolean allowGarbage)
// TODO: use consructPropertyLine().
String line;
do {
while (true) {
line = getLine();
if (line == null) {
return false;
} else if (line.trim().length() > 0) {
break;
}
}
final String[] strArray = line.split(":", 2);
final int length = strArray.length;
// Although vCard 2.1/3.0 specification does not allow lower cases,
// we found vCard file emitted by some external vCard expoter have such
// invalid Strings.
// e.g. BEGIN:vCard
if (length == 2 && strArray[0].trim().equalsIgnoreCase("BEGIN")
&& strArray[1].trim().equalsIgnoreCase("VCARD")) {
return true;
} else if (!allowGarbage) {
throw new VCardException("Expected String \"BEGIN:VCARD\" did not come "
+ "(Instead, \"" + line + "\" came)");
}
} while (allowGarbage);
throw new VCardException("Reached where must not be reached.");
|
static java.lang.String | unescapeCharacter(char ch)
// Original vCard 2.1 specification does not allow transformation
// "\:" -> ":", "\," -> ",", and "\\" -> "\", but previous
// implementation of
// this class allowed them, so keep it as is.
if (ch == '\\" || ch == ';" || ch == ':" || ch == ',") {
return String.valueOf(ch);
} else {
return null;
}
|