mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-30 04:17:31 +09:00
ICU: replace windows related source files with those from mypal68 (ICU 64.2)
This commit is contained in:
parent
1822f2031e
commit
3a65ef9ca8
10 changed files with 503 additions and 689 deletions
|
|
@ -32,18 +32,9 @@
|
||||||
#include "cmemory.h"
|
#include "cmemory.h"
|
||||||
#include "unicode/uloc.h"
|
#include "unicode/uloc.h"
|
||||||
|
|
||||||
#if U_PLATFORM == U_PF_WINDOWS && defined(_MSC_VER) && (_MSC_VER >= 1500)
|
#if U_PLATFORM_HAS_WIN32_API && UCONFIG_USE_WINDOWS_LCID_MAPPING_API
|
||||||
/*
|
|
||||||
* 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
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <winnls.h>
|
#include <winnls.h> // LCIDToLocaleName and LocaleNameToLCID
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -973,7 +964,7 @@ idCmp(const char* id1, const char* id2)
|
||||||
/**
|
/**
|
||||||
* Searches for a Windows LCID
|
* 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
|
* @param status gets set to U_ILLEGAL_ARGUMENT_ERROR when the Posix ID has
|
||||||
* no equivalent Windows LCID.
|
* no equivalent Windows LCID.
|
||||||
* @return the 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:
|
* Various language tags needs to be changed:
|
||||||
* quz -> qu
|
* quz -> qu
|
||||||
|
|
@ -1053,6 +1044,7 @@ getPosixID(const ILcidPosixMap *this_0, uint32_t hostID)
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
U_CAPI int32_t
|
U_CAPI int32_t
|
||||||
uprv_convertToPosix(uint32_t hostid, char *posixID, int32_t posixIDCapacity, UErrorCode* status)
|
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;
|
UBool bLookup = TRUE;
|
||||||
const char *pPosixID = NULL;
|
const char *pPosixID = NULL;
|
||||||
|
|
||||||
#ifdef USE_WINDOWS_LCID_MAPPING_API
|
#if U_PLATFORM_HAS_WIN32_API && UCONFIG_USE_WINDOWS_LCID_MAPPING_API
|
||||||
char locName[LOCALE_NAME_MAX_LENGTH] = {}; // ICU name can't be longer than Windows name
|
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
|
// 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
|
// 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.
|
// use the Windows API to resolve locale ID for this specific case.
|
||||||
if ((hostid & 0x3FF) != 0x92) {
|
if ((hostid & 0x3FF) != 0x92) {
|
||||||
int32_t tmpLen = 0;
|
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.
|
// 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) {
|
if (tmpLen > 1) {
|
||||||
int32_t i = 0;
|
/* Windows locale name may contain sorting variant, such as "es-ES_tradnl".
|
||||||
// Only need to look up in table if have _, eg for de-de_phoneb type alternate sort.
|
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);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* No hardcoded table lookup necessary */
|
||||||
bLookup = FALSE;
|
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'-')
|
/* Change the tag separator from '-' to '_' */
|
||||||
{
|
p = locName;
|
||||||
// Windows names use -, ICU uses _
|
while (*p) {
|
||||||
locName[i] = '_';
|
if (*p == '-') {
|
||||||
|
*p = '_';
|
||||||
}
|
}
|
||||||
else if (windowsLocaleName[i] == L'\0')
|
p++;
|
||||||
{
|
|
||||||
// No point in doing more work than necessary
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// TODO: Need to understand this better, why isn't it an alias?
|
|
||||||
FIX_LANGUAGE_ID_TAG(locName, tmpLen);
|
FIX_LANGUAGE_ID_TAG(locName, tmpLen);
|
||||||
pPosixID = locName;
|
pPosixID = locName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // USE_WINDOWS_LCID_MAPPING_API
|
#endif
|
||||||
|
|
||||||
if (bLookup) {
|
if (bLookup) {
|
||||||
const char *pCandidate = NULL;
|
const char *pCandidate = NULL;
|
||||||
|
|
@ -1132,7 +1116,7 @@ uprv_convertToPosix(uint32_t hostid, char *posixID, int32_t posixIDCapacity, UEr
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pPosixID) {
|
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;
|
int32_t copyLen = resLen <= posixIDCapacity ? resLen : posixIDCapacity;
|
||||||
uprv_memcpy(posixID, pPosixID, copyLen);
|
uprv_memcpy(posixID, pPosixID, copyLen);
|
||||||
if (resLen < posixIDCapacity) {
|
if (resLen < posixIDCapacity) {
|
||||||
|
|
@ -1162,21 +1146,16 @@ uprv_convertToPosix(uint32_t hostid, char *posixID, int32_t posixIDCapacity, UEr
|
||||||
//
|
//
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
*/
|
*/
|
||||||
U_CAPI uint32_t
|
/*U_CAPI uint32_t
|
||||||
uprv_convertToLCIDPlatform(const char* localeID)
|
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.
|
// conversion functionality when available.
|
||||||
#ifdef USE_WINDOWS_LCID_MAPPING_API
|
#if U_PLATFORM_HAS_WIN32_API && UCONFIG_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 */
|
|
||||||
|
|
||||||
int32_t len;
|
int32_t len;
|
||||||
char collVal[ULOC_KEYWORDS_CAPACITY] = {};
|
char collVal[ULOC_KEYWORDS_CAPACITY] = {};
|
||||||
char baseName[ULOC_FULLNAME_CAPACITY] = {};
|
char baseName[ULOC_FULLNAME_CAPACITY] = {};
|
||||||
|
|
@ -1185,8 +1164,8 @@ uprv_convertToLCIDPlatform(const char* localeID)
|
||||||
// Check any for keywords.
|
// Check any for keywords.
|
||||||
if (uprv_strchr(localeID, '@'))
|
if (uprv_strchr(localeID, '@'))
|
||||||
{
|
{
|
||||||
len = uloc_getKeywordValue(localeID, "collation", collVal, UPRV_LENGTHOF(collVal) - 1, &myStatus);
|
len = uloc_getKeywordValue(localeID, "collation", collVal, UPRV_LENGTHOF(collVal) - 1, status);
|
||||||
if (U_SUCCESS(myStatus) && len > 0)
|
if (U_SUCCESS(*status) && len > 0)
|
||||||
{
|
{
|
||||||
// If it contains the keyword collation, return 0 so that the LCID lookup table will be used.
|
// If it contains the keyword collation, return 0 so that the LCID lookup table will be used.
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -1194,9 +1173,9 @@ uprv_convertToLCIDPlatform(const char* localeID)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If the locale ID contains keywords other than collation, just use the base name.
|
// 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;
|
baseName[len] = 0;
|
||||||
mylocaleID = baseName;
|
mylocaleID = baseName;
|
||||||
|
|
@ -1206,9 +1185,9 @@ uprv_convertToLCIDPlatform(const char* localeID)
|
||||||
|
|
||||||
char asciiBCP47Tag[LOCALE_NAME_MAX_LENGTH] = {};
|
char asciiBCP47Tag[LOCALE_NAME_MAX_LENGTH] = {};
|
||||||
// this will change it from de_DE@collation=phonebook to de-DE-u-co-phonebk form
|
// 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
|
// Need it to be UTF-16, not 8-bit
|
||||||
wchar_t bcp47Tag[LOCALE_NAME_MAX_LENGTH] = {};
|
wchar_t bcp47Tag[LOCALE_NAME_MAX_LENGTH] = {};
|
||||||
|
|
@ -1230,7 +1209,7 @@ uprv_convertToLCIDPlatform(const char* localeID)
|
||||||
{
|
{
|
||||||
// Ensure it's null terminated
|
// Ensure it's null terminated
|
||||||
bcp47Tag[i] = L'\0';
|
bcp47Tag[i] = L'\0';
|
||||||
LCID lcid = LocaleNameToLCID(bcp47Tag, nameLCIDFlags);
|
LCID lcid = LocaleNameToLCID(bcp47Tag, LOCALE_ALLOW_NEUTRAL_NAMES);
|
||||||
if (lcid > 0)
|
if (lcid > 0)
|
||||||
{
|
{
|
||||||
// Found LCID from windows, return that one, unless its completely ambiguous
|
// Found LCID from windows, return that one, unless its completely ambiguous
|
||||||
|
|
@ -1244,12 +1223,12 @@ uprv_convertToLCIDPlatform(const char* localeID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
(void)localeID; // Suppress unused variable warning.
|
(void) localeID; // Suppress unused variable warning.
|
||||||
#endif /* USE_WINDOWS_LCID_MAPPING_API */
|
#endif
|
||||||
|
|
||||||
// No found, or not implemented on platforms without native name->lcid conversion
|
// Nothing found, or not implemented.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
U_CAPI uint32_t
|
U_CAPI uint32_t
|
||||||
uprv_convertToLCID(const char *langID, const char* posixID, UErrorCode* status)
|
uprv_convertToLCID(const char *langID, const char* posixID, UErrorCode* status)
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,8 @@
|
||||||
U_CAPI int32_t uprv_convertToPosix(uint32_t hostid, char* posixID, int32_t posixIDCapacity, UErrorCode* status);
|
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. */
|
/* 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_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);
|
U_CAPI uint32_t uprv_convertToLCID(const char* langID, const char* posixID, UErrorCode* status);
|
||||||
|
|
||||||
#endif /* LOCMAP_H */
|
#endif /* LOCMAP_H */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,17 +103,6 @@
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
# include "unicode/uloc.h"
|
# include "unicode/uloc.h"
|
||||||
# include "wintz.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
|
#elif U_PLATFORM == U_PF_OS400
|
||||||
# include <float.h>
|
# include <float.h>
|
||||||
# include <qusec.h> /* error code structure */
|
# 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_t0 = 0; /** Time to start the clock from **/
|
||||||
UDate fakeClock_dt = 0; /** Offset (fake time - real time) **/
|
UDate fakeClock_dt = 0; /** Offset (fake time - real time) **/
|
||||||
UBool fakeClock_set = FALSE; /** True if fake clock has spun up **/
|
UBool fakeClock_set = FALSE; /** True if fake clock has spun up **/
|
||||||
static UMutex fakeClockMutex = U_MUTEX_INTIALIZER;
|
|
||||||
|
|
||||||
static UDate getUTCtime_real() {
|
static UDate getUTCtime_real() {
|
||||||
struct timeval posixTime;
|
struct timeval posixTime;
|
||||||
|
|
@ -261,6 +249,7 @@ static UDate getUTCtime_real() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static UDate getUTCtime_fake() {
|
static UDate getUTCtime_fake() {
|
||||||
|
static UMutex fakeClockMutex = U_MUTEX_INTIALIZER;
|
||||||
umtx_lock(&fakeClockMutex);
|
umtx_lock(&fakeClockMutex);
|
||||||
if(!fakeClock_set) {
|
if(!fakeClock_set) {
|
||||||
UDate real = getUTCtime_real();
|
UDate real = getUTCtime_real();
|
||||||
|
|
@ -997,7 +986,8 @@ static char* searchForTZFile(const char* path, DefaultTZInfo* tzInfo) {
|
||||||
/* Check each entry in the directory. */
|
/* Check each entry in the directory. */
|
||||||
while((dirEntry = readdir(dirp)) != NULL) {
|
while((dirEntry = readdir(dirp)) != NULL) {
|
||||||
const char* dirName = dirEntry->d_name;
|
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. */
|
/* Create a newpath with the new entry to test each entry in the directory. */
|
||||||
CharString newpath(curpath, status);
|
CharString newpath(curpath, status);
|
||||||
newpath.append(dirName, -1, status);
|
newpath.append(dirName, -1, status);
|
||||||
|
|
@ -1024,7 +1014,7 @@ static char* searchForTZFile(const char* path, DefaultTZInfo* tzInfo) {
|
||||||
*/
|
*/
|
||||||
if (result != NULL)
|
if (result != NULL)
|
||||||
break;
|
break;
|
||||||
} else if (uprv_strcmp(TZFILE_SKIP, dirName) != 0 && uprv_strcmp(TZFILE_SKIP2, dirName) != 0) {
|
} else {
|
||||||
if(compareBinaryFiles(TZDEFAULT, newpath.data(), tzInfo)) {
|
if(compareBinaryFiles(TZDEFAULT, newpath.data(), tzInfo)) {
|
||||||
int32_t amountToSkip = sizeof(TZZONEINFO) - 1;
|
int32_t amountToSkip = sizeof(TZZONEINFO) - 1;
|
||||||
if (amountToSkip > newpath.length()) {
|
if (amountToSkip > newpath.length()) {
|
||||||
|
|
@ -1078,7 +1068,7 @@ uprv_tzname(int n)
|
||||||
// the other code path returns a pointer to a heap location.
|
// 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
|
// If we don't have a name already, then tzname wouldn't be any
|
||||||
// better, so just fall back.
|
// better, so just fall back.
|
||||||
return uprv_strdup("Etc/UTC");
|
return uprv_strdup("");
|
||||||
#endif // !U_TZNAME
|
#endif // !U_TZNAME
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
@ -1317,9 +1307,9 @@ uprv_pathIsAbsolute(const char *path)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Temporary backup setting of ICU_DATA_DIR_PREFIX_ENV_VAR
|
/* Backup setting of ICU_DATA_DIR_PREFIX_ENV_VAR
|
||||||
until some client wrapper makefiles are updated */
|
(needed for some Darwin ICU build environments) */
|
||||||
#if U_PLATFORM_IS_DARWIN_BASED && TARGET_IPHONE_SIMULATOR
|
#if U_PLATFORM_IS_DARWIN_BASED && TARGET_OS_SIMULATOR
|
||||||
# if !defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
|
# if !defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
|
||||||
# define ICU_DATA_DIR_PREFIX_ENV_VAR "IPHONE_SIMULATOR_ROOT"
|
# define ICU_DATA_DIR_PREFIX_ENV_VAR "IPHONE_SIMULATOR_ROOT"
|
||||||
# endif
|
# endif
|
||||||
|
|
@ -1430,12 +1420,7 @@ static void U_CALLCONV dataDirectoryInitFn() {
|
||||||
|
|
||||||
if(path==NULL) {
|
if(path==NULL) {
|
||||||
/* It looks really bad, set it to something. */
|
/* 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 = "";
|
path = "";
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u_setDataDirectory(path);
|
u_setDataDirectory(path);
|
||||||
|
|
@ -1633,11 +1618,7 @@ The variant cannot have dots in it.
|
||||||
The 'rightmost' variant (@xxx) wins.
|
The 'rightmost' variant (@xxx) wins.
|
||||||
The leftmost codepage (.xxx) wins.
|
The leftmost codepage (.xxx) wins.
|
||||||
*/
|
*/
|
||||||
char *correctedPOSIXLocale = 0;
|
|
||||||
const char* posixID = uprv_getPOSIXIDForDefaultLocale();
|
const char* posixID = uprv_getPOSIXIDForDefaultLocale();
|
||||||
const char *p;
|
|
||||||
const char *q;
|
|
||||||
int32_t len;
|
|
||||||
|
|
||||||
/* Format: (no spaces)
|
/* Format: (no spaces)
|
||||||
ll [ _CC ] [ . MM ] [ @ VV]
|
ll [ _CC ] [ . MM ] [ @ VV]
|
||||||
|
|
@ -1645,38 +1626,29 @@ The leftmost codepage (.xxx) wins.
|
||||||
l = lang, C = ctry, M = charmap, V = variant
|
l = lang, C = ctry, M = charmap, V = variant
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (gCorrectedPOSIXLocale != NULL) {
|
if (gCorrectedPOSIXLocale != nullptr) {
|
||||||
return gCorrectedPOSIXLocale;
|
return gCorrectedPOSIXLocale;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((p = uprv_strchr(posixID, '.')) != NULL) {
|
// Copy the ID into owned memory.
|
||||||
/* assume new locale can't be larger than old one? */
|
// Over-allocate in case we replace "@" with "__".
|
||||||
correctedPOSIXLocale = static_cast<char *>(uprv_malloc(uprv_strlen(posixID)+1));
|
char *correctedPOSIXLocale = static_cast<char *>(uprv_malloc(uprv_strlen(posixID) + 1 + 1));
|
||||||
/* Exit on memory allocation error. */
|
if (correctedPOSIXLocale == nullptr) {
|
||||||
if (correctedPOSIXLocale == NULL) {
|
return nullptr;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
uprv_strncpy(correctedPOSIXLocale, posixID, p-posixID);
|
uprv_strcpy(correctedPOSIXLocale, posixID);
|
||||||
correctedPOSIXLocale[p-posixID] = 0;
|
|
||||||
|
|
||||||
/* do not copy after the @ */
|
char *limit;
|
||||||
if ((p = uprv_strchr(correctedPOSIXLocale, '@')) != NULL) {
|
if ((limit = uprv_strchr(correctedPOSIXLocale, '.')) != nullptr) {
|
||||||
correctedPOSIXLocale[p-correctedPOSIXLocale] = 0;
|
*limit = 0;
|
||||||
|
if ((limit = uprv_strchr(correctedPOSIXLocale, '@')) != nullptr) {
|
||||||
|
*limit = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note that we scan the *uncorrected* ID. */
|
/* Note that we scan the *uncorrected* ID. */
|
||||||
if ((p = uprv_strrchr(posixID, '@')) != NULL) {
|
const char *p;
|
||||||
if (correctedPOSIXLocale == NULL) {
|
if ((p = uprv_strrchr(posixID, '@')) != nullptr) {
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
/* Take care of any special cases here.. */
|
/* 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. */
|
/* 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) */
|
uprv_strcat(correctedPOSIXLocale, "__"); /* aa@b -> aa__b (note this can make the new locale 1 char longer) */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
uprv_strcat(correctedPOSIXLocale, "_"); /* aa_CC@b -> aa_CC_b */
|
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? */
|
/* 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);
|
uprv_strncat(correctedPOSIXLocale, p, q-p);
|
||||||
correctedPOSIXLocale[len] = 0;
|
correctedPOSIXLocale[len] = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1710,28 +1683,15 @@ The leftmost codepage (.xxx) wins.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Was a correction made? */
|
if (gCorrectedPOSIXLocale == nullptr) {
|
||||||
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) {
|
|
||||||
gCorrectedPOSIXLocale = correctedPOSIXLocale;
|
gCorrectedPOSIXLocale = correctedPOSIXLocale;
|
||||||
gCorrectedPOSIXLocaleHeapAllocated = true;
|
gCorrectedPOSIXLocaleHeapAllocated = true;
|
||||||
ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
|
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);
|
uprv_free(correctedPOSIXLocale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1747,60 +1707,18 @@ The leftmost codepage (.xxx) wins.
|
||||||
return gCorrectedPOSIXLocale;
|
return gCorrectedPOSIXLocale;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No cached value, need to determine the current value
|
LCID id = GetThreadLocale();
|
||||||
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));
|
correctedPOSIXLocale = static_cast<char *>(uprv_malloc(POSIX_LOCALE_CAPACITY + 1));
|
||||||
/* TODO: Should we just exit on memory allocation failure? */
|
if (correctedPOSIXLocale) {
|
||||||
if (correctedPOSIXLocale)
|
int32_t posixLen = uprv_convertToPosix(id, correctedPOSIXLocale, POSIX_LOCALE_CAPACITY, &status);
|
||||||
{
|
if (U_SUCCESS(status)) {
|
||||||
int32_t posixLen = uloc_canonicalize(modifiedWindowsLocale, correctedPOSIXLocale, POSIX_LOCALE_CAPACITY, &status);
|
|
||||||
if (U_SUCCESS(status))
|
|
||||||
{
|
|
||||||
*(correctedPOSIXLocale + posixLen) = 0;
|
*(correctedPOSIXLocale + posixLen) = 0;
|
||||||
gCorrectedPOSIXLocale = correctedPOSIXLocale;
|
gCorrectedPOSIXLocale = correctedPOSIXLocale;
|
||||||
gCorrectedPOSIXLocaleHeapAllocated = true;
|
|
||||||
ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
|
ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
uprv_free(correctedPOSIXLocale);
|
uprv_free(correctedPOSIXLocale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// If unable to find a locale we can agree upon, use en-US by default
|
// If unable to find a locale we can agree upon, use en-US by default
|
||||||
if (gCorrectedPOSIXLocale == nullptr) {
|
if (gCorrectedPOSIXLocale == nullptr) {
|
||||||
|
|
|
||||||
|
|
@ -457,8 +457,6 @@ NULL
|
||||||
typedef struct CanonicalizationMap {
|
typedef struct CanonicalizationMap {
|
||||||
const char *id; /* input ID */
|
const char *id; /* input ID */
|
||||||
const char *canonicalID; /* canonicalized output 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;
|
} CanonicalizationMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -466,64 +464,16 @@ typedef struct CanonicalizationMap {
|
||||||
* different semantic kinds of transformations.
|
* different semantic kinds of transformations.
|
||||||
*/
|
*/
|
||||||
static const CanonicalizationMap CANONICALIZE_MAP[] = {
|
static const CanonicalizationMap CANONICALIZE_MAP[] = {
|
||||||
{ "", "en_US_POSIX", NULL, NULL }, /* .NET name */
|
{ "art_LOJBAN", "jbo" }, /* registered name */
|
||||||
{ "c", "en_US_POSIX", NULL, NULL }, /* POSIX name */
|
{ "hy__AREVELA", "hy" }, /* Registered IANA variant */
|
||||||
{ "posix", "en_US_POSIX", NULL, NULL }, /* POSIX name (alias of C) */
|
{ "hy__AREVMDA", "hyw" }, /* Registered IANA variant */
|
||||||
{ "art_LOJBAN", "jbo", NULL, NULL }, /* registered name */
|
{ "zh_GAN", "gan" }, /* registered name */
|
||||||
{ "az_AZ_CYRL", "az_Cyrl_AZ", NULL, NULL }, /* .NET name */
|
{ "zh_GUOYU", "zh" }, /* registered name */
|
||||||
{ "az_AZ_LATN", "az_Latn_AZ", NULL, NULL }, /* .NET name */
|
{ "zh_HAKKA", "hak" }, /* registered name */
|
||||||
{ "ca_ES_PREEURO", "ca_ES", "currency", "ESP" },
|
{ "zh_MIN_NAN", "nan" }, /* registered name */
|
||||||
{ "de__PHONEBOOK", "de", "collation", "phonebook" }, /* Old ICU name */
|
{ "zh_WUU", "wuu" }, /* registered name */
|
||||||
{ "de_AT_PREEURO", "de_AT", "currency", "ATS" },
|
{ "zh_XIANG", "hsn" }, /* registered name */
|
||||||
{ "de_DE_PREEURO", "de_DE", "currency", "DEM" },
|
{ "zh_YUE", "yue" }, /* registered name */
|
||||||
{ "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 */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ### BCP47 Conversion *******************************************/
|
/* ### BCP47 Conversion *******************************************/
|
||||||
|
|
@ -643,20 +593,12 @@ compareKeywordStructs(const void * /*context*/, const void *left, const void *ri
|
||||||
return uprv_strcmp(leftString, rightString);
|
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
|
static int32_t
|
||||||
_getKeywords(const char *localeID,
|
_getKeywords(const char *localeID,
|
||||||
char prev,
|
char prev,
|
||||||
char *keywords, int32_t keywordCapacity,
|
char *keywords, int32_t keywordCapacity,
|
||||||
char *values, int32_t valuesCapacity, int32_t *valLen,
|
char *values, int32_t valuesCapacity, int32_t *valLen,
|
||||||
UBool valuesToo,
|
UBool valuesToo,
|
||||||
const char* addKeyword,
|
|
||||||
const char* addValue,
|
|
||||||
UErrorCode *status)
|
UErrorCode *status)
|
||||||
{
|
{
|
||||||
KeywordStruct keywordList[ULOC_MAX_NO_KEYWORDS];
|
KeywordStruct keywordList[ULOC_MAX_NO_KEYWORDS];
|
||||||
|
|
@ -755,33 +697,6 @@ _getKeywords(const char *localeID,
|
||||||
}
|
}
|
||||||
} while(pos);
|
} 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 */
|
/* now we have a list of keywords */
|
||||||
/* we need to sort it */
|
/* we need to sort it */
|
||||||
uprv_sortArray(keywordList, numKeywords, sizeof(KeywordStruct), compareKeywordStructs, NULL, FALSE, status);
|
uprv_sortArray(keywordList, numKeywords, sizeof(KeywordStruct), compareKeywordStructs, NULL, FALSE, status);
|
||||||
|
|
@ -839,7 +754,7 @@ locale_getKeywords(const char *localeID,
|
||||||
UErrorCode *status) {
|
UErrorCode *status) {
|
||||||
return _getKeywords(localeID, prev, keywords, keywordCapacity,
|
return _getKeywords(localeID, prev, keywords, keywordCapacity,
|
||||||
values, valuesCapacity, valLen, valuesToo,
|
values, valuesCapacity, valLen, valuesToo,
|
||||||
NULL, NULL, status);
|
status);
|
||||||
}
|
}
|
||||||
|
|
||||||
U_CAPI int32_t U_EXPORT2
|
U_CAPI int32_t U_EXPORT2
|
||||||
|
|
@ -1188,20 +1103,6 @@ uloc_setKeywordValue(const char* keywordName,
|
||||||
*/
|
*/
|
||||||
#define _isTerminator(a) ((a==0)||(a=='.')||(a=='@'))
|
#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
|
* Lookup 'key' in the array 'list'. The array 'list' should contain
|
||||||
* a NULL entry, followed by more entries, and a second NULL entry.
|
* a NULL entry, followed by more entries, and a second NULL entry.
|
||||||
|
|
@ -1279,6 +1180,16 @@ ulocimp_getLanguage(const char *localeID,
|
||||||
int32_t offset;
|
int32_t offset;
|
||||||
char lang[4]={ 0, 0, 0, 0 }; /* temporary buffer to hold language code for searching */
|
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 it starts with i- or x- then copy that prefix */
|
||||||
if(_isIDPrefix(localeID)) {
|
if(_isIDPrefix(localeID)) {
|
||||||
if(i<languageCapacity) {
|
if(i<languageCapacity) {
|
||||||
|
|
@ -1476,50 +1387,6 @@ _getVariant(const char *localeID,
|
||||||
return _getVariantEx(localeID, prev, variant, variantCapacity, FALSE);
|
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 */
|
/* Keyword enumeration */
|
||||||
|
|
||||||
typedef struct UKeywordsContext {
|
typedef struct UKeywordsContext {
|
||||||
|
|
@ -1698,8 +1565,6 @@ _canonicalize(const char* localeID,
|
||||||
const char* tmpLocaleID;
|
const char* tmpLocaleID;
|
||||||
const char* keywordAssign = NULL;
|
const char* keywordAssign = NULL;
|
||||||
const char* separatorIndicator = NULL;
|
const char* separatorIndicator = NULL;
|
||||||
const char* addKeyword = NULL;
|
|
||||||
const char* addValue = NULL;
|
|
||||||
char* name;
|
char* name;
|
||||||
char* variant = NULL; /* pointer into name, or NULL */
|
char* variant = NULL; /* pointer into name, or NULL */
|
||||||
|
|
||||||
|
|
@ -1738,7 +1603,7 @@ _canonicalize(const char* localeID,
|
||||||
len = (int32_t)uprv_strlen(d);
|
len = (int32_t)uprv_strlen(d);
|
||||||
|
|
||||||
if (name != NULL) {
|
if (name != NULL) {
|
||||||
uprv_strncpy(name, d, len);
|
uprv_memcpy(name, d, len);
|
||||||
}
|
}
|
||||||
} else if(_isIDSeparator(*tmpLocaleID)) {
|
} else if(_isIDSeparator(*tmpLocaleID)) {
|
||||||
const char *scriptID;
|
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 */
|
/* Look up the ID in the canonicalization map */
|
||||||
for (j=0; j<UPRV_LENGTHOF(CANONICALIZE_MAP); j++) {
|
for (j=0; j<UPRV_LENGTHOF(CANONICALIZE_MAP); j++) {
|
||||||
const char* id = CANONICALIZE_MAP[j].id;
|
const char* id = CANONICALIZE_MAP[j].id;
|
||||||
|
|
@ -1894,10 +1738,6 @@ _canonicalize(const char* localeID,
|
||||||
break; /* Don't remap "" if keywords present */
|
break; /* Don't remap "" if keywords present */
|
||||||
}
|
}
|
||||||
len = _copyCount(name, nameCapacity, CANONICALIZE_MAP[j].canonicalID);
|
len = _copyCount(name, nameCapacity, CANONICALIZE_MAP[j].canonicalID);
|
||||||
if (CANONICALIZE_MAP[j].keyword) {
|
|
||||||
addKeyword = CANONICALIZE_MAP[j].keyword;
|
|
||||||
addValue = CANONICALIZE_MAP[j].value;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1912,14 +1752,7 @@ _canonicalize(const char* localeID,
|
||||||
++len;
|
++len;
|
||||||
++fieldCount;
|
++fieldCount;
|
||||||
len += _getKeywords(tmpLocaleID+1, '@', (len<nameCapacity ? name+len : NULL), nameCapacity-len,
|
len += _getKeywords(tmpLocaleID+1, '@', (len<nameCapacity ? name+len : NULL), nameCapacity-len,
|
||||||
NULL, 0, NULL, TRUE, addKeyword, addValue, err);
|
NULL, 0, NULL, TRUE, 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1954,9 +1787,16 @@ uloc_getParent(const char* localeID,
|
||||||
i=0;
|
i=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(i>0 && parent != localeID) {
|
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));
|
uprv_memcpy(parent, localeID, uprv_min(i, parentCapacity));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return u_terminateChars(parent, parentCapacity, i, err);
|
return u_terminateChars(parent, parentCapacity, i, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2172,23 +2012,14 @@ uloc_getLCID(const char* localeID)
|
||||||
{
|
{
|
||||||
UErrorCode status = U_ZERO_ERROR;
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
char langID[ULOC_FULLNAME_CAPACITY];
|
char langID[ULOC_FULLNAME_CAPACITY];
|
||||||
uint32_t lcid = 0;
|
|
||||||
|
|
||||||
/* Check for incomplete id. */
|
/* Check for incomplete id. */
|
||||||
if (!localeID || uprv_strlen(localeID) < 2) {
|
if (!localeID || uprv_strlen(localeID) < 2) {
|
||||||
return 0;
|
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);
|
uloc_getLanguage(localeID, langID, sizeof(langID), &status);
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,9 @@
|
||||||
|
|
||||||
#include "unicode/utypes.h"
|
#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 "wintz.h"
|
||||||
#include "cmemory.h"
|
#include "cmemory.h"
|
||||||
|
|
@ -21,7 +23,6 @@
|
||||||
|
|
||||||
#include "unicode/ures.h"
|
#include "unicode/ures.h"
|
||||||
#include "unicode/ustring.h"
|
#include "unicode/ustring.h"
|
||||||
#include "uresimp.h"
|
|
||||||
|
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
# define WIN32_LEAN_AND_MEAN
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
|
@ -33,94 +34,362 @@
|
||||||
# define NOMCX
|
# define NOMCX
|
||||||
#include <windows.h>
|
#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
|
/* The layout of the Tzi value in the registry */
|
||||||
#define MAX_TIMEZONE_ID_LENGTH 128
|
typedef struct
|
||||||
|
{
|
||||||
|
int32_t bias;
|
||||||
|
int32_t standardBias;
|
||||||
|
int32_t daylightBias;
|
||||||
|
SYSTEMTIME standardDate;
|
||||||
|
SYSTEMTIME daylightDate;
|
||||||
|
} TZI;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main Windows time zone detection function.
|
* Various registry keys and key fragments.
|
||||||
* 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.
|
static const wchar_t CURRENT_ZONE_REGKEY[] = L"SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation\\";
|
||||||
* This API returns a non-localized time zone name, which we can then map to an ICU time zone name.
|
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
|
U_CFUNC const char* U_EXPORT2
|
||||||
uprv_detectWindowsTimeZone()
|
uprv_detectWindowsTimeZone()
|
||||||
{
|
{
|
||||||
UErrorCode status = U_ZERO_ERROR;
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
char* icuid = nullptr;
|
UResourceBundle* bundle = NULL;
|
||||||
char dynamicTZKeyName[MAX_TIMEZONE_ID_LENGTH];
|
char* icuid = NULL;
|
||||||
char tmpid[MAX_TIMEZONE_ID_LENGTH];
|
char apiStdName[MAX_LENGTH_ID];
|
||||||
|
char regStdName[MAX_LENGTH_ID];
|
||||||
|
char tmpid[MAX_LENGTH_ID];
|
||||||
int32_t len;
|
int32_t len;
|
||||||
int id = GEOID_NOT_AVAILABLE;
|
int id;
|
||||||
int errorCode;
|
int errorCode;
|
||||||
wchar_t ISOcodeW[3] = {}; /* 2 letter ISO code in UTF-16 */
|
wchar_t ISOcodeW[3]; /* 2 letter iso code in UTF-16*/
|
||||||
char ISOcode[3] = {}; /* 2 letter ISO code in UTF-8 */
|
char ISOcodeA[3]; /* 2 letter iso code in ansi */
|
||||||
|
|
||||||
DYNAMIC_TIME_ZONE_INFORMATION dynamicTZI;
|
LONG result;
|
||||||
uprv_memset(&dynamicTZI, 0, sizeof(dynamicTZI));
|
TZI tziKey;
|
||||||
uprv_memset(dynamicTZKeyName, 0, sizeof(dynamicTZKeyName));
|
TZI tziReg;
|
||||||
uprv_memset(tmpid, 0, sizeof(tmpid));
|
TIME_ZONE_INFORMATION apiTZI;
|
||||||
|
|
||||||
/* Obtain TIME_ZONE_INFORMATION from the API and get the non-localized time zone name. */
|
BOOL tryPreVistaFallback;
|
||||||
if (TIME_ZONE_ID_INVALID == GetDynamicTimeZoneInformation(&dynamicTZI)) {
|
OSVERSIONINFO osVerInfo;
|
||||||
return nullptr;
|
|
||||||
}
|
/* 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);
|
id = GetUserGeoID(GEOCLASS_NATION);
|
||||||
errorCode = GetGeoInfoW(id, GEO_ISO2, ISOcodeW, 3, 0);
|
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).
|
bundle = ures_openDirect(NULL, "windowsZones", &status);
|
||||||
u_strToUTF8(ISOcode, UPRV_LENGTHOF(ISOcode), nullptr,
|
ures_getByKey(bundle, "mapTimezones", bundle, &status);
|
||||||
reinterpret_cast<const UChar*>(ISOcodeW), UPRV_LENGTHOF(ISOcodeW), &status);
|
|
||||||
|
|
||||||
LocalUResourceBundlePointer bundle(ures_openDirect(nullptr, "windowsZones", &status));
|
/*
|
||||||
ures_getByKey(bundle.getAlias(), "mapTimezones", bundle.getAlias(), &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
|
||||||
// convert from wchar_t* (UTF-16 on Windows) to char* (UTF-8).
|
if we're on Vista or higher
|
||||||
u_strToUTF8(dynamicTZKeyName, UPRV_LENGTHOF(dynamicTZKeyName), nullptr,
|
*/
|
||||||
reinterpret_cast<const UChar*>(dynamicTZI.TimeZoneKeyName), UPRV_LENGTHOF(dynamicTZI.TimeZoneKeyName), &status);
|
uprv_memset(&osVerInfo, 0, sizeof(osVerInfo));
|
||||||
|
osVerInfo.dwOSVersionInfoSize = sizeof(osVerInfo);
|
||||||
if (U_FAILURE(status)) {
|
tryPreVistaFallback = TRUE;
|
||||||
return nullptr;
|
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==NULL)
|
||||||
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);
|
|
||||||
}
|
|
||||||
if (errorCode == 0 || icuTZ == nullptr) {
|
|
||||||
/* fallback to default "001" and reset status */
|
/* fallback to default "001" and reset status */
|
||||||
status = U_ZERO_ERROR;
|
status = U_ZERO_ERROR;
|
||||||
icuTZ = ures_getStringByKey(&winTZ, "001", &len, &status);
|
icuTZ = ures_getStringByKey(winTZ, "001", &len, &status);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (U_SUCCESS(status)) {
|
if(U_SUCCESS(status))
|
||||||
int index = 0;
|
{
|
||||||
|
int index=0;
|
||||||
while (!(*icuTZ == '\0' || *icuTZ == ' ')) {
|
while (! (*icuTZ == '\0' || *icuTZ ==' '))
|
||||||
// time zone IDs only contain ASCII invariant characters.
|
{
|
||||||
tmpid[index++] = (char)(*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(tryPreVistaFallback)
|
||||||
if (tmpid[0] != 0) {
|
{
|
||||||
icuid = uprv_strdup(tmpid);
|
/* 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;
|
return icuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
U_NAMESPACE_END
|
#endif /* U_PLATFORM_USES_ONLY_WIN32_API && (U_PLATFORM_HAS_WINUWP_API == 0) */
|
||||||
#endif /* U_PLATFORM_USES_ONLY_WIN32_API */
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ U_CDECL_BEGIN
|
||||||
typedef struct _TIME_ZONE_INFORMATION TIME_ZONE_INFORMATION;
|
typedef struct _TIME_ZONE_INFORMATION TIME_ZONE_INFORMATION;
|
||||||
U_CDECL_END
|
U_CDECL_END
|
||||||
|
|
||||||
U_CFUNC const char* U_EXPORT2
|
U_INTERNAL const char* U_EXPORT2
|
||||||
uprv_detectWindowsTimeZone();
|
uprv_detectWindowsTimeZone();
|
||||||
|
|
||||||
#endif /* U_PLATFORM_USES_ONLY_WIN32_API */
|
#endif /* U_PLATFORM_USES_ONLY_WIN32_API */
|
||||||
|
|
|
||||||
|
|
@ -94,83 +94,12 @@ UnicodeString* Win32DateFormat::getTimeDateFormat(const Calendar *cal, const Loc
|
||||||
return result;
|
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
|
// TODO: Range-check timeStyle, dateStyle
|
||||||
Win32DateFormat::Win32DateFormat(DateFormat::EStyle timeStyle, DateFormat::EStyle dateStyle, const Locale &locale, UErrorCode &status)
|
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)) {
|
if (U_SUCCESS(status)) {
|
||||||
GetEquivalentWindowsLocaleName(locale, &fWindowsLocaleName);
|
fLCID = locale.getLCID();
|
||||||
// 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.
|
|
||||||
|
|
||||||
fTZI = NEW_ARRAY(TIME_ZONE_INFORMATION, 1);
|
fTZI = NEW_ARRAY(TIME_ZONE_INFORMATION, 1);
|
||||||
uprv_memset(fTZI, 0, sizeof(TIME_ZONE_INFORMATION));
|
uprv_memset(fTZI, 0, sizeof(TIME_ZONE_INFORMATION));
|
||||||
adoptCalendar(Calendar::createInstance(locale, status));
|
adoptCalendar(Calendar::createInstance(locale, status));
|
||||||
|
|
@ -188,7 +117,6 @@ Win32DateFormat::~Win32DateFormat()
|
||||||
// delete fCalendar;
|
// delete fCalendar;
|
||||||
uprv_free(fTZI);
|
uprv_free(fTZI);
|
||||||
delete fDateTimeMsg;
|
delete fDateTimeMsg;
|
||||||
delete fWindowsLocaleName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Win32DateFormat &Win32DateFormat::operator=(const Win32DateFormat &other)
|
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 = NEW_ARRAY(TIME_ZONE_INFORMATION, 1);
|
||||||
*this->fTZI = *other.fTZI;
|
*this->fTZI = *other.fTZI;
|
||||||
|
|
||||||
this->fWindowsLocaleName = other.fWindowsLocaleName == NULL ? NULL : new UnicodeString(*other.fWindowsLocaleName);
|
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -309,22 +235,16 @@ void Win32DateFormat::formatDate(const SYSTEMTIME *st, UnicodeString &appendTo)
|
||||||
int result=0;
|
int result=0;
|
||||||
wchar_t stackBuffer[STACK_BUFFER_SIZE];
|
wchar_t stackBuffer[STACK_BUFFER_SIZE];
|
||||||
wchar_t *buffer = stackBuffer;
|
wchar_t *buffer = stackBuffer;
|
||||||
const wchar_t *localeName = nullptr;
|
|
||||||
|
|
||||||
if (fWindowsLocaleName != nullptr)
|
result = GetDateFormatW(fLCID, dfFlags[fDateStyle - kDateOffset], st, NULL, buffer, STACK_BUFFER_SIZE);
|
||||||
{
|
|
||||||
localeName = reinterpret_cast<const wchar_t*>(toOldUCharPtr(fWindowsLocaleName->getTerminatedBuffer()));
|
|
||||||
}
|
|
||||||
|
|
||||||
result = GetDateFormatEx(localeName, dfFlags[fDateStyle - kDateOffset], st, NULL, buffer, STACK_BUFFER_SIZE, NULL);
|
|
||||||
|
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
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);
|
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;
|
int result;
|
||||||
wchar_t stackBuffer[STACK_BUFFER_SIZE];
|
wchar_t stackBuffer[STACK_BUFFER_SIZE];
|
||||||
wchar_t *buffer = stackBuffer;
|
wchar_t *buffer = stackBuffer;
|
||||||
const wchar_t *localeName = nullptr;
|
|
||||||
|
|
||||||
if (fWindowsLocaleName != nullptr)
|
result = GetTimeFormatW(fLCID, tfFlags[fTimeStyle], st, NULL, buffer, STACK_BUFFER_SIZE);
|
||||||
{
|
|
||||||
localeName = reinterpret_cast<const wchar_t*>(toOldUCharPtr(fWindowsLocaleName->getTerminatedBuffer()));
|
|
||||||
}
|
|
||||||
|
|
||||||
result = GetTimeFormatEx(localeName, tfFlags[fTimeStyle], st, NULL, buffer, STACK_BUFFER_SIZE);
|
|
||||||
|
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
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);
|
buffer = NEW_ARRAY(wchar_t, newLength);
|
||||||
|
|
||||||
GetTimeFormatEx(localeName, tfFlags[fTimeStyle], st, NULL, buffer, newLength);
|
GetDateFormatW(fLCID, tfFlags[fTimeStyle], st, NULL, buffer, newLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -124,10 +124,9 @@ private:
|
||||||
DateFormat::EStyle fTimeStyle;
|
DateFormat::EStyle fTimeStyle;
|
||||||
DateFormat::EStyle fDateStyle;
|
DateFormat::EStyle fDateStyle;
|
||||||
Locale fLocale;
|
Locale fLocale;
|
||||||
|
int32_t fLCID;
|
||||||
UnicodeString fZoneID;
|
UnicodeString fZoneID;
|
||||||
TIME_ZONE_INFORMATION *fTZI;
|
TIME_ZONE_INFORMATION *fTZI;
|
||||||
|
|
||||||
UnicodeString* fWindowsLocaleName; // Stores the equivalent Windows locale name.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
U_NAMESPACE_END
|
U_NAMESPACE_END
|
||||||
|
|
|
||||||
|
|
@ -60,43 +60,43 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Win32NumberFormat)
|
||||||
* end in ";0" then the return value should be multiplied by 10.
|
* end in ";0" then the return value should be multiplied by 10.
|
||||||
* (e.g. "3" => 30, "3;2" => 320)
|
* (e.g. "3" => 30, "3;2" => 320)
|
||||||
*/
|
*/
|
||||||
static UINT getGrouping(const wchar_t *grouping)
|
static UINT getGrouping(const char *grouping)
|
||||||
{
|
{
|
||||||
UINT g = 0;
|
UINT g = 0;
|
||||||
const wchar_t *s;
|
const char *s;
|
||||||
|
|
||||||
for (s = grouping; *s != L'\0'; s += 1) {
|
for (s = grouping; *s != '\0'; s += 1) {
|
||||||
if (*s > L'0' && *s < L'9') {
|
if (*s > '0' && *s < '9') {
|
||||||
g = g * 10 + (*s - L'0');
|
g = g * 10 + (*s - '0');
|
||||||
} else if (*s != L';') {
|
} else if (*s != ';') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*s != L'0') {
|
if (*s != '0') {
|
||||||
g *= 10;
|
g *= 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
return g;
|
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));
|
GetLocaleInfoW(lcid, 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_ILZERO, (LPWSTR) &fmt->LeadingZero, sizeof(UINT));
|
||||||
|
|
||||||
GetLocaleInfoEx(windowsLocaleName, LOCALE_SGROUPING, (LPWSTR)buf, 10);
|
GetLocaleInfoA(lcid, LOCALE_SGROUPING, buf, 10);
|
||||||
fmt->Grouping = getGrouping(buf);
|
fmt->Grouping = getGrouping(buf);
|
||||||
|
|
||||||
fmt->lpDecimalSep = NEW_ARRAY(wchar_t, 6);
|
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);
|
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)
|
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));
|
GetLocaleInfoW(lcid, 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_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->Grouping = getGrouping(buf);
|
||||||
|
|
||||||
fmt->lpDecimalSep = NEW_ARRAY(wchar_t, 6);
|
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);
|
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));
|
GetLocaleInfoW(lcid, 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_ICURRENCY, (LPWSTR) &fmt->PositiveOrder, sizeof(UINT));
|
||||||
|
|
||||||
fmt->lpCurrencySymbol = NEW_ARRAY(wchar_t, 8);
|
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)
|
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)
|
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)) {
|
if (!U_FAILURE(status)) {
|
||||||
fLCID = locale.getLCID();
|
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
|
// Resolve actual locale to be used later
|
||||||
UErrorCode tmpsts = U_ZERO_ERROR;
|
UErrorCode tmpsts = U_ZERO_ERROR;
|
||||||
|
|
@ -226,19 +155,12 @@ Win32NumberFormat::Win32NumberFormat(const Locale &locale, UBool currency, UErro
|
||||||
fLocale = Locale((const char*)tmpLocID);
|
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));
|
fFormatInfo = (FormatInfo*)uprv_malloc(sizeof(FormatInfo));
|
||||||
|
|
||||||
if (fCurrency) {
|
if (fCurrency) {
|
||||||
getCurrencyFormat(&fFormatInfo->currency, localeName);
|
getCurrencyFormat(&fFormatInfo->currency, fLCID);
|
||||||
} else {
|
} else {
|
||||||
getNumberFormat(&fFormatInfo->number, localeName);
|
getNumberFormat(&fFormatInfo->number, fLCID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -263,7 +185,6 @@ Win32NumberFormat::~Win32NumberFormat()
|
||||||
|
|
||||||
uprv_free(fFormatInfo);
|
uprv_free(fFormatInfo);
|
||||||
}
|
}
|
||||||
delete fWindowsLocaleName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Win32NumberFormat &Win32NumberFormat::operator=(const Win32NumberFormat &other)
|
Win32NumberFormat &Win32NumberFormat::operator=(const Win32NumberFormat &other)
|
||||||
|
|
@ -274,21 +195,13 @@ Win32NumberFormat &Win32NumberFormat::operator=(const Win32NumberFormat &other)
|
||||||
this->fLocale = other.fLocale;
|
this->fLocale = other.fLocale;
|
||||||
this->fLCID = other.fLCID;
|
this->fLCID = other.fLCID;
|
||||||
this->fFractionDigitsSet = other.fFractionDigitsSet;
|
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) {
|
if (fCurrency) {
|
||||||
freeCurrencyFormat(&fFormatInfo->currency);
|
freeCurrencyFormat(&fFormatInfo->currency);
|
||||||
getCurrencyFormat(&fFormatInfo->currency, localeName);
|
getCurrencyFormat(&fFormatInfo->currency, fLCID);
|
||||||
} else {
|
} else {
|
||||||
freeNumberFormat(&fFormatInfo->number);
|
freeNumberFormat(&fFormatInfo->number);
|
||||||
getNumberFormat(&fFormatInfo->number, localeName);
|
getNumberFormat(&fFormatInfo->number, fLCID);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
|
|
@ -389,13 +302,6 @@ UnicodeString &Win32NumberFormat::format(int32_t numDigits, UnicodeString &appen
|
||||||
formatInfo = *fFormatInfo;
|
formatInfo = *fFormatInfo;
|
||||||
buffer[0] = 0x0000;
|
buffer[0] = 0x0000;
|
||||||
|
|
||||||
const wchar_t *localeName = nullptr;
|
|
||||||
|
|
||||||
if (fWindowsLocaleName != nullptr)
|
|
||||||
{
|
|
||||||
localeName = reinterpret_cast<const wchar_t*>(toOldUCharPtr(fWindowsLocaleName->getTerminatedBuffer()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fCurrency) {
|
if (fCurrency) {
|
||||||
if (fFractionDigitsSet) {
|
if (fFractionDigitsSet) {
|
||||||
formatInfo.currency.NumDigits = (UINT) numDigits;
|
formatInfo.currency.NumDigits = (UINT) numDigits;
|
||||||
|
|
@ -405,17 +311,17 @@ UnicodeString &Win32NumberFormat::format(int32_t numDigits, UnicodeString &appen
|
||||||
formatInfo.currency.Grouping = 0;
|
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) {
|
if (result == 0) {
|
||||||
DWORD lastError = GetLastError();
|
DWORD lastError = GetLastError();
|
||||||
|
|
||||||
if (lastError == ERROR_INSUFFICIENT_BUFFER) {
|
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 = NEW_ARRAY(wchar_t, newLength);
|
||||||
buffer[0] = 0x0000;
|
buffer[0] = 0x0000;
|
||||||
GetCurrencyFormatEx(localeName, 0, nBuffer, &formatInfo.currency, buffer, newLength);
|
GetCurrencyFormatW(fLCID, 0, nBuffer, &formatInfo.currency, buffer, newLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -427,15 +333,15 @@ UnicodeString &Win32NumberFormat::format(int32_t numDigits, UnicodeString &appen
|
||||||
formatInfo.number.Grouping = 0;
|
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 (result == 0) {
|
||||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
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 = NEW_ARRAY(wchar_t, newLength);
|
||||||
buffer[0] = 0x0000;
|
buffer[0] = 0x0000;
|
||||||
GetNumberFormatEx(localeName, 0, nBuffer, &formatInfo.number, buffer, newLength);
|
GetNumberFormatW(fLCID, 0, nBuffer, &formatInfo.number, buffer, newLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -154,8 +154,6 @@ private:
|
||||||
int32_t fLCID;
|
int32_t fLCID;
|
||||||
FormatInfo *fFormatInfo;
|
FormatInfo *fFormatInfo;
|
||||||
UBool fFractionDigitsSet;
|
UBool fFractionDigitsSet;
|
||||||
|
|
||||||
UnicodeString* fWindowsLocaleName; // Stores the equivalent Windows locale name.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
U_NAMESPACE_END
|
U_NAMESPACE_END
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue