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