ICU-4152 Initial check in of Windows formatting code!

X-SVN-Rev: 18963
This commit is contained in:
Eric Mader 2006-01-12 19:53:58 +00:00
parent 7a4ffed22c
commit a992570c40
15 changed files with 2354 additions and 489 deletions

View file

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

View file

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

View file

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

View file

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

View 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

View file

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

View file

@ -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 &quot;$(InputPath)&quot; ..\..\include\unicode"
CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode
"
Outputs="..\..\include\unicode\$(InputFileName)"/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCustomBuildTool"
CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode"
CommandLine="copy &quot;$(InputPath)&quot; ..\..\include\unicode
"
Outputs="..\..\include\unicode\$(InputFileName)"/>
</FileConfiguration>
</File>

View 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;

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

View 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

View 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

View 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

View 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 &lt;= 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