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