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