1 // Copyright 2014 PDFium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com 6 7 #include "fxjs/JS_Define.h" 8 9 #include <time.h> 10 11 #include <algorithm> 12 #include <cmath> 13 #include <limits> 14 #include <vector> 15 16 #include "fxjs/cjs_document.h" 17 #include "fxjs/cjs_object.h" 18 19 namespace { 20 21 double GetLocalTZA() { 22 if (!FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS)) 23 return 0; 24 time_t t = 0; 25 time(&t); 26 localtime(&t); 27 #if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_ 28 // In gcc 'timezone' is a global variable declared in time.h. In VC++, that 29 // variable was removed in VC++ 2015, with _get_timezone replacing it. 30 long timezone = 0; 31 _get_timezone(&timezone); 32 #endif // _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_ 33 return (double)(-(timezone * 1000)); 34 } 35 36 int GetDaylightSavingTA(double d) { 37 if (!FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS)) 38 return 0; 39 time_t t = (time_t)(d / 1000); 40 struct tm* tmp = localtime(&t); 41 if (!tmp) 42 return 0; 43 if (tmp->tm_isdst > 0) 44 // One hour. 45 return (int)60 * 60 * 1000; 46 return 0; 47 } 48 49 double Mod(double x, double y) { 50 double r = fmod(x, y); 51 if (r < 0) 52 r += y; 53 return r; 54 } 55 56 bool IsLeapYear(int year) { 57 return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 != 0)); 58 } 59 60 int DayFromYear(int y) { 61 return (int)(365 * (y - 1970.0) + floor((y - 1969.0) / 4) - 62 floor((y - 1901.0) / 100) + floor((y - 1601.0) / 400)); 63 } 64 65 double TimeFromYear(int y) { 66 return 86400000.0 * DayFromYear(y); 67 } 68 69 static const uint16_t daysMonth[12] = {0, 31, 59, 90, 120, 151, 70 181, 212, 243, 273, 304, 334}; 71 static const uint16_t leapDaysMonth[12] = {0, 31, 60, 91, 121, 152, 72 182, 213, 244, 274, 305, 335}; 73 74 double TimeFromYearMonth(int y, int m) { 75 const uint16_t* pMonth = IsLeapYear(y) ? leapDaysMonth : daysMonth; 76 return TimeFromYear(y) + ((double)pMonth[m]) * 86400000; 77 } 78 79 int Day(double t) { 80 return static_cast<int>(floor(t / 86400000.0)); 81 } 82 83 int YearFromTime(double t) { 84 // estimate the time. 85 int y = 1970 + static_cast<int>(t / (365.2425 * 86400000.0)); 86 if (TimeFromYear(y) <= t) { 87 while (TimeFromYear(y + 1) <= t) 88 y++; 89 } else { 90 while (TimeFromYear(y) > t) 91 y--; 92 } 93 return y; 94 } 95 96 int DayWithinYear(double t) { 97 int year = YearFromTime(t); 98 int day = Day(t); 99 return day - DayFromYear(year); 100 } 101 102 int MonthFromTime(double t) { 103 int day = DayWithinYear(t); 104 int year = YearFromTime(t); 105 if (0 <= day && day < 31) 106 return 0; 107 if (31 <= day && day < 59 + IsLeapYear(year)) 108 return 1; 109 if ((59 + IsLeapYear(year)) <= day && day < (90 + IsLeapYear(year))) 110 return 2; 111 if ((90 + IsLeapYear(year)) <= day && day < (120 + IsLeapYear(year))) 112 return 3; 113 if ((120 + IsLeapYear(year)) <= day && day < (151 + IsLeapYear(year))) 114 return 4; 115 if ((151 + IsLeapYear(year)) <= day && day < (181 + IsLeapYear(year))) 116 return 5; 117 if ((181 + IsLeapYear(year)) <= day && day < (212 + IsLeapYear(year))) 118 return 6; 119 if ((212 + IsLeapYear(year)) <= day && day < (243 + IsLeapYear(year))) 120 return 7; 121 if ((243 + IsLeapYear(year)) <= day && day < (273 + IsLeapYear(year))) 122 return 8; 123 if ((273 + IsLeapYear(year)) <= day && day < (304 + IsLeapYear(year))) 124 return 9; 125 if ((304 + IsLeapYear(year)) <= day && day < (334 + IsLeapYear(year))) 126 return 10; 127 if ((334 + IsLeapYear(year)) <= day && day < (365 + IsLeapYear(year))) 128 return 11; 129 130 return -1; 131 } 132 133 int DateFromTime(double t) { 134 int day = DayWithinYear(t); 135 int year = YearFromTime(t); 136 int leap = IsLeapYear(year); 137 int month = MonthFromTime(t); 138 switch (month) { 139 case 0: 140 return day + 1; 141 case 1: 142 return day - 30; 143 case 2: 144 return day - 58 - leap; 145 case 3: 146 return day - 89 - leap; 147 case 4: 148 return day - 119 - leap; 149 case 5: 150 return day - 150 - leap; 151 case 6: 152 return day - 180 - leap; 153 case 7: 154 return day - 211 - leap; 155 case 8: 156 return day - 242 - leap; 157 case 9: 158 return day - 272 - leap; 159 case 10: 160 return day - 303 - leap; 161 case 11: 162 return day - 333 - leap; 163 default: 164 return 0; 165 } 166 } 167 168 } // namespace 169 170 double JS_GetDateTime() { 171 if (!FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS)) 172 return 0; 173 time_t t = time(nullptr); 174 struct tm* pTm = localtime(&t); 175 176 int year = pTm->tm_year + 1900; 177 double t1 = TimeFromYear(year); 178 179 return t1 + pTm->tm_yday * 86400000.0 + pTm->tm_hour * 3600000.0 + 180 pTm->tm_min * 60000.0 + pTm->tm_sec * 1000.0; 181 } 182 183 int JS_GetYearFromTime(double dt) { 184 return YearFromTime(dt); 185 } 186 187 int JS_GetMonthFromTime(double dt) { 188 return MonthFromTime(dt); 189 } 190 191 int JS_GetDayFromTime(double dt) { 192 return DateFromTime(dt); 193 } 194 195 int JS_GetHourFromTime(double dt) { 196 return (int)Mod(floor(dt / (60 * 60 * 1000)), 24); 197 } 198 199 int JS_GetMinFromTime(double dt) { 200 return (int)Mod(floor(dt / (60 * 1000)), 60); 201 } 202 203 int JS_GetSecFromTime(double dt) { 204 return (int)Mod(floor(dt / 1000), 60); 205 } 206 207 double JS_LocalTime(double d) { 208 return d + GetLocalTZA() + GetDaylightSavingTA(d); 209 } 210 211 double JS_DateParse(const WideString& str) { 212 v8::Isolate* pIsolate = v8::Isolate::GetCurrent(); 213 v8::Isolate::Scope isolate_scope(pIsolate); 214 v8::HandleScope scope(pIsolate); 215 216 v8::Local<v8::Context> context = pIsolate->GetCurrentContext(); 217 218 // Use the built-in object method. 219 v8::Local<v8::Value> v = 220 context->Global() 221 ->Get(context, v8::String::NewFromUtf8(pIsolate, "Date", 222 v8::NewStringType::kNormal) 223 .ToLocalChecked()) 224 .ToLocalChecked(); 225 if (v->IsObject()) { 226 v8::Local<v8::Object> o = v->ToObject(context).ToLocalChecked(); 227 v = o->Get(context, v8::String::NewFromUtf8(pIsolate, "parse", 228 v8::NewStringType::kNormal) 229 .ToLocalChecked()) 230 .ToLocalChecked(); 231 if (v->IsFunction()) { 232 v8::Local<v8::Function> funC = v8::Local<v8::Function>::Cast(v); 233 const int argc = 1; 234 v8::Local<v8::Value> timeStr = 235 CJS_Runtime::CurrentRuntimeFromIsolate(pIsolate)->NewString( 236 str.AsStringView()); 237 v8::Local<v8::Value> argv[argc] = {timeStr}; 238 v = funC->Call(context, context->Global(), argc, argv).ToLocalChecked(); 239 if (v->IsNumber()) { 240 double date = v->ToNumber(context).ToLocalChecked()->Value(); 241 if (!std::isfinite(date)) 242 return date; 243 return JS_LocalTime(date); 244 } 245 } 246 } 247 return 0; 248 } 249 250 double JS_MakeDay(int nYear, int nMonth, int nDate) { 251 double y = static_cast<double>(nYear); 252 double m = static_cast<double>(nMonth); 253 double dt = static_cast<double>(nDate); 254 double ym = y + floor(m / 12); 255 double mn = Mod(m, 12); 256 double t = TimeFromYearMonth(static_cast<int>(ym), static_cast<int>(mn)); 257 if (YearFromTime(t) != ym || MonthFromTime(t) != mn || DateFromTime(t) != 1) 258 return std::nan(""); 259 260 return Day(t) + dt - 1; 261 } 262 263 double JS_MakeTime(int nHour, int nMin, int nSec, int nMs) { 264 double h = static_cast<double>(nHour); 265 double m = static_cast<double>(nMin); 266 double s = static_cast<double>(nSec); 267 double milli = static_cast<double>(nMs); 268 return h * 3600000 + m * 60000 + s * 1000 + milli; 269 } 270 271 double JS_MakeDate(double day, double time) { 272 if (!std::isfinite(day) || !std::isfinite(time)) 273 return std::nan(""); 274 275 return day * 86400000 + time; 276 } 277 278 std::vector<v8::Local<v8::Value>> ExpandKeywordParams( 279 CJS_Runtime* pRuntime, 280 const std::vector<v8::Local<v8::Value>>& originals, 281 size_t nKeywords, 282 ...) { 283 ASSERT(nKeywords); 284 285 std::vector<v8::Local<v8::Value>> result(nKeywords, v8::Local<v8::Value>()); 286 size_t size = std::min(originals.size(), nKeywords); 287 for (size_t i = 0; i < size; ++i) 288 result[i] = originals[i]; 289 290 if (originals.size() != 1 || !originals[0]->IsObject() || 291 originals[0]->IsArray()) { 292 return result; 293 } 294 result[0] = v8::Local<v8::Value>(); // Make unknown. 295 296 v8::Local<v8::Object> pObj = pRuntime->ToObject(originals[0]); 297 va_list ap; 298 va_start(ap, nKeywords); 299 for (size_t i = 0; i < nKeywords; ++i) { 300 const wchar_t* property = va_arg(ap, const wchar_t*); 301 v8::Local<v8::Value> v8Value = pRuntime->GetObjectProperty(pObj, property); 302 if (!v8Value->IsUndefined()) 303 result[i] = v8Value; 304 } 305 va_end(ap); 306 307 return result; 308 } 309