PublicMethods.cpp revision 5ae9d0c6fd838a2967cca72aa5751b51dadc2769
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
33JSMethodSpec 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
58IMPLEMENT_JS_STATIC_GLOBAL_FUN(CJS_PublicMethods)
59
60namespace {
61
62const 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
66const 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
71CFX_ByteString StrTrim(const CFX_ByteString& pStr) {
72  CFX_ByteString result(pStr);
73  result.TrimLeft(' ');
74  result.TrimRight(' ');
75  return result;
76}
77
78CFX_WideString StrTrim(const CFX_WideString& pStr) {
79  CFX_WideString result(pStr);
80  result.TrimLeft(' ');
81  result.TrimRight(' ');
82  return result;
83}
84
85void 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_
92CFX_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
116bool 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
152bool 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
167bool CJS_PublicMethods::isReservedMaskChar(wchar_t ch) {
168  return ch == L'9' || ch == L'A' || ch == L'O' || ch == L'X';
169}
170
171double 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
190CJS_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
228int 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
251CFX_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
268double 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
348double 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
620CFX_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)
753bool 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)
900bool 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)
999bool 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)
1090bool 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)
1099bool 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
1141double 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)
1198bool 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
1232bool 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)
1266bool 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)
1300bool 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
1321bool 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
1342bool 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
1349bool 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)
1357bool 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)
1396bool 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)
1479bool 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
1518bool 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
1558bool 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
1582bool 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
1599bool 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
1617bool 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
1716bool 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
1762bool 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