intl/locale/src/unix/nsDateTimeFormatUnix.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include <locale.h>
michael@0 7 #include "plstr.h"
michael@0 8 #include "nsIServiceManager.h"
michael@0 9 #include "nsDateTimeFormatUnix.h"
michael@0 10 #include "nsIComponentManager.h"
michael@0 11 #include "nsILocaleService.h"
michael@0 12 #include "nsIPlatformCharset.h"
michael@0 13 #include "nsPosixLocale.h"
michael@0 14 #include "nsCRT.h"
michael@0 15 #include "nsReadableUtils.h"
michael@0 16 #include "nsUnicharUtils.h"
michael@0 17
michael@0 18 NS_IMPL_ISUPPORTS(nsDateTimeFormatUnix, nsIDateTimeFormat)
michael@0 19
michael@0 20 // init this interface to a specified locale
michael@0 21 nsresult nsDateTimeFormatUnix::Initialize(nsILocale* locale)
michael@0 22 {
michael@0 23 nsAutoString localeStr;
michael@0 24 NS_NAMED_LITERAL_STRING(aCategory, "NSILOCALE_TIME##PLATFORM");
michael@0 25 nsresult res = NS_OK;
michael@0 26
michael@0 27 // use cached info if match with stored locale
michael@0 28 if (!locale) {
michael@0 29 if (!mLocale.IsEmpty() &&
michael@0 30 mLocale.Equals(mAppLocale, nsCaseInsensitiveStringComparator())) {
michael@0 31 return NS_OK;
michael@0 32 }
michael@0 33 }
michael@0 34 else {
michael@0 35 res = locale->GetCategory(aCategory, localeStr);
michael@0 36 if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) {
michael@0 37 if (!mLocale.IsEmpty() &&
michael@0 38 mLocale.Equals(localeStr,
michael@0 39 nsCaseInsensitiveStringComparator())) {
michael@0 40 return NS_OK;
michael@0 41 }
michael@0 42 }
michael@0 43 }
michael@0 44
michael@0 45 mCharset.AssignLiteral("ISO-8859-1");
michael@0 46 mPlatformLocale.Assign("en_US");
michael@0 47
michael@0 48 // get locale name string, use app default if no locale specified
michael@0 49 if (!locale) {
michael@0 50 nsCOMPtr<nsILocaleService> localeService =
michael@0 51 do_GetService(NS_LOCALESERVICE_CONTRACTID, &res);
michael@0 52 if (NS_SUCCEEDED(res)) {
michael@0 53 nsCOMPtr<nsILocale> appLocale;
michael@0 54 res = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
michael@0 55 if (NS_SUCCEEDED(res)) {
michael@0 56 res = appLocale->GetCategory(aCategory, localeStr);
michael@0 57 if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) {
michael@0 58 NS_ASSERTION(NS_SUCCEEDED(res), "failed to get app locale info");
michael@0 59 mAppLocale = localeStr; // cache app locale name
michael@0 60 }
michael@0 61 }
michael@0 62 }
michael@0 63 }
michael@0 64 else {
michael@0 65 res = locale->GetCategory(aCategory, localeStr);
michael@0 66 NS_ASSERTION(NS_SUCCEEDED(res), "failed to get locale info");
michael@0 67 }
michael@0 68
michael@0 69 if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) {
michael@0 70 mLocale = localeStr; // cache locale name
michael@0 71
michael@0 72 nsPosixLocale::GetPlatformLocale(mLocale, mPlatformLocale);
michael@0 73
michael@0 74 nsCOMPtr <nsIPlatformCharset> platformCharset = do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &res);
michael@0 75 if (NS_SUCCEEDED(res)) {
michael@0 76 nsAutoCString mappedCharset;
michael@0 77 res = platformCharset->GetDefaultCharsetForLocale(mLocale, mappedCharset);
michael@0 78 if (NS_SUCCEEDED(res)) {
michael@0 79 mCharset = mappedCharset;
michael@0 80 }
michael@0 81 }
michael@0 82 }
michael@0 83
michael@0 84 // Initialize unicode decoder
michael@0 85 nsCOMPtr <nsICharsetConverterManager> charsetConverterManager;
michael@0 86 charsetConverterManager = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &res);
michael@0 87 if (NS_SUCCEEDED(res)) {
michael@0 88 res = charsetConverterManager->GetUnicodeDecoder(mCharset.get(), getter_AddRefs(mDecoder));
michael@0 89 }
michael@0 90
michael@0 91 LocalePreferred24hour();
michael@0 92
michael@0 93 return res;
michael@0 94 }
michael@0 95
michael@0 96 void nsDateTimeFormatUnix::LocalePreferred24hour()
michael@0 97 {
michael@0 98 char str[100];
michael@0 99 time_t tt;
michael@0 100 struct tm *tmc;
michael@0 101 int i;
michael@0 102
michael@0 103 tt = time(nullptr);
michael@0 104 tmc = localtime(&tt);
michael@0 105
michael@0 106 tmc->tm_hour=22; // put the test sample hour to 22:00 which is 10PM
michael@0 107 tmc->tm_min=0; // set the min & sec other number than '2'
michael@0 108 tmc->tm_sec=0;
michael@0 109
michael@0 110 char *temp = setlocale(LC_TIME, mPlatformLocale.get());
michael@0 111 strftime(str, (size_t)99, "%X", (struct tm *)tmc);
michael@0 112
michael@0 113 (void) setlocale(LC_TIME, temp);
michael@0 114
michael@0 115 mLocalePreferred24hour = false;
michael@0 116 for (i=0; str[i]; i++) {
michael@0 117 if (str[i] == '2') { // if there is any '2', that locale use 0-23 time format
michael@0 118 mLocalePreferred24hour = true;
michael@0 119 break;
michael@0 120 }
michael@0 121 }
michael@0 122
michael@0 123 mLocaleAMPMfirst = true;
michael@0 124 if (mLocalePreferred24hour == false) {
michael@0 125 if (str[0] && str[0] == '1') { // if the first character is '1' of 10:00,
michael@0 126 // AMPM string is located after 10:00
michael@0 127 mLocaleAMPMfirst = false;
michael@0 128 }
michael@0 129 }
michael@0 130 }
michael@0 131
michael@0 132 nsresult nsDateTimeFormatUnix::FormatTime(nsILocale* locale,
michael@0 133 const nsDateFormatSelector dateFormatSelector,
michael@0 134 const nsTimeFormatSelector timeFormatSelector,
michael@0 135 const time_t timetTime,
michael@0 136 nsAString& stringOut)
michael@0 137 {
michael@0 138 struct tm tmTime;
michael@0 139 memcpy(&tmTime, localtime(&timetTime), sizeof(struct tm));
michael@0 140 return FormatTMTime(locale, dateFormatSelector, timeFormatSelector, &tmTime, stringOut);
michael@0 141 }
michael@0 142
michael@0 143 // performs a locale sensitive date formatting operation on the struct tm parameter
michael@0 144 nsresult nsDateTimeFormatUnix::FormatTMTime(nsILocale* locale,
michael@0 145 const nsDateFormatSelector dateFormatSelector,
michael@0 146 const nsTimeFormatSelector timeFormatSelector,
michael@0 147 const struct tm* tmTime,
michael@0 148 nsAString& stringOut)
michael@0 149 {
michael@0 150 #define NSDATETIME_FORMAT_BUFFER_LEN 80
michael@0 151 char strOut[NSDATETIME_FORMAT_BUFFER_LEN*2]; // buffer for date and time
michael@0 152 char fmtD[NSDATETIME_FORMAT_BUFFER_LEN], fmtT[NSDATETIME_FORMAT_BUFFER_LEN];
michael@0 153 nsresult rv;
michael@0 154
michael@0 155
michael@0 156 // set up locale data
michael@0 157 (void) Initialize(locale);
michael@0 158 NS_ENSURE_TRUE(mDecoder, NS_ERROR_NOT_INITIALIZED);
michael@0 159
michael@0 160 // set date format
michael@0 161 if (dateFormatSelector == kDateFormatLong && timeFormatSelector == kTimeFormatSeconds) {
michael@0 162 PL_strncpy(fmtD, "%c", NSDATETIME_FORMAT_BUFFER_LEN);
michael@0 163 PL_strncpy(fmtT, "", NSDATETIME_FORMAT_BUFFER_LEN);
michael@0 164 } else {
michael@0 165
michael@0 166 switch (dateFormatSelector) {
michael@0 167 case kDateFormatNone:
michael@0 168 PL_strncpy(fmtD, "", NSDATETIME_FORMAT_BUFFER_LEN);
michael@0 169 break;
michael@0 170 case kDateFormatLong:
michael@0 171 case kDateFormatShort:
michael@0 172 PL_strncpy(fmtD, "%x", NSDATETIME_FORMAT_BUFFER_LEN);
michael@0 173 break;
michael@0 174 case kDateFormatYearMonth:
michael@0 175 PL_strncpy(fmtD, "%Y/%m", NSDATETIME_FORMAT_BUFFER_LEN);
michael@0 176 break;
michael@0 177 case kDateFormatWeekday:
michael@0 178 PL_strncpy(fmtD, "%a", NSDATETIME_FORMAT_BUFFER_LEN);
michael@0 179 break;
michael@0 180 default:
michael@0 181 PL_strncpy(fmtD, "", NSDATETIME_FORMAT_BUFFER_LEN);
michael@0 182 }
michael@0 183
michael@0 184 // set time format
michael@0 185 switch (timeFormatSelector) {
michael@0 186 case kTimeFormatNone:
michael@0 187 PL_strncpy(fmtT, "", NSDATETIME_FORMAT_BUFFER_LEN);
michael@0 188 break;
michael@0 189 case kTimeFormatSeconds:
michael@0 190 PL_strncpy(fmtT, "%X", NSDATETIME_FORMAT_BUFFER_LEN);
michael@0 191 break;
michael@0 192 case kTimeFormatNoSeconds:
michael@0 193 PL_strncpy(fmtT,
michael@0 194 mLocalePreferred24hour ? "%H:%M" : mLocaleAMPMfirst ? "%p %I:%M" : "%I:%M %p",
michael@0 195 NSDATETIME_FORMAT_BUFFER_LEN);
michael@0 196 break;
michael@0 197 case kTimeFormatSecondsForce24Hour:
michael@0 198 PL_strncpy(fmtT, "%H:%M:%S", NSDATETIME_FORMAT_BUFFER_LEN);
michael@0 199 break;
michael@0 200 case kTimeFormatNoSecondsForce24Hour:
michael@0 201 PL_strncpy(fmtT, "%H:%M", NSDATETIME_FORMAT_BUFFER_LEN);
michael@0 202 break;
michael@0 203 default:
michael@0 204 PL_strncpy(fmtT, "", NSDATETIME_FORMAT_BUFFER_LEN);
michael@0 205 }
michael@0 206 }
michael@0 207
michael@0 208 // generate data/time string
michael@0 209 char *old_locale = setlocale(LC_TIME, nullptr);
michael@0 210 (void) setlocale(LC_TIME, mPlatformLocale.get());
michael@0 211 if (strlen(fmtD) && strlen(fmtT)) {
michael@0 212 PL_strncat(fmtD, " ", NSDATETIME_FORMAT_BUFFER_LEN);
michael@0 213 PL_strncat(fmtD, fmtT, NSDATETIME_FORMAT_BUFFER_LEN);
michael@0 214 strftime(strOut, NSDATETIME_FORMAT_BUFFER_LEN, fmtD, tmTime);
michael@0 215 }
michael@0 216 else if (strlen(fmtD) && !strlen(fmtT)) {
michael@0 217 strftime(strOut, NSDATETIME_FORMAT_BUFFER_LEN, fmtD, tmTime);
michael@0 218 }
michael@0 219 else if (!strlen(fmtD) && strlen(fmtT)) {
michael@0 220 strftime(strOut, NSDATETIME_FORMAT_BUFFER_LEN, fmtT, tmTime);
michael@0 221 }
michael@0 222 else {
michael@0 223 PL_strncpy(strOut, "", NSDATETIME_FORMAT_BUFFER_LEN);
michael@0 224 }
michael@0 225 (void) setlocale(LC_TIME, old_locale);
michael@0 226
michael@0 227 // convert result to unicode
michael@0 228 int32_t srcLength = (int32_t) strlen(strOut);
michael@0 229 int32_t unicharLength = NSDATETIME_FORMAT_BUFFER_LEN*2;
michael@0 230 char16_t unichars[NSDATETIME_FORMAT_BUFFER_LEN*2]; // buffer for date and time
michael@0 231
michael@0 232 rv = mDecoder->Convert(strOut, &srcLength, unichars, &unicharLength);
michael@0 233 if (NS_FAILED(rv))
michael@0 234 return rv;
michael@0 235 stringOut.Assign(unichars, unicharLength);
michael@0 236
michael@0 237 return rv;
michael@0 238 }
michael@0 239
michael@0 240 // performs a locale sensitive date formatting operation on the PRTime parameter
michael@0 241 nsresult nsDateTimeFormatUnix::FormatPRTime(nsILocale* locale,
michael@0 242 const nsDateFormatSelector dateFormatSelector,
michael@0 243 const nsTimeFormatSelector timeFormatSelector,
michael@0 244 const PRTime prTime,
michael@0 245 nsAString& stringOut)
michael@0 246 {
michael@0 247 PRExplodedTime explodedTime;
michael@0 248 PR_ExplodeTime(prTime, PR_LocalTimeParameters, &explodedTime);
michael@0 249
michael@0 250 return FormatPRExplodedTime(locale, dateFormatSelector, timeFormatSelector, &explodedTime, stringOut);
michael@0 251 }
michael@0 252
michael@0 253 // performs a locale sensitive date formatting operation on the PRExplodedTime parameter
michael@0 254 nsresult nsDateTimeFormatUnix::FormatPRExplodedTime(nsILocale* locale,
michael@0 255 const nsDateFormatSelector dateFormatSelector,
michael@0 256 const nsTimeFormatSelector timeFormatSelector,
michael@0 257 const PRExplodedTime* explodedTime,
michael@0 258 nsAString& stringOut)
michael@0 259 {
michael@0 260 struct tm tmTime;
michael@0 261 /* be safe and set all members of struct tm to zero
michael@0 262 *
michael@0 263 * there are other fields in the tm struct that we aren't setting
michael@0 264 * (tm_isdst, tm_gmtoff, tm_zone, should we set these?) and since
michael@0 265 * tmTime is on the stack, it may be filled with garbage, but
michael@0 266 * the garbage may vary. (this may explain why some saw bug #10412, and
michael@0 267 * others did not.
michael@0 268 *
michael@0 269 * when tmTime is passed to strftime() with garbage bad things may happen.
michael@0 270 * see bug #10412
michael@0 271 */
michael@0 272 memset( &tmTime, 0, sizeof(tmTime) );
michael@0 273
michael@0 274 tmTime.tm_yday = explodedTime->tm_yday;
michael@0 275 tmTime.tm_wday = explodedTime->tm_wday;
michael@0 276 tmTime.tm_year = explodedTime->tm_year;
michael@0 277 tmTime.tm_year -= 1900;
michael@0 278 tmTime.tm_mon = explodedTime->tm_month;
michael@0 279 tmTime.tm_mday = explodedTime->tm_mday;
michael@0 280 tmTime.tm_hour = explodedTime->tm_hour;
michael@0 281 tmTime.tm_min = explodedTime->tm_min;
michael@0 282 tmTime.tm_sec = explodedTime->tm_sec;
michael@0 283
michael@0 284 return FormatTMTime(locale, dateFormatSelector, timeFormatSelector, &tmTime, stringOut);
michael@0 285 }
michael@0 286

mercurial