mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-04 21:15:35 +00:00
ICU-22696 Update ulocimp_to*{Key,Type}() to use std::string_view.
This commit is contained in:
parent
1eb0ed2fad
commit
8a6d59ec80
6 changed files with 226 additions and 169 deletions
|
@ -1,6 +1,8 @@
|
|||
// © 2019 and later: Unicode, Inc. and others.
|
||||
// License & terms of use: http://www.unicode.org/copyright.html
|
||||
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include "bytesinkutil.h" // StringByteSink<CharString>
|
||||
|
@ -162,12 +164,15 @@ _isKeywordValue(const char* key, const char* value, int32_t value_len)
|
|||
// otherwise: unicode extension value
|
||||
// We need to convert from legacy key/value to unicode
|
||||
// key/value
|
||||
const char* unicode_locale_key = uloc_toUnicodeLocaleKey(key);
|
||||
const char* unicode_locale_type = uloc_toUnicodeLocaleType(key, value);
|
||||
std::optional<std::string_view> unicode_locale_key = ulocimp_toBcpKeyWithFallback(key);
|
||||
std::optional<std::string_view> unicode_locale_type = ulocimp_toBcpTypeWithFallback(key, value);
|
||||
|
||||
return unicode_locale_key && unicode_locale_type &&
|
||||
ultag_isUnicodeLocaleKey(unicode_locale_key, -1) &&
|
||||
ultag_isUnicodeLocaleType(unicode_locale_type, -1);
|
||||
return unicode_locale_key.has_value() &&
|
||||
unicode_locale_type.has_value() &&
|
||||
ultag_isUnicodeLocaleKey(unicode_locale_key->data(),
|
||||
static_cast<int32_t>(unicode_locale_key->size())) &&
|
||||
ultag_isUnicodeLocaleType(unicode_locale_type->data(),
|
||||
static_cast<int32_t>(unicode_locale_type->size()));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include "unicode/bytestream.h"
|
||||
|
@ -1570,8 +1572,8 @@ AliasReplacer::replaceTransformedExtensions(
|
|||
// Split the "tkey-tvalue" pair string so that we can canonicalize the tvalue.
|
||||
*const_cast<char*>(tvalue++) = '\0'; // NUL terminate tkey
|
||||
output.append(tfield, status).append('-', status);
|
||||
const char* bcpTValue = ulocimp_toBcpType(tfield, tvalue);
|
||||
output.append((bcpTValue == nullptr) ? tvalue : bcpTValue, status);
|
||||
std::optional<std::string_view> bcpTValue = ulocimp_toBcpType(tfield, tvalue);
|
||||
output.append(bcpTValue.has_value() ? *bcpTValue : tvalue, status);
|
||||
}
|
||||
}
|
||||
if (U_FAILURE(status)) {
|
||||
|
@ -2608,33 +2610,26 @@ Locale::getUnicodeKeywordValue(StringPiece keywordName,
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO: Remove the need for a const char* to a NUL terminated buffer.
|
||||
const CharString keywordName_nul(keywordName, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char* legacy_key = uloc_toLegacyKey(keywordName_nul.data());
|
||||
if (legacy_key == nullptr) {
|
||||
std::optional<std::string_view> legacy_key = ulocimp_toLegacyKeyWithFallback(keywordName);
|
||||
if (!legacy_key.has_value()) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
auto legacy_value = getKeywordValue<CharString>(legacy_key, status);
|
||||
auto legacy_value = getKeywordValue<CharString>(*legacy_key, status);
|
||||
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char* unicode_value = uloc_toUnicodeLocaleType(
|
||||
keywordName_nul.data(), legacy_value.data());
|
||||
|
||||
if (unicode_value == nullptr) {
|
||||
std::optional<std::string_view> unicode_value =
|
||||
ulocimp_toBcpTypeWithFallback(keywordName, legacy_value.toStringPiece());
|
||||
if (!unicode_value.has_value()) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
sink.Append(unicode_value, static_cast<int32_t>(uprv_strlen(unicode_value)));
|
||||
sink.Append(unicode_value->data(), static_cast<int32_t>(unicode_value->size()));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2699,32 +2694,25 @@ Locale::setUnicodeKeywordValue(StringPiece keywordName,
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO: Remove the need for a const char* to a NUL terminated buffer.
|
||||
const CharString keywordName_nul(keywordName, status);
|
||||
const CharString keywordValue_nul(keywordValue, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char* legacy_key = uloc_toLegacyKey(keywordName_nul.data());
|
||||
if (legacy_key == nullptr) {
|
||||
std::optional<std::string_view> legacy_key = ulocimp_toLegacyKeyWithFallback(keywordName);
|
||||
if (!legacy_key.has_value()) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
const char* legacy_value = nullptr;
|
||||
std::string_view value;
|
||||
|
||||
if (!keywordValue_nul.isEmpty()) {
|
||||
legacy_value =
|
||||
uloc_toLegacyType(keywordName_nul.data(), keywordValue_nul.data());
|
||||
|
||||
if (legacy_value == nullptr) {
|
||||
if (!keywordValue.empty()) {
|
||||
std::optional<std::string_view> legacy_value =
|
||||
ulocimp_toLegacyTypeWithFallback(keywordName, keywordValue);
|
||||
if (!legacy_value.has_value()) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return;
|
||||
}
|
||||
value = *legacy_value;
|
||||
}
|
||||
|
||||
setKeywordValue(legacy_key, legacy_value, status);
|
||||
setKeywordValue(*legacy_key, value, status);
|
||||
}
|
||||
|
||||
const char *
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
l = lang, C = ctry, M = charmap, V = variant
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
|
@ -2291,8 +2292,17 @@ uloc_getISOCountries()
|
|||
U_CAPI const char* U_EXPORT2
|
||||
uloc_toUnicodeLocaleKey(const char* keyword)
|
||||
{
|
||||
const char* bcpKey = ulocimp_toBcpKey(keyword);
|
||||
if (bcpKey == nullptr && ultag_isUnicodeLocaleKey(keyword, -1)) {
|
||||
if (keyword == nullptr || *keyword == '\0') { return nullptr; }
|
||||
std::optional<std::string_view> result = ulocimp_toBcpKeyWithFallback(keyword);
|
||||
return result.has_value() ? result->data() : nullptr; // Known to be NUL terminated.
|
||||
}
|
||||
|
||||
U_EXPORT std::optional<std::string_view>
|
||||
ulocimp_toBcpKeyWithFallback(std::string_view keyword)
|
||||
{
|
||||
std::optional<std::string_view> bcpKey = ulocimp_toBcpKey(keyword);
|
||||
if (!bcpKey.has_value() &&
|
||||
ultag_isUnicodeLocaleKey(keyword.data(), static_cast<int32_t>(keyword.size()))) {
|
||||
// unknown keyword, but syntax is fine..
|
||||
return keyword;
|
||||
}
|
||||
|
@ -2302,8 +2312,18 @@ uloc_toUnicodeLocaleKey(const char* keyword)
|
|||
U_CAPI const char* U_EXPORT2
|
||||
uloc_toUnicodeLocaleType(const char* keyword, const char* value)
|
||||
{
|
||||
const char* bcpType = ulocimp_toBcpType(keyword, value);
|
||||
if (bcpType == nullptr && ultag_isUnicodeLocaleType(value, -1)) {
|
||||
if (keyword == nullptr || *keyword == '\0' ||
|
||||
value == nullptr || *value == '\0') { return nullptr; }
|
||||
std::optional<std::string_view> result = ulocimp_toBcpTypeWithFallback(keyword, value);
|
||||
return result.has_value() ? result->data() : nullptr; // Known to be NUL terminated.
|
||||
}
|
||||
|
||||
U_EXPORT std::optional<std::string_view>
|
||||
ulocimp_toBcpTypeWithFallback(std::string_view keyword, std::string_view value)
|
||||
{
|
||||
std::optional<std::string_view> bcpType = ulocimp_toBcpType(keyword, value);
|
||||
if (!bcpType.has_value() &&
|
||||
ultag_isUnicodeLocaleType(value.data(), static_cast<int32_t>(value.size()))) {
|
||||
// unknown keyword, but syntax is fine..
|
||||
return value;
|
||||
}
|
||||
|
@ -2313,37 +2333,28 @@ uloc_toUnicodeLocaleType(const char* keyword, const char* value)
|
|||
namespace {
|
||||
|
||||
bool
|
||||
isWellFormedLegacyKey(const char* legacyKey)
|
||||
isWellFormedLegacyKey(std::string_view key)
|
||||
{
|
||||
const char* p = legacyKey;
|
||||
while (*p) {
|
||||
if (!UPRV_ISALPHANUM(*p)) {
|
||||
return false;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return true;
|
||||
return std::all_of(key.begin(), key.end(), UPRV_ISALPHANUM);
|
||||
}
|
||||
|
||||
bool
|
||||
isWellFormedLegacyType(const char* legacyType)
|
||||
isWellFormedLegacyType(std::string_view legacyType)
|
||||
{
|
||||
const char* p = legacyType;
|
||||
int32_t alphaNumLen = 0;
|
||||
while (*p) {
|
||||
if (*p == '_' || *p == '/' || *p == '-') {
|
||||
for (char c : legacyType) {
|
||||
if (c == '_' || c == '/' || c == '-') {
|
||||
if (alphaNumLen == 0) {
|
||||
return false;
|
||||
}
|
||||
alphaNumLen = 0;
|
||||
} else if (UPRV_ISALPHANUM(*p)) {
|
||||
} else if (UPRV_ISALPHANUM(c)) {
|
||||
alphaNumLen++;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return (alphaNumLen != 0);
|
||||
return alphaNumLen != 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -2351,8 +2362,16 @@ isWellFormedLegacyType(const char* legacyType)
|
|||
U_CAPI const char* U_EXPORT2
|
||||
uloc_toLegacyKey(const char* keyword)
|
||||
{
|
||||
const char* legacyKey = ulocimp_toLegacyKey(keyword);
|
||||
if (legacyKey == nullptr) {
|
||||
if (keyword == nullptr || *keyword == '\0') { return nullptr; }
|
||||
std::optional<std::string_view> result = ulocimp_toLegacyKeyWithFallback(keyword);
|
||||
return result.has_value() ? result->data() : nullptr; // Known to be NUL terminated.
|
||||
}
|
||||
|
||||
U_EXPORT std::optional<std::string_view>
|
||||
ulocimp_toLegacyKeyWithFallback(std::string_view keyword)
|
||||
{
|
||||
std::optional<std::string_view> legacyKey = ulocimp_toLegacyKey(keyword);
|
||||
if (!legacyKey.has_value() && isWellFormedLegacyKey(keyword)) {
|
||||
// Checks if the specified locale key is well-formed with the legacy locale syntax.
|
||||
//
|
||||
// Note:
|
||||
|
@ -2360,9 +2379,7 @@ uloc_toLegacyKey(const char* keyword)
|
|||
// * http://www.unicode.org/reports/tr35/#Unicode_locale_identifier and
|
||||
// * http://www.unicode.org/reports/tr35/#Old_Locale_Extension_Syntax
|
||||
// Keys can only consist of [0-9a-zA-Z].
|
||||
if (isWellFormedLegacyKey(keyword)) {
|
||||
return keyword;
|
||||
}
|
||||
return keyword;
|
||||
}
|
||||
return legacyKey;
|
||||
}
|
||||
|
@ -2370,8 +2387,17 @@ uloc_toLegacyKey(const char* keyword)
|
|||
U_CAPI const char* U_EXPORT2
|
||||
uloc_toLegacyType(const char* keyword, const char* value)
|
||||
{
|
||||
const char* legacyType = ulocimp_toLegacyType(keyword, value);
|
||||
if (legacyType == nullptr) {
|
||||
if (keyword == nullptr || *keyword == '\0' ||
|
||||
value == nullptr || *value == '\0') { return nullptr; }
|
||||
std::optional<std::string_view> result = ulocimp_toLegacyTypeWithFallback(keyword, value);
|
||||
return result.has_value() ? result->data() : nullptr; // Known to be NUL terminated.
|
||||
}
|
||||
|
||||
U_EXPORT std::optional<std::string_view>
|
||||
ulocimp_toLegacyTypeWithFallback(std::string_view keyword, std::string_view value)
|
||||
{
|
||||
std::optional<std::string_view> legacyType = ulocimp_toLegacyType(keyword, value);
|
||||
if (!legacyType.has_value() && isWellFormedLegacyType(value)) {
|
||||
// Checks if the specified locale type is well-formed with the legacy locale syntax.
|
||||
//
|
||||
// Note:
|
||||
|
@ -2380,9 +2406,7 @@ uloc_toLegacyType(const char* keyword, const char* value)
|
|||
// * http://www.unicode.org/reports/tr35/#Old_Locale_Extension_Syntax
|
||||
// Values (types) can only consist of [0-9a-zA-Z], plus for legacy values
|
||||
// we allow [/_-+] in the middle (e.g. "Etc/GMT+1", "Asia/Tel_Aviv")
|
||||
if (isWellFormedLegacyType(value)) {
|
||||
return value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
return legacyType;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
**********************************************************************
|
||||
*/
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
#include "unicode/unistr.h"
|
||||
|
@ -18,6 +20,7 @@
|
|||
#include "uassert.h"
|
||||
#include "ucln_cmn.h"
|
||||
#include "uhash.h"
|
||||
#include "ulocimp.h"
|
||||
#include "umutex.h"
|
||||
#include "uresimp.h"
|
||||
#include "uvector.h"
|
||||
|
@ -35,20 +38,25 @@ typedef enum {
|
|||
} SpecialType;
|
||||
|
||||
struct LocExtKeyData : public icu::UMemory {
|
||||
const char* legacyId;
|
||||
const char* bcpId;
|
||||
std::string_view legacyId;
|
||||
std::string_view bcpId;
|
||||
icu::LocalUHashtablePointer typeMap;
|
||||
uint32_t specialTypes;
|
||||
};
|
||||
|
||||
struct LocExtType : public icu::UMemory {
|
||||
const char* legacyId;
|
||||
const char* bcpId;
|
||||
std::string_view legacyId;
|
||||
std::string_view bcpId;
|
||||
};
|
||||
|
||||
struct TypeAlias : public icu::UMemory {
|
||||
std::string_view from;
|
||||
};
|
||||
|
||||
static icu::MemoryPool<icu::CharString>* gKeyTypeStringPool = nullptr;
|
||||
static icu::MemoryPool<LocExtKeyData>* gLocExtKeyDataEntries = nullptr;
|
||||
static icu::MemoryPool<LocExtType>* gLocExtTypeEntries = nullptr;
|
||||
static icu::MemoryPool<TypeAlias>* gTypeAliasEntries = nullptr;
|
||||
|
||||
U_CDECL_BEGIN
|
||||
|
||||
|
@ -65,6 +73,9 @@ uloc_key_type_cleanup() {
|
|||
delete gLocExtTypeEntries;
|
||||
gLocExtTypeEntries = nullptr;
|
||||
|
||||
delete gTypeAliasEntries;
|
||||
gTypeAliasEntries = nullptr;
|
||||
|
||||
delete gKeyTypeStringPool;
|
||||
gKeyTypeStringPool = nullptr;
|
||||
|
||||
|
@ -81,7 +92,7 @@ initFromResourceBundle(UErrorCode& sts) {
|
|||
U_NAMESPACE_USE
|
||||
ucln_common_registerCleanup(UCLN_COMMON_LOCALE_KEY_TYPE, uloc_key_type_cleanup);
|
||||
|
||||
gLocExtKeyMap = uhash_open(uhash_hashIChars, uhash_compareIChars, nullptr, &sts);
|
||||
gLocExtKeyMap = uhash_open(uhash_hashIStringView, uhash_compareIStringView, nullptr, &sts);
|
||||
|
||||
LocalUResourceBundlePointer keyTypeDataRes(ures_openDirect(nullptr, "keyTypeData", &sts));
|
||||
LocalUResourceBundlePointer keyMapRes(ures_getByKey(keyTypeDataRes.getAlias(), "keyMap", nullptr, &sts));
|
||||
|
@ -112,6 +123,11 @@ initFromResourceBundle(UErrorCode& sts) {
|
|||
sts = U_MEMORY_ALLOCATION_ERROR;
|
||||
return;
|
||||
}
|
||||
gTypeAliasEntries = new icu::MemoryPool<TypeAlias>;
|
||||
if (gTypeAliasEntries == nullptr) {
|
||||
sts = U_MEMORY_ALLOCATION_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
// iterate through keyMap resource
|
||||
LocalUResourceBundlePointer keyMapEntry;
|
||||
|
@ -144,7 +160,7 @@ initFromResourceBundle(UErrorCode& sts) {
|
|||
|
||||
bool isTZ = uprv_strcmp(legacyKeyId, "timezone") == 0;
|
||||
|
||||
UHashtable* typeDataMap = uhash_open(uhash_hashIChars, uhash_compareIChars, nullptr, &sts);
|
||||
UHashtable* typeDataMap = uhash_open(uhash_hashIStringView, uhash_compareIStringView, nullptr, &sts);
|
||||
if (U_FAILURE(sts)) {
|
||||
break;
|
||||
}
|
||||
|
@ -253,10 +269,10 @@ initFromResourceBundle(UErrorCode& sts) {
|
|||
t->bcpId = bcpTypeId;
|
||||
t->legacyId = legacyTypeId;
|
||||
|
||||
uhash_put(typeDataMap, (void*)legacyTypeId, t, &sts);
|
||||
uhash_put(typeDataMap, &t->legacyId, t, &sts);
|
||||
if (bcpTypeId != legacyTypeId) {
|
||||
// different type value
|
||||
uhash_put(typeDataMap, (void*)bcpTypeId, t, &sts);
|
||||
uhash_put(typeDataMap, &t->bcpId, t, &sts);
|
||||
}
|
||||
if (U_FAILURE(sts)) {
|
||||
break;
|
||||
|
@ -275,8 +291,14 @@ initFromResourceBundle(UErrorCode& sts) {
|
|||
break;
|
||||
}
|
||||
// check if this is an alias of canonical legacy type
|
||||
if (uprv_compareInvWithUChar(nullptr, legacyTypeId, -1, to, toLen) == 0) {
|
||||
if (uprv_compareInvWithUChar(
|
||||
nullptr,
|
||||
t->legacyId.data(),
|
||||
static_cast<int32_t>(t->legacyId.size()),
|
||||
to,
|
||||
toLen) == 0) {
|
||||
const char* from = ures_getKey(typeAliasDataEntry.getAlias());
|
||||
TypeAlias* alias = gTypeAliasEntries->create(TypeAlias{{}, from});
|
||||
if (isTZ) {
|
||||
// replace colon with slash if necessary
|
||||
if (uprv_strchr(from, ':') != nullptr) {
|
||||
|
@ -293,10 +315,10 @@ initFromResourceBundle(UErrorCode& sts) {
|
|||
fromBuf->data(),
|
||||
fromBuf->data() + fromBuf->length(),
|
||||
':', '/');
|
||||
from = fromBuf->data();
|
||||
alias->from = fromBuf->toStringPiece();
|
||||
}
|
||||
}
|
||||
uhash_put(typeDataMap, (void*)from, t, &sts);
|
||||
uhash_put(typeDataMap, &alias->from, t, &sts);
|
||||
}
|
||||
}
|
||||
if (U_FAILURE(sts)) {
|
||||
|
@ -316,9 +338,15 @@ initFromResourceBundle(UErrorCode& sts) {
|
|||
break;
|
||||
}
|
||||
// check if this is an alias of bcp type
|
||||
if (uprv_compareInvWithUChar(nullptr, bcpTypeId, -1, to, toLen) == 0) {
|
||||
if (uprv_compareInvWithUChar(
|
||||
nullptr,
|
||||
t->bcpId.data(),
|
||||
static_cast<int32_t>(t->bcpId.size()),
|
||||
to,
|
||||
toLen) == 0) {
|
||||
const char* from = ures_getKey(bcpTypeAliasDataEntry.getAlias());
|
||||
uhash_put(typeDataMap, (void*)from, t, &sts);
|
||||
TypeAlias* alias = gTypeAliasEntries->create(TypeAlias{{}, from});
|
||||
uhash_put(typeDataMap, &alias->from, t, &sts);
|
||||
}
|
||||
}
|
||||
if (U_FAILURE(sts)) {
|
||||
|
@ -341,10 +369,10 @@ initFromResourceBundle(UErrorCode& sts) {
|
|||
keyData->specialTypes = specialTypes;
|
||||
keyData->typeMap.adoptInstead(typeDataMap);
|
||||
|
||||
uhash_put(gLocExtKeyMap, (void*)legacyKeyId, keyData, &sts);
|
||||
uhash_put(gLocExtKeyMap, &keyData->legacyId, keyData, &sts);
|
||||
if (legacyKeyId != bcpKeyId) {
|
||||
// different key value
|
||||
uhash_put(gLocExtKeyMap, (void*)bcpKeyId, keyData, &sts);
|
||||
uhash_put(gLocExtKeyMap, &keyData->bcpId, keyData, &sts);
|
||||
}
|
||||
if (U_FAILURE(sts)) {
|
||||
break;
|
||||
|
@ -363,100 +391,96 @@ init() {
|
|||
}
|
||||
|
||||
bool
|
||||
isSpecialTypeCodepoints(const char* val) {
|
||||
isSpecialTypeCodepoints(std::string_view val) {
|
||||
int32_t subtagLen = 0;
|
||||
const char* p = val;
|
||||
while (*p) {
|
||||
if (*p == '-') {
|
||||
for (char c : val) {
|
||||
if (c == '-') {
|
||||
if (subtagLen < 4 || subtagLen > 6) {
|
||||
return false;
|
||||
}
|
||||
subtagLen = 0;
|
||||
} else if ((*p >= '0' && *p <= '9') ||
|
||||
(*p >= 'A' && *p <= 'F') || // A-F/a-f are contiguous
|
||||
(*p >= 'a' && *p <= 'f')) { // also in EBCDIC
|
||||
} else if ((c >= '0' && c <= '9') ||
|
||||
(c >= 'A' && c <= 'F') || // A-F/a-f are contiguous
|
||||
(c >= 'a' && c <= 'f')) { // also in EBCDIC
|
||||
subtagLen++;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return (subtagLen >= 4 && subtagLen <= 6);
|
||||
return subtagLen >= 4 && subtagLen <= 6;
|
||||
}
|
||||
|
||||
bool
|
||||
isSpecialTypeReorderCode(const char* val) {
|
||||
isSpecialTypeReorderCode(std::string_view val) {
|
||||
int32_t subtagLen = 0;
|
||||
const char* p = val;
|
||||
while (*p) {
|
||||
if (*p == '-') {
|
||||
for (char c : val) {
|
||||
if (c == '-') {
|
||||
if (subtagLen < 3 || subtagLen > 8) {
|
||||
return false;
|
||||
}
|
||||
subtagLen = 0;
|
||||
} else if (uprv_isASCIILetter(*p)) {
|
||||
} else if (uprv_isASCIILetter(c)) {
|
||||
subtagLen++;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return (subtagLen >=3 && subtagLen <=8);
|
||||
return subtagLen >= 3 && subtagLen <= 8;
|
||||
}
|
||||
|
||||
bool
|
||||
isSpecialTypeRgKeyValue(const char* val) {
|
||||
isSpecialTypeRgKeyValue(std::string_view val) {
|
||||
int32_t subtagLen = 0;
|
||||
const char* p = val;
|
||||
while (*p) {
|
||||
if ( (subtagLen < 2 && uprv_isASCIILetter(*p)) ||
|
||||
(subtagLen >= 2 && (*p == 'Z' || *p == 'z')) ) {
|
||||
for (char c : val) {
|
||||
if ((subtagLen < 2 && uprv_isASCIILetter(c)) ||
|
||||
(subtagLen >= 2 && (c == 'Z' || c == 'z'))) {
|
||||
subtagLen++;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return (subtagLen == 6);
|
||||
return subtagLen == 6;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
U_EXPORT const char*
|
||||
ulocimp_toBcpKey(const char* key) {
|
||||
U_EXPORT std::optional<std::string_view>
|
||||
ulocimp_toBcpKey(std::string_view key) {
|
||||
if (!init()) {
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
LocExtKeyData* keyData = static_cast<LocExtKeyData*>(uhash_get(gLocExtKeyMap, key));
|
||||
LocExtKeyData* keyData = static_cast<LocExtKeyData*>(uhash_get(gLocExtKeyMap, &key));
|
||||
if (keyData != nullptr) {
|
||||
return keyData->bcpId;
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
U_EXPORT const char*
|
||||
ulocimp_toLegacyKey(const char* key) {
|
||||
U_EXPORT std::optional<std::string_view>
|
||||
ulocimp_toLegacyKey(std::string_view key) {
|
||||
if (!init()) {
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
LocExtKeyData* keyData = static_cast<LocExtKeyData*>(uhash_get(gLocExtKeyMap, key));
|
||||
LocExtKeyData* keyData = static_cast<LocExtKeyData*>(uhash_get(gLocExtKeyMap, &key));
|
||||
if (keyData != nullptr) {
|
||||
return keyData->legacyId;
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
U_EXPORT const char*
|
||||
ulocimp_toBcpType(const char* key, const char* type) {
|
||||
U_EXPORT std::optional<std::string_view>
|
||||
ulocimp_toBcpType(std::string_view key, std::string_view type) {
|
||||
if (!init()) {
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
LocExtKeyData* keyData = static_cast<LocExtKeyData*>(uhash_get(gLocExtKeyMap, key));
|
||||
LocExtKeyData* keyData = static_cast<LocExtKeyData*>(uhash_get(gLocExtKeyMap, &key));
|
||||
if (keyData != nullptr) {
|
||||
LocExtType* t = static_cast<LocExtType*>(uhash_get(keyData->typeMap.getAlias(), type));
|
||||
LocExtType* t = static_cast<LocExtType*>(uhash_get(keyData->typeMap.getAlias(), &type));
|
||||
if (t != nullptr) {
|
||||
return t->bcpId;
|
||||
}
|
||||
|
@ -476,19 +500,20 @@ ulocimp_toBcpType(const char* key, const char* type) {
|
|||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
U_EXPORT const char*
|
||||
ulocimp_toLegacyType(const char* key, const char* type) {
|
||||
U_EXPORT std::optional<std::string_view>
|
||||
ulocimp_toLegacyType(std::string_view key, std::string_view type) {
|
||||
if (!init()) {
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
LocExtKeyData* keyData = static_cast<LocExtKeyData*>(uhash_get(gLocExtKeyMap, key));
|
||||
LocExtKeyData* keyData = static_cast<LocExtKeyData*>(uhash_get(gLocExtKeyMap, &key));
|
||||
if (keyData != nullptr) {
|
||||
LocExtType* t = static_cast<LocExtType*>(uhash_get(keyData->typeMap.getAlias(), type));
|
||||
LocExtType* t = static_cast<LocExtType*>(uhash_get(keyData->typeMap.getAlias(), &type));
|
||||
if (t != nullptr) {
|
||||
return t->legacyId;
|
||||
}
|
||||
|
@ -508,5 +533,6 @@ ulocimp_toLegacyType(const char* key, const char* type) {
|
|||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
**********************************************************************
|
||||
*/
|
||||
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include "unicode/bytestream.h"
|
||||
|
@ -1374,27 +1376,28 @@ _appendKeywordsToLanguageTag(const char* localeID, icu::ByteSink& sink, bool str
|
|||
bcpValue = nullptr;
|
||||
}
|
||||
} else if (isBcpUExt) {
|
||||
bcpKey = uloc_toUnicodeLocaleKey(key);
|
||||
if (bcpKey == nullptr) {
|
||||
std::optional<std::string_view> optBcpKey = ulocimp_toBcpKeyWithFallback(key);
|
||||
if (!optBcpKey.has_value()) {
|
||||
if (strict) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
bcpKey = optBcpKey->data();
|
||||
|
||||
/* we've checked buf is null-terminated above */
|
||||
bcpValue = uloc_toUnicodeLocaleType(key, buf.data());
|
||||
if (bcpValue == nullptr) {
|
||||
std::optional<std::string_view> optBcpValue =
|
||||
ulocimp_toBcpTypeWithFallback(key, buf.toStringPiece());
|
||||
if (!optBcpValue.has_value()) {
|
||||
if (strict) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (bcpValue == buf.data()) {
|
||||
if (optBcpValue->data() == buf.data()) {
|
||||
/*
|
||||
When uloc_toUnicodeLocaleType(key, buf) returns the
|
||||
When ulocimp_toBcpTypeWithFallback(key, buf) returns the
|
||||
input value as is, the value is well-formed, but has
|
||||
no known mapping. This implementation normalizes the
|
||||
value to lower case
|
||||
|
@ -1412,6 +1415,8 @@ _appendKeywordsToLanguageTag(const char* localeID, icu::ByteSink& sink, bool str
|
|||
|
||||
T_CString_toLowerCase(extBuf->data());
|
||||
bcpValue = extBuf->data();
|
||||
} else {
|
||||
bcpValue = optBcpValue->data();
|
||||
}
|
||||
} else {
|
||||
if (*key == PRIVATEUSE) {
|
||||
|
@ -1669,33 +1674,28 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT
|
|||
const char *pKey = nullptr; /* LDML key */
|
||||
const char *pType = nullptr; /* LDML type */
|
||||
|
||||
char bcpKeyBuf[3]; /* BCP key length is always 2 for now */
|
||||
|
||||
U_ASSERT(pBcpKey != nullptr);
|
||||
|
||||
if (bcpKeyLen >= static_cast<int32_t>(sizeof(bcpKeyBuf))) {
|
||||
/* BCP key length is always 2 for now */
|
||||
if (bcpKeyLen != 2) {
|
||||
/* the BCP key is invalid */
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return;
|
||||
}
|
||||
U_ASSERT(bcpKeyLen <= 2);
|
||||
|
||||
uprv_strncpy(bcpKeyBuf, pBcpKey, bcpKeyLen);
|
||||
bcpKeyBuf[bcpKeyLen] = 0;
|
||||
|
||||
/* u extension key to LDML key */
|
||||
pKey = uloc_toLegacyKey(bcpKeyBuf);
|
||||
if (pKey == nullptr) {
|
||||
std::optional<std::string_view> legacyKey = ulocimp_toLegacyKeyWithFallback(
|
||||
{pBcpKey, static_cast<std::string_view::size_type>(bcpKeyLen)});
|
||||
if (!legacyKey.has_value()) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return;
|
||||
}
|
||||
if (pKey == bcpKeyBuf) {
|
||||
if (legacyKey->data() == pBcpKey) {
|
||||
/*
|
||||
The key returned by toLegacyKey points to the input buffer.
|
||||
We normalize the result key to lower case.
|
||||
*/
|
||||
T_CString_toLowerCase(bcpKeyBuf);
|
||||
icu::CharString* key = kwdBuf.create(bcpKeyBuf, bcpKeyLen, status);
|
||||
icu::CharString* key = kwdBuf.create(pBcpKey, bcpKeyLen, status);
|
||||
if (key == nullptr) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return;
|
||||
|
@ -1703,36 +1703,37 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT
|
|||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
T_CString_toLowerCase(key->data());
|
||||
pKey = key->data();
|
||||
} else {
|
||||
pKey = legacyKey->data();
|
||||
}
|
||||
|
||||
if (pBcpType) {
|
||||
icu::CharString bcpTypeBuf(pBcpType, bcpTypeLen, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* BCP type to locale type */
|
||||
pType = uloc_toLegacyType(pKey, bcpTypeBuf.data());
|
||||
if (pType == nullptr) {
|
||||
std::optional<std::string_view> legacyType = ulocimp_toLegacyTypeWithFallback(
|
||||
pKey, {pBcpType, static_cast<std::string_view::size_type>(bcpTypeLen)});
|
||||
if (!legacyType.has_value()) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return;
|
||||
}
|
||||
if (pType == bcpTypeBuf.data()) {
|
||||
if (legacyType->data() == pBcpType) {
|
||||
/*
|
||||
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.data());
|
||||
if (icu::CharString* type =
|
||||
kwdBuf.create(std::move(bcpTypeBuf), status)) {
|
||||
if (U_FAILURE(status)) { return; }
|
||||
pType = type->data();
|
||||
} else {
|
||||
icu::CharString* type = kwdBuf.create(pBcpType, bcpTypeLen, status);
|
||||
if (type == nullptr) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return;
|
||||
}
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
T_CString_toLowerCase(type->data());
|
||||
pType = type->data();
|
||||
} else {
|
||||
pType = legacyType->data();
|
||||
}
|
||||
} else {
|
||||
/* typeless - default type value is "yes" */
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#define ULOCIMP_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "unicode/bytestream.h"
|
||||
|
@ -54,6 +55,18 @@ uloc_getCurrentCountryID(const char* oldID);
|
|||
U_CFUNC const char*
|
||||
uloc_getCurrentLanguageID(const char* oldID);
|
||||
|
||||
U_EXPORT std::optional<std::string_view>
|
||||
ulocimp_toBcpKeyWithFallback(std::string_view keyword);
|
||||
|
||||
U_EXPORT std::optional<std::string_view>
|
||||
ulocimp_toBcpTypeWithFallback(std::string_view keyword, std::string_view value);
|
||||
|
||||
U_EXPORT std::optional<std::string_view>
|
||||
ulocimp_toLegacyKeyWithFallback(std::string_view keyword);
|
||||
|
||||
U_EXPORT std::optional<std::string_view>
|
||||
ulocimp_toLegacyTypeWithFallback(std::string_view keyword, std::string_view value);
|
||||
|
||||
U_EXPORT icu::CharString
|
||||
ulocimp_getKeywords(const char* localeID,
|
||||
char prev,
|
||||
|
@ -392,17 +405,17 @@ ultag_isVariantSubtags(const char* s, int32_t len);
|
|||
const char*
|
||||
ultag_getTKeyStart(const char* localeID);
|
||||
|
||||
U_EXPORT const char*
|
||||
ulocimp_toBcpKey(const char* key);
|
||||
U_EXPORT std::optional<std::string_view>
|
||||
ulocimp_toBcpKey(std::string_view key);
|
||||
|
||||
U_EXPORT const char*
|
||||
ulocimp_toLegacyKey(const char* key);
|
||||
U_EXPORT std::optional<std::string_view>
|
||||
ulocimp_toLegacyKey(std::string_view key);
|
||||
|
||||
U_EXPORT const char*
|
||||
ulocimp_toBcpType(const char* key, const char* type);
|
||||
U_EXPORT std::optional<std::string_view>
|
||||
ulocimp_toBcpType(std::string_view key, std::string_view type);
|
||||
|
||||
U_EXPORT const char*
|
||||
ulocimp_toLegacyType(const char* key, const char* type);
|
||||
U_EXPORT std::optional<std::string_view>
|
||||
ulocimp_toLegacyType(std::string_view key, std::string_view type);
|
||||
|
||||
/* Function for testing purpose */
|
||||
U_EXPORT const char* const*
|
||||
|
|
Loading…
Add table
Reference in a new issue