• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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