ICU: replace windows related source files with those from mypal68 (ICU 64.2)

This commit is contained in:
roytam1 2022-07-26 23:55:00 +08:00
commit 3a65ef9ca8
10 changed files with 503 additions and 689 deletions

View file

@ -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 <windows.h>
#include <winnls.h>
#include <winnls.h> // 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<int32_t>(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)

View file

@ -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 */

View file

@ -103,17 +103,6 @@
# include <windows.h>
# 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 <Windows.Globalization.h>
#include <windows.system.userprofile.h>
#include <wrl/wrappers/corewrappers.h>
#include <wrl/client.h>
using namespace ABI::Windows::Foundation;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
#endif
#elif U_PLATFORM == U_PF_OS400
# include <float.h>
# include <qusec.h> /* 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<char *>(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<char *>(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<char *>(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<char>(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<char *>(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<char *>(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);
}
}

View file

@ -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<numKeywords; ++j) {
if (uprv_strcmp(keywordList[j].keyword, addKeyword) == 0) {
duplicate = TRUE;
break;
}
}
if (!duplicate) {
if (numKeywords == maxKeywords) {
*status = U_INTERNAL_PROGRAM_ERROR;
return 0;
}
uprv_strcpy(keywordList[numKeywords].keyword, addKeyword);
keywordList[numKeywords].keywordLen = (int32_t)uprv_strlen(addKeyword);
keywordList[numKeywords].valueStart = addValue;
keywordList[numKeywords].valueLen = (int32_t)uprv_strlen(addValue);
++numKeywords;
}
} else {
U_ASSERT(addValue == NULL);
}
/* now we have a list of keywords */
/* we need to sort it */
uprv_sortArray(keywordList, numKeywords, sizeof(KeywordStruct), compareKeywordStructs, NULL, FALSE, status);
@ -839,7 +754,7 @@ locale_getKeywords(const char *localeID,
UErrorCode *status) {
return _getKeywords(localeID, prev, keywords, keywordCapacity,
values, valuesCapacity, valLen, valuesToo,
NULL, NULL, status);
status);
}
U_CAPI int32_t U_EXPORT2
@ -1188,20 +1103,6 @@ uloc_setKeywordValue(const char* keywordName,
*/
#define _isTerminator(a) ((a==0)||(a=='.')||(a=='@'))
static char* _strnchr(const char* str, int32_t len, char c) {
U_ASSERT(str != 0 && len >= 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<languageCapacity) {
@ -1476,50 +1387,6 @@ _getVariant(const char *localeID,
return _getVariantEx(localeID, prev, variant, variantCapacity, FALSE);
}
/**
* Delete ALL instances of a variant from the given list of one or
* more variants. Example: "FOO_EURO_BAR_EURO" => "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<UPRV_LENGTHOF(VARIANT_MAP); j++) {
const char* variantToCompare = VARIANT_MAP[j].variant;
int32_t n = (int32_t)uprv_strlen(variantToCompare);
int32_t variantLen = _deleteVariant(variant, uprv_min(variantSize, (nameCapacity-len)), variantToCompare, n);
len -= variantLen;
if (variantLen > 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<UPRV_LENGTHOF(CANONICALIZE_MAP); j++) {
const char* id = CANONICALIZE_MAP[j].id;
@ -1894,10 +1738,6 @@ _canonicalize(const char* localeID,
break; /* Don't remap "" if keywords present */
}
len = _copyCount(name, nameCapacity, CANONICALIZE_MAP[j].canonicalID);
if (CANONICALIZE_MAP[j].keyword) {
addKeyword = CANONICALIZE_MAP[j].keyword;
addValue = CANONICALIZE_MAP[j].value;
}
break;
}
}
@ -1912,14 +1752,7 @@ _canonicalize(const char* localeID,
++len;
++fieldCount;
len += _getKeywords(tmpLocaleID+1, '@', (len<nameCapacity ? name+len : NULL), nameCapacity-len,
NULL, 0, NULL, TRUE, addKeyword, addValue, err);
} else if (addKeyword != NULL) {
U_ASSERT(addValue != NULL && len < nameCapacity);
/* inelegant but works -- later make _getKeywords do this? */
len += _copyCount(name+len, nameCapacity-len, "@");
len += _copyCount(name+len, nameCapacity-len, addKeyword);
len += _copyCount(name+len, nameCapacity-len, "=");
len += _copyCount(name+len, nameCapacity-len, addValue);
NULL, 0, NULL, TRUE, err);
}
}
@ -1954,9 +1787,16 @@ uloc_getParent(const char* localeID,
i=0;
}
if(i>0 && parent != localeID) {
uprv_memcpy(parent, localeID, uprv_min(i, parentCapacity));
if (i > 0) {
if (uprv_strnicmp(localeID, "und_", 4) == 0) {
localeID += 3;
i -= 3;
uprv_memmove(parent, localeID, uprv_min(i, parentCapacity));
} else if (parent != localeID) {
uprv_memcpy(parent, localeID, uprv_min(i, parentCapacity));
}
}
return u_terminateChars(parent, parentCapacity, i, err);
}
@ -2172,23 +2012,14 @@ uloc_getLCID(const char* localeID)
{
UErrorCode status = U_ZERO_ERROR;
char langID[ULOC_FULLNAME_CAPACITY];
uint32_t lcid = 0;
/* Check for incomplete id. */
if (!localeID || uprv_strlen(localeID) < 2) {
return 0;
}
// Attempt platform lookup if available
lcid = uprv_convertToLCIDPlatform(localeID);
if (lcid > 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;
}

View file

@ -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 <windows.h>
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<DWORD>(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<const UChar *>(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 <cbrown@xnetinc.com>
*/
/**
* 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<const UChar*>(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<const UChar*>(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) */

View file

@ -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 */

View file

@ -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<wchar_t>(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<const wchar_t*>(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<const wchar_t*>(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);
}
}

View file

@ -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

View file

@ -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<wchar_t>(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<const wchar_t*>(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<const wchar_t*>(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<const wchar_t*>(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);
}
}
}

View file

@ -154,8 +154,6 @@ private:
int32_t fLCID;
FormatInfo *fFormatInfo;
UBool fFractionDigitsSet;
UnicodeString* fWindowsLocaleName; // Stores the equivalent Windows locale name.
};
U_NAMESPACE_END