From a750fdd765ec253ffa8bf3d4848d5c3a35e1979b Mon Sep 17 00:00:00 2001 From: Daisuke Miyakawa Date: Fri, 20 Nov 2009 16:09:34 +0900 Subject: Fix a problem in which Android custom fields are not emitted correctly in non-Ascii languages. Internal issue number: 2195990 --- core/java/android/pim/vcard/VCardBuilder.java | 79 +++++++++++++++--------- core/java/android/pim/vcard/VCardParser_V21.java | 3 - core/java/android/pim/vcard/VCardUtils.java | 75 ++++++++++++++-------- 3 files changed, 98 insertions(+), 59 deletions(-) (limited to 'core/java/android/pim') diff --git a/core/java/android/pim/vcard/VCardBuilder.java b/core/java/android/pim/vcard/VCardBuilder.java index 3980940..09ac1fd 100644 --- a/core/java/android/pim/vcard/VCardBuilder.java +++ b/core/java/android/pim/vcard/VCardBuilder.java @@ -1536,13 +1536,10 @@ public class VCardBuilder { } public void appendAndroidSpecificProperty(final String mimeType, ContentValues contentValues) { - List rawValueList = new ArrayList(); - rawValueList.add(mimeType); - final List columnNameList; if (!sAllowedAndroidPropertySet.contains(mimeType)) { return; } - + final List rawValueList = new ArrayList(); for (int i = 1; i <= VCardConstants.MAX_DATA_COLUMN; i++) { String value = contentValues.getAsString("data" + i); if (value == null) { @@ -1551,8 +1548,38 @@ public class VCardBuilder { rawValueList.add(value); } - appendLineWithCharsetAndQPDetection( - VCardConstants.PROPERTY_X_ANDROID_CUSTOM, rawValueList); + boolean needCharset = + (mShouldAppendCharsetParam && + !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValueList)); + boolean reallyUseQuotedPrintable = + (mShouldUseQuotedPrintable && + !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValueList)); + mBuilder.append(VCardConstants.PROPERTY_X_ANDROID_CUSTOM); + if (needCharset) { + mBuilder.append(VCARD_PARAM_SEPARATOR); + mBuilder.append(mVCardCharsetParameter); + } + if (reallyUseQuotedPrintable) { + mBuilder.append(VCARD_PARAM_SEPARATOR); + mBuilder.append(VCARD_PARAM_ENCODING_QP); + } + mBuilder.append(VCARD_DATA_SEPARATOR); + mBuilder.append(mimeType); // Should not be encoded. + for (String rawValue : rawValueList) { + final String encodedValue; + if (reallyUseQuotedPrintable) { + encodedValue = encodeQuotedPrintable(rawValue); + } else { + // TODO: one line may be too huge, which may be invalid in vCard 3.0 + // (which says "When generating a content line, lines longer than + // 75 characters SHOULD be folded"), though several + // (even well-known) applications do not care this. + encodedValue = escapeCharacters(rawValue); + } + mBuilder.append(VCARD_ITEM_SEPARATOR); + mBuilder.append(encodedValue); + } + mBuilder.append(VCARD_END_OF_LINE); } public void appendLineWithCharsetAndQPDetection(final String propertyName, @@ -1560,7 +1587,7 @@ public class VCardBuilder { appendLineWithCharsetAndQPDetection(propertyName, null, rawValue); } - private void appendLineWithCharsetAndQPDetection( + public void appendLineWithCharsetAndQPDetection( final String propertyName, final List rawValueList) { appendLineWithCharsetAndQPDetection(propertyName, null, rawValueList); } @@ -1578,22 +1605,12 @@ public class VCardBuilder { public void appendLineWithCharsetAndQPDetection(final String propertyName, final List parameterList, final List rawValueList) { - boolean needCharset = false; - boolean reallyUseQuotedPrintable = false; - for (String rawValue : rawValueList) { - if (!needCharset && mShouldUseQuotedPrintable && - !VCardUtils.containsOnlyPrintableAscii(rawValue)) { - needCharset = true; - } - if (!reallyUseQuotedPrintable && - !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValue)) { - reallyUseQuotedPrintable = true; - } - if (needCharset && reallyUseQuotedPrintable) { - break; - } - } - + boolean needCharset = + (mShouldAppendCharsetParam && + !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValueList)); + boolean reallyUseQuotedPrintable = + (mShouldUseQuotedPrintable && + !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawValueList)); appendLine(propertyName, parameterList, rawValueList, needCharset, reallyUseQuotedPrintable); } @@ -1610,8 +1627,9 @@ public class VCardBuilder { } public void appendLine(final String propertyName, - final String rawValue, final boolean needCharset, boolean needQuotedPrintable) { - appendLine(propertyName, null, rawValue, needCharset, needQuotedPrintable); + final String rawValue, final boolean needCharset, + boolean reallyUseQuotedPrintable) { + appendLine(propertyName, null, rawValue, needCharset, reallyUseQuotedPrintable); } public void appendLine(final String propertyName, final List parameterList, @@ -1620,7 +1638,8 @@ public class VCardBuilder { } public void appendLine(final String propertyName, final List parameterList, - final String rawValue, final boolean needCharset, boolean needQuotedPrintable) { + final String rawValue, final boolean needCharset, + boolean reallyUseQuotedPrintable) { mBuilder.append(propertyName); if (parameterList != null && parameterList.size() > 0) { mBuilder.append(VCARD_PARAM_SEPARATOR); @@ -1632,7 +1651,7 @@ public class VCardBuilder { } final String encodedValue; - if (needQuotedPrintable) { + if (reallyUseQuotedPrintable) { mBuilder.append(VCARD_PARAM_SEPARATOR); mBuilder.append(VCARD_PARAM_ENCODING_QP); encodedValue = encodeQuotedPrintable(rawValue); @@ -1664,14 +1683,16 @@ public class VCardBuilder { mBuilder.append(VCARD_PARAM_SEPARATOR); mBuilder.append(mVCardCharsetParameter); } + if (needQuotedPrintable) { + mBuilder.append(VCARD_PARAM_SEPARATOR); + mBuilder.append(VCARD_PARAM_ENCODING_QP); + } mBuilder.append(VCARD_DATA_SEPARATOR); boolean first = true; for (String rawValue : rawValueList) { final String encodedValue; if (needQuotedPrintable) { - mBuilder.append(VCARD_PARAM_SEPARATOR); - mBuilder.append(VCARD_PARAM_ENCODING_QP); encodedValue = encodeQuotedPrintable(rawValue); } else { // TODO: one line may be too huge, which may be invalid in vCard 3.0 diff --git a/core/java/android/pim/vcard/VCardParser_V21.java b/core/java/android/pim/vcard/VCardParser_V21.java index ec569d4..e7c19cf 100644 --- a/core/java/android/pim/vcard/VCardParser_V21.java +++ b/core/java/android/pim/vcard/VCardParser_V21.java @@ -117,9 +117,6 @@ public class VCardParser_V21 extends VCardParser { this(detector.getEstimatedType()); } - /** - * TODO: Merge detector and parser mode. - */ public VCardParser_V21(int parseType) { super(parseType); if (parseType == VCardConfig.PARSE_TYPE_FOMA) { diff --git a/core/java/android/pim/vcard/VCardUtils.java b/core/java/android/pim/vcard/VCardUtils.java index 80457bb..ec75a98 100644 --- a/core/java/android/pim/vcard/VCardUtils.java +++ b/core/java/android/pim/vcard/VCardUtils.java @@ -352,6 +352,13 @@ public class VCardUtils { if (values == null) { return true; } + return containsOnlyPrintableAscii(Arrays.asList(values)); + } + + public static boolean containsOnlyPrintableAscii(final Collection values) { + if (values == null) { + return true; + } final int asciiFirst = 0x20; final int asciiLast = 0x7E; // included for (final String value : values) { @@ -378,6 +385,13 @@ public class VCardUtils { if (values == null) { return true; } + return containsOnlyNonCrLfPrintableAscii(Arrays.asList(values)); + } + + public static boolean containsOnlyNonCrLfPrintableAscii(final Collection values) { + if (values == null) { + return true; + } final int asciiFirst = 0x20; final int asciiLast = 0x7E; // included for (final String value : values) { @@ -399,32 +413,6 @@ public class VCardUtils { new HashSet(Arrays.asList('[', ']', '=', ':', '.', ',', ' ')); /** - *

- * Returns true when the given String is categorized as "word" specified in vCard spec 2.1. - *

- *

- * vCard 2.1 specifies:
- * word = <any printable 7bit us-ascii except []=:., > - *

- */ - public static boolean isV21Word(final String value) { - if (TextUtils.isEmpty(value)) { - return true; - } - final int asciiFirst = 0x20; - final int asciiLast = 0x7E; // included - final int length = value.length(); - for (int i = 0; i < length; i = value.offsetByCodePoints(i, 1)) { - final int c = value.codePointAt(i); - if (!(asciiFirst <= c && c <= asciiLast) || - sUnAcceptableAsciiInV21WordSet.contains((char)c)) { - return false; - } - } - return true; - } - - /** * This is useful since vCard 3.0 often requires the ("X-") properties and groups * should contain only alphabets, digits, and hyphen. * @@ -437,6 +425,13 @@ public class VCardUtils { if (values == null) { return true; } + return containsOnlyAlphaDigitHyphen(Arrays.asList(values)); + } + + public static boolean containsOnlyAlphaDigitHyphen(final Collection values) { + if (values == null) { + return true; + } final int upperAlphabetFirst = 0x41; // A final int upperAlphabetAfterLast = 0x5b; // [ final int lowerAlphabetFirst = 0x61; // a @@ -461,7 +456,33 @@ public class VCardUtils { } return true; } - + + /** + *

+ * Returns true when the given String is categorized as "word" specified in vCard spec 2.1. + *

+ *

+ * vCard 2.1 specifies:
+ * word = <any printable 7bit us-ascii except []=:., > + *

+ */ + public static boolean isV21Word(final String value) { + if (TextUtils.isEmpty(value)) { + return true; + } + final int asciiFirst = 0x20; + final int asciiLast = 0x7E; // included + final int length = value.length(); + for (int i = 0; i < length; i = value.offsetByCodePoints(i, 1)) { + final int c = value.codePointAt(i); + if (!(asciiFirst <= c && c <= asciiLast) || + sUnAcceptableAsciiInV21WordSet.contains((char)c)) { + return false; + } + } + return true; + } + public static String toHalfWidthString(final String orgString) { if (TextUtils.isEmpty(orgString)) { return null; -- cgit v1.1