VCardParserImpl_V21.java revision 677ef21613a9d35053ec098444832ce4125a847e
14199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa/* 24199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Copyright (C) 2010 The Android Open Source Project 34199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * 44199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Licensed under the Apache License, Version 2.0 (the "License"); 54199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * you may not use this file except in compliance with the License. 64199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * You may obtain a copy of the License at 74199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * 84199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * http://www.apache.org/licenses/LICENSE-2.0 94199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * 104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Unless required by applicable law or agreed to in writing, software 114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * distributed under the License is distributed on an "AS IS" BASIS, 124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * See the License for the specific language governing permissions and 144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * limitations under the License. 154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawapackage com.android.vcard; 174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 18f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawaimport android.text.TextUtils; 194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.util.Log; 204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport com.android.vcard.exception.VCardAgentNotSupportedException; 224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport com.android.vcard.exception.VCardException; 234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport com.android.vcard.exception.VCardInvalidCommentLineException; 244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport com.android.vcard.exception.VCardInvalidLineException; 254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport com.android.vcard.exception.VCardNestedException; 264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport com.android.vcard.exception.VCardVersionException; 274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.io.BufferedReader; 294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.io.IOException; 304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.io.InputStream; 314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.io.InputStreamReader; 324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.io.Reader; 334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.ArrayList; 344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.HashSet; 354560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawaimport java.util.List; 364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.Set; 374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa/** 394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 40677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa * Basic implementation achieving vCard parsing. Based on vCard 2.1. 414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @hide 434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa/* package */ class VCardParserImpl_V21 { 454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final String LOG_TAG = "VCardParserImpl_V21"; 464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 474560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa private static final class EmptyInterpreter implements VCardInterpreter { 484560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa @Override 494560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa public void end() { 504560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } 514560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa @Override 524560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa public void endEntry() { 534560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } 544560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa @Override 554560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa public void endProperty() { 564560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } 574560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa @Override 584560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa public void propertyGroup(String group) { 594560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } 604560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa @Override 614560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa public void propertyName(String name) { 624560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } 634560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa @Override 644560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa public void propertyParamType(String type) { 654560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } 664560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa @Override 674560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa public void propertyParamValue(String value) { 684560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } 694560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa @Override 704560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa public void propertyValues(List<String> values) { 714560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } 724560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa @Override 734560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa public void start() { 744560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } 754560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa @Override 764560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa public void startEntry() { 774560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } 784560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa @Override 794560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa public void startProperty() { 804560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } 814560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } 824560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa 83147f1ae5371954ae845cb2330b221df6ca1d8831Daisuke Miyakawa protected static final class CustomBufferedReader extends BufferedReader { 844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private long mTime; 854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 86f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa /** 87f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa * Needed since "next line" may be null due to end of line. 88f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa */ 89f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa private boolean mNextLineIsValid; 90f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa private String mNextLine; 91f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa 924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public CustomBufferedReader(Reader in) { 934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa super(in); 944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public String readLine() throws IOException { 98f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa if (mNextLineIsValid) { 99f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa final String ret = mNextLine; 100f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa mNextLine = null; 101f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa mNextLineIsValid = false; 102f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa return ret; 103f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa } 104f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa 105677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa final long start = System.currentTimeMillis(); 106f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa final String line = super.readLine(); 107677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa final long end = System.currentTimeMillis(); 1084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mTime += end - start; 109f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa return line; 110f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa } 111f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa 112f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa /** 113f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa * Read one line, but make this object store it in its queue. 114f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa */ 115f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa public String peekLine() throws IOException { 116f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa if (!mNextLineIsValid) { 117677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa final long start = System.currentTimeMillis(); 118f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa final String line = super.readLine(); 119677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa final long end = System.currentTimeMillis(); 120f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa mTime += end - start; 121f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa 122f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa mNextLine = line; 123f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa mNextLineIsValid = true; 124f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa } 125f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa 126f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa return mNextLine; 1274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public long getTotalmillisecond() { 1304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return mTime; 1314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final String DEFAULT_ENCODING = "8BIT"; 1354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected boolean mCanceled; 1374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected VCardInterpreter mInterpreter; 1384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected final String mIntermediateCharset; 1404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 1424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 1434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * The encoding type for deconding byte streams. This member variable is 1444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * reset to a default encoding every time when a new item comes. 1454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 1464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 1474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * "Encoding" in vCard is different from "Charset". It is mainly used for 1484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * addresses, notes, images. "7BIT", "8BIT", "BASE64", and 1494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * "QUOTED-PRINTABLE" are known examples. 1504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 1514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 1524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected String mCurrentEncoding; 1534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 1554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 1564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * The reader object to be used internally. 1574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 1584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 1594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Developers should not directly read a line from this object. Use 1604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * getLine() unless there some reason. 1614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 1624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 163f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa protected CustomBufferedReader mReader; 1644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 1664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 1674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Set for storing unkonwn TYPE attributes, which is not acceptable in vCard 1684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * specification, but happens to be seen in real world vCard. 1694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 170677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa * <p> 171677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa * We just accept those invalid types after emitting a warning for each of it. 172677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa * </p> 1734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 1744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected final Set<String> mUnknownTypeSet = new HashSet<String>(); 1754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 1774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 1784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Set for storing unkonwn VALUE attributes, which is not acceptable in 1794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * vCard specification, but happens to be seen in real world vCard. 1804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 181677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa * <p> 182677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa * We just accept those invalid types after emitting a warning for each of it. 183677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa * </p> 1844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 1854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected final Set<String> mUnknownValueSet = new HashSet<String>(); 1864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // In some cases, vCard is nested. Currently, we only consider the most 1894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // interior vCard data. 1904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // See v21_foma_1.vcf in test directory for more information. 1914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // TODO: Don't ignore by using count, but read all of information outside vCard. 1924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private int mNestCount; 1934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Used only for parsing END:VCARD. 1954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private String mPreviousLine; 1964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // For measuring performance. 1984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private long mTimeTotal; 1994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private long mTimeReadStartRecord; 2004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private long mTimeReadEndRecord; 2014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private long mTimeStartProperty; 2024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private long mTimeEndProperty; 2034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private long mTimeParseItems; 2044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private long mTimeParseLineAndHandleGroup; 2054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private long mTimeParsePropertyValues; 2064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private long mTimeParseAdrOrgN; 2074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private long mTimeHandleMiscPropertyValue; 2084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private long mTimeHandleQuotedPrintable; 2094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private long mTimeHandleBase64; 2104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public VCardParserImpl_V21() { 2124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa this(VCardConfig.VCARD_TYPE_DEFAULT); 2134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public VCardParserImpl_V21(int vcardType) { 2164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if ((vcardType & VCardConfig.FLAG_TORELATE_NEST) != 0) { 2174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mNestCount = 1; 2184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mIntermediateCharset = VCardConfig.DEFAULT_INTERMEDIATE_CHARSET; 2214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 2244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 2254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Parses the file at the given position. 2264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 2274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 2284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // <pre class="prettyprint">vcard_file = [wsls] vcard [wsls]</pre> 2294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected void parseVCardFile() throws IOException, VCardException { 2304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa boolean readingFirstFile = true; 2314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa while (true) { 2324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (mCanceled) { 233b23043e3a199e951817b6d86c301b9521d4c26feDaisuke Miyakawa Log.i(LOG_TAG, "Cancel request has come. exitting parse operation."); 2344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 2354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!parseOneVCard(readingFirstFile)) { 2374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 2384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa readingFirstFile = false; 2404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (mNestCount > 0) { 2434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa boolean useCache = true; 2444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (int i = 0; i < mNestCount; i++) { 2454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa readEndVCard(useCache, true); 2464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa useCache = false; 2474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 2524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @return true when a given property name is a valid property name. 2534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 2544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected boolean isValidPropertyName(final String propertyName) { 2554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!(getKnownPropertyNameSet().contains(propertyName.toUpperCase()) || 2564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa propertyName.startsWith("X-")) 2574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa && !mUnknownTypeSet.contains(propertyName)) { 2584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mUnknownTypeSet.add(propertyName); 2594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.w(LOG_TAG, "Property name unsupported by vCard 2.1: " + propertyName); 2604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return true; 2624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 2654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @return String. It may be null, or its length may be 0 2664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @throws IOException 2674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 2684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected String getLine() throws IOException { 2694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return mReader.readLine(); 2704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 272f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa protected String peekLine() throws IOException { 273f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa return mReader.peekLine(); 274f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa } 275f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa 2764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 2774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @return String with it's length > 0 2784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @throws IOException 2794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @throws VCardException when the stream reached end of line 2804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 2814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected String getNonEmptyLine() throws IOException, VCardException { 2824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String line; 2834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa while (true) { 2844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa line = getLine(); 2854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (line == null) { 2864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardException("Reached end of buffer."); 2874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (line.trim().length() > 0) { 2884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return line; 2894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /* 2944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF 2954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * items *CRLF 2964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * "END" [ws] ":" [ws] "VCARD" 2974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 2984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private boolean parseOneVCard(boolean firstRead) throws IOException, VCardException { 2994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa boolean allowGarbage = false; 3004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (firstRead) { 3014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (mNestCount > 0) { 3024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (int i = 0; i < mNestCount; i++) { 3034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!readBeginVCard(allowGarbage)) { 3044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return false; 3054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa allowGarbage = true; 3074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 3114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!readBeginVCard(allowGarbage)) { 3124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return false; 3134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3144560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa final long beforeStartEntry = System.currentTimeMillis(); 3154560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.startEntry(); 3164560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mTimeReadStartRecord += System.currentTimeMillis() - beforeStartEntry; 3174560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa 3184560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa final long beforeParseItems = System.currentTimeMillis(); 3194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parseItems(); 3204560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mTimeParseItems += System.currentTimeMillis() - beforeParseItems; 3214560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa 3224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa readEndVCard(true, false); 3234560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa 3244560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa final long beforeEndEntry = System.currentTimeMillis(); 3254560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.endEntry(); 3264560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mTimeReadEndRecord += System.currentTimeMillis() - beforeEndEntry; 3274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return true; 3284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 3304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 3314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @return True when successful. False when reaching the end of line 3324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @throws IOException 3334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @throws VCardException 3344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 3354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected boolean readBeginVCard(boolean allowGarbage) throws IOException, VCardException { 3364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String line; 3374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa do { 3384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa while (true) { 3394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa line = getLine(); 3404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (line == null) { 3414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return false; 3424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (line.trim().length() > 0) { 3434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 3444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 346f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa final String[] strArray = line.split(":", 2); 347f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa final int length = strArray.length; 3484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 349f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // Although vCard 2.1/3.0 specification does not allow lower cases, 350f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // we found vCard file emitted by some external vCard expoter have such 3514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // invalid Strings. 3524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // So we allow it. 353f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // e.g. 354f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // BEGIN:vCard 3554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (length == 2 && strArray[0].trim().equalsIgnoreCase("BEGIN") 3564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa && strArray[1].trim().equalsIgnoreCase("VCARD")) { 3574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return true; 3584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (!allowGarbage) { 3594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (mNestCount > 0) { 3604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mPreviousLine = line; 3614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return false; 3624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 3634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardException("Expected String \"BEGIN:VCARD\" did not come " 3644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa + "(Instead, \"" + line + "\" came)"); 3654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } while (allowGarbage); 3684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 3694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardException("Reached where must not be reached."); 3704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 3724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 3734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 3744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * The arguments useCache and allowGarbase are usually true and false 3754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * accordingly when this function is called outside this function itself. 3764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 377677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa * 3784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @param useCache When true, line is obtained from mPreviousline. 3794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Otherwise, getLine() is used. 3804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @param allowGarbage When true, ignore non "END:VCARD" line. 3814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @throws IOException 3824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @throws VCardException 3834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 3844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected void readEndVCard(boolean useCache, boolean allowGarbage) throws IOException, 3854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa VCardException { 3864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String line; 3874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa do { 3884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (useCache) { 3894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Though vCard specification does not allow lower cases, 3904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // some data may have them, so we allow it. 3914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa line = mPreviousLine; 3924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 3934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa while (true) { 3944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa line = getLine(); 3954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (line == null) { 3964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardException("Expected END:VCARD was not found."); 3974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (line.trim().length() > 0) { 3984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 3994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 4034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String[] strArray = line.split(":", 2); 4044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (strArray.length == 2 && strArray[0].trim().equalsIgnoreCase("END") 4054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa && strArray[1].trim().equalsIgnoreCase("VCARD")) { 4064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return; 4074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (!allowGarbage) { 4084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardException("END:VCARD != \"" + mPreviousLine + "\""); 4094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa useCache = false; 4114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } while (allowGarbage); 4124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 4144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /* 4154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * items = *CRLF item / item 4164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 4174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected void parseItems() throws IOException, VCardException { 4184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa boolean ended = false; 4194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 4204560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa final long beforeBeginProperty = System.currentTimeMillis(); 4214560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.startProperty(); 4224560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mTimeStartProperty += System.currentTimeMillis() - beforeBeginProperty; 4234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa ended = parseItem(); 4244560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa if (!ended) { 4254560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa final long beforeEndProperty = System.currentTimeMillis(); 4264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mInterpreter.endProperty(); 4274560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mTimeEndProperty += System.currentTimeMillis() - beforeEndProperty; 4284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 4304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa while (!ended) { 4314560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa final long beforeStartProperty = System.currentTimeMillis(); 4324560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.startProperty(); 4334560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mTimeStartProperty += System.currentTimeMillis() - beforeStartProperty; 4344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa try { 4354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa ended = parseItem(); 4364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } catch (VCardInvalidCommentLineException e) { 4374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.e(LOG_TAG, "Invalid line which looks like some comment was found. Ignored."); 4384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa ended = false; 4394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4404560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa 4414560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa if (!ended) { 4424560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa final long beforeEndProperty = System.currentTimeMillis(); 4434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mInterpreter.endProperty(); 4444560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mTimeEndProperty += System.currentTimeMillis() - beforeEndProperty; 4454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 4494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /* 4504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * item = [groups "."] name [params] ":" value CRLF / [groups "."] "ADR" 4514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * [params] ":" addressparts CRLF / [groups "."] "ORG" [params] ":" orgparts 4524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * CRLF / [groups "."] "N" [params] ":" nameparts CRLF / [groups "."] 4534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * "AGENT" [params] ":" vcard CRLF 4544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 4554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected boolean parseItem() throws IOException, VCardException { 4564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mCurrentEncoding = DEFAULT_ENCODING; 4574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 4584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String line = getNonEmptyLine(); 4594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa long start = System.currentTimeMillis(); 4604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 4614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String[] propertyNameAndValue = separateLineAndHandleGroup(line); 4624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (propertyNameAndValue == null) { 4634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return true; 4644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (propertyNameAndValue.length != 2) { 4664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardInvalidLineException("Invalid line \"" + line + "\""); 4674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String propertyName = propertyNameAndValue[0].toUpperCase(); 4694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String propertyValue = propertyNameAndValue[1]; 4704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 4714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mTimeParseLineAndHandleGroup += System.currentTimeMillis() - start; 4724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 4734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (propertyName.equals("ADR") || propertyName.equals("ORG") || propertyName.equals("N")) { 4744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa start = System.currentTimeMillis(); 4754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa handleMultiplePropertyValue(propertyName, propertyValue); 4764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mTimeParseAdrOrgN += System.currentTimeMillis() - start; 4774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return false; 4784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (propertyName.equals("AGENT")) { 4794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa handleAgent(propertyValue); 4804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return false; 4814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (isValidPropertyName(propertyName)) { 4824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (propertyName.equals("BEGIN")) { 4834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (propertyValue.equals("VCARD")) { 4844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardNestedException("This vCard has nested vCard data in it."); 4854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 4864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardException("Unknown BEGIN type: " + propertyValue); 4874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (propertyName.equals("VERSION") && !propertyValue.equals(getVersionString())) { 4894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardVersionException("Incompatible version: " + propertyValue + " != " 4904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa + getVersionString()); 4914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa start = System.currentTimeMillis(); 4934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa handlePropertyValue(propertyName, propertyValue); 4944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mTimeParsePropertyValues += System.currentTimeMillis() - start; 4954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return false; 4964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 4974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 4984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardException("Unknown property name: \"" + propertyName + "\""); 4994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 5014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // For performance reason, the states for group and property name are merged into one. 5024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa static private final int STATE_GROUP_OR_PROPERTY_NAME = 0; 5034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa static private final int STATE_PARAMS = 1; 5044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // vCard 3.0 specification allows double-quoted parameters, while vCard 2.1 does not. 5054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa static private final int STATE_PARAMS_IN_DQUOTE = 2; 5064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 5074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected String[] separateLineAndHandleGroup(String line) throws VCardException { 5084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String[] propertyNameAndValue = new String[2]; 5094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int length = line.length(); 5104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (length > 0 && line.charAt(0) == '#') { 5114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardInvalidCommentLineException(); 5124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 5144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa int state = STATE_GROUP_OR_PROPERTY_NAME; 5154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa int nameIndex = 0; 5164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 5174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // This loop is developed so that we don't have to take care of bottle neck here. 5184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Refactor carefully when you need to do so. 5194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (int i = 0; i < length; i++) { 5204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final char ch = line.charAt(i); 5214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa switch (state) { 5224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case STATE_GROUP_OR_PROPERTY_NAME: { 5234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (ch == ':') { // End of a property name. 5244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String propertyName = line.substring(nameIndex, i); 5254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (propertyName.equalsIgnoreCase("END")) { 5264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mPreviousLine = line; 5274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return null; 5284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5294560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.propertyName(propertyName); 5304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa propertyNameAndValue[0] = propertyName; 5314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (i < length - 1) { 5324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa propertyNameAndValue[1] = line.substring(i + 1); 5334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 5344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa propertyNameAndValue[1] = ""; 5354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return propertyNameAndValue; 5374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (ch == '.') { // Each group is followed by the dot. 5384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String groupName = line.substring(nameIndex, i); 5394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (groupName.length() == 0) { 5404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.w(LOG_TAG, "Empty group found. Ignoring."); 5414560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } else { 5424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mInterpreter.propertyGroup(groupName); 5434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa nameIndex = i + 1; // Next should be another group or a property name. 545677ef21613a9d35053ec098444832ce4125a847eDaisuke Miyakawa } else if (ch == ';') { // End of property name and beginneng of parameters. 5464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String propertyName = line.substring(nameIndex, i); 5474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (propertyName.equalsIgnoreCase("END")) { 5484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mPreviousLine = line; 5494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return null; 5504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5514560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.propertyName(propertyName); 5524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa propertyNameAndValue[0] = propertyName; 5534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa nameIndex = i + 1; 5544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa state = STATE_PARAMS; // Start parameter parsing. 5554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 556d5a8fc2a35c69fc34df35fd545ccf83d548ba50cDaisuke Miyakawa // TODO: comma support (in vCard 3.0 and 4.0). 5574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 5584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case STATE_PARAMS: { 5604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (ch == '"') { 5614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (VCardConstants.VERSION_V21.equalsIgnoreCase(getVersionString())) { 5624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.w(LOG_TAG, "Double-quoted params found in vCard 2.1. " + 5634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa "Silently allow it"); 5644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa state = STATE_PARAMS_IN_DQUOTE; 5664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (ch == ';') { // Starts another param. 5674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa handleParams(line.substring(nameIndex, i)); 5684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa nameIndex = i + 1; 5694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (ch == ':') { // End of param and beginenning of values. 5704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa handleParams(line.substring(nameIndex, i)); 5714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (i < length - 1) { 5724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa propertyNameAndValue[1] = line.substring(i + 1); 5734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 5744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa propertyNameAndValue[1] = ""; 5754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return propertyNameAndValue; 5774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 5794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa case STATE_PARAMS_IN_DQUOTE: { 5814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (ch == '"') { 5824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (VCardConstants.VERSION_V21.equalsIgnoreCase(getVersionString())) { 5834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.w(LOG_TAG, "Double-quoted params found in vCard 2.1. " + 5844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa "Silently allow it"); 5854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa state = STATE_PARAMS; 5874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 5894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 5934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardInvalidLineException("Invalid line: \"" + line + "\""); 5944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 5954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 5964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /* 5974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * params = ";" [ws] paramlist paramlist = paramlist [ws] ";" [ws] param / 5984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * param param = "TYPE" [ws] "=" [ws] ptypeval / "VALUE" [ws] "=" [ws] 5994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * pvalueval / "ENCODING" [ws] "=" [ws] pencodingval / "CHARSET" [ws] "=" 6004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * [ws] charsetval / "LANGUAGE" [ws] "=" [ws] langval / "X-" word [ws] "=" 6014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * [ws] word / knowntype 6024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 6034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected void handleParams(String params) throws VCardException { 6044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String[] strArray = params.split("=", 2); 6054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (strArray.length == 2) { 6064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String paramName = strArray[0].trim().toUpperCase(); 6074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String paramValue = strArray[1].trim(); 6084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (paramName.equals("TYPE")) { 6094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa handleType(paramValue); 6104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (paramName.equals("VALUE")) { 6114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa handleValue(paramValue); 6124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (paramName.equals("ENCODING")) { 6134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa handleEncoding(paramValue); 6144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (paramName.equals("CHARSET")) { 6154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa handleCharset(paramValue); 6164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (paramName.equals("LANGUAGE")) { 6174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa handleLanguage(paramValue); 6184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (paramName.startsWith("X-")) { 6194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa handleAnyParam(paramName, paramValue); 6204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 6214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardException("Unknown type \"" + paramName + "\""); 6224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 6244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa handleParamWithoutName(strArray[0]); 6254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 6284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 6294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * vCard 3.0 parser implementation may throw VCardException. 6304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 6314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @SuppressWarnings("unused") 6324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected void handleParamWithoutName(final String paramValue) throws VCardException { 6334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa handleType(paramValue); 6344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 6364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /* 6374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * ptypeval = knowntype / "X-" word 6384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 6394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected void handleType(final String ptypeval) { 6404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!(getKnownTypeSet().contains(ptypeval.toUpperCase()) 6414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa || ptypeval.startsWith("X-")) 6424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa && !mUnknownTypeSet.contains(ptypeval)) { 6434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mUnknownTypeSet.add(ptypeval); 6444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.w(LOG_TAG, String.format("TYPE unsupported by %s: ", getVersion(), ptypeval)); 6454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6464560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.propertyParamType("TYPE"); 6474560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.propertyParamValue(ptypeval); 6484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 6504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /* 6514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * pvalueval = "INLINE" / "URL" / "CONTENT-ID" / "CID" / "X-" word 6524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 6534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected void handleValue(final String pvalueval) { 6544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!(getKnownValueSet().contains(pvalueval.toUpperCase()) 6554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa || pvalueval.startsWith("X-") 6564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa || mUnknownValueSet.contains(pvalueval))) { 6574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mUnknownValueSet.add(pvalueval); 6584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.w(LOG_TAG, String.format( 6594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa "The value unsupported by TYPE of %s: ", getVersion(), pvalueval)); 6604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6614560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.propertyParamType("VALUE"); 6624560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.propertyParamValue(pvalueval); 6634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 6654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /* 6664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * pencodingval = "7BIT" / "8BIT" / "QUOTED-PRINTABLE" / "BASE64" / "X-" word 6674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 6684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected void handleEncoding(String pencodingval) throws VCardException { 6694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (getAvailableEncodingSet().contains(pencodingval) || 6704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa pencodingval.startsWith("X-")) { 6714560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.propertyParamType("ENCODING"); 6724560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.propertyParamValue(pencodingval); 6734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mCurrentEncoding = pencodingval; 6744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 6754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardException("Unknown encoding \"" + pencodingval + "\""); 6764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 6794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 6804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 6814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * vCard 2.1 specification only allows us-ascii and iso-8859-xxx (See RFC 1521), 6824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * but recent vCard files often contain other charset like UTF-8, SHIFT_JIS, etc. 6834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * We allow any charset. 6844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 6854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 6864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected void handleCharset(String charsetval) { 6874560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.propertyParamType("CHARSET"); 6884560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.propertyParamValue(charsetval); 6894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 6914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 6924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * See also Section 7.1 of RFC 1521 6934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 6944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected void handleLanguage(String langval) throws VCardException { 6954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String[] strArray = langval.split("-"); 6964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (strArray.length != 2) { 6974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardException("Invalid Language: \"" + langval + "\""); 6984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 6994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String tmp = strArray[0]; 7004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa int length = tmp.length(); 7014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (int i = 0; i < length; i++) { 7024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!isAsciiLetter(tmp.charAt(i))) { 7034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardException("Invalid Language: \"" + langval + "\""); 7044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa tmp = strArray[1]; 7074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa length = tmp.length(); 7084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (int i = 0; i < length; i++) { 7094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!isAsciiLetter(tmp.charAt(i))) { 7104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardException("Invalid Language: \"" + langval + "\""); 7114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7134560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.propertyParamType(VCardConstants.PARAM_LANGUAGE); 7144560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.propertyParamValue(langval); 7154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 7174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private boolean isAsciiLetter(char ch) { 7184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) { 7194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return true; 7204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return false; 7224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 7244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 7254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Mainly for "X-" type. This accepts any kind of type without check. 7264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 7274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected void handleAnyParam(String paramName, String paramValue) { 7284560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.propertyParamType(paramName); 7294560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.propertyParamValue(paramValue); 7304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 7324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected void handlePropertyValue(String propertyName, String propertyValue) 7334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throws IOException, VCardException { 7344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String upperEncoding = mCurrentEncoding.toUpperCase(); 7354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (upperEncoding.equals(VCardConstants.PARAM_ENCODING_QP)) { 7364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final long start = System.currentTimeMillis(); 7374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String result = getQuotedPrintable(propertyValue); 7384560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa final ArrayList<String> v = new ArrayList<String>(); 7394560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa v.add(result); 7404560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.propertyValues(v); 7414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mTimeHandleQuotedPrintable += System.currentTimeMillis() - start; 7424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (upperEncoding.equals(VCardConstants.PARAM_ENCODING_BASE64) 7434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa || upperEncoding.equals(VCardConstants.PARAM_ENCODING_B)) { 7444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final long start = System.currentTimeMillis(); 7454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // It is very rare, but some BASE64 data may be so big that 7464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // OutOfMemoryError occurs. To ignore such cases, use try-catch. 7474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa try { 7484560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa final ArrayList<String> arrayList = new ArrayList<String>(); 7494560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa arrayList.add(getBase64(propertyValue)); 7504560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.propertyValues(arrayList); 7514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } catch (OutOfMemoryError error) { 7524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.e(LOG_TAG, "OutOfMemoryError happened during parsing BASE64 data!"); 7534560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.propertyValues(null); 7544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mTimeHandleBase64 += System.currentTimeMillis() - start; 7564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 7574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!(upperEncoding.equals("7BIT") || upperEncoding.equals("8BIT") || 7584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa upperEncoding.startsWith("X-"))) { 7594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.w(LOG_TAG, 7604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String.format("The encoding \"%s\" is unsupported by vCard %s", 7614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mCurrentEncoding, getVersionString())); 7624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 7634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 764f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // Some device uses line folding defined in RFC 2425, which is not allowed 765f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // in vCard 2.1 (while needed in vCard 3.0). 766f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // 767f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // e.g. 768f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // BEGIN:VCARD 769f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // VERSION:2.1 770f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // N:;Omega;;; 771f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // EMAIL;INTERNET:"Omega" 772f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // <omega@example.com> 773f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // FN:Omega 774f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // END:VCARD 775f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // 776f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // The vCard above assumes that email address should become: 777f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // "Omega" <omega@example.com> 778f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // 779f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // But vCard 2.1 requires Quote-Printable when a line contains line break(s). 780f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // 781f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // For more information about line folding, 782f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // see "5.8.1. Line delimiting and folding" in RFC 2425. 783f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // 784f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // We take care of this case more formally in vCard 3.0, so we only need to 785f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // do this in vCard 2.1. 786be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa if (getVersion() == VCardConfig.VERSION_21) { 787f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa StringBuilder builder = null; 788f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa while (true) { 789f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa final String nextLine = peekLine(); 790f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // We don't need to care too much about this exceptional case, 791f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // but we should not wrongly eat up "END:VCARD", since it critically 792f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // breaks this parser's state machine. 793f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // Thus we roughly look over the next line and confirm it is at least not 794f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // "END:VCARD". This extra fee is worth paying. This is exceptional 795f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa // anyway. 796f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa if (!TextUtils.isEmpty(nextLine) && 797f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa nextLine.charAt(0) == ' ' && 798f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa !"END:VCARD".contains(nextLine.toUpperCase())) { 799f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa getLine(); // Drop the next line. 800f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa 801f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa if (builder == null) { 802f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa builder = new StringBuilder(); 803f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa builder.append(propertyValue); 804f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa } 805f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa builder.append(nextLine.substring(1)); 806f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa } else { 807f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa break; 808f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa } 809f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa } 810f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa if (builder != null) { 811f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa propertyValue = builder.toString(); 812f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa } 813f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa } 814f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa 8154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final long start = System.currentTimeMillis(); 8164560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa ArrayList<String> v = new ArrayList<String>(); 8174560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa v.add(maybeUnescapeText(propertyValue)); 8184560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.propertyValues(v); 8194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mTimeHandleMiscPropertyValue += System.currentTimeMillis() - start; 8204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 8214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 8224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 8234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 8244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 8254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Parses and returns Quoted-Printable. 8264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 8274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * 8284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @param firstString The string following a parameter name and attributes. 8294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Example: "string" in 8304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * "ADR:ENCODING=QUOTED-PRINTABLE:string\n\r". 8314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @return whole Quoted-Printable string, including a given argument and 8324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * following lines. Excludes the last empty line following to Quoted 8334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Printable lines. 8344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @throws IOException 8354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @throws VCardException 8364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 8374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private String getQuotedPrintable(String firstString) throws IOException, VCardException { 8384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Specifically, there may be some padding between = and CRLF. 8394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // See the following: 8404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 8414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // qp-line := *(qp-segment transport-padding CRLF) 8424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // qp-part transport-padding 8434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // qp-segment := qp-section *(SPACE / TAB) "=" 8444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // ; Maximum length of 76 characters 8454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 8464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // e.g. (from RFC 2045) 8474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Now's the time = 8484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // for all folk to come= 8494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // to the aid of their country. 8504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (firstString.trim().endsWith("=")) { 8514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // remove "transport-padding" 8524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa int pos = firstString.length() - 1; 8534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa while (firstString.charAt(pos) != '=') { 8544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 8554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa StringBuilder builder = new StringBuilder(); 8564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(firstString.substring(0, pos + 1)); 8574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append("\r\n"); 8584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String line; 8594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa while (true) { 8604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa line = getLine(); 8614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (line == null) { 8624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardException("File ended during parsing a Quoted-Printable String"); 8634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 8644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (line.trim().endsWith("=")) { 8654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // remove "transport-padding" 8664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa pos = line.length() - 1; 8674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa while (line.charAt(pos) != '=') { 8684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 8694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(line.substring(0, pos + 1)); 8704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append("\r\n"); 8714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 8724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(line); 8734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 8744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 8754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 8764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return builder.toString(); 8774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 8784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return firstString; 8794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 8804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 8814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 8824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected String getBase64(String firstString) throws IOException, VCardException { 883c955c8b0da0c9fcbad0ddcae76641358c27e72cdDaisuke Miyakawa final StringBuilder builder = new StringBuilder(); 8844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(firstString); 8854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 8864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa while (true) { 887c955c8b0da0c9fcbad0ddcae76641358c27e72cdDaisuke Miyakawa final String line = peekLine(); 8884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (line == null) { 8894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardException("File ended during parsing BASE64 binary"); 8904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 891c955c8b0da0c9fcbad0ddcae76641358c27e72cdDaisuke Miyakawa 892c955c8b0da0c9fcbad0ddcae76641358c27e72cdDaisuke Miyakawa // vCard 2.1 requires two spaces at the end of BASE64 strings, but some vCard doesn't 893c955c8b0da0c9fcbad0ddcae76641358c27e72cdDaisuke Miyakawa // have them. We try to detect those cases using semi-colon, given BASE64 doesn't 894c955c8b0da0c9fcbad0ddcae76641358c27e72cdDaisuke Miyakawa // contain it. Specifically BASE64 doesn't have semi-colon in it, so we should be able 895c955c8b0da0c9fcbad0ddcae76641358c27e72cdDaisuke Miyakawa // to detect the case safely. 896c955c8b0da0c9fcbad0ddcae76641358c27e72cdDaisuke Miyakawa if (line.contains(":")) { 897c955c8b0da0c9fcbad0ddcae76641358c27e72cdDaisuke Miyakawa if (getKnownPropertyNameSet().contains( 898c955c8b0da0c9fcbad0ddcae76641358c27e72cdDaisuke Miyakawa line.substring(0, line.indexOf(":")).toUpperCase())) { 899c955c8b0da0c9fcbad0ddcae76641358c27e72cdDaisuke Miyakawa Log.w(LOG_TAG, "Found a next property during parsing a BASE64 string, " + 900c955c8b0da0c9fcbad0ddcae76641358c27e72cdDaisuke Miyakawa "which must not contain semi-colon. Treat the line as next property."); 901c955c8b0da0c9fcbad0ddcae76641358c27e72cdDaisuke Miyakawa Log.w(LOG_TAG, "Problematic line: " + line.trim()); 902c955c8b0da0c9fcbad0ddcae76641358c27e72cdDaisuke Miyakawa break; 903c955c8b0da0c9fcbad0ddcae76641358c27e72cdDaisuke Miyakawa } 904c955c8b0da0c9fcbad0ddcae76641358c27e72cdDaisuke Miyakawa } 905c955c8b0da0c9fcbad0ddcae76641358c27e72cdDaisuke Miyakawa 906c955c8b0da0c9fcbad0ddcae76641358c27e72cdDaisuke Miyakawa // Consume the line. 907c955c8b0da0c9fcbad0ddcae76641358c27e72cdDaisuke Miyakawa getLine(); 908c955c8b0da0c9fcbad0ddcae76641358c27e72cdDaisuke Miyakawa 9094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (line.length() == 0) { 9104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 9114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(line); 9134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 9154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return builder.toString(); 9164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 9184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 9194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 9204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Mainly for "ADR", "ORG", and "N" 9214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 9224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 9234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /* 9244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * addressparts = 0*6(strnosemi ";") strnosemi ; PO Box, Extended Addr, 9254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Street, Locality, Region, Postal Code, Country Name orgparts = 9264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * *(strnosemi ";") strnosemi ; First is Organization Name, remainder are 9274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Organization Units. nameparts = 0*4(strnosemi ";") strnosemi ; Family, 9284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Given, Middle, Prefix, Suffix. ; Example:Public;John;Q.;Reverend Dr.;III, 9294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Esq. strnosemi = *(*nonsemi ("\;" / "\" CRLF)) *nonsemi ; To include a 9304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * semicolon in this string, it must be escaped ; with a "\" character. We 9314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * do not care the number of "strnosemi" here. We are not sure whether we 9324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * should add "\" CRLF to each value. We exclude them for now. 9334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 9344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected void handleMultiplePropertyValue(String propertyName, String propertyValue) 9354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throws IOException, VCardException { 9364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // vCard 2.1 does not allow QUOTED-PRINTABLE here, but some 9374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // softwares/devices 9384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // emit such data. 9394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (mCurrentEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) { 9404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa propertyValue = getQuotedPrintable(propertyValue); 9414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 9434560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter.propertyValues(VCardUtils.constructListFromValue(propertyValue, 9444560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa getVersion())); 9454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 9474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /* 9484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * vCard 2.1 specifies AGENT allows one vcard entry. Currently we emit an 9494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * error toward the AGENT property. 9504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * // TODO: Support AGENT property. 9514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * item = 9524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * ... / [groups "."] "AGENT" [params] ":" vcard CRLF vcard = "BEGIN" [ws] 9534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * ":" [ws] "VCARD" [ws] 1*CRLF items *CRLF "END" [ws] ":" [ws] "VCARD" 9544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 9554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected void handleAgent(final String propertyValue) throws VCardException { 9564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!propertyValue.toUpperCase().contains("BEGIN:VCARD")) { 9574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Apparently invalid line seen in Windows Mobile 6.5. Ignore them. 9584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return; 9594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 9604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardAgentNotSupportedException("AGENT Property is not supported now."); 9614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 9644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 9654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * For vCard 3.0. 9664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 9674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected String maybeUnescapeText(final String text) { 9684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return text; 9694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 9714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 9724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Returns unescaped String if the character should be unescaped. Return 9734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * null otherwise. e.g. In vCard 2.1, "\;" should be unescaped into ";" 9744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * while "\x" should not be. 9754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 9764560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa protected String maybeUnescapeCharacter(final char ch) { 9774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return unescapeCharacter(ch); 9784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 9804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /* package */ static String unescapeCharacter(final char ch) { 9814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Original vCard 2.1 specification does not allow transformation 9824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // "\:" -> ":", "\," -> ",", and "\\" -> "\", but previous 9834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // implementation of 9844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // this class allowed them, so keep it as is. 9854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (ch == '\\' || ch == ';' || ch == ':' || ch == ',') { 9864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return String.valueOf(ch); 9874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 9884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return null; 9894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 9914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 9924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private void showPerformanceInfo() { 9934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.d(LOG_TAG, "Total parsing time: " + mTimeTotal + " ms"); 994f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa Log.d(LOG_TAG, "Total readLine time: " + mReader.getTotalmillisecond() + " ms"); 9954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.d(LOG_TAG, "Time for handling the beggining of the record: " + mTimeReadStartRecord 9964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa + " ms"); 9974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.d(LOG_TAG, "Time for handling the end of the record: " + mTimeReadEndRecord + " ms"); 9984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.d(LOG_TAG, "Time for parsing line, and handling group: " + mTimeParseLineAndHandleGroup 9994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa + " ms"); 10004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.d(LOG_TAG, "Time for parsing ADR, ORG, and N fields:" + mTimeParseAdrOrgN + " ms"); 10014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.d(LOG_TAG, "Time for parsing property values: " + mTimeParsePropertyValues + " ms"); 10024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.d(LOG_TAG, "Time for handling normal property values: " + mTimeHandleMiscPropertyValue 10034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa + " ms"); 10044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.d(LOG_TAG, "Time for handling Quoted-Printable: " + mTimeHandleQuotedPrintable + " ms"); 10054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.d(LOG_TAG, "Time for handling Base64: " + mTimeHandleBase64 + " ms"); 10064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 1009be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa * @return {@link VCardConfig#VERSION_21} 10104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 10114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected int getVersion() { 1012be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa return VCardConfig.VERSION_21; 10134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 1016be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa * @return {@link VCardConfig#VERSION_30} 10174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 10184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected String getVersionString() { 10194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return VCardConstants.VERSION_V21; 10204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected Set<String> getKnownPropertyNameSet() { 10234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return VCardParser_V21.sKnownPropertyNameSet; 10244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected Set<String> getKnownTypeSet() { 10274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return VCardParser_V21.sKnownTypeSet; 10284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected Set<String> getKnownValueSet() { 10314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return VCardParser_V21.sKnownValueSet; 10324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected Set<String> getAvailableEncodingSet() { 10354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return VCardParser_V21.sAvailableEncoding; 10364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected String getDefaultEncoding() { 10394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return DEFAULT_ENCODING; 10404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public void parse(InputStream is, VCardInterpreter interpreter) 10444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throws IOException, VCardException { 10454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (is == null) { 10464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new NullPointerException("InputStream must not be null."); 10474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final InputStreamReader tmpReader = new InputStreamReader(is, mIntermediateCharset); 1050f6d9e0eeae38a72481ce2e19d0872d3f8f81189fDaisuke Miyakawa mReader = new CustomBufferedReader(tmpReader); 10514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10524560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa mInterpreter = (interpreter != null ? interpreter : new EmptyInterpreter()); 10534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final long start = System.currentTimeMillis(); 10554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (mInterpreter != null) { 10564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mInterpreter.start(); 10574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa parseVCardFile(); 10594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (mInterpreter != null) { 10604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mInterpreter.end(); 10614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mTimeTotal += System.currentTimeMillis() - start; 10634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (VCardConfig.showPerformanceLog()) { 10654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa showPerformanceInfo(); 10664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 10694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public final void cancel() { 1070b23043e3a199e951817b6d86c301b9521d4c26feDaisuke Miyakawa Log.i(LOG_TAG, "ParserImpl received cancel operation."); 10714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mCanceled = true; 10724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 10734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa} 1074