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/src/javascript/util.h"
8 
9 #include <time.h>
10 
11 #include "core/include/fxcrt/fx_ext.h"
12 #include "fpdfsdk/include/javascript/IJavaScript.h"
13 #include "fpdfsdk/src/javascript/JS_Context.h"
14 #include "fpdfsdk/src/javascript/JS_Define.h"
15 #include "fpdfsdk/src/javascript/JS_EventHandler.h"
16 #include "fpdfsdk/src/javascript/JS_Object.h"
17 #include "fpdfsdk/src/javascript/JS_Runtime.h"
18 #include "fpdfsdk/src/javascript/JS_Value.h"
19 #include "fpdfsdk/src/javascript/PublicMethods.h"
20 #include "fpdfsdk/src/javascript/resource.h"
21 
22 #if _FX_OS_ == _FX_ANDROID_
23 #include <ctype.h>
24 #endif
25 
26 BEGIN_JS_STATIC_CONST(CJS_Util)
END_JS_STATIC_CONST()27 END_JS_STATIC_CONST()
28 
29 BEGIN_JS_STATIC_PROP(CJS_Util)
30 END_JS_STATIC_PROP()
31 
32 BEGIN_JS_STATIC_METHOD(CJS_Util)
33 JS_STATIC_METHOD_ENTRY(printd)
34 JS_STATIC_METHOD_ENTRY(printf)
35 JS_STATIC_METHOD_ENTRY(printx)
36 JS_STATIC_METHOD_ENTRY(scand)
37 JS_STATIC_METHOD_ENTRY(byteToChar)
38 END_JS_STATIC_METHOD()
39 
40 IMPLEMENT_JS_CLASS(CJS_Util, util)
41 
42 util::util(CJS_Object* pJSObject) : CJS_EmbedObj(pJSObject) {}
43 
~util()44 util::~util() {
45 }
46 
47 struct stru_TbConvert {
48   const FX_WCHAR* lpszJSMark;
49   const FX_WCHAR* lpszCppMark;
50 };
51 
52 const stru_TbConvert fcTable[] = {
53     {L"mmmm", L"%B"},
54     {L"mmm", L"%b"},
55     {L"mm", L"%m"},
56     //"m"
57     {L"dddd", L"%A"},
58     {L"ddd", L"%a"},
59     {L"dd", L"%d"},
60     //"d",   "%w",
61     {L"yyyy", L"%Y"},
62     {L"yy", L"%y"},
63     {L"HH", L"%H"},
64     //"H"
65     {L"hh", L"%I"},
66     //"h"
67     {L"MM", L"%M"},
68     //"M"
69     {L"ss", L"%S"},
70     //"s
71     {L"TT", L"%p"},
72 //"t"
73 #if defined(_WIN32)
74     {L"tt", L"%p"},
75     {L"h", L"%#I"},
76 #else
77     {L"tt", L"%P"},
78     {L"h", L"%l"},
79 #endif
80 };
81 
82 #define UTIL_INT 0
83 #define UTIL_DOUBLE 1
84 #define UTIL_STRING 2
85 
ParstDataType(std::wstring * sFormat)86 int util::ParstDataType(std::wstring* sFormat) {
87   bool bPercent = FALSE;
88   for (size_t i = 0; i < sFormat->length(); ++i) {
89     wchar_t c = (*sFormat)[i];
90     if (c == L'%') {
91       bPercent = true;
92       continue;
93     }
94 
95     if (bPercent) {
96       if (c == L'c' || c == L'C' || c == L'd' || c == L'i' || c == L'o' ||
97           c == L'u' || c == L'x' || c == L'X') {
98         return UTIL_INT;
99       }
100       if (c == L'e' || c == L'E' || c == L'f' || c == L'g' || c == L'G') {
101         return UTIL_DOUBLE;
102       }
103       if (c == L's' || c == L'S') {
104         // Map s to S since we always deal internally
105         // with wchar_t strings.
106         (*sFormat)[i] = L'S';
107         return UTIL_STRING;
108       }
109       if (c == L'.' || c == L'+' || c == L'-' || c == L'#' || c == L' ' ||
110           FXSYS_iswdigit(c)) {
111         continue;
112       }
113       break;
114     }
115   }
116 
117   return -1;
118 }
119 
printf(IJS_Context * cc,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)120 FX_BOOL util::printf(IJS_Context* cc,
121                      const std::vector<CJS_Value>& params,
122                      CJS_Value& vRet,
123                      CFX_WideString& sError) {
124   int iSize = params.size();
125   if (iSize < 1)
126     return FALSE;
127   std::wstring c_ConvChar(params[0].ToCFXWideString().c_str());
128   std::vector<std::wstring> c_strConvers;
129   int iOffset = 0;
130   int iOffend = 0;
131   c_ConvChar.insert(c_ConvChar.begin(), L'S');
132   while (iOffset != -1) {
133     iOffend = c_ConvChar.find(L"%", iOffset + 1);
134     std::wstring strSub;
135     if (iOffend == -1)
136       strSub = c_ConvChar.substr(iOffset);
137     else
138       strSub = c_ConvChar.substr(iOffset, iOffend - iOffset);
139     c_strConvers.push_back(strSub);
140     iOffset = iOffend;
141   }
142 
143   std::wstring c_strResult;
144 
145   // for(int iIndex = 1;iIndex < params.size();iIndex++)
146   std::wstring c_strFormat;
147   for (int iIndex = 0; iIndex < (int)c_strConvers.size(); iIndex++) {
148     c_strFormat = c_strConvers[iIndex];
149     if (iIndex == 0) {
150       c_strResult = c_strFormat;
151       continue;
152     }
153 
154     CFX_WideString strSegment;
155     if (iIndex >= iSize) {
156       c_strResult += c_strFormat;
157       continue;
158     }
159 
160     switch (ParstDataType(&c_strFormat)) {
161       case UTIL_INT:
162         strSegment.Format(c_strFormat.c_str(), params[iIndex].ToInt());
163         break;
164       case UTIL_DOUBLE:
165         strSegment.Format(c_strFormat.c_str(), params[iIndex].ToDouble());
166         break;
167       case UTIL_STRING:
168         strSegment.Format(c_strFormat.c_str(),
169                           params[iIndex].ToCFXWideString().c_str());
170         break;
171       default:
172         strSegment.Format(L"%S", c_strFormat.c_str());
173         break;
174     }
175     c_strResult += strSegment.GetBuffer(strSegment.GetLength() + 1);
176   }
177 
178   c_strResult.erase(c_strResult.begin());
179   vRet = c_strResult.c_str();
180   return TRUE;
181 }
182 
printd(IJS_Context * cc,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)183 FX_BOOL util::printd(IJS_Context* cc,
184                      const std::vector<CJS_Value>& params,
185                      CJS_Value& vRet,
186                      CFX_WideString& sError) {
187   int iSize = params.size();
188   if (iSize < 2)
189     return FALSE;
190 
191   CJS_Runtime* pRuntime = CJS_Runtime::FromContext(cc);
192   CJS_Value p1(pRuntime);
193   p1 = params[0];
194 
195   CJS_Value p2 = params[1];
196   CJS_Date jsDate(pRuntime);
197   if (!p2.ConvertToDate(jsDate)) {
198     sError = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSPRINT1);
199     return FALSE;
200   }
201 
202   if (!jsDate.IsValidDate()) {
203     sError = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSPRINT2);
204     return FALSE;
205   }
206 
207   if (p1.GetType() == CJS_Value::VT_number) {
208     int nFormat = p1.ToInt();
209     CFX_WideString swResult;
210 
211     switch (nFormat) {
212       case 0:
213         swResult.Format(L"D:%04d%02d%02d%02d%02d%02d", jsDate.GetYear(),
214                         jsDate.GetMonth() + 1, jsDate.GetDay(),
215                         jsDate.GetHours(), jsDate.GetMinutes(),
216                         jsDate.GetSeconds());
217         break;
218       case 1:
219         swResult.Format(L"%04d.%02d.%02d %02d:%02d:%02d", jsDate.GetYear(),
220                         jsDate.GetMonth() + 1, jsDate.GetDay(),
221                         jsDate.GetHours(), jsDate.GetMinutes(),
222                         jsDate.GetSeconds());
223         break;
224       case 2:
225         swResult.Format(L"%04d/%02d/%02d %02d:%02d:%02d", jsDate.GetYear(),
226                         jsDate.GetMonth() + 1, jsDate.GetDay(),
227                         jsDate.GetHours(), jsDate.GetMinutes(),
228                         jsDate.GetSeconds());
229         break;
230       default:
231         return FALSE;
232     }
233 
234     vRet = swResult.c_str();
235     return TRUE;
236   }
237   if (p1.GetType() == CJS_Value::VT_string) {
238     std::basic_string<wchar_t> cFormat = p1.ToCFXWideString().c_str();
239 
240     bool bXFAPicture = false;
241     if (iSize > 2) {
242       bXFAPicture = params[2].ToBool();
243     }
244 
245     if (bXFAPicture) {
246       return FALSE;  // currently, it doesn't support XFAPicture.
247     }
248 
249     for (size_t i = 0; i < sizeof(fcTable) / sizeof(stru_TbConvert); ++i) {
250       int iStart = 0;
251       int iEnd;
252       while ((iEnd = cFormat.find(fcTable[i].lpszJSMark, iStart)) != -1) {
253         cFormat.replace(iEnd, FXSYS_wcslen(fcTable[i].lpszJSMark),
254                         fcTable[i].lpszCppMark);
255         iStart = iEnd;
256       }
257     }
258 
259     int iYear, iMonth, iDay, iHour, iMin, iSec;
260     iYear = jsDate.GetYear();
261     iMonth = jsDate.GetMonth();
262     iDay = jsDate.GetDay();
263     iHour = jsDate.GetHours();
264     iMin = jsDate.GetMinutes();
265     iSec = jsDate.GetSeconds();
266 
267     struct tm time = {};
268     time.tm_year = iYear - 1900;
269     time.tm_mon = iMonth;
270     time.tm_mday = iDay;
271     time.tm_hour = iHour;
272     time.tm_min = iMin;
273     time.tm_sec = iSec;
274 
275     struct stru_TbConvertAd {
276       const FX_WCHAR* lpszJSMark;
277       int iValue;
278     };
279 
280     stru_TbConvertAd cTableAd[] = {
281         {L"m", iMonth + 1}, {L"d", iDay},
282         {L"H", iHour},      {L"h", iHour > 12 ? iHour - 12 : iHour},
283         {L"M", iMin},       {L"s", iSec},
284     };
285 
286     for (size_t i = 0; i < sizeof(cTableAd) / sizeof(stru_TbConvertAd); ++i) {
287       wchar_t tszValue[10];
288       CFX_WideString sValue;
289       sValue.Format(L"%d", cTableAd[i].iValue);
290       memcpy(tszValue, (wchar_t*)sValue.GetBuffer(sValue.GetLength() + 1),
291              (sValue.GetLength() + 1) * sizeof(wchar_t));
292 
293       int iStart = 0;
294       int iEnd;
295       while ((iEnd = cFormat.find(cTableAd[i].lpszJSMark, iStart)) != -1) {
296         if (iEnd > 0) {
297           if (cFormat[iEnd - 1] == L'%') {
298             iStart = iEnd + 1;
299             continue;
300           }
301         }
302         cFormat.replace(iEnd, FXSYS_wcslen(cTableAd[i].lpszJSMark), tszValue);
303         iStart = iEnd;
304       }
305     }
306 
307     CFX_WideString strFormat;
308     wchar_t buf[64] = {};
309     strFormat = wcsftime(buf, 64, cFormat.c_str(), &time);
310     cFormat = buf;
311     vRet = cFormat.c_str();
312     return TRUE;
313   }
314   return FALSE;
315 }
316 
printd(const std::wstring & cFormat2,CJS_Date jsDate,bool bXFAPicture,std::wstring & cPurpose)317 void util::printd(const std::wstring& cFormat2,
318                   CJS_Date jsDate,
319                   bool bXFAPicture,
320                   std::wstring& cPurpose) {
321   std::wstring cFormat = cFormat2;
322 
323   if (bXFAPicture) {
324     return;  // currently, it doesn't support XFAPicture.
325   }
326 
327   for (size_t i = 0; i < sizeof(fcTable) / sizeof(stru_TbConvert); ++i) {
328     int iStart = 0;
329     int iEnd;
330     while ((iEnd = cFormat.find(fcTable[i].lpszJSMark, iStart)) != -1) {
331       cFormat.replace(iEnd, FXSYS_wcslen(fcTable[i].lpszJSMark),
332                       fcTable[i].lpszCppMark);
333       iStart = iEnd;
334     }
335   }
336 
337   int iYear, iMonth, iDay, iHour, iMin, iSec;
338   iYear = jsDate.GetYear();
339   iMonth = jsDate.GetMonth();
340   iDay = jsDate.GetDay();
341   iHour = jsDate.GetHours();
342   iMin = jsDate.GetMinutes();
343   iSec = jsDate.GetSeconds();
344 
345   struct tm time = {};
346   time.tm_year = iYear - 1900;
347   time.tm_mon = iMonth;
348   time.tm_mday = iDay;
349   time.tm_hour = iHour;
350   time.tm_min = iMin;
351   time.tm_sec = iSec;
352   //  COleDateTime cppTm(iYear,iMonth+1,iDay,iHour,iMin,iSec);
353   // CString strFormat = cppTm.Format(cFormat.c_str());
354 
355   struct stru_TbConvertAd {
356     const FX_WCHAR* lpszJSMark;
357     int iValue;
358   };
359 
360   stru_TbConvertAd cTableAd[] = {
361       {L"m", iMonth + 1}, {L"d", iDay},
362       {L"H", iHour},      {L"h", iHour > 12 ? iHour - 12 : iHour},
363       {L"M", iMin},       {L"s", iSec},
364   };
365 
366   // cFormat = strFormat.GetBuffer(strFormat.GetLength()+1);
367   for (size_t i = 0; i < sizeof(cTableAd) / sizeof(stru_TbConvertAd); ++i) {
368     wchar_t tszValue[10];
369     CFX_WideString sValue;
370     sValue.Format(L"%d", cTableAd[i].iValue);
371     memcpy(tszValue, (wchar_t*)sValue.GetBuffer(sValue.GetLength() + 1),
372            sValue.GetLength() * sizeof(wchar_t));
373 
374     int iStart = 0;
375     int iEnd;
376     while ((iEnd = cFormat.find(cTableAd[i].lpszJSMark, iStart)) != -1) {
377       if (iEnd > 0) {
378         if (cFormat[iEnd - 1] == L'%') {
379           iStart = iEnd + 1;
380           continue;
381         }
382       }
383       cFormat.replace(iEnd, FXSYS_wcslen(cTableAd[i].lpszJSMark), tszValue);
384       iStart = iEnd;
385     }
386   }
387 
388   CFX_WideString strFormat;
389   wchar_t buf[64] = {};
390   strFormat = wcsftime(buf, 64, cFormat.c_str(), &time);
391   cFormat = buf;
392   cPurpose = cFormat;
393 }
394 
printx(IJS_Context * cc,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)395 FX_BOOL util::printx(IJS_Context* cc,
396                      const std::vector<CJS_Value>& params,
397                      CJS_Value& vRet,
398                      CFX_WideString& sError) {
399   int iSize = params.size();
400   if (iSize < 2)
401     return FALSE;
402   CFX_WideString sFormat = params[0].ToCFXWideString();
403   CFX_WideString sSource = params[1].ToCFXWideString();
404   std::string cFormat = CFX_ByteString::FromUnicode(sFormat).c_str();
405   std::string cSource = CFX_ByteString::FromUnicode(sSource).c_str();
406   std::string cDest;
407   printx(cFormat, cSource, cDest);
408   vRet = cDest.c_str();
409   return TRUE;
410 }
411 
printx(const std::string & cFormat,const std::string & cSource2,std::string & cPurpose)412 void util::printx(const std::string& cFormat,
413                   const std::string& cSource2,
414                   std::string& cPurpose) {
415   std::string cSource(cSource2);
416   if (!cPurpose.empty())
417     // cPurpose.clear();
418     cPurpose.erase();
419   int itSource = 0;
420   int iSize = cSource.size();
421   for (int iIndex = 0; iIndex < (int)cFormat.size() && itSource < iSize;
422        iIndex++) {
423     char letter = cFormat[iIndex];
424     switch (letter) {
425       case '?':
426         cPurpose += cSource[itSource];
427         itSource++;
428         break;
429       case 'X': {
430         while (itSource < iSize) {
431           if (std::isdigit(cSource[itSource]) ||
432               (cSource[itSource] >= 'a' && cSource[itSource] <= 'z') ||
433               (cSource[itSource] >= 'A' && cSource[itSource] <= 'Z')) {
434             cPurpose += cSource[itSource];
435             itSource++;
436             break;
437           }
438           itSource++;
439         }
440         break;
441       } break;
442       case 'A': {
443         while (itSource < iSize) {
444           if ((cSource[itSource] >= 'a' && cSource[itSource] <= 'z') ||
445               (cSource[itSource] >= 'A' && cSource[itSource] <= 'Z')) {
446             cPurpose += cSource[itSource];
447             itSource++;
448             break;
449           }
450           itSource++;
451         }
452         break;
453       } break;
454       case '9': {
455         while (itSource < iSize) {
456           if (std::isdigit(cSource[itSource])) {
457             cPurpose += cSource[itSource];
458             itSource++;
459             break;
460           }
461           itSource++;
462         }
463         break;
464       }
465       case '*': {
466         cPurpose.append(cSource, itSource, iSize - itSource);
467         itSource = iSize - 1;
468         break;
469       }
470       case '\\':
471         break;
472       case '>': {
473         for (char& c : cSource)
474           c = toupper(c);
475         break;
476       }
477       case '<': {
478         for (char& c : cSource)
479           c = tolower(c);
480         break;
481       }
482       case '=':
483         break;
484       default:
485         cPurpose += letter;
486         break;
487     }
488   }
489 }
490 
scand(IJS_Context * cc,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)491 FX_BOOL util::scand(IJS_Context* cc,
492                     const std::vector<CJS_Value>& params,
493                     CJS_Value& vRet,
494                     CFX_WideString& sError) {
495   int iSize = params.size();
496   if (iSize < 2)
497     return FALSE;
498 
499   CFX_WideString sFormat = params[0].ToCFXWideString();
500   CFX_WideString sDate = params[1].ToCFXWideString();
501   double dDate = JS_GetDateTime();
502   if (sDate.GetLength() > 0) {
503     dDate = CJS_PublicMethods::MakeRegularDate(sDate, sFormat, nullptr);
504   }
505 
506   if (!JS_PortIsNan(dDate)) {
507     vRet = CJS_Date(CJS_Runtime::FromContext(cc), dDate);
508   } else {
509     vRet.SetNull();
510   }
511 
512   return TRUE;
513 }
514 
FX_atoi64(const char * nptr)515 int64_t FX_atoi64(const char* nptr) {
516   int c;         /* current char */
517   int64_t total; /* current total */
518   int sign;      /* if '-', then negative, otherwise positive */
519 
520   /* skip whitespace */
521   while (isspace((int)(unsigned char)*nptr))
522     ++nptr;
523 
524   c = (int)(unsigned char)*nptr++;
525   sign = c; /* save sign indication */
526   if (c == '-' || c == '+')
527     c = (int)(unsigned char)*nptr++; /* skip sign */
528 
529   total = 0;
530 
531   while (isdigit(c)) {
532     total = 10 * total + FXSYS_toDecimalDigit(c); /* accumulate digit */
533     c = (int)(unsigned char)*nptr++; /* get next char */
534   }
535 
536   return sign == '-' ? -total : total;
537 }
538 
byteToChar(IJS_Context * cc,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)539 FX_BOOL util::byteToChar(IJS_Context* cc,
540                          const std::vector<CJS_Value>& params,
541                          CJS_Value& vRet,
542                          CFX_WideString& sError) {
543   int iSize = params.size();
544   if (iSize == 0)
545     return FALSE;
546   int nByte = params[0].ToInt();
547   unsigned char cByte = (unsigned char)nByte;
548   CFX_WideString csValue;
549   csValue.Format(L"%c", cByte);
550   vRet = csValue.c_str();
551   return TRUE;
552 }
553