1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/i18n/windtfmt.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,322 @@ 1.4 +/* 1.5 +******************************************************************************** 1.6 +* Copyright (C) 2005-2013, International Business Machines 1.7 +* Corporation and others. All Rights Reserved. 1.8 +******************************************************************************** 1.9 +* 1.10 +* File WINDTFMT.CPP 1.11 +* 1.12 +******************************************************************************** 1.13 +*/ 1.14 + 1.15 +#include "unicode/utypes.h" 1.16 + 1.17 +#if U_PLATFORM_HAS_WIN32_API 1.18 + 1.19 +#if !UCONFIG_NO_FORMATTING 1.20 + 1.21 +#include "unicode/ures.h" 1.22 +#include "unicode/format.h" 1.23 +#include "unicode/fmtable.h" 1.24 +#include "unicode/datefmt.h" 1.25 +#include "unicode/msgfmt.h" 1.26 +#include "unicode/calendar.h" 1.27 +#include "unicode/gregocal.h" 1.28 +#include "unicode/locid.h" 1.29 +#include "unicode/unistr.h" 1.30 +#include "unicode/ustring.h" 1.31 +#include "unicode/timezone.h" 1.32 +#include "unicode/utmscale.h" 1.33 + 1.34 +#include "cmemory.h" 1.35 +#include "uresimp.h" 1.36 +#include "windtfmt.h" 1.37 +#include "wintzimpl.h" 1.38 + 1.39 +# define WIN32_LEAN_AND_MEAN 1.40 +# define VC_EXTRALEAN 1.41 +# define NOUSER 1.42 +# define NOSERVICE 1.43 +# define NOIME 1.44 +# define NOMCX 1.45 +#include <windows.h> 1.46 + 1.47 +U_NAMESPACE_BEGIN 1.48 + 1.49 +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Win32DateFormat) 1.50 + 1.51 +#define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) 1.52 + 1.53 +#define NEW_ARRAY(type,count) (type *) uprv_malloc((count) * sizeof(type)) 1.54 +#define DELETE_ARRAY(array) uprv_free((void *) (array)) 1.55 + 1.56 +#define STACK_BUFFER_SIZE 64 1.57 + 1.58 +UnicodeString* Win32DateFormat::getTimeDateFormat(const Calendar *cal, const Locale *locale, UErrorCode &status) const 1.59 +{ 1.60 + UnicodeString *result = NULL; 1.61 + const char *type = cal->getType(); 1.62 + const char *base = locale->getBaseName(); 1.63 + UResourceBundle *topBundle = ures_open((char *) 0, base, &status); 1.64 + UResourceBundle *calBundle = ures_getByKey(topBundle, "calendar", NULL, &status); 1.65 + UResourceBundle *typBundle = ures_getByKeyWithFallback(calBundle, type, NULL, &status); 1.66 + UResourceBundle *patBundle = ures_getByKeyWithFallback(typBundle, "DateTimePatterns", NULL, &status); 1.67 + 1.68 + if (status == U_MISSING_RESOURCE_ERROR) { 1.69 + status = U_ZERO_ERROR; 1.70 + typBundle = ures_getByKeyWithFallback(calBundle, "gregorian", typBundle, &status); 1.71 + patBundle = ures_getByKeyWithFallback(typBundle, "DateTimePatterns", patBundle, &status); 1.72 + } 1.73 + 1.74 + if (U_FAILURE(status)) { 1.75 + static const UChar defaultPattern[] = {0x007B, 0x0031, 0x007D, 0x0020, 0x007B, 0x0030, 0x007D, 0x0000}; // "{1} {0}" 1.76 + return new UnicodeString(defaultPattern, ARRAY_SIZE(defaultPattern)); 1.77 + } 1.78 + 1.79 + int32_t resStrLen = 0; 1.80 + int32_t glueIndex = DateFormat::kDateTime; 1.81 + int32_t patSize = ures_getSize(patBundle); 1.82 + if (patSize >= (DateFormat::kDateTimeOffset + DateFormat::kShort + 1)) { 1.83 + // Get proper date time format 1.84 + glueIndex = (int32_t)(DateFormat::kDateTimeOffset + (fDateStyle - DateFormat::kDateOffset)); 1.85 + } 1.86 + const UChar *resStr = ures_getStringByIndex(patBundle, glueIndex, &resStrLen, &status); 1.87 + 1.88 + result = new UnicodeString(TRUE, resStr, resStrLen); 1.89 + 1.90 + ures_close(patBundle); 1.91 + ures_close(typBundle); 1.92 + ures_close(calBundle); 1.93 + ures_close(topBundle); 1.94 + 1.95 + return result; 1.96 +} 1.97 + 1.98 +// TODO: Range-check timeStyle, dateStyle 1.99 +Win32DateFormat::Win32DateFormat(DateFormat::EStyle timeStyle, DateFormat::EStyle dateStyle, const Locale &locale, UErrorCode &status) 1.100 + : DateFormat(), fDateTimeMsg(NULL), fTimeStyle(timeStyle), fDateStyle(dateStyle), fLocale(locale), fZoneID() 1.101 +{ 1.102 + if (U_SUCCESS(status)) { 1.103 + fLCID = locale.getLCID(); 1.104 + fTZI = NEW_ARRAY(TIME_ZONE_INFORMATION, 1); 1.105 + uprv_memset(fTZI, 0, sizeof(TIME_ZONE_INFORMATION)); 1.106 + adoptCalendar(Calendar::createInstance(locale, status)); 1.107 + } 1.108 +} 1.109 + 1.110 +Win32DateFormat::Win32DateFormat(const Win32DateFormat &other) 1.111 + : DateFormat(other) 1.112 +{ 1.113 + *this = other; 1.114 +} 1.115 + 1.116 +Win32DateFormat::~Win32DateFormat() 1.117 +{ 1.118 +// delete fCalendar; 1.119 + uprv_free(fTZI); 1.120 + delete fDateTimeMsg; 1.121 +} 1.122 + 1.123 +Win32DateFormat &Win32DateFormat::operator=(const Win32DateFormat &other) 1.124 +{ 1.125 + // The following handles fCalendar 1.126 + DateFormat::operator=(other); 1.127 + 1.128 +// delete fCalendar; 1.129 + 1.130 + this->fDateTimeMsg = other.fDateTimeMsg; 1.131 + this->fTimeStyle = other.fTimeStyle; 1.132 + this->fDateStyle = other.fDateStyle; 1.133 + this->fLocale = other.fLocale; 1.134 + this->fLCID = other.fLCID; 1.135 +// this->fCalendar = other.fCalendar->clone(); 1.136 + this->fZoneID = other.fZoneID; 1.137 + 1.138 + this->fTZI = NEW_ARRAY(TIME_ZONE_INFORMATION, 1); 1.139 + *this->fTZI = *other.fTZI; 1.140 + 1.141 + return *this; 1.142 +} 1.143 + 1.144 +Format *Win32DateFormat::clone(void) const 1.145 +{ 1.146 + return new Win32DateFormat(*this); 1.147 +} 1.148 + 1.149 +// TODO: Is just ignoring pos the right thing? 1.150 +UnicodeString &Win32DateFormat::format(Calendar &cal, UnicodeString &appendTo, FieldPosition &pos) const 1.151 +{ 1.152 + FILETIME ft; 1.153 + SYSTEMTIME st_gmt; 1.154 + SYSTEMTIME st_local; 1.155 + TIME_ZONE_INFORMATION tzi = *fTZI; 1.156 + UErrorCode status = U_ZERO_ERROR; 1.157 + const TimeZone &tz = cal.getTimeZone(); 1.158 + int64_t uct, uft; 1.159 + 1.160 + setTimeZoneInfo(&tzi, tz); 1.161 + 1.162 + uct = utmscale_fromInt64((int64_t) cal.getTime(status), UDTS_ICU4C_TIME, &status); 1.163 + uft = utmscale_toInt64(uct, UDTS_WINDOWS_FILE_TIME, &status); 1.164 + 1.165 + ft.dwLowDateTime = (DWORD) (uft & 0xFFFFFFFF); 1.166 + ft.dwHighDateTime = (DWORD) ((uft >> 32) & 0xFFFFFFFF); 1.167 + 1.168 + FileTimeToSystemTime(&ft, &st_gmt); 1.169 + SystemTimeToTzSpecificLocalTime(&tzi, &st_gmt, &st_local); 1.170 + 1.171 + 1.172 + if (fDateStyle != DateFormat::kNone && fTimeStyle != DateFormat::kNone) { 1.173 + UnicodeString *date = new UnicodeString(); 1.174 + UnicodeString *time = new UnicodeString(); 1.175 + UnicodeString *pattern = fDateTimeMsg; 1.176 + Formattable timeDateArray[2]; 1.177 + 1.178 + formatDate(&st_local, *date); 1.179 + formatTime(&st_local, *time); 1.180 + 1.181 + timeDateArray[0].adoptString(time); 1.182 + timeDateArray[1].adoptString(date); 1.183 + 1.184 + if (strcmp(fCalendar->getType(), cal.getType()) != 0) { 1.185 + pattern = getTimeDateFormat(&cal, &fLocale, status); 1.186 + } 1.187 + 1.188 + MessageFormat::format(*pattern, timeDateArray, 2, appendTo, status); 1.189 + } else if (fDateStyle != DateFormat::kNone) { 1.190 + formatDate(&st_local, appendTo); 1.191 + } else if (fTimeStyle != DateFormat::kNone) { 1.192 + formatTime(&st_local, appendTo); 1.193 + } 1.194 + 1.195 + return appendTo; 1.196 +} 1.197 + 1.198 +void Win32DateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition& pos) const 1.199 +{ 1.200 + pos.setErrorIndex(pos.getIndex()); 1.201 +} 1.202 + 1.203 +void Win32DateFormat::adoptCalendar(Calendar *newCalendar) 1.204 +{ 1.205 + if (fCalendar == NULL || strcmp(fCalendar->getType(), newCalendar->getType()) != 0) { 1.206 + UErrorCode status = U_ZERO_ERROR; 1.207 + 1.208 + if (fDateStyle != DateFormat::kNone && fTimeStyle != DateFormat::kNone) { 1.209 + delete fDateTimeMsg; 1.210 + fDateTimeMsg = getTimeDateFormat(newCalendar, &fLocale, status); 1.211 + } 1.212 + } 1.213 + 1.214 + delete fCalendar; 1.215 + fCalendar = newCalendar; 1.216 + 1.217 + fZoneID = setTimeZoneInfo(fTZI, fCalendar->getTimeZone()); 1.218 +} 1.219 + 1.220 +void Win32DateFormat::setCalendar(const Calendar &newCalendar) 1.221 +{ 1.222 + adoptCalendar(newCalendar.clone()); 1.223 +} 1.224 + 1.225 +void Win32DateFormat::adoptTimeZone(TimeZone *zoneToAdopt) 1.226 +{ 1.227 + fZoneID = setTimeZoneInfo(fTZI, *zoneToAdopt); 1.228 + fCalendar->adoptTimeZone(zoneToAdopt); 1.229 +} 1.230 + 1.231 +void Win32DateFormat::setTimeZone(const TimeZone& zone) 1.232 +{ 1.233 + fZoneID = setTimeZoneInfo(fTZI, zone); 1.234 + fCalendar->setTimeZone(zone); 1.235 +} 1.236 + 1.237 +static const DWORD dfFlags[] = {DATE_LONGDATE, DATE_LONGDATE, DATE_SHORTDATE, DATE_SHORTDATE}; 1.238 + 1.239 +void Win32DateFormat::formatDate(const SYSTEMTIME *st, UnicodeString &appendTo) const 1.240 +{ 1.241 + int result; 1.242 + UChar stackBuffer[STACK_BUFFER_SIZE]; 1.243 + UChar *buffer = stackBuffer; 1.244 + 1.245 + result = GetDateFormatW(fLCID, dfFlags[fDateStyle - kDateOffset], st, NULL, buffer, STACK_BUFFER_SIZE); 1.246 + 1.247 + if (result == 0) { 1.248 + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { 1.249 + int newLength = GetDateFormatW(fLCID, dfFlags[fDateStyle - kDateOffset], st, NULL, NULL, 0); 1.250 + 1.251 + buffer = NEW_ARRAY(UChar, newLength); 1.252 + GetDateFormatW(fLCID, dfFlags[fDateStyle - kDateOffset], st, NULL, buffer, newLength); 1.253 + } 1.254 + } 1.255 + 1.256 + appendTo.append(buffer, (int32_t) wcslen(buffer)); 1.257 + 1.258 + if (buffer != stackBuffer) { 1.259 + DELETE_ARRAY(buffer); 1.260 + } 1.261 +} 1.262 + 1.263 +static const DWORD tfFlags[] = {0, 0, 0, TIME_NOSECONDS}; 1.264 + 1.265 +void Win32DateFormat::formatTime(const SYSTEMTIME *st, UnicodeString &appendTo) const 1.266 +{ 1.267 + int result; 1.268 + UChar stackBuffer[STACK_BUFFER_SIZE]; 1.269 + UChar *buffer = stackBuffer; 1.270 + 1.271 + result = GetTimeFormatW(fLCID, tfFlags[fTimeStyle], st, NULL, buffer, STACK_BUFFER_SIZE); 1.272 + 1.273 + if (result == 0) { 1.274 + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { 1.275 + int newLength = GetTimeFormatW(fLCID, tfFlags[fTimeStyle], st, NULL, NULL, 0); 1.276 + 1.277 + buffer = NEW_ARRAY(UChar, newLength); 1.278 + GetDateFormatW(fLCID, tfFlags[fTimeStyle], st, NULL, buffer, newLength); 1.279 + } 1.280 + } 1.281 + 1.282 + appendTo.append(buffer, (int32_t) wcslen(buffer)); 1.283 + 1.284 + if (buffer != stackBuffer) { 1.285 + DELETE_ARRAY(buffer); 1.286 + } 1.287 +} 1.288 + 1.289 +UnicodeString Win32DateFormat::setTimeZoneInfo(TIME_ZONE_INFORMATION *tzi, const TimeZone &zone) const 1.290 +{ 1.291 + UnicodeString zoneID; 1.292 + 1.293 + zone.getID(zoneID); 1.294 + 1.295 + if (zoneID.compare(fZoneID) != 0) { 1.296 + UnicodeString icuid; 1.297 + 1.298 + zone.getID(icuid); 1.299 + if (! uprv_getWindowsTimeZoneInfo(tzi, icuid.getBuffer(), icuid.length())) { 1.300 + UBool found = FALSE; 1.301 + int32_t ec = TimeZone::countEquivalentIDs(icuid); 1.302 + 1.303 + for (int z = 0; z < ec; z += 1) { 1.304 + UnicodeString equiv = TimeZone::getEquivalentID(icuid, z); 1.305 + 1.306 + if (found = uprv_getWindowsTimeZoneInfo(tzi, equiv.getBuffer(), equiv.length())) { 1.307 + break; 1.308 + } 1.309 + } 1.310 + 1.311 + if (! found) { 1.312 + GetTimeZoneInformation(tzi); 1.313 + } 1.314 + } 1.315 + } 1.316 + 1.317 + return zoneID; 1.318 +} 1.319 + 1.320 +U_NAMESPACE_END 1.321 + 1.322 +#endif /* #if !UCONFIG_NO_FORMATTING */ 1.323 + 1.324 +#endif // U_PLATFORM_HAS_WIN32_API 1.325 +