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
GetIsolate(IFXJS_Context * cc)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)
END_JS_STATIC_CONST()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
~util(void)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
ParstDataType(std::wstring * sFormat)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
printf(IFXJS_Context * cc,const CJS_Parameters & params,CJS_Value & vRet,CFX_WideString & sError)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
printd(IFXJS_Context * cc,const CJS_Parameters & params,CJS_Value & vRet,CFX_WideString & sError)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.c_str();
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(fcTable[iIndex].lpszJSMark, iStart)) != -1)
292 {
293 cFormat.replace(iEnd, FXSYS_wcslen(fcTable[iIndex].lpszJSMark), 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(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
printd(const std::wstring & cFormat2,CJS_Date jsDate,bool bXFAPicture,std::wstring & cPurpose)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(fcTable[iIndex].lpszJSMark, iStart)) != -1)
388 {
389 cFormat.replace(iEnd,FXSYS_wcslen(fcTable[iIndex].lpszJSMark), 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(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
printx(IFXJS_Context * cc,const CJS_Parameters & params,CJS_Value & vRet,CFX_WideString & sError)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
printx(const std::string & cFormat,const std::string & cSource2,std::string & cPurpose)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
scand(IFXJS_Context * cc,const CJS_Parameters & params,CJS_Value & vRet,CFX_WideString & sError)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
FX_atoi64(const char * nptr)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
byteToChar(IFXJS_Context * cc,const CJS_Parameters & params,CJS_Value & vRet,CFX_WideString & sError)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.c_str();
644 return TRUE;
645 }
646