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