VCardSourceDetector.java revision 4199c54c527330ac01699b176e7bca186a3aa3a4
1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package com.android.vcard; 17 18import android.text.TextUtils; 19 20import java.util.Arrays; 21import java.util.HashSet; 22import java.util.List; 23import java.util.Set; 24 25/** 26 * <p> 27 * The class which tries to detects the source of a vCard file from its contents. 28 * </p> 29 * <p> 30 * The specification of vCard (including both 2.1 and 3.0) is not so strict as to 31 * guess its format just by reading beginning few lines (usually we can, but in 32 * some most pessimistic case, we cannot until at almost the end of the file). 33 * Also we cannot store all vCard entries in memory, while there's no specification 34 * how big the vCard entry would become after the parse. 35 * </p> 36 * <p> 37 * This class is usually used for the "first scan", in which we can understand which vCard 38 * version is used (and how many entries exist in a file). 39 * </p> 40 */ 41public class VCardSourceDetector implements VCardInterpreter { 42 private static Set<String> APPLE_SIGNS = new HashSet<String>(Arrays.asList( 43 "X-PHONETIC-FIRST-NAME", "X-PHONETIC-MIDDLE-NAME", "X-PHONETIC-LAST-NAME", 44 "X-ABADR", "X-ABUID")); 45 46 private static Set<String> JAPANESE_MOBILE_PHONE_SIGNS = new HashSet<String>(Arrays.asList( 47 "X-GNO", "X-GN", "X-REDUCTION")); 48 49 private static Set<String> WINDOWS_MOBILE_PHONE_SIGNS = new HashSet<String>(Arrays.asList( 50 "X-MICROSOFT-ASST_TEL", "X-MICROSOFT-ASSISTANT", "X-MICROSOFT-OFFICELOC")); 51 52 // Note: these signes appears before the signs of the other type (e.g. "X-GN"). 53 // In other words, Japanese FOMA mobile phones are detected as FOMA, not JAPANESE_MOBILE_PHONES. 54 private static Set<String> FOMA_SIGNS = new HashSet<String>(Arrays.asList( 55 "X-SD-VERN", "X-SD-FORMAT_VER", "X-SD-CATEGORIES", "X-SD-CLASS", "X-SD-DCREATED", 56 "X-SD-DESCRIPTION")); 57 private static String TYPE_FOMA_CHARSET_SIGN = "X-SD-CHAR_CODE"; 58 59 60 // TODO: Should replace this with types in VCardConfig 61 private static final int PARSE_TYPE_UNKNOWN = 0; 62 // For Apple's software, which does not mean this type is effective for all its products. 63 // We confirmed they usually use UTF-8, but not sure about vCard type. 64 private static final int PARSE_TYPE_APPLE = 1; 65 // For Japanese mobile phones, which are usually using Shift_JIS as a charset. 66 private static final int PARSE_TYPE_MOBILE_PHONE_JP = 2; 67 // For some of mobile phones released from DoCoMo, which use nested vCard. 68 private static final int PARSE_TYPE_DOCOMO_TORELATE_NEST = 3; 69 // For Japanese Windows Mobel phones. It's version is supposed to be 6.5. 70 private static final int PARSE_TYPE_WINDOWS_MOBILE_V65_JP = 4; 71 72 private int mParseType = 0; // Not sure. 73 74 // Some mobile phones (like FOMA) tells us the charset of the data. 75 private boolean mNeedParseSpecifiedCharset; 76 private String mSpecifiedCharset; 77 78 public void start() { 79 } 80 81 public void end() { 82 } 83 84 public void startEntry() { 85 } 86 87 public void startProperty() { 88 mNeedParseSpecifiedCharset = false; 89 } 90 91 public void endProperty() { 92 } 93 94 public void endEntry() { 95 } 96 97 public void propertyGroup(String group) { 98 } 99 100 public void propertyName(String name) { 101 if (name.equalsIgnoreCase(TYPE_FOMA_CHARSET_SIGN)) { 102 mParseType = PARSE_TYPE_DOCOMO_TORELATE_NEST; 103 // Probably Shift_JIS is used, but we should double confirm. 104 mNeedParseSpecifiedCharset = true; 105 return; 106 } 107 if (mParseType != PARSE_TYPE_UNKNOWN) { 108 return; 109 } 110 if (WINDOWS_MOBILE_PHONE_SIGNS.contains(name)) { 111 mParseType = PARSE_TYPE_WINDOWS_MOBILE_V65_JP; 112 } else if (FOMA_SIGNS.contains(name)) { 113 mParseType = PARSE_TYPE_DOCOMO_TORELATE_NEST; 114 } else if (JAPANESE_MOBILE_PHONE_SIGNS.contains(name)) { 115 mParseType = PARSE_TYPE_MOBILE_PHONE_JP; 116 } else if (APPLE_SIGNS.contains(name)) { 117 mParseType = PARSE_TYPE_APPLE; 118 } 119 } 120 121 public void propertyParamType(String type) { 122 } 123 124 public void propertyParamValue(String value) { 125 } 126 127 public void propertyValues(List<String> values) { 128 if (mNeedParseSpecifiedCharset && values.size() > 0) { 129 mSpecifiedCharset = values.get(0); 130 } 131 } 132 133 /** 134 * @return The available type can be used with vCard parser. You probably need to 135 * use {{@link #getEstimatedCharset()} to understand the charset to be used. 136 */ 137 public int getEstimatedType() { 138 switch (mParseType) { 139 case PARSE_TYPE_DOCOMO_TORELATE_NEST: 140 return VCardConfig.VCARD_TYPE_DOCOMO | VCardConfig.FLAG_TORELATE_NEST; 141 case PARSE_TYPE_MOBILE_PHONE_JP: 142 return VCardConfig.VCARD_TYPE_V21_JAPANESE_MOBILE; 143 case PARSE_TYPE_APPLE: 144 case PARSE_TYPE_WINDOWS_MOBILE_V65_JP: 145 default: 146 return VCardConfig.VCARD_TYPE_UNKNOWN; 147 } 148 } 149 150 /** 151 * <p> 152 * Returns charset String guessed from the source's properties. 153 * This method must be called after parsing target file(s). 154 * </p> 155 * @return Charset String. Null is returned if guessing the source fails. 156 */ 157 public String getEstimatedCharset() { 158 if (TextUtils.isEmpty(mSpecifiedCharset)) { 159 return mSpecifiedCharset; 160 } 161 switch (mParseType) { 162 case PARSE_TYPE_WINDOWS_MOBILE_V65_JP: 163 case PARSE_TYPE_DOCOMO_TORELATE_NEST: 164 case PARSE_TYPE_MOBILE_PHONE_JP: 165 return "SHIFT_JIS"; 166 case PARSE_TYPE_APPLE: 167 return "UTF-8"; 168 default: 169 return null; 170 } 171 } 172} 173