diff --git a/icu4c/source/common/ucnv_bld.c b/icu4c/source/common/ucnv_bld.c index 8fb78fd47bc..b0cd2981590 100644 --- a/icu4c/source/common/ucnv_bld.c +++ b/icu4c/source/common/ucnv_bld.c @@ -160,6 +160,7 @@ static uint16_t gAvailableConverterCount = 0; static char gDefaultConverterNameBuffer[UCNV_MAX_CONVERTER_NAME_LENGTH + 1]; /* +1 for NULL */ static const char *gDefaultConverterName = NULL; +static UBool gDefaultConverterContainsOption; static const char DATA_TYPE[] = "cnv"; @@ -182,6 +183,7 @@ static UBool U_CALLCONV ucnv_cleanup(void) { gDefaultConverterName = NULL; gDefaultConverterNameBuffer[0] = 0; + gDefaultConverterContainsOption = FALSE; umtx_destroy(&cnvCacheMutex); /* Don't worry about destroying the mutex even */ /* if the hash table still exists. The mutex */ @@ -658,6 +660,7 @@ ucnv_loadSharedData(const char *converterName, UConverterLookupData *lookup, UEr UConverterLookupData stackLookup; UConverterSharedData *mySharedConverterData = NULL; UErrorCode internalErrorCode = U_ZERO_ERROR; + UBool mayContainOption = TRUE; if (U_FAILURE (*err)) { return NULL; @@ -673,6 +676,7 @@ ucnv_loadSharedData(const char *converterName, UConverterLookupData *lookup, UEr /* In case "name" is NULL we want to open the default converter. */ if (converterName == NULL) { lookup->realName = ucnv_getDefaultName(); + mayContainOption = gDefaultConverterContainsOption; if (lookup->realName == NULL) { *err = U_MISSING_RESOURCE_ERROR; return NULL; @@ -687,7 +691,7 @@ ucnv_loadSharedData(const char *converterName, UConverterLookupData *lookup, UEr } /* get the canonical converter name */ - lookup->realName = ucnv_io_getConverterName(lookup->cnvName, &internalErrorCode); + lookup->realName = ucnv_io_getConverterName(lookup->cnvName, &mayContainOption, &internalErrorCode); if (U_FAILURE(internalErrorCode) || lookup->realName == NULL) { /* * set the input name in case the converter was added @@ -698,7 +702,7 @@ ucnv_loadSharedData(const char *converterName, UConverterLookupData *lookup, UEr } /* separate the converter name from the options */ - if(lookup->realName != lookup->cnvName) { + if(mayContainOption && lookup->realName != lookup->cnvName) { parseConverterOptions(lookup->realName, lookup->cnvName, lookup->locale, &lookup->options, err); lookup->realName = lookup->cnvName; } @@ -1113,6 +1117,7 @@ ucnv_getDefaultName() { uprv_memcpy(gDefaultConverterNameBuffer, name, length); gDefaultConverterNameBuffer[length]=0; gDefaultConverterName = gDefaultConverterNameBuffer; + gDefaultConverterContainsOption = (UBool)(uprv_strchr(gDefaultConverterName, UCNV_OPTION_SEP_CHAR) != NULL); name = gDefaultConverterName; ucln_common_registerCleanup(UCLN_COMMON_UCNV, ucnv_cleanup); umtx_unlock(&cnvCacheMutex); @@ -1133,7 +1138,7 @@ ucnv_setDefaultName(const char *converterName) { umtx_unlock(&cnvCacheMutex); } else { UErrorCode errorCode=U_ZERO_ERROR; - const char *name=ucnv_io_getConverterName(converterName, &errorCode); + const char *name=ucnv_io_getConverterName(converterName, NULL, &errorCode); umtx_lock(&cnvCacheMutex); @@ -1147,6 +1152,7 @@ ucnv_setDefaultName(const char *converterName) { uprv_memcpy(gDefaultConverterNameBuffer, converterName, length); gDefaultConverterNameBuffer[length]=0; gDefaultConverterName=gDefaultConverterNameBuffer; + gDefaultConverterContainsOption = (UBool)(uprv_strchr(gDefaultConverterName, UCNV_OPTION_SEP_CHAR) != NULL); } } umtx_unlock(&cnvCacheMutex); diff --git a/icu4c/source/common/ucnv_io.c b/icu4c/source/common/ucnv_io.c index c8524b719c1..320733ef5e6 100644 --- a/icu4c/source/common/ucnv_io.c +++ b/icu4c/source/common/ucnv_io.c @@ -73,6 +73,8 @@ * index of this list is also used by other sections, like the 4th section. * The index for the 3rd and 4th section is used to get the * alias -> converter name mapping. Section 3 and 4 form a two column table. + * Some of the most significant bits of each index may contain other + * information (see findConverter for details). * * 4) This section contains a list of mapped converter names. Consider this * as a table that maps the 3rd section to the 1st section. This list contains @@ -187,7 +189,8 @@ enum { }; static const UConverterAliasOptions defaultTableOptions = { - UCNV_IO_UNNORMALIZED + UCNV_IO_UNNORMALIZED, + 0 /* containsCnvOptionInfo */ }; static UConverterAlias gMainTable; @@ -435,7 +438,7 @@ ucnv_compareNames(const char *name1, const char *name2) { * return the converter number index for gConverterList */ static U_INLINE uint32_t -findConverter(const char *alias, UErrorCode *pErrorCode) { +findConverter(const char *alias, UBool *containsOption, UErrorCode *pErrorCode) { uint32_t mid, start, limit; uint32_t lastMid; int result; @@ -484,6 +487,14 @@ findConverter(const char *alias, UErrorCode *pErrorCode) { if (gMainTable.untaggedConvArray[mid] & UCNV_AMBIGUOUS_ALIAS_MAP_BIT) { *pErrorCode = U_AMBIGUOUS_ALIAS_WARNING; } + /* State whether the canonical converter name contains an option. + This information is contained in this list in order to maintain backward & forward compatibility. */ + if (containsOption) { + UBool containsCnvOptionInfo = (UBool)gMainTable.optionTable->containsCnvOptionInfo; + *containsOption = (UBool)((containsCnvOptionInfo + && ((gMainTable.untaggedConvArray[mid] & UCNV_CONTAINS_OPTION_BIT) != 0)) + || !containsCnvOptionInfo); + } return gMainTable.untaggedConvArray[mid] & UCNV_CONVERTER_INDEX_MASK; } } @@ -528,7 +539,7 @@ findTaggedAliasListsOffset(const char *alias, const char *standard, UErrorCode * uint32_t tagNum = getTagNumber(standard); /* Make a quick guess. Hopefully they used a TR22 canonical alias. */ - convNum = findConverter(alias, &myErr); + convNum = findConverter(alias, NULL, &myErr); if (myErr != U_ZERO_ERROR) { *pErrorCode = myErr; } @@ -579,7 +590,7 @@ findTaggedConverterNum(const char *alias, const char *standard, UErrorCode *pErr uint32_t tagNum = getTagNumber(standard); /* Make a quick guess. Hopefully they used a TR22 canonical alias. */ - convNum = findConverter(alias, &myErr); + convNum = findConverter(alias, NULL, &myErr); if (myErr != U_ZERO_ERROR) { *pErrorCode = myErr; } @@ -615,9 +626,9 @@ findTaggedConverterNum(const char *alias, const char *standard, UErrorCode *pErr U_CFUNC const char * -ucnv_io_getConverterName(const char *alias, UErrorCode *pErrorCode) { +ucnv_io_getConverterName(const char *alias, UBool *containsOption, UErrorCode *pErrorCode) { if(haveAliasData(pErrorCode) && isAlias(alias, pErrorCode)) { - uint32_t convNum = findConverter(alias, pErrorCode); + uint32_t convNum = findConverter(alias, containsOption, pErrorCode); if (convNum < gMainTable.converterListSize) { return GET_STRING(gMainTable.converterList[convNum]); } @@ -724,7 +735,7 @@ ucnv_openStandardNames(const char *convName, static uint16_t ucnv_io_countAliases(const char *alias, UErrorCode *pErrorCode) { if(haveAliasData(pErrorCode) && isAlias(alias, pErrorCode)) { - uint32_t convNum = findConverter(alias, pErrorCode); + uint32_t convNum = findConverter(alias, NULL, pErrorCode); if (convNum < gMainTable.converterListSize) { /* tagListNum - 1 is the ALL tag */ int32_t listOffset = gMainTable.taggedAliasArray[(gMainTable.tagListSize - 1)*gMainTable.converterListSize + convNum]; @@ -743,7 +754,7 @@ static uint16_t ucnv_io_getAliases(const char *alias, uint16_t start, const char **aliases, UErrorCode *pErrorCode) { if(haveAliasData(pErrorCode) && isAlias(alias, pErrorCode)) { uint32_t currAlias; - uint32_t convNum = findConverter(alias, pErrorCode); + uint32_t convNum = findConverter(alias, NULL, pErrorCode); if (convNum < gMainTable.converterListSize) { /* tagListNum - 1 is the ALL tag */ int32_t listOffset = gMainTable.taggedAliasArray[(gMainTable.tagListSize - 1)*gMainTable.converterListSize + convNum]; @@ -767,7 +778,7 @@ ucnv_io_getAliases(const char *alias, uint16_t start, const char **aliases, UErr static const char * ucnv_io_getAlias(const char *alias, uint16_t n, UErrorCode *pErrorCode) { if(haveAliasData(pErrorCode) && isAlias(alias, pErrorCode)) { - uint32_t convNum = findConverter(alias, pErrorCode); + uint32_t convNum = findConverter(alias, NULL, pErrorCode); if (convNum < gMainTable.converterListSize) { /* tagListNum - 1 is the ALL tag */ int32_t listOffset = gMainTable.taggedAliasArray[(gMainTable.tagListSize - 1)*gMainTable.converterListSize + convNum]; diff --git a/icu4c/source/common/ucnv_io.h b/icu4c/source/common/ucnv_io.h index 49e6eba854c..c45f904745d 100644 --- a/icu4c/source/common/ucnv_io.h +++ b/icu4c/source/common/ucnv_io.h @@ -20,6 +20,7 @@ #include "udataswp.h" #define UCNV_AMBIGUOUS_ALIAS_MAP_BIT 0x8000 +#define UCNV_CONTAINS_OPTION_BIT 0x4000 #define UCNV_CONVERTER_INDEX_MASK 0xFFF #define UCNV_NUM_RESERVED_TAGS 2 #define UCNV_NUM_HIDDEN_TAGS 1 @@ -32,6 +33,7 @@ typedef enum { typedef struct { uint16_t stringNormalizationType; + uint16_t containsCnvOptionInfo; } UConverterAliasOptions; typedef struct UConverterAlias { @@ -85,11 +87,12 @@ ucnv_io_stripEBCDICForCompare(char *dst, const char *name); * is returned in mixed-case. * Returns NULL if the alias is not found. * @param alias The alias name to be searched. + * @param containsOption A return value stating whether the returned converter name contains an option (a comma) * @param pErrorCode The error code * @return the converter name in mixed-case, return NULL if the alias is not found. */ U_CFUNC const char * -ucnv_io_getConverterName(const char *alias, UErrorCode *pErrorCode); +ucnv_io_getConverterName(const char *alias, UBool *containsOption, UErrorCode *pErrorCode); /** * Return the number of all aliases and converter names. diff --git a/icu4c/source/tools/gencnval/gencnval.c b/icu4c/source/tools/gencnval/gencnval.c index a56d7ef4ba1..dddd3ade1b6 100644 --- a/icu4c/source/tools/gencnval/gencnval.c +++ b/icu4c/source/tools/gencnval/gencnval.c @@ -138,7 +138,8 @@ static UBool verbose = FALSE; static int lineNum = 1; static UConverterAliasOptions tableOptions = { - UCNV_IO_UNNORMALIZED + UCNV_IO_UNNORMALIZED, + 1 /* containsCnvOptionInfo */ }; /* prototypes --------------------------------------------------------------- */ @@ -880,6 +881,9 @@ resolveAliases(uint16_t *uniqueAliasArr, uint16_t *uniqueAliasToConverterArr, ui oldTagNum = currTagNum; /*printf("%s -> %s\n", GET_ALIAS_STR(knownAliases[idx]), GET_ALIAS_STR(converters[currConvNum].converter));*/ } + if (uprv_strchr(GET_ALIAS_STR(converters[currConvNum].converter), UCNV_OPTION_SEP_CHAR) != NULL) { + uniqueAliasToConverterArr[uniqueAliasIdx-1] |= UCNV_CONTAINS_OPTION_BIT; + } } return uniqueAliasIdx; }