mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-10 10:18:38 +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
|
|
@ -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) */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue