FileDocCategorySizeDatePackage
VCardUtils.javaAPI DocAndroid 5.1 API33535Thu Mar 12 22:22:54 GMT 2015com.android.vcard

VCardUtils

public class VCardUtils extends Object
Utilities for VCard handling codes.

Fields Summary
private static final String
LOG_TAG
private static final Map
sKnownPhoneTypesMap_ItoS
private static final Set
sPhoneTypesUnknownToContactsSet
private static final Map
sKnownPhoneTypeMap_StoI
private static final Map
sKnownImPropNameMap_ItoS
private static final Set
sMobilePhoneLabelSet
private static final Set
sUnAcceptableAsciiInV21WordSet
private static final int[]
sEscapeIndicatorsV30
private static final int[]
sEscapeIndicatorsV40
Constructors Summary
private VCardUtils()

    
Methods Summary
public static booleanappearsLikeAndroidVCardQuotedPrintable(java.lang.String value)
Checks to see if a string looks like it could be an android generated quoted printable. Identification of quoted printable is not 100% reliable since it's just ascii. But given the high number and exact location of generated = signs, there is a high likely-hood that it would be.

return
True if it appears like android quoted printable. False otherwise.


        // Quoted printable is always in multiple of 3s. With optional 1 '=' at end.
        final int remainder = (value.length() % 3);
        if (value.length() < 2 || (remainder != 1 && remainder != 0)) {
            return false;
        }
        for (int i = 0; i < value.length(); i += 3) {
            if (value.charAt(i) != '=") {
                return false;
            }
        }
        return true;
    
public static booleanareAllEmpty(java.lang.String values)

return
True when all the given values are null or empty Strings.

        if (values == null) {
            return true;
        }

        for (final String value : values) {
            if (!TextUtils.isEmpty(value)) {
                return false;
            }
        }
        return true;
    
public static java.util.ListconstructListFromValue(java.lang.String value, int vcardType)
Splits the given value into pieces using the delimiter ';' inside it. Escaped characters in those values are automatically unescaped into original form.

        final List<String> list = new ArrayList<String>();
        StringBuilder builder = new StringBuilder();
        final int length = value.length();
        for (int i = 0; i < length; i++) {
            char ch = value.charAt(i);
            if (ch == '\\" && i < length - 1) {
                char nextCh = value.charAt(i + 1);
                final String unescapedString;
                if (VCardConfig.isVersion40(vcardType)) {
                    unescapedString = VCardParserImpl_V40.unescapeCharacter(nextCh);
                } else if (VCardConfig.isVersion30(vcardType)) {
                    unescapedString = VCardParserImpl_V30.unescapeCharacter(nextCh);
                } else {
                    if (!VCardConfig.isVersion21(vcardType)) {
                        // Unknown vCard type
                        Log.w(LOG_TAG, "Unknown vCard type");
                    }
                    unescapedString = VCardParserImpl_V21.unescapeCharacter(nextCh);
                }

                if (unescapedString != null) {
                    builder.append(unescapedString);
                    i++;
                } else {
                    builder.append(ch);
                }
            } else if (ch == ';") {
                list.add(builder.toString());
                builder = new StringBuilder();
            } else {
                builder.append(ch);
            }
        }
        list.add(builder.toString());
        return list;
    
public static java.lang.StringconstructNameFromElements(int nameOrder, java.lang.String familyName, java.lang.String middleName, java.lang.String givenName)

        return constructNameFromElements(nameOrder, familyName, middleName, givenName,
                null, null);
    
public static java.lang.StringconstructNameFromElements(int nameOrder, java.lang.String familyName, java.lang.String middleName, java.lang.String givenName, java.lang.String prefix, java.lang.String suffix)

        final StringBuilder builder = new StringBuilder();
        final String[] nameList = sortNameElements(nameOrder, familyName, middleName, givenName);
        boolean first = true;
        if (!TextUtils.isEmpty(prefix)) {
            first = false;
            builder.append(prefix);
        }
        for (final String namePart : nameList) {
            if (!TextUtils.isEmpty(namePart)) {
                if (first) {
                    first = false;
                } else {
                    builder.append(' ");
                }
                builder.append(namePart);
            }
        }
        if (!TextUtils.isEmpty(suffix)) {
            if (!first) {
                builder.append(' ");
            }
            builder.append(suffix);
        }
        return builder.toString();
    
public static booleancontainsOnlyAlphaDigitHyphen(java.lang.String values)

This is useful since vCard 3.0 often requires the ("X-") properties and groups should contain only alphabets, digits, and hyphen.

Note: It is already known some devices (wrongly) outputs properties with characters which should not be in the field. One example is "X-GOOGLE TALK". We accept such kind of input but must never output it unless the target is very specific to the device which is able to parse the malformed input.


                                                                                                       
         
        if (values == null) {
            return true;
        }
        return containsOnlyAlphaDigitHyphen(Arrays.asList(values));
    
public static booleancontainsOnlyAlphaDigitHyphen(java.util.Collection values)

        if (values == null) {
            return true;
        }
        final int upperAlphabetFirst = 0x41;  // A
        final int upperAlphabetAfterLast = 0x5b;  // [
        final int lowerAlphabetFirst = 0x61;  // a
        final int lowerAlphabetAfterLast = 0x7b;  // {
        final int digitFirst = 0x30;  // 0
        final int digitAfterLast = 0x3A;  // :
        final int hyphen = '-";
        for (final String str : values) {
            if (TextUtils.isEmpty(str)) {
                continue;
            }
            final int length = str.length();
            for (int i = 0; i < length; i = str.offsetByCodePoints(i, 1)) {
                int codepoint = str.codePointAt(i);
                if (!((lowerAlphabetFirst <= codepoint && codepoint < lowerAlphabetAfterLast) ||
                    (upperAlphabetFirst <= codepoint && codepoint < upperAlphabetAfterLast) ||
                    (digitFirst <= codepoint && codepoint < digitAfterLast) ||
                    (codepoint == hyphen))) {
                    return false;
                }
            }
        }
        return true;
    
public static booleancontainsOnlyNonCrLfPrintableAscii(java.lang.String values)

This is useful when checking the string should be encoded into quoted-printable or not, which is required by vCard 2.1.

See the definition of "7bit" in vCard 2.1 spec for more information.

        if (values == null) {
            return true;
        }
        return containsOnlyNonCrLfPrintableAscii(Arrays.asList(values));
    
public static booleancontainsOnlyNonCrLfPrintableAscii(java.util.Collection values)

        if (values == null) {
            return true;
        }
        final int asciiFirst = 0x20;
        final int asciiLast = 0x7E;  // included
        for (final String value : values) {
            if (TextUtils.isEmpty(value)) {
                continue;
            }
            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)) {
                    return false;
                }
            }
        }
        return true;
    
public static booleancontainsOnlyPrintableAscii(java.lang.String values)

        if (values == null) {
            return true;
        }
        return containsOnlyPrintableAscii(Arrays.asList(values));
    
public static booleancontainsOnlyPrintableAscii(java.util.Collection values)

        if (values == null) {
            return true;
        }
        for (final String value : values) {
            if (TextUtils.isEmpty(value)) {
                continue;
            }
            if (!TextUtilsPort.isPrintableAsciiOnly(value)) {
                return false;
            }
        }
        return true;
    
public static booleancontainsOnlyWhiteSpaces(java.lang.String values)

        if (values == null) {
            return true;
        }
        return containsOnlyWhiteSpaces(Arrays.asList(values));
    
public static booleancontainsOnlyWhiteSpaces(java.util.Collection values)

        if (values == null) {
            return true;
        }
        for (final String str : values) {
            if (TextUtils.isEmpty(str)) {
                continue;
            }
            final int length = str.length();
            for (int i = 0; i < length; i = str.offsetByCodePoints(i, 1)) {
                if (!Character.isWhitespace(str.codePointAt(i))) {
                    return false;
                }
            }
        }
        return true;
    
public static final java.lang.StringconvertStringCharset(java.lang.String originalString, java.lang.String sourceCharset, java.lang.String targetCharset)

        if (sourceCharset.equalsIgnoreCase(targetCharset)) {
            return originalString;
        }
        final Charset charset = Charset.forName(sourceCharset);
        final ByteBuffer byteBuffer = charset.encode(originalString);
        // byteBuffer.array() "may" return byte array which is larger than
        // byteBuffer.remaining(). Here, we keep on the safe side.
        final byte[] bytes = new byte[byteBuffer.remaining()];
        byteBuffer.get(bytes);
        try {
            return new String(bytes, targetCharset);
        } catch (UnsupportedEncodingException e) {
            Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
            return null;
        }
    
public static final VCardParsergetAppropriateParser(int vcardType)

        if (VCardConfig.isVersion21(vcardType)) {
            return new VCardParser_V21();
        } else if (VCardConfig.isVersion30(vcardType)) {
            return new VCardParser_V30();
        } else if (VCardConfig.isVersion40(vcardType)) {
            return new VCardParser_V40();
        } else {
            throw new VCardException("Version is not specified");
        }
    
public static intgetPhoneNumberFormat(int vcardType)

        if (VCardConfig.isJapaneseDevice(vcardType)) {
            return PhoneNumberUtils.FORMAT_JAPAN;
        } else {
            return PhoneNumberUtils.FORMAT_NANP;
        }
    
public static java.lang.ObjectgetPhoneTypeFromStrings(java.util.Collection types, java.lang.String number)
Returns Interger when the given types can be parsed as known type. Returns String object when not, which should be set to label.

        if (number == null) {
            number = "";
        }
        int type = -1;
        String label = null;
        boolean isFax = false;
        boolean hasPref = false;

        if (types != null) {
            for (final String typeStringOrg : types) {
                if (typeStringOrg == null) {
                    continue;
                }
                final String typeStringUpperCase = typeStringOrg.toUpperCase();
                if (typeStringUpperCase.equals(VCardConstants.PARAM_TYPE_PREF)) {
                    hasPref = true;
                } else if (typeStringUpperCase.equals(VCardConstants.PARAM_TYPE_FAX)) {
                    isFax = true;
                } else {
                    final String labelCandidate;
                    if (typeStringUpperCase.startsWith("X-") && type < 0) {
                        labelCandidate = typeStringOrg.substring(2);
                    } else {
                        labelCandidate = typeStringOrg;
                    }
                    if (labelCandidate.length() == 0) {
                        continue;
                    }
                    // e.g. "home" -> TYPE_HOME
                    final Integer tmp = sKnownPhoneTypeMap_StoI.get(labelCandidate.toUpperCase());
                    if (tmp != null) {
                        final int typeCandidate = tmp;
                        // 1. If a type isn't specified yet, we'll choose the new type candidate.
                        // 2. If the current type is default one (OTHER) or custom one, we'll
                        // prefer more specific types specified in the vCard. Note that OTHER and
                        // the other different types may appear simultaneously here, since vCard
                        // allow to have VOICE and HOME/WORK in one line.
                        // e.g. "TEL;WORK;VOICE:1" -> WORK + OTHER -> Type should be WORK
                        // 3. TYPE_PAGER is prefered when the number contains @ surronded by
                        // a pager number and a domain name.
                        // e.g.
                        // o 1111@domain.com
                        // x @domain.com
                        // x 1111@
                        final int indexOfAt = number.indexOf("@");
                        if ((typeCandidate == Phone.TYPE_PAGER
                                && 0 < indexOfAt && indexOfAt < number.length() - 1)
                                || type < 0
                                || type == Phone.TYPE_CUSTOM
                                || type == Phone.TYPE_OTHER) {
                            type = tmp;
                        }
                    } else if (type < 0) {
                        type = Phone.TYPE_CUSTOM;
                        label = labelCandidate;
                    }
                }
            }
        }
        if (type < 0) {
            if (hasPref) {
                type = Phone.TYPE_MAIN;
            } else {
                // default to TYPE_HOME
                type = Phone.TYPE_HOME;
            }
        }
        if (isFax) {
            if (type == Phone.TYPE_HOME) {
                type = Phone.TYPE_FAX_HOME;
            } else if (type == Phone.TYPE_WORK) {
                type = Phone.TYPE_FAX_WORK;
            } else if (type == Phone.TYPE_OTHER) {
                type = Phone.TYPE_OTHER_FAX;
            }
        }
        if (type == Phone.TYPE_CUSTOM) {
            return label;
        } else {
            return type;
        }
    
public static java.lang.StringgetPhoneTypeString(java.lang.Integer type)

        sKnownPhoneTypesMap_ItoS = new HashMap<Integer, String>();
        sKnownPhoneTypeMap_StoI = new HashMap<String, Integer>();

        sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_CAR, VCardConstants.PARAM_TYPE_CAR);
        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_CAR, Phone.TYPE_CAR);
        sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_PAGER, VCardConstants.PARAM_TYPE_PAGER);
        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_PAGER, Phone.TYPE_PAGER);
        sKnownPhoneTypesMap_ItoS.put(Phone.TYPE_ISDN, VCardConstants.PARAM_TYPE_ISDN);
        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_ISDN, Phone.TYPE_ISDN);

        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_HOME, Phone.TYPE_HOME);
        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_WORK, Phone.TYPE_WORK);
        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_CELL, Phone.TYPE_MOBILE);

        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_OTHER, Phone.TYPE_OTHER);
        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_CALLBACK,
                Phone.TYPE_CALLBACK);
        sKnownPhoneTypeMap_StoI.put(
                VCardConstants.PARAM_PHONE_EXTRA_TYPE_COMPANY_MAIN, Phone.TYPE_COMPANY_MAIN);
        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_RADIO, Phone.TYPE_RADIO);
        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_TTY_TDD,
                Phone.TYPE_TTY_TDD);
        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_PHONE_EXTRA_TYPE_ASSISTANT,
                Phone.TYPE_ASSISTANT);
        // OTHER (default in Android) should correspond to VOICE (default in vCard).
        sKnownPhoneTypeMap_StoI.put(VCardConstants.PARAM_TYPE_VOICE, Phone.TYPE_OTHER);

        sPhoneTypesUnknownToContactsSet = new HashSet<String>();
        sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_MODEM);
        sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_MSG);
        sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_BBS);
        sPhoneTypesUnknownToContactsSet.add(VCardConstants.PARAM_TYPE_VIDEO);

        sKnownImPropNameMap_ItoS = new HashMap<Integer, String>();
        sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_AIM, VCardConstants.PROPERTY_X_AIM);
        sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_MSN, VCardConstants.PROPERTY_X_MSN);
        sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_YAHOO, VCardConstants.PROPERTY_X_YAHOO);
        sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_SKYPE, VCardConstants.PROPERTY_X_SKYPE_USERNAME);
        sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_GOOGLE_TALK,
                VCardConstants.PROPERTY_X_GOOGLE_TALK);
        sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_ICQ, VCardConstants.PROPERTY_X_ICQ);
        sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_JABBER, VCardConstants.PROPERTY_X_JABBER);
        sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_QQ, VCardConstants.PROPERTY_X_QQ);
        sKnownImPropNameMap_ItoS.put(Im.PROTOCOL_NETMEETING, VCardConstants.PROPERTY_X_NETMEETING);

        // \u643A\u5E2F\u96FB\u8A71 = Full-width Hiragana "Keitai-Denwa" (mobile phone)
        // \u643A\u5E2F = Full-width Hiragana "Keitai" (mobile phone)
        // \u30B1\u30A4\u30BF\u30A4 = Full-width Katakana "Keitai" (mobile phone)
        // \uFF79\uFF72\uFF80\uFF72 = Half-width Katakana "Keitai" (mobile phone)
        sMobilePhoneLabelSet = new HashSet<String>(Arrays.asList(
                "MOBILE", "\u643A\u5E2F\u96FB\u8A71", "\u643A\u5E2F", "\u30B1\u30A4\u30BF\u30A4",
                "\uFF79\uFF72\uFF80\uFF72"));
    
        return sKnownPhoneTypesMap_ItoS.get(type);
    
public static java.lang.StringgetPropertyNameForIm(int protocol)

        return sKnownImPropNameMap_ItoS.get(protocol);
    
public static java.lang.StringguessImageType(byte[] input)
Guesses the format of input image. Currently just the first few bytes are used. The type "GIF", "PNG", or "JPEG" is returned when possible. Returns null when the guess failed.

param
input Image as byte array.
return
The image type or null when the type cannot be determined.

        if (input == null) {
            return null;
        }
        if (input.length >= 3 && input[0] == 'G" && input[1] == 'I" && input[2] == 'F") {
            return "GIF";
        } else if (input.length >= 4 && input[0] == (byte) 0x89
                && input[1] == 'P" && input[2] == 'N" && input[3] == 'G") {
            // Note: vCard 2.1 officially does not support PNG, but we may have it and
            //       using X- word like "X-PNG" may not let importers know it is PNG.
            //       So we use the String "PNG" as is...
            return "PNG";
        } else if (input.length >= 2 && input[0] == (byte) 0xff
                && input[1] == (byte) 0xd8) {
            return "JPEG";
        } else {
            return null;
        }
    
public static booleanisMobilePhoneLabel(java.lang.String label)

        // For backward compatibility.
        // Detail: Until Donut, there isn't TYPE_MOBILE for email while there is now.
        //         To support mobile type at that time, this custom label had been used.
        return ("_AUTO_CELL".equals(label) || sMobilePhoneLabelSet.contains(label));
    
public static booleanisV21Word(java.lang.String value)

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 []=:., >

        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 booleanisValidInV21ButUnknownToContactsPhoteType(java.lang.String label)

        return sPhoneTypesUnknownToContactsSet.contains(label);
    
public static java.lang.StringparseQuotedPrintable(java.lang.String value, boolean strictLineBreaking, java.lang.String sourceCharset, java.lang.String targetCharset)
Unquotes given Quoted-Printable value. value must not be null.

        // "= " -> " ", "=\t" -> "\t".
        // Previous code had done this replacement. Keep on the safe side.
        final String quotedPrintable;
        {
            final StringBuilder builder = new StringBuilder();
            final int length = value.length();
            for (int i = 0; i < length; i++) {
                char ch = value.charAt(i);
                if (ch == '=" && i < length - 1) {
                    char nextCh = value.charAt(i + 1);
                    if (nextCh == ' " || nextCh == '\t") {
                        builder.append(nextCh);
                        i++;
                        continue;
                    }
                }
                builder.append(ch);
            }
            quotedPrintable = builder.toString();
        }

        String[] lines;
        if (strictLineBreaking) {
            lines = quotedPrintable.split("\r\n");
        } else {
            StringBuilder builder = new StringBuilder();
            final int length = quotedPrintable.length();
            ArrayList<String> list = new ArrayList<String>();
            for (int i = 0; i < length; i++) {
                char ch = quotedPrintable.charAt(i);
                if (ch == '\n") {
                    list.add(builder.toString());
                    builder = new StringBuilder();
                } else if (ch == '\r") {
                    list.add(builder.toString());
                    builder = new StringBuilder();
                    if (i < length - 1) {
                        char nextCh = quotedPrintable.charAt(i + 1);
                        if (nextCh == '\n") {
                            i++;
                        }
                    }
                } else {
                    builder.append(ch);
                }
            }
            final String lastLine = builder.toString();
            if (lastLine.length() > 0) {
                list.add(lastLine);
            }
            lines = list.toArray(new String[0]);
        }

        final StringBuilder builder = new StringBuilder();
        for (String line : lines) {
            if (line.endsWith("=")) {
                line = line.substring(0, line.length() - 1);
            }
            builder.append(line);
        }

        final String rawString = builder.toString();
        if (TextUtils.isEmpty(rawString)) {
            Log.w(LOG_TAG, "Given raw string is empty.");
        }

        byte[] rawBytes = null;
        try {
            rawBytes = rawString.getBytes(sourceCharset);
        } catch (UnsupportedEncodingException e) {
            Log.w(LOG_TAG, "Failed to decode: " + sourceCharset);
            rawBytes = rawString.getBytes();
        }

        byte[] decodedBytes = null;
        try {
            decodedBytes = QuotedPrintableCodecPort.decodeQuotedPrintable(rawBytes);
        } catch (DecoderException e) {
            Log.e(LOG_TAG, "DecoderException is thrown.");
            decodedBytes = rawBytes;
        }

        try {
            return new String(decodedBytes, targetCharset);
        } catch (UnsupportedEncodingException e) {
            Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
            return new String(decodedBytes);
        }
    
public static java.lang.String[]sortNameElements(int nameOrder, java.lang.String familyName, java.lang.String middleName, java.lang.String givenName)

        final String[] list = new String[3];
        final int nameOrderType = VCardConfig.getNameOrderType(nameOrder);
        switch (nameOrderType) {
            case VCardConfig.NAME_ORDER_JAPANESE: {
                if (containsOnlyPrintableAscii(familyName) &&
                        containsOnlyPrintableAscii(givenName)) {
                    list[0] = givenName;
                    list[1] = middleName;
                    list[2] = familyName;
                } else {
                    list[0] = familyName;
                    list[1] = middleName;
                    list[2] = givenName;
                }
                break;
            }
            case VCardConfig.NAME_ORDER_EUROPE: {
                list[0] = middleName;
                list[1] = givenName;
                list[2] = familyName;
                break;
            }
            default: {
                list[0] = givenName;
                list[1] = middleName;
                list[2] = familyName;
                break;
            }
        }
        return list;
    
public static java.lang.StringtoHalfWidthString(java.lang.String orgString)

        if (TextUtils.isEmpty(orgString)) {
            return null;
        }
        final StringBuilder builder = new StringBuilder();
        final int length = orgString.length();
        for (int i = 0; i < length; i = orgString.offsetByCodePoints(i, 1)) {
            // All Japanese character is able to be expressed by char.
            // Do not need to use String#codepPointAt().
            final char ch = orgString.charAt(i);
            final String halfWidthText = JapaneseUtils.tryGetHalfWidthText(ch);
            if (halfWidthText != null) {
                builder.append(halfWidthText);
            } else {
                builder.append(ch);
            }
        }
        return builder.toString();
    
private static java.lang.StringtoStringAsParamValue(java.lang.String value, int[] escapeIndicators)

        if (TextUtils.isEmpty(value)) {
            value = "";
        }
        final int asciiFirst = 0x20;
        final int asciiLast = 0x7E;  // included
        final StringBuilder builder = new StringBuilder();
        final int length = value.length();
        boolean needQuote = false;
        for (int i = 0; i < length; i = value.offsetByCodePoints(i, 1)) {
            final int codePoint = value.codePointAt(i);
            if (codePoint < asciiFirst || codePoint == '"") {
                // CTL characters and DQUOTE are never accepted. Remove them.
                continue;
            }
            builder.appendCodePoint(codePoint);
            for (int indicator : escapeIndicators) {
                if (codePoint == indicator) {
                    needQuote = true;
                    break;
                }
            }
        }

        final String result = builder.toString();
        return ((result.isEmpty() || VCardUtils.containsOnlyWhiteSpaces(result))
                ? ""
                : (needQuote ? ('"" + result + '"")
                : result));
    
public static java.lang.StringtoStringAsV30ParamValue(java.lang.String value)

Returns String available as parameter value in vCard 3.0.

RFC 2426 requires vCard composer to quote parameter values when it contains semi-colon, for example (See RFC 2426 for more information). This method checks whether the given String can be used without quotes.

Note: We remove DQUOTE inside the given value silently for now.


                                                                    
         
        return toStringAsParamValue(value, sEscapeIndicatorsV30);
    
public static java.lang.StringtoStringAsV40ParamValue(java.lang.String value)

        return toStringAsParamValue(value, sEscapeIndicatorsV40);