]> git.saurik.com Git - apple/icu.git/blob - icuSources/i18n/windtfmt.cpp
ICU-57132.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / windtfmt.cpp
1 /*
2 ********************************************************************************
3 * Copyright (C) 2005-2016, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 ********************************************************************************
6 *
7 * File WINDTFMT.CPP
8 *
9 ********************************************************************************
10 */
11
12 #include "unicode/utypes.h"
13
14 #if U_PLATFORM_HAS_WIN32_API
15
16 #if !UCONFIG_NO_FORMATTING
17
18 #include "unicode/ures.h"
19 #include "unicode/format.h"
20 #include "unicode/fmtable.h"
21 #include "unicode/datefmt.h"
22 #include "unicode/simpleformatter.h"
23 #include "unicode/calendar.h"
24 #include "unicode/gregocal.h"
25 #include "unicode/locid.h"
26 #include "unicode/unistr.h"
27 #include "unicode/ustring.h"
28 #include "unicode/timezone.h"
29 #include "unicode/utmscale.h"
30
31 #include "cmemory.h"
32 #include "uresimp.h"
33 #include "windtfmt.h"
34 #include "wintzimpl.h"
35
36 # define WIN32_LEAN_AND_MEAN
37 # define VC_EXTRALEAN
38 # define NOUSER
39 # define NOSERVICE
40 # define NOIME
41 # define NOMCX
42 #include <windows.h>
43
44 U_NAMESPACE_BEGIN
45
46 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Win32DateFormat)
47
48 #define NEW_ARRAY(type,count) (type *) uprv_malloc((count) * sizeof(type))
49 #define DELETE_ARRAY(array) uprv_free((void *) (array))
50
51 #define STACK_BUFFER_SIZE 64
52
53 UnicodeString* Win32DateFormat::getTimeDateFormat(const Calendar *cal, const Locale *locale, UErrorCode &status) const
54 {
55 UnicodeString *result = NULL;
56 const char *type = cal->getType();
57 const char *base = locale->getBaseName();
58 UResourceBundle *topBundle = ures_open((char *) 0, base, &status);
59 UResourceBundle *calBundle = ures_getByKey(topBundle, "calendar", NULL, &status);
60 UResourceBundle *typBundle = ures_getByKeyWithFallback(calBundle, type, NULL, &status);
61 UResourceBundle *patBundle = ures_getByKeyWithFallback(typBundle, "DateTimePatterns", NULL, &status);
62
63 if (status == U_MISSING_RESOURCE_ERROR) {
64 status = U_ZERO_ERROR;
65 typBundle = ures_getByKeyWithFallback(calBundle, "gregorian", typBundle, &status);
66 patBundle = ures_getByKeyWithFallback(typBundle, "DateTimePatterns", patBundle, &status);
67 }
68
69 if (U_FAILURE(status)) {
70 static const UChar defaultPattern[] = {0x007B, 0x0031, 0x007D, 0x0020, 0x007B, 0x0030, 0x007D, 0x0000}; // "{1} {0}"
71 return new UnicodeString(defaultPattern, UPRV_LENGTHOF(defaultPattern));
72 }
73
74 int32_t resStrLen = 0;
75 int32_t glueIndex = DateFormat::kDateTime;
76 int32_t patSize = ures_getSize(patBundle);
77 if (patSize >= (DateFormat::kDateTimeOffset + DateFormat::kShort + 1)) {
78 // Get proper date time format
79 glueIndex = (int32_t)(DateFormat::kDateTimeOffset + (fDateStyle - DateFormat::kDateOffset));
80 }
81 const UChar *resStr = ures_getStringByIndex(patBundle, glueIndex, &resStrLen, &status);
82
83 result = new UnicodeString(TRUE, resStr, resStrLen);
84
85 ures_close(patBundle);
86 ures_close(typBundle);
87 ures_close(calBundle);
88 ures_close(topBundle);
89
90 return result;
91 }
92
93 // TODO: Range-check timeStyle, dateStyle
94 Win32DateFormat::Win32DateFormat(DateFormat::EStyle timeStyle, DateFormat::EStyle dateStyle, const Locale &locale, UErrorCode &status)
95 : DateFormat(), fDateTimeMsg(NULL), fTimeStyle(timeStyle), fDateStyle(dateStyle), fLocale(locale), fZoneID()
96 {
97 if (U_SUCCESS(status)) {
98 fLCID = locale.getLCID();
99 fTZI = NEW_ARRAY(TIME_ZONE_INFORMATION, 1);
100 uprv_memset(fTZI, 0, sizeof(TIME_ZONE_INFORMATION));
101 adoptCalendar(Calendar::createInstance(locale, status));
102 }
103 }
104
105 Win32DateFormat::Win32DateFormat(const Win32DateFormat &other)
106 : DateFormat(other)
107 {
108 *this = other;
109 }
110
111 Win32DateFormat::~Win32DateFormat()
112 {
113 // delete fCalendar;
114 uprv_free(fTZI);
115 delete fDateTimeMsg;
116 }
117
118 Win32DateFormat &Win32DateFormat::operator=(const Win32DateFormat &other)
119 {
120 // The following handles fCalendar
121 DateFormat::operator=(other);
122
123 // delete fCalendar;
124
125 this->fDateTimeMsg = other.fDateTimeMsg == NULL ? NULL : new UnicodeString(*other.fDateTimeMsg);
126 this->fTimeStyle = other.fTimeStyle;
127 this->fDateStyle = other.fDateStyle;
128 this->fLocale = other.fLocale;
129 this->fLCID = other.fLCID;
130 // this->fCalendar = other.fCalendar->clone();
131 this->fZoneID = other.fZoneID;
132
133 this->fTZI = NEW_ARRAY(TIME_ZONE_INFORMATION, 1);
134 *this->fTZI = *other.fTZI;
135
136 return *this;
137 }
138
139 Format *Win32DateFormat::clone(void) const
140 {
141 return new Win32DateFormat(*this);
142 }
143
144 // TODO: Is just ignoring pos the right thing?
145 UnicodeString &Win32DateFormat::format(Calendar &cal, UnicodeString &appendTo, FieldPosition &pos) const
146 {
147 FILETIME ft;
148 SYSTEMTIME st_gmt;
149 SYSTEMTIME st_local;
150 TIME_ZONE_INFORMATION tzi = *fTZI;
151 UErrorCode status = U_ZERO_ERROR;
152 const TimeZone &tz = cal.getTimeZone();
153 int64_t uct, uft;
154
155 setTimeZoneInfo(&tzi, tz);
156
157 uct = utmscale_fromInt64((int64_t) cal.getTime(status), UDTS_ICU4C_TIME, &status);
158 uft = utmscale_toInt64(uct, UDTS_WINDOWS_FILE_TIME, &status);
159
160 ft.dwLowDateTime = (DWORD) (uft & 0xFFFFFFFF);
161 ft.dwHighDateTime = (DWORD) ((uft >> 32) & 0xFFFFFFFF);
162
163 FileTimeToSystemTime(&ft, &st_gmt);
164 SystemTimeToTzSpecificLocalTime(&tzi, &st_gmt, &st_local);
165
166
167 if (fDateStyle != DateFormat::kNone && fTimeStyle != DateFormat::kNone) {
168 UnicodeString date;
169 UnicodeString time;
170 UnicodeString *pattern = fDateTimeMsg;
171
172 formatDate(&st_local, date);
173 formatTime(&st_local, time);
174
175 if (strcmp(fCalendar->getType(), cal.getType()) != 0) {
176 pattern = getTimeDateFormat(&cal, &fLocale, status);
177 }
178
179 SimpleFormatter(*pattern, 2, 2, status).format(time, date, appendTo, status);
180 } else if (fDateStyle != DateFormat::kNone) {
181 formatDate(&st_local, appendTo);
182 } else if (fTimeStyle != DateFormat::kNone) {
183 formatTime(&st_local, appendTo);
184 }
185
186 return appendTo;
187 }
188
189 void Win32DateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition& pos) const
190 {
191 pos.setErrorIndex(pos.getIndex());
192 }
193
194 void Win32DateFormat::adoptCalendar(Calendar *newCalendar)
195 {
196 if (fCalendar == NULL || strcmp(fCalendar->getType(), newCalendar->getType()) != 0) {
197 UErrorCode status = U_ZERO_ERROR;
198
199 if (fDateStyle != DateFormat::kNone && fTimeStyle != DateFormat::kNone) {
200 delete fDateTimeMsg;
201 fDateTimeMsg = getTimeDateFormat(newCalendar, &fLocale, status);
202 }
203 }
204
205 delete fCalendar;
206 fCalendar = newCalendar;
207
208 fZoneID = setTimeZoneInfo(fTZI, fCalendar->getTimeZone());
209 }
210
211 void Win32DateFormat::setCalendar(const Calendar &newCalendar)
212 {
213 adoptCalendar(newCalendar.clone());
214 }
215
216 void Win32DateFormat::adoptTimeZone(TimeZone *zoneToAdopt)
217 {
218 fZoneID = setTimeZoneInfo(fTZI, *zoneToAdopt);
219 fCalendar->adoptTimeZone(zoneToAdopt);
220 }
221
222 void Win32DateFormat::setTimeZone(const TimeZone& zone)
223 {
224 fZoneID = setTimeZoneInfo(fTZI, zone);
225 fCalendar->setTimeZone(zone);
226 }
227
228 static const DWORD dfFlags[] = {DATE_LONGDATE, DATE_LONGDATE, DATE_SHORTDATE, DATE_SHORTDATE};
229
230 void Win32DateFormat::formatDate(const SYSTEMTIME *st, UnicodeString &appendTo) const
231 {
232 int result;
233 UChar stackBuffer[STACK_BUFFER_SIZE];
234 UChar *buffer = stackBuffer;
235
236 result = GetDateFormatW(fLCID, dfFlags[fDateStyle - kDateOffset], st, NULL, buffer, STACK_BUFFER_SIZE);
237
238 if (result == 0) {
239 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
240 int newLength = GetDateFormatW(fLCID, dfFlags[fDateStyle - kDateOffset], st, NULL, NULL, 0);
241
242 buffer = NEW_ARRAY(UChar, newLength);
243 GetDateFormatW(fLCID, dfFlags[fDateStyle - kDateOffset], st, NULL, buffer, newLength);
244 }
245 }
246
247 appendTo.append(buffer, (int32_t) wcslen(buffer));
248
249 if (buffer != stackBuffer) {
250 DELETE_ARRAY(buffer);
251 }
252 }
253
254 static const DWORD tfFlags[] = {0, 0, 0, TIME_NOSECONDS};
255
256 void Win32DateFormat::formatTime(const SYSTEMTIME *st, UnicodeString &appendTo) const
257 {
258 int result;
259 UChar stackBuffer[STACK_BUFFER_SIZE];
260 UChar *buffer = stackBuffer;
261
262 result = GetTimeFormatW(fLCID, tfFlags[fTimeStyle], st, NULL, buffer, STACK_BUFFER_SIZE);
263
264 if (result == 0) {
265 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
266 int newLength = GetTimeFormatW(fLCID, tfFlags[fTimeStyle], st, NULL, NULL, 0);
267
268 buffer = NEW_ARRAY(UChar, newLength);
269 GetDateFormatW(fLCID, tfFlags[fTimeStyle], st, NULL, buffer, newLength);
270 }
271 }
272
273 appendTo.append(buffer, (int32_t) wcslen(buffer));
274
275 if (buffer != stackBuffer) {
276 DELETE_ARRAY(buffer);
277 }
278 }
279
280 UnicodeString Win32DateFormat::setTimeZoneInfo(TIME_ZONE_INFORMATION *tzi, const TimeZone &zone) const
281 {
282 UnicodeString zoneID;
283
284 zone.getID(zoneID);
285
286 if (zoneID.compare(fZoneID) != 0) {
287 UnicodeString icuid;
288
289 zone.getID(icuid);
290 if (! uprv_getWindowsTimeZoneInfo(tzi, icuid.getBuffer(), icuid.length())) {
291 UBool found = FALSE;
292 int32_t ec = TimeZone::countEquivalentIDs(icuid);
293
294 for (int z = 0; z < ec; z += 1) {
295 UnicodeString equiv = TimeZone::getEquivalentID(icuid, z);
296
297 if (found = uprv_getWindowsTimeZoneInfo(tzi, equiv.getBuffer(), equiv.length())) {
298 break;
299 }
300 }
301
302 if (! found) {
303 GetTimeZoneInformation(tzi);
304 }
305 }
306 }
307
308 return zoneID;
309 }
310
311 U_NAMESPACE_END
312
313 #endif /* #if !UCONFIG_NO_FORMATTING */
314
315 #endif // U_PLATFORM_HAS_WIN32_API
316