Index: source/common/uloc_tag.c |
diff --git a/source/common/uloc_tag.c b/source/common/uloc_tag.c |
index d40099e5e71df515a6f0c72aa38df57d3ecbab99..c038026790d6a9bc55dc2501034f99568b9c9467 100644 |
--- a/source/common/uloc_tag.c |
+++ b/source/common/uloc_tag.c |
@@ -1,6 +1,6 @@ |
/* |
********************************************************************** |
-* Copyright (C) 2009-2012, International Business Machines |
+* Copyright (C) 2009-2014, International Business Machines |
* Corporation and others. All Rights Reserved. |
********************************************************************** |
*/ |
@@ -17,8 +17,6 @@ |
#include "ulocimp.h" |
#include "uassert.h" |
-#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) |
- |
/* struct holding a single variant */ |
typedef struct VariantListEntry { |
const char *variant; |
@@ -410,8 +408,8 @@ _isPrivateuseValueSubtags(const char* s, int32_t len) { |
return _isPrivateuseValueSubtag(pSubtag, (int32_t)(p - pSubtag)); |
} |
-static UBool |
-_isLDMLKey(const char* s, int32_t len) { |
+U_CFUNC UBool |
+ultag_isUnicodeLocaleKey(const char* s, int32_t len) { |
if (len < 0) { |
len = (int32_t)uprv_strlen(s); |
} |
@@ -421,17 +419,33 @@ _isLDMLKey(const char* s, int32_t len) { |
return FALSE; |
} |
-static UBool |
-_isLDMLType(const char* s, int32_t len) { |
+U_CFUNC UBool |
+ultag_isUnicodeLocaleType(const char*s, int32_t len) { |
+ const char* p; |
+ int32_t subtagLen = 0; |
+ |
if (len < 0) { |
len = (int32_t)uprv_strlen(s); |
} |
- if (len >= 3 && len <= 8 && _isAlphaNumericString(s, len)) { |
- return TRUE; |
+ |
+ for (p = s; len > 0; p++, len--) { |
+ if (*p == SEP) { |
+ if (subtagLen < 3) { |
+ return FALSE; |
+ } |
+ subtagLen = 0; |
+ } else if (ISALPHA(*p) || ISNUMERIC(*p)) { |
+ subtagLen++; |
+ if (subtagLen > 8) { |
+ return FALSE; |
+ } |
+ } else { |
+ return FALSE; |
+ } |
} |
- return FALSE; |
-} |
+ return (subtagLen >= 3); |
+} |
/* |
* ------------------------------------------------- |
* |
@@ -610,386 +624,6 @@ _initializeULanguageTag(ULanguageTag* langtag) { |
langtag->privateuse = EMPTY; |
} |
-#define KEYTYPEDATA "keyTypeData" |
-#define KEYMAP "keyMap" |
-#define TYPEMAP "typeMap" |
-#define TYPEALIAS "typeAlias" |
-#define MAX_BCP47_SUBTAG_LEN 9 /* including null terminator */ |
-#define MAX_LDML_KEY_LEN 22 |
-#define MAX_LDML_TYPE_LEN 32 |
- |
-static int32_t |
-_ldmlKeyToBCP47(const char* key, int32_t keyLen, |
- char* bcpKey, int32_t bcpKeyCapacity, |
- UErrorCode *status) { |
- UResourceBundle *rb; |
- char keyBuf[MAX_LDML_KEY_LEN]; |
- char bcpKeyBuf[MAX_BCP47_SUBTAG_LEN]; |
- int32_t resultLen = 0; |
- int32_t i; |
- UErrorCode tmpStatus = U_ZERO_ERROR; |
- const UChar *uBcpKey; |
- int32_t bcpKeyLen; |
- |
- if (keyLen < 0) { |
- keyLen = (int32_t)uprv_strlen(key); |
- } |
- |
- if (keyLen >= sizeof(keyBuf)) { |
- /* no known valid LDML key exceeding 21 */ |
- *status = U_ILLEGAL_ARGUMENT_ERROR; |
- return 0; |
- } |
- |
- uprv_memcpy(keyBuf, key, keyLen); |
- keyBuf[keyLen] = 0; |
- |
- /* to lower case */ |
- for (i = 0; i < keyLen; i++) { |
- keyBuf[i] = uprv_tolower(keyBuf[i]); |
- } |
- |
- rb = ures_openDirect(NULL, KEYTYPEDATA, status); |
- ures_getByKey(rb, KEYMAP, rb, status); |
- |
- if (U_FAILURE(*status)) { |
- ures_close(rb); |
- return 0; |
- } |
- |
- uBcpKey = ures_getStringByKey(rb, keyBuf, &bcpKeyLen, &tmpStatus); |
- if (U_SUCCESS(tmpStatus)) { |
- u_UCharsToChars(uBcpKey, bcpKeyBuf, bcpKeyLen); |
- bcpKeyBuf[bcpKeyLen] = 0; |
- resultLen = bcpKeyLen; |
- } else { |
- if (_isLDMLKey(key, keyLen)) { |
- uprv_memcpy(bcpKeyBuf, key, keyLen); |
- bcpKeyBuf[keyLen] = 0; |
- resultLen = keyLen; |
- } else { |
- /* mapping not availabe */ |
- *status = U_ILLEGAL_ARGUMENT_ERROR; |
- } |
- } |
- ures_close(rb); |
- |
- if (U_FAILURE(*status)) { |
- return 0; |
- } |
- |
- uprv_memcpy(bcpKey, bcpKeyBuf, uprv_min(resultLen, bcpKeyCapacity)); |
- return u_terminateChars(bcpKey, bcpKeyCapacity, resultLen, status); |
-} |
- |
-static int32_t |
-_bcp47ToLDMLKey(const char* bcpKey, int32_t bcpKeyLen, |
- char* key, int32_t keyCapacity, |
- UErrorCode *status) { |
- UResourceBundle *rb; |
- char bcpKeyBuf[MAX_BCP47_SUBTAG_LEN]; |
- int32_t resultLen = 0; |
- int32_t i; |
- const char *resKey = NULL; |
- UResourceBundle *mapData; |
- |
- if (bcpKeyLen < 0) { |
- bcpKeyLen = (int32_t)uprv_strlen(bcpKey); |
- } |
- |
- if (bcpKeyLen >= sizeof(bcpKeyBuf)) { |
- *status = U_ILLEGAL_ARGUMENT_ERROR; |
- return 0; |
- } |
- |
- uprv_memcpy(bcpKeyBuf, bcpKey, bcpKeyLen); |
- bcpKeyBuf[bcpKeyLen] = 0; |
- |
- /* to lower case */ |
- for (i = 0; i < bcpKeyLen; i++) { |
- bcpKeyBuf[i] = uprv_tolower(bcpKeyBuf[i]); |
- } |
- |
- rb = ures_openDirect(NULL, KEYTYPEDATA, status); |
- ures_getByKey(rb, KEYMAP, rb, status); |
- if (U_FAILURE(*status)) { |
- ures_close(rb); |
- return 0; |
- } |
- |
- mapData = ures_getNextResource(rb, NULL, status); |
- while (U_SUCCESS(*status)) { |
- const UChar *uBcpKey; |
- char tmpBcpKeyBuf[MAX_BCP47_SUBTAG_LEN]; |
- int32_t tmpBcpKeyLen; |
- |
- uBcpKey = ures_getString(mapData, &tmpBcpKeyLen, status); |
- if (U_FAILURE(*status)) { |
- break; |
- } |
- u_UCharsToChars(uBcpKey, tmpBcpKeyBuf, tmpBcpKeyLen); |
- tmpBcpKeyBuf[tmpBcpKeyLen] = 0; |
- if (uprv_compareInvCharsAsAscii(bcpKeyBuf, tmpBcpKeyBuf) == 0) { |
- /* found a matching BCP47 key */ |
- resKey = ures_getKey(mapData); |
- resultLen = (int32_t)uprv_strlen(resKey); |
- break; |
- } |
- if (!ures_hasNext(rb)) { |
- break; |
- } |
- ures_getNextResource(rb, mapData, status); |
- } |
- ures_close(mapData); |
- ures_close(rb); |
- |
- if (U_FAILURE(*status)) { |
- return 0; |
- } |
- |
- if (resKey == NULL) { |
- resKey = bcpKeyBuf; |
- resultLen = bcpKeyLen; |
- } |
- |
- uprv_memcpy(key, resKey, uprv_min(resultLen, keyCapacity)); |
- return u_terminateChars(key, keyCapacity, resultLen, status); |
-} |
- |
-static int32_t |
-_ldmlTypeToBCP47(const char* key, int32_t keyLen, |
- const char* type, int32_t typeLen, |
- char* bcpType, int32_t bcpTypeCapacity, |
- UErrorCode *status) { |
- UResourceBundle *rb, *keyTypeData, *typeMapForKey; |
- char keyBuf[MAX_LDML_KEY_LEN]; |
- char typeBuf[MAX_LDML_TYPE_LEN]; |
- char bcpTypeBuf[MAX_BCP47_SUBTAG_LEN]; |
- int32_t resultLen = 0; |
- int32_t i; |
- UErrorCode tmpStatus = U_ZERO_ERROR; |
- const UChar *uBcpType, *uCanonicalType; |
- int32_t bcpTypeLen, canonicalTypeLen; |
- UBool isTimezone = FALSE; |
- |
- if (keyLen < 0) { |
- keyLen = (int32_t)uprv_strlen(key); |
- } |
- if (keyLen >= sizeof(keyBuf)) { |
- /* no known valid LDML key exceeding 21 */ |
- *status = U_ILLEGAL_ARGUMENT_ERROR; |
- return 0; |
- } |
- uprv_memcpy(keyBuf, key, keyLen); |
- keyBuf[keyLen] = 0; |
- |
- /* to lower case */ |
- for (i = 0; i < keyLen; i++) { |
- keyBuf[i] = uprv_tolower(keyBuf[i]); |
- } |
- if (uprv_compareInvCharsAsAscii(keyBuf, "timezone") == 0) { |
- isTimezone = TRUE; |
- } |
- |
- if (typeLen < 0) { |
- typeLen = (int32_t)uprv_strlen(type); |
- } |
- if (typeLen >= sizeof(typeBuf)) { |
- *status = U_ILLEGAL_ARGUMENT_ERROR; |
- return 0; |
- } |
- |
- if (isTimezone) { |
- /* replace '/' with ':' */ |
- for (i = 0; i < typeLen; i++) { |
- if (*(type + i) == '/') { |
- typeBuf[i] = ':'; |
- } else { |
- typeBuf[i] = *(type + i); |
- } |
- } |
- typeBuf[typeLen] = 0; |
- type = &typeBuf[0]; |
- } |
- |
- keyTypeData = ures_openDirect(NULL, KEYTYPEDATA, status); |
- rb = ures_getByKey(keyTypeData, TYPEMAP, NULL, status); |
- if (U_FAILURE(*status)) { |
- ures_close(rb); |
- ures_close(keyTypeData); |
- return 0; |
- } |
- |
- typeMapForKey = ures_getByKey(rb, keyBuf, NULL, &tmpStatus); |
- uBcpType = ures_getStringByKey(typeMapForKey, type, &bcpTypeLen, &tmpStatus); |
- if (U_SUCCESS(tmpStatus)) { |
- u_UCharsToChars(uBcpType, bcpTypeBuf, bcpTypeLen); |
- resultLen = bcpTypeLen; |
- } else if (tmpStatus == U_MISSING_RESOURCE_ERROR) { |
- /* is this type alias? */ |
- tmpStatus = U_ZERO_ERROR; |
- ures_getByKey(keyTypeData, TYPEALIAS, rb, &tmpStatus); |
- ures_getByKey(rb, keyBuf, rb, &tmpStatus); |
- uCanonicalType = ures_getStringByKey(rb, type, &canonicalTypeLen, &tmpStatus); |
- if (U_SUCCESS(tmpStatus)) { |
- u_UCharsToChars(uCanonicalType, typeBuf, canonicalTypeLen); |
- if (isTimezone) { |
- /* replace '/' with ':' */ |
- for (i = 0; i < canonicalTypeLen; i++) { |
- if (typeBuf[i] == '/') { |
- typeBuf[i] = ':'; |
- } |
- } |
- } |
- typeBuf[canonicalTypeLen] = 0; |
- |
- /* look up the canonical type */ |
- uBcpType = ures_getStringByKey(typeMapForKey, typeBuf, &bcpTypeLen, &tmpStatus); |
- if (U_SUCCESS(tmpStatus)) { |
- u_UCharsToChars(uBcpType, bcpTypeBuf, bcpTypeLen); |
- resultLen = bcpTypeLen; |
- } |
- } |
- if (tmpStatus == U_MISSING_RESOURCE_ERROR) { |
- if (_isLDMLType(type, typeLen)) { |
- uprv_memcpy(bcpTypeBuf, type, typeLen); |
- resultLen = typeLen; |
- } else { |
- /* mapping not availabe */ |
- *status = U_ILLEGAL_ARGUMENT_ERROR; |
- } |
- } |
- } else { |
- *status = tmpStatus; |
- } |
- ures_close(rb); |
- ures_close(typeMapForKey); |
- ures_close(keyTypeData); |
- |
- if (U_FAILURE(*status)) { |
- return 0; |
- } |
- |
- uprv_memcpy(bcpType, bcpTypeBuf, uprv_min(resultLen, bcpTypeCapacity)); |
- return u_terminateChars(bcpType, bcpTypeCapacity, resultLen, status); |
-} |
- |
-static int32_t |
-_bcp47ToLDMLType(const char* key, int32_t keyLen, |
- const char* bcpType, int32_t bcpTypeLen, |
- char* type, int32_t typeCapacity, |
- UErrorCode *status) { |
- UResourceBundle *rb; |
- char keyBuf[MAX_LDML_KEY_LEN]; |
- char bcpTypeBuf[ULOC_KEYWORDS_CAPACITY]; /* ensure buffter is large enough for multiple values (e.g. buddhist-greg) */ |
- int32_t resultLen = 0; |
- int32_t i, typeSize; |
- const char *resType = NULL; |
- UResourceBundle *mapData; |
- UErrorCode tmpStatus = U_ZERO_ERROR; |
- int32_t copyLen; |
- |
- if (keyLen < 0) { |
- keyLen = (int32_t)uprv_strlen(key); |
- } |
- |
- if (keyLen >= sizeof(keyBuf)) { |
- /* no known valid LDML key exceeding 21 */ |
- *status = U_ILLEGAL_ARGUMENT_ERROR; |
- return 0; |
- } |
- uprv_memcpy(keyBuf, key, keyLen); |
- keyBuf[keyLen] = 0; |
- |
- /* to lower case */ |
- for (i = 0; i < keyLen; i++) { |
- keyBuf[i] = uprv_tolower(keyBuf[i]); |
- } |
- |
- |
- if (bcpTypeLen < 0) { |
- bcpTypeLen = (int32_t)uprv_strlen(bcpType); |
- } |
- |
- typeSize = 0; |
- for (i = 0; i < bcpTypeLen; i++) { |
- if (bcpType[i] == SEP) { |
- if (typeSize >= MAX_BCP47_SUBTAG_LEN) { |
- *status = U_ILLEGAL_ARGUMENT_ERROR; |
- return 0; |
- } |
- typeSize = 0; |
- } else { |
- typeSize++; |
- } |
- } |
- |
- uprv_memcpy(bcpTypeBuf, bcpType, bcpTypeLen); |
- bcpTypeBuf[bcpTypeLen] = 0; |
- |
- /* to lower case */ |
- for (i = 0; i < bcpTypeLen; i++) { |
- bcpTypeBuf[i] = uprv_tolower(bcpTypeBuf[i]); |
- } |
- |
- rb = ures_openDirect(NULL, KEYTYPEDATA, status); |
- ures_getByKey(rb, TYPEMAP, rb, status); |
- if (U_FAILURE(*status)) { |
- ures_close(rb); |
- return 0; |
- } |
- |
- ures_getByKey(rb, keyBuf, rb, &tmpStatus); |
- mapData = ures_getNextResource(rb, NULL, &tmpStatus); |
- while (U_SUCCESS(tmpStatus)) { |
- const UChar *uBcpType; |
- char tmpBcpTypeBuf[MAX_BCP47_SUBTAG_LEN]; |
- int32_t tmpBcpTypeLen; |
- |
- uBcpType = ures_getString(mapData, &tmpBcpTypeLen, &tmpStatus); |
- if (U_FAILURE(tmpStatus)) { |
- break; |
- } |
- u_UCharsToChars(uBcpType, tmpBcpTypeBuf, tmpBcpTypeLen); |
- tmpBcpTypeBuf[tmpBcpTypeLen] = 0; |
- if (uprv_compareInvCharsAsAscii(bcpTypeBuf, tmpBcpTypeBuf) == 0) { |
- /* found a matching BCP47 type */ |
- resType = ures_getKey(mapData); |
- resultLen = (int32_t)uprv_strlen(resType); |
- break; |
- } |
- if (!ures_hasNext(rb)) { |
- break; |
- } |
- ures_getNextResource(rb, mapData, &tmpStatus); |
- } |
- ures_close(mapData); |
- ures_close(rb); |
- |
- if (U_FAILURE(tmpStatus) && tmpStatus != U_MISSING_RESOURCE_ERROR) { |
- *status = tmpStatus; |
- return 0; |
- } |
- |
- if (resType == NULL) { |
- resType = bcpTypeBuf; |
- resultLen = bcpTypeLen; |
- } |
- |
- copyLen = uprv_min(resultLen, typeCapacity); |
- uprv_memcpy(type, resType, copyLen); |
- |
- if (uprv_compareInvCharsAsAscii(keyBuf, "timezone") == 0) { |
- for (i = 0; i < copyLen; i++) { |
- if (*(type + i) == ':') { |
- *(type + i) = '/'; |
- } |
- } |
- } |
- |
- return u_terminateChars(type, typeCapacity, resultLen, status); |
-} |
- |
static int32_t |
_appendLanguageToLanguageTag(const char* localeID, char* appendAt, int32_t capacity, UBool strict, UErrorCode* status) { |
char buf[ULOC_LANG_CAPACITY]; |
@@ -1029,7 +663,7 @@ _appendLanguageToLanguageTag(const char* localeID, char* appendAt, int32_t capac |
reslen += LANG_UND_LEN; |
} else { |
/* resolve deprecated */ |
- for (i = 0; i < LENGTHOF(DEPRECATEDLANGS); i += 2) { |
+ for (i = 0; i < UPRV_LENGTHOF(DEPRECATEDLANGS); i += 2) { |
if (uprv_compareInvCharsAsAscii(buf, DEPRECATEDLANGS[i]) == 0) { |
uprv_strcpy(buf, DEPRECATEDLANGS[i + 1]); |
len = (int32_t)uprv_strlen(buf); |
@@ -1282,7 +916,7 @@ _appendKeywordsToLanguageTag(const char* localeID, char* appendAt, int32_t capac |
const char *bcpKey, *bcpValue; |
UErrorCode tmpStatus = U_ZERO_ERROR; |
int32_t keylen; |
- UBool isLDMLKeyword; |
+ UBool isBcpUExt; |
while (TRUE) { |
isAttribute = FALSE; |
@@ -1291,7 +925,8 @@ _appendKeywordsToLanguageTag(const char* localeID, char* appendAt, int32_t capac |
break; |
} |
len = uloc_getKeywordValue(localeID, key, buf, sizeof(buf), &tmpStatus); |
- if (U_FAILURE(tmpStatus)) { |
+ /* buf must be null-terminated */ |
+ if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) { |
if (strict) { |
*status = U_ILLEGAL_ARGUMENT_ERROR; |
break; |
@@ -1302,7 +937,7 @@ _appendKeywordsToLanguageTag(const char* localeID, char* appendAt, int32_t capac |
} |
keylen = (int32_t)uprv_strlen(key); |
- isLDMLKeyword = (keylen > 1); |
+ isBcpUExt = (keylen > 1); |
/* special keyword used for representing Unicode locale attributes */ |
if (uprv_strcmp(key, LOCALE_ATTRIBUTE_KEY) == 0) { |
@@ -1350,36 +985,49 @@ _appendKeywordsToLanguageTag(const char* localeID, char* appendAt, int32_t capac |
} |
} |
} |
- } else if (isLDMLKeyword) { |
- int32_t modKeyLen; |
- |
- /* transform key and value to bcp47 style */ |
- modKeyLen = _ldmlKeyToBCP47(key, keylen, pExtBuf, extBufCapacity, &tmpStatus); |
- if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) { |
+ } else if (isBcpUExt) { |
+ bcpKey = uloc_toUnicodeLocaleKey(key); |
+ if (bcpKey == NULL) { |
if (strict) { |
*status = U_ILLEGAL_ARGUMENT_ERROR; |
break; |
} |
- tmpStatus = U_ZERO_ERROR; |
continue; |
} |
- bcpKey = pExtBuf; |
- pExtBuf += (modKeyLen + 1); |
- extBufCapacity -= (modKeyLen + 1); |
- |
- len = _ldmlTypeToBCP47(key, keylen, buf, len, pExtBuf, extBufCapacity, &tmpStatus); |
- if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) { |
+ /* we've checked buf is null-terminated above */ |
+ bcpValue = uloc_toUnicodeLocaleType(key, buf); |
+ if (bcpValue == NULL) { |
if (strict) { |
*status = U_ILLEGAL_ARGUMENT_ERROR; |
break; |
} |
- tmpStatus = U_ZERO_ERROR; |
continue; |
} |
- bcpValue = pExtBuf; |
- pExtBuf += (len + 1); |
- extBufCapacity -= (len + 1); |
+ if (bcpValue == buf) { |
+ /* |
+ When uloc_toUnicodeLocaleType(key, buf) returns the |
+ input value as is, the value is well-formed, but has |
+ no known mapping. This implementation normalizes the |
+ the value to lower case |
+ */ |
+ int32_t bcpValueLen = uprv_strlen(bcpValue); |
+ if (bcpValueLen < extBufCapacity) { |
+ uprv_strcpy(pExtBuf, bcpValue); |
+ T_CString_toLowerCase(pExtBuf); |
+ |
+ bcpValue = pExtBuf; |
+ |
+ pExtBuf += (bcpValueLen + 1); |
+ extBufCapacity -= (bcpValueLen + 1); |
+ } else { |
+ if (strict) { |
+ *status = U_ILLEGAL_ARGUMENT_ERROR; |
+ break; |
+ } |
+ continue; |
+ } |
+ } |
} else { |
if (*key == PRIVATEUSE) { |
if (!_isPrivateuseValueSubtags(buf, len)) { |
@@ -1571,7 +1219,7 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT |
/* locate next separator char */ |
for (len = 0; *(pTag + len) && *(pTag + len) != SEP; len++); |
- if (_isLDMLKey(pTag, len)) { |
+ if (ultag_isUnicodeLocaleKey(pTag, len)) { |
pKwds = pTag; |
break; |
} |
@@ -1679,7 +1327,7 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT |
/* locate next separator char */ |
for (len = 0; *(pTag + len) && *(pTag + len) != SEP; len++); |
- if (_isLDMLKey(pTag, len)) { |
+ if (ultag_isUnicodeLocaleKey(pTag, len)) { |
if (pBcpKey) { |
emitKeyword = TRUE; |
pNextBcpKey = pTag; |
@@ -1715,28 +1363,78 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT |
const char *pKey = NULL; /* LDML key */ |
const char *pType = NULL; /* LDML type */ |
+ char bcpKeyBuf[9]; /* BCP key length is always 2 for now */ |
+ |
U_ASSERT(pBcpKey != NULL); |
+ if (bcpKeyLen >= sizeof(bcpKeyBuf)) { |
+ /* the BCP key is invalid */ |
+ *status = U_ILLEGAL_ARGUMENT_ERROR; |
+ goto cleanup; |
+ } |
+ |
+ uprv_strncpy(bcpKeyBuf, pBcpKey, bcpKeyLen); |
+ bcpKeyBuf[bcpKeyLen] = 0; |
+ |
/* u extension key to LDML key */ |
- len = _bcp47ToLDMLKey(pBcpKey, bcpKeyLen, buf + bufIdx, bufSize - bufIdx - 1, status); |
- if (U_FAILURE(*status)) { |
+ pKey = uloc_toLegacyKey(bcpKeyBuf); |
+ if (pKey == NULL) { |
+ *status = U_ILLEGAL_ARGUMENT_ERROR; |
goto cleanup; |
} |
- pKey = buf + bufIdx; |
- bufIdx += len; |
- *(buf + bufIdx) = 0; |
- bufIdx++; |
+ if (pKey == bcpKeyBuf) { |
+ /* |
+ The key returned by toLegacyKey points to the input buffer. |
+ We normalize the result key to lower case. |
+ */ |
+ T_CString_toLowerCase(bcpKeyBuf); |
+ if (bufSize - bufIdx - 1 >= bcpKeyLen) { |
+ uprv_memcpy(buf + bufIdx, bcpKeyBuf, bcpKeyLen); |
+ pKey = buf + bufIdx; |
+ bufIdx += bcpKeyLen; |
+ *(buf + bufIdx) = 0; |
+ bufIdx++; |
+ } else { |
+ *status = U_BUFFER_OVERFLOW_ERROR; |
+ goto cleanup; |
+ } |
+ } |
if (pBcpType) { |
+ char bcpTypeBuf[128]; /* practically long enough even considering multiple subtag type */ |
+ if (bcpTypeLen >= sizeof(bcpTypeBuf)) { |
+ /* the BCP type is too long */ |
+ *status = U_ILLEGAL_ARGUMENT_ERROR; |
+ goto cleanup; |
+ } |
+ |
+ uprv_strncpy(bcpTypeBuf, pBcpType, bcpTypeLen); |
+ bcpTypeBuf[bcpTypeLen] = 0; |
+ |
/* BCP type to locale type */ |
- len = _bcp47ToLDMLType(pKey, -1, pBcpType, bcpTypeLen, buf + bufIdx, bufSize - bufIdx - 1, status); |
- if (U_FAILURE(*status)) { |
+ pType = uloc_toLegacyType(pKey, bcpTypeBuf); |
+ if (pType == NULL) { |
+ *status = U_ILLEGAL_ARGUMENT_ERROR; |
goto cleanup; |
} |
- pType = buf + bufIdx; |
- bufIdx += len; |
- *(buf + bufIdx) = 0; |
- bufIdx++; |
+ if (pType == bcpTypeBuf) { |
+ /* |
+ The type returned by toLegacyType points to the input buffer. |
+ We normalize the result type to lower case. |
+ */ |
+ /* normalize to lower case */ |
+ T_CString_toLowerCase(bcpTypeBuf); |
+ if (bufSize - bufIdx - 1 >= bcpTypeLen) { |
+ uprv_memcpy(buf + bufIdx, bcpTypeBuf, bcpTypeLen); |
+ pType = buf + bufIdx; |
+ bufIdx += bcpTypeLen; |
+ *(buf + bufIdx) = 0; |
+ bufIdx++; |
+ } else { |
+ *status = U_BUFFER_OVERFLOW_ERROR; |
+ goto cleanup; |
+ } |
+ } |
} else { |
/* typeless - default type value is "yes" */ |
pType = LOCALE_TYPE_YES; |