mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-14 17:24:01 +00:00
ICU-4152 Initial check in of Windows formatting code!
X-SVN-Rev: 18963
This commit is contained in:
parent
7a4ffed22c
commit
a992570c40
15 changed files with 2354 additions and 489 deletions
|
@ -765,6 +765,24 @@
|
|||
Outputs="..\..\include\unicode\$(InputFileName)"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\wintz.c">
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
DisableLanguageExtensions="FALSE"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
DisableLanguageExtensions="FALSE"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\wintz.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="conversion"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
**********************************************************************
|
||||
* Copyright (C) 1997-2005, International Business Machines
|
||||
* Copyright (C) 1997-2006, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
**********************************************************************
|
||||
*
|
||||
|
@ -357,7 +357,7 @@ Locale::Locale( const char * newLanguage,
|
|||
|
||||
/*if the whole string is longer than our internal limit, we need
|
||||
to go to the heap for temporary buffers*/
|
||||
if (size > ULOC_FULLNAME_CAPACITY)
|
||||
if (size >= ULOC_FULLNAME_CAPACITY)
|
||||
{
|
||||
togo_heap = (char *)uprv_malloc(sizeof(char)*(size+1));
|
||||
togo = togo_heap;
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
# define NOIME
|
||||
# define NOMCX
|
||||
# include <windows.h>
|
||||
# include "wintz.h"
|
||||
#elif defined(U_CYGWIN) && defined(__STRICT_ANSI__)
|
||||
/* tzset isn't defined in strict ANSI on Cygwin. */
|
||||
# undef __STRICT_ANSI__
|
||||
|
@ -682,487 +683,6 @@ uprv_digitsAfterDecimal(double x)
|
|||
platform with new implementations.
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
/* Win32 time zone detection ------------------------------------------------ */
|
||||
|
||||
#ifdef U_WINDOWS
|
||||
|
||||
/*
|
||||
This code attempts to detect the Windows time zone, as set in the
|
||||
Windows Date and Time control panel. It attempts to work on
|
||||
multiple flavors of Windows (9x, Me, NT, 2000, XP) 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 one of two keys (depending on
|
||||
the flavor of Windows):
|
||||
|
||||
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones\
|
||||
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\
|
||||
|
||||
Under this key are several subkeys, one for each time zone. These
|
||||
subkeys are named "Pacific" on Win9x/Me and "Pacific Standard Time"
|
||||
on WinNT/2k/XP. 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>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Layout of the binary registry data under the "TZI" key.
|
||||
*/
|
||||
typedef struct {
|
||||
LONG Bias;
|
||||
LONG StandardBias;
|
||||
LONG DaylightBias; /* Tweaked by GetTimeZoneInformation */
|
||||
SYSTEMTIME StandardDate;
|
||||
SYSTEMTIME DaylightDate;
|
||||
} TZI;
|
||||
|
||||
typedef struct {
|
||||
const char* icuid;
|
||||
const char* winid;
|
||||
} WindowsICUMap;
|
||||
|
||||
/**
|
||||
* Mapping between Windows zone IDs and ICU zone IDs. This list has
|
||||
* been mechanically checked; all zone offsets match (most important)
|
||||
* and city names match the display city names (where possible). The
|
||||
* presence or absence of DST differs in some cases, but this is
|
||||
* acceptable as long as the zone is semantically the same (which has
|
||||
* been manually checked).
|
||||
*
|
||||
* Windows 9x/Me zone IDs are listed as "Pacific" rather than "Pacific
|
||||
* Standard Time", which is seen in NT/2k/XP. This is fixed-up at
|
||||
* runtime as needed. The one exception is "Mexico Standard Time 2",
|
||||
* which is not present on Windows 9x/Me.
|
||||
*
|
||||
* Zones that are not unique under Offset+Rules should be grouped
|
||||
* together for efficiency (see code below). In addition, rules MUST
|
||||
* be grouped so that all zones of a single offset are together.
|
||||
*
|
||||
* Comments list S(tandard) or D(aylight), as declared by Windows,
|
||||
* followed by the display name (data from Windows XP).
|
||||
*
|
||||
* NOTE: Etc/GMT+12 is CORRECT for offset GMT-12:00. Consult
|
||||
* documentation elsewhere for an explanation.
|
||||
*/
|
||||
static const WindowsICUMap ZONE_MAP[] = {
|
||||
"Etc/GMT+12", "Dateline", /* S (GMT-12:00) International Date Line West */
|
||||
|
||||
"Pacific/Apia", "Samoa", /* S (GMT-11:00) Midway Island, Samoa */
|
||||
|
||||
"Pacific/Honolulu", "Hawaiian", /* S (GMT-10:00) Hawaii */
|
||||
|
||||
"America/Anchorage", "Alaskan", /* D (GMT-09:00) Alaska */
|
||||
|
||||
"America/Los_Angeles", "Pacific", /* D (GMT-08:00) Pacific Time (US & Canada); Tijuana */
|
||||
|
||||
"America/Phoenix", "US Mountain", /* S (GMT-07:00) Arizona */
|
||||
"America/Denver", "Mountain", /* D (GMT-07:00) Mountain Time (US & Canada) */
|
||||
"America/Chihuahua", "Mexico Standard Time 2", /* D (GMT-07:00) Chihuahua, La Paz, Mazatlan */
|
||||
|
||||
"America/Managua", "Central America", /* S (GMT-06:00) Central America */
|
||||
"America/Regina", "Canada Central", /* S (GMT-06:00) Saskatchewan */
|
||||
"America/Mexico_City", "Mexico", /* D (GMT-06:00) Guadalajara, Mexico City, Monterrey */
|
||||
"America/Chicago", "Central", /* D (GMT-06:00) Central Time (US & Canada) */
|
||||
|
||||
"America/Indianapolis", "US Eastern", /* S (GMT-05:00) Indiana (East) */
|
||||
"America/Bogota", "SA Pacific", /* S (GMT-05:00) Bogota, Lima, Quito */
|
||||
"America/New_York", "Eastern", /* D (GMT-05:00) Eastern Time (US & Canada) */
|
||||
|
||||
"America/Caracas", "SA Western", /* S (GMT-04:00) Caracas, La Paz */
|
||||
"America/Santiago", "Pacific SA", /* D (GMT-04:00) Santiago */
|
||||
"America/Halifax", "Atlantic", /* D (GMT-04:00) Atlantic Time (Canada) */
|
||||
|
||||
"America/St_Johns", "Newfoundland", /* D (GMT-03:30) Newfoundland */
|
||||
|
||||
"America/Buenos_Aires", "SA Eastern", /* S (GMT-03:00) Buenos Aires, Georgetown */
|
||||
"America/Godthab", "Greenland", /* D (GMT-03:00) Greenland */
|
||||
"America/Sao_Paulo", "E. South America", /* D (GMT-03:00) Brasilia */
|
||||
|
||||
"America/Noronha", "Mid-Atlantic", /* D (GMT-02:00) Mid-Atlantic */
|
||||
|
||||
"Atlantic/Cape_Verde", "Cape Verde", /* S (GMT-01:00) Cape Verde Is. */
|
||||
"Atlantic/Azores", "Azores", /* D (GMT-01:00) Azores */
|
||||
|
||||
"Africa/Casablanca", "Greenwich", /* S (GMT) Casablanca, Monrovia */
|
||||
"Europe/London", "GMT", /* D (GMT) Greenwich Mean Time : Dublin, Edinburgh, Lisbon, London */
|
||||
|
||||
"Africa/Lagos", "W. Central Africa", /* S (GMT+01:00) West Central Africa */
|
||||
"Europe/Berlin", "W. Europe", /* D (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna */
|
||||
"Europe/Paris", "Romance", /* D (GMT+01:00) Brussels, Copenhagen, Madrid, Paris */
|
||||
"Europe/Sarajevo", "Central European", /* D (GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb */
|
||||
"Europe/Belgrade", "Central Europe", /* D (GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague */
|
||||
|
||||
"Africa/Johannesburg", "South Africa", /* S (GMT+02:00) Harare, Pretoria */
|
||||
"Asia/Jerusalem", "Israel", /* S (GMT+02:00) Jerusalem */
|
||||
"Europe/Istanbul", "GTB", /* D (GMT+02:00) Athens, Istanbul, Minsk */
|
||||
"Europe/Helsinki", "FLE", /* D (GMT+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius */
|
||||
"Africa/Cairo", "Egypt", /* D (GMT+02:00) Cairo */
|
||||
"Europe/Bucharest", "E. Europe", /* D (GMT+02:00) Bucharest */
|
||||
|
||||
"Africa/Nairobi", "E. Africa", /* S (GMT+03:00) Nairobi */
|
||||
"Asia/Riyadh", "Arab", /* S (GMT+03:00) Kuwait, Riyadh */
|
||||
"Europe/Moscow", "Russian", /* D (GMT+03:00) Moscow, St. Petersburg, Volgograd */
|
||||
"Asia/Baghdad", "Arabic", /* D (GMT+03:00) Baghdad */
|
||||
|
||||
"Asia/Tehran", "Iran", /* D (GMT+03:30) Tehran */
|
||||
|
||||
"Asia/Muscat", "Arabian", /* S (GMT+04:00) Abu Dhabi, Muscat */
|
||||
"Asia/Tbilisi", "Caucasus", /* D (GMT+04:00) Baku, Tbilisi, Yerevan */
|
||||
|
||||
"Asia/Kabul", "Afghanistan", /* S (GMT+04:30) Kabul */
|
||||
|
||||
"Asia/Karachi", "West Asia", /* S (GMT+05:00) Islamabad, Karachi, Tashkent */
|
||||
"Asia/Yekaterinburg", "Ekaterinburg", /* D (GMT+05:00) Ekaterinburg */
|
||||
|
||||
"Asia/Calcutta", "India", /* S (GMT+05:30) Chennai, Kolkata, Mumbai, New Delhi */
|
||||
|
||||
"Asia/Katmandu", "Nepal", /* S (GMT+05:45) Kathmandu */
|
||||
|
||||
"Asia/Colombo", "Sri Lanka", /* S (GMT+06:00) Sri Jayawardenepura */
|
||||
"Asia/Dhaka", "Central Asia", /* S (GMT+06:00) Astana, Dhaka */
|
||||
"Asia/Novosibirsk", "N. Central Asia", /* D (GMT+06:00) Almaty, Novosibirsk */
|
||||
|
||||
"Asia/Rangoon", "Myanmar", /* S (GMT+06:30) Rangoon */
|
||||
|
||||
"Asia/Bangkok", "SE Asia", /* S (GMT+07:00) Bangkok, Hanoi, Jakarta */
|
||||
"Asia/Krasnoyarsk", "North Asia", /* D (GMT+07:00) Krasnoyarsk */
|
||||
|
||||
"Australia/Perth", "W. Australia", /* S (GMT+08:00) Perth */
|
||||
"Asia/Taipei", "Taipei", /* S (GMT+08:00) Taipei */
|
||||
"Asia/Singapore", "Singapore", /* S (GMT+08:00) Kuala Lumpur, Singapore */
|
||||
"Asia/Hong_Kong", "China", /* S (GMT+08:00) Beijing, Chongqing, Hong Kong, Urumqi */
|
||||
"Asia/Irkutsk", "North Asia East", /* D (GMT+08:00) Irkutsk, Ulaan Bataar */
|
||||
|
||||
"Asia/Tokyo", "Tokyo", /* S (GMT+09:00) Osaka, Sapporo, Tokyo */
|
||||
"Asia/Seoul", "Korea", /* S (GMT+09:00) Seoul */
|
||||
"Asia/Yakutsk", "Yakutsk", /* D (GMT+09:00) Yakutsk */
|
||||
|
||||
"Australia/Darwin", "AUS Central", /* S (GMT+09:30) Darwin */
|
||||
"Australia/Adelaide", "Cen. Australia", /* D (GMT+09:30) Adelaide */
|
||||
|
||||
"Pacific/Guam", "West Pacific", /* S (GMT+10:00) Guam, Port Moresby */
|
||||
"Australia/Brisbane", "E. Australia", /* S (GMT+10:00) Brisbane */
|
||||
"Asia/Vladivostok", "Vladivostok", /* D (GMT+10:00) Vladivostok */
|
||||
"Australia/Hobart", "Tasmania", /* D (GMT+10:00) Hobart */
|
||||
"Australia/Sydney", "AUS Eastern", /* D (GMT+10:00) Canberra, Melbourne, Sydney */
|
||||
|
||||
"Asia/Magadan", "Central Pacific", /* S (GMT+11:00) Magadan, Solomon Is., New Caledonia */
|
||||
|
||||
"Pacific/Fiji", "Fiji", /* S (GMT+12:00) Fiji, Kamchatka, Marshall Is. */
|
||||
"Pacific/Auckland", "New Zealand", /* D (GMT+12:00) Auckland, Wellington */
|
||||
|
||||
"Pacific/Tongatapu", "Tonga", /* S (GMT+13:00) Nuku'alofa */
|
||||
NULL, NULL
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const char* winid;
|
||||
const char* altwinid;
|
||||
} WindowsZoneRemap;
|
||||
|
||||
/**
|
||||
* If a lookup fails, we attempt to remap certain Windows ids to
|
||||
* alternate Windows ids. If the alternate listed here begins with
|
||||
* '-', we use it as is (without the '-'). If it begins with '+', we
|
||||
* append a " Standard Time" if appropriate.
|
||||
*/
|
||||
static const WindowsZoneRemap ZONE_REMAP[] = {
|
||||
"Central European", "-Warsaw",
|
||||
"Central Europe", "-Prague Bratislava",
|
||||
"China", "-Beijing",
|
||||
|
||||
"Greenwich", "+GMT",
|
||||
"GTB", "+GFT",
|
||||
"Arab", "+Saudi Arabia",
|
||||
"SE Asia", "+Bangkok",
|
||||
"AUS Eastern", "+Sydney",
|
||||
NULL, NULL,
|
||||
};
|
||||
|
||||
/**
|
||||
* Various registry keys and key fragments.
|
||||
*/
|
||||
static const char CURRENT_ZONE_REGKEY[] = "SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation\\";
|
||||
static const char STANDARD_NAME_REGKEY[] = "StandardName";
|
||||
static const char STANDARD_TIME_REGKEY[] = " Standard Time";
|
||||
static const char TZI_REGKEY[] = "TZI";
|
||||
static const char STD_REGKEY[] = "Std";
|
||||
|
||||
/**
|
||||
* HKLM subkeys used to probe for the flavor of Windows. Note that we
|
||||
* specifically check for the "GMT" zone subkey; this is present on
|
||||
* NT, but on XP has become "GMT Standard Time". We need to
|
||||
* discriminate between these cases.
|
||||
*/
|
||||
static const char* const WIN_TYPE_PROBE_REGKEY[] = {
|
||||
/* WIN_9X_ME_TYPE */
|
||||
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones",
|
||||
|
||||
/* WIN_NT_TYPE */
|
||||
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\GMT"
|
||||
|
||||
/* otherwise: WIN_2K_XP_TYPE */
|
||||
};
|
||||
|
||||
/**
|
||||
* The time zone root subkeys (under HKLM) for different flavors of
|
||||
* Windows.
|
||||
*/
|
||||
static const char* const TZ_REGKEY[] = {
|
||||
/* WIN_9X_ME_TYPE */
|
||||
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones\\",
|
||||
|
||||
/* WIN_NT_TYPE | WIN_2K_XP_TYPE */
|
||||
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\"
|
||||
};
|
||||
|
||||
/**
|
||||
* Flavor of Windows, from our perspective. Not a real OS version,
|
||||
* but rather the flavor of the layout of the time zone information in
|
||||
* the registry.
|
||||
*/
|
||||
enum {
|
||||
WIN_9X_ME_TYPE = 0,
|
||||
WIN_NT_TYPE = 1,
|
||||
WIN_2K_XP_TYPE = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* Auxiliary Windows time zone function. Attempts to open the given
|
||||
* Windows time zone ID as a registry key. Returns ERROR_SUCCESS if
|
||||
* successful. Caller must close the registry key. Handles
|
||||
* variations in the resource layout in different flavors of Windows.
|
||||
*
|
||||
* @param hkey output parameter to receive opened registry key
|
||||
* @param winid Windows zone ID, e.g., "Pacific", without the
|
||||
* " Standard Time" suffix (if any). Special case "Mexico Standard Time 2"
|
||||
* allowed.
|
||||
* @param winType Windows flavor (WIN_9X_ME_TYPE, etc.)
|
||||
* @return ERROR_SUCCESS upon success
|
||||
*/
|
||||
static LONG openTZRegKey(HKEY *hkey, const char* winid, int winType) {
|
||||
LONG result;
|
||||
char subKeyName[96];
|
||||
char* name;
|
||||
int i;
|
||||
|
||||
uprv_strcpy(subKeyName, TZ_REGKEY[(winType == WIN_9X_ME_TYPE) ? 0 : 1]);
|
||||
name = &subKeyName[strlen(subKeyName)];
|
||||
uprv_strcat(subKeyName, winid);
|
||||
if (winType != WIN_9X_ME_TYPE) {
|
||||
/* Don't modify "Mexico Standard Time 2", which does not occur
|
||||
on WIN_9X_ME_TYPE. Also, if the type is WIN_NT_TYPE, then
|
||||
in practice this means the GMT key is not followed by
|
||||
" Standard Time", so don't append in that case. */
|
||||
int isMexico2 = (winid[uprv_strlen(winid)- 1] == '2');
|
||||
if (!isMexico2 &&
|
||||
!(winType == WIN_NT_TYPE && uprv_strcmp(winid, "GMT") == 0)) {
|
||||
uprv_strcat(subKeyName, STANDARD_TIME_REGKEY);
|
||||
}
|
||||
}
|
||||
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||||
subKeyName,
|
||||
0,
|
||||
KEY_QUERY_VALUE,
|
||||
hkey);
|
||||
|
||||
if (result != ERROR_SUCCESS) {
|
||||
/* If the primary lookup fails, try to remap the Windows zone
|
||||
ID, according to the remapping table. */
|
||||
for (i=0; ZONE_REMAP[i].winid; ++i) {
|
||||
if (uprv_strcmp(winid, ZONE_REMAP[i].winid) == 0) {
|
||||
uprv_strcpy(name, ZONE_REMAP[i].altwinid + 1);
|
||||
if (*(ZONE_REMAP[i].altwinid) == '+' &&
|
||||
winType != WIN_9X_ME_TYPE) {
|
||||
uprv_strcat(subKeyName, STANDARD_TIME_REGKEY);
|
||||
}
|
||||
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||||
subKeyName,
|
||||
0,
|
||||
KEY_QUERY_VALUE,
|
||||
hkey);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main Windows time zone detection function. Returns the Windows
|
||||
* time zone, translated to an ICU time zone, or NULL upon failure.
|
||||
*/
|
||||
static const char* detectWindowsTimeZone() {
|
||||
int winType;
|
||||
LONG result;
|
||||
HKEY hkey;
|
||||
TZI tziKey;
|
||||
TZI tziReg;
|
||||
DWORD cbData = sizeof(TZI);
|
||||
TIME_ZONE_INFORMATION apiTZI;
|
||||
char stdName[32];
|
||||
DWORD stdNameSize;
|
||||
char stdRegName[64];
|
||||
DWORD stdRegNameSize;
|
||||
int firstMatch, lastMatch;
|
||||
int j;
|
||||
|
||||
/* Detect the version of windows by trying to open a sequence of
|
||||
probe keys. We don't use the OS version API because what we
|
||||
really want to know is how the registry is laid out.
|
||||
Specifically, is it 9x/Me or not, and is it "GMT" or "GMT
|
||||
Standard Time". */
|
||||
for (winType=0; winType<2; ++winType) {
|
||||
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||||
WIN_TYPE_PROBE_REGKEY[winType],
|
||||
0,
|
||||
KEY_QUERY_VALUE,
|
||||
&hkey);
|
||||
RegCloseKey(hkey);
|
||||
if (result == ERROR_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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));
|
||||
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));
|
||||
|
||||
/* For each zone that can be identified by Offset+Rules, see if we
|
||||
have a match. Continue scanning after finding a match,
|
||||
recording the index of the first and the last match. We have
|
||||
to do this because some zones are not unique under
|
||||
Offset+Rules. */
|
||||
firstMatch = lastMatch = -1;
|
||||
for (j=0; ZONE_MAP[j].icuid; j++) {
|
||||
result = openTZRegKey(&hkey, ZONE_MAP[j].winid, winType);
|
||||
if (result == ERROR_SUCCESS) {
|
||||
result = RegQueryValueEx(hkey,
|
||||
TZI_REGKEY,
|
||||
NULL,
|
||||
NULL,
|
||||
(LPBYTE)&tziReg,
|
||||
&cbData);
|
||||
}
|
||||
RegCloseKey(hkey);
|
||||
if (result == ERROR_SUCCESS) {
|
||||
/* Assume that offsets are grouped together, and bail out
|
||||
when we've scanned everything with a matching
|
||||
offset. */
|
||||
if (firstMatch >= 0 && tziKey.Bias != tziReg.Bias) {
|
||||
break;
|
||||
}
|
||||
/* 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) {
|
||||
if (firstMatch < 0) {
|
||||
firstMatch = j;
|
||||
}
|
||||
lastMatch = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This should never happen; if it does it means our table doesn't
|
||||
match Windows AT ALL, perhaps because this is post-XP? */
|
||||
if (firstMatch < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (firstMatch != lastMatch) {
|
||||
/* Offset+Rules lookup yielded >= 2 matches. Try to match the
|
||||
localized display name. Get the name from the registry
|
||||
(not the API). This avoids conversion issues. Use the
|
||||
standard name, since Windows modifies the daylight name to
|
||||
match the standard name if there is no DST. */
|
||||
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||||
CURRENT_ZONE_REGKEY,
|
||||
0,
|
||||
KEY_QUERY_VALUE,
|
||||
&hkey);
|
||||
if (result == ERROR_SUCCESS) {
|
||||
stdNameSize = sizeof(stdName);
|
||||
result = RegQueryValueEx(hkey,
|
||||
(LPTSTR)STANDARD_NAME_REGKEY,
|
||||
NULL,
|
||||
NULL,
|
||||
(LPBYTE)stdName,
|
||||
&stdNameSize);
|
||||
RegCloseKey(hkey);
|
||||
|
||||
/* Scan through the Windows time zone data in the registry
|
||||
again (just the range of zones with matching TZIs) and
|
||||
look for a standard display name match. */
|
||||
for (j=firstMatch; j<=lastMatch; j++) {
|
||||
result = openTZRegKey(&hkey, ZONE_MAP[j].winid, winType);
|
||||
if (result == ERROR_SUCCESS) {
|
||||
stdRegNameSize = sizeof(stdRegName);
|
||||
result = RegQueryValueEx(hkey,
|
||||
(LPTSTR)STD_REGKEY,
|
||||
NULL,
|
||||
NULL,
|
||||
(LPBYTE)stdRegName,
|
||||
&stdRegNameSize);
|
||||
}
|
||||
RegCloseKey(hkey);
|
||||
if (result == ERROR_SUCCESS &&
|
||||
stdRegNameSize == stdNameSize &&
|
||||
uprv_memcmp(stdName, stdRegName, stdNameSize) == 0) {
|
||||
firstMatch = j; /* record the match */
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
RegCloseKey(hkey); /* should never get here */
|
||||
}
|
||||
}
|
||||
|
||||
return ZONE_MAP[firstMatch].icuid;
|
||||
}
|
||||
|
||||
#endif /*U_WINDOWS*/
|
||||
|
||||
/* Generic time zone layer -------------------------------------------------- */
|
||||
|
||||
/* Time zone utilities */
|
||||
|
@ -1221,7 +741,12 @@ U_CAPI const char* U_EXPORT2
|
|||
uprv_tzname(int n)
|
||||
{
|
||||
#ifdef U_WINDOWS
|
||||
#if 0
|
||||
char* id = (char*) detectWindowsTimeZone();
|
||||
#else
|
||||
char *id = (char *) u_detectWindowsTimeZone();
|
||||
#endif
|
||||
|
||||
if (id != NULL) {
|
||||
return id;
|
||||
}
|
||||
|
|
|
@ -1532,6 +1532,9 @@ uloc_openKeywords(const char* localeID,
|
|||
|
||||
#define OPTION_SET(options, mask) ((options & mask) != 0)
|
||||
|
||||
static const char i_default[] = {'i', '-', 'd', 'e', 'f', 'a', 'u', 'l', 't'};
|
||||
#define I_DEFAULT_LENGTH (sizeof i_default / sizeof i_default[0])
|
||||
|
||||
/**
|
||||
* Canonicalize the given localeID, to level 1 or to level 2,
|
||||
* depending on the options. To specify level 1, pass in options=0.
|
||||
|
@ -1576,7 +1579,13 @@ _canonicalize(const char* localeID,
|
|||
|
||||
/* get all pieces, one after another, and separate with '_' */
|
||||
len=_getLanguage(localeID, name, nameCapacity, &localeID);
|
||||
if(_isIDSeparator(*localeID)) {
|
||||
|
||||
if(len == I_DEFAULT_LENGTH && uprv_strncmp(name, i_default, len) == 0) {
|
||||
const char *d = uloc_getDefault();
|
||||
|
||||
len = uprv_strlen(d);
|
||||
uprv_strncpy(name, d, len);
|
||||
} else if(_isIDSeparator(*localeID)) {
|
||||
const char *scriptID;
|
||||
|
||||
++fieldCount;
|
||||
|
|
577
icu4c/source/common/wintz.c
Normal file
577
icu4c/source/common/wintz.c
Normal file
|
@ -0,0 +1,577 @@
|
|||
/*
|
||||
********************************************************************************
|
||||
* Copyright (C) 2005-2006, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
********************************************************************************
|
||||
*
|
||||
* File WINTZ.CPP
|
||||
*
|
||||
********************************************************************************
|
||||
*/
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
#ifdef U_WINDOWS
|
||||
|
||||
#include "wintz.h"
|
||||
|
||||
#include "cmemory.h"
|
||||
#include "cstring.h"
|
||||
|
||||
#include "unicode/ustring.h"
|
||||
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# define VC_EXTRALEAN
|
||||
# define NOUSER
|
||||
# define NOSERVICE
|
||||
# define NOIME
|
||||
# define NOMCX
|
||||
#include <windows.h>
|
||||
|
||||
#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
|
||||
#define NEW_ARRAY(type,count) (type *) uprv_malloc((count) * sizeof(type))
|
||||
#define DELETE_ARRAY(array) uprv_free((void *) (array))
|
||||
|
||||
#define ICUID_STACK_BUFFER_SIZE 32
|
||||
|
||||
// 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;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *icuid;
|
||||
const char *winid;
|
||||
} WindowsICUMap;
|
||||
|
||||
typedef struct {
|
||||
const char* winid;
|
||||
const char* altwinid;
|
||||
} WindowsZoneRemap;
|
||||
|
||||
/**
|
||||
* Various registry keys and key fragments.
|
||||
*/
|
||||
static const char CURRENT_ZONE_REGKEY[] = "SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation\\";
|
||||
static const char STANDARD_NAME_REGKEY[] = "StandardName";
|
||||
static const char STANDARD_TIME_REGKEY[] = " Standard Time";
|
||||
static const char TZI_REGKEY[] = "TZI";
|
||||
static const char STD_REGKEY[] = "Std";
|
||||
|
||||
/**
|
||||
* HKLM subkeys used to probe for the flavor of Windows. Note that we
|
||||
* specifically check for the "GMT" zone subkey; this is present on
|
||||
* NT, but on XP has become "GMT Standard Time". We need to
|
||||
* discriminate between these cases.
|
||||
*/
|
||||
static const char* const WIN_TYPE_PROBE_REGKEY[] = {
|
||||
/* WIN_9X_ME_TYPE */
|
||||
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones",
|
||||
|
||||
/* WIN_NT_TYPE */
|
||||
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\GMT"
|
||||
|
||||
/* otherwise: WIN_2K_XP_TYPE */
|
||||
};
|
||||
|
||||
/**
|
||||
* The time zone root subkeys (under HKLM) for different flavors of
|
||||
* Windows.
|
||||
*/
|
||||
static const char* const TZ_REGKEY[] = {
|
||||
/* WIN_9X_ME_TYPE */
|
||||
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones\\",
|
||||
|
||||
/* WIN_NT_TYPE | WIN_2K_XP_TYPE */
|
||||
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\"
|
||||
};
|
||||
|
||||
/**
|
||||
* Flavor of Windows, from our perspective. Not a real OS version,
|
||||
* but rather the flavor of the layout of the time zone information in
|
||||
* the registry.
|
||||
*/
|
||||
enum {
|
||||
WIN_9X_ME_TYPE = 0,
|
||||
WIN_NT_TYPE = 1,
|
||||
WIN_2K_XP_TYPE = 2
|
||||
};
|
||||
|
||||
// TODO: Sort on ICU ID?
|
||||
// TODO: No static initialization!
|
||||
// TODO: This data should come from ICU/CLDR...
|
||||
static const WindowsICUMap ZONE_MAP[] = {
|
||||
{"Etc/GMT+12", "Dateline"}, /* S (GMT-12:00) International Date Line West */
|
||||
|
||||
{"Pacific/Apia", "Samoa"}, /* S (GMT-11:00) Midway Island, Samoa */
|
||||
|
||||
{"Pacific/Honolulu", "Hawaiian"}, /* S (GMT-10:00) Hawaii */
|
||||
|
||||
{"America/Anchorage", "Alaskan"}, /* D (GMT-09:00) Alaska */
|
||||
|
||||
{"America/Los_Angeles", "Pacific"}, /* D (GMT-08:00) Pacific Time (US & Canada); Tijuana */
|
||||
|
||||
{"America/Phoenix", "US Mountain"}, /* S (GMT-07:00) Arizona */
|
||||
{"America/Denver", "Mountain"}, /* D (GMT-07:00) Mountain Time (US & Canada) */
|
||||
{"America/Chihuahua", "Mexico Standard Time 2"}, /* D (GMT-07:00) Chihuahua, La Paz, Mazatlan */
|
||||
|
||||
{"America/Managua", "Central America"}, /* S (GMT-06:00) Central America */
|
||||
{"America/Regina", "Canada Central"}, /* S (GMT-06:00) Saskatchewan */
|
||||
{"America/Mexico_City", "Mexico"}, /* D (GMT-06:00) Guadalajara, Mexico City, Monterrey */
|
||||
{"America/Chicago", "Central"}, /* D (GMT-06:00) Central Time (US & Canada) */
|
||||
|
||||
{"America/Indianapolis", "US Eastern"}, /* S (GMT-05:00) Indiana (East) */
|
||||
{"America/Bogota", "SA Pacific"}, /* S (GMT-05:00) Bogota, Lima, Quito */
|
||||
{"America/New_York", "Eastern"}, /* D (GMT-05:00) Eastern Time (US & Canada) */
|
||||
|
||||
{"America/Caracas", "SA Western"}, /* S (GMT-04:00) Caracas, La Paz */
|
||||
{"America/Santiago", "Pacific SA"}, /* D (GMT-04:00) Santiago */
|
||||
{"America/Halifax", "Atlantic"}, /* D (GMT-04:00) Atlantic Time (Canada) */
|
||||
|
||||
{"America/St_Johns", "Newfoundland"}, /* D (GMT-03:30) Newfoundland */
|
||||
|
||||
{"America/Buenos_Aires", "SA Eastern"}, /* S (GMT-03:00) Buenos Aires, Georgetown */
|
||||
{"America/Godthab", "Greenland"}, /* D (GMT-03:00) Greenland */
|
||||
{"America/Sao_Paulo", "E. South America"}, /* D (GMT-03:00) Brasilia */
|
||||
|
||||
{"America/Noronha", "Mid-Atlantic"}, /* D (GMT-02:00) Mid-Atlantic */
|
||||
|
||||
{"Atlantic/Cape_Verde", "Cape Verde"}, /* S (GMT-01:00) Cape Verde Is. */
|
||||
{"Atlantic/Azores", "Azores"}, /* D (GMT-01:00) Azores */
|
||||
|
||||
{"Africa/Casablanca", "Greenwich"}, /* S (GMT) Casablanca, Monrovia */
|
||||
{"Europe/London", "GMT"}, /* D (GMT) Greenwich Mean Time : Dublin, Edinburgh, Lisbon, London */
|
||||
|
||||
{"Africa/Lagos", "W. Central Africa"}, /* S (GMT+01:00) West Central Africa */
|
||||
{"Europe/Berlin", "W. Europe"}, /* D (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna */
|
||||
{"Europe/Paris", "Romance"}, /* D (GMT+01:00) Brussels, Copenhagen, Madrid, Paris */
|
||||
{"Europe/Sarajevo", "Central European"}, /* D (GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb */
|
||||
{"Europe/Belgrade", "Central Europe"}, /* D (GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague */
|
||||
|
||||
{"Africa/Johannesburg", "South Africa"}, /* S (GMT+02:00) Harare, Pretoria */
|
||||
{"Asia/Jerusalem", "Israel"}, /* S (GMT+02:00) Jerusalem */
|
||||
{"Europe/Istanbul", "GTB"}, /* D (GMT+02:00) Athens, Istanbul, Minsk */
|
||||
{"Europe/Helsinki", "FLE"}, /* D (GMT+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius */
|
||||
{"Africa/Cairo", "Egypt"}, /* D (GMT+02:00) Cairo */
|
||||
{"Europe/Bucharest", "E. Europe"}, /* D (GMT+02:00) Bucharest */
|
||||
|
||||
{"Africa/Nairobi", "E. Africa"}, /* S (GMT+03:00) Nairobi */
|
||||
{"Asia/Riyadh", "Arab"}, /* S (GMT+03:00) Kuwait, Riyadh */
|
||||
{"Europe/Moscow", "Russian"}, /* D (GMT+03:00) Moscow, St. Petersburg, Volgograd */
|
||||
{"Asia/Baghdad", "Arabic"}, /* D (GMT+03:00) Baghdad */
|
||||
|
||||
{"Asia/Tehran", "Iran"}, /* D (GMT+03:30) Tehran */
|
||||
|
||||
{"Asia/Muscat", "Arabian"}, /* S (GMT+04:00) Abu Dhabi, Muscat */
|
||||
{"Asia/Tbilisi", "Caucasus"}, /* D (GMT+04:00) Baku, Tbilisi, Yerevan */
|
||||
|
||||
{"Asia/Kabul", "Afghanistan"}, /* S (GMT+04:30) Kabul */
|
||||
|
||||
{"Asia/Karachi", "West Asia"}, /* S (GMT+05:00) Islamabad, Karachi, Tashkent */
|
||||
{"Asia/Yekaterinburg", "Ekaterinburg"}, /* D (GMT+05:00) Ekaterinburg */
|
||||
|
||||
{"Asia/Calcutta", "India"}, /* S (GMT+05:30) Chennai, Kolkata, Mumbai, New Delhi */
|
||||
|
||||
{"Asia/Katmandu", "Nepal"}, /* S (GMT+05:45) Kathmandu */
|
||||
|
||||
{"Asia/Colombo", "Sri Lanka"}, /* S (GMT+06:00) Sri Jayawardenepura */
|
||||
{"Asia/Dhaka", "Central Asia"}, /* S (GMT+06:00) Astana, Dhaka */
|
||||
{"Asia/Novosibirsk", "N. Central Asia"}, /* D (GMT+06:00) Almaty, Novosibirsk */
|
||||
|
||||
{"Asia/Rangoon", "Myanmar"}, /* S (GMT+06:30) Rangoon */
|
||||
|
||||
{"Asia/Bangkok", "SE Asia"}, /* S (GMT+07:00) Bangkok, Hanoi, Jakarta */
|
||||
{"Asia/Krasnoyarsk", "North Asia"}, /* D (GMT+07:00) Krasnoyarsk */
|
||||
|
||||
{"Australia/Perth", "W. Australia"}, /* S (GMT+08:00) Perth */
|
||||
{"Asia/Taipei", "Taipei"}, /* S (GMT+08:00) Taipei */
|
||||
{"Asia/Singapore", "Singapore"}, /* S (GMT+08:00) Kuala Lumpur, Singapore */
|
||||
{"Asia/Hong_Kong", "China"}, /* S (GMT+08:00) Beijing, Chongqing, Hong Kong, Urumqi */
|
||||
{"Asia/Irkutsk", "North Asia East"}, /* D (GMT+08:00) Irkutsk, Ulaan Bataar */
|
||||
|
||||
{"Asia/Tokyo", "Tokyo"}, /* S (GMT+09:00) Osaka, Sapporo, Tokyo */
|
||||
{"Asia/Seoul", "Korea"}, /* S (GMT+09:00) Seoul */
|
||||
{"Asia/Yakutsk", "Yakutsk"}, /* D (GMT+09:00) Yakutsk */
|
||||
|
||||
{"Australia/Darwin", "AUS Central"}, /* S (GMT+09:30) Darwin */
|
||||
{"Australia/Adelaide", "Cen. Australia"}, /* D (GMT+09:30) Adelaide */
|
||||
|
||||
{"Pacific/Guam", "West Pacific"}, /* S (GMT+10:00) Guam, Port Moresby */
|
||||
{"Australia/Brisbane", "E. Australia"}, /* S (GMT+10:00) Brisbane */
|
||||
{"Asia/Vladivostok", "Vladivostok"}, /* D (GMT+10:00) Vladivostok */
|
||||
{"Australia/Hobart", "Tasmania"}, /* D (GMT+10:00) Hobart */
|
||||
{"Australia/Sydney", "AUS Eastern"}, /* D (GMT+10:00) Canberra, Melbourne, Sydney */
|
||||
|
||||
{"Asia/Magadan", "Central Pacific"}, /* S (GMT+11:00) Magadan, Solomon Is., New Caledonia */
|
||||
|
||||
{"Pacific/Fiji", "Fiji"}, /* S (GMT+12:00) Fiji, Kamchatka, Marshall Is. */
|
||||
{"Pacific/Auckland", "New Zealand"}, /* D (GMT+12:00) Auckland, Wellington */
|
||||
|
||||
{"Pacific/Tongatapu", "Tonga"}, /* S (GMT+13:00) Nuku'alofa */
|
||||
NULL, NULL
|
||||
};
|
||||
|
||||
/**
|
||||
* If a lookup fails, we attempt to remap certain Windows ids to
|
||||
* alternate Windows ids. If the alternate listed here begins with
|
||||
* '-', we use it as is (without the '-'). If it begins with '+', we
|
||||
* append a " Standard Time" if appropriate.
|
||||
*/
|
||||
static const WindowsZoneRemap ZONE_REMAP[] = {
|
||||
"Central European", "-Warsaw",
|
||||
"Central Europe", "-Prague Bratislava",
|
||||
"China", "-Beijing",
|
||||
|
||||
"Greenwich", "+GMT",
|
||||
"GTB", "+GFT",
|
||||
"Arab", "+Saudi Arabia",
|
||||
"SE Asia", "+Bangkok",
|
||||
"AUS Eastern", "+Sydney",
|
||||
NULL, NULL,
|
||||
};
|
||||
|
||||
static int32_t fWinType = -1;
|
||||
|
||||
static int32_t detectWindowsType()
|
||||
{
|
||||
int32_t winType;
|
||||
LONG result;
|
||||
HKEY hkey;
|
||||
|
||||
/* Detect the version of windows by trying to open a sequence of
|
||||
probe keys. We don't use the OS version API because what we
|
||||
really want to know is how the registry is laid out.
|
||||
Specifically, is it 9x/Me or not, and is it "GMT" or "GMT
|
||||
Standard Time". */
|
||||
for (winType = 0; winType < 2; winType += 1) {
|
||||
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||||
WIN_TYPE_PROBE_REGKEY[winType],
|
||||
0,
|
||||
KEY_QUERY_VALUE,
|
||||
&hkey);
|
||||
RegCloseKey(hkey);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return winType;
|
||||
}
|
||||
|
||||
// TODO: Binary search sorted ZONE_MAP...
|
||||
// (u_detectWindowsTimeZone() needs them sorted by offset...)
|
||||
static const char *findWindowsZoneID(const UChar *icuid, int32_t length)
|
||||
{
|
||||
char stackBuffer[ICUID_STACK_BUFFER_SIZE];
|
||||
char *buffer = stackBuffer;
|
||||
const char *result = NULL;
|
||||
int i;
|
||||
|
||||
// NOTE: >= because length doesn't include
|
||||
// trailing null.
|
||||
if (length >= ICUID_STACK_BUFFER_SIZE) {
|
||||
buffer = NEW_ARRAY(char, length);
|
||||
}
|
||||
|
||||
u_UCharsToChars(icuid, buffer, length);
|
||||
buffer[length] = '\0';
|
||||
|
||||
for (i = 0; ZONE_MAP[i].icuid != NULL; i += 1) {
|
||||
if (uprv_strcmp(buffer, ZONE_MAP[i].icuid) == 0) {
|
||||
result = ZONE_MAP[i].winid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer != stackBuffer) {
|
||||
DELETE_ARRAY(buffer);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static LONG openTZRegKey(HKEY *hkey, const char *winid)
|
||||
{
|
||||
char subKeyName[96]; // TODO: why 96??
|
||||
char *name;
|
||||
LONG result;
|
||||
|
||||
// TODO: This isn't thread safe, but it's probably good enough.
|
||||
if (fWinType < 0) {
|
||||
fWinType = detectWindowsType();
|
||||
}
|
||||
|
||||
uprv_strcpy(subKeyName, TZ_REGKEY[(fWinType == WIN_9X_ME_TYPE) ? 0 : 1]);
|
||||
name = &subKeyName[strlen(subKeyName)];
|
||||
uprv_strcat(subKeyName, winid);
|
||||
|
||||
if (fWinType != WIN_9X_ME_TYPE &&
|
||||
(winid[strlen(winid) - 1] != '2') &&
|
||||
!(fWinType == WIN_NT_TYPE && strcmp(winid, "GMT") == 0)) {
|
||||
uprv_strcat(subKeyName, STANDARD_TIME_REGKEY);
|
||||
}
|
||||
|
||||
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||||
subKeyName,
|
||||
0,
|
||||
KEY_QUERY_VALUE,
|
||||
hkey);
|
||||
|
||||
if (result != ERROR_SUCCESS) {
|
||||
int i;
|
||||
|
||||
/* If the primary lookup fails, try to remap the Windows zone
|
||||
ID, according to the remapping table. */
|
||||
for (i=0; ZONE_REMAP[i].winid; i += 1) {
|
||||
if (uprv_strcmp(winid, ZONE_REMAP[i].winid) == 0) {
|
||||
uprv_strcpy(name, ZONE_REMAP[i].altwinid + 1);
|
||||
if (*(ZONE_REMAP[i].altwinid) == '+' &&
|
||||
fWinType != WIN_9X_ME_TYPE) {
|
||||
uprv_strcat(subKeyName, STANDARD_TIME_REGKEY);
|
||||
}
|
||||
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||||
subKeyName,
|
||||
0,
|
||||
KEY_QUERY_VALUE,
|
||||
hkey);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static LONG getTZI(const char *winid, TZI *tzi)
|
||||
{
|
||||
DWORD cbData = sizeof(TZI);
|
||||
LONG result;
|
||||
HKEY hkey;
|
||||
|
||||
// TODO: This isn't thread safe, but it's probably good enough.
|
||||
if (fWinType < 0) {
|
||||
fWinType = detectWindowsType();
|
||||
}
|
||||
|
||||
result = openTZRegKey(&hkey, winid);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
result = RegQueryValueEx(hkey,
|
||||
TZI_REGKEY,
|
||||
NULL,
|
||||
NULL,
|
||||
(LPBYTE)tzi,
|
||||
&cbData);
|
||||
|
||||
}
|
||||
|
||||
RegCloseKey(hkey);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
U_CAPI void U_EXPORT2
|
||||
u_getWindowsTimeZoneInfo(TIME_ZONE_INFORMATION *zoneInfo, const UChar *icuid, int32_t length)
|
||||
{
|
||||
const char *winid;
|
||||
TZI tzi;
|
||||
LONG result;
|
||||
|
||||
winid = findWindowsZoneID(icuid, length);
|
||||
result = getTZI(winid, &tzi);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
zoneInfo->Bias = tzi.bias;
|
||||
zoneInfo->DaylightBias = tzi.daylightBias;
|
||||
zoneInfo->StandardBias = tzi.standardBias;
|
||||
zoneInfo->DaylightDate = tzi.daylightDate;
|
||||
zoneInfo->StandardDate = tzi.standardDate;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Can't find a match - use Windows default zone.
|
||||
GetTimeZoneInformation(zoneInfo);
|
||||
}
|
||||
|
||||
/*
|
||||
This code attempts to detect the Windows time zone, as set in the
|
||||
Windows Date and Time control panel. It attempts to work on
|
||||
multiple flavors of Windows (9x, Me, NT, 2000, XP) 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 one of two keys (depending on
|
||||
the flavor of Windows):
|
||||
|
||||
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones\
|
||||
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\
|
||||
|
||||
Under this key are several subkeys, one for each time zone. These
|
||||
subkeys are named "Pacific" on Win9x/Me and "Pacific Standard Time"
|
||||
on WinNT/2k/XP. 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_CAPI const char* U_EXPORT2
|
||||
u_detectWindowsTimeZone() {
|
||||
LONG result;
|
||||
HKEY hkey;
|
||||
TZI tziKey;
|
||||
TZI tziReg;
|
||||
DWORD cbData = sizeof(TZI);
|
||||
TIME_ZONE_INFORMATION apiTZI;
|
||||
char stdName[32];
|
||||
DWORD stdNameSize;
|
||||
char stdRegName[64];
|
||||
DWORD stdRegNameSize;
|
||||
int firstMatch, lastMatch;
|
||||
int j;
|
||||
|
||||
/* 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));
|
||||
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));
|
||||
|
||||
/* For each zone that can be identified by Offset+Rules, see if we
|
||||
have a match. Continue scanning after finding a match,
|
||||
recording the index of the first and the last match. We have
|
||||
to do this because some zones are not unique under
|
||||
Offset+Rules. */
|
||||
firstMatch = lastMatch = -1;
|
||||
for (j=0; ZONE_MAP[j].icuid; j++) {
|
||||
result = getTZI(ZONE_MAP[j].winid, &tziReg);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
/* Assume that offsets are grouped together, and bail out
|
||||
when we've scanned everything with a matching
|
||||
offset. */
|
||||
if (firstMatch >= 0 && tziKey.bias != tziReg.bias) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
if (firstMatch < 0) {
|
||||
firstMatch = j;
|
||||
}
|
||||
|
||||
lastMatch = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This should never happen; if it does it means our table doesn't
|
||||
match Windows AT ALL, perhaps because this is post-XP? */
|
||||
if (firstMatch < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (firstMatch != lastMatch) {
|
||||
/* Offset+Rules lookup yielded >= 2 matches. Try to match the
|
||||
localized display name. Get the name from the registry
|
||||
(not the API). This avoids conversion issues. Use the
|
||||
standard name, since Windows modifies the daylight name to
|
||||
match the standard name if there is no DST. */
|
||||
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||||
CURRENT_ZONE_REGKEY,
|
||||
0,
|
||||
KEY_QUERY_VALUE,
|
||||
&hkey);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
stdNameSize = sizeof(stdName);
|
||||
result = RegQueryValueEx(hkey,
|
||||
(LPTSTR)STANDARD_NAME_REGKEY,
|
||||
NULL,
|
||||
NULL,
|
||||
(LPBYTE)stdName,
|
||||
&stdNameSize);
|
||||
RegCloseKey(hkey);
|
||||
|
||||
/* Scan through the Windows time zone data in the registry
|
||||
again (just the range of zones with matching TZIs) and
|
||||
look for a standard display name match. */
|
||||
for (j = firstMatch; j <= lastMatch; j += 1) {
|
||||
result = openTZRegKey(&hkey, ZONE_MAP[j].winid);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
stdRegNameSize = sizeof(stdRegName);
|
||||
result = RegQueryValueEx(hkey,
|
||||
(LPTSTR)STD_REGKEY,
|
||||
NULL,
|
||||
NULL,
|
||||
(LPBYTE)stdRegName,
|
||||
&stdRegNameSize);
|
||||
}
|
||||
|
||||
RegCloseKey(hkey);
|
||||
|
||||
if (result == ERROR_SUCCESS &&
|
||||
stdRegNameSize == stdNameSize &&
|
||||
uprv_memcmp(stdName, stdRegName, stdNameSize) == 0) {
|
||||
firstMatch = j; /* record the match */
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
RegCloseKey(hkey); /* should never get here */
|
||||
}
|
||||
}
|
||||
|
||||
return ZONE_MAP[firstMatch].icuid;
|
||||
}
|
||||
|
||||
#endif // #ifdef U_WINDOWS
|
37
icu4c/source/common/wintz.h
Normal file
37
icu4c/source/common/wintz.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
********************************************************************************
|
||||
* Copyright (C) 2005-2006, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
********************************************************************************
|
||||
*
|
||||
* File WINTZ.H
|
||||
*
|
||||
********************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __WINTZ
|
||||
#define __WINTZ
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
#ifdef U_WINDOWS
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief C API: Utilities for dealing w/ Windows time zones.
|
||||
*/
|
||||
|
||||
U_CDECL_BEGIN
|
||||
// Forward declarations for Windows types...
|
||||
typedef struct _TIME_ZONE_INFORMATION TIME_ZONE_INFORMATION;
|
||||
U_CDECL_END
|
||||
|
||||
U_CAPI void U_EXPORT2
|
||||
u_getWindowsTimeZoneInfo(TIME_ZONE_INFORMATION *zoneInfo, const UChar *icuid, int32_t length);
|
||||
|
||||
U_CAPI const char* U_EXPORT2
|
||||
u_detectWindowsTimeZone();
|
||||
|
||||
#endif // #ifdef U_WINDOWS
|
||||
|
||||
#endif // __WINTZ
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 1997-2004, International Business Machines Corporation and *
|
||||
* Copyright (C) 1997-2006, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*
|
||||
|
@ -13,7 +13,7 @@
|
|||
* 03/31/97 aliu Modified extensively to work with 50 locales.
|
||||
* 04/01/97 aliu Added support for centuries.
|
||||
* 08/12/97 aliu Fixed operator== to use Calendar::equivalentTo.
|
||||
* 07/20/98 stephen Changed ParsePosition initialization
|
||||
* 07/20/98 stephen Changed ParsePosition initialization
|
||||
********************************************************************************
|
||||
*/
|
||||
|
||||
|
@ -25,6 +25,9 @@
|
|||
#include "unicode/datefmt.h"
|
||||
#include "unicode/smpdtfmt.h"
|
||||
|
||||
#include "cstring.h"
|
||||
#include "windtfmt.h"
|
||||
|
||||
#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
@ -267,8 +270,25 @@ DateFormat::createInstance()
|
|||
DateFormat* U_EXPORT2
|
||||
DateFormat::create(EStyle timeStyle, EStyle dateStyle, const Locale& locale)
|
||||
{
|
||||
// Try to create a SimpleDateFormat of the desired style.
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
#ifdef U_WINDOWS
|
||||
char buffer[8];
|
||||
int32_t count = locale.getKeywordValue("compat", buffer, sizeof(buffer), status);
|
||||
|
||||
// if the locale has "@compat=host", create a host-specific DateFormat...
|
||||
if (count > 0 && uprv_strcmp(buffer, "host") == 0) {
|
||||
Win32DateFormat *f = new Win32DateFormat(dateStyle, timeStyle, locale, status);
|
||||
|
||||
if (U_SUCCESS(status)) {
|
||||
return f;
|
||||
}
|
||||
|
||||
delete f;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Try to create a SimpleDateFormat of the desired style.
|
||||
SimpleDateFormat *f = new SimpleDateFormat(timeStyle, dateStyle, locale, status);
|
||||
if (U_SUCCESS(status)) return f;
|
||||
delete f;
|
||||
|
|
|
@ -1091,6 +1091,60 @@
|
|||
Outputs="..\..\include\unicode\$(InputFileName)"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\wincoll.cpp">
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
DisableLanguageExtensions="FALSE"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
DisableLanguageExtensions="FALSE"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\wincoll.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\windtfmt.cpp">
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
DisableLanguageExtensions="FALSE"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
DisableLanguageExtensions="FALSE"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\windtfmt.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\winnmfmt.cpp">
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
DisableLanguageExtensions="FALSE"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
DisableLanguageExtensions="FALSE"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\winnmfmt.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="misc"
|
||||
|
@ -1400,14 +1454,16 @@
|
|||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
CommandLine="copy "$(InputPath)" ..\..\include\unicode"
|
||||
CommandLine="copy "$(InputPath)" ..\..\include\unicode
|
||||
"
|
||||
Outputs="..\..\include\unicode\$(InputFileName)"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
CommandLine="copy "$(InputPath)" ..\..\include\unicode"
|
||||
CommandLine="copy "$(InputPath)" ..\..\include\unicode
|
||||
"
|
||||
Outputs="..\..\include\unicode\$(InputFileName)"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "unicode/ustring.h"
|
||||
#include "unicode/ucurr.h"
|
||||
#include "unicode/curramt.h"
|
||||
#include "winnmfmt.h"
|
||||
#include "uresimp.h"
|
||||
#include "uhash.h"
|
||||
#include "cmemory.h"
|
||||
|
@ -825,6 +826,36 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef U_WINDOWS
|
||||
char buffer[8];
|
||||
int32_t count = desiredLocale.getKeywordValue("compat", buffer, sizeof(buffer), status);
|
||||
|
||||
// if the locale has "@compat=host", create a host-specific NumberFormat
|
||||
if (count > 0 && uprv_strcmp(buffer, "host") == 0) {
|
||||
Win32NumberFormat *f = NULL;
|
||||
UBool curr = TRUE;
|
||||
|
||||
switch (style) {
|
||||
case kNumberStyle:
|
||||
curr = FALSE;
|
||||
// fall-through
|
||||
|
||||
case kCurrencyStyle:
|
||||
f = new Win32NumberFormat(desiredLocale, curr, status);
|
||||
|
||||
if (U_SUCCESS(status)) {
|
||||
return f;
|
||||
}
|
||||
|
||||
delete f;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
NumberFormat* f = NULL;
|
||||
DecimalFormatSymbols* symbolsToAdopt = NULL;
|
||||
UnicodeString pattern;
|
||||
|
|
259
icu4c/source/i18n/wincoll.cpp
Normal file
259
icu4c/source/i18n/wincoll.cpp
Normal file
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
********************************************************************************
|
||||
* Copyright (C) 2005-2006, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
********************************************************************************
|
||||
*
|
||||
* File WINCOLL.CPP
|
||||
*
|
||||
********************************************************************************
|
||||
*/
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
#ifdef U_WINDOWS
|
||||
|
||||
#if !UCONFIG_NO_COLLATION
|
||||
|
||||
#include "wincoll.h"
|
||||
|
||||
#include "unicode/coll.h"
|
||||
#include "unicode/locid.h"
|
||||
#include "unicode/ustring.h"
|
||||
|
||||
// NOTE: a PRIVATE interface!
|
||||
#include "locmap.h"
|
||||
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# define VC_EXTRALEAN
|
||||
# define NOUSER
|
||||
# define NOSERVICE
|
||||
# define NOIME
|
||||
# define NOMCX
|
||||
#include <windows.h>
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Win32Collator)
|
||||
|
||||
Win32Collator::Win32Collator(const Locale &locale, UErrorCode &status)
|
||||
: Collator(), fStrength(TERTIARY)
|
||||
{
|
||||
if (!U_FAILURE(status)) {
|
||||
fLCID = locale.getLCID();
|
||||
}
|
||||
}
|
||||
|
||||
Win32Collator::Win32Collator(const Locale &locale, ECollationStrength strength, UErrorCode &status)
|
||||
: Collator(), fStrength(strength)
|
||||
{
|
||||
if (!U_FAILURE(status)) {
|
||||
fLCID = locale.getLCID();
|
||||
}
|
||||
}
|
||||
|
||||
Win32Collator::Win32Collator(const Win32Collator &other)
|
||||
: Collator(other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
Win32Collator::~Win32Collator()
|
||||
{
|
||||
// anything?
|
||||
}
|
||||
|
||||
Win32Collator &Win32Collator::operator=(const Win32Collator &other)
|
||||
{
|
||||
// Collator::operator=(other);
|
||||
|
||||
this->fLCID = other.fLCID;
|
||||
this->fStrength = other.fStrength;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Collator *Win32Collator::clone(void) const
|
||||
{
|
||||
return new Win32Collator(*this);
|
||||
}
|
||||
|
||||
UCollationResult Win32Collator::compare(const UnicodeString& source,
|
||||
const UnicodeString& target,
|
||||
UErrorCode &status) const
|
||||
{
|
||||
return compare(source.getBuffer(), source.length(),
|
||||
target.getBuffer(), target.length(),
|
||||
status);
|
||||
}
|
||||
|
||||
UCollationResult Win32Collator::compare(const UnicodeString& source,
|
||||
const UnicodeString& target,
|
||||
int32_t length,
|
||||
UErrorCode &status) const
|
||||
{
|
||||
return compare(source.getBuffer(), length, target.getBuffer(), length, status);
|
||||
}
|
||||
|
||||
UCollationResult Win32Collator::compare(const UChar* source, int32_t sourceLength,
|
||||
const UChar* target, int32_t targetLength,
|
||||
UErrorCode &status) const
|
||||
{
|
||||
DWORD dwCmpFlags = fStrength > Collator::SECONDARY? 0 : NORM_IGNORECASE;
|
||||
int32_t result = CompareStringW(fLCID, dwCmpFlags, source, sourceLength, target, targetLength);
|
||||
|
||||
return (UCollationResult) (result - 2);
|
||||
}
|
||||
|
||||
CollationKey &Win32Collator::getCollationKey(const UnicodeString& source,
|
||||
CollationKey& key,
|
||||
UErrorCode& status) const
|
||||
{
|
||||
return getCollationKey(source.getBuffer(), source.length(), key, status);
|
||||
}
|
||||
|
||||
// TODO: This ends up pre-flighting twice, becuase it calls getSortKey() twice,
|
||||
// and that always pre-flights. Might be OK for a deprecated API...
|
||||
CollationKey &Win32Collator::getCollationKey(const UChar*source,
|
||||
int32_t sourceLength,
|
||||
CollationKey& key,
|
||||
UErrorCode& status) const
|
||||
{
|
||||
#ifdef FRIEND_OF_COLLATION_KEY
|
||||
if (U_FAILURE(status)) {
|
||||
return key.setToBogus();
|
||||
}
|
||||
|
||||
if ((!source) || (sourceLen == 0)) {
|
||||
return key.reset();
|
||||
}
|
||||
|
||||
int32_t resultLen = getSortKey(source, sourceLength, NULL, 0);
|
||||
uint8_t *result = new uint8_t[resultLen];
|
||||
|
||||
getSortKey(source, sourceLength, result, resutLen);
|
||||
key.adopt(result, resultLen);
|
||||
#else
|
||||
status = U_UNSUPPORTED_ERROR;
|
||||
#endif
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
// TODO: is this good enough? (Do we care?)
|
||||
int32_t Win32Collator::hashCode(void) const
|
||||
{
|
||||
return fLCID ^ fStrength;
|
||||
}
|
||||
|
||||
// TODO: Good enough?
|
||||
const Locale Win32Collator::getLocale(ULocDataLocaleType type, UErrorCode& status) const
|
||||
{
|
||||
Locale loc(uprv_convertToPosix(fLCID, &status));
|
||||
|
||||
return loc;
|
||||
}
|
||||
|
||||
Collator::ECollationStrength Win32Collator::getStrength(void) const
|
||||
{
|
||||
return fStrength;
|
||||
}
|
||||
|
||||
void Win32Collator::setStrength(Collator::ECollationStrength newStrength)
|
||||
{
|
||||
fStrength = newStrength;
|
||||
}
|
||||
|
||||
// TODO: Need to include Windows version?
|
||||
void Win32Collator::getVersion(UVersionInfo info) const
|
||||
{
|
||||
info[0] = info[1] = info[2] = info[3] = 0;
|
||||
}
|
||||
|
||||
void Win32Collator::setAttribute(UColAttribute attr, UColAttributeValue value, UErrorCode &status)
|
||||
{
|
||||
if (attr == UCOL_STRENGTH) {
|
||||
fStrength = getECollationStrength(value);
|
||||
} else {
|
||||
status = U_UNSUPPORTED_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
UColAttributeValue Win32Collator::getAttribute(UColAttribute attr, UErrorCode &status)
|
||||
{
|
||||
if (attr == UCOL_STRENGTH) {
|
||||
return getUCollationStrength(fStrength);
|
||||
}
|
||||
|
||||
status = U_UNSUPPORTED_ERROR;
|
||||
return UCOL_DEFAULT;
|
||||
}
|
||||
|
||||
uint32_t Win32Collator::setVariableTop(const UChar *varTop, int32_t len, UErrorCode &status)
|
||||
{
|
||||
status = U_UNSUPPORTED_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t Win32Collator::setVariableTop(const UnicodeString varTop, UErrorCode &status)
|
||||
{
|
||||
status = U_UNSUPPORTED_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Win32Collator::setVariableTop(const uint32_t varTop, UErrorCode &status)
|
||||
{
|
||||
status = U_UNSUPPORTED_ERROR;
|
||||
}
|
||||
|
||||
uint32_t Win32Collator::getVariableTop(UErrorCode &status) const
|
||||
{
|
||||
status = U_UNSUPPORTED_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Collator* Win32Collator::safeClone(void)
|
||||
{
|
||||
return clone();
|
||||
}
|
||||
|
||||
int32_t Win32Collator::getSortKey(const UnicodeString &source, uint8_t *result, int32_t resultLength) const
|
||||
{
|
||||
return getSortKey(source.getBuffer(), source.length(), result, resultLength);
|
||||
}
|
||||
|
||||
// TODO: Is there a way to do this w/o pre-flighting?
|
||||
// TODO: We could avoid the tests of resultLength if we always copy from our buffer into result
|
||||
int32_t Win32Collator::getSortKey(const UChar *source, int32_t sourceLength, uint8_t *result, int32_t resultLength) const
|
||||
{
|
||||
int32_t requiredLength = LCMapStringW(fLCID, LCMAP_SORTKEY, source, sourceLength, NULL, 0);
|
||||
|
||||
if (result != NULL) {
|
||||
uint8_t *res = result;
|
||||
int32_t resLen = resultLength;
|
||||
|
||||
if (requiredLength > resultLength) {
|
||||
res = new uint8_t[requiredLength];
|
||||
resLen = requiredLength;
|
||||
}
|
||||
|
||||
// We don't need to keep the return value here because it will be requiredLength.
|
||||
LCMapStringW(fLCID, LCMAP_SORTKEY, source, sourceLength, (LPWSTR) res, resLen);
|
||||
|
||||
if (requiredLength > resultLength) {
|
||||
for (int32_t i = 0; i < resultLength; i += 1) {
|
||||
result[i] = res[i];
|
||||
}
|
||||
|
||||
delete[] res;
|
||||
}
|
||||
}
|
||||
|
||||
return requiredLength;
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif /* #if !UCONFIG_NO_COLLATION */
|
||||
|
||||
#endif // #ifdef U_WINDOWS
|
397
icu4c/source/i18n/wincoll.h
Normal file
397
icu4c/source/i18n/wincoll.h
Normal file
|
@ -0,0 +1,397 @@
|
|||
/*
|
||||
********************************************************************************
|
||||
* Copyright (C) 2005-2006, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
********************************************************************************
|
||||
*
|
||||
* File WINCOLL.H
|
||||
*
|
||||
********************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __WINCOLL
|
||||
#define __WINCOLL
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
#ifdef U_WINDOWS
|
||||
|
||||
#if !UCONFIG_NO_COLLATION
|
||||
|
||||
#include "unicode/coll.h"
|
||||
#include "unicode/ustring.h"
|
||||
#include "unicode/locid.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief C++ API: Collation using Windows API.
|
||||
*/
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
class Win32Collator : public Collator
|
||||
{
|
||||
public:
|
||||
Win32Collator(const Locale &locale, UErrorCode &status);
|
||||
|
||||
Win32Collator(const Locale &locale, ECollationStrength strength, UErrorCode &status);
|
||||
|
||||
Win32Collator(const Win32Collator &other);
|
||||
|
||||
virtual ~Win32Collator();
|
||||
|
||||
virtual Collator *clone(void) const;
|
||||
|
||||
Win32Collator &operator=(const Win32Collator &other);
|
||||
|
||||
/**
|
||||
* The comparison function compares the character data stored in two
|
||||
* different strings. Returns information about whether a string is less
|
||||
* than, greater than or equal to another string.
|
||||
* @param source the source string to be compared with.
|
||||
* @param target the string that is to be compared with the source string.
|
||||
* @param status possible error code
|
||||
* @return Returns an enum value. UCOL_GREATER if source is greater
|
||||
* than target; UCOL_EQUAL if source is equal to target; UCOL_LESS if source is less
|
||||
* than target
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual UCollationResult compare(const UnicodeString& source,
|
||||
const UnicodeString& target,
|
||||
UErrorCode &status) const;
|
||||
|
||||
/**
|
||||
* Does the same thing as compare but limits the comparison to a specified
|
||||
* length
|
||||
* @param source the source string to be compared with.
|
||||
* @param target the string that is to be compared with the source string.
|
||||
* @param length the length the comparison is limited to
|
||||
* @param status possible error code
|
||||
* @return Returns an enum value. UCOL_GREATER if source (up to the specified
|
||||
* length) is greater than target; UCOL_EQUAL if source (up to specified
|
||||
* length) is equal to target; UCOL_LESS if source (up to the specified
|
||||
* length) is less than target.
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual UCollationResult compare(const UnicodeString& source,
|
||||
const UnicodeString& target,
|
||||
int32_t length,
|
||||
UErrorCode &status) const;
|
||||
|
||||
/**
|
||||
* The comparison function compares the character data stored in two
|
||||
* different string arrays. Returns information about whether a string array
|
||||
* is less than, greater than or equal to another string array.
|
||||
* @param source the source string array to be compared with.
|
||||
* @param sourceLength the length of the source string array. If this value
|
||||
* is equal to -1, the string array is null-terminated.
|
||||
* @param target the string that is to be compared with the source string.
|
||||
* @param targetLength the length of the target string array. If this value
|
||||
* is equal to -1, the string array is null-terminated.
|
||||
* @param status possible error code
|
||||
* @return Returns an enum value. UCOL_GREATER if source is greater
|
||||
* than target; UCOL_EQUAL if source is equal to target; UCOL_LESS if source is less
|
||||
* than target
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual UCollationResult compare(const UChar* source, int32_t sourceLength,
|
||||
const UChar* target, int32_t targetLength,
|
||||
UErrorCode &status) const;
|
||||
|
||||
/**
|
||||
* Transforms the string into a series of characters that can be compared
|
||||
* with CollationKey::compareTo. It is not possible to restore the original
|
||||
* string from the chars in the sort key. The generated sort key handles
|
||||
* only a limited number of ignorable characters.
|
||||
* <p>Use CollationKey::equals or CollationKey::compare to compare the
|
||||
* generated sort keys.
|
||||
* If the source string is null, a null collation key will be returned.
|
||||
* @param source the source string to be transformed into a sort key.
|
||||
* @param key the collation key to be filled in
|
||||
* @param status the error code status.
|
||||
* @return the collation key of the string based on the collation rules.
|
||||
* @see CollationKey#compare
|
||||
* @deprecated ICU 2.8 Use getSortKey(...) instead
|
||||
*/
|
||||
virtual CollationKey& getCollationKey(const UnicodeString& source,
|
||||
CollationKey& key,
|
||||
UErrorCode& status) const;
|
||||
|
||||
/**
|
||||
* Transforms the string into a series of characters that can be compared
|
||||
* with CollationKey::compareTo. It is not possible to restore the original
|
||||
* string from the chars in the sort key. The generated sort key handles
|
||||
* only a limited number of ignorable characters.
|
||||
* <p>Use CollationKey::equals or CollationKey::compare to compare the
|
||||
* generated sort keys.
|
||||
* <p>If the source string is null, a null collation key will be returned.
|
||||
* @param source the source string to be transformed into a sort key.
|
||||
* @param sourceLength length of the collation key
|
||||
* @param key the collation key to be filled in
|
||||
* @param status the error code status.
|
||||
* @return the collation key of the string based on the collation rules.
|
||||
* @see CollationKey#compare
|
||||
* @deprecated ICU 2.8 Use getSortKey(...) instead
|
||||
*/
|
||||
virtual CollationKey& getCollationKey(const UChar*source,
|
||||
int32_t sourceLength,
|
||||
CollationKey& key,
|
||||
UErrorCode& status) const;
|
||||
/**
|
||||
* Generates the hash code for the collation object
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual int32_t hashCode(void) const;
|
||||
|
||||
/**
|
||||
* Gets the locale of the Collator
|
||||
*
|
||||
* @param type can be either requested, valid or actual locale. For more
|
||||
* information see the definition of ULocDataLocaleType in
|
||||
* uloc.h
|
||||
* @param status the error code status.
|
||||
* @return locale where the collation data lives. If the collator
|
||||
* was instantiated from rules, locale is empty.
|
||||
* @deprecated ICU 2.8 This API is under consideration for revision
|
||||
* in ICU 3.0.
|
||||
*/
|
||||
virtual const Locale getLocale(ULocDataLocaleType type, UErrorCode& status) const;
|
||||
|
||||
/**
|
||||
* Determines the minimum strength that will be use in comparison or
|
||||
* transformation.
|
||||
* <p>E.g. with strength == SECONDARY, the tertiary difference is ignored
|
||||
* <p>E.g. with strength == PRIMARY, the secondary and tertiary difference
|
||||
* are ignored.
|
||||
* @return the current comparison level.
|
||||
* @see Collator#setStrength
|
||||
* @deprecated ICU 2.6 Use getAttribute(UCOL_STRENGTH...) instead
|
||||
*/
|
||||
virtual ECollationStrength getStrength(void) const;
|
||||
|
||||
/**
|
||||
* Sets the minimum strength to be used in comparison or transformation.
|
||||
* <p>Example of use:
|
||||
* <pre>
|
||||
* \code
|
||||
* UErrorCode status = U_ZERO_ERROR;
|
||||
* Collator*myCollation = Collator::createInstance(Locale::US, status);
|
||||
* if (U_FAILURE(status)) return;
|
||||
* myCollation->setStrength(Collator::PRIMARY);
|
||||
* // result will be "abc" == "ABC"
|
||||
* // tertiary differences will be ignored
|
||||
* Collator::ComparisonResult result = myCollation->compare("abc", "ABC");
|
||||
* \endcode
|
||||
* </pre>
|
||||
* @see Collator#getStrength
|
||||
* @param newStrength the new comparison level.
|
||||
* @deprecated ICU 2.6 Use setAttribute(UCOL_STRENGTH...) instead
|
||||
*/
|
||||
virtual void setStrength(ECollationStrength newStrength);
|
||||
|
||||
/**
|
||||
* Gets the version information for a Collator.
|
||||
* @param info the version # information, the result will be filled in
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual void getVersion(UVersionInfo info) const;
|
||||
|
||||
/**
|
||||
* Universal attribute setter
|
||||
* @param attr attribute type
|
||||
* @param value attribute value
|
||||
* @param status to indicate whether the operation went on smoothly or
|
||||
* there were errors
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual void setAttribute(UColAttribute attr, UColAttributeValue value,
|
||||
UErrorCode &status);
|
||||
|
||||
/**
|
||||
* Universal attribute getter
|
||||
* @param attr attribute type
|
||||
* @param status to indicate whether the operation went on smoothly or
|
||||
* there were errors
|
||||
* @return attribute value
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual UColAttributeValue getAttribute(UColAttribute attr,
|
||||
UErrorCode &status);
|
||||
|
||||
/**
|
||||
* Sets the variable top to a collation element value of a string supplied.
|
||||
* @param varTop one or more (if contraction) UChars to which the variable top should be set
|
||||
* @param len length of variable top string. If -1 it is considered to be zero terminated.
|
||||
* @param status error code. If error code is set, the return value is undefined. Errors set by this function are: <br>
|
||||
* U_CE_NOT_FOUND_ERROR if more than one character was passed and there is no such a contraction<br>
|
||||
* U_PRIMARY_TOO_LONG_ERROR if the primary for the variable top has more than two bytes
|
||||
* @return a 32 bit value containing the value of the variable top in upper 16 bits. Lower 16 bits are undefined
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual uint32_t setVariableTop(const UChar *varTop, int32_t len, UErrorCode &status);
|
||||
|
||||
/**
|
||||
* Sets the variable top to a collation element value of a string supplied.
|
||||
* @param varTop an UnicodeString size 1 or more (if contraction) of UChars to which the variable top should be set
|
||||
* @param status error code. If error code is set, the return value is undefined. Errors set by this function are: <br>
|
||||
* U_CE_NOT_FOUND_ERROR if more than one character was passed and there is no such a contraction<br>
|
||||
* U_PRIMARY_TOO_LONG_ERROR if the primary for the variable top has more than two bytes
|
||||
* @return a 32 bit value containing the value of the variable top in upper 16 bits. Lower 16 bits are undefined
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual uint32_t setVariableTop(const UnicodeString varTop, UErrorCode &status);
|
||||
|
||||
/**
|
||||
* Sets the variable top to a collation element value supplied. Variable top is set to the upper 16 bits.
|
||||
* Lower 16 bits are ignored.
|
||||
* @param varTop CE value, as returned by setVariableTop or ucol)getVariableTop
|
||||
* @param status error code (not changed by function)
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual void setVariableTop(const uint32_t varTop, UErrorCode &status);
|
||||
|
||||
/**
|
||||
* Gets the variable top value of a Collator.
|
||||
* Lower 16 bits are undefined and should be ignored.
|
||||
* @param status error code (not changed by function). If error code is set, the return value is undefined.
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual uint32_t getVariableTop(UErrorCode &status) const;
|
||||
|
||||
/**
|
||||
* Thread safe cloning operation
|
||||
* @return pointer to the new clone, user should remove it.
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual Collator* safeClone(void);
|
||||
|
||||
/**
|
||||
* Get the sort key as an array of bytes from an UnicodeString.
|
||||
* Sort key byte arrays are zero-terminated and can be compared using
|
||||
* strcmp().
|
||||
* @param source string to be processed.
|
||||
* @param result buffer to store result in. If NULL, number of bytes needed
|
||||
* will be returned.
|
||||
* @param resultLength length of the result buffer. If if not enough the
|
||||
* buffer will be filled to capacity.
|
||||
* @return Number of bytes needed for storing the sort key
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual int32_t getSortKey(const UnicodeString& source,
|
||||
uint8_t* result,
|
||||
int32_t resultLength) const;
|
||||
|
||||
/**
|
||||
* Get the sort key as an array of bytes from an UChar buffer.
|
||||
* Sort key byte arrays are zero-terminated and can be compared using
|
||||
* strcmp().
|
||||
* @param source string to be processed.
|
||||
* @param sourceLength length of string to be processed.
|
||||
* If -1, the string is 0 terminated and length will be decided by the
|
||||
* function.
|
||||
* @param result buffer to store result in. If NULL, number of bytes needed
|
||||
* will be returned.
|
||||
* @param resultLength length of the result buffer. If if not enough the
|
||||
* buffer will be filled to capacity.
|
||||
* @return Number of bytes needed for storing the sort key
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual int32_t getSortKey(const UChar*source, int32_t sourceLength,
|
||||
uint8_t*result, int32_t resultLength) const;
|
||||
|
||||
/**
|
||||
* Return the class ID for this class. This is useful only for comparing to
|
||||
* a return value from getDynamicClassID(). For example:
|
||||
* <pre>
|
||||
* . Base* polymorphic_pointer = createPolymorphicObject();
|
||||
* . if (polymorphic_pointer->getDynamicClassID() ==
|
||||
* . erived::getStaticClassID()) ...
|
||||
* </pre>
|
||||
* @return The class ID for all objects of this class.
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
static UClassID U_EXPORT2 getStaticClassID(void);
|
||||
|
||||
/**
|
||||
* Returns a unique class ID POLYMORPHICALLY. Pure virtual override. This
|
||||
* method is to implement a simple version of RTTI, since not all C++
|
||||
* compilers support genuine RTTI. Polymorphic operator==() and clone()
|
||||
* methods call this method.
|
||||
*
|
||||
* @return The class ID for this object. All objects of a
|
||||
* given class have the same class ID. Objects of
|
||||
* other classes have different class IDs.
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual UClassID getDynamicClassID(void) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Converts C's UCollationStrength to ECollationStrength
|
||||
* @param strength member of the enum UCollationStrength
|
||||
* @return ECollationStrength equivalent of UCollationStrength
|
||||
*/
|
||||
Collator::ECollationStrength getECollationStrength(UCollationStrength strength) const;
|
||||
|
||||
/**
|
||||
* Converts C++'s ECollationStrength to UCollationStrength
|
||||
* @param strength member of the enum ECollationStrength
|
||||
* @return UCollationStrength equivalent of ECollationStrength
|
||||
*/
|
||||
UCollationStrength getUCollationStrength(Collator::ECollationStrength strength) const;
|
||||
|
||||
|
||||
int32_t fLCID;
|
||||
ECollationStrength fStrength;
|
||||
|
||||
};
|
||||
|
||||
inline Collator::ECollationStrength Win32Collator::getECollationStrength(UCollationStrength strength) const
|
||||
{
|
||||
switch (strength)
|
||||
{
|
||||
case UCOL_PRIMARY :
|
||||
return Collator::PRIMARY;
|
||||
|
||||
case UCOL_SECONDARY :
|
||||
return Collator::SECONDARY;
|
||||
|
||||
case UCOL_TERTIARY :
|
||||
return Collator::TERTIARY;
|
||||
|
||||
case UCOL_QUATERNARY :
|
||||
return Collator::QUATERNARY;
|
||||
|
||||
default :
|
||||
return Collator::IDENTICAL;
|
||||
}
|
||||
}
|
||||
|
||||
inline UCollationStrength Win32Collator::getUCollationStrength(Collator::ECollationStrength strength) const
|
||||
{
|
||||
switch (strength)
|
||||
{
|
||||
case Collator::PRIMARY :
|
||||
return UCOL_PRIMARY;
|
||||
|
||||
case Collator::SECONDARY :
|
||||
return UCOL_SECONDARY;
|
||||
|
||||
case Collator::TERTIARY :
|
||||
return UCOL_TERTIARY;
|
||||
|
||||
case Collator::QUATERNARY :
|
||||
return UCOL_QUATERNARY;
|
||||
|
||||
default :
|
||||
return UCOL_IDENTICAL;
|
||||
}
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif /* #if !UCONFIG_NO_COLLATION */
|
||||
|
||||
#endif // #ifdef U_WINDOWS
|
||||
|
||||
#endif // __WINCOLL
|
306
icu4c/source/i18n/windtfmt.cpp
Normal file
306
icu4c/source/i18n/windtfmt.cpp
Normal file
|
@ -0,0 +1,306 @@
|
|||
/*
|
||||
********************************************************************************
|
||||
* Copyright (C) 2005-2006, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
********************************************************************************
|
||||
*
|
||||
* File WINDTFMT.CPP
|
||||
*
|
||||
********************************************************************************
|
||||
*/
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
#ifdef U_WINDOWS
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
#include "unicode/ures.h"
|
||||
#include "unicode/format.h"
|
||||
#include "unicode/fmtable.h"
|
||||
#include "unicode/datefmt.h"
|
||||
#include "unicode/msgfmt.h"
|
||||
#include "unicode/calendar.h"
|
||||
#include "unicode/gregocal.h"
|
||||
#include "unicode/locid.h"
|
||||
#include "unicode/unistr.h"
|
||||
#include "unicode/ustring.h"
|
||||
#include "unicode/timezone.h"
|
||||
#include "unicode/utmscale.h"
|
||||
|
||||
#include "cmemory.h"
|
||||
#include "uresimp.h"
|
||||
#include "windtfmt.h"
|
||||
#include "wintz.h"
|
||||
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# define VC_EXTRALEAN
|
||||
# define NOUSER
|
||||
# define NOSERVICE
|
||||
# define NOIME
|
||||
# define NOMCX
|
||||
#include <windows.h>
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Win32DateFormat)
|
||||
|
||||
#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
|
||||
|
||||
#define NEW_ARRAY(type,count) (type *) uprv_malloc((count) * sizeof(type))
|
||||
#define DELETE_ARRAY(array) uprv_free((void *) (array))
|
||||
|
||||
#define STACK_BUFFER_SIZE 64
|
||||
|
||||
UnicodeString *getTimeDateFormat(const Calendar *cal, const Locale *locale, UErrorCode &status)
|
||||
{
|
||||
UnicodeString *result = NULL;
|
||||
const char *type = cal->getType();
|
||||
const char *base = locale->getBaseName();
|
||||
UResourceBundle *topBundle = ures_open((char *) 0, base, &status);
|
||||
UResourceBundle *calBundle = ures_getByKey(topBundle, "calendar", NULL, &status);
|
||||
UResourceBundle *typBundle = ures_getByKeyWithFallback(calBundle, type, NULL, &status);
|
||||
UResourceBundle *patBundle = ures_getByKeyWithFallback(typBundle, "DateTimePatterns", NULL, &status);
|
||||
|
||||
if (status == U_MISSING_RESOURCE_ERROR) {
|
||||
status = U_ZERO_ERROR;
|
||||
typBundle = ures_getByKeyWithFallback(calBundle, "gregorian", typBundle, &status);
|
||||
patBundle = ures_getByKeyWithFallback(typBundle, "DateTimePatterns", patBundle, &status);
|
||||
}
|
||||
|
||||
if (U_FAILURE(status)) {
|
||||
UChar defaultPattern[] = {0x007B, 0x0031, 0x007D, 0x0020, 0x007B, 0x0030, 0x007D, 0x0000}; // "{1} {0}"
|
||||
return new UnicodeString(defaultPattern, ARRAY_SIZE(defaultPattern));
|
||||
}
|
||||
|
||||
int32_t resStrLen = 0;
|
||||
const UChar *resStr = ures_getStringByIndex(patBundle, (int32_t)DateFormat::kDateTime, &resStrLen, &status);
|
||||
|
||||
result = new UnicodeString(TRUE, resStr, resStrLen);
|
||||
|
||||
ures_close(patBundle);
|
||||
ures_close(typBundle);
|
||||
ures_close(calBundle);
|
||||
ures_close(topBundle);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO: Range-check timeStyle, dateStyle
|
||||
Win32DateFormat::Win32DateFormat(DateFormat::EStyle timeStyle, DateFormat::EStyle dateStyle, const Locale &locale, UErrorCode &status)
|
||||
: DateFormat(), fDateTimeMsg(NULL), fTimeStyle(timeStyle), fDateStyle(dateStyle), fLocale(&locale), fZoneID(NULL)
|
||||
{
|
||||
if (!U_FAILURE(status)) {
|
||||
fLCID = locale.getLCID();
|
||||
fTZI = new TIME_ZONE_INFORMATION();
|
||||
adoptCalendar(Calendar::createInstance(locale, status));
|
||||
}
|
||||
}
|
||||
|
||||
Win32DateFormat::Win32DateFormat(const Win32DateFormat &other)
|
||||
: DateFormat(other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
Win32DateFormat::~Win32DateFormat()
|
||||
{
|
||||
delete fCalendar;
|
||||
delete fTZI;
|
||||
delete fDateTimeMsg;
|
||||
}
|
||||
|
||||
Win32DateFormat &Win32DateFormat::operator=(const Win32DateFormat &other)
|
||||
{
|
||||
DateFormat::operator=(other);
|
||||
|
||||
delete fCalendar;
|
||||
|
||||
this->fDateTimeMsg = other.fDateTimeMsg;
|
||||
this->fTimeStyle = other.fTimeStyle;
|
||||
this->fDateStyle = other.fDateStyle;
|
||||
this->fLCID = other.fLCID;
|
||||
this->fCalendar = other.fCalendar->clone();
|
||||
this->fZoneID = other.fZoneID;
|
||||
|
||||
this->fTZI = new TIME_ZONE_INFORMATION();
|
||||
*this->fTZI = *other.fTZI;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Format *Win32DateFormat::clone(void) const
|
||||
{
|
||||
return new Win32DateFormat(*this);
|
||||
}
|
||||
|
||||
// TODO: Is just ignoring pos the right thing?
|
||||
UnicodeString &Win32DateFormat::format(Calendar &cal, UnicodeString &appendTo, FieldPosition &pos) const
|
||||
{
|
||||
FILETIME ft;
|
||||
SYSTEMTIME st_gmt;
|
||||
SYSTEMTIME st_local;
|
||||
UnicodeString zoneID;
|
||||
TIME_ZONE_INFORMATION tzi = *fTZI;
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
const TimeZone &tz = cal.getTimeZone();
|
||||
int64_t uct, uft;
|
||||
|
||||
tz.getID(zoneID);
|
||||
|
||||
if (zoneID.compare(fZoneID) != 0) {
|
||||
UnicodeString icuid;
|
||||
|
||||
tz.getID(icuid);
|
||||
u_getWindowsTimeZoneInfo(&tzi, icuid.getBuffer(), icuid.length());
|
||||
}
|
||||
|
||||
uct = utmscale_fromInt64((int64_t) cal.getTime(status), UDTS_ICU4C_TIME, &status);
|
||||
uft = utmscale_toInt64(uct, UDTS_WINDOWS_FILE_TIME, &status);
|
||||
|
||||
ft.dwLowDateTime = (DWORD) (uft & 0xFFFFFFFF);
|
||||
ft.dwHighDateTime = (DWORD) ((uft >> 32) & 0xFFFFFFFF);
|
||||
|
||||
FileTimeToSystemTime(&ft, &st_gmt);
|
||||
SystemTimeToTzSpecificLocalTime(&tzi, &st_gmt, &st_local);
|
||||
|
||||
|
||||
if (fDateStyle != DateFormat::kNone && fTimeStyle != DateFormat::kNone) {
|
||||
UnicodeString *date = new UnicodeString();
|
||||
UnicodeString *time = new UnicodeString();
|
||||
UnicodeString *pattern = fDateTimeMsg;
|
||||
Formattable timeDateArray[2];
|
||||
|
||||
formatDate(&st_local, *date);
|
||||
formatTime(&st_local, *time);
|
||||
|
||||
timeDateArray[0].adoptString(time);
|
||||
timeDateArray[1].adoptString(date);
|
||||
|
||||
if (strcmp(fCalendar->getType(), cal.getType()) != 0) {
|
||||
pattern = getTimeDateFormat(&cal, fLocale, status);
|
||||
}
|
||||
|
||||
MessageFormat::format(*pattern, timeDateArray, 2, appendTo, status);
|
||||
} else if (fDateStyle != DateFormat::kNone) {
|
||||
formatDate(&st_local, appendTo);
|
||||
} else if (fDateStyle != DateFormat::kNone) {
|
||||
formatTime(&st_local, appendTo);
|
||||
}
|
||||
|
||||
return appendTo;
|
||||
}
|
||||
|
||||
void Win32DateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition& pos) const
|
||||
{
|
||||
pos.setErrorIndex(pos.getIndex());
|
||||
}
|
||||
|
||||
void Win32DateFormat::adoptCalendar(Calendar *newCalendar)
|
||||
{
|
||||
if (fCalendar == NULL || strcmp(fCalendar->getType(), newCalendar->getType()) != 0) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
|
||||
if (fDateStyle != DateFormat::kNone && fTimeStyle != DateFormat::kNone) {
|
||||
delete fDateTimeMsg;
|
||||
fDateTimeMsg = getTimeDateFormat(newCalendar, fLocale, status);
|
||||
}
|
||||
}
|
||||
|
||||
delete fCalendar;
|
||||
fCalendar = newCalendar;
|
||||
|
||||
setTimeZoneInfo(fCalendar->getTimeZone());
|
||||
}
|
||||
|
||||
void Win32DateFormat::setCalendar(const Calendar &newCalendar)
|
||||
{
|
||||
adoptCalendar(newCalendar.clone());
|
||||
}
|
||||
|
||||
void Win32DateFormat::adoptTimeZone(TimeZone *zoneToAdopt)
|
||||
{
|
||||
setTimeZoneInfo(*zoneToAdopt);
|
||||
fCalendar->adoptTimeZone(zoneToAdopt);
|
||||
}
|
||||
|
||||
void Win32DateFormat::setTimeZone(const TimeZone& zone)
|
||||
{
|
||||
setTimeZoneInfo(zone);
|
||||
fCalendar->setTimeZone(zone);
|
||||
}
|
||||
|
||||
static const DWORD dfFlags[] = {DATE_LONGDATE, DATE_LONGDATE, DATE_SHORTDATE, DATE_SHORTDATE};
|
||||
|
||||
void Win32DateFormat::formatDate(const SYSTEMTIME *st, UnicodeString &appendTo) const
|
||||
{
|
||||
int result;
|
||||
UChar stackBuffer[STACK_BUFFER_SIZE];
|
||||
UChar *buffer = stackBuffer;
|
||||
|
||||
result = GetDateFormatW(fLCID, dfFlags[fDateStyle], st, NULL, buffer, STACK_BUFFER_SIZE);
|
||||
|
||||
if (result == 0) {
|
||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||||
int newLength = GetDateFormatW(fLCID, dfFlags[fDateStyle], st, NULL, NULL, 0);
|
||||
|
||||
buffer = NEW_ARRAY(UChar, newLength);
|
||||
GetDateFormatW(fLCID, dfFlags[fDateStyle], st, NULL, buffer, newLength);
|
||||
}
|
||||
}
|
||||
|
||||
appendTo.append(buffer, (int32_t) wcslen(buffer));
|
||||
|
||||
if (buffer != stackBuffer) {
|
||||
DELETE_ARRAY(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static const DWORD tfFlags[] = {0, 0, 0, TIME_NOSECONDS};
|
||||
|
||||
void Win32DateFormat::formatTime(const SYSTEMTIME *st, UnicodeString &appendTo) const
|
||||
{
|
||||
int result;
|
||||
UChar stackBuffer[STACK_BUFFER_SIZE];
|
||||
UChar *buffer = stackBuffer;
|
||||
|
||||
result = GetTimeFormatW(fLCID, tfFlags[fTimeStyle], st, NULL, buffer, STACK_BUFFER_SIZE);
|
||||
|
||||
if (result == 0) {
|
||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||||
int newLength = GetTimeFormatW(fLCID, tfFlags[fTimeStyle], st, NULL, NULL, 0);
|
||||
|
||||
buffer = NEW_ARRAY(UChar, newLength);
|
||||
GetDateFormatW(fLCID, tfFlags[fTimeStyle], st, NULL, buffer, newLength);
|
||||
}
|
||||
}
|
||||
|
||||
appendTo.append(buffer, (int32_t) wcslen(buffer));
|
||||
|
||||
if (buffer != stackBuffer) {
|
||||
DELETE_ARRAY(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void Win32DateFormat::setTimeZoneInfo(const TimeZone &zone)
|
||||
{
|
||||
UnicodeString zoneID;
|
||||
|
||||
zone.getID(zoneID);
|
||||
|
||||
if (zoneID.compare(fZoneID) != 0) {
|
||||
UnicodeString icuid;
|
||||
|
||||
fZoneID = zoneID;
|
||||
|
||||
zone.getID(icuid);
|
||||
u_getWindowsTimeZoneInfo(fTZI, icuid.getBuffer(), icuid.length());
|
||||
}
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
||||
#endif // #ifdef U_WINDOWS
|
||||
|
148
icu4c/source/i18n/windtfmt.h
Normal file
148
icu4c/source/i18n/windtfmt.h
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
********************************************************************************
|
||||
* Copyright (C) 2005-2006, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
********************************************************************************
|
||||
*
|
||||
* File WINDTFMT.H
|
||||
*
|
||||
********************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __WINDTFMT
|
||||
#define __WINDTFMT
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
#ifdef U_WINDOWS
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
#include "unicode/format.h"
|
||||
#include "unicode/datefmt.h"
|
||||
#include "unicode/calendar.h"
|
||||
#include "unicode/ustring.h"
|
||||
#include "unicode/locid.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief C++ API: Format dates using Windows API.
|
||||
*/
|
||||
|
||||
U_CDECL_BEGIN
|
||||
// Forward declarations for Windows types...
|
||||
typedef struct _SYSTEMTIME SYSTEMTIME;
|
||||
typedef struct _TIME_ZONE_INFORMATION TIME_ZONE_INFORMATION;
|
||||
U_CDECL_END
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
class Win32DateFormat : public DateFormat
|
||||
{
|
||||
public:
|
||||
Win32DateFormat(DateFormat::EStyle timeStyle, DateFormat::EStyle dateStyle, const Locale &locale, UErrorCode &status);
|
||||
|
||||
Win32DateFormat(const Win32DateFormat &other);
|
||||
|
||||
virtual ~Win32DateFormat();
|
||||
|
||||
virtual Format *clone(void) const;
|
||||
|
||||
Win32DateFormat &operator=(const Win32DateFormat &other);
|
||||
|
||||
UnicodeString &format(Calendar &cal, UnicodeString &appendTo, FieldPosition &pos) const;
|
||||
|
||||
UnicodeString& format(UDate date, UnicodeString& appendTo) const;
|
||||
|
||||
void parse(const UnicodeString& text, Calendar& cal, ParsePosition& pos) const;
|
||||
|
||||
/**
|
||||
* Set the calendar to be used by this date format. Initially, the default
|
||||
* calendar for the specified or default locale is used. The caller should
|
||||
* not delete the Calendar object after it is adopted by this call.
|
||||
*
|
||||
* @param calendarToAdopt Calendar object to be adopted.
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual void adoptCalendar(Calendar* calendarToAdopt);
|
||||
|
||||
/**
|
||||
* Set the calendar to be used by this date format. Initially, the default
|
||||
* calendar for the specified or default locale is used.
|
||||
*
|
||||
* @param newCalendar Calendar object to be set.
|
||||
*
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual void setCalendar(const Calendar& newCalendar);
|
||||
|
||||
/**
|
||||
* Sets the time zone for the calendar of this DateFormat object. The caller
|
||||
* no longer owns the TimeZone object and should not delete it after this call.
|
||||
*
|
||||
* @param zoneToAdopt the TimeZone to be adopted.
|
||||
*
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual void adoptTimeZone(TimeZone* zoneToAdopt);
|
||||
|
||||
/**
|
||||
* Sets the time zone for the calendar of this DateFormat object.
|
||||
* @param zone the new time zone.
|
||||
*
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual void setTimeZone(const TimeZone& zone);
|
||||
|
||||
/**
|
||||
* Return the class ID for this class. This is useful only for comparing to
|
||||
* a return value from getDynamicClassID(). For example:
|
||||
* <pre>
|
||||
* . Base* polymorphic_pointer = createPolymorphicObject();
|
||||
* . if (polymorphic_pointer->getDynamicClassID() ==
|
||||
* . erived::getStaticClassID()) ...
|
||||
* </pre>
|
||||
* @return The class ID for all objects of this class.
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
static UClassID U_EXPORT2 getStaticClassID(void);
|
||||
|
||||
/**
|
||||
* Returns a unique class ID POLYMORPHICALLY. Pure virtual override. This
|
||||
* method is to implement a simple version of RTTI, since not all C++
|
||||
* compilers support genuine RTTI. Polymorphic operator==() and clone()
|
||||
* methods call this method.
|
||||
*
|
||||
* @return The class ID for this object. All objects of a
|
||||
* given class have the same class ID. Objects of
|
||||
* other classes have different class IDs.
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual UClassID getDynamicClassID(void) const;
|
||||
|
||||
private:
|
||||
void formatDate(const SYSTEMTIME *st, UnicodeString &appendTo) const;
|
||||
void formatTime(const SYSTEMTIME *st, UnicodeString &appendTo) const;
|
||||
|
||||
void setTimeZoneInfo(const TimeZone &zone);
|
||||
|
||||
UnicodeString *fDateTimeMsg;
|
||||
DateFormat::EStyle fTimeStyle;
|
||||
DateFormat::EStyle fDateStyle;
|
||||
const Locale *fLocale;
|
||||
int32_t fLCID;
|
||||
UnicodeString fZoneID;
|
||||
TIME_ZONE_INFORMATION *fTZI;
|
||||
};
|
||||
|
||||
inline UnicodeString &Win32DateFormat::format(UDate date, UnicodeString& appendTo) const {
|
||||
return DateFormat::format(date, appendTo);
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
||||
#endif // #ifdef U_WINDOWS
|
||||
|
||||
#endif // __WINDTFMT
|
300
icu4c/source/i18n/winnmfmt.cpp
Normal file
300
icu4c/source/i18n/winnmfmt.cpp
Normal file
|
@ -0,0 +1,300 @@
|
|||
/*
|
||||
********************************************************************************
|
||||
* Copyright (C) 2005-2006, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
********************************************************************************
|
||||
*
|
||||
* File WINNMFMT.CPP
|
||||
*
|
||||
********************************************************************************
|
||||
*/
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
#ifdef U_WINDOWS
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
#include "winnmfmt.h"
|
||||
|
||||
#include "unicode/format.h"
|
||||
#include "unicode/numfmt.h"
|
||||
#include "unicode/locid.h"
|
||||
#include "unicode/ustring.h"
|
||||
|
||||
#include "cmemory.h"
|
||||
#include "locmap.h"
|
||||
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# define VC_EXTRALEAN
|
||||
# define NOUSER
|
||||
# define NOSERVICE
|
||||
# define NOIME
|
||||
# define NOMCX
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
union FormatInfo
|
||||
{
|
||||
NUMBERFMTW number;
|
||||
CURRENCYFMTW currency;
|
||||
};
|
||||
|
||||
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Win32NumberFormat)
|
||||
|
||||
#define NEW_ARRAY(type,count) (type *) uprv_malloc((count) * sizeof(type))
|
||||
#define DELETE_ARRAY(array) uprv_free((void *) (array))
|
||||
|
||||
#define STACK_BUFFER_SIZE 32
|
||||
|
||||
UINT getGrouping(const char *grouping)
|
||||
{
|
||||
UINT g = 0;
|
||||
|
||||
for (const char *s = grouping; *s != '\0'; s += 1) {
|
||||
if (*s > '0' && *s < '9') {
|
||||
g = g * 10 + (*s - '0');
|
||||
}
|
||||
}
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
void getNumberFormat(NUMBERFMTW *fmt, int32_t lcid)
|
||||
{
|
||||
int STR_LEN = 100;
|
||||
char buf[10];
|
||||
|
||||
GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_IDIGITS, (LPWSTR) &fmt->NumDigits, STR_LEN);
|
||||
GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_ILZERO, (LPWSTR) &fmt->LeadingZero, STR_LEN);
|
||||
|
||||
GetLocaleInfoA(lcid, LOCALE_SGROUPING, buf, 10);
|
||||
fmt->Grouping = getGrouping(buf);
|
||||
|
||||
fmt->lpDecimalSep = NEW_ARRAY(UChar, 6);
|
||||
GetLocaleInfoW(lcid, LOCALE_SDECIMAL, fmt->lpDecimalSep, 6);
|
||||
|
||||
fmt->lpThousandSep = NEW_ARRAY(UChar, 6);
|
||||
GetLocaleInfoW(lcid, LOCALE_STHOUSAND, fmt->lpThousandSep, 6);
|
||||
|
||||
GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_INEGNUMBER, (LPWSTR) &fmt->NegativeOrder, STR_LEN);
|
||||
}
|
||||
|
||||
void freeNumberFormat(NUMBERFMTW *fmt)
|
||||
{
|
||||
DELETE_ARRAY(fmt->lpThousandSep);
|
||||
DELETE_ARRAY(fmt->lpDecimalSep);
|
||||
}
|
||||
|
||||
void getCurrencyFormat(CURRENCYFMTW *fmt, int32_t lcid)
|
||||
{
|
||||
int STR_LEN = 100;
|
||||
char buf[10];
|
||||
|
||||
GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_IDIGITS, (LPWSTR) &fmt->NumDigits, STR_LEN);
|
||||
GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_ILZERO, (LPWSTR) &fmt->LeadingZero, STR_LEN);
|
||||
|
||||
GetLocaleInfoA(lcid, LOCALE_SMONGROUPING, buf, 10);
|
||||
fmt->Grouping = getGrouping(buf);
|
||||
|
||||
fmt->lpDecimalSep = NEW_ARRAY(UChar, 6);
|
||||
GetLocaleInfoW(lcid, LOCALE_SMONDECIMALSEP, fmt->lpDecimalSep, 6);
|
||||
|
||||
fmt->lpThousandSep = NEW_ARRAY(UChar, 6);
|
||||
GetLocaleInfoW(lcid, LOCALE_SMONTHOUSANDSEP, fmt->lpThousandSep, 6);
|
||||
|
||||
GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_INEGCURR, (LPWSTR) &fmt->NegativeOrder, STR_LEN);
|
||||
GetLocaleInfoW(lcid, LOCALE_RETURN_NUMBER|LOCALE_ICURRENCY, (LPWSTR) &fmt->PositiveOrder, STR_LEN);
|
||||
|
||||
fmt->lpCurrencySymbol = NEW_ARRAY(UChar, 8);
|
||||
GetLocaleInfoW(lcid, LOCALE_SCURRENCY, (LPWSTR) fmt->lpCurrencySymbol, 8);
|
||||
}
|
||||
|
||||
void freeCurrencyFormat(CURRENCYFMTW *fmt)
|
||||
{
|
||||
DELETE_ARRAY(fmt->lpCurrencySymbol);
|
||||
DELETE_ARRAY(fmt->lpThousandSep);
|
||||
DELETE_ARRAY(fmt->lpDecimalSep);
|
||||
}
|
||||
|
||||
// TODO: keep locale too?
|
||||
Win32NumberFormat::Win32NumberFormat(const Locale &locale, UBool currency, UErrorCode &status)
|
||||
: NumberFormat(), fCurrency(currency), fFractionDigitsSet(FALSE)
|
||||
{
|
||||
if (!U_FAILURE(status)) {
|
||||
fLCID = locale.getLCID();
|
||||
|
||||
fFormatInfo = new FormatInfo();
|
||||
|
||||
if (fCurrency) {
|
||||
getCurrencyFormat(&fFormatInfo->currency, fLCID);
|
||||
} else {
|
||||
getNumberFormat(&fFormatInfo->number, fLCID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Win32NumberFormat::Win32NumberFormat(const Win32NumberFormat &other)
|
||||
: NumberFormat(other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
Win32NumberFormat::~Win32NumberFormat()
|
||||
{
|
||||
if (fCurrency) {
|
||||
freeCurrencyFormat(&fFormatInfo->currency);
|
||||
} else {
|
||||
freeNumberFormat(&fFormatInfo->number);
|
||||
}
|
||||
|
||||
delete fFormatInfo;
|
||||
}
|
||||
|
||||
Win32NumberFormat &Win32NumberFormat::operator=(const Win32NumberFormat &other)
|
||||
{
|
||||
NumberFormat::operator=(other);
|
||||
|
||||
this->fCurrency = other.fCurrency;
|
||||
this->fLCID = other.fLCID;
|
||||
this->fFractionDigitsSet = other.fFractionDigitsSet;
|
||||
|
||||
this->fFormatInfo = new FormatInfo;
|
||||
*this->fFormatInfo = *other.fFormatInfo;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Format *Win32NumberFormat::clone(void) const
|
||||
{
|
||||
return new Win32NumberFormat(*this);
|
||||
}
|
||||
|
||||
UnicodeString& Win32NumberFormat::format(double number, UnicodeString& appendTo, FieldPosition& pos) const
|
||||
{
|
||||
return format(getMaximumFractionDigits(), appendTo, L"%f", number);
|
||||
}
|
||||
|
||||
UnicodeString& Win32NumberFormat::format(int32_t number, UnicodeString& appendTo, FieldPosition& pos) const
|
||||
{
|
||||
return format(getMinimumFractionDigits(), appendTo, L"%I32d", number);
|
||||
}
|
||||
|
||||
UnicodeString& Win32NumberFormat::format(int64_t number, UnicodeString& appendTo, FieldPosition& pos) const
|
||||
{
|
||||
return format(getMinimumFractionDigits(), appendTo, L"%I64d", number);
|
||||
}
|
||||
|
||||
// TODO: cache Locale and NumberFormat? Could keep locale passed to constructor...
|
||||
void Win32NumberFormat::parse(const UnicodeString& text, Formattable& result, ParsePosition& parsePosition) const
|
||||
{
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
Locale loc(uprv_convertToPosix(fLCID, &status));
|
||||
NumberFormat *nf = fCurrency? NumberFormat::createCurrencyInstance(loc, status) : NumberFormat::createInstance(loc, status);
|
||||
|
||||
nf->parse(text, result, parsePosition);
|
||||
delete nf;
|
||||
}
|
||||
void Win32NumberFormat::setMaximumFractionDigits(int32_t newValue)
|
||||
{
|
||||
fFractionDigitsSet = TRUE;
|
||||
NumberFormat::setMaximumFractionDigits(newValue);
|
||||
}
|
||||
|
||||
void Win32NumberFormat::setMinimumFractionDigits(int32_t newValue)
|
||||
{
|
||||
fFractionDigitsSet = TRUE;
|
||||
NumberFormat::setMinimumFractionDigits(newValue);
|
||||
}
|
||||
|
||||
UnicodeString &Win32NumberFormat::format(int32_t numDigits, UnicodeString &appendTo, wchar_t *fmt, ...) const
|
||||
{
|
||||
wchar_t nStackBuffer[STACK_BUFFER_SIZE];
|
||||
wchar_t *nBuffer = nStackBuffer;
|
||||
va_list args;
|
||||
int result;
|
||||
|
||||
va_start(args, fmt);
|
||||
result = vswprintf(nBuffer, STACK_BUFFER_SIZE, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
if (result < 0) {
|
||||
int newLength;
|
||||
|
||||
va_start(args, fmt);
|
||||
newLength = _vscwprintf(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
nBuffer = NEW_ARRAY(UChar, newLength);
|
||||
|
||||
va_start(args, fmt);
|
||||
result = vswprintf(nBuffer, newLength, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
UChar stackBuffer[STACK_BUFFER_SIZE];
|
||||
UChar *buffer = stackBuffer;
|
||||
FormatInfo formatInfo;
|
||||
|
||||
formatInfo = *fFormatInfo;
|
||||
|
||||
if (fCurrency) {
|
||||
if (fFractionDigitsSet) {
|
||||
formatInfo.currency.NumDigits = (UINT) numDigits;
|
||||
}
|
||||
|
||||
if (!isGroupingUsed()) {
|
||||
formatInfo.currency.Grouping = 0;
|
||||
}
|
||||
|
||||
result = GetCurrencyFormatW(fLCID, 0, nBuffer, &formatInfo.currency, buffer, STACK_BUFFER_SIZE);
|
||||
|
||||
if (result == 0) {
|
||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||||
int newLength = GetCurrencyFormatW(fLCID, 0, nBuffer, &formatInfo.currency, NULL, 0);
|
||||
|
||||
buffer = NEW_ARRAY(UChar, newLength);
|
||||
GetCurrencyFormatW(fLCID, 0, nBuffer, &formatInfo.currency, buffer, newLength);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (fFractionDigitsSet) {
|
||||
formatInfo.number.NumDigits = (UINT) numDigits;
|
||||
}
|
||||
|
||||
if (!isGroupingUsed()) {
|
||||
formatInfo.number.Grouping = 0;
|
||||
}
|
||||
|
||||
result = GetNumberFormatW(fLCID, 0, nBuffer, &formatInfo.number, buffer, STACK_BUFFER_SIZE);
|
||||
|
||||
if (result == 0) {
|
||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||||
int newLength = GetNumberFormatW(fLCID, 0, nBuffer, &formatInfo.number, NULL, 0);
|
||||
|
||||
buffer = NEW_ARRAY(UChar, newLength);
|
||||
GetNumberFormatW(fLCID, 0, nBuffer, &formatInfo.number, buffer, newLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
appendTo.append(buffer, (int32_t) wcslen(buffer));
|
||||
|
||||
if (buffer != stackBuffer) {
|
||||
DELETE_ARRAY(buffer);
|
||||
}
|
||||
|
||||
if (nBuffer != nStackBuffer) {
|
||||
DELETE_ARRAY(nBuffer);
|
||||
}
|
||||
|
||||
return appendTo;
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
||||
#endif // #ifdef U_WINDOWS
|
182
icu4c/source/i18n/winnmfmt.h
Normal file
182
icu4c/source/i18n/winnmfmt.h
Normal file
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
********************************************************************************
|
||||
* Copyright (C) 2005-2006, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
********************************************************************************
|
||||
*
|
||||
* File WINNMFMT.H
|
||||
*
|
||||
********************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __WINNMFMT
|
||||
#define __WINNMFMT
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
#ifdef U_WINDOWS
|
||||
|
||||
#include "unicode/format.h"
|
||||
#include "unicode/datefmt.h"
|
||||
#include "unicode/calendar.h"
|
||||
#include "unicode/ustring.h"
|
||||
#include "unicode/locid.h"
|
||||
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief C++ API: Format numbers using Windows API.
|
||||
*/
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
union FormatInfo;
|
||||
|
||||
class Win32NumberFormat : public NumberFormat
|
||||
{
|
||||
public:
|
||||
Win32NumberFormat(const Locale &locale, UBool currency, UErrorCode &status);
|
||||
|
||||
Win32NumberFormat(const Win32NumberFormat &other);
|
||||
|
||||
virtual ~Win32NumberFormat();
|
||||
|
||||
virtual Format *clone(void) const;
|
||||
|
||||
Win32NumberFormat &operator=(const Win32NumberFormat &other);
|
||||
|
||||
/**
|
||||
* Format a double number. Concrete subclasses must implement
|
||||
* these pure virtual methods.
|
||||
*
|
||||
* @param number The value to be formatted.
|
||||
* @param appendTo Output parameter to receive result.
|
||||
* Result is appended to existing contents.
|
||||
* @param pos On input: an alignment field, if desired.
|
||||
* On output: the offsets of the alignment field.
|
||||
* @return Reference to 'appendTo' parameter.
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual UnicodeString& format(double number,
|
||||
UnicodeString& appendTo,
|
||||
FieldPosition& pos) const;
|
||||
/**
|
||||
* Format a long number. Concrete subclasses must implement
|
||||
* these pure virtual methods.
|
||||
*
|
||||
* @param number The value to be formatted.
|
||||
* @param appendTo Output parameter to receive result.
|
||||
* Result is appended to existing contents.
|
||||
* @param pos On input: an alignment field, if desired.
|
||||
* On output: the offsets of the alignment field.
|
||||
* @return Reference to 'appendTo' parameter.
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual UnicodeString& format(int32_t number,
|
||||
UnicodeString& appendTo,
|
||||
FieldPosition& pos) const;
|
||||
|
||||
/**
|
||||
* Format an int64 number.
|
||||
*
|
||||
* @param number The value to be formatted.
|
||||
* @param appendTo Output parameter to receive result.
|
||||
* Result is appended to existing contents.
|
||||
* @param pos On input: an alignment field, if desired.
|
||||
* On output: the offsets of the alignment field.
|
||||
* @return Reference to 'appendTo' parameter.
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual UnicodeString& format(int64_t number,
|
||||
UnicodeString& appendTo,
|
||||
FieldPosition& pos) const;
|
||||
|
||||
virtual UnicodeString &format(double number, UnicodeString &appendTo) const;
|
||||
virtual UnicodeString &format(int32_t number, UnicodeString &appendTo) const;
|
||||
virtual UnicodeString &format(int64_t number, UnicodeString &appendTo) const;
|
||||
|
||||
virtual void parse(const UnicodeString& text, Formattable& result, ParsePosition& parsePosition) const;
|
||||
|
||||
/**
|
||||
* Sets the maximum number of digits allowed in the fraction portion of a
|
||||
* number. maximumFractionDigits must be >= minimumFractionDigits. If the
|
||||
* new value for maximumFractionDigits is less than the current value
|
||||
* of minimumFractionDigits, then minimumFractionDigits will also be set to
|
||||
* the new value.
|
||||
* @param newValue the new value to be set.
|
||||
* @see getMaximumFractionDigits
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual void setMaximumFractionDigits(int32_t newValue);
|
||||
|
||||
/**
|
||||
* Sets the minimum number of digits allowed in the fraction portion of a
|
||||
* number. minimumFractionDigits must be <= maximumFractionDigits. If the
|
||||
* new value for minimumFractionDigits exceeds the current value
|
||||
* of maximumFractionDigits, then maximumIntegerDigits will also be set to
|
||||
* the new value
|
||||
* @param newValue the new value to be set.
|
||||
* @see getMinimumFractionDigits
|
||||
* @draft ICU 3.6
|
||||
*/
|
||||
virtual void setMinimumFractionDigits(int32_t newValue);
|
||||
|
||||
/**
|
||||
* Return the class ID for this class. This is useful only for comparing to
|
||||
* a return value from getDynamicClassID(). For example:
|
||||
* <pre>
|
||||
* . Base* polymorphic_pointer = createPolymorphicObject();
|
||||
* . if (polymorphic_pointer->getDynamicClassID() ==
|
||||
* . erived::getStaticClassID()) ...
|
||||
* </pre>
|
||||
* @return The class ID for all objects of this class.
|
||||
* @stable ICU 2.0
|
||||
*/
|
||||
static UClassID U_EXPORT2 getStaticClassID(void);
|
||||
|
||||
/**
|
||||
* Returns a unique class ID POLYMORPHICALLY. Pure virtual override. This
|
||||
* method is to implement a simple version of RTTI, since not all C++
|
||||
* compilers support genuine RTTI. Polymorphic operator==() and clone()
|
||||
* methods call this method.
|
||||
*
|
||||
* @return The class ID for this object. All objects of a
|
||||
* given class have the same class ID. Objects of
|
||||
* other classes have different class IDs.
|
||||
* @stable ICU 2.0
|
||||
*/
|
||||
virtual UClassID getDynamicClassID(void) const;
|
||||
|
||||
private:
|
||||
UnicodeString &format(int32_t numDigits, UnicodeString &appendTo, wchar_t *format, ...) const;
|
||||
|
||||
UBool fCurrency;
|
||||
int32_t fLCID;
|
||||
FormatInfo *fFormatInfo;
|
||||
UBool fFractionDigitsSet;
|
||||
|
||||
};
|
||||
|
||||
inline UnicodeString &Win32NumberFormat::format(double number, UnicodeString &appendTo) const
|
||||
{
|
||||
return NumberFormat::format(number, appendTo);
|
||||
}
|
||||
|
||||
inline UnicodeString &Win32NumberFormat::format(int32_t number, UnicodeString &appendTo) const
|
||||
{
|
||||
return NumberFormat::format(number, appendTo);
|
||||
}
|
||||
|
||||
inline UnicodeString &Win32NumberFormat::format(int64_t number, UnicodeString &appendTo) const
|
||||
{
|
||||
return NumberFormat::format(number, appendTo);
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
||||
#endif // #ifdef U_WINDOWS
|
||||
|
||||
#endif // __WINNMFMT
|
Loading…
Add table
Reference in a new issue