diff --git a/intl/icu/source/common/locmap.cpp b/intl/icu/source/common/locmap.cpp index 6d62d8310c..66630bf63d 100644 --- a/intl/icu/source/common/locmap.cpp +++ b/intl/icu/source/common/locmap.cpp @@ -32,18 +32,9 @@ #include "cmemory.h" #include "unicode/uloc.h" -#if U_PLATFORM == U_PF_WINDOWS && defined(_MSC_VER) && (_MSC_VER >= 1500) -/* - * TODO: It seems like we should widen this to - * either U_PLATFORM_USES_ONLY_WIN32_API (includes MinGW) - * or U_PLATFORM_HAS_WIN32_API (includes MinGW and Cygwin) - * but those use gcc and won't have defined(_MSC_VER). - * We might need to #include some Windows header and test for some version macro from there. - * Or call some Windows function and see what it returns. - */ -#define USE_WINDOWS_LCID_MAPPING_API +#if U_PLATFORM_HAS_WIN32_API && UCONFIG_USE_WINDOWS_LCID_MAPPING_API #include -#include +#include // LCIDToLocaleName and LocaleNameToLCID #endif /* @@ -973,7 +964,7 @@ idCmp(const char* id1, const char* id2) /** * Searches for a Windows LCID * - * @param posixid the Posix style locale id. + * @param posixID the Posix style locale id. * @param status gets set to U_ILLEGAL_ARGUMENT_ERROR when the Posix ID has * no equivalent Windows LCID. * @return the LCID @@ -1035,7 +1026,7 @@ getPosixID(const ILcidPosixMap *this_0, uint32_t hostID) // ///////////////////////////////////// */ -#ifdef USE_WINDOWS_LCID_MAPPING_API +#if U_PLATFORM_HAS_WIN32_API && UCONFIG_USE_WINDOWS_LCID_MAPPING_API /* * Various language tags needs to be changed: * quz -> qu @@ -1053,6 +1044,7 @@ getPosixID(const ILcidPosixMap *this_0, uint32_t hostID) } #endif + U_CAPI int32_t uprv_convertToPosix(uint32_t hostid, char *posixID, int32_t posixIDCapacity, UErrorCode* status) { @@ -1061,8 +1053,10 @@ uprv_convertToPosix(uint32_t hostid, char *posixID, int32_t posixIDCapacity, UEr UBool bLookup = TRUE; const char *pPosixID = NULL; -#ifdef USE_WINDOWS_LCID_MAPPING_API - char locName[LOCALE_NAME_MAX_LENGTH] = {}; // ICU name can't be longer than Windows name +#if U_PLATFORM_HAS_WIN32_API && UCONFIG_USE_WINDOWS_LCID_MAPPING_API + static_assert(ULOC_FULLNAME_CAPACITY > LOCALE_NAME_MAX_LENGTH, "Windows locale names have smaller length than ICU locale names."); + + char locName[157]; /* ULOC_FULLNAME_CAPACITY */ // Note: Windows primary lang ID 0x92 in LCID is used for Central Kurdish and // GetLocaleInfo() maps such LCID to "ku". However, CLDR uses "ku" for @@ -1070,47 +1064,37 @@ uprv_convertToPosix(uint32_t hostid, char *posixID, int32_t posixIDCapacity, UEr // use the Windows API to resolve locale ID for this specific case. if ((hostid & 0x3FF) != 0x92) { int32_t tmpLen = 0; - UChar windowsLocaleName[LOCALE_NAME_MAX_LENGTH]; // ULOC_FULLNAME_CAPACITY > LOCALE_NAME_MAX_LENGTH - + char16_t windowsLocaleName[LOCALE_NAME_MAX_LENGTH] = {}; +#define LOCALE_SNAME 0x0000005c // Note: LOCALE_ALLOW_NEUTRAL_NAMES was enabled in Windows7+, prior versions did not handle neutral (no-region) locale names. - tmpLen = LCIDToLocaleName(hostid, (PWSTR)windowsLocaleName, UPRV_LENGTHOF(windowsLocaleName), LOCALE_ALLOW_NEUTRAL_NAMES); + tmpLen = GetLocaleInfoA(hostid, LOCALE_SNAME, (LPSTR)locName, UPRV_LENGTHOF(locName)); if (tmpLen > 1) { - int32_t i = 0; - // Only need to look up in table if have _, eg for de-de_phoneb type alternate sort. - bLookup = FALSE; - for (i = 0; i < UPRV_LENGTHOF(locName); i++) - { - locName[i] = (char)(windowsLocaleName[i]); - - // Windows locale name may contain sorting variant, such as "es-ES_tradnl". - // In such cases, we need special mapping data found in the hardcoded table - // in this source file. - if (windowsLocaleName[i] == L'_') - { - // Keep the base locale, without variant - // TODO: Should these be mapped from _phoneb to @collation=phonebook, etc.? - locName[i] = '\0'; - tmpLen = i; - bLookup = TRUE; - break; - } - else if (windowsLocaleName[i] == L'-') - { - // Windows names use -, ICU uses _ - locName[i] = '_'; - } - else if (windowsLocaleName[i] == L'\0') - { - // No point in doing more work than necessary - break; - } + /* Windows locale name may contain sorting variant, such as "es-ES_tradnl". + In such case, we need special mapping data found in the hardcoded table + in this source file. */ + char *p = uprv_strchr(locName, '_'); + if (p) { + /* Keep the base locale, without variant */ + *p = 0; + tmpLen = uprv_strlen(locName); } - // TODO: Need to understand this better, why isn't it an alias? + else { + /* No hardcoded table lookup necessary */ + bLookup = FALSE; + } + /* Change the tag separator from '-' to '_' */ + p = locName; + while (*p) { + if (*p == '-') { + *p = '_'; + } + p++; + } FIX_LANGUAGE_ID_TAG(locName, tmpLen); pPosixID = locName; } } -#endif // USE_WINDOWS_LCID_MAPPING_API +#endif if (bLookup) { const char *pCandidate = NULL; @@ -1132,7 +1116,7 @@ uprv_convertToPosix(uint32_t hostid, char *posixID, int32_t posixIDCapacity, UEr } if (pPosixID) { - int32_t resLen = static_cast(uprv_strlen(pPosixID)); + int32_t resLen = uprv_strlen(pPosixID); int32_t copyLen = resLen <= posixIDCapacity ? resLen : posixIDCapacity; uprv_memcpy(posixID, pPosixID, copyLen); if (resLen < posixIDCapacity) { @@ -1162,21 +1146,16 @@ uprv_convertToPosix(uint32_t hostid, char *posixID, int32_t posixIDCapacity, UEr // ///////////////////////////////////// */ -U_CAPI uint32_t -uprv_convertToLCIDPlatform(const char* localeID) +/*U_CAPI uint32_t +uprv_convertToLCIDPlatform(const char* localeID, UErrorCode* status) { - // The purpose of this function is to leverage native platform name->lcid + if (U_FAILURE(*status)) { + return 0; + } + + // The purpose of this function is to leverage the Windows platform name->lcid // conversion functionality when available. -#ifdef USE_WINDOWS_LCID_MAPPING_API - DWORD nameLCIDFlags = 0; - UErrorCode myStatus = U_ZERO_ERROR; - - // First check for a Windows name->LCID match, fall through to catch - // ICU special cases, but Windows may know it already. -#if LOCALE_ALLOW_NEUTRAL_NAMES - nameLCIDFlags = LOCALE_ALLOW_NEUTRAL_NAMES; -#endif /* LOCALE_ALLOW_NEUTRAL_NAMES */ - +#if U_PLATFORM_HAS_WIN32_API && UCONFIG_USE_WINDOWS_LCID_MAPPING_API int32_t len; char collVal[ULOC_KEYWORDS_CAPACITY] = {}; char baseName[ULOC_FULLNAME_CAPACITY] = {}; @@ -1185,8 +1164,8 @@ uprv_convertToLCIDPlatform(const char* localeID) // Check any for keywords. if (uprv_strchr(localeID, '@')) { - len = uloc_getKeywordValue(localeID, "collation", collVal, UPRV_LENGTHOF(collVal) - 1, &myStatus); - if (U_SUCCESS(myStatus) && len > 0) + len = uloc_getKeywordValue(localeID, "collation", collVal, UPRV_LENGTHOF(collVal) - 1, status); + if (U_SUCCESS(*status) && len > 0) { // If it contains the keyword collation, return 0 so that the LCID lookup table will be used. return 0; @@ -1194,9 +1173,9 @@ uprv_convertToLCIDPlatform(const char* localeID) else { // If the locale ID contains keywords other than collation, just use the base name. - len = uloc_getBaseName(localeID, baseName, UPRV_LENGTHOF(baseName) - 1, &myStatus); + len = uloc_getBaseName(localeID, baseName, UPRV_LENGTHOF(baseName) - 1, status); - if (U_SUCCESS(myStatus) && len > 0) + if (U_SUCCESS(*status) && len > 0) { baseName[len] = 0; mylocaleID = baseName; @@ -1206,9 +1185,9 @@ uprv_convertToLCIDPlatform(const char* localeID) char asciiBCP47Tag[LOCALE_NAME_MAX_LENGTH] = {}; // this will change it from de_DE@collation=phonebook to de-DE-u-co-phonebk form - (void)uloc_toLanguageTag(mylocaleID, asciiBCP47Tag, UPRV_LENGTHOF(asciiBCP47Tag), FALSE, &myStatus); + (void)uloc_toLanguageTag(mylocaleID, asciiBCP47Tag, UPRV_LENGTHOF(asciiBCP47Tag), FALSE, status); - if (U_SUCCESS(myStatus)) + if (U_SUCCESS(*status)) { // Need it to be UTF-16, not 8-bit wchar_t bcp47Tag[LOCALE_NAME_MAX_LENGTH] = {}; @@ -1230,7 +1209,7 @@ uprv_convertToLCIDPlatform(const char* localeID) { // Ensure it's null terminated bcp47Tag[i] = L'\0'; - LCID lcid = LocaleNameToLCID(bcp47Tag, nameLCIDFlags); + LCID lcid = LocaleNameToLCID(bcp47Tag, LOCALE_ALLOW_NEUTRAL_NAMES); if (lcid > 0) { // Found LCID from windows, return that one, unless its completely ambiguous @@ -1244,12 +1223,12 @@ uprv_convertToLCIDPlatform(const char* localeID) } } #else - (void)localeID; // Suppress unused variable warning. -#endif /* USE_WINDOWS_LCID_MAPPING_API */ + (void) localeID; // Suppress unused variable warning. +#endif - // No found, or not implemented on platforms without native name->lcid conversion + // Nothing found, or not implemented. return 0; -} +}*/ U_CAPI uint32_t uprv_convertToLCID(const char *langID, const char* posixID, UErrorCode* status) diff --git a/intl/icu/source/common/locmap.h b/intl/icu/source/common/locmap.h index bef62956e6..a250419d15 100644 --- a/intl/icu/source/common/locmap.h +++ b/intl/icu/source/common/locmap.h @@ -33,8 +33,8 @@ U_CAPI int32_t uprv_convertToPosix(uint32_t hostid, char* posixID, int32_t posixIDCapacity, UErrorCode* status); /* Don't call these functions directly. Use uloc_getLCID instead. */ -U_CAPI uint32_t uprv_convertToLCIDPlatform(const char *localeID); // Leverage platform conversion if possible -U_CAPI uint32_t uprv_convertToLCID(const char *langID, const char* posixID, UErrorCode* status); +//U_CAPI uint32_t uprv_convertToLCIDPlatform(const char* localeID, UErrorCode* status); // Leverage platform conversion if possible +U_CAPI uint32_t uprv_convertToLCID(const char* langID, const char* posixID, UErrorCode* status); #endif /* LOCMAP_H */ diff --git a/intl/icu/source/common/putil.cpp b/intl/icu/source/common/putil.cpp index 769309b422..1a0129684a 100644 --- a/intl/icu/source/common/putil.cpp +++ b/intl/icu/source/common/putil.cpp @@ -103,17 +103,6 @@ # include # include "unicode/uloc.h" # include "wintz.h" -#if U_PLATFORM_HAS_WINUWP_API -typedef PVOID LPMSG; // TODO: figure out how to get rid of this typedef -#include -#include -#include -#include - -using namespace ABI::Windows::Foundation; -using namespace Microsoft::WRL; -using namespace Microsoft::WRL::Wrappers; -#endif #elif U_PLATFORM == U_PF_OS400 # include # include /* error code structure */ @@ -252,7 +241,6 @@ u_signBit(double d) { UDate fakeClock_t0 = 0; /** Time to start the clock from **/ UDate fakeClock_dt = 0; /** Offset (fake time - real time) **/ UBool fakeClock_set = FALSE; /** True if fake clock has spun up **/ -static UMutex fakeClockMutex = U_MUTEX_INTIALIZER; static UDate getUTCtime_real() { struct timeval posixTime; @@ -261,6 +249,7 @@ static UDate getUTCtime_real() { } static UDate getUTCtime_fake() { + static UMutex fakeClockMutex = U_MUTEX_INTIALIZER; umtx_lock(&fakeClockMutex); if(!fakeClock_set) { UDate real = getUTCtime_real(); @@ -997,7 +986,8 @@ static char* searchForTZFile(const char* path, DefaultTZInfo* tzInfo) { /* Check each entry in the directory. */ while((dirEntry = readdir(dirp)) != NULL) { const char* dirName = dirEntry->d_name; - if (uprv_strcmp(dirName, SKIP1) != 0 && uprv_strcmp(dirName, SKIP2) != 0) { + if (uprv_strcmp(dirName, SKIP1) != 0 && uprv_strcmp(dirName, SKIP2) != 0 + && uprv_strcmp(TZFILE_SKIP, dirName) != 0 && uprv_strcmp(TZFILE_SKIP2, dirName) != 0) { /* Create a newpath with the new entry to test each entry in the directory. */ CharString newpath(curpath, status); newpath.append(dirName, -1, status); @@ -1024,7 +1014,7 @@ static char* searchForTZFile(const char* path, DefaultTZInfo* tzInfo) { */ if (result != NULL) break; - } else if (uprv_strcmp(TZFILE_SKIP, dirName) != 0 && uprv_strcmp(TZFILE_SKIP2, dirName) != 0) { + } else { if(compareBinaryFiles(TZDEFAULT, newpath.data(), tzInfo)) { int32_t amountToSkip = sizeof(TZZONEINFO) - 1; if (amountToSkip > newpath.length()) { @@ -1078,7 +1068,7 @@ uprv_tzname(int n) // the other code path returns a pointer to a heap location. // If we don't have a name already, then tzname wouldn't be any // better, so just fall back. - return uprv_strdup("Etc/UTC"); + return uprv_strdup(""); #endif // !U_TZNAME #else @@ -1317,9 +1307,9 @@ uprv_pathIsAbsolute(const char *path) return FALSE; } -/* Temporary backup setting of ICU_DATA_DIR_PREFIX_ENV_VAR - until some client wrapper makefiles are updated */ -#if U_PLATFORM_IS_DARWIN_BASED && TARGET_IPHONE_SIMULATOR +/* Backup setting of ICU_DATA_DIR_PREFIX_ENV_VAR + (needed for some Darwin ICU build environments) */ +#if U_PLATFORM_IS_DARWIN_BASED && TARGET_OS_SIMULATOR # if !defined(ICU_DATA_DIR_PREFIX_ENV_VAR) # define ICU_DATA_DIR_PREFIX_ENV_VAR "IPHONE_SIMULATOR_ROOT" # endif @@ -1430,12 +1420,7 @@ static void U_CALLCONV dataDirectoryInitFn() { if(path==NULL) { /* It looks really bad, set it to something. */ -#if U_PLATFORM_HAS_WIN32_API - // Windows UWP will require icudtl.dat file in same directory as icuuc.dll - path = ".\\"; -#else path = ""; -#endif } u_setDataDirectory(path); @@ -1633,11 +1618,7 @@ The variant cannot have dots in it. The 'rightmost' variant (@xxx) wins. The leftmost codepage (.xxx) wins. */ - char *correctedPOSIXLocale = 0; const char* posixID = uprv_getPOSIXIDForDefaultLocale(); - const char *p; - const char *q; - int32_t len; /* Format: (no spaces) ll [ _CC ] [ . MM ] [ @ VV] @@ -1645,38 +1626,29 @@ The leftmost codepage (.xxx) wins. l = lang, C = ctry, M = charmap, V = variant */ - if (gCorrectedPOSIXLocale != NULL) { + if (gCorrectedPOSIXLocale != nullptr) { return gCorrectedPOSIXLocale; } - if ((p = uprv_strchr(posixID, '.')) != NULL) { - /* assume new locale can't be larger than old one? */ - correctedPOSIXLocale = static_cast(uprv_malloc(uprv_strlen(posixID)+1)); - /* Exit on memory allocation error. */ - if (correctedPOSIXLocale == NULL) { - return NULL; - } - uprv_strncpy(correctedPOSIXLocale, posixID, p-posixID); - correctedPOSIXLocale[p-posixID] = 0; + // Copy the ID into owned memory. + // Over-allocate in case we replace "@" with "__". + char *correctedPOSIXLocale = static_cast(uprv_malloc(uprv_strlen(posixID) + 1 + 1)); + if (correctedPOSIXLocale == nullptr) { + return nullptr; + } + uprv_strcpy(correctedPOSIXLocale, posixID); - /* do not copy after the @ */ - if ((p = uprv_strchr(correctedPOSIXLocale, '@')) != NULL) { - correctedPOSIXLocale[p-correctedPOSIXLocale] = 0; + char *limit; + if ((limit = uprv_strchr(correctedPOSIXLocale, '.')) != nullptr) { + *limit = 0; + if ((limit = uprv_strchr(correctedPOSIXLocale, '@')) != nullptr) { + *limit = 0; } } /* Note that we scan the *uncorrected* ID. */ - if ((p = uprv_strrchr(posixID, '@')) != NULL) { - if (correctedPOSIXLocale == NULL) { - /* new locale can be 1 char longer than old one if @ -> __ */ - correctedPOSIXLocale = static_cast(uprv_malloc(uprv_strlen(posixID)+2)); - /* Exit on memory allocation error. */ - if (correctedPOSIXLocale == NULL) { - return NULL; - } - uprv_strncpy(correctedPOSIXLocale, posixID, p-posixID); - correctedPOSIXLocale[p-posixID] = 0; - } + const char *p; + if ((p = uprv_strrchr(posixID, '@')) != nullptr) { p++; /* Take care of any special cases here.. */ @@ -1685,16 +1657,17 @@ The leftmost codepage (.xxx) wins. /* Don't worry about no__NY. In practice, it won't appear. */ } - if (uprv_strchr(correctedPOSIXLocale,'_') == NULL) { + if (uprv_strchr(correctedPOSIXLocale,'_') == nullptr) { uprv_strcat(correctedPOSIXLocale, "__"); /* aa@b -> aa__b (note this can make the new locale 1 char longer) */ } else { uprv_strcat(correctedPOSIXLocale, "_"); /* aa_CC@b -> aa_CC_b */ } - if ((q = uprv_strchr(p, '.')) != NULL) { + const char *q; + if ((q = uprv_strchr(p, '.')) != nullptr) { /* How big will the resulting string be? */ - len = (int32_t)(uprv_strlen(correctedPOSIXLocale) + (q-p)); + int32_t len = (int32_t)(uprv_strlen(correctedPOSIXLocale) + (q-p)); uprv_strncat(correctedPOSIXLocale, p, q-p); correctedPOSIXLocale[len] = 0; } @@ -1710,28 +1683,15 @@ The leftmost codepage (.xxx) wins. */ } - /* Was a correction made? */ - if (correctedPOSIXLocale != NULL) { - posixID = correctedPOSIXLocale; - } - else { - /* copy it, just in case the original pointer goes away. See j2395 */ - correctedPOSIXLocale = (char *)uprv_malloc(uprv_strlen(posixID) + 1); - /* Exit on memory allocation error. */ - if (correctedPOSIXLocale == NULL) { - return NULL; - } - posixID = uprv_strcpy(correctedPOSIXLocale, posixID); - } - - if (gCorrectedPOSIXLocale == NULL) { + if (gCorrectedPOSIXLocale == nullptr) { gCorrectedPOSIXLocale = correctedPOSIXLocale; gCorrectedPOSIXLocaleHeapAllocated = true; ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup); - correctedPOSIXLocale = NULL; + correctedPOSIXLocale = nullptr; } + posixID = gCorrectedPOSIXLocale; - if (correctedPOSIXLocale != NULL) { /* Was already set - clean up. */ + if (correctedPOSIXLocale != nullptr) { /* Was already set - clean up. */ uprv_free(correctedPOSIXLocale); } @@ -1747,58 +1707,16 @@ The leftmost codepage (.xxx) wins. return gCorrectedPOSIXLocale; } - // No cached value, need to determine the current value - static WCHAR windowsLocale[LOCALE_NAME_MAX_LENGTH] = {}; - int length = GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, windowsLocale, LOCALE_NAME_MAX_LENGTH); - - // Now we should have a Windows locale name that needs converted to the POSIX style. - if (length > 0) // If length is 0, then the GetLocaleInfoEx failed. - { - // First we need to go from UTF-16 to char (and also convert from _ to - while we're at it.) - char modifiedWindowsLocale[LOCALE_NAME_MAX_LENGTH] = {}; - - int32_t i; - for (i = 0; i < UPRV_LENGTHOF(modifiedWindowsLocale); i++) - { - if (windowsLocale[i] == '_') - { - modifiedWindowsLocale[i] = '-'; - } - else - { - modifiedWindowsLocale[i] = static_cast(windowsLocale[i]); - } - - if (modifiedWindowsLocale[i] == '\0') - { - break; - } - } - - if (i >= UPRV_LENGTHOF(modifiedWindowsLocale)) - { - // Ran out of room, can't really happen, maybe we'll be lucky about a matching - // locale when tags are dropped - modifiedWindowsLocale[UPRV_LENGTHOF(modifiedWindowsLocale) - 1] = '\0'; - } - - // Now normalize the resulting name - correctedPOSIXLocale = static_cast(uprv_malloc(POSIX_LOCALE_CAPACITY + 1)); - /* TODO: Should we just exit on memory allocation failure? */ - if (correctedPOSIXLocale) - { - int32_t posixLen = uloc_canonicalize(modifiedWindowsLocale, correctedPOSIXLocale, POSIX_LOCALE_CAPACITY, &status); - if (U_SUCCESS(status)) - { - *(correctedPOSIXLocale + posixLen) = 0; - gCorrectedPOSIXLocale = correctedPOSIXLocale; - gCorrectedPOSIXLocaleHeapAllocated = true; - ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup); - } - else - { - uprv_free(correctedPOSIXLocale); - } + LCID id = GetThreadLocale(); + correctedPOSIXLocale = static_cast(uprv_malloc(POSIX_LOCALE_CAPACITY + 1)); + if (correctedPOSIXLocale) { + int32_t posixLen = uprv_convertToPosix(id, correctedPOSIXLocale, POSIX_LOCALE_CAPACITY, &status); + if (U_SUCCESS(status)) { + *(correctedPOSIXLocale + posixLen) = 0; + gCorrectedPOSIXLocale = correctedPOSIXLocale; + ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup); + } else { + uprv_free(correctedPOSIXLocale); } } diff --git a/intl/icu/source/common/uloc.cpp b/intl/icu/source/common/uloc.cpp index 81b6e0f68a..418c0772d3 100644 --- a/intl/icu/source/common/uloc.cpp +++ b/intl/icu/source/common/uloc.cpp @@ -457,8 +457,6 @@ NULL typedef struct CanonicalizationMap { const char *id; /* input ID */ const char *canonicalID; /* canonicalized output ID */ - const char *keyword; /* keyword, or NULL if none */ - const char *value; /* keyword value, or NULL if kw==NULL */ } CanonicalizationMap; /** @@ -466,64 +464,16 @@ typedef struct CanonicalizationMap { * different semantic kinds of transformations. */ static const CanonicalizationMap CANONICALIZE_MAP[] = { - { "", "en_US_POSIX", NULL, NULL }, /* .NET name */ - { "c", "en_US_POSIX", NULL, NULL }, /* POSIX name */ - { "posix", "en_US_POSIX", NULL, NULL }, /* POSIX name (alias of C) */ - { "art_LOJBAN", "jbo", NULL, NULL }, /* registered name */ - { "az_AZ_CYRL", "az_Cyrl_AZ", NULL, NULL }, /* .NET name */ - { "az_AZ_LATN", "az_Latn_AZ", NULL, NULL }, /* .NET name */ - { "ca_ES_PREEURO", "ca_ES", "currency", "ESP" }, - { "de__PHONEBOOK", "de", "collation", "phonebook" }, /* Old ICU name */ - { "de_AT_PREEURO", "de_AT", "currency", "ATS" }, - { "de_DE_PREEURO", "de_DE", "currency", "DEM" }, - { "de_LU_PREEURO", "de_LU", "currency", "LUF" }, - { "el_GR_PREEURO", "el_GR", "currency", "GRD" }, - { "en_BE_PREEURO", "en_BE", "currency", "BEF" }, - { "en_IE_PREEURO", "en_IE", "currency", "IEP" }, - { "es__TRADITIONAL", "es", "collation", "traditional" }, /* Old ICU name */ - { "es_ES_PREEURO", "es_ES", "currency", "ESP" }, - { "eu_ES_PREEURO", "eu_ES", "currency", "ESP" }, - { "fi_FI_PREEURO", "fi_FI", "currency", "FIM" }, - { "fr_BE_PREEURO", "fr_BE", "currency", "BEF" }, - { "fr_FR_PREEURO", "fr_FR", "currency", "FRF" }, - { "fr_LU_PREEURO", "fr_LU", "currency", "LUF" }, - { "ga_IE_PREEURO", "ga_IE", "currency", "IEP" }, - { "gl_ES_PREEURO", "gl_ES", "currency", "ESP" }, - { "hi__DIRECT", "hi", "collation", "direct" }, /* Old ICU name */ - { "it_IT_PREEURO", "it_IT", "currency", "ITL" }, - { "ja_JP_TRADITIONAL", "ja_JP", "calendar", "japanese" }, /* Old ICU name */ - { "nb_NO_NY", "nn_NO", NULL, NULL }, /* "markus said this was ok" :-) */ - { "nl_BE_PREEURO", "nl_BE", "currency", "BEF" }, - { "nl_NL_PREEURO", "nl_NL", "currency", "NLG" }, - { "pt_PT_PREEURO", "pt_PT", "currency", "PTE" }, - { "sr_SP_CYRL", "sr_Cyrl_RS", NULL, NULL }, /* .NET name */ - { "sr_SP_LATN", "sr_Latn_RS", NULL, NULL }, /* .NET name */ - { "sr_YU_CYRILLIC", "sr_Cyrl_RS", NULL, NULL }, /* Linux name */ - { "th_TH_TRADITIONAL", "th_TH", "calendar", "buddhist" }, /* Old ICU name */ - { "uz_UZ_CYRILLIC", "uz_Cyrl_UZ", NULL, NULL }, /* Linux name */ - { "uz_UZ_CYRL", "uz_Cyrl_UZ", NULL, NULL }, /* .NET name */ - { "uz_UZ_LATN", "uz_Latn_UZ", NULL, NULL }, /* .NET name */ - { "zh_CHS", "zh_Hans", NULL, NULL }, /* .NET name */ - { "zh_CHT", "zh_Hant", NULL, NULL }, /* .NET name */ - { "zh_GAN", "gan", NULL, NULL }, /* registered name */ - { "zh_GUOYU", "zh", NULL, NULL }, /* registered name */ - { "zh_HAKKA", "hak", NULL, NULL }, /* registered name */ - { "zh_MIN_NAN", "nan", NULL, NULL }, /* registered name */ - { "zh_WUU", "wuu", NULL, NULL }, /* registered name */ - { "zh_XIANG", "hsn", NULL, NULL }, /* registered name */ - { "zh_YUE", "yue", NULL, NULL }, /* registered name */ -}; - -typedef struct VariantMap { - const char *variant; /* input ID */ - const char *keyword; /* keyword, or NULL if none */ - const char *value; /* keyword value, or NULL if kw==NULL */ -} VariantMap; - -static const VariantMap VARIANT_MAP[] = { - { "EURO", "currency", "EUR" }, - { "PINYIN", "collation", "pinyin" }, /* Solaris variant */ - { "STROKE", "collation", "stroke" } /* Solaris variant */ + { "art_LOJBAN", "jbo" }, /* registered name */ + { "hy__AREVELA", "hy" }, /* Registered IANA variant */ + { "hy__AREVMDA", "hyw" }, /* Registered IANA variant */ + { "zh_GAN", "gan" }, /* registered name */ + { "zh_GUOYU", "zh" }, /* registered name */ + { "zh_HAKKA", "hak" }, /* registered name */ + { "zh_MIN_NAN", "nan" }, /* registered name */ + { "zh_WUU", "wuu" }, /* registered name */ + { "zh_XIANG", "hsn" }, /* registered name */ + { "zh_YUE", "yue" }, /* registered name */ }; /* ### BCP47 Conversion *******************************************/ @@ -643,20 +593,12 @@ compareKeywordStructs(const void * /*context*/, const void *left, const void *ri return uprv_strcmp(leftString, rightString); } -/** - * Both addKeyword and addValue must already be in canonical form. - * Either both addKeyword and addValue are NULL, or neither is NULL. - * If they are not NULL they must be zero terminated. - * If addKeyword is not NULL is must have length small enough to fit in KeywordStruct.keyword. - */ static int32_t _getKeywords(const char *localeID, char prev, char *keywords, int32_t keywordCapacity, char *values, int32_t valuesCapacity, int32_t *valLen, UBool valuesToo, - const char* addKeyword, - const char* addValue, UErrorCode *status) { KeywordStruct keywordList[ULOC_MAX_NO_KEYWORDS]; @@ -755,33 +697,6 @@ _getKeywords(const char *localeID, } } while(pos); - /* Handle addKeyword/addValue. */ - if (addKeyword != NULL) { - UBool duplicate = FALSE; - U_ASSERT(addValue != NULL); - /* Search for duplicate; if found, do nothing. Explicit keyword - overrides addKeyword. */ - for (j=0; j= 0); - while (len-- != 0) { - char d = *str; - if (d == c) { - return (char*) str; - } else if (d == 0) { - break; - } - ++str; - } - return NULL; -} - /** * Lookup 'key' in the array 'list'. The array 'list' should contain * a NULL entry, followed by more entries, and a second NULL entry. @@ -1279,6 +1180,16 @@ ulocimp_getLanguage(const char *localeID, int32_t offset; char lang[4]={ 0, 0, 0, 0 }; /* temporary buffer to hold language code for searching */ + if (uprv_stricmp(localeID, "root") == 0) { + localeID += 4; + } else if (uprv_strnicmp(localeID, "und", 3) == 0 && + (localeID[3] == '\0' || + localeID[3] == '-' || + localeID[3] == '_' || + localeID[3] == '@')) { + localeID += 3; + } + /* if it starts with i- or x- then copy that prefix */ if(_isIDPrefix(localeID)) { if(i "FOO_BAR". - * @param variants the source string of one or more variants, - * separated by '_'. This will be MODIFIED IN PLACE. Not zero - * terminated; if it is, trailing zero will NOT be maintained. - * @param variantsLen length of variants - * @param toDelete variant to delete, without separators, e.g. "EURO" - * or "PREEURO"; not zero terminated - * @param toDeleteLen length of toDelete - * @return number of characters deleted from variants - */ -static int32_t -_deleteVariant(char* variants, int32_t variantsLen, - const char* toDelete, int32_t toDeleteLen) -{ - int32_t delta = 0; /* number of chars deleted */ - for (;;) { - UBool flag = FALSE; - if (variantsLen < toDeleteLen) { - return delta; - } - if (uprv_strncmp(variants, toDelete, toDeleteLen) == 0 && - (variantsLen == toDeleteLen || - (flag=(variants[toDeleteLen] == '_')) != 0)) - { - int32_t d = toDeleteLen + (flag?1:0); - variantsLen -= d; - delta += d; - if (variantsLen > 0) { - uprv_memmove(variants, variants+d, variantsLen); - } - } else { - char* p = _strnchr(variants, variantsLen, '_'); - if (p == NULL) { - return delta; - } - ++p; - variantsLen -= (int32_t)(p - variants); - variants = p; - } - } -} - /* Keyword enumeration */ typedef struct UKeywordsContext { @@ -1698,8 +1565,6 @@ _canonicalize(const char* localeID, const char* tmpLocaleID; const char* keywordAssign = NULL; const char* separatorIndicator = NULL; - const char* addKeyword = NULL; - const char* addValue = NULL; char* name; char* variant = NULL; /* pointer into name, or NULL */ @@ -1738,7 +1603,7 @@ _canonicalize(const char* localeID, len = (int32_t)uprv_strlen(d); if (name != NULL) { - uprv_strncpy(name, d, len); + uprv_memcpy(name, d, len); } } else if(_isIDSeparator(*tmpLocaleID)) { const char *scriptID; @@ -1864,27 +1729,6 @@ _canonicalize(const char* localeID, } } - /* Handle generic variants first */ - if (variant) { - for (j=0; j 0) { - if (len > 0 && name[len-1] == '_') { /* delete trailing '_' */ - --len; - } - addKeyword = VARIANT_MAP[j].keyword; - addValue = VARIANT_MAP[j].value; - break; - } - } - if (len > 0 && len <= nameCapacity && name[len-1] == '_') { /* delete trailing '_' */ - --len; - } - } - /* Look up the ID in the canonicalization map */ for (j=0; j 0) - { - // Windows found an LCID, return that - return lcid; - } - uloc_getLanguage(localeID, langID, sizeof(langID), &status); - if (U_FAILURE(status)) { + if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) { return 0; } diff --git a/intl/icu/source/common/wintz.cpp b/intl/icu/source/common/wintz.cpp index 5e9ac0d2f3..f62cbdb498 100644 --- a/intl/icu/source/common/wintz.cpp +++ b/intl/icu/source/common/wintz.cpp @@ -13,7 +13,9 @@ #include "unicode/utypes.h" -#if U_PLATFORM_USES_ONLY_WIN32_API +// This file contains only desktop Windows behavior +// Windows UWP calls Windows::Globalization directly, so this isn't needed there. +#if U_PLATFORM_USES_ONLY_WIN32_API && (U_PLATFORM_HAS_WINUWP_API == 0) #include "wintz.h" #include "cmemory.h" @@ -21,7 +23,6 @@ #include "unicode/ures.h" #include "unicode/ustring.h" -#include "uresimp.h" #ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN @@ -33,94 +34,362 @@ # define NOMCX #include -U_NAMESPACE_BEGIN +#define MAX_LENGTH_ID 40 -// The value of MAX_TIMEZONE_ID_LENGTH is 128, which is defined in DYNAMIC_TIME_ZONE_INFORMATION -#define MAX_TIMEZONE_ID_LENGTH 128 +/* The layout of the Tzi value in the registry */ +typedef struct +{ + int32_t bias; + int32_t standardBias; + int32_t daylightBias; + SYSTEMTIME standardDate; + SYSTEMTIME daylightDate; +} TZI; /** -* Main Windows time zone detection function. -* Returns the Windows time zone converted to an ICU time zone as a heap-allocated buffer, or nullptr upon failure. -* Note: We use the Win32 API GetDynamicTimeZoneInformation to get the current time zone info. -* This API returns a non-localized time zone name, which we can then map to an ICU time zone name. + * Various registry keys and key fragments. + */ +static const wchar_t CURRENT_ZONE_REGKEY[] = L"SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation\\"; +static const char TZI_REGKEY[] = "TZI"; +static const char STD_REGKEY[] = "Std"; + +/** + * The time zone root keys (under HKLM) for Win7+ + */ +static const char TZ_REGKEY[] = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\"; + +static LONG openTZRegKey(HKEY *hkey, const char *winid) +{ + char subKeyName[110]; /* TODO: why 110?? */ + char *name; + LONG result; + + uprv_strcpy(subKeyName, TZ_REGKEY); + name = &subKeyName[strlen(subKeyName)]; + uprv_strcat(subKeyName, winid); + + result = RegOpenKeyExA(HKEY_LOCAL_MACHINE, + subKeyName, + 0, + KEY_QUERY_VALUE, + hkey); + return result; +} + +static LONG getTZI(const char *winid, TZI *tzi) +{ + DWORD cbData = sizeof(TZI); + LONG result; + HKEY hkey; + + result = openTZRegKey(&hkey, winid); + + if (result == ERROR_SUCCESS) + { + result = RegQueryValueExA(hkey, + TZI_REGKEY, + NULL, + NULL, + (LPBYTE)tzi, + &cbData); + RegCloseKey(hkey); + } + + return result; +} + +static LONG getSTDName(const char *winid, char *regStdName, int32_t length) +{ + DWORD cbData = length; + LONG result; + HKEY hkey; + + result = openTZRegKey(&hkey, winid); + + if (result == ERROR_SUCCESS) + { + result = RegQueryValueExA(hkey, + STD_REGKEY, + NULL, + NULL, + (LPBYTE)regStdName, + &cbData); + RegCloseKey(hkey); + } + + return result; +} + +static LONG getTZKeyName(char* tzKeyName, int32_t tzKeyNamelength) +{ + HKEY hkey; + LONG result = FALSE; + WCHAR timeZoneKeyNameData[128]; + DWORD timeZoneKeyNameLength = static_cast(sizeof(timeZoneKeyNameData)); + + if(ERROR_SUCCESS == RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + CURRENT_ZONE_REGKEY, + 0, + KEY_QUERY_VALUE, + &hkey)) + { + if (ERROR_SUCCESS == RegQueryValueExW( + hkey, + L"TimeZoneKeyName", + NULL, + NULL, + (LPBYTE)timeZoneKeyNameData, + &timeZoneKeyNameLength)) + { + // Ensure null termination. + timeZoneKeyNameData[UPRV_LENGTHOF(timeZoneKeyNameData) - 1] = L'\0'; + + // Convert the UTF-16 string to UTF-8. + UErrorCode status = U_ZERO_ERROR; + u_strToUTF8(tzKeyName, tzKeyNamelength, NULL, reinterpret_cast(timeZoneKeyNameData), -1, &status); + if (U_ZERO_ERROR == status) + { + result = ERROR_SUCCESS; + } + } + RegCloseKey(hkey); + } + + return result; +} + +/* + This code attempts to detect the Windows time zone directly, + as set in the Windows Date and Time control panel. It attempts + to work on versions greater than Windows Vista and on localized + installs. It works by directly interrogating the registry and + comparing the data there with the data returned by the + GetTimeZoneInformation API, along with some other strategies. The + registry contains time zone data under this key: + + HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\ + + Under this key are several subkeys, one for each time zone. For + example these subkeys are named "Pacific Standard Time" on Vista+. + There are some other wrinkles; see the code for + details. The subkey name is NOT LOCALIZED, allowing us to support + localized installs. + + Under the subkey are data values. We care about: + + Std Standard time display name, localized + TZI Binary block of data + + The TZI data is of particular interest. It contains the offset, two + more offsets for standard and daylight time, and the start and end + rules. This is the same data returned by the GetTimeZoneInformation + API. The API may modify the data on the way out, so we have to be + careful, but essentially we do a binary comparison against the TZI + blocks of various registry keys. When we find a match, we know what + time zone Windows is set to. Since the registry key is not + localized, we can then translate the key through a simple table + lookup into the corresponding ICU time zone. + + This strategy doesn't always work because there are zones which + share an offset and rules, so more than one TZI block will match. + For example, both Tokyo and Seoul are at GMT+9 with no DST rules; + their TZI blocks are identical. For these cases, we fall back to a + name lookup. We attempt to match the display name as stored in the + registry for the current zone to the display name stored in the + registry for various Windows zones. By comparing the registry data + directly we avoid conversion complications. + + Author: Alan Liu + Since: ICU 2.6 + Based on original code by Carl Brown */ + +/** + * Main Windows time zone detection function. Returns the Windows + * time zone, translated to an ICU time zone, or NULL upon failure. + */ U_CFUNC const char* U_EXPORT2 uprv_detectWindowsTimeZone() { UErrorCode status = U_ZERO_ERROR; - char* icuid = nullptr; - char dynamicTZKeyName[MAX_TIMEZONE_ID_LENGTH]; - char tmpid[MAX_TIMEZONE_ID_LENGTH]; + UResourceBundle* bundle = NULL; + char* icuid = NULL; + char apiStdName[MAX_LENGTH_ID]; + char regStdName[MAX_LENGTH_ID]; + char tmpid[MAX_LENGTH_ID]; int32_t len; - int id = GEOID_NOT_AVAILABLE; + int id; int errorCode; - wchar_t ISOcodeW[3] = {}; /* 2 letter ISO code in UTF-16 */ - char ISOcode[3] = {}; /* 2 letter ISO code in UTF-8 */ + wchar_t ISOcodeW[3]; /* 2 letter iso code in UTF-16*/ + char ISOcodeA[3]; /* 2 letter iso code in ansi */ - DYNAMIC_TIME_ZONE_INFORMATION dynamicTZI; - uprv_memset(&dynamicTZI, 0, sizeof(dynamicTZI)); - uprv_memset(dynamicTZKeyName, 0, sizeof(dynamicTZKeyName)); - uprv_memset(tmpid, 0, sizeof(tmpid)); + LONG result; + TZI tziKey; + TZI tziReg; + TIME_ZONE_INFORMATION apiTZI; - /* Obtain TIME_ZONE_INFORMATION from the API and get the non-localized time zone name. */ - if (TIME_ZONE_ID_INVALID == GetDynamicTimeZoneInformation(&dynamicTZI)) { - return nullptr; - } + BOOL tryPreVistaFallback; + OSVERSIONINFO osVerInfo; + + /* Obtain TIME_ZONE_INFORMATION from the API, and then convert it + to TZI. We could also interrogate the registry directly; we do + this below if needed. */ + uprv_memset(&apiTZI, 0, sizeof(apiTZI)); + uprv_memset(&tziKey, 0, sizeof(tziKey)); + uprv_memset(&tziReg, 0, sizeof(tziReg)); + GetTimeZoneInformation(&apiTZI); + tziKey.bias = apiTZI.Bias; + uprv_memcpy((char *)&tziKey.standardDate, (char*)&apiTZI.StandardDate, + sizeof(apiTZI.StandardDate)); + uprv_memcpy((char *)&tziKey.daylightDate, (char*)&apiTZI.DaylightDate, + sizeof(apiTZI.DaylightDate)); + + /* Convert the wchar_t* standard name to char* */ + uprv_memset(apiStdName, 0, sizeof(apiStdName)); + wcstombs(apiStdName, apiTZI.StandardName, MAX_LENGTH_ID); + + tmpid[0] = 0; id = GetUserGeoID(GEOCLASS_NATION); errorCode = GetGeoInfoW(id, GEO_ISO2, ISOcodeW, 3, 0); + u_strToUTF8(ISOcodeA, 3, NULL, (const UChar *)ISOcodeW, 3, &status); - // convert from wchar_t* (UTF-16 on Windows) to char* (UTF-8). - u_strToUTF8(ISOcode, UPRV_LENGTHOF(ISOcode), nullptr, - reinterpret_cast(ISOcodeW), UPRV_LENGTHOF(ISOcodeW), &status); + bundle = ures_openDirect(NULL, "windowsZones", &status); + ures_getByKey(bundle, "mapTimezones", bundle, &status); - LocalUResourceBundlePointer bundle(ures_openDirect(nullptr, "windowsZones", &status)); - ures_getByKey(bundle.getAlias(), "mapTimezones", bundle.getAlias(), &status); - - // convert from wchar_t* (UTF-16 on Windows) to char* (UTF-8). - u_strToUTF8(dynamicTZKeyName, UPRV_LENGTHOF(dynamicTZKeyName), nullptr, - reinterpret_cast(dynamicTZI.TimeZoneKeyName), UPRV_LENGTHOF(dynamicTZI.TimeZoneKeyName), &status); - - if (U_FAILURE(status)) { - return nullptr; - } - - if (dynamicTZI.TimeZoneKeyName[0] != 0) { - UResourceBundle winTZ; - ures_initStackObject(&winTZ); - ures_getByKey(bundle.getAlias(), dynamicTZKeyName, &winTZ, &status); - - if (U_SUCCESS(status)) { - const UChar* icuTZ = nullptr; - if (errorCode != 0) { - icuTZ = ures_getStringByKey(&winTZ, ISOcode, &len, &status); + /* + Windows Vista+ provides us with a "TimeZoneKeyName" that is not localized + and can be used to directly map a name in our bundle. Try to use that first + if we're on Vista or higher + */ + uprv_memset(&osVerInfo, 0, sizeof(osVerInfo)); + osVerInfo.dwOSVersionInfoSize = sizeof(osVerInfo); + tryPreVistaFallback = TRUE; + result = getTZKeyName(regStdName, sizeof(regStdName)); + if(ERROR_SUCCESS == result) + { + UResourceBundle* winTZ = ures_getByKey(bundle, regStdName, NULL, &status); + if(U_SUCCESS(status)) + { + const UChar* icuTZ = NULL; + if (errorCode != 0) + { + icuTZ = ures_getStringByKey(winTZ, ISOcodeA, &len, &status); } - if (errorCode == 0 || icuTZ == nullptr) { + if (errorCode==0 || icuTZ==NULL) + { /* fallback to default "001" and reset status */ status = U_ZERO_ERROR; - icuTZ = ures_getStringByKey(&winTZ, "001", &len, &status); + icuTZ = ures_getStringByKey(winTZ, "001", &len, &status); } - if (U_SUCCESS(status)) { - int index = 0; - - while (!(*icuTZ == '\0' || *icuTZ == ' ')) { - // time zone IDs only contain ASCII invariant characters. - tmpid[index++] = (char)(*icuTZ++); + if(U_SUCCESS(status)) + { + int index=0; + while (! (*icuTZ == '\0' || *icuTZ ==' ')) + { + tmpid[index++]=(char)(*icuTZ++); /* safe to assume 'char' is ASCII compatible on windows */ } - tmpid[index] = '\0'; + tmpid[index]='\0'; + tryPreVistaFallback = FALSE; } } - ures_close(&winTZ); + ures_close(winTZ); } - // Copy the timezone ID to icuid to be returned. - if (tmpid[0] != 0) { - icuid = uprv_strdup(tmpid); + if(tryPreVistaFallback) + { + /* Note: We get the winid not from static tables but from resource bundle. */ + while (U_SUCCESS(status) && ures_hasNext(bundle)) + { + UBool idFound = FALSE; + const char* winid; + UResourceBundle* winTZ = ures_getNextResource(bundle, NULL, &status); + if (U_FAILURE(status)) + { + break; + } + winid = ures_getKey(winTZ); + result = getTZI(winid, &tziReg); + + if (result == ERROR_SUCCESS) + { + /* Windows alters the DaylightBias in some situations. + Using the bias and the rules suffices, so overwrite + these unreliable fields. */ + tziKey.standardBias = tziReg.standardBias; + tziKey.daylightBias = tziReg.daylightBias; + + if (uprv_memcmp((char *)&tziKey, (char*)&tziReg, sizeof(tziKey)) == 0) + { + const UChar* icuTZ = NULL; + if (errorCode != 0) + { + icuTZ = ures_getStringByKey(winTZ, ISOcodeA, &len, &status); + } + if (errorCode==0 || icuTZ==NULL) + { + /* fallback to default "001" and reset status */ + status = U_ZERO_ERROR; + icuTZ = ures_getStringByKey(winTZ, "001", &len, &status); + } + + if (U_SUCCESS(status)) + { + /* Get the standard name from the registry key to compare with + the one from Windows API call. */ + uprv_memset(regStdName, 0, sizeof(regStdName)); + result = getSTDName(winid, regStdName, sizeof(regStdName)); + if (result == ERROR_SUCCESS) + { + if (uprv_strcmp(apiStdName, regStdName) == 0) + { + idFound = TRUE; + } + } + + /* tmpid buffer holds the ICU timezone ID corresponding to the timezone ID from Windows. + * If none is found, tmpid buffer will contain a fallback ID (i.e. the time zone ID matching + * the current time zone information) + */ + if (idFound || tmpid[0] == 0) + { + /* if icuTZ has more than one city, take only the first (i.e. terminate icuTZ at first space) */ + int index=0; + while (! (*icuTZ == '\0' || *icuTZ ==' ')) + { + tmpid[index++]=(char)(*icuTZ++); /* safe to assume 'char' is ASCII compatible on windows */ + } + tmpid[index]='\0'; + } + } + } + } + ures_close(winTZ); + if (idFound) + { + break; + } + } } + /* + * Copy the timezone ID to icuid to be returned. + */ + if (tmpid[0] != 0) + { + len = uprv_strlen(tmpid); + icuid = (char*)uprv_calloc(len + 1, sizeof(char)); + if (icuid != NULL) + { + uprv_strcpy(icuid, tmpid); + } + } + + ures_close(bundle); + return icuid; } -U_NAMESPACE_END -#endif /* U_PLATFORM_USES_ONLY_WIN32_API */ +#endif /* U_PLATFORM_USES_ONLY_WIN32_API && (U_PLATFORM_HAS_WINUWP_API == 0) */ diff --git a/intl/icu/source/common/wintz.h b/intl/icu/source/common/wintz.h index f98b1779b5..cd8565eef1 100644 --- a/intl/icu/source/common/wintz.h +++ b/intl/icu/source/common/wintz.h @@ -28,7 +28,7 @@ U_CDECL_BEGIN typedef struct _TIME_ZONE_INFORMATION TIME_ZONE_INFORMATION; U_CDECL_END -U_CFUNC const char* U_EXPORT2 +U_INTERNAL const char* U_EXPORT2 uprv_detectWindowsTimeZone(); #endif /* U_PLATFORM_USES_ONLY_WIN32_API */ diff --git a/intl/icu/source/i18n/windtfmt.cpp b/intl/icu/source/i18n/windtfmt.cpp index 6a3779a29e..043469bd7d 100644 --- a/intl/icu/source/i18n/windtfmt.cpp +++ b/intl/icu/source/i18n/windtfmt.cpp @@ -94,83 +94,12 @@ UnicodeString* Win32DateFormat::getTimeDateFormat(const Calendar *cal, const Loc return result; } -// TODO: This is copied in both winnmfmt.cpp and windtfmt.cpp, but really should -// be factored out into a common helper for both. -static UErrorCode GetEquivalentWindowsLocaleName(const Locale& locale, UnicodeString** buffer) -{ - UErrorCode status = U_ZERO_ERROR; - char asciiBCP47Tag[LOCALE_NAME_MAX_LENGTH] = {}; - - // Convert from names like "en_CA" and "de_DE@collation=phonebook" to "en-CA" and "de-DE-u-co-phonebk". - (void)uloc_toLanguageTag(locale.getName(), asciiBCP47Tag, UPRV_LENGTHOF(asciiBCP47Tag), FALSE, &status); - - if (U_SUCCESS(status)) - { - // Need it to be UTF-16, not 8-bit - // TODO: This seems like a good thing for a helper - wchar_t bcp47Tag[LOCALE_NAME_MAX_LENGTH] = {}; - int32_t i; - for (i = 0; i < UPRV_LENGTHOF(bcp47Tag); i++) - { - if (asciiBCP47Tag[i] == '\0') - { - break; - } - else - { - // normally just copy the character - bcp47Tag[i] = static_cast(asciiBCP47Tag[i]); - } - } - - // Ensure it's null terminated - if (i < (UPRV_LENGTHOF(bcp47Tag) - 1)) - { - bcp47Tag[i] = L'\0'; - } - else - { - // Ran out of room. - bcp47Tag[UPRV_LENGTHOF(bcp47Tag) - 1] = L'\0'; - } - - - wchar_t windowsLocaleName[LOCALE_NAME_MAX_LENGTH] = {}; - - // Note: On Windows versions below 10, there is no support for locale name aliases. - // This means that it will fail for locales where ICU has a completely different - // name (like ku vs ckb), and it will also not work for alternate sort locale - // names like "de-DE-u-co-phonebk". - - // TODO: We could add some sort of exception table for cases like ku vs ckb. - - int length = ResolveLocaleName(bcp47Tag, windowsLocaleName, UPRV_LENGTHOF(windowsLocaleName)); - - if (length > 0) - { - *buffer = new UnicodeString(windowsLocaleName); - } - else - { - status = U_UNSUPPORTED_ERROR; - } - } - return status; -} - // TODO: Range-check timeStyle, dateStyle Win32DateFormat::Win32DateFormat(DateFormat::EStyle timeStyle, DateFormat::EStyle dateStyle, const Locale &locale, UErrorCode &status) - : DateFormat(), fDateTimeMsg(NULL), fTimeStyle(timeStyle), fDateStyle(dateStyle), fLocale(locale), fZoneID(), fWindowsLocaleName(nullptr) + : DateFormat(), fDateTimeMsg(NULL), fTimeStyle(timeStyle), fDateStyle(dateStyle), fLocale(locale), fZoneID() { if (U_SUCCESS(status)) { - GetEquivalentWindowsLocaleName(locale, &fWindowsLocaleName); - // Note: In the previous code, it would look up the LCID for the locale, and if - // the locale was not recognized then it would get an LCID of 0, which is a - // synonym for LOCALE_USER_DEFAULT on Windows. - // If the above method fails, then fWindowsLocaleName will remain as nullptr, and - // then we will pass nullptr to API GetLocaleInfoEx, which is the same as passing - // LOCALE_USER_DEFAULT. - + fLCID = locale.getLCID(); fTZI = NEW_ARRAY(TIME_ZONE_INFORMATION, 1); uprv_memset(fTZI, 0, sizeof(TIME_ZONE_INFORMATION)); adoptCalendar(Calendar::createInstance(locale, status)); @@ -188,7 +117,6 @@ Win32DateFormat::~Win32DateFormat() // delete fCalendar; uprv_free(fTZI); delete fDateTimeMsg; - delete fWindowsLocaleName; } Win32DateFormat &Win32DateFormat::operator=(const Win32DateFormat &other) @@ -208,8 +136,6 @@ Win32DateFormat &Win32DateFormat::operator=(const Win32DateFormat &other) this->fTZI = NEW_ARRAY(TIME_ZONE_INFORMATION, 1); *this->fTZI = *other.fTZI; - this->fWindowsLocaleName = other.fWindowsLocaleName == NULL ? NULL : new UnicodeString(*other.fWindowsLocaleName); - return *this; } @@ -309,22 +235,16 @@ void Win32DateFormat::formatDate(const SYSTEMTIME *st, UnicodeString &appendTo) int result=0; wchar_t stackBuffer[STACK_BUFFER_SIZE]; wchar_t *buffer = stackBuffer; - const wchar_t *localeName = nullptr; - if (fWindowsLocaleName != nullptr) - { - localeName = reinterpret_cast(toOldUCharPtr(fWindowsLocaleName->getTerminatedBuffer())); - } - - result = GetDateFormatEx(localeName, dfFlags[fDateStyle - kDateOffset], st, NULL, buffer, STACK_BUFFER_SIZE, NULL); + result = GetDateFormatW(fLCID, dfFlags[fDateStyle - kDateOffset], st, NULL, buffer, STACK_BUFFER_SIZE); if (result == 0) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - int newLength = GetDateFormatEx(localeName, dfFlags[fDateStyle - kDateOffset], st, NULL, NULL, 0, NULL); + int newLength = GetDateFormatW(fLCID, dfFlags[fDateStyle - kDateOffset], st, NULL, NULL, 0); buffer = NEW_ARRAY(wchar_t, newLength); - GetDateFormatEx(localeName, dfFlags[fDateStyle - kDateOffset], st, NULL, buffer, newLength, NULL); + GetDateFormatW(fLCID, dfFlags[fDateStyle - kDateOffset], st, NULL, buffer, newLength); } } @@ -342,22 +262,16 @@ void Win32DateFormat::formatTime(const SYSTEMTIME *st, UnicodeString &appendTo) int result; wchar_t stackBuffer[STACK_BUFFER_SIZE]; wchar_t *buffer = stackBuffer; - const wchar_t *localeName = nullptr; - if (fWindowsLocaleName != nullptr) - { - localeName = reinterpret_cast(toOldUCharPtr(fWindowsLocaleName->getTerminatedBuffer())); - } - - result = GetTimeFormatEx(localeName, tfFlags[fTimeStyle], st, NULL, buffer, STACK_BUFFER_SIZE); + result = GetTimeFormatW(fLCID, tfFlags[fTimeStyle], st, NULL, buffer, STACK_BUFFER_SIZE); if (result == 0) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - int newLength = GetTimeFormatEx(localeName, tfFlags[fTimeStyle], st, NULL, NULL, 0); + int newLength = GetTimeFormatW(fLCID, tfFlags[fTimeStyle], st, NULL, NULL, 0); buffer = NEW_ARRAY(wchar_t, newLength); - GetTimeFormatEx(localeName, tfFlags[fTimeStyle], st, NULL, buffer, newLength); + GetDateFormatW(fLCID, tfFlags[fTimeStyle], st, NULL, buffer, newLength); } } diff --git a/intl/icu/source/i18n/windtfmt.h b/intl/icu/source/i18n/windtfmt.h index 33069058fb..9d457c18ae 100644 --- a/intl/icu/source/i18n/windtfmt.h +++ b/intl/icu/source/i18n/windtfmt.h @@ -124,10 +124,9 @@ private: DateFormat::EStyle fTimeStyle; DateFormat::EStyle fDateStyle; Locale fLocale; + int32_t fLCID; UnicodeString fZoneID; TIME_ZONE_INFORMATION *fTZI; - - UnicodeString* fWindowsLocaleName; // Stores the equivalent Windows locale name. }; U_NAMESPACE_END diff --git a/intl/icu/source/i18n/winnmfmt.cpp b/intl/icu/source/i18n/winnmfmt.cpp index 5637a0f4a1..9660fa9ea5 100644 --- a/intl/icu/source/i18n/winnmfmt.cpp +++ b/intl/icu/source/i18n/winnmfmt.cpp @@ -60,43 +60,43 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Win32NumberFormat) * end in ";0" then the return value should be multiplied by 10. * (e.g. "3" => 30, "3;2" => 320) */ -static UINT getGrouping(const wchar_t *grouping) +static UINT getGrouping(const char *grouping) { UINT g = 0; - const wchar_t *s; + const char *s; - for (s = grouping; *s != L'\0'; s += 1) { - if (*s > L'0' && *s < L'9') { - g = g * 10 + (*s - L'0'); - } else if (*s != L';') { + for (s = grouping; *s != '\0'; s += 1) { + if (*s > '0' && *s < '9') { + g = g * 10 + (*s - '0'); + } else if (*s != ';') { break; } } - if (*s != L'0') { + if (*s != '0') { g *= 10; } return g; } -static void getNumberFormat(NUMBERFMTW *fmt, const wchar_t *windowsLocaleName) +static void getNumberFormat(NUMBERFMTW *fmt, int32_t lcid) { - wchar_t buf[10]; + char buf[10]; - GetLocaleInfoEx(windowsLocaleName, LOCALE_RETURN_NUMBER|LOCALE_IDIGITS, (LPWSTR) &fmt->NumDigits, sizeof(UINT)); - GetLocaleInfoEx(windowsLocaleName, LOCALE_RETURN_NUMBER|LOCALE_ILZERO, (LPWSTR) &fmt->LeadingZero, sizeof(UINT)); + GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_IDIGITS, (LPWSTR) &fmt->NumDigits, sizeof(UINT)); + GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_ILZERO, (LPWSTR) &fmt->LeadingZero, sizeof(UINT)); - GetLocaleInfoEx(windowsLocaleName, LOCALE_SGROUPING, (LPWSTR)buf, 10); + GetLocaleInfoA(lcid, LOCALE_SGROUPING, buf, 10); fmt->Grouping = getGrouping(buf); fmt->lpDecimalSep = NEW_ARRAY(wchar_t, 6); - GetLocaleInfoEx(windowsLocaleName, LOCALE_SDECIMAL, fmt->lpDecimalSep, 6); + GetLocaleInfoW(lcid, LOCALE_SDECIMAL, fmt->lpDecimalSep, 6); fmt->lpThousandSep = NEW_ARRAY(wchar_t, 6); - GetLocaleInfoEx(windowsLocaleName, LOCALE_STHOUSAND, fmt->lpThousandSep, 6); + GetLocaleInfoW(lcid, LOCALE_STHOUSAND, fmt->lpThousandSep, 6); - GetLocaleInfoEx(windowsLocaleName, LOCALE_RETURN_NUMBER|LOCALE_INEGNUMBER, (LPWSTR) &fmt->NegativeOrder, sizeof(UINT)); + GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_INEGNUMBER, (LPWSTR) &fmt->NegativeOrder, sizeof(UINT)); } static void freeNumberFormat(NUMBERFMTW *fmt) @@ -107,27 +107,27 @@ static void freeNumberFormat(NUMBERFMTW *fmt) } } -static void getCurrencyFormat(CURRENCYFMTW *fmt, const wchar_t *windowsLocaleName) +static void getCurrencyFormat(CURRENCYFMTW *fmt, int32_t lcid) { - wchar_t buf[10]; + char buf[10]; - GetLocaleInfoEx(windowsLocaleName, LOCALE_RETURN_NUMBER|LOCALE_ICURRDIGITS, (LPWSTR) &fmt->NumDigits, sizeof(UINT)); - GetLocaleInfoEx(windowsLocaleName, LOCALE_RETURN_NUMBER|LOCALE_ILZERO, (LPWSTR) &fmt->LeadingZero, sizeof(UINT)); + GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_ICURRDIGITS, (LPWSTR) &fmt->NumDigits, sizeof(UINT)); + GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_ILZERO, (LPWSTR) &fmt->LeadingZero, sizeof(UINT)); - GetLocaleInfoEx(windowsLocaleName, LOCALE_SMONGROUPING, (LPWSTR)buf, sizeof(buf)); + GetLocaleInfoA(lcid, LOCALE_SMONGROUPING, buf, sizeof(buf)); fmt->Grouping = getGrouping(buf); fmt->lpDecimalSep = NEW_ARRAY(wchar_t, 6); - GetLocaleInfoEx(windowsLocaleName, LOCALE_SMONDECIMALSEP, fmt->lpDecimalSep, 6); + GetLocaleInfoW(lcid, LOCALE_SMONDECIMALSEP, fmt->lpDecimalSep, 6); fmt->lpThousandSep = NEW_ARRAY(wchar_t, 6); - GetLocaleInfoEx(windowsLocaleName, LOCALE_SMONTHOUSANDSEP, fmt->lpThousandSep, 6); + GetLocaleInfoW(lcid, LOCALE_SMONTHOUSANDSEP, fmt->lpThousandSep, 6); - GetLocaleInfoEx(windowsLocaleName, LOCALE_RETURN_NUMBER|LOCALE_INEGCURR, (LPWSTR) &fmt->NegativeOrder, sizeof(UINT)); - GetLocaleInfoEx(windowsLocaleName, LOCALE_RETURN_NUMBER|LOCALE_ICURRENCY, (LPWSTR) &fmt->PositiveOrder, sizeof(UINT)); + GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_INEGCURR, (LPWSTR) &fmt->NegativeOrder, sizeof(UINT)); + GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_ICURRENCY, (LPWSTR) &fmt->PositiveOrder, sizeof(UINT)); fmt->lpCurrencySymbol = NEW_ARRAY(wchar_t, 8); - GetLocaleInfoEx(windowsLocaleName, LOCALE_SCURRENCY, (LPWSTR) fmt->lpCurrencySymbol, 8); + GetLocaleInfoW(lcid, LOCALE_SCURRENCY, (LPWSTR) fmt->lpCurrencySymbol, 8); } static void freeCurrencyFormat(CURRENCYFMTW *fmt) @@ -139,83 +139,12 @@ static void freeCurrencyFormat(CURRENCYFMTW *fmt) } } -// TODO: This is copied in both winnmfmt.cpp and windtfmt.cpp, but really should -// be factored out into a common helper for both. -static UErrorCode GetEquivalentWindowsLocaleName(const Locale& locale, UnicodeString** buffer) -{ - UErrorCode status = U_ZERO_ERROR; - char asciiBCP47Tag[LOCALE_NAME_MAX_LENGTH] = {}; - - // Convert from names like "en_CA" and "de_DE@collation=phonebook" to "en-CA" and "de-DE-u-co-phonebk". - (void) uloc_toLanguageTag(locale.getName(), asciiBCP47Tag, UPRV_LENGTHOF(asciiBCP47Tag), FALSE, &status); - - if (U_SUCCESS(status)) - { - // Need it to be UTF-16, not 8-bit - // TODO: This seems like a good thing for a helper - wchar_t bcp47Tag[LOCALE_NAME_MAX_LENGTH] = {}; - int32_t i; - for (i = 0; i < UPRV_LENGTHOF(bcp47Tag); i++) - { - if (asciiBCP47Tag[i] == '\0') - { - break; - } - else - { - // normally just copy the character - bcp47Tag[i] = static_cast(asciiBCP47Tag[i]); - } - } - - // Ensure it's null terminated - if (i < (UPRV_LENGTHOF(bcp47Tag) - 1)) - { - bcp47Tag[i] = L'\0'; - } - else - { - // Ran out of room. - bcp47Tag[UPRV_LENGTHOF(bcp47Tag) - 1] = L'\0'; - } - - - wchar_t windowsLocaleName[LOCALE_NAME_MAX_LENGTH] = {}; - - // Note: On Windows versions below 10, there is no support for locale name aliases. - // This means that it will fail for locales where ICU has a completely different - // name (like ku vs ckb), and it will also not work for alternate sort locale - // names like "de-DE-u-co-phonebk". - - // TODO: We could add some sort of exception table for cases like ku vs ckb. - - int length = ResolveLocaleName(bcp47Tag, windowsLocaleName, UPRV_LENGTHOF(windowsLocaleName)); - - if (length > 0) - { - *buffer = new UnicodeString(windowsLocaleName); - } - else - { - status = U_UNSUPPORTED_ERROR; - } - } - return status; -} - Win32NumberFormat::Win32NumberFormat(const Locale &locale, UBool currency, UErrorCode &status) - : NumberFormat(), fCurrency(currency), fFormatInfo(NULL), fFractionDigitsSet(FALSE), fWindowsLocaleName(nullptr) + : NumberFormat(), fCurrency(currency), fFormatInfo(NULL), fFractionDigitsSet(FALSE) { if (!U_FAILURE(status)) { fLCID = locale.getLCID(); - GetEquivalentWindowsLocaleName(locale, &fWindowsLocaleName); - // Note: In the previous code, it would look up the LCID for the locale, and if - // the locale was not recognized then it would get an LCID of 0, which is a - // synonym for LOCALE_USER_DEFAULT on Windows. - // If the above method fails, then fWindowsLocaleName will remain as nullptr, and - // then we will pass nullptr to API GetLocaleInfoEx, which is the same as passing - // LOCALE_USER_DEFAULT. // Resolve actual locale to be used later UErrorCode tmpsts = U_ZERO_ERROR; @@ -226,19 +155,12 @@ Win32NumberFormat::Win32NumberFormat(const Locale &locale, UBool currency, UErro fLocale = Locale((const char*)tmpLocID); } - const wchar_t *localeName = nullptr; - - if (fWindowsLocaleName != nullptr) - { - localeName = reinterpret_cast(toOldUCharPtr(fWindowsLocaleName->getTerminatedBuffer())); - } - fFormatInfo = (FormatInfo*)uprv_malloc(sizeof(FormatInfo)); if (fCurrency) { - getCurrencyFormat(&fFormatInfo->currency, localeName); + getCurrencyFormat(&fFormatInfo->currency, fLCID); } else { - getNumberFormat(&fFormatInfo->number, localeName); + getNumberFormat(&fFormatInfo->number, fLCID); } } } @@ -263,7 +185,6 @@ Win32NumberFormat::~Win32NumberFormat() uprv_free(fFormatInfo); } - delete fWindowsLocaleName; } Win32NumberFormat &Win32NumberFormat::operator=(const Win32NumberFormat &other) @@ -274,21 +195,13 @@ Win32NumberFormat &Win32NumberFormat::operator=(const Win32NumberFormat &other) this->fLocale = other.fLocale; this->fLCID = other.fLCID; this->fFractionDigitsSet = other.fFractionDigitsSet; - this->fWindowsLocaleName = other.fWindowsLocaleName == NULL ? NULL : new UnicodeString(*other.fWindowsLocaleName); - const wchar_t *localeName = nullptr; - - if (fWindowsLocaleName != nullptr) - { - localeName = reinterpret_cast(toOldUCharPtr(fWindowsLocaleName->getTerminatedBuffer())); - } - if (fCurrency) { freeCurrencyFormat(&fFormatInfo->currency); - getCurrencyFormat(&fFormatInfo->currency, localeName); + getCurrencyFormat(&fFormatInfo->currency, fLCID); } else { freeNumberFormat(&fFormatInfo->number); - getNumberFormat(&fFormatInfo->number, localeName); + getNumberFormat(&fFormatInfo->number, fLCID); } return *this; @@ -389,13 +302,6 @@ UnicodeString &Win32NumberFormat::format(int32_t numDigits, UnicodeString &appen formatInfo = *fFormatInfo; buffer[0] = 0x0000; - const wchar_t *localeName = nullptr; - - if (fWindowsLocaleName != nullptr) - { - localeName = reinterpret_cast(toOldUCharPtr(fWindowsLocaleName->getTerminatedBuffer())); - } - if (fCurrency) { if (fFractionDigitsSet) { formatInfo.currency.NumDigits = (UINT) numDigits; @@ -405,17 +311,17 @@ UnicodeString &Win32NumberFormat::format(int32_t numDigits, UnicodeString &appen formatInfo.currency.Grouping = 0; } - result = GetCurrencyFormatEx(localeName, 0, nBuffer, &formatInfo.currency, buffer, STACK_BUFFER_SIZE); + result = GetCurrencyFormatW(fLCID, 0, nBuffer, &formatInfo.currency, buffer, STACK_BUFFER_SIZE); if (result == 0) { DWORD lastError = GetLastError(); if (lastError == ERROR_INSUFFICIENT_BUFFER) { - int newLength = GetCurrencyFormatEx(localeName, 0, nBuffer, &formatInfo.currency, NULL, 0); + int newLength = GetCurrencyFormatW(fLCID, 0, nBuffer, &formatInfo.currency, NULL, 0); buffer = NEW_ARRAY(wchar_t, newLength); buffer[0] = 0x0000; - GetCurrencyFormatEx(localeName, 0, nBuffer, &formatInfo.currency, buffer, newLength); + GetCurrencyFormatW(fLCID, 0, nBuffer, &formatInfo.currency, buffer, newLength); } } } else { @@ -427,15 +333,15 @@ UnicodeString &Win32NumberFormat::format(int32_t numDigits, UnicodeString &appen formatInfo.number.Grouping = 0; } - result = GetNumberFormatEx(localeName, 0, nBuffer, &formatInfo.number, buffer, STACK_BUFFER_SIZE); + result = GetNumberFormatW(fLCID, 0, nBuffer, &formatInfo.number, buffer, STACK_BUFFER_SIZE); if (result == 0) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - int newLength = GetNumberFormatEx(localeName, 0, nBuffer, &formatInfo.number, NULL, 0); + int newLength = GetNumberFormatW(fLCID, 0, nBuffer, &formatInfo.number, NULL, 0); buffer = NEW_ARRAY(wchar_t, newLength); buffer[0] = 0x0000; - GetNumberFormatEx(localeName, 0, nBuffer, &formatInfo.number, buffer, newLength); + GetNumberFormatW(fLCID, 0, nBuffer, &formatInfo.number, buffer, newLength); } } } diff --git a/intl/icu/source/i18n/winnmfmt.h b/intl/icu/source/i18n/winnmfmt.h index 6139c1ff68..331d535495 100644 --- a/intl/icu/source/i18n/winnmfmt.h +++ b/intl/icu/source/i18n/winnmfmt.h @@ -154,8 +154,6 @@ private: int32_t fLCID; FormatInfo *fFormatInfo; UBool fFractionDigitsSet; - - UnicodeString* fWindowsLocaleName; // Stores the equivalent Windows locale name. }; U_NAMESPACE_END