Home | History | Annotate | Download | only in javascript
      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 
     71 CFX_ByteString StrTrim(const CFX_ByteString& pStr) {
     72   CFX_ByteString result(pStr);
     73   result.TrimLeft(' ');
     74   result.TrimRight(' ');
     75   return result;
     76 }
     77 
     78 CFX_WideString StrTrim(const CFX_WideString& pStr) {
     79   CFX_WideString result(pStr);
     80   result.TrimLeft(' ');
     81   result.TrimRight(' ');
     82   return result;
     83 }
     84 
     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_
     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 
    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 
    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 
    167 bool CJS_PublicMethods::isReservedMaskChar(wchar_t ch) {
    168   return ch == L'9' || ch == L'A' || ch == L'O' || ch == L'X';
    169 }
    170 
    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 
    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 
    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 
    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 
    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 
    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 
    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)
    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)
    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)
    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)
   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)
   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 
   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)
   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 
   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)
   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)
   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 
   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 
   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 
   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)
   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)
   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)
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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