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.

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

mercurial