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 "fpdfsdk/javascript/JS_Value.h"
8
9 #include <time.h>
10
11 #include <algorithm>
12 #include <cmath>
13 #include <limits>
14 #include <vector>
15
16 #include "fpdfsdk/javascript/Document.h"
17 #include "fpdfsdk/javascript/JS_Define.h"
18 #include "fpdfsdk/javascript/JS_Object.h"
19
20 namespace {
21
22 const uint32_t g_nan[2] = {0, 0x7FF80000};
23
GetNan()24 double GetNan() {
25 return *(double*)g_nan;
26 }
27
28 double
MakeDate(int year,int mon,int day,int hour,int min,int sec,int ms)29 MakeDate(int year, int mon, int day, int hour, int min, int sec, int ms) {
30 return JS_MakeDate(JS_MakeDay(year, mon, day),
31 JS_MakeTime(hour, min, sec, ms));
32 }
33
34 } // namespace
35
CJS_Value(CJS_Runtime * pRuntime)36 CJS_Value::CJS_Value(CJS_Runtime* pRuntime) {}
37
CJS_Value(CJS_Runtime * pRuntime,v8::Local<v8::Value> pValue)38 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, v8::Local<v8::Value> pValue)
39 : m_pValue(pValue) {}
40
CJS_Value(CJS_Runtime * pRuntime,const int & iValue)41 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const int& iValue)
42 : m_pValue(pRuntime->NewNumber(iValue)) {}
43
CJS_Value(CJS_Runtime * pRuntime,const bool & bValue)44 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const bool& bValue)
45 : m_pValue(pRuntime->NewBoolean(bValue)) {}
46
CJS_Value(CJS_Runtime * pRuntime,const float & fValue)47 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const float& fValue)
48 : m_pValue(pRuntime->NewNumber(fValue)) {}
49
CJS_Value(CJS_Runtime * pRuntime,const double & dValue)50 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const double& dValue)
51 : m_pValue(pRuntime->NewNumber(dValue)) {}
52
CJS_Value(CJS_Runtime * pRuntime,CJS_Object * pObj)53 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, CJS_Object* pObj) {
54 if (pObj)
55 m_pValue = pObj->ToV8Object();
56 }
57
CJS_Value(CJS_Runtime * pRuntime,const FX_WCHAR * pWstr)58 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const FX_WCHAR* pWstr)
59 : m_pValue(pRuntime->NewString(pWstr)) {}
60
CJS_Value(CJS_Runtime * pRuntime,const FX_CHAR * pStr)61 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const FX_CHAR* pStr)
62 : m_pValue(pRuntime->NewString(CFX_WideString::FromLocal(pStr).c_str())) {}
63
CJS_Value(CJS_Runtime * pRuntime,const CJS_Array & array)64 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const CJS_Array& array)
65 : m_pValue(array.ToV8Array(pRuntime)) {}
66
CJS_Value(CJS_Runtime * pRuntime,const CJS_Date & date)67 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const CJS_Date& date)
68 : m_pValue(date.ToV8Date(pRuntime)) {}
69
~CJS_Value()70 CJS_Value::~CJS_Value() {}
71
72 CJS_Value::CJS_Value(const CJS_Value& other) = default;
73
Attach(v8::Local<v8::Value> pValue)74 void CJS_Value::Attach(v8::Local<v8::Value> pValue) {
75 m_pValue = pValue;
76 }
77
Detach()78 void CJS_Value::Detach() {
79 m_pValue = v8::Local<v8::Value>();
80 }
81
ToInt(CJS_Runtime * pRuntime) const82 int CJS_Value::ToInt(CJS_Runtime* pRuntime) const {
83 return pRuntime->ToInt32(m_pValue);
84 }
85
ToBool(CJS_Runtime * pRuntime) const86 bool CJS_Value::ToBool(CJS_Runtime* pRuntime) const {
87 return pRuntime->ToBoolean(m_pValue);
88 }
89
ToDouble(CJS_Runtime * pRuntime) const90 double CJS_Value::ToDouble(CJS_Runtime* pRuntime) const {
91 return pRuntime->ToDouble(m_pValue);
92 }
93
ToFloat(CJS_Runtime * pRuntime) const94 float CJS_Value::ToFloat(CJS_Runtime* pRuntime) const {
95 return (float)ToDouble(pRuntime);
96 }
97
ToCJSObject(CJS_Runtime * pRuntime) const98 CJS_Object* CJS_Value::ToCJSObject(CJS_Runtime* pRuntime) const {
99 v8::Local<v8::Object> pObj = pRuntime->ToObject(m_pValue);
100 return static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(pObj));
101 }
102
ToV8Object(CJS_Runtime * pRuntime) const103 v8::Local<v8::Object> CJS_Value::ToV8Object(CJS_Runtime* pRuntime) const {
104 return pRuntime->ToObject(m_pValue);
105 }
106
ToCFXWideString(CJS_Runtime * pRuntime) const107 CFX_WideString CJS_Value::ToCFXWideString(CJS_Runtime* pRuntime) const {
108 return pRuntime->ToWideString(m_pValue);
109 }
110
ToCFXByteString(CJS_Runtime * pRuntime) const111 CFX_ByteString CJS_Value::ToCFXByteString(CJS_Runtime* pRuntime) const {
112 return CFX_ByteString::FromUnicode(ToCFXWideString(pRuntime));
113 }
114
ToV8Value(CJS_Runtime * pRuntime) const115 v8::Local<v8::Value> CJS_Value::ToV8Value(CJS_Runtime* pRuntime) const {
116 return m_pValue;
117 }
118
ToV8Array(CJS_Runtime * pRuntime) const119 v8::Local<v8::Array> CJS_Value::ToV8Array(CJS_Runtime* pRuntime) const {
120 return pRuntime->ToArray(m_pValue);
121 }
122
SetNull(CJS_Runtime * pRuntime)123 void CJS_Value::SetNull(CJS_Runtime* pRuntime) {
124 m_pValue = pRuntime->NewNull();
125 }
126
MaybeCoerceToNumber(CJS_Runtime * pRuntime)127 void CJS_Value::MaybeCoerceToNumber(CJS_Runtime* pRuntime) {
128 bool bAllowNaN = false;
129 if (GetType() == VT_string) {
130 CFX_ByteString bstr = ToCFXByteString(pRuntime);
131 if (bstr.GetLength() == 0)
132 return;
133 if (bstr == "NaN")
134 bAllowNaN = true;
135 }
136 v8::Isolate* pIsolate = pRuntime->GetIsolate();
137 v8::TryCatch try_catch(pIsolate);
138 v8::MaybeLocal<v8::Number> maybeNum =
139 m_pValue->ToNumber(pIsolate->GetCurrentContext());
140 if (maybeNum.IsEmpty())
141 return;
142 v8::Local<v8::Number> num = maybeNum.ToLocalChecked();
143 if (std::isnan(num->Value()) && !bAllowNaN)
144 return;
145 m_pValue = num;
146 }
147
148 // static
GetValueType(v8::Local<v8::Value> value)149 CJS_Value::Type CJS_Value::GetValueType(v8::Local<v8::Value> value) {
150 if (value.IsEmpty())
151 return VT_unknown;
152 if (value->IsString())
153 return VT_string;
154 if (value->IsNumber())
155 return VT_number;
156 if (value->IsBoolean())
157 return VT_boolean;
158 if (value->IsDate())
159 return VT_date;
160 if (value->IsObject())
161 return VT_object;
162 if (value->IsNull())
163 return VT_null;
164 if (value->IsUndefined())
165 return VT_undefined;
166 return VT_unknown;
167 }
168
IsArrayObject() const169 bool CJS_Value::IsArrayObject() const {
170 return !m_pValue.IsEmpty() && m_pValue->IsArray();
171 }
172
IsDateObject() const173 bool CJS_Value::IsDateObject() const {
174 return !m_pValue.IsEmpty() && m_pValue->IsDate();
175 }
176
ConvertToArray(CJS_Runtime * pRuntime,CJS_Array & array) const177 bool CJS_Value::ConvertToArray(CJS_Runtime* pRuntime, CJS_Array& array) const {
178 if (!IsArrayObject())
179 return false;
180 array.Attach(pRuntime->ToArray(m_pValue));
181 return true;
182 }
183
ConvertToDate(CJS_Runtime * pRuntime,CJS_Date & date) const184 bool CJS_Value::ConvertToDate(CJS_Runtime* pRuntime, CJS_Date& date) const {
185 if (!IsDateObject())
186 return false;
187 v8::Local<v8::Value> mutable_value = m_pValue;
188 date.Attach(mutable_value.As<v8::Date>());
189 return true;
190 }
191
CJS_PropValue(CJS_Runtime * pRuntime)192 CJS_PropValue::CJS_PropValue(CJS_Runtime* pRuntime)
193 : m_bIsSetting(0), m_Value(pRuntime), m_pJSRuntime(pRuntime) {}
194
CJS_PropValue(CJS_Runtime * pRuntime,const CJS_Value & value)195 CJS_PropValue::CJS_PropValue(CJS_Runtime* pRuntime, const CJS_Value& value)
196 : m_bIsSetting(0), m_Value(value), m_pJSRuntime(pRuntime) {}
197
~CJS_PropValue()198 CJS_PropValue::~CJS_PropValue() {}
199
operator <<(int iValue)200 void CJS_PropValue::operator<<(int iValue) {
201 ASSERT(!m_bIsSetting);
202 m_Value = CJS_Value(m_pJSRuntime, iValue);
203 }
204
operator >>(int & iValue) const205 void CJS_PropValue::operator>>(int& iValue) const {
206 ASSERT(m_bIsSetting);
207 iValue = m_Value.ToInt(m_pJSRuntime);
208 }
209
operator <<(bool bValue)210 void CJS_PropValue::operator<<(bool bValue) {
211 ASSERT(!m_bIsSetting);
212 m_Value = CJS_Value(m_pJSRuntime, bValue);
213 }
214
operator >>(bool & bValue) const215 void CJS_PropValue::operator>>(bool& bValue) const {
216 ASSERT(m_bIsSetting);
217 bValue = m_Value.ToBool(m_pJSRuntime);
218 }
219
operator <<(double dValue)220 void CJS_PropValue::operator<<(double dValue) {
221 ASSERT(!m_bIsSetting);
222 m_Value = CJS_Value(m_pJSRuntime, dValue);
223 }
224
operator >>(double & dValue) const225 void CJS_PropValue::operator>>(double& dValue) const {
226 ASSERT(m_bIsSetting);
227 dValue = m_Value.ToDouble(m_pJSRuntime);
228 }
229
operator <<(CJS_Object * pObj)230 void CJS_PropValue::operator<<(CJS_Object* pObj) {
231 ASSERT(!m_bIsSetting);
232 m_Value = CJS_Value(m_pJSRuntime, pObj);
233 }
234
operator >>(CJS_Object * & ppObj) const235 void CJS_PropValue::operator>>(CJS_Object*& ppObj) const {
236 ASSERT(m_bIsSetting);
237 ppObj = m_Value.ToCJSObject(m_pJSRuntime);
238 }
239
operator <<(CJS_Document * pJsDoc)240 void CJS_PropValue::operator<<(CJS_Document* pJsDoc) {
241 ASSERT(!m_bIsSetting);
242 m_Value = CJS_Value(m_pJSRuntime, pJsDoc);
243 }
244
operator >>(CJS_Document * & ppJsDoc) const245 void CJS_PropValue::operator>>(CJS_Document*& ppJsDoc) const {
246 ASSERT(m_bIsSetting);
247 ppJsDoc = static_cast<CJS_Document*>(m_Value.ToCJSObject(m_pJSRuntime));
248 }
249
operator <<(v8::Local<v8::Object> pObj)250 void CJS_PropValue::operator<<(v8::Local<v8::Object> pObj) {
251 ASSERT(!m_bIsSetting);
252 m_Value = CJS_Value(m_pJSRuntime, pObj);
253 }
254
operator >>(v8::Local<v8::Object> & ppObj) const255 void CJS_PropValue::operator>>(v8::Local<v8::Object>& ppObj) const {
256 ASSERT(m_bIsSetting);
257 ppObj = m_Value.ToV8Object(m_pJSRuntime);
258 }
259
operator <<(CFX_ByteString str)260 void CJS_PropValue::operator<<(CFX_ByteString str) {
261 ASSERT(!m_bIsSetting);
262 m_Value = CJS_Value(m_pJSRuntime, str.c_str());
263 }
264
operator >>(CFX_ByteString & str) const265 void CJS_PropValue::operator>>(CFX_ByteString& str) const {
266 ASSERT(m_bIsSetting);
267 str = m_Value.ToCFXByteString(m_pJSRuntime);
268 }
269
operator <<(const FX_WCHAR * str)270 void CJS_PropValue::operator<<(const FX_WCHAR* str) {
271 ASSERT(!m_bIsSetting);
272 m_Value = CJS_Value(m_pJSRuntime, str);
273 }
274
operator >>(CFX_WideString & wide_string) const275 void CJS_PropValue::operator>>(CFX_WideString& wide_string) const {
276 ASSERT(m_bIsSetting);
277 wide_string = m_Value.ToCFXWideString(m_pJSRuntime);
278 }
279
operator <<(CFX_WideString wide_string)280 void CJS_PropValue::operator<<(CFX_WideString wide_string) {
281 ASSERT(!m_bIsSetting);
282 m_Value = CJS_Value(m_pJSRuntime, wide_string.c_str());
283 }
284
operator >>(CJS_Array & array) const285 void CJS_PropValue::operator>>(CJS_Array& array) const {
286 ASSERT(m_bIsSetting);
287 m_Value.ConvertToArray(m_pJSRuntime, array);
288 }
289
operator <<(CJS_Array & array)290 void CJS_PropValue::operator<<(CJS_Array& array) {
291 ASSERT(!m_bIsSetting);
292 m_Value = CJS_Value(m_pJSRuntime, array.ToV8Array(m_pJSRuntime));
293 }
294
operator >>(CJS_Date & date) const295 void CJS_PropValue::operator>>(CJS_Date& date) const {
296 ASSERT(m_bIsSetting);
297 m_Value.ConvertToDate(m_pJSRuntime, date);
298 }
299
operator <<(CJS_Date & date)300 void CJS_PropValue::operator<<(CJS_Date& date) {
301 ASSERT(!m_bIsSetting);
302 m_Value = CJS_Value(m_pJSRuntime, date);
303 }
304
CJS_Array()305 CJS_Array::CJS_Array() {}
306
307 CJS_Array::CJS_Array(const CJS_Array& other) = default;
308
~CJS_Array()309 CJS_Array::~CJS_Array() {}
310
Attach(v8::Local<v8::Array> pArray)311 void CJS_Array::Attach(v8::Local<v8::Array> pArray) {
312 m_pArray = pArray;
313 }
314
GetElement(CJS_Runtime * pRuntime,unsigned index,CJS_Value & value) const315 void CJS_Array::GetElement(CJS_Runtime* pRuntime,
316 unsigned index,
317 CJS_Value& value) const {
318 if (!m_pArray.IsEmpty())
319 value.Attach(pRuntime->GetArrayElement(m_pArray, index));
320 }
321
SetElement(CJS_Runtime * pRuntime,unsigned index,const CJS_Value & value)322 void CJS_Array::SetElement(CJS_Runtime* pRuntime,
323 unsigned index,
324 const CJS_Value& value) {
325 if (m_pArray.IsEmpty())
326 m_pArray = pRuntime->NewArray();
327
328 pRuntime->PutArrayElement(m_pArray, index, value.ToV8Value(pRuntime));
329 }
330
GetLength(CJS_Runtime * pRuntime) const331 int CJS_Array::GetLength(CJS_Runtime* pRuntime) const {
332 if (m_pArray.IsEmpty())
333 return 0;
334 return pRuntime->GetArrayLength(m_pArray);
335 }
336
ToV8Array(CJS_Runtime * pRuntime) const337 v8::Local<v8::Array> CJS_Array::ToV8Array(CJS_Runtime* pRuntime) const {
338 if (m_pArray.IsEmpty())
339 m_pArray = pRuntime->NewArray();
340
341 return m_pArray;
342 }
343
CJS_Date()344 CJS_Date::CJS_Date() {}
345
CJS_Date(CJS_Runtime * pRuntime,double dMsecTime)346 CJS_Date::CJS_Date(CJS_Runtime* pRuntime, double dMsecTime)
347 : m_pDate(pRuntime->NewDate(dMsecTime)) {}
348
CJS_Date(CJS_Runtime * pRuntime,int year,int mon,int day,int hour,int min,int sec)349 CJS_Date::CJS_Date(CJS_Runtime* pRuntime,
350 int year,
351 int mon,
352 int day,
353 int hour,
354 int min,
355 int sec)
356 : m_pDate(pRuntime->NewDate(MakeDate(year, mon, day, hour, min, sec, 0))) {}
357
~CJS_Date()358 CJS_Date::~CJS_Date() {}
359
IsValidDate(CJS_Runtime * pRuntime) const360 bool CJS_Date::IsValidDate(CJS_Runtime* pRuntime) const {
361 return !m_pDate.IsEmpty() && !JS_PortIsNan(pRuntime->ToDouble(m_pDate));
362 }
363
Attach(v8::Local<v8::Date> pDate)364 void CJS_Date::Attach(v8::Local<v8::Date> pDate) {
365 m_pDate = pDate;
366 }
367
GetYear(CJS_Runtime * pRuntime) const368 int CJS_Date::GetYear(CJS_Runtime* pRuntime) const {
369 if (!IsValidDate(pRuntime))
370 return 0;
371
372 return JS_GetYearFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate)));
373 }
374
SetYear(CJS_Runtime * pRuntime,int iYear)375 void CJS_Date::SetYear(CJS_Runtime* pRuntime, int iYear) {
376 m_pDate = pRuntime->NewDate(
377 MakeDate(iYear, GetMonth(pRuntime), GetDay(pRuntime), GetHours(pRuntime),
378 GetMinutes(pRuntime), GetSeconds(pRuntime), 0));
379 }
380
GetMonth(CJS_Runtime * pRuntime) const381 int CJS_Date::GetMonth(CJS_Runtime* pRuntime) const {
382 if (!IsValidDate(pRuntime))
383 return 0;
384
385 return JS_GetMonthFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate)));
386 }
387
SetMonth(CJS_Runtime * pRuntime,int iMonth)388 void CJS_Date::SetMonth(CJS_Runtime* pRuntime, int iMonth) {
389 m_pDate = pRuntime->NewDate(
390 MakeDate(GetYear(pRuntime), iMonth, GetDay(pRuntime), GetHours(pRuntime),
391 GetMinutes(pRuntime), GetSeconds(pRuntime), 0));
392 }
393
GetDay(CJS_Runtime * pRuntime) const394 int CJS_Date::GetDay(CJS_Runtime* pRuntime) const {
395 if (!IsValidDate(pRuntime))
396 return 0;
397
398 return JS_GetDayFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate)));
399 }
400
SetDay(CJS_Runtime * pRuntime,int iDay)401 void CJS_Date::SetDay(CJS_Runtime* pRuntime, int iDay) {
402 m_pDate = pRuntime->NewDate(
403 MakeDate(GetYear(pRuntime), GetMonth(pRuntime), iDay, GetHours(pRuntime),
404 GetMinutes(pRuntime), GetSeconds(pRuntime), 0));
405 }
406
GetHours(CJS_Runtime * pRuntime) const407 int CJS_Date::GetHours(CJS_Runtime* pRuntime) const {
408 if (!IsValidDate(pRuntime))
409 return 0;
410
411 return JS_GetHourFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate)));
412 }
413
SetHours(CJS_Runtime * pRuntime,int iHours)414 void CJS_Date::SetHours(CJS_Runtime* pRuntime, int iHours) {
415 m_pDate = pRuntime->NewDate(
416 MakeDate(GetYear(pRuntime), GetMonth(pRuntime), GetDay(pRuntime), iHours,
417 GetMinutes(pRuntime), GetSeconds(pRuntime), 0));
418 }
419
GetMinutes(CJS_Runtime * pRuntime) const420 int CJS_Date::GetMinutes(CJS_Runtime* pRuntime) const {
421 if (!IsValidDate(pRuntime))
422 return 0;
423
424 return JS_GetMinFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate)));
425 }
426
SetMinutes(CJS_Runtime * pRuntime,int minutes)427 void CJS_Date::SetMinutes(CJS_Runtime* pRuntime, int minutes) {
428 m_pDate = pRuntime->NewDate(MakeDate(GetYear(pRuntime), GetMonth(pRuntime),
429 GetDay(pRuntime), GetHours(pRuntime),
430 minutes, GetSeconds(pRuntime), 0));
431 }
432
GetSeconds(CJS_Runtime * pRuntime) const433 int CJS_Date::GetSeconds(CJS_Runtime* pRuntime) const {
434 if (!IsValidDate(pRuntime))
435 return 0;
436
437 return JS_GetSecFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate)));
438 }
439
SetSeconds(CJS_Runtime * pRuntime,int seconds)440 void CJS_Date::SetSeconds(CJS_Runtime* pRuntime, int seconds) {
441 m_pDate = pRuntime->NewDate(MakeDate(GetYear(pRuntime), GetMonth(pRuntime),
442 GetDay(pRuntime), GetHours(pRuntime),
443 GetMinutes(pRuntime), seconds, 0));
444 }
445
ToDouble(CJS_Runtime * pRuntime) const446 double CJS_Date::ToDouble(CJS_Runtime* pRuntime) const {
447 return !m_pDate.IsEmpty() ? pRuntime->ToDouble(m_pDate) : 0.0;
448 }
449
ToString(CJS_Runtime * pRuntime) const450 CFX_WideString CJS_Date::ToString(CJS_Runtime* pRuntime) const {
451 return !m_pDate.IsEmpty() ? pRuntime->ToWideString(m_pDate)
452 : CFX_WideString();
453 }
454
ToV8Date(CJS_Runtime * pRuntime) const455 v8::Local<v8::Date> CJS_Date::ToV8Date(CJS_Runtime* pRuntime) const {
456 return m_pDate;
457 }
458
_getLocalTZA()459 double _getLocalTZA() {
460 if (!FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS))
461 return 0;
462 time_t t = 0;
463 time(&t);
464 localtime(&t);
465 #if _MSC_VER >= 1900
466 // In gcc and in Visual Studio prior to VS 2015 'timezone' is a global
467 // variable declared in time.h. That variable was deprecated and in VS 2015
468 // is removed, with _get_timezone replacing it.
469 long timezone = 0;
470 _get_timezone(&timezone);
471 #endif
472 return (double)(-(timezone * 1000));
473 }
474
_getDaylightSavingTA(double d)475 int _getDaylightSavingTA(double d) {
476 if (!FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS))
477 return 0;
478 time_t t = (time_t)(d / 1000);
479 struct tm* tmp = localtime(&t);
480 if (!tmp)
481 return 0;
482 if (tmp->tm_isdst > 0)
483 // One hour.
484 return (int)60 * 60 * 1000;
485 return 0;
486 }
487
_Mod(double x,double y)488 double _Mod(double x, double y) {
489 double r = fmod(x, y);
490 if (r < 0)
491 r += y;
492 return r;
493 }
494
_isfinite(double v)495 int _isfinite(double v) {
496 #if _MSC_VER
497 return ::_finite(v);
498 #else
499 return std::fabs(v) < std::numeric_limits<double>::max();
500 #endif
501 }
502
_toInteger(double n)503 double _toInteger(double n) {
504 return (n >= 0) ? FXSYS_floor(n) : -FXSYS_floor(-n);
505 }
506
_isLeapYear(int year)507 bool _isLeapYear(int year) {
508 return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 != 0));
509 }
510
_DayFromYear(int y)511 int _DayFromYear(int y) {
512 return (int)(365 * (y - 1970.0) + FXSYS_floor((y - 1969.0) / 4) -
513 FXSYS_floor((y - 1901.0) / 100) +
514 FXSYS_floor((y - 1601.0) / 400));
515 }
516
_TimeFromYear(int y)517 double _TimeFromYear(int y) {
518 return 86400000.0 * _DayFromYear(y);
519 }
520
521 static const uint16_t daysMonth[12] = {0, 31, 59, 90, 120, 151,
522 181, 212, 243, 273, 304, 334};
523 static const uint16_t leapDaysMonth[12] = {0, 31, 60, 91, 121, 152,
524 182, 213, 244, 274, 305, 335};
525
_TimeFromYearMonth(int y,int m)526 double _TimeFromYearMonth(int y, int m) {
527 const uint16_t* pMonth = _isLeapYear(y) ? leapDaysMonth : daysMonth;
528 return _TimeFromYear(y) + ((double)pMonth[m]) * 86400000;
529 }
530
_Day(double t)531 int _Day(double t) {
532 return (int)FXSYS_floor(t / 86400000);
533 }
534
_YearFromTime(double t)535 int _YearFromTime(double t) {
536 // estimate the time.
537 int y = 1970 + static_cast<int>(t / (365.2425 * 86400000));
538 if (_TimeFromYear(y) <= t) {
539 while (_TimeFromYear(y + 1) <= t)
540 y++;
541 } else {
542 while (_TimeFromYear(y) > t)
543 y--;
544 }
545 return y;
546 }
547
_DayWithinYear(double t)548 int _DayWithinYear(double t) {
549 int year = _YearFromTime(t);
550 int day = _Day(t);
551 return day - _DayFromYear(year);
552 }
553
_MonthFromTime(double t)554 int _MonthFromTime(double t) {
555 int day = _DayWithinYear(t);
556 int year = _YearFromTime(t);
557 if (0 <= day && day < 31)
558 return 0;
559 if (31 <= day && day < 59 + _isLeapYear(year))
560 return 1;
561 if ((59 + _isLeapYear(year)) <= day && day < (90 + _isLeapYear(year)))
562 return 2;
563 if ((90 + _isLeapYear(year)) <= day && day < (120 + _isLeapYear(year)))
564 return 3;
565 if ((120 + _isLeapYear(year)) <= day && day < (151 + _isLeapYear(year)))
566 return 4;
567 if ((151 + _isLeapYear(year)) <= day && day < (181 + _isLeapYear(year)))
568 return 5;
569 if ((181 + _isLeapYear(year)) <= day && day < (212 + _isLeapYear(year)))
570 return 6;
571 if ((212 + _isLeapYear(year)) <= day && day < (243 + _isLeapYear(year)))
572 return 7;
573 if ((243 + _isLeapYear(year)) <= day && day < (273 + _isLeapYear(year)))
574 return 8;
575 if ((273 + _isLeapYear(year)) <= day && day < (304 + _isLeapYear(year)))
576 return 9;
577 if ((304 + _isLeapYear(year)) <= day && day < (334 + _isLeapYear(year)))
578 return 10;
579 if ((334 + _isLeapYear(year)) <= day && day < (365 + _isLeapYear(year)))
580 return 11;
581
582 return -1;
583 }
584
_DateFromTime(double t)585 int _DateFromTime(double t) {
586 int day = _DayWithinYear(t);
587 int year = _YearFromTime(t);
588 int leap = _isLeapYear(year);
589 int month = _MonthFromTime(t);
590 switch (month) {
591 case 0:
592 return day + 1;
593 case 1:
594 return day - 30;
595 case 2:
596 return day - 58 - leap;
597 case 3:
598 return day - 89 - leap;
599 case 4:
600 return day - 119 - leap;
601 case 5:
602 return day - 150 - leap;
603 case 6:
604 return day - 180 - leap;
605 case 7:
606 return day - 211 - leap;
607 case 8:
608 return day - 242 - leap;
609 case 9:
610 return day - 272 - leap;
611 case 10:
612 return day - 303 - leap;
613 case 11:
614 return day - 333 - leap;
615 default:
616 return 0;
617 }
618 }
619
JS_GetDateTime()620 double JS_GetDateTime() {
621 if (!FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS))
622 return 0;
623 time_t t = time(nullptr);
624 struct tm* pTm = localtime(&t);
625
626 int year = pTm->tm_year + 1900;
627 double t1 = _TimeFromYear(year);
628
629 return t1 + pTm->tm_yday * 86400000.0 + pTm->tm_hour * 3600000.0 +
630 pTm->tm_min * 60000.0 + pTm->tm_sec * 1000.0;
631 }
632
JS_GetYearFromTime(double dt)633 int JS_GetYearFromTime(double dt) {
634 return _YearFromTime(dt);
635 }
636
JS_GetMonthFromTime(double dt)637 int JS_GetMonthFromTime(double dt) {
638 return _MonthFromTime(dt);
639 }
640
JS_GetDayFromTime(double dt)641 int JS_GetDayFromTime(double dt) {
642 return _DateFromTime(dt);
643 }
644
JS_GetHourFromTime(double dt)645 int JS_GetHourFromTime(double dt) {
646 return (int)_Mod(floor(dt / (60 * 60 * 1000)), 24);
647 }
648
JS_GetMinFromTime(double dt)649 int JS_GetMinFromTime(double dt) {
650 return (int)_Mod(floor(dt / (60 * 1000)), 60);
651 }
652
JS_GetSecFromTime(double dt)653 int JS_GetSecFromTime(double dt) {
654 return (int)_Mod(floor(dt / 1000), 60);
655 }
656
JS_DateParse(const CFX_WideString & str)657 double JS_DateParse(const CFX_WideString& str) {
658 v8::Isolate* pIsolate = v8::Isolate::GetCurrent();
659 v8::Isolate::Scope isolate_scope(pIsolate);
660 v8::HandleScope scope(pIsolate);
661
662 v8::Local<v8::Context> context = pIsolate->GetCurrentContext();
663
664 // Use the built-in object method.
665 v8::Local<v8::Value> v =
666 context->Global()
667 ->Get(context, v8::String::NewFromUtf8(pIsolate, "Date",
668 v8::NewStringType::kNormal)
669 .ToLocalChecked())
670 .ToLocalChecked();
671 if (v->IsObject()) {
672 v8::Local<v8::Object> o = v->ToObject(context).ToLocalChecked();
673 v = o->Get(context, v8::String::NewFromUtf8(pIsolate, "parse",
674 v8::NewStringType::kNormal)
675 .ToLocalChecked())
676 .ToLocalChecked();
677 if (v->IsFunction()) {
678 v8::Local<v8::Function> funC = v8::Local<v8::Function>::Cast(v);
679 const int argc = 1;
680 v8::Local<v8::Value> timeStr =
681 CJS_Runtime::CurrentRuntimeFromIsolate(pIsolate)->NewString(
682 str.AsStringC());
683 v8::Local<v8::Value> argv[argc] = {timeStr};
684 v = funC->Call(context, context->Global(), argc, argv).ToLocalChecked();
685 if (v->IsNumber()) {
686 double date = v->ToNumber(context).ToLocalChecked()->Value();
687 if (!_isfinite(date))
688 return date;
689 return JS_LocalTime(date);
690 }
691 }
692 }
693 return 0;
694 }
695
JS_MakeDay(int nYear,int nMonth,int nDate)696 double JS_MakeDay(int nYear, int nMonth, int nDate) {
697 if (!_isfinite(nYear) || !_isfinite(nMonth) || !_isfinite(nDate))
698 return GetNan();
699 double y = _toInteger(nYear);
700 double m = _toInteger(nMonth);
701 double dt = _toInteger(nDate);
702 double ym = y + FXSYS_floor((double)m / 12);
703 double mn = _Mod(m, 12);
704
705 double t = _TimeFromYearMonth((int)ym, (int)mn);
706
707 if (_YearFromTime(t) != ym || _MonthFromTime(t) != mn ||
708 _DateFromTime(t) != 1)
709 return GetNan();
710 return _Day(t) + dt - 1;
711 }
712
JS_MakeTime(int nHour,int nMin,int nSec,int nMs)713 double JS_MakeTime(int nHour, int nMin, int nSec, int nMs) {
714 if (!_isfinite(nHour) || !_isfinite(nMin) || !_isfinite(nSec) ||
715 !_isfinite(nMs))
716 return GetNan();
717
718 double h = _toInteger(nHour);
719 double m = _toInteger(nMin);
720 double s = _toInteger(nSec);
721 double milli = _toInteger(nMs);
722
723 return h * 3600000 + m * 60000 + s * 1000 + milli;
724 }
725
JS_MakeDate(double day,double time)726 double JS_MakeDate(double day, double time) {
727 if (!_isfinite(day) || !_isfinite(time))
728 return GetNan();
729
730 return day * 86400000 + time;
731 }
732
JS_PortIsNan(double d)733 bool JS_PortIsNan(double d) {
734 return d != d;
735 }
736
JS_LocalTime(double d)737 double JS_LocalTime(double d) {
738 return d + _getLocalTZA() + _getDaylightSavingTA(d);
739 }
740
JS_ExpandKeywordParams(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & originals,size_t nKeywords,...)741 std::vector<CJS_Value> JS_ExpandKeywordParams(
742 CJS_Runtime* pRuntime,
743 const std::vector<CJS_Value>& originals,
744 size_t nKeywords,
745 ...) {
746 ASSERT(nKeywords);
747
748 std::vector<CJS_Value> result(nKeywords, CJS_Value(pRuntime));
749 size_t size = std::min(originals.size(), nKeywords);
750 for (size_t i = 0; i < size; ++i)
751 result[i] = originals[i];
752
753 if (originals.size() != 1 || originals[0].GetType() != CJS_Value::VT_object ||
754 originals[0].IsArrayObject()) {
755 return result;
756 }
757 v8::Local<v8::Object> pObj = originals[0].ToV8Object(pRuntime);
758 result[0] = CJS_Value(pRuntime); // Make unknown.
759
760 va_list ap;
761 va_start(ap, nKeywords);
762 for (size_t i = 0; i < nKeywords; ++i) {
763 const wchar_t* property = va_arg(ap, const wchar_t*);
764 v8::Local<v8::Value> v8Value = pRuntime->GetObjectProperty(pObj, property);
765 if (!v8Value->IsUndefined())
766 result[i] = CJS_Value(pRuntime, v8Value);
767 }
768 va_end(ap);
769 return result;
770 }
771