• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/javascript/PublicMethods.h"
8 
9 #include <algorithm>
10 #include <iomanip>
11 #include <limits>
12 #include <sstream>
13 #include <string>
14 #include <vector>
15 
16 #include "core/fpdfdoc/cpdf_interform.h"
17 #include "core/fxcrt/fx_ext.h"
18 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
19 #include "fpdfsdk/cpdfsdk_interform.h"
20 #include "fpdfsdk/javascript/Field.h"
21 #include "fpdfsdk/javascript/JS_Define.h"
22 #include "fpdfsdk/javascript/JS_EventHandler.h"
23 #include "fpdfsdk/javascript/JS_Object.h"
24 #include "fpdfsdk/javascript/JS_Value.h"
25 #include "fpdfsdk/javascript/cjs_event_context.h"
26 #include "fpdfsdk/javascript/cjs_runtime.h"
27 #include "fpdfsdk/javascript/color.h"
28 #include "fpdfsdk/javascript/resource.h"
29 #include "fpdfsdk/javascript/util.h"
30 
31 #define DOUBLE_CORRECT 0.000000000000001
32 
33 JSMethodSpec CJS_PublicMethods::GlobalFunctionSpecs[] = {
34     {"AFNumber_Format", AFNumber_Format_static},
35     {"AFNumber_Keystroke", AFNumber_Keystroke_static},
36     {"AFPercent_Format", AFPercent_Format_static},
37     {"AFPercent_Keystroke", AFPercent_Keystroke_static},
38     {"AFDate_FormatEx", AFDate_FormatEx_static},
39     {"AFDate_KeystrokeEx", AFDate_KeystrokeEx_static},
40     {"AFDate_Format", AFDate_Format_static},
41     {"AFDate_Keystroke", AFDate_Keystroke_static},
42     {"AFTime_FormatEx", AFTime_FormatEx_static},
43     {"AFTime_KeystrokeEx", AFTime_KeystrokeEx_static},
44     {"AFTime_Format", AFTime_Format_static},
45     {"AFTime_Keystroke", AFTime_Keystroke_static},
46     {"AFSpecial_Format", AFSpecial_Format_static},
47     {"AFSpecial_Keystroke", AFSpecial_Keystroke_static},
48     {"AFSpecial_KeystrokeEx", AFSpecial_KeystrokeEx_static},
49     {"AFSimple", AFSimple_static},
50     {"AFMakeNumber", AFMakeNumber_static},
51     {"AFSimple_Calculate", AFSimple_Calculate_static},
52     {"AFRange_Validate", AFRange_Validate_static},
53     {"AFMergeChange", AFMergeChange_static},
54     {"AFParseDateEx", AFParseDateEx_static},
55     {"AFExtractNums", AFExtractNums_static},
56     {0, 0}};
57 
58 IMPLEMENT_JS_STATIC_GLOBAL_FUN(CJS_PublicMethods)
59 
60 namespace {
61 
62 const FX_WCHAR* const months[] = {L"Jan", L"Feb", L"Mar", L"Apr",
63                                   L"May", L"Jun", L"Jul", L"Aug",
64                                   L"Sep", L"Oct", L"Nov", L"Dec"};
65 
66 const FX_WCHAR* const fullmonths[] = {L"January", L"February", L"March",
67                                       L"April",   L"May",      L"June",
68                                       L"July",    L"August",   L"September",
69                                       L"October", L"November", L"December"};
70 
StrTrim(const CFX_ByteString & pStr)71 CFX_ByteString StrTrim(const CFX_ByteString& pStr) {
72   CFX_ByteString result(pStr);
73   result.TrimLeft(' ');
74   result.TrimRight(' ');
75   return result;
76 }
77 
StrTrim(const CFX_WideString & pStr)78 CFX_WideString StrTrim(const CFX_WideString& pStr) {
79   CFX_WideString result(pStr);
80   result.TrimLeft(' ');
81   result.TrimRight(' ');
82   return result;
83 }
84 
AlertIfPossible(CJS_EventContext * pContext,const FX_WCHAR * swMsg)85 void AlertIfPossible(CJS_EventContext* pContext, const FX_WCHAR* swMsg) {
86   CPDFSDK_FormFillEnvironment* pFormFillEnv = pContext->GetFormFillEnv();
87   if (pFormFillEnv)
88     pFormFillEnv->JS_appAlert(swMsg, nullptr, 0, 3);
89 }
90 
91 #if _FX_OS_ != _FX_ANDROID_
CalculateString(double dValue,int iDec,int * iDec2,bool * bNegative)92 CFX_ByteString CalculateString(double dValue,
93                                int iDec,
94                                int* iDec2,
95                                bool* bNegative) {
96   *bNegative = dValue < 0;
97   if (*bNegative)
98     dValue = -dValue;
99 
100   // Make sure the number of precision characters will fit.
101   if (iDec > std::numeric_limits<double>::digits10)
102     iDec = std::numeric_limits<double>::digits10;
103 
104   std::stringstream ss;
105   ss << std::fixed << std::setprecision(iDec) << dValue;
106   std::string stringValue = ss.str();
107   size_t iDecimalPos = stringValue.find(".");
108   *iDec2 = iDecimalPos == std::string::npos ? stringValue.size()
109                                             : static_cast<int>(iDecimalPos);
110   return CFX_ByteString(stringValue.c_str());
111 }
112 #endif
113 
114 }  // namespace
115 
IsNumber(const CFX_WideString & str)116 bool CJS_PublicMethods::IsNumber(const CFX_WideString& str) {
117   CFX_WideString sTrim = StrTrim(str);
118   const FX_WCHAR* pTrim = sTrim.c_str();
119   const FX_WCHAR* p = pTrim;
120   bool bDot = false;
121   bool bKXJS = false;
122 
123   wchar_t c;
124   while ((c = *p) != L'\0') {
125     if (c == L'.' || c == L',') {
126       if (bDot)
127         return false;
128       bDot = true;
129     } else if (c == L'-' || c == L'+') {
130       if (p != pTrim)
131         return false;
132     } else if (c == L'e' || c == L'E') {
133       if (bKXJS)
134         return false;
135 
136       p++;
137       c = *p;
138       if (c == L'+' || c == L'-') {
139         bKXJS = true;
140       } else {
141         return false;
142       }
143     } else if (!FXSYS_iswdigit(c)) {
144       return false;
145     }
146     p++;
147   }
148 
149   return true;
150 }
151 
maskSatisfied(wchar_t c_Change,wchar_t c_Mask)152 bool CJS_PublicMethods::maskSatisfied(wchar_t c_Change, wchar_t c_Mask) {
153   switch (c_Mask) {
154     case L'9':
155       return FXSYS_iswdigit(c_Change);
156     case L'A':
157       return FXSYS_iswalpha(c_Change);
158     case L'O':
159       return FXSYS_iswalnum(c_Change);
160     case L'X':
161       return true;
162     default:
163       return (c_Change == c_Mask);
164   }
165 }
166 
isReservedMaskChar(wchar_t ch)167 bool CJS_PublicMethods::isReservedMaskChar(wchar_t ch) {
168   return ch == L'9' || ch == L'A' || ch == L'O' || ch == L'X';
169 }
170 
AF_Simple(const FX_WCHAR * sFuction,double dValue1,double dValue2)171 double CJS_PublicMethods::AF_Simple(const FX_WCHAR* sFuction,
172                                     double dValue1,
173                                     double dValue2) {
174   if (FXSYS_wcsicmp(sFuction, L"AVG") == 0 ||
175       FXSYS_wcsicmp(sFuction, L"SUM") == 0) {
176     return dValue1 + dValue2;
177   }
178   if (FXSYS_wcsicmp(sFuction, L"PRD") == 0) {
179     return dValue1 * dValue2;
180   }
181   if (FXSYS_wcsicmp(sFuction, L"MIN") == 0) {
182     return std::min(dValue1, dValue2);
183   }
184   if (FXSYS_wcsicmp(sFuction, L"MAX") == 0) {
185     return std::max(dValue1, dValue2);
186   }
187   return dValue1;
188 }
189 
AF_MakeArrayFromList(CJS_Runtime * pRuntime,CJS_Value val)190 CJS_Array CJS_PublicMethods::AF_MakeArrayFromList(CJS_Runtime* pRuntime,
191                                                   CJS_Value val) {
192   CJS_Array StrArray;
193   if (val.IsArrayObject()) {
194     val.ConvertToArray(pRuntime, StrArray);
195     return StrArray;
196   }
197   CFX_WideString wsStr = val.ToCFXWideString(pRuntime);
198   CFX_ByteString t = CFX_ByteString::FromUnicode(wsStr);
199   const char* p = t.c_str();
200 
201   int ch = ',';
202   int nIndex = 0;
203 
204   while (*p) {
205     const char* pTemp = strchr(p, ch);
206     if (!pTemp) {
207       StrArray.SetElement(
208           pRuntime, nIndex,
209           CJS_Value(pRuntime, StrTrim(CFX_ByteString(p)).c_str()));
210       break;
211     }
212 
213     char* pSub = new char[pTemp - p + 1];
214     strncpy(pSub, p, pTemp - p);
215     *(pSub + (pTemp - p)) = '\0';
216 
217     StrArray.SetElement(
218         pRuntime, nIndex,
219         CJS_Value(pRuntime, StrTrim(CFX_ByteString(pSub)).c_str()));
220     delete[] pSub;
221 
222     nIndex++;
223     p = ++pTemp;
224   }
225   return StrArray;
226 }
227 
ParseStringInteger(const CFX_WideString & str,int nStart,int & nSkip,int nMaxStep)228 int CJS_PublicMethods::ParseStringInteger(const CFX_WideString& str,
229                                           int nStart,
230                                           int& nSkip,
231                                           int nMaxStep) {
232   int nRet = 0;
233   nSkip = 0;
234   for (int i = nStart, sz = str.GetLength(); i < sz; i++) {
235     if (i - nStart > 10)
236       break;
237 
238     FX_WCHAR c = str.GetAt(i);
239     if (!FXSYS_iswdigit(c))
240       break;
241 
242     nRet = nRet * 10 + FXSYS_toDecimalDigit(c);
243     nSkip = i - nStart + 1;
244     if (nSkip >= nMaxStep)
245       break;
246   }
247 
248   return nRet;
249 }
250 
ParseStringString(const CFX_WideString & str,int nStart,int & nSkip)251 CFX_WideString CJS_PublicMethods::ParseStringString(const CFX_WideString& str,
252                                                     int nStart,
253                                                     int& nSkip) {
254   CFX_WideString swRet;
255   nSkip = 0;
256   for (int i = nStart, sz = str.GetLength(); i < sz; i++) {
257     FX_WCHAR c = str.GetAt(i);
258     if (!FXSYS_iswdigit(c))
259       break;
260 
261     swRet += c;
262     nSkip = i - nStart + 1;
263   }
264 
265   return swRet;
266 }
267 
ParseNormalDate(const CFX_WideString & value,bool * bWrongFormat)268 double CJS_PublicMethods::ParseNormalDate(const CFX_WideString& value,
269                                           bool* bWrongFormat) {
270   double dt = JS_GetDateTime();
271 
272   int nYear = JS_GetYearFromTime(dt);
273   int nMonth = JS_GetMonthFromTime(dt) + 1;
274   int nDay = JS_GetDayFromTime(dt);
275   int nHour = JS_GetHourFromTime(dt);
276   int nMin = JS_GetMinFromTime(dt);
277   int nSec = JS_GetSecFromTime(dt);
278 
279   int number[3];
280 
281   int nSkip = 0;
282   int nLen = value.GetLength();
283   int nIndex = 0;
284   int i = 0;
285   while (i < nLen) {
286     if (nIndex > 2)
287       break;
288 
289     FX_WCHAR c = value.GetAt(i);
290     if (FXSYS_iswdigit(c)) {
291       number[nIndex++] = ParseStringInteger(value, i, nSkip, 4);
292       i += nSkip;
293     } else {
294       i++;
295     }
296   }
297 
298   if (nIndex == 2) {
299     // case2: month/day
300     // case3: day/month
301     if ((number[0] >= 1 && number[0] <= 12) &&
302         (number[1] >= 1 && number[1] <= 31)) {
303       nMonth = number[0];
304       nDay = number[1];
305     } else if ((number[0] >= 1 && number[0] <= 31) &&
306                (number[1] >= 1 && number[1] <= 12)) {
307       nDay = number[0];
308       nMonth = number[1];
309     }
310 
311     if (bWrongFormat)
312       *bWrongFormat = false;
313   } else if (nIndex == 3) {
314     // case1: year/month/day
315     // case2: month/day/year
316     // case3: day/month/year
317 
318     if (number[0] > 12 && (number[1] >= 1 && number[1] <= 12) &&
319         (number[2] >= 1 && number[2] <= 31)) {
320       nYear = number[0];
321       nMonth = number[1];
322       nDay = number[2];
323     } else if ((number[0] >= 1 && number[0] <= 12) &&
324                (number[1] >= 1 && number[1] <= 31) && number[2] > 31) {
325       nMonth = number[0];
326       nDay = number[1];
327       nYear = number[2];
328     } else if ((number[0] >= 1 && number[0] <= 31) &&
329                (number[1] >= 1 && number[1] <= 12) && number[2] > 31) {
330       nDay = number[0];
331       nMonth = number[1];
332       nYear = number[2];
333     }
334 
335     if (bWrongFormat)
336       *bWrongFormat = false;
337   } else {
338     if (bWrongFormat)
339       *bWrongFormat = true;
340     return dt;
341   }
342 
343   CFX_WideString swTemp;
344   swTemp.Format(L"%d/%d/%d %d:%d:%d", nMonth, nDay, nYear, nHour, nMin, nSec);
345   return JS_DateParse(swTemp);
346 }
347 
MakeRegularDate(const CFX_WideString & value,const CFX_WideString & format,bool * bWrongFormat)348 double CJS_PublicMethods::MakeRegularDate(const CFX_WideString& value,
349                                           const CFX_WideString& format,
350                                           bool* bWrongFormat) {
351   double dt = JS_GetDateTime();
352 
353   if (format.IsEmpty() || value.IsEmpty())
354     return dt;
355 
356   int nYear = JS_GetYearFromTime(dt);
357   int nMonth = JS_GetMonthFromTime(dt) + 1;
358   int nDay = JS_GetDayFromTime(dt);
359   int nHour = JS_GetHourFromTime(dt);
360   int nMin = JS_GetMinFromTime(dt);
361   int nSec = JS_GetSecFromTime(dt);
362 
363   int nYearSub = 99;  // nYear - 2000;
364 
365   bool bPm = false;
366   bool bExit = false;
367   bool bBadFormat = false;
368 
369   int i = 0;
370   int j = 0;
371 
372   while (i < format.GetLength()) {
373     if (bExit)
374       break;
375 
376     FX_WCHAR c = format.GetAt(i);
377     switch (c) {
378       case ':':
379       case '.':
380       case '-':
381       case '\\':
382       case '/':
383         i++;
384         j++;
385         break;
386 
387       case 'y':
388       case 'm':
389       case 'd':
390       case 'H':
391       case 'h':
392       case 'M':
393       case 's':
394       case 't': {
395         int oldj = j;
396         int nSkip = 0;
397         int remaining = format.GetLength() - i - 1;
398 
399         if (remaining == 0 || format.GetAt(i + 1) != c) {
400           switch (c) {
401             case 'y':
402               i++;
403               j++;
404               break;
405             case 'm':
406               nMonth = ParseStringInteger(value, j, nSkip, 2);
407               i++;
408               j += nSkip;
409               break;
410             case 'd':
411               nDay = ParseStringInteger(value, j, nSkip, 2);
412               i++;
413               j += nSkip;
414               break;
415             case 'H':
416               nHour = ParseStringInteger(value, j, nSkip, 2);
417               i++;
418               j += nSkip;
419               break;
420             case 'h':
421               nHour = ParseStringInteger(value, j, nSkip, 2);
422               i++;
423               j += nSkip;
424               break;
425             case 'M':
426               nMin = ParseStringInteger(value, j, nSkip, 2);
427               i++;
428               j += nSkip;
429               break;
430             case 's':
431               nSec = ParseStringInteger(value, j, nSkip, 2);
432               i++;
433               j += nSkip;
434               break;
435             case 't':
436               bPm = (j < value.GetLength() && value.GetAt(j) == 'p');
437               i++;
438               j++;
439               break;
440           }
441         } else if (remaining == 1 || format.GetAt(i + 2) != c) {
442           switch (c) {
443             case 'y':
444               nYear = ParseStringInteger(value, j, nSkip, 4);
445               i += 2;
446               j += nSkip;
447               break;
448             case 'm':
449               nMonth = ParseStringInteger(value, j, nSkip, 2);
450               i += 2;
451               j += nSkip;
452               break;
453             case 'd':
454               nDay = ParseStringInteger(value, j, nSkip, 2);
455               i += 2;
456               j += nSkip;
457               break;
458             case 'H':
459               nHour = ParseStringInteger(value, j, nSkip, 2);
460               i += 2;
461               j += nSkip;
462               break;
463             case 'h':
464               nHour = ParseStringInteger(value, j, nSkip, 2);
465               i += 2;
466               j += nSkip;
467               break;
468             case 'M':
469               nMin = ParseStringInteger(value, j, nSkip, 2);
470               i += 2;
471               j += nSkip;
472               break;
473             case 's':
474               nSec = ParseStringInteger(value, j, nSkip, 2);
475               i += 2;
476               j += nSkip;
477               break;
478             case 't':
479               bPm = (j + 1 < value.GetLength() && value.GetAt(j) == 'p' &&
480                      value.GetAt(j + 1) == 'm');
481               i += 2;
482               j += 2;
483               break;
484           }
485         } else if (remaining == 2 || format.GetAt(i + 3) != c) {
486           switch (c) {
487             case 'm': {
488               CFX_WideString sMonth = ParseStringString(value, j, nSkip);
489               bool bFind = false;
490               for (int m = 0; m < 12; m++) {
491                 if (sMonth.CompareNoCase(months[m]) == 0) {
492                   nMonth = m + 1;
493                   i += 3;
494                   j += nSkip;
495                   bFind = true;
496                   break;
497                 }
498               }
499 
500               if (!bFind) {
501                 nMonth = ParseStringInteger(value, j, nSkip, 3);
502                 i += 3;
503                 j += nSkip;
504               }
505             } break;
506             case 'y':
507               break;
508             default:
509               i += 3;
510               j += 3;
511               break;
512           }
513         } else if (remaining == 3 || format.GetAt(i + 4) != c) {
514           switch (c) {
515             case 'y':
516               nYear = ParseStringInteger(value, j, nSkip, 4);
517               j += nSkip;
518               i += 4;
519               break;
520             case 'm': {
521               bool bFind = false;
522 
523               CFX_WideString sMonth = ParseStringString(value, j, nSkip);
524               sMonth.MakeLower();
525 
526               for (int m = 0; m < 12; m++) {
527                 CFX_WideString sFullMonths = fullmonths[m];
528                 sFullMonths.MakeLower();
529 
530                 if (sFullMonths.Find(sMonth.c_str(), 0) != -1) {
531                   nMonth = m + 1;
532                   i += 4;
533                   j += nSkip;
534                   bFind = true;
535                   break;
536                 }
537               }
538 
539               if (!bFind) {
540                 nMonth = ParseStringInteger(value, j, nSkip, 4);
541                 i += 4;
542                 j += nSkip;
543               }
544             } break;
545             default:
546               i += 4;
547               j += 4;
548               break;
549           }
550         } else {
551           if (j >= value.GetLength() || format.GetAt(i) != value.GetAt(j)) {
552             bBadFormat = true;
553             bExit = true;
554           }
555           i++;
556           j++;
557         }
558 
559         if (oldj == j) {
560           bBadFormat = true;
561           bExit = true;
562         }
563       }
564 
565       break;
566       default:
567         if (value.GetLength() <= j) {
568           bExit = true;
569         } else if (format.GetAt(i) != value.GetAt(j)) {
570           bBadFormat = true;
571           bExit = true;
572         }
573 
574         i++;
575         j++;
576         break;
577     }
578   }
579 
580   if (bPm)
581     nHour += 12;
582 
583   if (nYear >= 0 && nYear <= nYearSub)
584     nYear += 2000;
585 
586   if (nMonth < 1 || nMonth > 12)
587     bBadFormat = true;
588 
589   if (nDay < 1 || nDay > 31)
590     bBadFormat = true;
591 
592   if (nHour < 0 || nHour > 24)
593     bBadFormat = true;
594 
595   if (nMin < 0 || nMin > 60)
596     bBadFormat = true;
597 
598   if (nSec < 0 || nSec > 60)
599     bBadFormat = true;
600 
601   double dRet = 0;
602   if (bBadFormat) {
603     dRet = ParseNormalDate(value, &bBadFormat);
604   } else {
605     dRet = JS_MakeDate(JS_MakeDay(nYear, nMonth - 1, nDay),
606                        JS_MakeTime(nHour, nMin, nSec, 0));
607     if (JS_PortIsNan(dRet))
608       dRet = JS_DateParse(value);
609   }
610 
611   if (JS_PortIsNan(dRet))
612     dRet = ParseNormalDate(value, &bBadFormat);
613 
614   if (bWrongFormat)
615     *bWrongFormat = bBadFormat;
616 
617   return dRet;
618 }
619 
MakeFormatDate(double dDate,const CFX_WideString & format)620 CFX_WideString CJS_PublicMethods::MakeFormatDate(double dDate,
621                                                  const CFX_WideString& format) {
622   CFX_WideString sRet = L"", sPart = L"";
623 
624   int nYear = JS_GetYearFromTime(dDate);
625   int nMonth = JS_GetMonthFromTime(dDate) + 1;
626   int nDay = JS_GetDayFromTime(dDate);
627   int nHour = JS_GetHourFromTime(dDate);
628   int nMin = JS_GetMinFromTime(dDate);
629   int nSec = JS_GetSecFromTime(dDate);
630 
631   int i = 0;
632   while (i < format.GetLength()) {
633     FX_WCHAR c = format.GetAt(i);
634     int remaining = format.GetLength() - i - 1;
635     sPart = L"";
636     switch (c) {
637       case 'y':
638       case 'm':
639       case 'd':
640       case 'H':
641       case 'h':
642       case 'M':
643       case 's':
644       case 't':
645         if (remaining == 0 || format.GetAt(i + 1) != c) {
646           switch (c) {
647             case 'y':
648               sPart += c;
649               break;
650             case 'm':
651               sPart.Format(L"%d", nMonth);
652               break;
653             case 'd':
654               sPart.Format(L"%d", nDay);
655               break;
656             case 'H':
657               sPart.Format(L"%d", nHour);
658               break;
659             case 'h':
660               sPart.Format(L"%d", nHour > 12 ? nHour - 12 : nHour);
661               break;
662             case 'M':
663               sPart.Format(L"%d", nMin);
664               break;
665             case 's':
666               sPart.Format(L"%d", nSec);
667               break;
668             case 't':
669               sPart += nHour > 12 ? 'p' : 'a';
670               break;
671           }
672           i++;
673         } else if (remaining == 1 || format.GetAt(i + 2) != c) {
674           switch (c) {
675             case 'y':
676               sPart.Format(L"%02d", nYear - (nYear / 100) * 100);
677               break;
678             case 'm':
679               sPart.Format(L"%02d", nMonth);
680               break;
681             case 'd':
682               sPart.Format(L"%02d", nDay);
683               break;
684             case 'H':
685               sPart.Format(L"%02d", nHour);
686               break;
687             case 'h':
688               sPart.Format(L"%02d", nHour > 12 ? nHour - 12 : nHour);
689               break;
690             case 'M':
691               sPart.Format(L"%02d", nMin);
692               break;
693             case 's':
694               sPart.Format(L"%02d", nSec);
695               break;
696             case 't':
697               sPart = nHour > 12 ? L"pm" : L"am";
698               break;
699           }
700           i += 2;
701         } else if (remaining == 2 || format.GetAt(i + 3) != c) {
702           switch (c) {
703             case 'm':
704               i += 3;
705               if (nMonth > 0 && nMonth <= 12)
706                 sPart += months[nMonth - 1];
707               break;
708             default:
709               i += 3;
710               sPart += c;
711               sPart += c;
712               sPart += c;
713               break;
714           }
715         } else if (remaining == 3 || format.GetAt(i + 4) != c) {
716           switch (c) {
717             case 'y':
718               sPart.Format(L"%04d", nYear);
719               i += 4;
720               break;
721             case 'm':
722               i += 4;
723               if (nMonth > 0 && nMonth <= 12)
724                 sPart += fullmonths[nMonth - 1];
725               break;
726             default:
727               i += 4;
728               sPart += c;
729               sPart += c;
730               sPart += c;
731               sPart += c;
732               break;
733           }
734         } else {
735           i++;
736           sPart += c;
737         }
738         break;
739       default:
740         i++;
741         sPart += c;
742         break;
743     }
744 
745     sRet += sPart;
746   }
747 
748   return sRet;
749 }
750 
751 // function AFNumber_Format(nDec, sepStyle, negStyle, currStyle, strCurrency,
752 // bCurrencyPrepend)
AFNumber_Format(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)753 bool CJS_PublicMethods::AFNumber_Format(CJS_Runtime* pRuntime,
754                                         const std::vector<CJS_Value>& params,
755                                         CJS_Value& vRet,
756                                         CFX_WideString& sError) {
757 #if _FX_OS_ != _FX_ANDROID_
758   if (params.size() != 6) {
759     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
760     return false;
761   }
762 
763   CJS_EventHandler* pEvent =
764       pRuntime->GetCurrentEventContext()->GetEventHandler();
765   if (!pEvent->m_pValue)
766     return false;
767 
768   CFX_WideString& Value = pEvent->Value();
769   CFX_ByteString strValue = StrTrim(CFX_ByteString::FromUnicode(Value));
770   if (strValue.IsEmpty())
771     return true;
772 
773   int iDec = params[0].ToInt(pRuntime);
774   int iSepStyle = params[1].ToInt(pRuntime);
775   int iNegStyle = params[2].ToInt(pRuntime);
776   // params[3] is iCurrStyle, it's not used.
777   CFX_WideString wstrCurrency = params[4].ToCFXWideString(pRuntime);
778   bool bCurrencyPrepend = params[5].ToBool(pRuntime);
779 
780   if (iDec < 0)
781     iDec = -iDec;
782 
783   if (iSepStyle < 0 || iSepStyle > 3)
784     iSepStyle = 0;
785 
786   if (iNegStyle < 0 || iNegStyle > 3)
787     iNegStyle = 0;
788 
789   // Processing decimal places
790   strValue.Replace(",", ".");
791   double dValue = atof(strValue.c_str());
792   if (iDec > 0)
793     dValue += DOUBLE_CORRECT;
794 
795   // Calculating number string
796   bool bNegative;
797   int iDec2;
798   strValue = CalculateString(dValue, iDec, &iDec2, &bNegative);
799   if (strValue.IsEmpty()) {
800     dValue = 0;
801     strValue = CalculateString(dValue, iDec, &iDec2, &bNegative);
802     if (strValue.IsEmpty()) {
803       strValue = "0";
804       iDec2 = 1;
805     }
806   }
807 
808   // Processing separator style
809   if (iDec2 < strValue.GetLength()) {
810     if (iSepStyle == 2 || iSepStyle == 3)
811       strValue.Replace(".", ",");
812 
813     if (iDec2 == 0)
814       strValue.Insert(iDec2, '0');
815   }
816   if (iSepStyle == 0 || iSepStyle == 2) {
817     char cSeparator;
818     if (iSepStyle == 0)
819       cSeparator = ',';
820     else
821       cSeparator = '.';
822 
823     for (int iDecPositive = iDec2 - 3; iDecPositive > 0; iDecPositive -= 3)
824       strValue.Insert(iDecPositive, cSeparator);
825   }
826 
827   // Processing currency string
828   Value = CFX_WideString::FromLocal(strValue.AsStringC());
829 
830   if (bCurrencyPrepend)
831     Value = wstrCurrency + Value;
832   else
833     Value = Value + wstrCurrency;
834 
835   // Processing negative style
836   if (bNegative) {
837     if (iNegStyle == 0)
838       Value = L"-" + Value;
839     else if (iNegStyle == 2 || iNegStyle == 3)
840       Value = L"(" + Value + L")";
841     if (iNegStyle == 1 || iNegStyle == 3) {
842       if (Field* fTarget = pEvent->Target_Field()) {
843         CJS_Array arColor;
844         CJS_Value vColElm(pRuntime);
845         vColElm = CJS_Value(pRuntime, L"RGB");
846         arColor.SetElement(pRuntime, 0, vColElm);
847         vColElm = CJS_Value(pRuntime, 1);
848         arColor.SetElement(pRuntime, 1, vColElm);
849         vColElm = CJS_Value(pRuntime, 0);
850         arColor.SetElement(pRuntime, 2, vColElm);
851         arColor.SetElement(pRuntime, 3, vColElm);
852 
853         CJS_PropValue vProp(pRuntime);
854         vProp.StartGetting();
855         vProp << arColor;
856         vProp.StartSetting();
857         fTarget->textColor(pRuntime, vProp, sError);  // red
858       }
859     }
860   } else {
861     if (iNegStyle == 1 || iNegStyle == 3) {
862       if (Field* fTarget = pEvent->Target_Field()) {
863         CJS_Array arColor;
864         CJS_Value vColElm(pRuntime);
865         vColElm = CJS_Value(pRuntime, L"RGB");
866         arColor.SetElement(pRuntime, 0, vColElm);
867         vColElm = CJS_Value(pRuntime, 0);
868         arColor.SetElement(pRuntime, 1, vColElm);
869         arColor.SetElement(pRuntime, 2, vColElm);
870         arColor.SetElement(pRuntime, 3, vColElm);
871 
872         CJS_PropValue vProp(pRuntime);
873         vProp.StartGetting();
874         fTarget->textColor(pRuntime, vProp, sError);
875 
876         CJS_Array aProp;
877         vProp.GetJSValue()->ConvertToArray(pRuntime, aProp);
878 
879         CPWL_Color crProp;
880         CPWL_Color crColor;
881         color::ConvertArrayToPWLColor(pRuntime, aProp, &crProp);
882         color::ConvertArrayToPWLColor(pRuntime, arColor, &crColor);
883 
884         if (crColor != crProp) {
885           CJS_PropValue vProp2(pRuntime);
886           vProp2.StartGetting();
887           vProp2 << arColor;
888           vProp2.StartSetting();
889           fTarget->textColor(pRuntime, vProp2, sError);
890         }
891       }
892     }
893   }
894 #endif
895   return true;
896 }
897 
898 // function AFNumber_Keystroke(nDec, sepStyle, negStyle, currStyle, strCurrency,
899 // bCurrencyPrepend)
AFNumber_Keystroke(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)900 bool CJS_PublicMethods::AFNumber_Keystroke(CJS_Runtime* pRuntime,
901                                            const std::vector<CJS_Value>& params,
902                                            CJS_Value& vRet,
903                                            CFX_WideString& sError) {
904   if (params.size() < 2)
905     return false;
906 
907   CJS_EventContext* pContext = pRuntime->GetCurrentEventContext();
908   CJS_EventHandler* pEvent = pContext->GetEventHandler();
909   if (!pEvent->m_pValue)
910     return false;
911 
912   CFX_WideString& val = pEvent->Value();
913   CFX_WideString& wstrChange = pEvent->Change();
914   CFX_WideString wstrValue = val;
915 
916   if (pEvent->WillCommit()) {
917     CFX_WideString swTemp = StrTrim(wstrValue);
918     if (swTemp.IsEmpty())
919       return true;
920 
921     swTemp.Replace(L",", L".");
922     if (!IsNumber(swTemp.c_str())) {
923       pEvent->Rc() = false;
924       sError = JSGetStringFromID(IDS_STRING_JSAFNUMBER_KEYSTROKE);
925       AlertIfPossible(pContext, sError.c_str());
926     }
927     return true;  // it happens after the last keystroke and before validating,
928   }
929 
930   CFX_WideString wstrSelected;
931   if (pEvent->SelStart() != -1) {
932     wstrSelected = wstrValue.Mid(pEvent->SelStart(),
933                                  pEvent->SelEnd() - pEvent->SelStart());
934   }
935 
936   bool bHasSign = wstrValue.Find(L'-') != -1 && wstrSelected.Find(L'-') == -1;
937   if (bHasSign) {
938     // can't insert "change" in front to sign postion.
939     if (pEvent->SelStart() == 0) {
940       bool& bRc = pEvent->Rc();
941       bRc = false;
942       return true;
943     }
944   }
945 
946   int iSepStyle = params[1].ToInt(pRuntime);
947   if (iSepStyle < 0 || iSepStyle > 3)
948     iSepStyle = 0;
949   const FX_WCHAR cSep = iSepStyle < 2 ? L'.' : L',';
950 
951   bool bHasSep = wstrValue.Find(cSep) != -1;
952   for (FX_STRSIZE i = 0; i < wstrChange.GetLength(); ++i) {
953     if (wstrChange[i] == cSep) {
954       if (bHasSep) {
955         bool& bRc = pEvent->Rc();
956         bRc = false;
957         return true;
958       }
959       bHasSep = true;
960       continue;
961     }
962     if (wstrChange[i] == L'-') {
963       if (bHasSign) {
964         bool& bRc = pEvent->Rc();
965         bRc = false;
966         return true;
967       }
968       // sign's position is not correct
969       if (i != 0) {
970         bool& bRc = pEvent->Rc();
971         bRc = false;
972         return true;
973       }
974       if (pEvent->SelStart() != 0) {
975         bool& bRc = pEvent->Rc();
976         bRc = false;
977         return true;
978       }
979       bHasSign = true;
980       continue;
981     }
982 
983     if (!FXSYS_iswdigit(wstrChange[i])) {
984       bool& bRc = pEvent->Rc();
985       bRc = false;
986       return true;
987     }
988   }
989 
990   CFX_WideString wprefix = wstrValue.Mid(0, pEvent->SelStart());
991   CFX_WideString wpostfix;
992   if (pEvent->SelEnd() < wstrValue.GetLength())
993     wpostfix = wstrValue.Mid(pEvent->SelEnd());
994   val = wprefix + wstrChange + wpostfix;
995   return true;
996 }
997 
998 // function AFPercent_Format(nDec, sepStyle)
AFPercent_Format(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)999 bool CJS_PublicMethods::AFPercent_Format(CJS_Runtime* pRuntime,
1000                                          const std::vector<CJS_Value>& params,
1001                                          CJS_Value& vRet,
1002                                          CFX_WideString& sError) {
1003 #if _FX_OS_ != _FX_ANDROID_
1004   if (params.size() != 2) {
1005     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
1006     return false;
1007   }
1008 
1009   CJS_EventHandler* pEvent =
1010       pRuntime->GetCurrentEventContext()->GetEventHandler();
1011   if (!pEvent->m_pValue)
1012     return false;
1013 
1014   CFX_WideString& Value = pEvent->Value();
1015   CFX_ByteString strValue = StrTrim(CFX_ByteString::FromUnicode(Value));
1016   if (strValue.IsEmpty())
1017     return true;
1018 
1019   int iDec = params[0].ToInt(pRuntime);
1020   if (iDec < 0)
1021     iDec = -iDec;
1022 
1023   int iSepStyle = params[1].ToInt(pRuntime);
1024   if (iSepStyle < 0 || iSepStyle > 3)
1025     iSepStyle = 0;
1026 
1027   // for processing decimal places
1028   double dValue = atof(strValue.c_str());
1029   dValue *= 100;
1030   if (iDec > 0)
1031     dValue += DOUBLE_CORRECT;
1032 
1033   int iDec2;
1034   int iNegative = 0;
1035   strValue = fcvt(dValue, iDec, &iDec2, &iNegative);
1036   if (strValue.IsEmpty()) {
1037     dValue = 0;
1038     strValue = fcvt(dValue, iDec, &iDec2, &iNegative);
1039   }
1040 
1041   if (iDec2 < 0) {
1042     for (int iNum = 0; iNum < abs(iDec2); iNum++) {
1043       strValue = "0" + strValue;
1044     }
1045     iDec2 = 0;
1046   }
1047   int iMax = strValue.GetLength();
1048   if (iDec2 > iMax) {
1049     for (int iNum = 0; iNum <= iDec2 - iMax; iNum++) {
1050       strValue += "0";
1051     }
1052     iMax = iDec2 + 1;
1053   }
1054 
1055   // for processing seperator style
1056   if (iDec2 < iMax) {
1057     if (iSepStyle == 0 || iSepStyle == 1) {
1058       strValue.Insert(iDec2, '.');
1059       iMax++;
1060     } else if (iSepStyle == 2 || iSepStyle == 3) {
1061       strValue.Insert(iDec2, ',');
1062       iMax++;
1063     }
1064 
1065     if (iDec2 == 0)
1066       strValue.Insert(iDec2, '0');
1067   }
1068   if (iSepStyle == 0 || iSepStyle == 2) {
1069     char cSeperator;
1070     if (iSepStyle == 0)
1071       cSeperator = ',';
1072     else
1073       cSeperator = '.';
1074 
1075     for (int iDecPositive = iDec2 - 3; iDecPositive > 0; iDecPositive -= 3) {
1076       strValue.Insert(iDecPositive, cSeperator);
1077       iMax++;
1078     }
1079   }
1080 
1081   // negative mark
1082   if (iNegative)
1083     strValue = "-" + strValue;
1084   strValue += "%";
1085   Value = CFX_WideString::FromLocal(strValue.AsStringC());
1086 #endif
1087   return true;
1088 }
1089 // AFPercent_Keystroke(nDec, sepStyle)
AFPercent_Keystroke(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)1090 bool CJS_PublicMethods::AFPercent_Keystroke(
1091     CJS_Runtime* pRuntime,
1092     const std::vector<CJS_Value>& params,
1093     CJS_Value& vRet,
1094     CFX_WideString& sError) {
1095   return AFNumber_Keystroke(pRuntime, params, vRet, sError);
1096 }
1097 
1098 // function AFDate_FormatEx(cFormat)
AFDate_FormatEx(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)1099 bool CJS_PublicMethods::AFDate_FormatEx(CJS_Runtime* pRuntime,
1100                                         const std::vector<CJS_Value>& params,
1101                                         CJS_Value& vRet,
1102                                         CFX_WideString& sError) {
1103   if (params.size() != 1) {
1104     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
1105     return false;
1106   }
1107 
1108   CJS_EventContext* pContext = pRuntime->GetCurrentEventContext();
1109   CJS_EventHandler* pEvent = pContext->GetEventHandler();
1110   if (!pEvent->m_pValue)
1111     return false;
1112 
1113   CFX_WideString& val = pEvent->Value();
1114   CFX_WideString strValue = val;
1115   if (strValue.IsEmpty())
1116     return true;
1117 
1118   CFX_WideString sFormat = params[0].ToCFXWideString(pRuntime);
1119   double dDate = 0.0f;
1120 
1121   if (strValue.Find(L"GMT") != -1) {
1122     // for GMT format time
1123     // such as "Tue Aug 11 14:24:16 GMT+08002009"
1124     dDate = MakeInterDate(strValue);
1125   } else {
1126     dDate = MakeRegularDate(strValue, sFormat, nullptr);
1127   }
1128 
1129   if (JS_PortIsNan(dDate)) {
1130     CFX_WideString swMsg;
1131     swMsg.Format(JSGetStringFromID(IDS_STRING_JSPARSEDATE).c_str(),
1132                  sFormat.c_str());
1133     AlertIfPossible(pContext, swMsg.c_str());
1134     return false;
1135   }
1136 
1137   val = MakeFormatDate(dDate, sFormat);
1138   return true;
1139 }
1140 
MakeInterDate(const CFX_WideString & strValue)1141 double CJS_PublicMethods::MakeInterDate(const CFX_WideString& strValue) {
1142   std::vector<CFX_WideString> wsArray;
1143   CFX_WideString sTemp = L"";
1144   for (int i = 0; i < strValue.GetLength(); ++i) {
1145     FX_WCHAR c = strValue.GetAt(i);
1146     if (c == L' ' || c == L':') {
1147       wsArray.push_back(sTemp);
1148       sTemp = L"";
1149       continue;
1150     }
1151     sTemp += c;
1152   }
1153   wsArray.push_back(sTemp);
1154   if (wsArray.size() != 8)
1155     return 0;
1156 
1157   int nMonth = 1;
1158   sTemp = wsArray[1];
1159   if (sTemp.Compare(L"Jan") == 0)
1160     nMonth = 1;
1161   else if (sTemp.Compare(L"Feb") == 0)
1162     nMonth = 2;
1163   else if (sTemp.Compare(L"Mar") == 0)
1164     nMonth = 3;
1165   else if (sTemp.Compare(L"Apr") == 0)
1166     nMonth = 4;
1167   else if (sTemp.Compare(L"May") == 0)
1168     nMonth = 5;
1169   else if (sTemp.Compare(L"Jun") == 0)
1170     nMonth = 6;
1171   else if (sTemp.Compare(L"Jul") == 0)
1172     nMonth = 7;
1173   else if (sTemp.Compare(L"Aug") == 0)
1174     nMonth = 8;
1175   else if (sTemp.Compare(L"Sep") == 0)
1176     nMonth = 9;
1177   else if (sTemp.Compare(L"Oct") == 0)
1178     nMonth = 10;
1179   else if (sTemp.Compare(L"Nov") == 0)
1180     nMonth = 11;
1181   else if (sTemp.Compare(L"Dec") == 0)
1182     nMonth = 12;
1183 
1184   int nDay = FX_atof(wsArray[2].AsStringC());
1185   int nHour = FX_atof(wsArray[3].AsStringC());
1186   int nMin = FX_atof(wsArray[4].AsStringC());
1187   int nSec = FX_atof(wsArray[5].AsStringC());
1188   int nYear = FX_atof(wsArray[7].AsStringC());
1189   double dRet = JS_MakeDate(JS_MakeDay(nYear, nMonth - 1, nDay),
1190                             JS_MakeTime(nHour, nMin, nSec, 0));
1191   if (JS_PortIsNan(dRet))
1192     dRet = JS_DateParse(strValue);
1193 
1194   return dRet;
1195 }
1196 
1197 // AFDate_KeystrokeEx(cFormat)
AFDate_KeystrokeEx(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)1198 bool CJS_PublicMethods::AFDate_KeystrokeEx(CJS_Runtime* pRuntime,
1199                                            const std::vector<CJS_Value>& params,
1200                                            CJS_Value& vRet,
1201                                            CFX_WideString& sError) {
1202   if (params.size() != 1) {
1203     sError = L"AFDate_KeystrokeEx's parameters' size r not correct";
1204     return false;
1205   }
1206 
1207   CJS_EventContext* pContext = pRuntime->GetCurrentEventContext();
1208   CJS_EventHandler* pEvent = pContext->GetEventHandler();
1209   if (pEvent->WillCommit()) {
1210     if (!pEvent->m_pValue)
1211       return false;
1212 
1213     CFX_WideString strValue = pEvent->Value();
1214     if (strValue.IsEmpty())
1215       return true;
1216 
1217     CFX_WideString sFormat = params[0].ToCFXWideString(pRuntime);
1218     bool bWrongFormat = false;
1219     double dRet = MakeRegularDate(strValue, sFormat, &bWrongFormat);
1220     if (bWrongFormat || JS_PortIsNan(dRet)) {
1221       CFX_WideString swMsg;
1222       swMsg.Format(JSGetStringFromID(IDS_STRING_JSPARSEDATE).c_str(),
1223                    sFormat.c_str());
1224       AlertIfPossible(pContext, swMsg.c_str());
1225       pEvent->Rc() = false;
1226       return true;
1227     }
1228   }
1229   return true;
1230 }
1231 
AFDate_Format(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)1232 bool CJS_PublicMethods::AFDate_Format(CJS_Runtime* pRuntime,
1233                                       const std::vector<CJS_Value>& params,
1234                                       CJS_Value& vRet,
1235                                       CFX_WideString& sError) {
1236   if (params.size() != 1) {
1237     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
1238     return false;
1239   }
1240 
1241   int iIndex = params[0].ToInt(pRuntime);
1242   const FX_WCHAR* cFormats[] = {L"m/d",
1243                                 L"m/d/yy",
1244                                 L"mm/dd/yy",
1245                                 L"mm/yy",
1246                                 L"d-mmm",
1247                                 L"d-mmm-yy",
1248                                 L"dd-mmm-yy",
1249                                 L"yy-mm-dd",
1250                                 L"mmm-yy",
1251                                 L"mmmm-yy",
1252                                 L"mmm d, yyyy",
1253                                 L"mmmm d, yyyy",
1254                                 L"m/d/yy h:MM tt",
1255                                 L"m/d/yy HH:MM"};
1256 
1257   if (iIndex < 0 || (static_cast<size_t>(iIndex) >= FX_ArraySize(cFormats)))
1258     iIndex = 0;
1259 
1260   std::vector<CJS_Value> newParams;
1261   newParams.push_back(CJS_Value(pRuntime, cFormats[iIndex]));
1262   return AFDate_FormatEx(pRuntime, newParams, vRet, sError);
1263 }
1264 
1265 // AFDate_KeystrokeEx(cFormat)
AFDate_Keystroke(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)1266 bool CJS_PublicMethods::AFDate_Keystroke(CJS_Runtime* pRuntime,
1267                                          const std::vector<CJS_Value>& params,
1268                                          CJS_Value& vRet,
1269                                          CFX_WideString& sError) {
1270   if (params.size() != 1) {
1271     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
1272     return false;
1273   }
1274 
1275   int iIndex = params[0].ToInt(pRuntime);
1276   const FX_WCHAR* cFormats[] = {L"m/d",
1277                                 L"m/d/yy",
1278                                 L"mm/dd/yy",
1279                                 L"mm/yy",
1280                                 L"d-mmm",
1281                                 L"d-mmm-yy",
1282                                 L"dd-mmm-yy",
1283                                 L"yy-mm-dd",
1284                                 L"mmm-yy",
1285                                 L"mmmm-yy",
1286                                 L"mmm d, yyyy",
1287                                 L"mmmm d, yyyy",
1288                                 L"m/d/yy h:MM tt",
1289                                 L"m/d/yy HH:MM"};
1290 
1291   if (iIndex < 0 || (static_cast<size_t>(iIndex) >= FX_ArraySize(cFormats)))
1292     iIndex = 0;
1293 
1294   std::vector<CJS_Value> newParams;
1295   newParams.push_back(CJS_Value(pRuntime, cFormats[iIndex]));
1296   return AFDate_KeystrokeEx(pRuntime, newParams, vRet, sError);
1297 }
1298 
1299 // function AFTime_Format(ptf)
AFTime_Format(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)1300 bool CJS_PublicMethods::AFTime_Format(CJS_Runtime* pRuntime,
1301                                       const std::vector<CJS_Value>& params,
1302                                       CJS_Value& vRet,
1303                                       CFX_WideString& sError) {
1304   if (params.size() != 1) {
1305     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
1306     return false;
1307   }
1308 
1309   int iIndex = params[0].ToInt(pRuntime);
1310   const FX_WCHAR* cFormats[] = {L"HH:MM", L"h:MM tt", L"HH:MM:ss",
1311                                 L"h:MM:ss tt"};
1312 
1313   if (iIndex < 0 || (static_cast<size_t>(iIndex) >= FX_ArraySize(cFormats)))
1314     iIndex = 0;
1315 
1316   std::vector<CJS_Value> newParams;
1317   newParams.push_back(CJS_Value(pRuntime, cFormats[iIndex]));
1318   return AFDate_FormatEx(pRuntime, newParams, vRet, sError);
1319 }
1320 
AFTime_Keystroke(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)1321 bool CJS_PublicMethods::AFTime_Keystroke(CJS_Runtime* pRuntime,
1322                                          const std::vector<CJS_Value>& params,
1323                                          CJS_Value& vRet,
1324                                          CFX_WideString& sError) {
1325   if (params.size() != 1) {
1326     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
1327     return false;
1328   }
1329 
1330   int iIndex = params[0].ToInt(pRuntime);
1331   const FX_WCHAR* cFormats[] = {L"HH:MM", L"h:MM tt", L"HH:MM:ss",
1332                                 L"h:MM:ss tt"};
1333 
1334   if (iIndex < 0 || (static_cast<size_t>(iIndex) >= FX_ArraySize(cFormats)))
1335     iIndex = 0;
1336 
1337   std::vector<CJS_Value> newParams;
1338   newParams.push_back(CJS_Value(pRuntime, cFormats[iIndex]));
1339   return AFDate_KeystrokeEx(pRuntime, newParams, vRet, sError);
1340 }
1341 
AFTime_FormatEx(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)1342 bool CJS_PublicMethods::AFTime_FormatEx(CJS_Runtime* pRuntime,
1343                                         const std::vector<CJS_Value>& params,
1344                                         CJS_Value& vRet,
1345                                         CFX_WideString& sError) {
1346   return AFDate_FormatEx(pRuntime, params, vRet, sError);
1347 }
1348 
AFTime_KeystrokeEx(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)1349 bool CJS_PublicMethods::AFTime_KeystrokeEx(CJS_Runtime* pRuntime,
1350                                            const std::vector<CJS_Value>& params,
1351                                            CJS_Value& vRet,
1352                                            CFX_WideString& sError) {
1353   return AFDate_KeystrokeEx(pRuntime, params, vRet, sError);
1354 }
1355 
1356 // function AFSpecial_Format(psf)
AFSpecial_Format(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)1357 bool CJS_PublicMethods::AFSpecial_Format(CJS_Runtime* pRuntime,
1358                                          const std::vector<CJS_Value>& params,
1359                                          CJS_Value& vRet,
1360                                          CFX_WideString& sError) {
1361   if (params.size() != 1) {
1362     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
1363     return false;
1364   }
1365 
1366   CJS_EventHandler* pEvent =
1367       pRuntime->GetCurrentEventContext()->GetEventHandler();
1368   if (!pEvent->m_pValue)
1369     return false;
1370 
1371   CFX_WideString wsSource = pEvent->Value();
1372   CFX_WideString wsFormat;
1373   switch (params[0].ToInt(pRuntime)) {
1374     case 0:
1375       wsFormat = L"99999";
1376       break;
1377     case 1:
1378       wsFormat = L"99999-9999";
1379       break;
1380     case 2:
1381       if (util::printx(L"9999999999", wsSource).GetLength() >= 10)
1382         wsFormat = L"(999) 999-9999";
1383       else
1384         wsFormat = L"999-9999";
1385       break;
1386     case 3:
1387       wsFormat = L"999-99-9999";
1388       break;
1389   }
1390 
1391   pEvent->Value() = util::printx(wsFormat, wsSource);
1392   return true;
1393 }
1394 
1395 // function AFSpecial_KeystrokeEx(mask)
AFSpecial_KeystrokeEx(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)1396 bool CJS_PublicMethods::AFSpecial_KeystrokeEx(
1397     CJS_Runtime* pRuntime,
1398     const std::vector<CJS_Value>& params,
1399     CJS_Value& vRet,
1400     CFX_WideString& sError) {
1401   if (params.size() < 1) {
1402     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
1403     return false;
1404   }
1405 
1406   CJS_EventContext* pContext = pRuntime->GetCurrentEventContext();
1407   CJS_EventHandler* pEvent = pContext->GetEventHandler();
1408   if (!pEvent->m_pValue)
1409     return false;
1410 
1411   CFX_WideString& valEvent = pEvent->Value();
1412   CFX_WideString wstrMask = params[0].ToCFXWideString(pRuntime);
1413   if (wstrMask.IsEmpty())
1414     return true;
1415 
1416   if (pEvent->WillCommit()) {
1417     if (valEvent.IsEmpty())
1418       return true;
1419 
1420     FX_STRSIZE iIndexMask = 0;
1421     for (; iIndexMask < valEvent.GetLength(); ++iIndexMask) {
1422       if (!maskSatisfied(valEvent[iIndexMask], wstrMask[iIndexMask]))
1423         break;
1424     }
1425 
1426     if (iIndexMask != wstrMask.GetLength() ||
1427         (iIndexMask != valEvent.GetLength() && wstrMask.GetLength() != 0)) {
1428       AlertIfPossible(
1429           pContext, JSGetStringFromID(IDS_STRING_JSAFNUMBER_KEYSTROKE).c_str());
1430       pEvent->Rc() = false;
1431     }
1432     return true;
1433   }
1434 
1435   CFX_WideString& wideChange = pEvent->Change();
1436   if (wideChange.IsEmpty())
1437     return true;
1438 
1439   CFX_WideString wChange = wideChange;
1440   FX_STRSIZE iIndexMask = pEvent->SelStart();
1441   FX_STRSIZE combined_len = valEvent.GetLength() + wChange.GetLength() +
1442                             pEvent->SelStart() - pEvent->SelEnd();
1443   if (combined_len > wstrMask.GetLength()) {
1444     AlertIfPossible(pContext,
1445                     JSGetStringFromID(IDS_STRING_JSPARAM_TOOLONG).c_str());
1446     pEvent->Rc() = false;
1447     return true;
1448   }
1449 
1450   if (iIndexMask >= wstrMask.GetLength() && !wChange.IsEmpty()) {
1451     AlertIfPossible(pContext,
1452                     JSGetStringFromID(IDS_STRING_JSPARAM_TOOLONG).c_str());
1453     pEvent->Rc() = false;
1454     return true;
1455   }
1456 
1457   for (FX_STRSIZE i = 0; i < wChange.GetLength(); ++i) {
1458     if (iIndexMask >= wstrMask.GetLength()) {
1459       AlertIfPossible(pContext,
1460                       JSGetStringFromID(IDS_STRING_JSPARAM_TOOLONG).c_str());
1461       pEvent->Rc() = false;
1462       return true;
1463     }
1464     FX_WCHAR wMask = wstrMask[iIndexMask];
1465     if (!isReservedMaskChar(wMask))
1466       wChange.SetAt(i, wMask);
1467 
1468     if (!maskSatisfied(wChange[i], wMask)) {
1469       pEvent->Rc() = false;
1470       return true;
1471     }
1472     iIndexMask++;
1473   }
1474   wideChange = wChange;
1475   return true;
1476 }
1477 
1478 // function AFSpecial_Keystroke(psf)
AFSpecial_Keystroke(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)1479 bool CJS_PublicMethods::AFSpecial_Keystroke(
1480     CJS_Runtime* pRuntime,
1481     const std::vector<CJS_Value>& params,
1482     CJS_Value& vRet,
1483     CFX_WideString& sError) {
1484   if (params.size() != 1) {
1485     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
1486     return false;
1487   }
1488 
1489   CJS_EventHandler* pEvent =
1490       pRuntime->GetCurrentEventContext()->GetEventHandler();
1491   if (!pEvent->m_pValue)
1492     return false;
1493 
1494   const char* cFormat = "";
1495   switch (params[0].ToInt(pRuntime)) {
1496     case 0:
1497       cFormat = "99999";
1498       break;
1499     case 1:
1500       cFormat = "999999999";
1501       break;
1502     case 2:
1503       if (pEvent->Value().GetLength() + pEvent->Change().GetLength() > 7)
1504         cFormat = "9999999999";
1505       else
1506         cFormat = "9999999";
1507       break;
1508     case 3:
1509       cFormat = "999999999";
1510       break;
1511   }
1512 
1513   std::vector<CJS_Value> params2;
1514   params2.push_back(CJS_Value(pRuntime, cFormat));
1515   return AFSpecial_KeystrokeEx(pRuntime, params2, vRet, sError);
1516 }
1517 
AFMergeChange(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)1518 bool CJS_PublicMethods::AFMergeChange(CJS_Runtime* pRuntime,
1519                                       const std::vector<CJS_Value>& params,
1520                                       CJS_Value& vRet,
1521                                       CFX_WideString& sError) {
1522   if (params.size() != 1) {
1523     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
1524     return false;
1525   }
1526 
1527   CJS_EventHandler* pEventHandler =
1528       pRuntime->GetCurrentEventContext()->GetEventHandler();
1529 
1530   CFX_WideString swValue;
1531   if (pEventHandler->m_pValue)
1532     swValue = pEventHandler->Value();
1533 
1534   if (pEventHandler->WillCommit()) {
1535     vRet = CJS_Value(pRuntime, swValue.c_str());
1536     return true;
1537   }
1538 
1539   CFX_WideString prefix, postfix;
1540 
1541   if (pEventHandler->SelStart() >= 0)
1542     prefix = swValue.Mid(0, pEventHandler->SelStart());
1543   else
1544     prefix = L"";
1545 
1546   if (pEventHandler->SelEnd() >= 0 &&
1547       pEventHandler->SelEnd() <= swValue.GetLength())
1548     postfix = swValue.Mid(pEventHandler->SelEnd(),
1549                           swValue.GetLength() - pEventHandler->SelEnd());
1550   else
1551     postfix = L"";
1552 
1553   vRet =
1554       CJS_Value(pRuntime, (prefix + pEventHandler->Change() + postfix).c_str());
1555   return true;
1556 }
1557 
AFParseDateEx(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)1558 bool CJS_PublicMethods::AFParseDateEx(CJS_Runtime* pRuntime,
1559                                       const std::vector<CJS_Value>& params,
1560                                       CJS_Value& vRet,
1561                                       CFX_WideString& sError) {
1562   if (params.size() != 2) {
1563     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
1564     return false;
1565   }
1566 
1567   CFX_WideString sValue = params[0].ToCFXWideString(pRuntime);
1568   CFX_WideString sFormat = params[1].ToCFXWideString(pRuntime);
1569   double dDate = MakeRegularDate(sValue, sFormat, nullptr);
1570   if (JS_PortIsNan(dDate)) {
1571     CFX_WideString swMsg;
1572     swMsg.Format(JSGetStringFromID(IDS_STRING_JSPARSEDATE).c_str(),
1573                  sFormat.c_str());
1574     AlertIfPossible(pRuntime->GetCurrentEventContext(), swMsg.c_str());
1575     return false;
1576   }
1577 
1578   vRet = CJS_Value(pRuntime, dDate);
1579   return true;
1580 }
1581 
AFSimple(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)1582 bool CJS_PublicMethods::AFSimple(CJS_Runtime* pRuntime,
1583                                  const std::vector<CJS_Value>& params,
1584                                  CJS_Value& vRet,
1585                                  CFX_WideString& sError) {
1586   if (params.size() != 3) {
1587     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
1588     return false;
1589   }
1590 
1591   vRet = CJS_Value(pRuntime, static_cast<double>(AF_Simple(
1592                                  params[0].ToCFXWideString(pRuntime).c_str(),
1593                                  params[1].ToDouble(pRuntime),
1594                                  params[2].ToDouble(pRuntime))));
1595 
1596   return true;
1597 }
1598 
AFMakeNumber(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)1599 bool CJS_PublicMethods::AFMakeNumber(CJS_Runtime* pRuntime,
1600                                      const std::vector<CJS_Value>& params,
1601                                      CJS_Value& vRet,
1602                                      CFX_WideString& sError) {
1603   if (params.size() != 1) {
1604     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
1605     return false;
1606   }
1607 
1608   CFX_WideString ws = params[0].ToCFXWideString(pRuntime);
1609   ws.Replace(L",", L".");
1610   vRet = CJS_Value(pRuntime, ws.c_str());
1611   vRet.MaybeCoerceToNumber(pRuntime);
1612   if (vRet.GetType() != CJS_Value::VT_number)
1613     vRet = CJS_Value(pRuntime, 0);
1614   return true;
1615 }
1616 
AFSimple_Calculate(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)1617 bool CJS_PublicMethods::AFSimple_Calculate(CJS_Runtime* pRuntime,
1618                                            const std::vector<CJS_Value>& params,
1619                                            CJS_Value& vRet,
1620                                            CFX_WideString& sError) {
1621   if (params.size() != 2) {
1622     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
1623     return false;
1624   }
1625 
1626   CJS_Value params1 = params[1];
1627   if (!params1.IsArrayObject() && params1.GetType() != CJS_Value::VT_string) {
1628     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
1629     return false;
1630   }
1631 
1632   CPDFSDK_InterForm* pReaderInterForm =
1633       pRuntime->GetFormFillEnv()->GetInterForm();
1634   CPDF_InterForm* pInterForm = pReaderInterForm->GetInterForm();
1635 
1636   CFX_WideString sFunction = params[0].ToCFXWideString(pRuntime);
1637   double dValue = wcscmp(sFunction.c_str(), L"PRD") == 0 ? 1.0 : 0.0;
1638 
1639   CJS_Array FieldNameArray = AF_MakeArrayFromList(pRuntime, params1);
1640   int nFieldsCount = 0;
1641 
1642   for (int i = 0, isz = FieldNameArray.GetLength(pRuntime); i < isz; i++) {
1643     CJS_Value jsValue(pRuntime);
1644     FieldNameArray.GetElement(pRuntime, i, jsValue);
1645     CFX_WideString wsFieldName = jsValue.ToCFXWideString(pRuntime);
1646 
1647     for (int j = 0, jsz = pInterForm->CountFields(wsFieldName); j < jsz; j++) {
1648       if (CPDF_FormField* pFormField = pInterForm->GetField(j, wsFieldName)) {
1649         double dTemp = 0.0;
1650         switch (pFormField->GetFieldType()) {
1651           case FIELDTYPE_TEXTFIELD:
1652           case FIELDTYPE_COMBOBOX: {
1653             CFX_WideString trimmed = pFormField->GetValue();
1654             trimmed.TrimRight();
1655             trimmed.TrimLeft();
1656             dTemp = FX_atof(trimmed.AsStringC());
1657           } break;
1658           case FIELDTYPE_PUSHBUTTON: {
1659             dTemp = 0.0;
1660           } break;
1661           case FIELDTYPE_CHECKBOX:
1662           case FIELDTYPE_RADIOBUTTON: {
1663             dTemp = 0.0;
1664             for (int c = 0, csz = pFormField->CountControls(); c < csz; c++) {
1665               if (CPDF_FormControl* pFormCtrl = pFormField->GetControl(c)) {
1666                 if (pFormCtrl->IsChecked()) {
1667                   CFX_WideString trimmed = pFormCtrl->GetExportValue();
1668                   trimmed.TrimRight();
1669                   trimmed.TrimLeft();
1670                   dTemp = FX_atof(trimmed.AsStringC());
1671                   break;
1672                 }
1673               }
1674             }
1675           } break;
1676           case FIELDTYPE_LISTBOX: {
1677             if (pFormField->CountSelectedItems() <= 1) {
1678               CFX_WideString trimmed = pFormField->GetValue();
1679               trimmed.TrimRight();
1680               trimmed.TrimLeft();
1681               dTemp = FX_atof(trimmed.AsStringC());
1682             }
1683           } break;
1684           default:
1685             break;
1686         }
1687 
1688         if (i == 0 && j == 0 && (wcscmp(sFunction.c_str(), L"MIN") == 0 ||
1689                                  wcscmp(sFunction.c_str(), L"MAX") == 0))
1690           dValue = dTemp;
1691 
1692         dValue = AF_Simple(sFunction.c_str(), dValue, dTemp);
1693 
1694         nFieldsCount++;
1695       }
1696     }
1697   }
1698 
1699   if (wcscmp(sFunction.c_str(), L"AVG") == 0 && nFieldsCount > 0)
1700     dValue /= nFieldsCount;
1701 
1702   dValue = (double)floor(dValue * FXSYS_pow((double)10, (double)6) + 0.49) /
1703            FXSYS_pow((double)10, (double)6);
1704 
1705   CJS_Value jsValue(pRuntime, dValue);
1706   CJS_EventContext* pContext = pRuntime->GetCurrentEventContext();
1707   if (pContext->GetEventHandler()->m_pValue)
1708     pContext->GetEventHandler()->Value() = jsValue.ToCFXWideString(pRuntime);
1709 
1710   return true;
1711 }
1712 
1713 /* This function validates the current event to ensure that its value is
1714 ** within the specified range. */
1715 
AFRange_Validate(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)1716 bool CJS_PublicMethods::AFRange_Validate(CJS_Runtime* pRuntime,
1717                                          const std::vector<CJS_Value>& params,
1718                                          CJS_Value& vRet,
1719                                          CFX_WideString& sError) {
1720   if (params.size() != 4) {
1721     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
1722     return false;
1723   }
1724   CJS_EventContext* pContext = pRuntime->GetCurrentEventContext();
1725   CJS_EventHandler* pEvent = pContext->GetEventHandler();
1726   if (!pEvent->m_pValue)
1727     return false;
1728 
1729   if (pEvent->Value().IsEmpty())
1730     return true;
1731 
1732   double dEentValue =
1733       atof(CFX_ByteString::FromUnicode(pEvent->Value()).c_str());
1734   bool bGreaterThan = params[0].ToBool(pRuntime);
1735   double dGreaterThan = params[1].ToDouble(pRuntime);
1736   bool bLessThan = params[2].ToBool(pRuntime);
1737   double dLessThan = params[3].ToDouble(pRuntime);
1738   CFX_WideString swMsg;
1739 
1740   if (bGreaterThan && bLessThan) {
1741     if (dEentValue < dGreaterThan || dEentValue > dLessThan)
1742       swMsg.Format(JSGetStringFromID(IDS_STRING_JSRANGE1).c_str(),
1743                    params[1].ToCFXWideString(pRuntime).c_str(),
1744                    params[3].ToCFXWideString(pRuntime).c_str());
1745   } else if (bGreaterThan) {
1746     if (dEentValue < dGreaterThan)
1747       swMsg.Format(JSGetStringFromID(IDS_STRING_JSRANGE2).c_str(),
1748                    params[1].ToCFXWideString(pRuntime).c_str());
1749   } else if (bLessThan) {
1750     if (dEentValue > dLessThan)
1751       swMsg.Format(JSGetStringFromID(IDS_STRING_JSRANGE3).c_str(),
1752                    params[3].ToCFXWideString(pRuntime).c_str());
1753   }
1754 
1755   if (!swMsg.IsEmpty()) {
1756     AlertIfPossible(pContext, swMsg.c_str());
1757     pEvent->Rc() = false;
1758   }
1759   return true;
1760 }
1761 
AFExtractNums(CJS_Runtime * pRuntime,const std::vector<CJS_Value> & params,CJS_Value & vRet,CFX_WideString & sError)1762 bool CJS_PublicMethods::AFExtractNums(CJS_Runtime* pRuntime,
1763                                       const std::vector<CJS_Value>& params,
1764                                       CJS_Value& vRet,
1765                                       CFX_WideString& sError) {
1766   if (params.size() != 1) {
1767     sError = JSGetStringFromID(IDS_STRING_JSPARAMERROR);
1768     return false;
1769   }
1770 
1771   CFX_WideString str = params[0].ToCFXWideString(pRuntime);
1772   if (str.GetAt(0) == L'.' || str.GetAt(0) == L',')
1773     str = L"0" + str;
1774 
1775   CFX_WideString sPart;
1776   CJS_Array nums;
1777   int nIndex = 0;
1778   for (int i = 0, sz = str.GetLength(); i < sz; i++) {
1779     FX_WCHAR wc = str.GetAt(i);
1780     if (FXSYS_iswdigit(wc)) {
1781       sPart += wc;
1782     } else {
1783       if (sPart.GetLength() > 0) {
1784         nums.SetElement(pRuntime, nIndex, CJS_Value(pRuntime, sPart.c_str()));
1785         sPart = L"";
1786         nIndex++;
1787       }
1788     }
1789   }
1790 
1791   if (sPart.GetLength() > 0) {
1792     nums.SetElement(pRuntime, nIndex, CJS_Value(pRuntime, sPart.c_str()));
1793   }
1794 
1795   if (nums.GetLength(pRuntime) > 0)
1796     vRet = CJS_Value(pRuntime, nums);
1797   else
1798     vRet.SetNull(pRuntime);
1799 
1800   return true;
1801 }
1802