summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/pim/vcard/VCardParser.java16
-rw-r--r--core/java/android/pim/vcard/VCardParser_V21.java93
-rw-r--r--core/java/android/pim/vcard/VCardParser_V30.java13
-rw-r--r--core/java/android/pim/vcard/exception/VCardAgentNotSupportedException.java27
-rw-r--r--tests/AndroidTests/res/raw/v21_winmo_65.vcf10
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNodesVerifier.java12
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/vcard/VCardImporterTests.java32
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java10
8 files changed, 177 insertions, 36 deletions
diff --git a/core/java/android/pim/vcard/VCardParser.java b/core/java/android/pim/vcard/VCardParser.java
index 0ffdb6c..462e22c 100644
--- a/core/java/android/pim/vcard/VCardParser.java
+++ b/core/java/android/pim/vcard/VCardParser.java
@@ -21,9 +21,23 @@ import java.io.IOException;
import java.io.InputStream;
public abstract class VCardParser {
+ public static final int PARSER_MODE_DEFAULT = 0;
+ /**
+ * The parser should ignore "AGENT" properties and nested vCard structure.
+ */
+ public static final int PARSER_MODE_SCAN = 1;
+ protected final int mParserMode;
protected boolean mCanceled;
-
+
+ public VCardParser() {
+ mParserMode = PARSER_MODE_DEFAULT;
+ }
+
+ public VCardParser(int parserMode) {
+ mParserMode = parserMode;
+ }
+
/**
* Parses the given stream and send the VCard data into VCardBuilderBase object.
*
diff --git a/core/java/android/pim/vcard/VCardParser_V21.java b/core/java/android/pim/vcard/VCardParser_V21.java
index 748ea37..251db68 100644
--- a/core/java/android/pim/vcard/VCardParser_V21.java
+++ b/core/java/android/pim/vcard/VCardParser_V21.java
@@ -15,11 +15,11 @@
*/
package android.pim.vcard;
+import android.pim.vcard.exception.VCardAgentNotSupportedException;
import android.pim.vcard.exception.VCardException;
import android.pim.vcard.exception.VCardInvalidCommentLineException;
import android.pim.vcard.exception.VCardInvalidLineException;
import android.pim.vcard.exception.VCardNestedException;
-import android.pim.vcard.exception.VCardNotSupportedException;
import android.pim.vcard.exception.VCardVersionException;
import android.util.Log;
@@ -91,8 +91,15 @@ public class VCardParser_V21 extends VCardParser {
// In order to reduce warning message as much as possible, we hold the value which made Logger
// emit a warning message.
- protected HashSet<String> mWarningValueMap = new HashSet<String>();
-
+ protected HashSet<String> mUnknownTypeMap = new HashSet<String>();
+ protected HashSet<String> mUnknownValueMap = new HashSet<String>();
+
+ // It seems Windows Mobile 6.5 uses "AGENT" property with completely wrong usage.
+ // We should just ignore just one line.
+ // e.g.
+ // "AGENT;CHARSET=SHIFT_JIS:some text"
+ private boolean mIgnoreAgentLine = false;
+
// Just for debugging
private long mTimeTotal;
private long mTimeReadStartRecord;
@@ -106,21 +113,41 @@ public class VCardParser_V21 extends VCardParser {
private long mTimeHandleMiscPropertyValue;
private long mTimeHandleQuotedPrintable;
private long mTimeHandleBase64;
-
+
/**
* Create a new VCard parser.
*/
public VCardParser_V21() {
- super();
+ this(null, PARSER_MODE_DEFAULT);
+ }
+
+ public VCardParser_V21(int parserMode) {
+ this(null, parserMode);
}
public VCardParser_V21(VCardSourceDetector detector) {
- super();
- if (detector != null && detector.getType() == VCardSourceDetector.TYPE_FOMA) {
- mNestCount = 1;
+ this(detector, PARSER_MODE_DEFAULT);
+ }
+
+ /**
+ * TODO: Merge detector and parser mode.
+ */
+ public VCardParser_V21(VCardSourceDetector detector, int parserMode) {
+ super(parserMode);
+ if (detector != null) {
+ final int type = detector.getType();
+ if (type == VCardSourceDetector.TYPE_FOMA) {
+ mNestCount = 1;
+ } else if (type == VCardSourceDetector.TYPE_JAPANESE_MOBILE_PHONE) {
+ mIgnoreAgentLine = true;
+ }
+ }
+
+ if (parserMode == PARSER_MODE_SCAN) {
+ mIgnoreAgentLine = true;
}
}
-
+
/**
* Parse the file at the given position
* vcard_file = [wsls] vcard [wsls]
@@ -160,8 +187,8 @@ public class VCardParser_V21 extends VCardParser {
protected boolean isValidPropertyName(String propertyName) {
if (!(sAvailablePropertyNameSetV21.contains(propertyName.toUpperCase()) ||
propertyName.startsWith("X-")) &&
- !mWarningValueMap.contains(propertyName)) {
- mWarningValueMap.add(propertyName);
+ !mUnknownTypeMap.contains(propertyName)) {
+ mUnknownTypeMap.add(propertyName);
Log.w(LOG_TAG, "Property name unsupported by vCard 2.1: " + propertyName);
}
return true;
@@ -554,9 +581,9 @@ public class VCardParser_V21 extends VCardParser {
protected void handleType(final String ptypeval) {
String upperTypeValue = ptypeval;
if (!(sKnownTypeSet.contains(upperTypeValue) || upperTypeValue.startsWith("X-")) &&
- !mWarningValueMap.contains(ptypeval)) {
- mWarningValueMap.add(ptypeval);
- Log.w(LOG_TAG, "Type unsupported by vCard 2.1: " + ptypeval);
+ !mUnknownTypeMap.contains(ptypeval)) {
+ mUnknownTypeMap.add(ptypeval);
+ Log.w(LOG_TAG, "TYPE unsupported by vCard 2.1: " + ptypeval);
}
if (mBuilder != null) {
mBuilder.propertyParamType("TYPE");
@@ -567,15 +594,16 @@ public class VCardParser_V21 extends VCardParser {
/**
* pvalueval = "INLINE" / "URL" / "CONTENT-ID" / "CID" / "X-" word
*/
- protected void handleValue(final String pvalueval) throws VCardException {
- if (sKnownValueSet.contains(pvalueval.toUpperCase()) ||
- pvalueval.startsWith("X-")) {
- if (mBuilder != null) {
- mBuilder.propertyParamType("VALUE");
- mBuilder.propertyParamValue(pvalueval);
- }
- } else {
- throw new VCardException("Unknown value \"" + pvalueval + "\"");
+ protected void handleValue(final String pvalueval) {
+ if (!sKnownValueSet.contains(pvalueval.toUpperCase()) &&
+ pvalueval.startsWith("X-") &&
+ !mUnknownValueMap.contains(pvalueval)) {
+ mUnknownValueMap.add(pvalueval);
+ Log.w(LOG_TAG, "VALUE unsupported by vCard 2.1: " + pvalueval);
+ }
+ if (mBuilder != null) {
+ mBuilder.propertyParamType("VALUE");
+ mBuilder.propertyParamValue(pvalueval);
}
}
@@ -800,9 +828,14 @@ public class VCardParser_V21 extends VCardParser {
* items *CRLF "END" [ws] ":" [ws] "VCARD"
*
*/
- protected void handleAgent(String propertyValue) throws VCardException {
- throw new VCardNotSupportedException("AGENT Property is not supported now.");
- /* This is insufficient support. Also, AGENT Property is very rare.
+ protected void handleAgent(final String propertyValue) throws VCardException {
+ if (mIgnoreAgentLine) {
+ return;
+ } else {
+ throw new VCardAgentNotSupportedException("AGENT Property is not supported now.");
+ }
+ /* This is insufficient support. Also, AGENT Property is very rare and really hard to
+ understand the content.
Ignore it for now.
String[] strArray = propertyValue.split(":", 2);
@@ -819,7 +852,7 @@ public class VCardParser_V21 extends VCardParser {
/**
* For vCard 3.0.
*/
- protected String maybeUnescapeText(String text) {
+ protected String maybeUnescapeText(final String text) {
return text;
}
@@ -827,11 +860,11 @@ public class VCardParser_V21 extends VCardParser {
* 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.
*/
- protected String maybeUnescapeCharacter(char ch) {
+ protected String maybeUnescapeCharacter(final char ch) {
return unescapeCharacter(ch);
}
- public static String unescapeCharacter(char ch) {
+ public static String unescapeCharacter(final 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.
@@ -843,7 +876,7 @@ public class VCardParser_V21 extends VCardParser {
}
@Override
- public boolean parse(InputStream is, VCardBuilder builder)
+ public boolean parse(final InputStream is, final VCardBuilder builder)
throws IOException, VCardException {
return parse(is, VCardConfig.DEFAULT_CHARSET, builder);
}
diff --git a/core/java/android/pim/vcard/VCardParser_V30.java b/core/java/android/pim/vcard/VCardParser_V30.java
index 86e7625..3dd467c 100644
--- a/core/java/android/pim/vcard/VCardParser_V30.java
+++ b/core/java/android/pim/vcard/VCardParser_V30.java
@@ -72,6 +72,11 @@ public class VCardParser_V30 extends VCardParser_V21 {
mStrictParsing = strictParsing;
}
+ public VCardParser_V30(int parseMode) {
+ super(parseMode);
+ mStrictParsing = false;
+ }
+
@Override
protected int getVersion() {
return VCardConfig.FLAG_V30;
@@ -87,18 +92,18 @@ public class VCardParser_V30 extends VCardParser_V21 {
if (!(sAcceptablePropsWithParam.contains(propertyName) ||
acceptablePropsWithoutParam.contains(propertyName) ||
propertyName.startsWith("X-")) &&
- !mWarningValueMap.contains(propertyName)) {
- mWarningValueMap.add(propertyName);
+ !mUnknownTypeMap.contains(propertyName)) {
+ mUnknownTypeMap.add(propertyName);
Log.w(LOG_TAG, "Property name unsupported by vCard 3.0: " + propertyName);
}
return true;
}
-
+
@Override
protected boolean isValidEncoding(String encoding) {
return sAcceptableEncodingV30.contains(encoding.toUpperCase());
}
-
+
@Override
protected String getLine() throws IOException {
if (mPreviousLine != null) {
diff --git a/core/java/android/pim/vcard/exception/VCardAgentNotSupportedException.java b/core/java/android/pim/vcard/exception/VCardAgentNotSupportedException.java
new file mode 100644
index 0000000..e72c7df
--- /dev/null
+++ b/core/java/android/pim/vcard/exception/VCardAgentNotSupportedException.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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 android.pim.vcard.exception;
+
+public class VCardAgentNotSupportedException extends VCardNotSupportedException {
+ public VCardAgentNotSupportedException() {
+ super();
+ }
+
+ public VCardAgentNotSupportedException(String message) {
+ super(message);
+ }
+
+} \ No newline at end of file
diff --git a/tests/AndroidTests/res/raw/v21_winmo_65.vcf b/tests/AndroidTests/res/raw/v21_winmo_65.vcf
new file mode 100644
index 0000000..f380d0d
--- /dev/null
+++ b/tests/AndroidTests/res/raw/v21_winmo_65.vcf
@@ -0,0 +1,10 @@
+BEGIN:VCARD
+VERSION:2.1
+N:Example;;;;
+FN:Example
+ANNIVERSARY;VALUE=DATE:20091010
+AGENT:Invalid line which must be handled correctly.
+X-CLASS:PUBLIC
+X-REDUCTION:
+X-NO:
+END:VCARD
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNodesVerifier.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNodesVerifier.java
index 917b18e..a9775fa 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNodesVerifier.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/PropertyNodesVerifier.java
@@ -23,7 +23,6 @@ import android.pim.vcard.VCardParser_V21;
import android.pim.vcard.VCardParser_V30;
import android.pim.vcard.exception.VCardException;
import android.test.AndroidTestCase;
-import android.util.Log;
import junit.framework.TestCase;
@@ -56,6 +55,12 @@ public class PropertyNodesVerifier extends VNodeBuilder {
verify(mAndroidTestCase.getContext().getResources().openRawResource(resId), vCardType);
}
+ public void verify(int resId, int vCardType, final VCardParser vCardParser)
+ throws IOException, VCardException {
+ verify(mAndroidTestCase.getContext().getResources().openRawResource(resId),
+ vCardType, vCardParser);
+ }
+
public void verify(InputStream is, int vCardType) throws IOException, VCardException {
final VCardParser vCardParser;
if (VCardConfig.isV30(vCardType)) {
@@ -63,6 +68,11 @@ public class PropertyNodesVerifier extends VNodeBuilder {
} else {
vCardParser = new VCardParser_V21();
}
+ verify(is, vCardType, vCardParser);
+ }
+
+ public void verify(InputStream is, int vCardType, final VCardParser vCardParser)
+ throws IOException, VCardException {
try {
vCardParser.parse(is, this);
} finally {
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardImporterTests.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardImporterTests.java
index 169ea71..b1fccaa 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardImporterTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardImporterTests.java
@@ -16,7 +16,10 @@
package com.android.unit_tests.vcard;
+import android.content.ContentValues;
import android.pim.vcard.VCardConfig;
+import android.pim.vcard.VCardParser;
+import android.pim.vcard.VCardParser_V21;
import android.pim.vcard.exception.VCardException;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.CommonDataKinds.Email;
@@ -999,6 +1002,35 @@ public class VCardImporterTests extends VCardTestsBase {
verifier.verify(R.raw.v21_multiple_entry, VCardConfig.VCARD_TYPE_V21_JAPANESE_SJIS);
}
+ public void testIgnoreAgentV21_Parse() throws IOException, VCardException {
+ PropertyNodesVerifier verifier = new PropertyNodesVerifier(this);
+ ContentValues contentValuesForValue = new ContentValues();
+ contentValuesForValue.put("VALUE", "DATE");
+ verifier.addPropertyNodesVerifierElem()
+ .addNodeWithOrder("VERSION", "2.1")
+ .addNodeWithOrder("N", Arrays.asList("Example", "", "", "", ""))
+ .addNodeWithOrder("FN", "Example")
+ .addNodeWithOrder("ANNIVERSARY", "20091010", contentValuesForValue)
+ .addNodeWithOrder("AGENT", "")
+ .addNodeWithOrder("X-CLASS", "PUBLIC")
+ .addNodeWithOrder("X-REDUCTION", "")
+ .addNodeWithOrder("X-NO", "");
+
+ // Only scan mode lets vCard parser accepts invalid AGENT lines like above.
+ verifier.verify(R.raw.v21_winmo_65, V21,
+ new VCardParser_V21(VCardParser.PARSER_MODE_SCAN));
+ }
+
+ public void testIgnoreAgentV21() throws IOException, VCardException {
+ ImportVerifier verifier = new ImportVerifier();
+ ImportVerifierElem elem = verifier.addImportVerifierElem();
+ elem.addExpected(StructuredName.CONTENT_ITEM_TYPE)
+ .put(StructuredName.FAMILY_NAME, "Example")
+ .put(StructuredName.DISPLAY_NAME, "Example");
+ verifier.verify(R.raw.v21_winmo_65, V21,
+ new VCardParser_V21(VCardParser.PARSER_MODE_SCAN));
+ }
+
public void testPagerV30_Parse() throws IOException, VCardException {
PropertyNodesVerifier verifier = new PropertyNodesVerifier(this);
verifier.addPropertyNodesVerifierElem()
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java
index bd4d13a..6176f5c 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardTestsBase.java
@@ -455,6 +455,11 @@ class CustomMockContext extends MockContext {
verify(getContext().getResources().openRawResource(resId), vCardType);
}
+ public void verify(int resId, int vCardType, final VCardParser vCardParser)
+ throws IOException, VCardException {
+ verify(getContext().getResources().openRawResource(resId), vCardType, vCardParser);
+ }
+
public void verify(InputStream is, int vCardType) throws IOException, VCardException {
final VCardParser vCardParser;
if (VCardConfig.isV30(vCardType)) {
@@ -462,6 +467,11 @@ class CustomMockContext extends MockContext {
} else {
vCardParser = new VCardParser_V21();
}
+ verify(is, vCardType, vCardParser);
+ }
+
+ public void verify(InputStream is, int vCardType, final VCardParser vCardParser)
+ throws IOException, VCardException {
VCardDataBuilder builder =
new VCardDataBuilder(null, null, false, vCardType, null);
builder.addEntryHandler(this);