Merge change I11526e6c into eclair-mr2

* changes:
  Clean up codes and remove/modify stale codes/comments.
This commit is contained in:
Android (Google) Code Review
2009-11-17 01:02:46 -08:00
16 changed files with 387 additions and 391 deletions

View File

@@ -89,7 +89,7 @@ public class VCardBuilder {
private final boolean mIsJapaneseMobilePhone;
private final boolean mOnlyOneNoteFieldIsAvailable;
private final boolean mIsDoCoMo;
private final boolean mUsesQuotedPrintable;
private final boolean mShouldUseQuotedPrintable;
private final boolean mUsesAndroidProperty;
private final boolean mUsesDefactProperty;
private final boolean mUsesUtf8;
@@ -110,7 +110,7 @@ public class VCardBuilder {
mVCardType = vcardType;
mIsV30 = VCardConfig.isV30(vcardType);
mUsesQuotedPrintable = VCardConfig.usesQuotedPrintable(vcardType);
mShouldUseQuotedPrintable = VCardConfig.shouldUseQuotedPrintable(vcardType);
mIsDoCoMo = VCardConfig.isDoCoMo(vcardType);
mIsJapaneseMobilePhone = VCardConfig.needsToConvertPhoneticString(vcardType);
mOnlyOneNoteFieldIsAvailable = VCardConfig.onlyOneNoteFieldIsAvailable(vcardType);
@@ -529,7 +529,7 @@ public class VCardBuilder {
if (mUsesDefactProperty) {
if (!TextUtils.isEmpty(phoneticGivenName)) {
final boolean reallyUseQuotedPrintable =
(mUsesQuotedPrintable &&
(mShouldUseQuotedPrintable &&
!VCardUtils.containsOnlyNonCrLfPrintableAscii(phoneticGivenName));
final String encodedPhoneticGivenName;
if (reallyUseQuotedPrintable) {
@@ -552,7 +552,7 @@ public class VCardBuilder {
}
if (!TextUtils.isEmpty(phoneticMiddleName)) {
final boolean reallyUseQuotedPrintable =
(mUsesQuotedPrintable &&
(mShouldUseQuotedPrintable &&
!VCardUtils.containsOnlyNonCrLfPrintableAscii(phoneticMiddleName));
final String encodedPhoneticMiddleName;
if (reallyUseQuotedPrintable) {
@@ -575,7 +575,7 @@ public class VCardBuilder {
}
if (!TextUtils.isEmpty(phoneticFamilyName)) {
final boolean reallyUseQuotedPrintable =
(mUsesQuotedPrintable &&
(mShouldUseQuotedPrintable &&
!VCardUtils.containsOnlyNonCrLfPrintableAscii(phoneticFamilyName));
final String encodedPhoneticFamilyName;
if (reallyUseQuotedPrintable) {
@@ -846,7 +846,7 @@ public class VCardBuilder {
if (!appendCharset && !VCardUtils.containsOnlyPrintableAscii(data)) {
appendCharset = true;
}
if (mUsesQuotedPrintable &&
if (mShouldUseQuotedPrintable &&
!VCardUtils.containsOnlyNonCrLfPrintableAscii(data)) {
reallyUseQuotedPrintable = true;
break;
@@ -1017,13 +1017,13 @@ public class VCardBuilder {
final String orgline = orgBuilder.toString();
appendLine(VCardConstants.PROPERTY_ORG, orgline,
!VCardUtils.containsOnlyPrintableAscii(orgline),
(mUsesQuotedPrintable &&
(mShouldUseQuotedPrintable &&
!VCardUtils.containsOnlyNonCrLfPrintableAscii(orgline)));
if (!TextUtils.isEmpty(title)) {
appendLine(VCardConstants.PROPERTY_TITLE, title,
!VCardUtils.containsOnlyPrintableAscii(title),
(mUsesQuotedPrintable &&
(mShouldUseQuotedPrintable &&
!VCardUtils.containsOnlyNonCrLfPrintableAscii(title)));
}
}
@@ -1094,7 +1094,7 @@ public class VCardBuilder {
final boolean shouldAppendCharsetInfo =
!VCardUtils.containsOnlyPrintableAscii(noteStr);
final boolean reallyUseQuotedPrintable =
(mUsesQuotedPrintable &&
(mShouldUseQuotedPrintable &&
!VCardUtils.containsOnlyNonCrLfPrintableAscii(noteStr));
appendLine(VCardConstants.PROPERTY_NOTE, noteStr,
shouldAppendCharsetInfo, reallyUseQuotedPrintable);
@@ -1105,7 +1105,7 @@ public class VCardBuilder {
final boolean shouldAppendCharsetInfo =
!VCardUtils.containsOnlyPrintableAscii(noteStr);
final boolean reallyUseQuotedPrintable =
(mUsesQuotedPrintable &&
(mShouldUseQuotedPrintable &&
!VCardUtils.containsOnlyNonCrLfPrintableAscii(noteStr));
appendLine(VCardConstants.PROPERTY_NOTE, noteStr,
shouldAppendCharsetInfo, reallyUseQuotedPrintable);
@@ -1541,9 +1541,10 @@ public class VCardBuilder {
public void appendLineWithCharsetAndQPDetection(final String propertyName,
final List<String> parameterList, final String rawValue) {
final boolean needCharset =
(mUsesQuotedPrintable && !VCardUtils.containsOnlyPrintableAscii(rawValue));
!VCardUtils.containsOnlyPrintableAscii(rawValue);
final boolean reallyUseQuotedPrintable =
!VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValue);
(mShouldUseQuotedPrintable &&
!VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValue));
appendLine(propertyName, parameterList,
rawValue, needCharset, reallyUseQuotedPrintable);
}
@@ -1553,7 +1554,7 @@ public class VCardBuilder {
boolean needCharset = false;
boolean reallyUseQuotedPrintable = false;
for (String rawValue : rawValueList) {
if (!needCharset && mUsesQuotedPrintable &&
if (!needCharset && mShouldUseQuotedPrintable &&
!VCardUtils.containsOnlyPrintableAscii(rawValue)) {
needCharset = true;
}

View File

@@ -27,10 +27,7 @@ import java.util.Set;
* but in VCardUtils.
*/
public class VCardConfig {
private static final String LOG_TAG = "vcard.VCardConfig";
// TODO: may be better to make the instance of this available and stop using static methods and
// one integer.
private static final String LOG_TAG = "VCardConfig";
/* package */ static final int LOG_LEVEL_NONE = 0;
/* package */ static final int LOG_LEVEL_PERFORMANCE_MEASUREMENT = 0x1;
@@ -44,9 +41,6 @@ public class VCardConfig {
// decode the unicode to the original charset. If not, this setting will cause some bug.
public static final String DEFAULT_CHARSET = "iso-8859-1";
// TODO: make the other codes use this flag
public static final boolean IGNORE_CASE_EXCEPT_VALUE = true;
public static final int FLAG_V21 = 0;
public static final int FLAG_V30 = 1;
@@ -319,7 +313,7 @@ public class VCardConfig {
FLAG_CONVERT_PHONETIC_NAME_STRINGS |
FLAG_REFRAIN_QP_TO_PRIMARY_PROPERTIES);
public static final String VCARD_TYPE_V21_JAPANESE_MOBILE_STR = "v21_japanese_mobile";
/* package */ static final String VCARD_TYPE_V21_JAPANESE_MOBILE_STR = "v21_japanese_mobile";
/**
* <P>
@@ -334,7 +328,7 @@ public class VCardConfig {
public static final int VCARD_TYPE_DOCOMO =
(VCARD_TYPE_V21_JAPANESE_MOBILE | FLAG_DOCOMO);
private static final String VCARD_TYPE_DOCOMO_STR = "docomo";
/* package */ static final String VCARD_TYPE_DOCOMO_STR = "docomo";
public static int VCARD_TYPE_DEFAULT = VCARD_TYPE_V21_GENERIC_UTF8;
@@ -369,7 +363,6 @@ public class VCardConfig {
if (sVCardTypeMap.containsKey(loweredKey)) {
return sVCardTypeMap.get(loweredKey);
} else {
// XXX: should return the value indicating the input is invalid?
Log.e(LOG_TAG, "Unknown vCard type String: \"" + vcardTypeString + "\"");
return VCARD_TYPE_DEFAULT;
}
@@ -379,7 +372,7 @@ public class VCardConfig {
return ((vcardType & FLAG_V30) != 0);
}
public static boolean usesQuotedPrintable(final int vcardType) {
public static boolean shouldUseQuotedPrintable(final int vcardType) {
return !isV30(vcardType);
}
@@ -408,7 +401,7 @@ public class VCardConfig {
}
public static boolean refrainsQPToPrimaryProperties(final int vcardType) {
return (!usesQuotedPrintable(vcardType) ||
return (!shouldUseQuotedPrintable(vcardType) ||
((vcardType & FLAG_REFRAIN_QP_TO_PRIMARY_PROPERTIES) != 0));
}

View File

@@ -46,6 +46,7 @@ import android.util.Log;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -57,11 +58,11 @@ import java.util.Map;
public class VCardEntry {
private static final String LOG_TAG = "VCardEntry";
private final static int DEFAULT_ORGANIZATION_TYPE = Organization.TYPE_WORK;
private static final String ACCOUNT_TYPE_GOOGLE = "com.google";
private static final String GOOGLE_MY_CONTACTS_GROUP = "System Group: My Contacts";
// Key: the name shown in VCard. e.g. "X-AIM", "X-ICQ"
// Value: the result of {@link Contacts.ContactMethods#encodePredefinedImProtocol}
private static final Map<String, Integer> sImMap = new HashMap<String, Integer>();
static {
@@ -107,9 +108,6 @@ public class VCardEntry {
}
}
/**
* @hide only for testing
*/
static public class EmailData {
public final int type;
public final String data;
@@ -154,17 +152,12 @@ public class VCardEntry {
public final String region;
public final String postalCode;
public final String country;
public final int type;
// Used only when type variable is TYPE_CUSTOM.
public final String label;
// isPrimary is changable only when there's no appropriate one existing in
// the original VCard.
public boolean isPrimary;
public PostalData(int type, List<String> propValueList,
String label, boolean isPrimary) {
public PostalData(final int type, final List<String> propValueList,
final String label, boolean isPrimary) {
this.type = type;
dataArray = new String[ADDR_MAX_DATA_SIZE];
@@ -173,9 +166,9 @@ public class VCardEntry {
size = ADDR_MAX_DATA_SIZE;
}
// adr-value = 0*6(text-value ";") text-value
// ; PO Box, Extended Address, Street, Locality, Region, Postal
// ; Code, Country Name
// adr-value = 0*6(text-value ";") text-value
// ; PO Box, Extended Address, Street, Locality, Region, Postal
// ; Code, Country Name
//
// Use Iterator assuming List may be LinkedList, though actually it is
// always ArrayList in the current implementation.
@@ -197,7 +190,6 @@ public class VCardEntry {
this.region = dataArray[4];
this.postalCode = dataArray[5];
this.country = dataArray[6];
this.label = label;
this.isPrimary = isPrimary;
}
@@ -207,15 +199,15 @@ public class VCardEntry {
if (!(obj instanceof PostalData)) {
return false;
}
PostalData postalData = (PostalData)obj;
final PostalData postalData = (PostalData)obj;
return (Arrays.equals(dataArray, postalData.dataArray) &&
(type == postalData.type &&
(type == StructuredPostal.TYPE_CUSTOM ?
(label == postalData.label) : true)) &&
(isPrimary == postalData.isPrimary));
}
public String getFormattedAddress(int vcardType) {
public String getFormattedAddress(final int vcardType) {
StringBuilder builder = new StringBuilder();
boolean empty = true;
if (VCardConfig.isJapaneseDevice(vcardType)) {
@@ -225,9 +217,10 @@ public class VCardEntry {
if (!TextUtils.isEmpty(addressPart)) {
if (!empty) {
builder.append(' ');
} else {
empty = false;
}
builder.append(addressPart);
empty = false;
}
}
} else {
@@ -236,9 +229,10 @@ public class VCardEntry {
if (!TextUtils.isEmpty(addressPart)) {
if (!empty) {
builder.append(' ');
} else {
empty = false;
}
builder.append(addressPart);
empty = false;
}
}
}
@@ -252,17 +246,16 @@ public class VCardEntry {
type, label, isPrimary);
}
}
static public class OrganizationData {
public final int type;
// non-final is Intended: we may change the values since this info is separated into
// non-final is Intentional: we may change the values since this info is separated into
// two parts in vCard: "ORG" + "TITLE".
public String companyName;
public String departmentName;
public String titleName;
// isPrimary is changable only when there's no appropriate one existing in
// the original VCard.
public boolean isPrimary;
public OrganizationData(int type,
String companyName,
String departmentName,
@@ -302,16 +295,16 @@ public class VCardEntry {
public final int type;
public final String data;
public final boolean isPrimary;
public ImData(int protocol, String customProtocol, int type,
String data, boolean isPrimary) {
public ImData(final int protocol, final String customProtocol, final int type,
final String data, final boolean isPrimary) {
this.protocol = protocol;
this.customProtocol = customProtocol;
this.type = type;
this.data = data;
this.isPrimary = isPrimary;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ImData)) {
@@ -324,7 +317,7 @@ public class VCardEntry {
&& (data != null ? data.equals(imData.data) : (imData.data == null))
&& isPrimary == imData.isPrimary);
}
@Override
public String toString() {
return String.format(
@@ -333,7 +326,7 @@ public class VCardEntry {
}
}
static public class PhotoData {
public static class PhotoData {
public static final String FORMAT_FLASH = "SWF";
public final int type;
public final String formatName; // used when type is not defined in ContactsContract.
@@ -367,13 +360,13 @@ public class VCardEntry {
}
}
static /* package */ class Property {
/* package */ static class Property {
private String mPropertyName;
private Map<String, Collection<String>> mParameterMap =
new HashMap<String, Collection<String>>();
private List<String> mPropertyValueList = new ArrayList<String>();
private byte[] mPropertyBytes;
public void setPropertyName(final String propertyName) {
mPropertyName = propertyName;
}
@@ -464,18 +457,12 @@ public class VCardEntry {
mAccount = account;
}
/**
* Add a phone info to phoneList.
* @param data phone number
* @param type type col of content://contacts/phones
* @param label lable col of content://contacts/phones
*/
private void addPhone(int type, String data, String label, boolean isPrimary){
private void addPhone(int type, String data, String label, boolean isPrimary) {
if (mPhoneList == null) {
mPhoneList = new ArrayList<PhoneData>();
}
StringBuilder builder = new StringBuilder();
String trimed = data.trim();
final StringBuilder builder = new StringBuilder();
final String trimed = data.trim();
final String formattedNumber;
if (type == Phone.TYPE_PAGER) {
formattedNumber = trimed;
@@ -532,13 +519,15 @@ public class VCardEntry {
departmentName, titleName, isPrimary));
}
private static final List<String> sEmptyList = new ArrayList<String>(0);
private static final List<String> sEmptyList =
Collections.unmodifiableList(new ArrayList<String>(0));
/**
* Set "ORG" related values to the appropriate data. If there's more than one
* OrganizationData objects, this input data are attached to the last one which does not
* have valid values (not including empty but only null). If there's no
* OrganizationData object, a new OrganizationData is created, whose title is set to null.
* {@link OrganizationData} objects, this input data are attached to the last one which
* does not have valid values (not including empty but only null). If there's no
* {@link OrganizationData} object, a new {@link OrganizationData} is created,
* whose title is set to null.
*/
private void handleOrgValue(final int type, List<String> orgList, boolean isPrimary) {
if (orgList == null) {
@@ -596,8 +585,6 @@ public class VCardEntry {
addNewOrganization(type, companyName, departmentName, null, isPrimary);
}
private final static int DEFAULT_ORGANIZATION_TYPE = Organization.TYPE_WORK;
/**
* Set "title" value to the appropriate data. If there's more than one
* OrganizationData objects, this input is attached to the last one which does not
@@ -658,25 +645,20 @@ public class VCardEntry {
}
switch (size) {
// fallthrough
case 5:
mSuffix = elems.get(4);
case 4:
mPrefix = elems.get(3);
case 3:
mMiddleName = elems.get(2);
case 2:
mGivenName = elems.get(1);
default:
mFamilyName = elems.get(0);
// fallthrough
case 5: mSuffix = elems.get(4);
case 4: mPrefix = elems.get(3);
case 3: mMiddleName = elems.get(2);
case 2: mGivenName = elems.get(1);
default: mFamilyName = elems.get(0);
}
}
/**
* Some Japanese mobile phones use this field for phonetic name,
* since vCard 2.1 does not have "SORT-STRING" type.
* Also, in some cases, the field has some ';'s in it.
* Assume the ';' means the same meaning in N property
* Note: Some Japanese mobile phones use this field for phonetic name,
* since vCard 2.1 does not have "SORT-STRING" type.
* Also, in some cases, the field has some ';'s in it.
* Assume the ';' means the same meaning in N property
*/
@SuppressWarnings("fallthrough")
private void handlePhoneticNameFromSound(List<String> elems) {
@@ -728,18 +710,15 @@ public class VCardEntry {
}
switch (size) {
// fallthrough
case 3:
mPhoneticMiddleName = elems.get(2);
case 2:
mPhoneticGivenName = elems.get(1);
default:
mPhoneticFamilyName = elems.get(0);
// fallthrough
case 3: mPhoneticMiddleName = elems.get(2);
case 2: mPhoneticGivenName = elems.get(1);
default: mPhoneticFamilyName = elems.get(0);
}
}
public void addProperty(Property property) {
String propName = property.mPropertyName;
public void addProperty(final Property property) {
final String propName = property.mPropertyName;
final Map<String, Collection<String>> paramMap = property.mParameterMap;
final List<String> propValueList = property.mPropertyValueList;
byte[] propBytes = property.mPropertyBytes;

View File

@@ -19,26 +19,29 @@ import android.content.ContentResolver;
import android.util.Log;
/**
* EntryHandler implementation which commits the entry to ContentResolver.
*
* Note:
* <P>
* {@link VCardEntryHandler} implementation which commits the entry to ContentResolver.
* </P>
* <P>
* Note:<BR />
* Each vCard may contain big photo images encoded by BASE64,
* If we store all vCard entries in memory, OutOfMemoryError may be thrown.
* Thus, this class push each VCard entry into ContentResolver immediately.
* </P>
*/
public class VCardEntryCommitter implements VCardEntryHandler {
public static String LOG_TAG = "vcard.EntryComitter";
public static String LOG_TAG = "VCardEntryComitter";
private ContentResolver mContentResolver;
private final ContentResolver mContentResolver;
private long mTimeToCommit;
public VCardEntryCommitter(ContentResolver resolver) {
mContentResolver = resolver;
}
public void onStart() {
}
public void onEnd() {
if (VCardConfig.showPerformanceLog()) {
Log.d(LOG_TAG, String.format("time to commit entries: %d ms", mTimeToCommit));

View File

@@ -32,69 +32,60 @@ import java.util.List;
public class VCardEntryConstructor implements VCardInterpreter {
private static String LOG_TAG = "VCardEntryConstructor";
/**
* If there's no other information available, this class uses this charset for encoding
* byte arrays.
* byte arrays to String.
*/
static public String TARGET_CHARSET = "UTF-8";
/* package */ static final String DEFAULT_CHARSET_FOR_DECODED_BYTES = "UTF-8";
private VCardEntry.Property mCurrentProperty = new VCardEntry.Property();
private VCardEntry mCurrentContactStruct;
private String mParamType;
/**
* The charset using which VParser parses the text.
* The charset using which {@link VCardInterpreter} parses the text.
*/
private String mSourceCharset;
private String mInputCharset;
/**
* The charset with which byte array is encoded to String.
*/
private String mTargetCharset;
private boolean mStrictLineBreakParsing;
final private String mCharsetForDecodedBytes;
final private boolean mStrictLineBreakParsing;
final private int mVCardType;
final private Account mAccount;
// Just for testing.
/** For measuring performance. */
private long mTimePushIntoContentResolver;
private List<VCardEntryHandler> mEntryHandlers = new ArrayList<VCardEntryHandler>();
final private List<VCardEntryHandler> mEntryHandlers = new ArrayList<VCardEntryHandler>();
public VCardEntryConstructor() {
this(null, null, false, VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8, null);
}
public VCardEntryConstructor(int vcardType) {
public VCardEntryConstructor(final int vcardType) {
this(null, null, false, vcardType, null);
}
/**
* @hide
*/
public VCardEntryConstructor(String charset,
boolean strictLineBreakParsing, int vcardType, Account account) {
public VCardEntryConstructor(final String charset, final boolean strictLineBreakParsing,
final int vcardType, final Account account) {
this(null, charset, strictLineBreakParsing, vcardType, account);
}
/**
* @hide
*/
public VCardEntryConstructor(String sourceCharset,
String targetCharset,
boolean strictLineBreakParsing,
int vcardType,
Account account) {
if (sourceCharset != null) {
mSourceCharset = sourceCharset;
public VCardEntryConstructor(final String inputCharset, final String charsetForDetodedBytes,
final boolean strictLineBreakParsing, final int vcardType,
final Account account) {
if (inputCharset != null) {
mInputCharset = inputCharset;
} else {
mSourceCharset = VCardConfig.DEFAULT_CHARSET;
mInputCharset = VCardConfig.DEFAULT_CHARSET;
}
if (targetCharset != null) {
mTargetCharset = targetCharset;
if (charsetForDetodedBytes != null) {
mCharsetForDecodedBytes = charsetForDetodedBytes;
} else {
mTargetCharset = TARGET_CHARSET;
mCharsetForDecodedBytes = DEFAULT_CHARSET_FOR_DECODED_BYTES;
}
mStrictLineBreakParsing = strictLineBreakParsing;
mVCardType = vcardType;
@@ -118,11 +109,7 @@ public class VCardEntryConstructor implements VCardInterpreter {
}
/**
* Called when the parse failed between startRecord() and endRecord().
* Currently it happens only when the vCard format is 3.0.
* (VCardVersionException is thrown by VCardParser_V21 and this object is reused by
* VCardParser_V30. At that time, startRecord() is called twice before endRecord() is called.)
* TODO: Should this be in VCardBuilder interface?
* Called when the parse failed between {@link #startEntry()} and {@link #endEntry()}.
*/
public void clear() {
mCurrentContactStruct = null;
@@ -132,22 +119,14 @@ public class VCardEntryConstructor implements VCardInterpreter {
/**
* Assume that VCard is not nested. In other words, this code does not accept
*/
public void startRecord(String type) {
// TODO: add the method clear() instead of using null for reducing GC?
public void startEntry() {
if (mCurrentContactStruct != null) {
// This means startRecord() is called inside startRecord() - endRecord() block.
// TODO: should throw some Exception
Log.e(LOG_TAG, "Nested VCard code is not supported now.");
}
if (!type.equalsIgnoreCase("VCARD")) {
// TODO: add test case for this
Log.e(LOG_TAG, "This is not VCARD!");
}
mCurrentContactStruct = new VCardEntry(mVCardType, mAccount);
}
public void endRecord() {
public void endEntry() {
mCurrentContactStruct.consolidateFields();
for (VCardEntryHandler entryHandler : mEntryHandlers) {
entryHandler.onEntryCreated(mCurrentContactStruct);
@@ -168,9 +147,8 @@ public class VCardEntryConstructor implements VCardInterpreter {
}
public void propertyGroup(String group) {
// ContactStruct does not support Group.
}
public void propertyParamType(String type) {
if (mParamType != null) {
Log.e(LOG_TAG, "propertyParamType() is called more than once " +
@@ -187,26 +165,26 @@ public class VCardEntryConstructor implements VCardInterpreter {
mCurrentProperty.addParameter(mParamType, value);
mParamType = null;
}
private String encodeString(String originalString, String targetCharset) {
if (mSourceCharset.equalsIgnoreCase(targetCharset)) {
private String encodeString(String originalString, String charsetForDecodedBytes) {
if (mInputCharset.equalsIgnoreCase(charsetForDecodedBytes)) {
return originalString;
}
Charset charset = Charset.forName(mSourceCharset);
Charset charset = Charset.forName(mInputCharset);
ByteBuffer byteBuffer = charset.encode(originalString);
// byteBuffer.array() "may" return byte array which is larger than
// byteBuffer.remaining(). Here, we keep on the safe side.
byte[] bytes = new byte[byteBuffer.remaining()];
byteBuffer.get(bytes);
try {
return new String(bytes, targetCharset);
return new String(bytes, charsetForDecodedBytes);
} catch (UnsupportedEncodingException e) {
Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
Log.e(LOG_TAG, "Failed to encode: charset=" + charsetForDecodedBytes);
return null;
}
}
private String handleOneValue(String value, String targetCharset, String encoding) {
private String handleOneValue(String value, String charsetForDecodedBytes, String encoding) {
if (encoding != null) {
if (encoding.equals("BASE64") || encoding.equals("B")) {
mCurrentProperty.setPropertyBytes(Base64.decodeBase64(value.getBytes()));
@@ -272,9 +250,9 @@ public class VCardEntryConstructor implements VCardInterpreter {
}
byte[] bytes;
try {
bytes = builder.toString().getBytes(mSourceCharset);
bytes = builder.toString().getBytes(mInputCharset);
} catch (UnsupportedEncodingException e1) {
Log.e(LOG_TAG, "Failed to encode: charset=" + mSourceCharset);
Log.e(LOG_TAG, "Failed to encode: charset=" + mInputCharset);
bytes = builder.toString().getBytes();
}
@@ -286,38 +264,37 @@ public class VCardEntryConstructor implements VCardInterpreter {
}
try {
return new String(bytes, targetCharset);
return new String(bytes, charsetForDecodedBytes);
} catch (UnsupportedEncodingException e) {
Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
Log.e(LOG_TAG, "Failed to encode: charset=" + charsetForDecodedBytes);
return new String(bytes);
}
}
// Unknown encoding. Fall back to default.
}
return encodeString(value, targetCharset);
return encodeString(value, charsetForDecodedBytes);
}
public void propertyValues(List<String> values) {
if (values == null || values.size() == 0) {
if (values == null || values.isEmpty()) {
return;
}
final Collection<String> charsetCollection = mCurrentProperty.getParameters("CHARSET");
String charset =
final String charset =
((charsetCollection != null) ? charsetCollection.iterator().next() : null);
String targetCharset = CharsetUtils.nameForDefaultVendor(charset);
final Collection<String> encodingCollection = mCurrentProperty.getParameters("ENCODING");
String encoding =
final String encoding =
((encodingCollection != null) ? encodingCollection.iterator().next() : null);
if (targetCharset == null || targetCharset.length() == 0) {
targetCharset = mTargetCharset;
String charsetForDecodedBytes = CharsetUtils.nameForDefaultVendor(charset);
if (charsetForDecodedBytes == null || charsetForDecodedBytes.length() == 0) {
charsetForDecodedBytes = mCharsetForDecodedBytes;
}
for (String value : values) {
for (final String value : values) {
mCurrentProperty.addToPropertyValueList(
handleOneValue(value, targetCharset, encoding));
handleOneValue(value, charsetForDecodedBytes, encoding));
}
}

View File

@@ -17,6 +17,9 @@ package android.pim.vcard;
import java.util.List;
/**
* The class which just counts the number of vCard entries in the specified input.
*/
public class VCardEntryCounter implements VCardInterpreter {
private int mCount;
@@ -30,10 +33,10 @@ public class VCardEntryCounter implements VCardInterpreter {
public void end() {
}
public void startRecord(String type) {
public void startEntry() {
}
public void endRecord() {
public void endEntry() {
mCount++;
}
@@ -57,4 +60,4 @@ public class VCardEntryCounter implements VCardInterpreter {
public void propertyValues(List<String> values) {
}
}
}

View File

@@ -15,6 +15,10 @@
*/
package android.pim.vcard;
/**
* The interface called by {@link VCardEntryConstructor}. Useful when you don't want to
* handle detailed information as what {@link VCardParser} provides via {@link VCardInterpreter}.
*/
public interface VCardEntryHandler {
/**
* Called when the parsing started.

View File

@@ -17,48 +17,86 @@ package android.pim.vcard;
import java.util.List;
/**
* <P>
* The interface which should be implemented by the classes which have to analyze each
* vCard entry more minutely than {@link VCardEntry} class analysis.
* </P>
* <P>
* Here, there are several terms specific to vCard (and this library).
* </P>
* <P>
* The term "entry" is one vCard representation in the input, which should start with "BEGIN:VCARD"
* and end with "END:VCARD".
* </P>
* <P>
* The term "property" is one line in vCard entry, which consists of "group", "property name",
* "parameter(param) names and values", and "property values".
* </P>
* <P>
* e.g. group1.propName;paramName1=paramValue1;paramName2=paramValue2;propertyValue1;propertyValue2...
* </P>
*/
public interface VCardInterpreter {
/**
* Called when vCard interpretation started.
*/
void start();
/**
* Called when vCard interpretation finished.
*/
void end();
/**
* BEGIN:VCARD
* Called when parsing one vCard entry started.
* More specifically, this method is called when "BEGIN:VCARD" is read.
*/
void startRecord(String type);
void startEntry();
/** END:VCARD */
void endRecord();
/**
* Called when parsing one vCard entry ended.
* More specifically, this method is called when "END:VCARD" is read.
* Note that {@link #startEntry()} may be called since
* vCard (especially 2.1) allows nested vCard.
*/
void endEntry();
/**
* Called when reading one property started.
*/
void startProperty();
/**
* Called when reading one property ended.
*/
void endProperty();
/**
* @param group
* @param group A group name. This method may be called more than once or may not be
* called at all, depending on how many gruoups are appended to the property.
*/
void propertyGroup(String group);
/**
* @param name
* N <br>
* N
* @param name A property name like "N", "FN", "ADR", etc.
*/
void propertyName(String name);
/**
* @param type
* LANGUAGE \ ENCODING <br>
* ;LANGUage= \ ;ENCODING=
* @param type A parameter name like "ENCODING", "CHARSET", etc.
*/
void propertyParamType(String type);
/**
* @param value
* FR-EN \ GBK <br>
* FR-EN \ GBK
* @param value A parameter value. This method may be called without
* {@link #propertyParamType(String)} being called (when the vCard is vCard 2.1).
*/
void propertyParamValue(String value);
/**
* @param values List of property values. The size of values would be 1 unless
* coressponding property name is "N", "ADR", or "ORG".
*/
void propertyValues(List<String> values);
}

View File

@@ -18,81 +18,84 @@ package android.pim.vcard;
import java.util.Collection;
import java.util.List;
public class VCardInterPreterCollection implements VCardInterpreter {
/**
* The {@link VCardInterpreter} implementation which aggregates more than one
* {@link VCardInterpreter} objects and make a user object treat them as one
* {@link VCardInterpreter} object.
*/
public class VCardInterpreterCollection implements VCardInterpreter {
private final Collection<VCardInterpreter> mInterpreterCollection;
public VCardInterpreterCollection(Collection<VCardInterpreter> interpreterCollection) {
mInterpreterCollection = interpreterCollection;
}
private final Collection<VCardInterpreter> mVCardBuilderCollection;
public VCardInterPreterCollection(Collection<VCardInterpreter> vBuilderCollection) {
mVCardBuilderCollection = vBuilderCollection;
}
public Collection<VCardInterpreter> getCollection() {
return mVCardBuilderCollection;
return mInterpreterCollection;
}
public void start() {
for (VCardInterpreter builder : mVCardBuilderCollection) {
for (VCardInterpreter builder : mInterpreterCollection) {
builder.start();
}
}
public void end() {
for (VCardInterpreter builder : mVCardBuilderCollection) {
for (VCardInterpreter builder : mInterpreterCollection) {
builder.end();
}
}
public void startRecord(String type) {
for (VCardInterpreter builder : mVCardBuilderCollection) {
builder.startRecord(type);
public void startEntry() {
for (VCardInterpreter builder : mInterpreterCollection) {
builder.startEntry();
}
}
public void endRecord() {
for (VCardInterpreter builder : mVCardBuilderCollection) {
builder.endRecord();
public void endEntry() {
for (VCardInterpreter builder : mInterpreterCollection) {
builder.endEntry();
}
}
public void startProperty() {
for (VCardInterpreter builder : mVCardBuilderCollection) {
for (VCardInterpreter builder : mInterpreterCollection) {
builder.startProperty();
}
}
public void endProperty() {
for (VCardInterpreter builder : mVCardBuilderCollection) {
for (VCardInterpreter builder : mInterpreterCollection) {
builder.endProperty();
}
}
public void propertyGroup(String group) {
for (VCardInterpreter builder : mVCardBuilderCollection) {
for (VCardInterpreter builder : mInterpreterCollection) {
builder.propertyGroup(group);
}
}
public void propertyName(String name) {
for (VCardInterpreter builder : mVCardBuilderCollection) {
for (VCardInterpreter builder : mInterpreterCollection) {
builder.propertyName(name);
}
}
public void propertyParamType(String type) {
for (VCardInterpreter builder : mVCardBuilderCollection) {
for (VCardInterpreter builder : mInterpreterCollection) {
builder.propertyParamType(type);
}
}
public void propertyParamValue(String value) {
for (VCardInterpreter builder : mVCardBuilderCollection) {
for (VCardInterpreter builder : mInterpreterCollection) {
builder.propertyParamValue(value);
}
}
public void propertyValues(List<String> values) {
for (VCardInterpreter builder : mVCardBuilderCollection) {
for (VCardInterpreter builder : mInterpreterCollection) {
builder.propertyValues(values);
}
}

View File

@@ -39,43 +39,48 @@ public abstract class VCardParser {
}
/**
* <P>
* Parses the given stream and send the VCard data into VCardBuilderBase object.
*
* </P.
* <P>
* Note that vCard 2.1 specification allows "CHARSET" parameter, and some career sets
* local encoding to it. For example, Japanese phone career uses Shift_JIS, which is
* formally allowed in VCard 2.1, but not recommended in VCard 3.0. In VCard 2.1,
* In some exreme case, some VCard may have different charsets in one VCard (though
* we do not see any device which emits such kind of malicious data)
*
* </P>
* <P>
* In order to avoid "misunderstanding" charset as much as possible, this method
* use "ISO-8859-1" for reading the stream. When charset is specified in some property
* (with "CHARSET=..." parameter), the string is decoded to raw bytes and encoded to
* the charset. This method assumes that "ISO-8859-1" has 1 to 1 mapping in all 8bit
* characters, which is not completely sure. In some cases, this "decoding-encoding"
* scheme may fail. To avoid the case,
*
* We recommend you to use VCardSourceDetector and detect which kind of source the
* </P>
* <P>
* We recommend you to use {@link VCardSourceDetector} and detect which kind of source the
* VCard comes from and explicitly specify a charset using the result.
*
* </P>
*
* @param is The source to parse.
* @param builder The VCardBuilderBase object which used to construct data. If you want to
* include multiple VCardBuilderBase objects in this field, consider using
* {#link VCardBuilderCollection} class.
* @param interepreter A {@link VCardInterpreter} object which used to construct data.
* @return Returns true for success. Otherwise returns false.
* @throws IOException, VCardException
*/
public abstract boolean parse(InputStream is, VCardInterpreter builder)
public abstract boolean parse(InputStream is, VCardInterpreter interepreter)
throws IOException, VCardException;
/**
* <P>
* The method variants which accept charset.
*
* </P>
* <P>
* RFC 2426 "recommends" (not forces) to use UTF-8, so it may be OK to use
* UTF-8 as an encoding when parsing vCard 3.0. But note that some Japanese
* phone uses Shift_JIS as a charset (e.g. W61SH), and another uses
* "CHARSET=SHIFT_JIS", which is explicitly prohibited in vCard 3.0 specification
* (e.g. W53K).
*
* "CHARSET=SHIFT_JIS", which is explicitly prohibited in vCard 3.0 specification (e.g. W53K).
* </P>
*
* @param is The source to parse.
* @param charset Charset to be used.
* @param builder The VCardBuilderBase object.
@@ -87,8 +92,6 @@ public abstract class VCardParser {
/**
* The method variants which tells this object the operation is already canceled.
* XXX: Is this really necessary?
* @hide
*/
public abstract void parse(InputStream is, String charset,
VCardInterpreter builder, boolean canceled)

View File

@@ -31,13 +31,14 @@ import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* This class is used to parse vcard. Please refer to vCard Specification 2.1.
* This class is used to parse vCard. Please refer to vCard Specification 2.1 for more detail.
*/
public class VCardParser_V21 extends VCardParser {
private static final String LOG_TAG = "vcard.VCardParser_V21";
private static final String LOG_TAG = "VCardParser_V21";
/** Store the known-type */
private static final HashSet<String> sKnownTypeSet = new HashSet<String>(
Arrays.asList("DOM", "INTL", "POSTAL", "PARCEL", "HOME", "WORK",
@@ -52,7 +53,7 @@ public class VCardParser_V21 extends VCardParser {
/** Store the known-value */
private static final HashSet<String> sKnownValueSet = new HashSet<String>(
Arrays.asList("INLINE", "URL", "CONTENT-ID", "CID"));
/** Store the property names available in vCard 2.1 */
private static final HashSet<String> sAvailablePropertyNameSetV21 =
new HashSet<String>(Arrays.asList(
@@ -82,7 +83,7 @@ public class VCardParser_V21 extends VCardParser {
protected final String sDefaultEncoding = "8BIT";
// Should not directly read a line from this. Use getLine() instead.
// Should not directly read a line from this object. Use getLine() instead.
protected BufferedReader mReader;
// In some cases, vCard is nested. Currently, we only consider the most interior vCard data.
@@ -91,16 +92,16 @@ public class VCardParser_V21 extends VCardParser {
// In order to reduce warning message as much as possible, we hold the value which made Logger
// emit a warning message.
protected HashSet<String> mUnknownTypeMap = new HashSet<String>();
protected HashSet<String> mUnknownValueMap = new HashSet<String>();
protected Set<String> mUnknownTypeMap = new HashSet<String>();
protected Set<String> mUnknownValueMap = new HashSet<String>();
// It seems Windows Mobile 6.5 uses "AGENT" property with completely wrong usage.
// We should just ignore just one line.
// e.g.
// "AGENT;CHARSET=SHIFT_JIS:some text"
private boolean mIgnoreAgentLine = false;
private boolean mIgnoreInvalidAgentLine = false;
// Just for debugging
// For measuring performance.
private long mTimeTotal;
private long mTimeReadStartRecord;
private long mTimeReadEndRecord;
@@ -114,9 +115,6 @@ public class VCardParser_V21 extends VCardParser {
private long mTimeHandleQuotedPrintable;
private long mTimeHandleBase64;
/**
* Create a new VCard parser.
*/
public VCardParser_V21() {
this(null, PARSER_MODE_DEFAULT);
}
@@ -139,17 +137,18 @@ public class VCardParser_V21 extends VCardParser {
if (type == VCardSourceDetector.TYPE_FOMA) {
mNestCount = 1;
} else if (type == VCardSourceDetector.TYPE_JAPANESE_MOBILE_PHONE) {
mIgnoreAgentLine = true;
mIgnoreInvalidAgentLine = true;
}
}
if (parserMode == PARSER_MODE_SCAN) {
mIgnoreAgentLine = true;
mIgnoreInvalidAgentLine = true;
}
}
/**
* Parse the file at the given position
* Parses the file at the given position.
*
* vcard_file = [wsls] vcard [wsls]
*/
protected void parseVCardFile() throws IOException, VCardException {
@@ -225,11 +224,11 @@ public class VCardParser_V21 extends VCardParser {
}
}
}
/**
* vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF
* items *CRLF
* "END" [ws] ":" [ws] "VCARD"
* vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF
* items *CRLF
* "END" [ws] ":" [ws] "VCARD"
*/
private boolean parseOneVCard(boolean firstReading) throws IOException, VCardException {
boolean allowGarbage = false;
@@ -250,7 +249,7 @@ public class VCardParser_V21 extends VCardParser {
long start;
if (mBuilder != null) {
start = System.currentTimeMillis();
mBuilder.startRecord("VCARD");
mBuilder.startEntry();
mTimeReadStartRecord += System.currentTimeMillis() - start;
}
start = System.currentTimeMillis();
@@ -259,7 +258,7 @@ public class VCardParser_V21 extends VCardParser {
readEndVCard(true, false);
if (mBuilder != null) {
start = System.currentTimeMillis();
mBuilder.endRecord();
mBuilder.endEntry();
mTimeReadEndRecord += System.currentTimeMillis() - start;
}
return true;
@@ -270,8 +269,7 @@ public class VCardParser_V21 extends VCardParser {
* @throws IOException
* @throws VCardException
*/
protected boolean readBeginVCard(boolean allowGarbage)
throws IOException, VCardException {
protected boolean readBeginVCard(boolean allowGarbage) throws IOException, VCardException {
String line;
do {
while (true) {
@@ -286,8 +284,9 @@ public class VCardParser_V21 extends VCardParser {
int length = strArray.length;
// Though vCard 2.1/3.0 specification does not allow lower cases,
// some data may have them, so we allow it (Actually, previous code
// had explicitly allowed "BEGIN:vCard" though there's no example).
// vCard file emitted by some external vCard expoter have such invalid Strings.
// So we allow it.
// e.g. BEGIN:vCard
if (length == 2 &&
strArray[0].trim().equalsIgnoreCase("BEGIN") &&
strArray[1].trim().equalsIgnoreCase("VCARD")) {
@@ -310,7 +309,7 @@ public class VCardParser_V21 extends VCardParser {
/**
* The arguments useCache and allowGarbase are usually true and false accordingly when
* this function is called outside this function itself.
*
*
* @param useCache When true, line is obtained from mPreviousline. Otherwise, getLine()
* is used.
* @param allowGarbage When true, ignore non "END:VCARD" line.
@@ -353,7 +352,6 @@ public class VCardParser_V21 extends VCardParser {
* / item
*/
protected void parseItems() throws IOException, VCardException {
/* items *CRLF item / item */
boolean ended = false;
if (mBuilder != null) {
@@ -399,7 +397,7 @@ public class VCardParser_V21 extends VCardParser {
protected boolean parseItem() throws IOException, VCardException {
mEncoding = sDefaultEncoding;
String line = getNonEmptyLine();
final String line = getNonEmptyLine();
long start = System.currentTimeMillis();
String[] propertyNameAndValue = separateLineAndHandleGroup(line);
@@ -441,23 +439,22 @@ public class VCardParser_V21 extends VCardParser {
return false;
}
throw new VCardException("Unknown property name: \"" +
propertyName + "\"");
throw new VCardException("Unknown property name: \"" + propertyName + "\"");
}
static private final int STATE_GROUP_OR_PROPNAME = 0;
static private final int STATE_PARAMS = 1;
// vCard 3.1 specification allows double-quoted param-value, while vCard 2.1 does not.
// vCard 3.0 specification allows double-quoted param-value, while vCard 2.1 does not.
// This is just for safety.
static private final int STATE_PARAMS_IN_DQUOTE = 2;
protected String[] separateLineAndHandleGroup(String line) throws VCardException {
int length = line.length();
int state = STATE_GROUP_OR_PROPNAME;
int nameIndex = 0;
String[] propertyNameAndValue = new String[2];
final String[] propertyNameAndValue = new String[2];
final int length = line.length();
if (length > 0 && line.charAt(0) == '#') {
throw new VCardInvalidCommentLineException();
}
@@ -465,82 +462,84 @@ public class VCardParser_V21 extends VCardParser {
for (int i = 0; i < length; i++) {
char ch = line.charAt(i);
switch (state) {
case STATE_GROUP_OR_PROPNAME:
if (ch == ':') {
String propertyName = line.substring(nameIndex, i);
if (propertyName.equalsIgnoreCase("END")) {
mPreviousLine = line;
return null;
case STATE_GROUP_OR_PROPNAME: {
if (ch == ':') {
final String propertyName = line.substring(nameIndex, i);
if (propertyName.equalsIgnoreCase("END")) {
mPreviousLine = line;
return null;
}
if (mBuilder != null) {
mBuilder.propertyName(propertyName);
}
propertyNameAndValue[0] = propertyName;
if (i < length - 1) {
propertyNameAndValue[1] = line.substring(i + 1);
} else {
propertyNameAndValue[1] = "";
}
return propertyNameAndValue;
} else if (ch == '.') {
String groupName = line.substring(nameIndex, i);
if (mBuilder != null) {
mBuilder.propertyGroup(groupName);
}
nameIndex = i + 1;
} else if (ch == ';') {
String propertyName = line.substring(nameIndex, i);
if (propertyName.equalsIgnoreCase("END")) {
mPreviousLine = line;
return null;
}
if (mBuilder != null) {
mBuilder.propertyName(propertyName);
}
propertyNameAndValue[0] = propertyName;
nameIndex = i + 1;
state = STATE_PARAMS;
}
if (mBuilder != null) {
mBuilder.propertyName(propertyName);
}
propertyNameAndValue[0] = propertyName;
if (i < length - 1) {
propertyNameAndValue[1] = line.substring(i + 1);
} else {
propertyNameAndValue[1] = "";
}
return propertyNameAndValue;
} else if (ch == '.') {
String groupName = line.substring(nameIndex, i);
if (mBuilder != null) {
mBuilder.propertyGroup(groupName);
}
nameIndex = i + 1;
} else if (ch == ';') {
String propertyName = line.substring(nameIndex, i);
if (propertyName.equalsIgnoreCase("END")) {
mPreviousLine = line;
return null;
}
if (mBuilder != null) {
mBuilder.propertyName(propertyName);
}
propertyNameAndValue[0] = propertyName;
nameIndex = i + 1;
state = STATE_PARAMS;
break;
}
break;
case STATE_PARAMS:
if (ch == '"') {
state = STATE_PARAMS_IN_DQUOTE;
} else if (ch == ';') {
handleParams(line.substring(nameIndex, i));
nameIndex = i + 1;
} else if (ch == ':') {
handleParams(line.substring(nameIndex, i));
if (i < length - 1) {
propertyNameAndValue[1] = line.substring(i + 1);
} else {
propertyNameAndValue[1] = "";
case STATE_PARAMS: {
if (ch == '"') {
state = STATE_PARAMS_IN_DQUOTE;
} else if (ch == ';') {
handleParams(line.substring(nameIndex, i));
nameIndex = i + 1;
} else if (ch == ':') {
handleParams(line.substring(nameIndex, i));
if (i < length - 1) {
propertyNameAndValue[1] = line.substring(i + 1);
} else {
propertyNameAndValue[1] = "";
}
return propertyNameAndValue;
}
return propertyNameAndValue;
break;
}
break;
case STATE_PARAMS_IN_DQUOTE:
if (ch == '"') {
state = STATE_PARAMS;
case STATE_PARAMS_IN_DQUOTE: {
if (ch == '"') {
state = STATE_PARAMS;
}
break;
}
break;
}
}
throw new VCardInvalidLineException("Invalid line: \"" + line + "\"");
}
/**
* params = ";" [ws] paramlist
* paramlist = paramlist [ws] ";" [ws] param
* / param
* param = "TYPE" [ws] "=" [ws] ptypeval
* / "VALUE" [ws] "=" [ws] pvalueval
* / "ENCODING" [ws] "=" [ws] pencodingval
* / "CHARSET" [ws] "=" [ws] charsetval
* / "LANGUAGE" [ws] "=" [ws] langval
* / "X-" word [ws] "=" [ws] word
* / knowntype
* params = ";" [ws] paramlist
* paramlist = paramlist [ws] ";" [ws] param
* / param
* param = "TYPE" [ws] "=" [ws] ptypeval
* / "VALUE" [ws] "=" [ws] pvalueval
* / "ENCODING" [ws] "=" [ws] pencodingval
* / "CHARSET" [ws] "=" [ws] charsetval
* / "LANGUAGE" [ws] "=" [ws] langval
* / "X-" word [ws] "=" [ws] word
* / knowntype
*/
protected void handleParams(String params) throws VCardException {
String[] strArray = params.split("=", 2);
@@ -624,8 +623,8 @@ public class VCardParser_V21 extends VCardParser {
}
/**
* vCard specification only allows us-ascii and iso-8859-xxx (See RFC 1521),
* but some vCard contains other charset, so we allow them.
* vCard 2.1 specification only allows us-ascii and iso-8859-xxx (See RFC 1521),
* but today's vCard often contains other charset, so we allow them.
*/
protected void handleCharset(String charsetval) {
if (mBuilder != null) {
@@ -633,7 +632,7 @@ public class VCardParser_V21 extends VCardParser {
mBuilder.propertyParamValue(charsetval);
}
}
/**
* See also Section 7.1 of RFC 1521
*/
@@ -671,12 +670,12 @@ public class VCardParser_V21 extends VCardParser {
mBuilder.propertyParamValue(paramValue);
}
}
protected void handlePropertyValue(String propertyName, String propertyValue) throws
IOException, VCardException {
protected void handlePropertyValue(String propertyName, String propertyValue)
throws IOException, VCardException {
if (mEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) {
long start = System.currentTimeMillis();
String result = getQuotedPrintable(propertyValue);
final long start = System.currentTimeMillis();
final String result = getQuotedPrintable(propertyValue);
if (mBuilder != null) {
ArrayList<String> v = new ArrayList<String>();
v.add(result);
@@ -685,11 +684,11 @@ public class VCardParser_V21 extends VCardParser {
mTimeHandleQuotedPrintable += System.currentTimeMillis() - start;
} else if (mEncoding.equalsIgnoreCase("BASE64") ||
mEncoding.equalsIgnoreCase("B")) {
long start = System.currentTimeMillis();
final long start = System.currentTimeMillis();
// It is very rare, but some BASE64 data may be so big that
// OutOfMemoryError occurs. To ignore such cases, use try-catch.
try {
String result = getBase64(propertyValue);
final String result = getBase64(propertyValue);
if (mBuilder != null) {
ArrayList<String> v = new ArrayList<String>();
v.add(result);
@@ -709,7 +708,7 @@ public class VCardParser_V21 extends VCardParser {
Log.w(LOG_TAG, "The encoding unsupported by vCard spec: \"" + mEncoding + "\".");
}
long start = System.currentTimeMillis();
final long start = System.currentTimeMillis();
if (mBuilder != null) {
ArrayList<String> v = new ArrayList<String>();
v.add(maybeUnescapeText(propertyValue));
@@ -820,16 +819,15 @@ public class VCardParser_V21 extends VCardParser {
/**
* vCard 2.1 specifies AGENT allows one vcard entry. It is not encoded at all.
*
* item = ...
* / [groups "."] "AGENT"
* [params] ":" vcard CRLF
* vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF
* items *CRLF "END" [ws] ":" [ws] "VCARD"
*
*
* item = ...
* / [groups "."] "AGENT"
* [params] ":" vcard CRLF
* vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF
* items *CRLF "END" [ws] ":" [ws] "VCARD"
*/
protected void handleAgent(final String propertyValue) throws VCardException {
if (mIgnoreAgentLine) {
if (mIgnoreInvalidAgentLine && !propertyValue.toUpperCase().contains("BEGIN:VCARD")) {
return;
} else {
throw new VCardAgentNotSupportedException("AGENT Property is not supported now.");

View File

@@ -23,12 +23,12 @@ import java.util.Arrays;
import java.util.HashSet;
/**
* This class is used to parse vcard3.0. <br>
* Please refer to vCard Specification 3.0 (http://tools.ietf.org/html/rfc2426)
* The class used to parse vCard 3.0.
* Please refer to vCard Specification 3.0 (http://tools.ietf.org/html/rfc2426).
*/
public class VCardParser_V30 extends VCardParser_V21 {
private static final String LOG_TAG = "vcard.VCardParser_V30";
private static final String LOG_TAG = "VCardParser_V30";
private static final HashSet<String> sAcceptablePropsWithParam = new HashSet<String>(
Arrays.asList(
"BEGIN", "LOGO", "PHOTO", "LABEL", "FN", "TITLE", "SOUND",
@@ -185,17 +185,17 @@ public class VCardParser_V30 extends VCardParser_V21 {
/**
* vcard = [group "."] "BEGIN" ":" "VCARD" 1*CRLF
* 1*(contentline)
* vcard = [group "."] "BEGIN" ":" "VCARD" 1 * CRLF
* 1 * (contentline)
* ;A vCard object MUST include the VERSION, FN and N types.
* [group "."] "END" ":" "VCARD" 1*CRLF
* [group "."] "END" ":" "VCARD" 1 * CRLF
*/
@Override
protected boolean readBeginVCard(boolean allowGarbage) throws IOException, VCardException {
// TODO: vCard 3.0 supports group.
return super.readBeginVCard(allowGarbage);
}
@Override
protected void readEndVCard(boolean useCache, boolean allowGarbage)
throws IOException, VCardException {
@@ -222,14 +222,9 @@ public class VCardParser_V30 extends VCardParser_V21 {
}
}
}
@Override
protected void handleAnyParam(String paramName, String paramValue) {
// vCard 3.0 accept comma-separated multiple values, but
// current PropertyNode does not accept it.
// For now, we do not split the values.
//
// TODO: fix this.
super.handleAnyParam(paramName, paramValue);
}
@@ -266,7 +261,7 @@ public class VCardParser_V30 extends VCardParser_V21 {
@Override
protected void handleAgent(String propertyValue) {
// The way how vCard 3.0 supports "AGENT" is completely different from vCard 2.0.
// The way how vCard 3.0 supports "AGENT" is completely different from vCard 2.1.
//
// e.g.
// AGENT:BEGIN:VCARD\nFN:Joe Friday\nTEL:+1-919-555-7878\n
@@ -281,13 +276,13 @@ public class VCardParser_V30 extends VCardParser_V21 {
// AGENT;VALUE=uri:
// CID:JQPUBLIC.part3.960129T083020.xyzMail@host3.com
//
// This is not VCARD. Should we support this?
// throw new VCardException("AGENT in vCard 3.0 is not supported yet.");
// This is not vCard. Should we support this?
//
// Just ignore the line for now, since we cannot know how to handle it...
if (!mEmittedAgentWarning) {
Log.w(LOG_TAG, "AGENT in vCard 3.0 is not supported yet. Ignore it");
mEmittedAgentWarning = true;
}
// Just ignore the line for now, since we cannot know how to handle it...
}
/**
@@ -298,7 +293,7 @@ public class VCardParser_V30 extends VCardParser_V21 {
protected String getBase64(String firstString) throws IOException, VCardException {
StringBuilder builder = new StringBuilder();
builder.append(firstString);
while (true) {
String line = getLine();
if (line == null) {
@@ -322,8 +317,8 @@ public class VCardParser_V30 extends VCardParser_V21 {
* ; \\ encodes \, \n or \N encodes newline
* ; \; encodes ;, \, encodes ,
*
* Note: Apple escape ':' into '\:' while does not escape '\'
*/
* Note: Apple escapes ':' into '\:' while does not escape '\'
*/
@Override
protected String maybeUnescapeText(String text) {
return unescapeText(text);
@@ -347,7 +342,7 @@ public class VCardParser_V30 extends VCardParser_V21 {
}
return builder.toString();
}
@Override
protected String maybeUnescapeCharacter(char ch) {
return unescapeCharacter(ch);

View File

@@ -62,7 +62,7 @@ public class VCardSourceDetector implements VCardInterpreter {
public void end() {
}
public void startRecord(String type) {
public void startEntry() {
}
public void startProperty() {
@@ -72,7 +72,7 @@ public class VCardSourceDetector implements VCardInterpreter {
public void endProperty() {
}
public void endRecord() {
public void endEntry() {
}
public void propertyGroup(String group) {

View File

@@ -64,7 +64,7 @@ public class PropertyNodesVerifier extends VNodeBuilder {
public void verify(InputStream is, int vCardType) throws IOException, VCardException {
final VCardParser vCardParser;
if (VCardConfig.isV30(vCardType)) {
vCardParser = new VCardParser_V30(true); // use StrictParsing
vCardParser = new VCardParser_V30(true); // Use StrictParsing.
} else {
vCardParser = new VCardParser_V21();
}
@@ -86,8 +86,8 @@ public class PropertyNodesVerifier extends VNodeBuilder {
}
@Override
public void endRecord() {
super.endRecord();
public void endEntry() {
super.endEntry();
mAndroidTestCase.assertTrue(mIndex < mPropertyNodesVerifierElemList.size());
mAndroidTestCase.assertTrue(mIndex < vNodeList.size());
mPropertyNodesVerifierElemList.get(mIndex).verify(vNodeList.get(mIndex));

View File

@@ -37,7 +37,7 @@ import android.pim.vcard.VCardEntry;
import android.pim.vcard.VCardEntryCommitter;
import android.pim.vcard.VCardEntryHandler;
import android.pim.vcard.VCardInterpreter;
import android.pim.vcard.VCardInterPreterCollection;
import android.pim.vcard.VCardInterpreterCollection;
import android.pim.vcard.VCardComposer;
import android.pim.vcard.VCardConfig;
import android.pim.vcard.VCardEntryConstructor;
@@ -863,7 +863,7 @@ class CustomMockContext extends MockContext {
new VCardEntryConstructor(mVCardType);
vcardDataBuilder.addEntryHandler(mImportVerifier);
if (mPropertyNodesVerifier != null) {
builder = new VCardInterPreterCollection(Arrays.asList(
builder = new VCardInterpreterCollection(Arrays.asList(
mPropertyNodesVerifier, vcardDataBuilder));
} else {
builder = vnodeBuilder;

View File

@@ -115,11 +115,10 @@ public class VNodeBuilder implements VCardInterpreter {
// I leave this code as is since I'm not familiar with vcalendar specification.
// But I believe we should refactor this code in the future.
// Until this, the last entry has to be removed when some error occurs.
public void startRecord(String type) {
public void startEntry() {
VNode vnode = new VNode();
vnode.parseStatus = 1;
vnode.VName = type;
vnode.VName = "VCARD";
// I feel this should be done in endRecord(), but it cannot be done because of
// the reason above.
vNodeList.add(vnode);
@@ -127,7 +126,7 @@ public class VNodeBuilder implements VCardInterpreter {
mCurrentVNode = vNodeList.get(mNodeListPos);
}
public void endRecord() {
public void endEntry() {
VNode endNode = vNodeList.get(mNodeListPos);
endNode.parseStatus = 0;
while(mNodeListPos > 0){