tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Time.cpp (6656B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 /* PR time code. */
      8 
      9 #include "vm/Time.h"
     10 
     11 #ifdef SOLARIS
     12 #  define _REENTRANT 1
     13 #endif
     14 #include <string.h>
     15 #include <time.h>
     16 
     17 #include "jstypes.h"
     18 
     19 #ifdef XP_WIN
     20 #  include "util/WindowsWrapper.h"
     21 #  include <crtdbg.h> /* for _CrtSetReportMode */
     22 #  include <stdlib.h> /* for _set_invalid_parameter_handler */
     23 #endif
     24 
     25 #ifdef XP_UNIX
     26 
     27 #  ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */
     28 extern int gettimeofday(struct timeval* tv);
     29 #  endif
     30 
     31 #  include <sys/time.h>
     32 
     33 #endif /* XP_UNIX */
     34 
     35 #if defined(XP_UNIX)
     36 int64_t PRMJ_Now() {
     37  struct timeval tv;
     38 
     39 #  ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */
     40  gettimeofday(&tv);
     41 #  else
     42  gettimeofday(&tv, 0);
     43 #  endif /* _SVID_GETTOD */
     44 
     45  return int64_t(tv.tv_sec) * PRMJ_USEC_PER_SEC + int64_t(tv.tv_usec);
     46 }
     47 
     48 #else
     49 
     50 // Returns the number of microseconds since the Unix epoch.
     51 static int64_t FileTimeToUnixMicroseconds(const FILETIME& ft) {
     52  // Get the time in 100ns intervals.
     53  int64_t t = (int64_t(ft.dwHighDateTime) << 32) | int64_t(ft.dwLowDateTime);
     54 
     55  // The Windows epoch is around 1600. The Unix epoch is around 1970.
     56  // Subtract the difference.
     57  static const int64_t TimeToEpochIn100ns = 0x19DB1DED53E8000;
     58  t -= TimeToEpochIn100ns;
     59 
     60  // Divide by 10 to convert to microseconds.
     61  return t / 10;
     62 }
     63 
     64 int64_t PRMJ_Now() {
     65  FILETIME ft;
     66  GetSystemTimePreciseAsFileTime(&ft);
     67  return FileTimeToUnixMicroseconds(ft);
     68 }
     69 #endif
     70 
     71 #if !JS_HAS_INTL_API
     72 #  ifdef XP_WIN
     73 static void PRMJ_InvalidParameterHandler(const wchar_t* expression,
     74                                         const wchar_t* function,
     75                                         const wchar_t* file, unsigned int line,
     76                                         uintptr_t pReserved) {
     77  /* empty */
     78 }
     79 #  endif
     80 
     81 /* Format a time value into a buffer. Same semantics as strftime() */
     82 size_t PRMJ_FormatTime(char* buf, size_t buflen, const char* fmt,
     83                       const PRMJTime* prtm, int timeZoneYear,
     84                       int offsetInSeconds) {
     85  size_t result = 0;
     86 #  if defined(XP_UNIX) || defined(XP_WIN)
     87  struct tm a;
     88 #    ifdef XP_WIN
     89  _invalid_parameter_handler oldHandler;
     90 #      ifndef __MINGW32__
     91  int oldReportMode;
     92 #      endif  // __MINGW32__
     93 #    endif    // XP_WIN
     94 
     95  memset(&a, 0, sizeof(struct tm));
     96 
     97  a.tm_sec = prtm->tm_sec;
     98  a.tm_min = prtm->tm_min;
     99  a.tm_hour = prtm->tm_hour;
    100  a.tm_mday = prtm->tm_mday;
    101  a.tm_mon = prtm->tm_mon;
    102  a.tm_wday = prtm->tm_wday;
    103 
    104  /*
    105   * On systems where |struct tm| has members tm_gmtoff and tm_zone, we
    106   * must fill in those values, or else strftime will return wrong results
    107   * (e.g., bug 511726, bug 554338).
    108   */
    109 #    if defined(HAVE_LOCALTIME_R) && defined(HAVE_TM_ZONE_TM_GMTOFF)
    110  char emptyTimeZoneId[] = "";
    111  {
    112    /*
    113     * Fill out |td| to the time represented by |prtm|, leaving the
    114     * timezone fields zeroed out. localtime_r will then fill in the
    115     * timezone fields for that local time according to the system's
    116     * timezone parameters. Use |timeZoneYear| for the year to ensure the
    117     * time zone name matches the time zone offset used by the caller.
    118     */
    119    struct tm td;
    120    memset(&td, 0, sizeof(td));
    121    td.tm_sec = prtm->tm_sec;
    122    td.tm_min = prtm->tm_min;
    123    td.tm_hour = prtm->tm_hour;
    124    td.tm_mday = prtm->tm_mday;
    125    td.tm_mon = prtm->tm_mon;
    126    td.tm_wday = prtm->tm_wday;
    127    td.tm_year = timeZoneYear - 1900;
    128    td.tm_yday = prtm->tm_yday;
    129    td.tm_isdst = prtm->tm_isdst;
    130 
    131    time_t t = mktime(&td);
    132 
    133    // If either mktime or localtime_r failed, fill in the fallback time
    134    // zone offset |offsetInSeconds| and set the time zone identifier to
    135    // the empty string.
    136    if (t != static_cast<time_t>(-1) && localtime_r(&t, &td)) {
    137      a.tm_gmtoff = td.tm_gmtoff;
    138      a.tm_zone = td.tm_zone;
    139    } else {
    140      a.tm_gmtoff = offsetInSeconds;
    141      a.tm_zone = emptyTimeZoneId;
    142    }
    143  }
    144 #    endif
    145 
    146  /*
    147   * Years before 1900 and after 9999 cause strftime() to abort on Windows.
    148   * To avoid that we replace it with FAKE_YEAR_BASE + year % 100 and then
    149   * replace matching substrings in the strftime() result with the real year.
    150   * Note that FAKE_YEAR_BASE should be a multiple of 100 to make 2-digit
    151   * year formats (%y) work correctly (since we won't find the fake year
    152   * in that case).
    153   */
    154  constexpr int FAKE_YEAR_BASE = 9900;
    155  int fake_tm_year = 0;
    156  if (prtm->tm_year < 1900 || prtm->tm_year > 9999) {
    157    fake_tm_year = FAKE_YEAR_BASE + prtm->tm_year % 100;
    158    a.tm_year = fake_tm_year - 1900;
    159  } else {
    160    a.tm_year = prtm->tm_year - 1900;
    161  }
    162  a.tm_yday = prtm->tm_yday;
    163  a.tm_isdst = prtm->tm_isdst;
    164 
    165  /*
    166   * Even with the above, SunOS 4 seems to detonate if tm_zone and tm_gmtoff
    167   * are null.  This doesn't quite work, though - the timezone is off by
    168   * tzoff + dst.  (And mktime seems to return -1 for the exact dst
    169   * changeover time.)
    170   */
    171 
    172 #    ifdef XP_WIN
    173  oldHandler = _set_invalid_parameter_handler(PRMJ_InvalidParameterHandler);
    174 #      ifndef __MINGW32__
    175  /*
    176   * MinGW doesn't have _CrtSetReportMode and defines it to be a no-op.
    177   * We ifdef it off to avoid warnings about unused variables
    178   */
    179  oldReportMode = _CrtSetReportMode(_CRT_ASSERT, 0);
    180 #      endif  // __MINGW32__
    181 #    endif    // XP_WIN
    182 
    183  result = strftime(buf, buflen, fmt, &a);
    184 
    185 #    ifdef XP_WIN
    186  _set_invalid_parameter_handler(oldHandler);
    187 #      ifndef __MINGW32__
    188  _CrtSetReportMode(_CRT_ASSERT, oldReportMode);
    189 #      endif  // __MINGW32__
    190 #    endif    // XP_WIN
    191 
    192  if (fake_tm_year && result) {
    193    char real_year[16];
    194    char fake_year[16];
    195    size_t real_year_len;
    196    size_t fake_year_len;
    197    char* p;
    198 
    199    sprintf(real_year, "%d", prtm->tm_year);
    200    real_year_len = strlen(real_year);
    201    sprintf(fake_year, "%d", fake_tm_year);
    202    fake_year_len = strlen(fake_year);
    203 
    204    /* Replace the fake year in the result with the real year. */
    205    for (p = buf; (p = strstr(p, fake_year)); p += real_year_len) {
    206      size_t new_result = result + real_year_len - fake_year_len;
    207      if (new_result >= buflen) {
    208        return 0;
    209      }
    210      memmove(p + real_year_len, p + fake_year_len, strlen(p + fake_year_len));
    211      memcpy(p, real_year, real_year_len);
    212      result = new_result;
    213      *(buf + result) = '\0';
    214    }
    215  }
    216 #  endif
    217  return result;
    218 }
    219 #endif /* !JS_HAS_INTL_API */