VCardParserImpl_V30.java revision 4199c54c527330ac01699b176e7bca186a3aa3a4
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 184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport android.util.Log; 194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport com.android.vcard.exception.VCardException; 214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.io.IOException; 234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawaimport java.util.Set; 244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa/** 264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Basic implementation achieving vCard 3.0 parsing. 284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * <p> 304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * This class inherits vCard 2.1 implementation since technically they are similar, 314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * while specifically there's logical no relevance between them. 324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * So that developers are not confused with the inheritance, 334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * {@link VCardParser_V30} does not inherit {@link VCardParser_V21}, while 344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * {@link VCardParserImpl_V30} inherits {@link VCardParserImpl_V21}. 354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * </p> 364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * @hide 374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa/* package */ class VCardParserImpl_V30 extends VCardParserImpl_V21 { 394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private static final String LOG_TAG = "VCardParserImpl_V30"; 404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private String mPreviousLine; 424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa private boolean mEmittedAgentWarning = false; 434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public VCardParserImpl_V30() { 454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa super(); 464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public VCardParserImpl_V30(int vcardType) { 494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa super(vcardType); 504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected int getVersion() { 544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return VCardConfig.FLAG_V30; 554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected String getVersionString() { 594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return VCardConstants.VERSION_V30; 604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected String getLine() throws IOException { 644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (mPreviousLine != null) { 654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String ret = mPreviousLine; 664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mPreviousLine = null; 674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return ret; 684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return mReader.readLine(); 704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * vCard 3.0 requires that the line with space at the beginning of the line 754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * must be combined with previous line. 764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected String getNonEmptyLine() throws IOException, VCardException { 794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String line; 804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa StringBuilder builder = null; 814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa while (true) { 824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa line = mReader.readLine(); 834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (line == null) { 844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (builder != null) { 854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return builder.toString(); 864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (mPreviousLine != null) { 874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String ret = mPreviousLine; 884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mPreviousLine = null; 894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return ret; 904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardException("Reached end of buffer."); 924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (line.length() == 0) { 934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (builder != null) { 944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return builder.toString(); 954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (mPreviousLine != null) { 964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String ret = mPreviousLine; 974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mPreviousLine = null; 984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return ret; 994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (line.charAt(0) == ' ' || line.charAt(0) == '\t') { 1014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (builder != null) { 1024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // See Section 5.8.1 of RFC 2425 (MIME-DIR document). 1034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Following is the excerpts from it. 1044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 1054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // DESCRIPTION:This is a long description that exists on a long line. 1064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 1074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Can be represented as: 1084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 1094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // DESCRIPTION:This is a long description 1104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // that exists on a long line. 1114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 1124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // It could also be represented as: 1134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 1144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // DESCRIPTION:This is a long descrip 1154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // tion that exists o 1164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // n a long line. 1174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(line.substring(1)); 1184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (mPreviousLine != null) { 1194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder = new StringBuilder(); 1204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(mPreviousLine); 1214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mPreviousLine = null; 1224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(line.substring(1)); 1234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 1244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardException("Space exists at the beginning of the line"); 1254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 1274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (mPreviousLine == null) { 1284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mPreviousLine = line; 1294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (builder != null) { 1304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return builder.toString(); 1314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 1334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String ret = mPreviousLine; 1344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mPreviousLine = line; 1354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return ret; 1364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /* 1424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * vcard = [group "."] "BEGIN" ":" "VCARD" 1 * CRLF 1434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * 1 * (contentline) 1444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * ;A vCard object MUST include the VERSION, FN and N types. 1454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * [group "."] "END" ":" "VCARD" 1 * CRLF 1464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 1474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 1484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected boolean readBeginVCard(boolean allowGarbage) throws IOException, VCardException { 1494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // TODO: vCard 3.0 supports group. 1504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return super.readBeginVCard(allowGarbage); 1514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 1544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected void readEndVCard(boolean useCache, boolean allowGarbage) 1554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throws IOException, VCardException { 1564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // TODO: vCard 3.0 supports group. 1574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa super.readEndVCard(useCache, allowGarbage); 1584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 1614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * vCard 3.0 allows iana-token as paramType, while vCard 2.1 does not. 1624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 1634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 1644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected void handleParams(final String params) throws VCardException { 1654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa try { 1664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa super.handleParams(params); 1674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } catch (VCardException e) { 1684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // maybe IANA type 1694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String[] strArray = params.split("=", 2); 1704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (strArray.length == 2) { 1714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa handleAnyParam(strArray[0], strArray[1]); 1724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 1734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Must not come here in the current implementation. 1744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardException( 1754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa "Unknown params value: " + params); 1764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 1814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected void handleAnyParam(final String paramName, final String paramValue) { 1824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa super.handleAnyParam(paramName, paramValue); 1834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 1864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected void handleParamWithoutName(final String paramValue) throws VCardException { 1874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa super.handleParamWithoutName(paramValue); 1884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /* 1914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * vCard 3.0 defines 1924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * 1934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * param = param-name "=" param-value *("," param-value) 1944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * param-name = iana-token / x-name 1954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * param-value = ptext / quoted-string 1964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * quoted-string = DQUOTE QSAFE-CHAR DQUOTE 1974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 1984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 1994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected void handleType(final String ptypevalues) { 2004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String[] ptypeArray = ptypevalues.split(","); 2014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mInterpreter.propertyParamType("TYPE"); 2024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (String value : ptypeArray) { 2034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa int length = value.length(); 2044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (length >= 2 && value.startsWith("\"") && value.endsWith("\"")) { 2054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mInterpreter.propertyParamValue(value.substring(1, value.length() - 1)); 2064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 2074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mInterpreter.propertyParamValue(value); 2084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 2134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected void handleAgent(final String propertyValue) { 2144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // The way how vCard 3.0 supports "AGENT" is completely different from vCard 2.1. 2154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 2164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // e.g. 2174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // AGENT:BEGIN:VCARD\nFN:Joe Friday\nTEL:+1-919-555-7878\n 2184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // TITLE:Area Administrator\, Assistant\n EMAIL\;TYPE=INTERN\n 2194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // ET:jfriday@host.com\nEND:VCARD\n 2204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 2214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // TODO: fix this. 2224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 2234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // issue: 2244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // vCard 3.0 also allows this as an example. 2254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 2264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // AGENT;VALUE=uri: 2274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // CID:JQPUBLIC.part3.960129T083020.xyzMail@host3.com 2284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 2294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // This is not vCard. Should we support this? 2304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 2314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Just ignore the line for now, since we cannot know how to handle it... 2324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!mEmittedAgentWarning) { 2334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.w(LOG_TAG, "AGENT in vCard 3.0 is not supported yet. Ignore it"); 2344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mEmittedAgentWarning = true; 2354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2374199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 2394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * vCard 3.0 does not require two CRLF at the last of BASE64 data. 2404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * It only requires that data should be MIME-encoded. 2414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 2424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 2434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected String getBase64(final String firstString) 2444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throws IOException, VCardException { 2454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final StringBuilder builder = new StringBuilder(); 2464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(firstString); 2474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa while (true) { 2494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final String line = getLine(); 2504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (line == null) { 2514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardException("File ended during parsing BASE64 binary"); 2524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (line.length() == 0) { 2544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 2554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (!line.startsWith(" ") && !line.startsWith("\t")) { 2564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mPreviousLine = line; 2574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa break; 2584199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2594199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(line); 2604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return builder.toString(); 2634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 2664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * ESCAPED-CHAR = "\\" / "\;" / "\," / "\n" / "\N") 2674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * ; \\ encodes \, \n or \N encodes newline 2684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * ; \; encodes ;, \, encodes , 2694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * 2704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Note: Apple escapes ':' into '\:' while does not escape '\' 2714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 2724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 2734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected String maybeUnescapeText(final String text) { 2744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return unescapeText(text); 2754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static String unescapeText(final String text) { 2784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa StringBuilder builder = new StringBuilder(); 2794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int length = text.length(); 2804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (int i = 0; i < length; i++) { 2814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa char ch = text.charAt(i); 2824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (ch == '\\' && i < length - 1) { 2834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final char next_ch = text.charAt(++i); 2844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (next_ch == 'n' || next_ch == 'N') { 2854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append("\n"); 2864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 2874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(next_ch); 2884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 2904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(ch); 2914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return builder.toString(); 2944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2964199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 2974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected String maybeUnescapeCharacter(final char ch) { 2984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return unescapeCharacter(ch); 2994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 3014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static String unescapeCharacter(final char ch) { 3024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (ch == 'n' || ch == 'N') { 3034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return "\n"; 3044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 3054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return String.valueOf(ch); 3064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 3094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 3104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected Set<String> getKnownPropertyNameSet() { 3114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return VCardParser_V30.sKnownPropertyNameSet; 3124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa} 314