summaryrefslogtreecommitdiffstats
path: root/core/java/android/pim/vcard/VCardParserImpl_V21.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/pim/vcard/VCardParserImpl_V21.java')
-rw-r--r--core/java/android/pim/vcard/VCardParserImpl_V21.java967
1 files changed, 0 insertions, 967 deletions
diff --git a/core/java/android/pim/vcard/VCardParserImpl_V21.java b/core/java/android/pim/vcard/VCardParserImpl_V21.java
deleted file mode 100644
index 7d294cc..0000000
--- a/core/java/android/pim/vcard/VCardParserImpl_V21.java
+++ /dev/null
@@ -1,967 +0,0 @@
-/*
- * Copyright (C) 2010 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;
-
-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.VCardVersionException;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * <p>
- * Basic implementation achieving vCard parsing. Based on vCard 2.1,
- * </p>
- * @hide
- */
-/* package */ class VCardParserImpl_V21 {
- private static final String LOG_TAG = "VCardParserImpl_V21";
-
- private static final class CustomBufferedReader extends BufferedReader {
- private long mTime;
-
- public CustomBufferedReader(Reader in) {
- super(in);
- }
-
- @Override
- public String readLine() throws IOException {
- long start = System.currentTimeMillis();
- String ret = super.readLine();
- long end = System.currentTimeMillis();
- mTime += end - start;
- return ret;
- }
-
- public long getTotalmillisecond() {
- return mTime;
- }
- }
-
- private static final String sDefaultEncoding = "8BIT";
-
- protected boolean mCanceled;
- protected VCardInterpreter mInterpreter;
-
- protected final String mImportCharset;
-
- /**
- * <p>
- * The encoding type for deconding byte streams. This member variable is
- * reset to a default encoding every time when a new item comes.
- * </p>
- * <p>
- * "Encoding" in vCard is different from "Charset". It is mainly used for
- * addresses, notes, images. "7BIT", "8BIT", "BASE64", and
- * "QUOTED-PRINTABLE" are known examples.
- * </p>
- */
- protected String mCurrentEncoding;
-
- /**
- * <p>
- * The reader object to be used internally.
- * </p>
- * <p>
- * Developers should not directly read a line from this object. Use
- * getLine() unless there some reason.
- * </p>
- */
- protected BufferedReader mReader;
-
- /**
- * <p>
- * Set for storing unkonwn TYPE attributes, which is not acceptable in vCard
- * specification, but happens to be seen in real world vCard.
- * </p>
- */
- protected final Set<String> mUnknownTypeSet = new HashSet<String>();
-
- /**
- * <p>
- * Set for storing unkonwn VALUE attributes, which is not acceptable in
- * vCard specification, but happens to be seen in real world vCard.
- * </p>
- */
- protected final Set<String> mUnknownValueSet = new HashSet<String>();
-
-
- // In some cases, vCard is nested. Currently, we only consider the most
- // interior vCard data.
- // See v21_foma_1.vcf in test directory for more information.
- // TODO: Don't ignore by using count, but read all of information outside vCard.
- private int mNestCount;
-
- // Used only for parsing END:VCARD.
- private String mPreviousLine;
-
- // For measuring performance.
- private long mTimeTotal;
- private long mTimeReadStartRecord;
- private long mTimeReadEndRecord;
- private long mTimeStartProperty;
- private long mTimeEndProperty;
- private long mTimeParseItems;
- private long mTimeParseLineAndHandleGroup;
- private long mTimeParsePropertyValues;
- private long mTimeParseAdrOrgN;
- private long mTimeHandleMiscPropertyValue;
- private long mTimeHandleQuotedPrintable;
- private long mTimeHandleBase64;
-
- public VCardParserImpl_V21() {
- this(VCardConfig.VCARD_TYPE_DEFAULT, null);
- }
-
- public VCardParserImpl_V21(int vcardType) {
- this(vcardType, null);
- }
-
- public VCardParserImpl_V21(int vcardType, String importCharset) {
- if ((vcardType & VCardConfig.FLAG_TORELATE_NEST) != 0) {
- mNestCount = 1;
- }
-
- mImportCharset = (!TextUtils.isEmpty(importCharset) ? importCharset :
- VCardConfig.DEFAULT_INTERMEDIATE_CHARSET);
- }
-
- /**
- * <p>
- * Parses the file at the given position.
- * </p>
- */
- // <pre class="prettyprint">vcard_file = [wsls] vcard [wsls]</pre>
- protected void parseVCardFile() throws IOException, VCardException {
- boolean readingFirstFile = true;
- while (true) {
- if (mCanceled) {
- break;
- }
- if (!parseOneVCard(readingFirstFile)) {
- break;
- }
- readingFirstFile = false;
- }
-
- if (mNestCount > 0) {
- boolean useCache = true;
- for (int i = 0; i < mNestCount; i++) {
- readEndVCard(useCache, true);
- useCache = false;
- }
- }
- }
-
- /**
- * @return true when a given property name is a valid property name.
- */
- protected boolean isValidPropertyName(final 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;
- }
-
- /**
- * @return String. It may be null, or its length may be 0
- * @throws IOException
- */
- protected String getLine() throws IOException {
- return mReader.readLine();
- }
-
- /**
- * @return String with it's length > 0
- * @throws IOException
- * @throws VCardException when the stream reached end of line
- */
- protected String getNonEmptyLine() throws IOException, VCardException {
- String line;
- while (true) {
- line = getLine();
- if (line == null) {
- throw new VCardException("Reached end of buffer.");
- } else if (line.trim().length() > 0) {
- return line;
- }
- }
- }
-
- /*
- * vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF
- * items *CRLF
- * "END" [ws] ":" [ws] "VCARD"
- */
- private boolean parseOneVCard(boolean firstRead) throws IOException, VCardException {
- boolean allowGarbage = false;
- if (firstRead) {
- if (mNestCount > 0) {
- for (int i = 0; i < mNestCount; i++) {
- if (!readBeginVCard(allowGarbage)) {
- return false;
- }
- allowGarbage = true;
- }
- }
- }
-
- if (!readBeginVCard(allowGarbage)) {
- return false;
- }
- long start;
- if (mInterpreter != null) {
- start = System.currentTimeMillis();
- mInterpreter.startEntry();
- mTimeReadStartRecord += System.currentTimeMillis() - start;
- }
- start = System.currentTimeMillis();
- parseItems();
- mTimeParseItems += System.currentTimeMillis() - start;
- readEndVCard(true, false);
- if (mInterpreter != null) {
- start = System.currentTimeMillis();
- mInterpreter.endEntry();
- mTimeReadEndRecord += System.currentTimeMillis() - start;
- }
- return true;
- }
-
- /**
- * @return True when successful. False when reaching the end of line
- * @throws IOException
- * @throws VCardException
- */
- protected boolean readBeginVCard(boolean allowGarbage) throws IOException, VCardException {
- String line;
- do {
- while (true) {
- line = getLine();
- if (line == null) {
- return false;
- } else if (line.trim().length() > 0) {
- break;
- }
- }
- String[] strArray = line.split(":", 2);
- int length = strArray.length;
-
- // Though vCard 2.1/3.0 specification does not allow lower cases,
- // vCard file emitted by some external vCard expoter have such
- // invalid Strings.
- // So we allow it.
- // e.g. BEGIN:vCard
- if (length == 2 && strArray[0].trim().equalsIgnoreCase("BEGIN")
- && strArray[1].trim().equalsIgnoreCase("VCARD")) {
- return true;
- } else if (!allowGarbage) {
- if (mNestCount > 0) {
- mPreviousLine = line;
- return false;
- } else {
- throw new VCardException("Expected String \"BEGIN:VCARD\" did not come "
- + "(Instead, \"" + line + "\" came)");
- }
- }
- } while (allowGarbage);
-
- throw new VCardException("Reached where must not be reached.");
- }
-
- /**
- * <p>
- * The arguments useCache and allowGarbase are usually true and false
- * accordingly when this function is called outside this function itself.
- * </p>
- *
- * @param useCache When true, line is obtained from mPreviousline.
- * Otherwise, getLine() is used.
- * @param allowGarbage When true, ignore non "END:VCARD" line.
- * @throws IOException
- * @throws VCardException
- */
- protected void readEndVCard(boolean useCache, boolean allowGarbage) throws IOException,
- VCardException {
- String line;
- do {
- if (useCache) {
- // Though vCard specification does not allow lower cases,
- // some data may have them, so we allow it.
- line = mPreviousLine;
- } else {
- while (true) {
- line = getLine();
- if (line == null) {
- throw new VCardException("Expected END:VCARD was not found.");
- } else if (line.trim().length() > 0) {
- break;
- }
- }
- }
-
- String[] strArray = line.split(":", 2);
- if (strArray.length == 2 && strArray[0].trim().equalsIgnoreCase("END")
- && strArray[1].trim().equalsIgnoreCase("VCARD")) {
- return;
- } else if (!allowGarbage) {
- throw new VCardException("END:VCARD != \"" + mPreviousLine + "\"");
- }
- useCache = false;
- } while (allowGarbage);
- }
-
- /*
- * items = *CRLF item / item
- */
- protected void parseItems() throws IOException, VCardException {
- boolean ended = false;
-
- if (mInterpreter != null) {
- long start = System.currentTimeMillis();
- mInterpreter.startProperty();
- mTimeStartProperty += System.currentTimeMillis() - start;
- }
- ended = parseItem();
- if (mInterpreter != null && !ended) {
- long start = System.currentTimeMillis();
- mInterpreter.endProperty();
- mTimeEndProperty += System.currentTimeMillis() - start;
- }
-
- while (!ended) {
- // follow VCARD ,it wont reach endProperty
- if (mInterpreter != null) {
- long start = System.currentTimeMillis();
- mInterpreter.startProperty();
- mTimeStartProperty += System.currentTimeMillis() - start;
- }
- try {
- ended = parseItem();
- } catch (VCardInvalidCommentLineException e) {
- Log.e(LOG_TAG, "Invalid line which looks like some comment was found. Ignored.");
- ended = false;
- }
- if (mInterpreter != null && !ended) {
- long start = System.currentTimeMillis();
- mInterpreter.endProperty();
- mTimeEndProperty += System.currentTimeMillis() - start;
- }
- }
- }
-
- /*
- * item = [groups "."] name [params] ":" value CRLF / [groups "."] "ADR"
- * [params] ":" addressparts CRLF / [groups "."] "ORG" [params] ":" orgparts
- * CRLF / [groups "."] "N" [params] ":" nameparts CRLF / [groups "."]
- * "AGENT" [params] ":" vcard CRLF
- */
- protected boolean parseItem() throws IOException, VCardException {
- mCurrentEncoding = sDefaultEncoding;
-
- final String line = getNonEmptyLine();
- long start = System.currentTimeMillis();
-
- String[] propertyNameAndValue = separateLineAndHandleGroup(line);
- if (propertyNameAndValue == null) {
- return true;
- }
- if (propertyNameAndValue.length != 2) {
- throw new VCardInvalidLineException("Invalid line \"" + line + "\"");
- }
- String propertyName = propertyNameAndValue[0].toUpperCase();
- String propertyValue = propertyNameAndValue[1];
-
- mTimeParseLineAndHandleGroup += System.currentTimeMillis() - start;
-
- if (propertyName.equals("ADR") || propertyName.equals("ORG") || propertyName.equals("N")) {
- start = System.currentTimeMillis();
- handleMultiplePropertyValue(propertyName, propertyValue);
- mTimeParseAdrOrgN += System.currentTimeMillis() - start;
- return false;
- } else if (propertyName.equals("AGENT")) {
- handleAgent(propertyValue);
- return false;
- } else if (isValidPropertyName(propertyName)) {
- if (propertyName.equals("BEGIN")) {
- if (propertyValue.equals("VCARD")) {
- throw new VCardNestedException("This vCard has nested vCard data in it.");
- } else {
- throw new VCardException("Unknown BEGIN type: " + propertyValue);
- }
- } else if (propertyName.equals("VERSION") && !propertyValue.equals(getVersionString())) {
- throw new VCardVersionException("Incompatible version: " + propertyValue + " != "
- + getVersionString());
- }
- start = System.currentTimeMillis();
- handlePropertyValue(propertyName, propertyValue);
- mTimeParsePropertyValues += System.currentTimeMillis() - start;
- return false;
- }
-
- throw new VCardException("Unknown property name: \"" + propertyName + "\"");
- }
-
- // For performance reason, the states for group and property name are merged into one.
- static private final int STATE_GROUP_OR_PROPERTY_NAME = 0;
- static private final int STATE_PARAMS = 1;
- // vCard 3.0 specification allows double-quoted parameters, while vCard 2.1 does not.
- static private final int STATE_PARAMS_IN_DQUOTE = 2;
-
- protected String[] separateLineAndHandleGroup(String line) throws VCardException {
- final String[] propertyNameAndValue = new String[2];
- 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);
- if (propertyName.equalsIgnoreCase("END")) {
- mPreviousLine = line;
- return null;
- }
- if (mInterpreter != null) {
- mInterpreter.propertyName(propertyName);
- }
- propertyNameAndValue[0] = propertyName;
- if (i < length - 1) {
- propertyNameAndValue[1] = line.substring(i + 1);
- } else {
- propertyNameAndValue[1] = "";
- }
- return propertyNameAndValue;
- } 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 if (mInterpreter != null) {
- mInterpreter.propertyGroup(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);
- if (propertyName.equalsIgnoreCase("END")) {
- mPreviousLine = line;
- return null;
- }
- if (mInterpreter != null) {
- mInterpreter.propertyName(propertyName);
- }
- propertyNameAndValue[0] = propertyName;
- nameIndex = i + 1;
- state = STATE_PARAMS; // Start parameter parsing.
- }
- 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(line.substring(nameIndex, i));
- nameIndex = i + 1;
- } else if (ch == ':') { // End of param and beginenning of values.
- handleParams(line.substring(nameIndex, i));
- if (i < length - 1) {
- propertyNameAndValue[1] = line.substring(i + 1);
- } else {
- propertyNameAndValue[1] = "";
- }
- return propertyNameAndValue;
- }
- 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 + "\"");
- }
-
- /*
- * params = ";" [ws] paramlist paramlist = paramlist [ws] ";" [ws] param /
- * param param = "TYPE" [ws] "=" [ws] ptypeval / "VALUE" [ws] "=" [ws]
- * pvalueval / "ENCODING" [ws] "=" [ws] pencodingval / "CHARSET" [ws] "="
- * [ws] charsetval / "LANGUAGE" [ws] "=" [ws] langval / "X-" word [ws] "="
- * [ws] word / knowntype
- */
- protected void handleParams(String params) throws VCardException {
- 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(paramValue);
- } else if (paramName.equals("VALUE")) {
- handleValue(paramValue);
- } else if (paramName.equals("ENCODING")) {
- handleEncoding(paramValue);
- } else if (paramName.equals("CHARSET")) {
- handleCharset(paramValue);
- } else if (paramName.equals("LANGUAGE")) {
- handleLanguage(paramValue);
- } else if (paramName.startsWith("X-")) {
- handleAnyParam(paramName, paramValue);
- } else {
- throw new VCardException("Unknown type \"" + paramName + "\"");
- }
- } else {
- handleParamWithoutName(strArray[0]);
- }
- }
-
- /**
- * vCard 3.0 parser implementation may throw VCardException.
- */
- @SuppressWarnings("unused")
- protected void handleParamWithoutName(final String paramValue) throws VCardException {
- handleType(paramValue);
- }
-
- /*
- * ptypeval = knowntype / "X-" word
- */
- protected void handleType(final 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));
- }
- if (mInterpreter != null) {
- mInterpreter.propertyParamType("TYPE");
- mInterpreter.propertyParamValue(ptypeval);
- }
- }
-
- /*
- * pvalueval = "INLINE" / "URL" / "CONTENT-ID" / "CID" / "X-" word
- */
- protected void handleValue(final 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));
- }
- if (mInterpreter != null) {
- mInterpreter.propertyParamType("VALUE");
- mInterpreter.propertyParamValue(pvalueval);
- }
- }
-
- /*
- * pencodingval = "7BIT" / "8BIT" / "QUOTED-PRINTABLE" / "BASE64" / "X-" word
- */
- protected void handleEncoding(String pencodingval) throws VCardException {
- if (getAvailableEncodingSet().contains(pencodingval) ||
- pencodingval.startsWith("X-")) {
- if (mInterpreter != null) {
- mInterpreter.propertyParamType("ENCODING");
- mInterpreter.propertyParamValue(pencodingval);
- }
- mCurrentEncoding = pencodingval;
- } else {
- throw new VCardException("Unknown encoding \"" + pencodingval + "\"");
- }
- }
-
- /**
- * <p>
- * 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.
- * </p>
- */
- protected void handleCharset(String charsetval) {
- if (mInterpreter != null) {
- mInterpreter.propertyParamType("CHARSET");
- mInterpreter.propertyParamValue(charsetval);
- }
- }
-
- /**
- * See also Section 7.1 of RFC 1521
- */
- protected void handleLanguage(String langval) throws VCardException {
- 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 + "\"");
- }
- }
- if (mInterpreter != null) {
- mInterpreter.propertyParamType("LANGUAGE");
- mInterpreter.propertyParamValue(langval);
- }
- }
-
- private boolean isAsciiLetter(char ch) {
- if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
- return true;
- }
- return false;
- }
-
- /**
- * Mainly for "X-" type. This accepts any kind of type without check.
- */
- protected void handleAnyParam(String paramName, String paramValue) {
- if (mInterpreter != null) {
- mInterpreter.propertyParamType(paramName);
- mInterpreter.propertyParamValue(paramValue);
- }
- }
-
- protected void handlePropertyValue(String propertyName, String propertyValue)
- throws IOException, VCardException {
- final String upperEncoding = mCurrentEncoding.toUpperCase();
- if (upperEncoding.equals(VCardConstants.PARAM_ENCODING_QP)) {
- final long start = System.currentTimeMillis();
- final String result = getQuotedPrintable(propertyValue);
- if (mInterpreter != null) {
- ArrayList<String> v = new ArrayList<String>();
- v.add(result);
- mInterpreter.propertyValues(v);
- }
- mTimeHandleQuotedPrintable += System.currentTimeMillis() - start;
- } else if (upperEncoding.equals(VCardConstants.PARAM_ENCODING_BASE64)
- || upperEncoding.equals(VCardConstants.PARAM_ENCODING_B)) {
- final long start = System.currentTimeMillis();
- // 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 result = getBase64(propertyValue);
- if (mInterpreter != null) {
- ArrayList<String> arrayList = new ArrayList<String>();
- arrayList.add(result);
- mInterpreter.propertyValues(arrayList);
- }
- } catch (OutOfMemoryError error) {
- Log.e(LOG_TAG, "OutOfMemoryError happened during parsing BASE64 data!");
- if (mInterpreter != null) {
- mInterpreter.propertyValues(null);
- }
- }
- mTimeHandleBase64 += System.currentTimeMillis() - start;
- } else {
- if (!(upperEncoding.equals("7BIT") || upperEncoding.equals("8BIT") ||
- upperEncoding.startsWith("X-"))) {
- Log.w(LOG_TAG,
- String.format("The encoding \"%s\" is unsupported by vCard %s",
- mCurrentEncoding, getVersionString()));
- }
-
- final long start = System.currentTimeMillis();
- if (mInterpreter != null) {
- ArrayList<String> v = new ArrayList<String>();
- v.add(maybeUnescapeText(propertyValue));
- mInterpreter.propertyValues(v);
- }
- mTimeHandleMiscPropertyValue += System.currentTimeMillis() - start;
- }
- }
-
- /**
- * <p>
- * Parses and returns Quoted-Printable.
- * </p>
- *
- * @param firstString The string following a parameter name and attributes.
- * Example: "string" in
- * "ADR:ENCODING=QUOTED-PRINTABLE:string\n\r".
- * @return whole Quoted-Printable string, including a given argument and
- * following lines. Excludes the last empty line following to Quoted
- * Printable lines.
- * @throws IOException
- * @throws VCardException
- */
- private String getQuotedPrintable(String firstString) throws IOException, VCardException {
- // 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 String getBase64(String firstString) throws IOException, VCardException {
- StringBuilder builder = new StringBuilder();
- builder.append(firstString);
-
- while (true) {
- String line = getLine();
- if (line == null) {
- throw new VCardException("File ended during parsing BASE64 binary");
- }
- if (line.length() == 0) {
- break;
- }
- builder.append(line);
- }
-
- return builder.toString();
- }
-
- /**
- * <p>
- * Mainly for "ADR", "ORG", and "N"
- * </p>
- */
- /*
- * addressparts = 0*6(strnosemi ";") strnosemi ; PO Box, Extended Addr,
- * Street, Locality, Region, Postal Code, Country Name orgparts =
- * *(strnosemi ";") strnosemi ; First is Organization Name, remainder are
- * Organization Units. nameparts = 0*4(strnosemi ";") strnosemi ; Family,
- * Given, Middle, Prefix, Suffix. ; Example:Public;John;Q.;Reverend Dr.;III,
- * Esq. strnosemi = *(*nonsemi ("\;" / "\" CRLF)) *nonsemi ; To include a
- * semicolon in this string, it must be escaped ; with a "\" character. We
- * do not care the number of "strnosemi" here. We are not sure whether we
- * should add "\" CRLF to each value. We exclude them for now.
- */
- protected void handleMultiplePropertyValue(String propertyName, String propertyValue)
- throws IOException, VCardException {
- // vCard 2.1 does not allow QUOTED-PRINTABLE here, but some
- // softwares/devices
- // emit such data.
- if (mCurrentEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) {
- propertyValue = getQuotedPrintable(propertyValue);
- }
-
- if (mInterpreter != null) {
- mInterpreter.propertyValues(VCardUtils.constructListFromValue(propertyValue,
- (getVersion() == VCardConfig.FLAG_V30)));
- }
- }
-
- /*
- * vCard 2.1 specifies AGENT allows one vcard entry. Currently we emit an
- * error toward the AGENT property.
- * // TODO: Support AGENT property.
- * item =
- * ... / [groups "."] "AGENT" [params] ":" vcard CRLF vcard = "BEGIN" [ws]
- * ":" [ws] "VCARD" [ws] 1*CRLF items *CRLF "END" [ws] ":" [ws] "VCARD"
- */
- protected void handleAgent(final String propertyValue) throws VCardException {
- if (!propertyValue.toUpperCase().contains("BEGIN:VCARD")) {
- // Apparently invalid line seen in Windows Mobile 6.5. Ignore them.
- return;
- } else {
- throw new VCardAgentNotSupportedException("AGENT Property is not supported now.");
- }
- }
-
- /**
- * For vCard 3.0.
- */
- protected String maybeUnescapeText(final String text) {
- return text;
- }
-
- /**
- * 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(final char ch) {
- return unescapeCharacter(ch);
- }
-
- /* package */ 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.
- if (ch == '\\' || ch == ';' || ch == ':' || ch == ',') {
- return String.valueOf(ch);
- } else {
- return null;
- }
- }
-
- private void showPerformanceInfo() {
- Log.d(LOG_TAG, "Total parsing time: " + mTimeTotal + " ms");
- if (mReader instanceof CustomBufferedReader) {
- Log.d(LOG_TAG, "Total readLine time: "
- + ((CustomBufferedReader) mReader).getTotalmillisecond() + " ms");
- }
- Log.d(LOG_TAG, "Time for handling the beggining of the record: " + mTimeReadStartRecord
- + " ms");
- Log.d(LOG_TAG, "Time for handling the end of the record: " + mTimeReadEndRecord + " ms");
- Log.d(LOG_TAG, "Time for parsing line, and handling group: " + mTimeParseLineAndHandleGroup
- + " ms");
- Log.d(LOG_TAG, "Time for parsing ADR, ORG, and N fields:" + mTimeParseAdrOrgN + " ms");
- Log.d(LOG_TAG, "Time for parsing property values: " + mTimeParsePropertyValues + " ms");
- Log.d(LOG_TAG, "Time for handling normal property values: " + mTimeHandleMiscPropertyValue
- + " ms");
- Log.d(LOG_TAG, "Time for handling Quoted-Printable: " + mTimeHandleQuotedPrintable + " ms");
- Log.d(LOG_TAG, "Time for handling Base64: " + mTimeHandleBase64 + " ms");
- }
-
- /**
- * @return {@link VCardConfig#FLAG_V21}
- */
- protected int getVersion() {
- return VCardConfig.FLAG_V21;
- }
-
- /**
- * @return {@link VCardConfig#FLAG_V30}
- */
- protected String getVersionString() {
- return VCardConstants.VERSION_V21;
- }
-
- protected Set<String> getKnownPropertyNameSet() {
- return VCardParser_V21.sKnownPropertyNameSet;
- }
-
- protected Set<String> getKnownTypeSet() {
- return VCardParser_V21.sKnownTypeSet;
- }
-
- protected Set<String> getKnownValueSet() {
- return VCardParser_V21.sKnownValueSet;
- }
-
- protected Set<String> getAvailableEncodingSet() {
- return VCardParser_V21.sAvailableEncoding;
- }
-
- protected String getDefaultEncoding() {
- return sDefaultEncoding;
- }
-
-
- public void parse(InputStream is, VCardInterpreter interpreter)
- throws IOException, VCardException {
- if (is == null) {
- throw new NullPointerException("InputStream must not be null.");
- }
-
- final InputStreamReader tmpReader = new InputStreamReader(is, mImportCharset);
- if (VCardConfig.showPerformanceLog()) {
- mReader = new CustomBufferedReader(tmpReader);
- } else {
- mReader = new BufferedReader(tmpReader);
- }
-
- mInterpreter = interpreter;
-
- final long start = System.currentTimeMillis();
- if (mInterpreter != null) {
- mInterpreter.start();
- }
- parseVCardFile();
- if (mInterpreter != null) {
- mInterpreter.end();
- }
- mTimeTotal += System.currentTimeMillis() - start;
-
- if (VCardConfig.showPerformanceLog()) {
- showPerformanceInfo();
- }
- }
-
- public final void cancel() {
- mCanceled = true;
- }
-}