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 { 3902117b3d19787ff65486b9f9db8abd338ae4c9f9Daisuke Miyakawa private static final String LOG_TAG = VCardConstants.LOG_TAG; 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() { 54be378d5b188f51cf717e5309e3c39180e85833a8Daisuke Miyakawa return VCardConfig.VERSION_30; 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; 81210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner while ((line = mReader.readLine()) != null) { 82210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner // Skip empty lines in order to accomodate implementations that 83210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner // send line termination variations such as \r\r\n. 84210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner if (line.length() == 0) { 85210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner continue; 864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else if (line.charAt(0) == ' ' || line.charAt(0) == '\t') { 87210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner // RFC 2425 describes line continuation as \r\n followed by 88210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner // a single ' ' or '\t' whitespace character. 89210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner if (builder == null) { 904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder = new StringBuilder(); 91210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner } 92210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner if (mPreviousLine != null) { 934199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(mPreviousLine); 944199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mPreviousLine = null; 954199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 96210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner builder.append(line.substring(1)); 974199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 98210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner if (builder != null || mPreviousLine != null) { 99210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner break; 1004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 101210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner mPreviousLine = line; 1024199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 104210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner 105210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner String ret = null; 106210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner if (builder != null) { 107210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner ret = builder.toString(); 108210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner } else if (mPreviousLine != null) { 109210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner ret = mPreviousLine; 110210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner } 111210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner mPreviousLine = line; 112210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner if (ret == null) { 113210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner throw new VCardException("Reached end of buffer."); 114210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner } 115210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner return ret; 1164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /* 1194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * vcard = [group "."] "BEGIN" ":" "VCARD" 1 * CRLF 1204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * 1 * (contentline) 1214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * ;A vCard object MUST include the VERSION, FN and N types. 1224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * [group "."] "END" ":" "VCARD" 1 * CRLF 1234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 1244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 1254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected boolean readBeginVCard(boolean allowGarbage) throws IOException, VCardException { 1264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // TODO: vCard 3.0 supports group. 1274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return super.readBeginVCard(allowGarbage); 1284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 1314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * vCard 3.0 allows iana-token as paramType, while vCard 2.1 does not. 1324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 1334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 1341de396f6df89363169d3a2e61a61fa98d12c1ef8Daisuke Miyakawa protected void handleParams(VCardProperty propertyData, final String params) 13548dd8e86a81d2ab40eb762975c8211c225002bf0Daisuke Miyakawa throws VCardException { 1364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa try { 13748dd8e86a81d2ab40eb762975c8211c225002bf0Daisuke Miyakawa super.handleParams(propertyData, params); 1384199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } catch (VCardException e) { 1394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // maybe IANA type 1404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa String[] strArray = params.split("=", 2); 1414199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (strArray.length == 2) { 14248dd8e86a81d2ab40eb762975c8211c225002bf0Daisuke Miyakawa handleAnyParam(propertyData, strArray[0], strArray[1]); 1434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 1444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Must not come here in the current implementation. 1454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throw new VCardException( 1464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa "Unknown params value: " + params); 1474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 15248dd8e86a81d2ab40eb762975c8211c225002bf0Daisuke Miyakawa protected void handleAnyParam( 1531de396f6df89363169d3a2e61a61fa98d12c1ef8Daisuke Miyakawa VCardProperty propertyData, final String paramName, final String paramValue) { 15448dd8e86a81d2ab40eb762975c8211c225002bf0Daisuke Miyakawa splitAndPutParam(propertyData, paramName, paramValue); 1554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 1581de396f6df89363169d3a2e61a61fa98d12c1ef8Daisuke Miyakawa protected void handleParamWithoutName(VCardProperty property, final String paramValue) { 1591de396f6df89363169d3a2e61a61fa98d12c1ef8Daisuke Miyakawa handleType(property, paramValue); 1604199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 1614199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 1624199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /* 1634199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * vCard 3.0 defines 1644199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * 1654199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * param = param-name "=" param-value *("," param-value) 1664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * param-name = iana-token / x-name 1674199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * param-value = ptext / quoted-string 1684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * quoted-string = DQUOTE QSAFE-CHAR DQUOTE 169a76f41e328f31c2e9e9006160d8f65fe651eeb6aDaisuke Miyakawa * QSAFE-CHAR = WSP / %x21 / %x23-7E / NON-ASCII 170a76f41e328f31c2e9e9006160d8f65fe651eeb6aDaisuke Miyakawa * ; Any character except CTLs, DQUOTE 171a76f41e328f31c2e9e9006160d8f65fe651eeb6aDaisuke Miyakawa * 172a76f41e328f31c2e9e9006160d8f65fe651eeb6aDaisuke Miyakawa * QSAFE-CHAR must not contain DQUOTE, including escaped one (\"). 1734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 1744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 1751de396f6df89363169d3a2e61a61fa98d12c1ef8Daisuke Miyakawa protected void handleType(VCardProperty property, final String paramValue) { 1761de396f6df89363169d3a2e61a61fa98d12c1ef8Daisuke Miyakawa splitAndPutParam(property, VCardConstants.PARAM_TYPE, paramValue); 1774560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } 178a76f41e328f31c2e9e9006160d8f65fe651eeb6aDaisuke Miyakawa 1794560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa /** 1804560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa * Splits parameter values into pieces in accordance with vCard 3.0 specification and 1814560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa * puts pieces into mInterpreter. 1824560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa */ 1834560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa /* 1844560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa * param-value = ptext / quoted-string 1854560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa * quoted-string = DQUOTE QSAFE-CHAR DQUOTE 1864560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa * QSAFE-CHAR = WSP / %x21 / %x23-7E / NON-ASCII 1874560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa * ; Any character except CTLs, DQUOTE 1884560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa * 1894560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa * QSAFE-CHAR must not contain DQUOTE, including escaped one (\") 1904560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa */ 1911de396f6df89363169d3a2e61a61fa98d12c1ef8Daisuke Miyakawa private void splitAndPutParam(VCardProperty property, String paramName, String paramValue) { 1924560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa // "comma,separated:inside.dquote",pref 1934560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa // --> 1944560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa // - comma,separated:inside.dquote 1954560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa // - pref 1964560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa // 1974560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa // Note: Though there's a code, we don't need to take much care of 1984560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa // wrongly-added quotes like the example above, as they induce 1994560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa // parse errors at the top level (when splitting a line into parts). 2004560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa StringBuilder builder = null; // Delay initialization. 2014560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa boolean insideDquote = false; 2024560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa final int length = paramValue.length(); 2034560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa for (int i = 0; i < length; i++) { 2044560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa final char ch = paramValue.charAt(i); 2054560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa if (ch == '"') { 2064560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa if (insideDquote) { 2074560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa // End of Dquote. 2081de396f6df89363169d3a2e61a61fa98d12c1ef8Daisuke Miyakawa property.addParameter(paramName, encodeParamValue(builder.toString())); 2094560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa builder = null; 2104560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa insideDquote = false; 211a76f41e328f31c2e9e9006160d8f65fe651eeb6aDaisuke Miyakawa } else { 2124560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa if (builder != null) { 2134560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa if (builder.length() > 0) { 2144560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa // e.g. 2154560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa // pref"quoted" 2164560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa Log.w(LOG_TAG, "Unexpected Dquote inside property."); 2174560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } else { 2184560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa // e.g. 2194560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa // pref,"quoted" 2204560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa // "quoted",pref 2211de396f6df89363169d3a2e61a61fa98d12c1ef8Daisuke Miyakawa property.addParameter(paramName, encodeParamValue(builder.toString())); 2224560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } 223a76f41e328f31c2e9e9006160d8f65fe651eeb6aDaisuke Miyakawa } 2244560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa insideDquote = true; 225a76f41e328f31c2e9e9006160d8f65fe651eeb6aDaisuke Miyakawa } 2264560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } else if (ch == ',' && !insideDquote) { 2274560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa if (builder == null) { 2284560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa Log.w(LOG_TAG, "Comma is used before actual string comes. (" + 2294560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa paramValue + ")"); 230a76f41e328f31c2e9e9006160d8f65fe651eeb6aDaisuke Miyakawa } else { 2311de396f6df89363169d3a2e61a61fa98d12c1ef8Daisuke Miyakawa property.addParameter(paramName, encodeParamValue(builder.toString())); 2324560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa builder = null; 2334560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } 2344560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } else { 2354560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa // To stop creating empty StringBuffer at the end of parameter, 2364560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa // we delay creating this object until this point. 2374560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa if (builder == null) { 2384560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa builder = new StringBuilder(); 239a76f41e328f31c2e9e9006160d8f65fe651eeb6aDaisuke Miyakawa } 2404560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa builder.append(ch); 2414560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } 2424560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } 2434560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa if (insideDquote) { 2444560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa // e.g. 2454560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa // "non-quote-at-end 2464560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa Log.d(LOG_TAG, "Dangling Dquote."); 2474560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } 2484560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa if (builder != null) { 2494560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa if (builder.length() == 0) { 2504560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa Log.w(LOG_TAG, "Unintended behavior. We must not see empty StringBuilder " + 2514560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa "at the end of parameter value parsing."); 2524560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa } else { 2531de396f6df89363169d3a2e61a61fa98d12c1ef8Daisuke Miyakawa property.addParameter(paramName, encodeParamValue(builder.toString())); 2544199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2554199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2564199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2574199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2581de396f6df89363169d3a2e61a61fa98d12c1ef8Daisuke Miyakawa /** 2591de396f6df89363169d3a2e61a61fa98d12c1ef8Daisuke Miyakawa * Encode a param value using UTF-8. 2601de396f6df89363169d3a2e61a61fa98d12c1ef8Daisuke Miyakawa */ 2611de396f6df89363169d3a2e61a61fa98d12c1ef8Daisuke Miyakawa protected String encodeParamValue(String paramValue) { 2621de396f6df89363169d3a2e61a61fa98d12c1ef8Daisuke Miyakawa return VCardUtils.convertStringCharset( 2631de396f6df89363169d3a2e61a61fa98d12c1ef8Daisuke Miyakawa paramValue, VCardConfig.DEFAULT_INTERMEDIATE_CHARSET, "UTF-8"); 2641de396f6df89363169d3a2e61a61fa98d12c1ef8Daisuke Miyakawa } 2651de396f6df89363169d3a2e61a61fa98d12c1ef8Daisuke Miyakawa 2664199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 2671de396f6df89363169d3a2e61a61fa98d12c1ef8Daisuke Miyakawa protected void handleAgent(VCardProperty property) { 2684199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // The way how vCard 3.0 supports "AGENT" is completely different from vCard 2.1. 2694199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 2704199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // e.g. 2714199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // AGENT:BEGIN:VCARD\nFN:Joe Friday\nTEL:+1-919-555-7878\n 2724199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // TITLE:Area Administrator\, Assistant\n EMAIL\;TYPE=INTERN\n 2734199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // ET:jfriday@host.com\nEND:VCARD\n 2744199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 2754199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // TODO: fix this. 2764199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 2774199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // issue: 2784199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // vCard 3.0 also allows this as an example. 2794199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 2804199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // AGENT;VALUE=uri: 2814199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // CID:JQPUBLIC.part3.960129T083020.xyzMail@host3.com 2824199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 2834199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // This is not vCard. Should we support this? 2844199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // 2854199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa // Just ignore the line for now, since we cannot know how to handle it... 2864199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (!mEmittedAgentWarning) { 2874199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa Log.w(LOG_TAG, "AGENT in vCard 3.0 is not supported yet. Ignore it"); 2884199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa mEmittedAgentWarning = true; 2894199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2904199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 2914199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 2924199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 293210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner * This is only called from handlePropertyValue(), which has already 294210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner * read the first line of this property. With v3.0, the getNonEmptyLine() 295210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner * routine has already concatenated all following continuation lines. 296210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner * The routine is implemented in the V21 parser to concatenate v2.1 style 297210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner * data blocks, but is unnecessary here. 2984199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 2994199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 3004199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected String getBase64(final String firstString) 3014199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa throws IOException, VCardException { 302210ebaab315e389ffc66278e28ecd6230e412b5fJay Shrauner return firstString; 3034199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3044199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 3054199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa /** 3064199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * ESCAPED-CHAR = "\\" / "\;" / "\," / "\n" / "\N") 3074199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * ; \\ encodes \, \n or \N encodes newline 3084199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * ; \; encodes ;, \, encodes , 3094199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * 3104199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa * Note: Apple escapes ':' into '\:' while does not escape '\' 3114199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa */ 3124199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 3134199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected String maybeUnescapeText(final String text) { 3144199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return unescapeText(text); 3154199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3164199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 3174199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa public static String unescapeText(final String text) { 3184199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa StringBuilder builder = new StringBuilder(); 3194199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final int length = text.length(); 3204199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa for (int i = 0; i < length; i++) { 3214199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa char ch = text.charAt(i); 3224199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (ch == '\\' && i < length - 1) { 3234199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa final char next_ch = text.charAt(++i); 3244199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (next_ch == 'n' || next_ch == 'N') { 3254199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append("\n"); 3264199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 3274199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(next_ch); 3284199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3294199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 3304199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa builder.append(ch); 3314199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3324199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3334199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return builder.toString(); 3344199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3354199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 3364199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 3374560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa protected String maybeUnescapeCharacter(final char ch) { 3384560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa return unescapeCharacter(ch); 3394199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3404199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 3414560bdde6dd75cca49fc55b58aafb5d416b88ca3Daisuke Miyakawa public static String unescapeCharacter(final char ch) { 3424199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa if (ch == 'n' || ch == 'N') { 3434199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return "\n"; 3444199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } else { 3454199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return String.valueOf(ch); 3464199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3474199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3484199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa 3494199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa @Override 3504199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa protected Set<String> getKnownPropertyNameSet() { 3514199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa return VCardParser_V30.sKnownPropertyNameSet; 3524199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa } 3534199c54c527330ac01699b176e7bca186a3aa3a4Daisuke Miyakawa} 354