Remove if checks after new.
[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   ASSERT(iIndex < FX_ArraySize(cFormats));
1500
1501   if (iIndex < 0)
1502     iIndex = 0;
1503   if (iIndex >= FX_ArraySize(cFormats))
1504     iIndex = 0;
1505   CJS_Parameters newParams;
1506   CJS_Value val(isolate, cFormats[iIndex]);
1507   newParams.push_back(val);
1508   return AFDate_FormatEx(cc, newParams, vRet, sError);
1509 }
1510
1511 // AFDate_KeystrokeEx(cFormat)
1512 FX_BOOL CJS_PublicMethods::AFDate_Keystroke(IFXJS_Context* cc,
1513                                             const CJS_Parameters& params,
1514                                             CJS_Value& vRet,
1515                                             CFX_WideString& sError) {
1516   v8::Isolate* isolate = ::GetIsolate(cc);
1517
1518   if (params.size() != 1) {
1519     CJS_Context* pContext = (CJS_Context*)cc;
1520     ASSERT(pContext != NULL);
1521
1522     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1523     return FALSE;
1524   }
1525
1526   int iIndex = params[0].ToInt();
1527   const FX_WCHAR* cFormats[] = {L"m/d",
1528                                 L"m/d/yy",
1529                                 L"mm/dd/yy",
1530                                 L"mm/yy",
1531                                 L"d-mmm",
1532                                 L"d-mmm-yy",
1533                                 L"dd-mmm-yy",
1534                                 L"yy-mm-dd",
1535                                 L"mmm-yy",
1536                                 L"mmmm-yy",
1537                                 L"mmm d, yyyy",
1538                                 L"mmmm d, yyyy",
1539                                 L"m/d/yy h:MM tt",
1540                                 L"m/d/yy HH:MM"};
1541
1542   ASSERT(iIndex < FX_ArraySize(cFormats));
1543
1544   if (iIndex < 0)
1545     iIndex = 0;
1546   if (iIndex >= FX_ArraySize(cFormats))
1547     iIndex = 0;
1548   CJS_Parameters newParams;
1549   CJS_Value val(isolate, cFormats[iIndex]);
1550   newParams.push_back(val);
1551   return AFDate_KeystrokeEx(cc, newParams, vRet, sError);
1552 }
1553
1554 // function AFTime_Format(ptf)
1555 FX_BOOL CJS_PublicMethods::AFTime_Format(IFXJS_Context* cc,
1556                                          const CJS_Parameters& params,
1557                                          CJS_Value& vRet,
1558                                          CFX_WideString& sError) {
1559   v8::Isolate* isolate = ::GetIsolate(cc);
1560
1561   if (params.size() != 1) {
1562     CJS_Context* pContext = (CJS_Context*)cc;
1563     ASSERT(pContext != NULL);
1564     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1565     return FALSE;
1566   }
1567
1568   int iIndex = params[0].ToInt();
1569   const FX_WCHAR* cFormats[] = {L"HH:MM", L"h:MM tt", L"HH:MM:ss",
1570                                 L"h:MM:ss tt"};
1571
1572   ASSERT(iIndex < FX_ArraySize(cFormats));
1573
1574   if (iIndex < 0)
1575     iIndex = 0;
1576   if (iIndex >= FX_ArraySize(cFormats))
1577     iIndex = 0;
1578   CJS_Parameters newParams;
1579   CJS_Value val(isolate, cFormats[iIndex]);
1580   newParams.push_back(val);
1581   return AFDate_FormatEx(cc, newParams, vRet, sError);
1582 }
1583
1584 FX_BOOL CJS_PublicMethods::AFTime_Keystroke(IFXJS_Context* cc,
1585                                             const CJS_Parameters& params,
1586                                             CJS_Value& vRet,
1587                                             CFX_WideString& sError) {
1588   v8::Isolate* isolate = ::GetIsolate(cc);
1589   if (params.size() != 1) {
1590     CJS_Context* pContext = (CJS_Context*)cc;
1591     ASSERT(pContext != NULL);
1592     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1593     return FALSE;
1594   }
1595
1596   int iIndex = params[0].ToInt();
1597   const FX_WCHAR* cFormats[] = {L"HH:MM", L"h:MM tt", L"HH:MM:ss",
1598                                 L"h:MM:ss tt"};
1599
1600   ASSERT(iIndex < FX_ArraySize(cFormats));
1601
1602   if (iIndex < 0)
1603     iIndex = 0;
1604   if (iIndex >= FX_ArraySize(cFormats))
1605     iIndex = 0;
1606   CJS_Parameters newParams;
1607   CJS_Value val(isolate, cFormats[iIndex]);
1608   newParams.push_back(val);
1609   return AFDate_KeystrokeEx(cc, newParams, vRet, sError);
1610 }
1611
1612 FX_BOOL CJS_PublicMethods::AFTime_FormatEx(IFXJS_Context* cc,
1613                                            const CJS_Parameters& params,
1614                                            CJS_Value& vRet,
1615                                            CFX_WideString& sError) {
1616   return AFDate_FormatEx(cc, params, vRet, sError);
1617 }
1618
1619 FX_BOOL CJS_PublicMethods::AFTime_KeystrokeEx(IFXJS_Context* cc,
1620                                               const CJS_Parameters& params,
1621                                               CJS_Value& vRet,
1622                                               CFX_WideString& sError) {
1623   return AFDate_KeystrokeEx(cc, params, vRet, sError);
1624 }
1625
1626 // function AFSpecial_Format(psf)
1627 FX_BOOL CJS_PublicMethods::AFSpecial_Format(IFXJS_Context* cc,
1628                                             const CJS_Parameters& params,
1629                                             CJS_Value& vRet,
1630                                             CFX_WideString& sError) {
1631   CJS_Context* pContext = (CJS_Context*)cc;
1632   ASSERT(pContext != NULL);
1633
1634   if (params.size() != 1) {
1635     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1636     return FALSE;
1637   }
1638
1639   std::string cFormat;
1640   int iIndex = params[0].ToInt();
1641
1642   CJS_EventHandler* pEvent = pContext->GetEventHandler();
1643   ASSERT(pEvent != NULL);
1644
1645   if (!pEvent->m_pValue)
1646     return FALSE;
1647   CFX_WideString& Value = pEvent->Value();
1648   std::string strSrc = CFX_ByteString::FromUnicode(Value).c_str();
1649
1650   switch (iIndex) {
1651     case 0:
1652       cFormat = "99999";
1653       break;
1654     case 1:
1655       cFormat = "99999-9999";
1656       break;
1657     case 2: {
1658       std::string NumberStr;
1659       util::printx("9999999999", strSrc, NumberStr);
1660       if (NumberStr.length() >= 10)
1661         cFormat = "(999) 999-9999";
1662       else
1663         cFormat = "999-9999";
1664       break;
1665     }
1666     case 3:
1667       cFormat = "999-99-9999";
1668       break;
1669   }
1670
1671   std::string strDes;
1672   util::printx(cFormat, strSrc, strDes);
1673   Value = CFX_WideString::FromLocal(strDes.c_str());
1674   return TRUE;
1675 }
1676
1677 // function AFSpecial_KeystrokeEx(mask)
1678 FX_BOOL CJS_PublicMethods::AFSpecial_KeystrokeEx(IFXJS_Context* cc,
1679                                                  const CJS_Parameters& params,
1680                                                  CJS_Value& vRet,
1681                                                  CFX_WideString& sError) {
1682   CJS_Context* pContext = (CJS_Context*)cc;
1683   ASSERT(pContext != NULL);
1684   CJS_EventHandler* pEvent = pContext->GetEventHandler();
1685
1686   ASSERT(pEvent != NULL);
1687
1688   if (params.size() < 1) {
1689     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1690     return FALSE;
1691   }
1692
1693   if (!pEvent->m_pValue)
1694     return FALSE;
1695   CFX_WideString& valEvent = pEvent->Value();
1696
1697   CFX_WideString wstrMask = params[0].ToCFXWideString();
1698   if (wstrMask.IsEmpty())
1699     return TRUE;
1700
1701   std::wstring wstrValue = valEvent.c_str();
1702
1703   if (pEvent->WillCommit()) {
1704     if (wstrValue.empty())
1705       return TRUE;
1706     int iIndexMask = 0;
1707     for (std::wstring::iterator it = wstrValue.begin(); it != wstrValue.end();
1708          it++) {
1709       wchar_t w_Value = *it;
1710       if (!maskSatisfied(w_Value, wstrMask[iIndexMask]))
1711         break;
1712       iIndexMask++;
1713     }
1714
1715     if (iIndexMask != wstrMask.GetLength() ||
1716         (iIndexMask != wstrValue.size() && wstrMask.GetLength() != 0)) {
1717       Alert(
1718           pContext,
1719           JSGetStringFromID(pContext, IDS_STRING_JSAFNUMBER_KEYSTROKE).c_str());
1720       pEvent->Rc() = FALSE;
1721     }
1722     return TRUE;
1723   }
1724
1725   CFX_WideString& wideChange = pEvent->Change();
1726   std::wstring wChange = wideChange.c_str();
1727   if (wChange.empty())
1728     return TRUE;
1729
1730   int iIndexMask = pEvent->SelStart();
1731
1732   if (wstrValue.length() - (pEvent->SelEnd() - pEvent->SelStart()) +
1733           wChange.length() >
1734       (FX_DWORD)wstrMask.GetLength()) {
1735     Alert(pContext,
1736           JSGetStringFromID(pContext, IDS_STRING_JSPARAM_TOOLONG).c_str());
1737     pEvent->Rc() = FALSE;
1738     return TRUE;
1739   }
1740
1741   if (iIndexMask >= wstrMask.GetLength() && (!wChange.empty())) {
1742     Alert(pContext,
1743           JSGetStringFromID(pContext, IDS_STRING_JSPARAM_TOOLONG).c_str());
1744     pEvent->Rc() = FALSE;
1745     return TRUE;
1746   }
1747
1748   for (std::wstring::iterator it = wChange.begin(); it != wChange.end(); it++) {
1749     if (iIndexMask >= wstrMask.GetLength()) {
1750       Alert(pContext,
1751             JSGetStringFromID(pContext, IDS_STRING_JSPARAM_TOOLONG).c_str());
1752       pEvent->Rc() = FALSE;
1753       return TRUE;
1754     }
1755     wchar_t w_Mask = wstrMask[iIndexMask];
1756     if (!isReservedMaskChar(w_Mask)) {
1757       *it = w_Mask;
1758     }
1759     wchar_t w_Change = *it;
1760     if (!maskSatisfied(w_Change, w_Mask)) {
1761       pEvent->Rc() = FALSE;
1762       return TRUE;
1763     }
1764     iIndexMask++;
1765   }
1766
1767   wideChange = wChange.c_str();
1768   return TRUE;
1769 }
1770
1771 // function AFSpecial_Keystroke(psf)
1772 FX_BOOL CJS_PublicMethods::AFSpecial_Keystroke(IFXJS_Context* cc,
1773                                                const CJS_Parameters& params,
1774                                                CJS_Value& vRet,
1775                                                CFX_WideString& sError) {
1776   v8::Isolate* isolate = ::GetIsolate(cc);
1777
1778   CJS_Context* pContext = (CJS_Context*)cc;
1779   ASSERT(pContext != NULL);
1780   CJS_EventHandler* pEvent = pContext->GetEventHandler();
1781   ASSERT(pEvent != NULL);
1782
1783   if (params.size() != 1) {
1784     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1785     return FALSE;
1786   }
1787
1788   std::string cFormat;
1789   int iIndex = params[0].ToInt();
1790
1791   if (!pEvent->m_pValue)
1792     return FALSE;
1793   // CJS_Value val = pEvent->Value();
1794   CFX_WideString& val = pEvent->Value();
1795   std::string strSrc = CFX_ByteString::FromUnicode(val).c_str();
1796   std::wstring wstrChange = pEvent->Change().c_str();
1797
1798   switch (iIndex) {
1799     case 0:
1800       cFormat = "99999";
1801       break;
1802     case 1:
1803       // cFormat = "99999-9999";
1804       cFormat = "999999999";
1805       break;
1806     case 2: {
1807       std::string NumberStr;
1808       util::printx("9999999999", strSrc, NumberStr);
1809       if (strSrc.length() + wstrChange.length() > 7)
1810         // cFormat = "(999) 999-9999";
1811         cFormat = "9999999999";
1812       else
1813         // cFormat = "999-9999";
1814         cFormat = "9999999";
1815       break;
1816     }
1817     case 3:
1818       // cFormat = "999-99-9999";
1819       cFormat = "999999999";
1820       break;
1821   }
1822
1823   CJS_Parameters params2;
1824   CJS_Value vMask(isolate, cFormat.c_str());
1825   params2.push_back(vMask);
1826
1827   return AFSpecial_KeystrokeEx(cc, params2, vRet, sError);
1828 }
1829
1830 FX_BOOL CJS_PublicMethods::AFMergeChange(IFXJS_Context* cc,
1831                                          const CJS_Parameters& params,
1832                                          CJS_Value& vRet,
1833                                          CFX_WideString& sError) {
1834   CJS_Context* pContext = (CJS_Context*)cc;
1835   ASSERT(pContext != NULL);
1836   CJS_EventHandler* pEventHandler = pContext->GetEventHandler();
1837   ASSERT(pEventHandler != NULL);
1838
1839   if (params.size() != 1) {
1840     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1841     return FALSE;
1842   }
1843
1844   CFX_WideString swValue;
1845   if (pEventHandler->m_pValue != NULL)
1846     swValue = pEventHandler->Value();
1847
1848   if (pEventHandler->WillCommit()) {
1849     vRet = swValue.c_str();
1850     return TRUE;
1851   }
1852
1853   CFX_WideString prefix, postfix;
1854
1855   if (pEventHandler->SelStart() >= 0)
1856     prefix = swValue.Mid(0, pEventHandler->SelStart());
1857   else
1858     prefix = L"";
1859
1860   if (pEventHandler->SelEnd() >= 0 &&
1861       pEventHandler->SelEnd() <= swValue.GetLength())
1862     postfix = swValue.Mid(pEventHandler->SelEnd(),
1863                           swValue.GetLength() - pEventHandler->SelEnd());
1864   else
1865     postfix = L"";
1866
1867   vRet = (prefix + pEventHandler->Change() + postfix).c_str();
1868
1869   return TRUE;
1870 }
1871
1872 FX_BOOL CJS_PublicMethods::AFParseDateEx(IFXJS_Context* cc,
1873                                          const CJS_Parameters& params,
1874                                          CJS_Value& vRet,
1875                                          CFX_WideString& sError) {
1876   CJS_Context* pContext = (CJS_Context*)cc;
1877   ASSERT(pContext != NULL);
1878
1879   if (params.size() != 2) {
1880     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1881     return FALSE;
1882   }
1883
1884   CFX_WideString sValue = params[0].ToCFXWideString();
1885   CFX_WideString sFormat = params[1].ToCFXWideString();
1886
1887   FX_BOOL bWrongFormat = FALSE;
1888   double dDate = MakeRegularDate(sValue, sFormat, bWrongFormat);
1889
1890   if (JS_PortIsNan(dDate)) {
1891     CFX_WideString swMsg;
1892     swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSPARSEDATE).c_str(),
1893                  sFormat.c_str());
1894     Alert((CJS_Context*)cc, swMsg.c_str());
1895     return FALSE;
1896   }
1897
1898   vRet = dDate;
1899   return TRUE;
1900 }
1901
1902 FX_BOOL CJS_PublicMethods::AFSimple(IFXJS_Context* cc,
1903                                     const CJS_Parameters& params,
1904                                     CJS_Value& vRet,
1905                                     CFX_WideString& sError) {
1906   if (params.size() != 3) {
1907     CJS_Context* pContext = (CJS_Context*)cc;
1908     ASSERT(pContext != NULL);
1909
1910     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1911     return FALSE;
1912   }
1913
1914   vRet = (double)AF_Simple(params[0].ToCFXWideString().c_str(),
1915                            params[1].ToDouble(), params[2].ToDouble());
1916   return TRUE;
1917 }
1918
1919 FX_BOOL CJS_PublicMethods::AFMakeNumber(IFXJS_Context* cc,
1920                                         const CJS_Parameters& params,
1921                                         CJS_Value& vRet,
1922                                         CFX_WideString& sError) {
1923   if (params.size() != 1) {
1924     CJS_Context* pContext = (CJS_Context*)cc;
1925     ASSERT(pContext != NULL);
1926
1927     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1928     return FALSE;
1929   }
1930   vRet = ParseStringToNumber(params[0].ToCFXWideString().c_str());
1931   return TRUE;
1932 }
1933
1934 FX_BOOL CJS_PublicMethods::AFSimple_Calculate(IFXJS_Context* cc,
1935                                               const CJS_Parameters& params,
1936                                               CJS_Value& vRet,
1937                                               CFX_WideString& sError) {
1938   v8::Isolate* isolate = ::GetIsolate(cc);
1939
1940   CJS_Context* pContext = (CJS_Context*)cc;
1941   ASSERT(pContext != NULL);
1942
1943   if (params.size() != 2) {
1944     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1945     return FALSE;
1946   }
1947
1948   CJS_Value params1 = params[1];
1949
1950   if (!params1.IsArrayObject() && params1.GetType() != VT_string) {
1951     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1952     return FALSE;
1953   }
1954
1955   CPDFSDK_Document* pReaderDoc = pContext->GetReaderDocument();
1956   ASSERT(pReaderDoc != NULL);
1957
1958   CPDFSDK_InterForm* pReaderInterForm = pReaderDoc->GetInterForm();
1959   ASSERT(pReaderInterForm != NULL);
1960
1961   CPDF_InterForm* pInterForm = pReaderInterForm->GetInterForm();
1962   ASSERT(pInterForm != NULL);
1963
1964   double dValue;
1965   CFX_WideString sFunction = params[0].ToCFXWideString();
1966   if (wcscmp(sFunction.c_str(), L"PRD") == 0)
1967     dValue = 1.0;
1968   else
1969     dValue = 0.0;
1970
1971   CJS_Array FieldNameArray = AF_MakeArrayFromList(isolate, params1);
1972
1973   int nFieldsCount = 0;
1974
1975   for (int i = 0, isz = FieldNameArray.GetLength(); i < isz; i++) {
1976     CJS_Value jsValue(isolate);
1977     FieldNameArray.GetElement(i, jsValue);
1978     CFX_WideString wsFieldName = jsValue.ToCFXWideString();
1979
1980     for (int j = 0, jsz = pInterForm->CountFields(wsFieldName); j < jsz; j++) {
1981       if (CPDF_FormField* pFormField = pInterForm->GetField(j, wsFieldName)) {
1982         double dTemp = 0.0;
1983
1984         switch (pFormField->GetFieldType()) {
1985           case FIELDTYPE_TEXTFIELD:
1986           case FIELDTYPE_COMBOBOX: {
1987             dTemp = ParseStringToNumber(pFormField->GetValue().c_str());
1988             break;
1989           }
1990           case FIELDTYPE_PUSHBUTTON: {
1991             dTemp = 0.0;
1992             break;
1993           }
1994           case FIELDTYPE_CHECKBOX:
1995           case FIELDTYPE_RADIOBUTTON: {
1996             dTemp = 0.0;
1997             for (int c = 0, csz = pFormField->CountControls(); c < csz; c++) {
1998               if (CPDF_FormControl* pFormCtrl = pFormField->GetControl(c)) {
1999                 if (pFormCtrl->IsChecked()) {
2000                   dTemp +=
2001                       ParseStringToNumber(pFormCtrl->GetExportValue().c_str());
2002                   break;
2003                 } else
2004                   continue;
2005               }
2006             }
2007             break;
2008           }
2009           case FIELDTYPE_LISTBOX: {
2010             dTemp = 0.0;
2011             if (pFormField->CountSelectedItems() > 1)
2012               break;
2013             else {
2014               dTemp = ParseStringToNumber(pFormField->GetValue().c_str());
2015               break;
2016             }
2017           }
2018           default:
2019             break;
2020         }
2021
2022         if (i == 0 && j == 0 && (wcscmp(sFunction.c_str(), L"MIN") == 0 ||
2023                                  wcscmp(sFunction.c_str(), L"MAX") == 0))
2024           dValue = dTemp;
2025
2026         dValue = AF_Simple(sFunction.c_str(), dValue, dTemp);
2027
2028         nFieldsCount++;
2029       }
2030     }
2031   }
2032
2033   if (wcscmp(sFunction.c_str(), L"AVG") == 0 && nFieldsCount > 0)
2034     dValue /= nFieldsCount;
2035
2036   dValue = (double)floor(dValue * FXSYS_pow((double)10, (double)6) + 0.49) /
2037            FXSYS_pow((double)10, (double)6);
2038   CJS_Value jsValue(isolate, dValue);
2039   if ((CJS_EventHandler*)pContext->GetEventHandler()->m_pValue)
2040     ((CJS_EventHandler*)pContext->GetEventHandler())->Value() =
2041         jsValue.ToCFXWideString();
2042
2043   return TRUE;
2044 }
2045
2046 /* This function validates the current event to ensure that its value is
2047 ** within the specified range. */
2048
2049 FX_BOOL CJS_PublicMethods::AFRange_Validate(IFXJS_Context* cc,
2050                                             const CJS_Parameters& params,
2051                                             CJS_Value& vRet,
2052                                             CFX_WideString& sError) {
2053   CJS_Context* pContext = (CJS_Context*)cc;
2054   ASSERT(pContext != NULL);
2055   CJS_EventHandler* pEvent = pContext->GetEventHandler();
2056   ASSERT(pEvent != NULL);
2057
2058   if (params.size() != 4) {
2059     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
2060     return FALSE;
2061   }
2062
2063   if (!pEvent->m_pValue)
2064     return FALSE;
2065   if (pEvent->Value().IsEmpty())
2066     return TRUE;
2067   double dEentValue = atof(CFX_ByteString::FromUnicode(pEvent->Value()));
2068   FX_BOOL bGreaterThan = params[0].ToBool();
2069   double dGreaterThan = params[1].ToDouble();
2070   FX_BOOL bLessThan = params[2].ToBool();
2071   double dLessThan = params[3].ToDouble();
2072   CFX_WideString swMsg;
2073
2074   if (bGreaterThan && bLessThan) {
2075     if (dEentValue < dGreaterThan || dEentValue > dLessThan)
2076       swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSRANGE1).c_str(),
2077                    params[1].ToCFXWideString().c_str(),
2078                    params[3].ToCFXWideString().c_str());
2079   } else if (bGreaterThan) {
2080     if (dEentValue < dGreaterThan)
2081       swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSRANGE2).c_str(),
2082                    params[1].ToCFXWideString().c_str());
2083   } else if (bLessThan) {
2084     if (dEentValue > dLessThan)
2085       swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSRANGE3).c_str(),
2086                    params[3].ToCFXWideString().c_str());
2087   }
2088
2089   if (!swMsg.IsEmpty()) {
2090     Alert(pContext, swMsg.c_str());
2091     pEvent->Rc() = FALSE;
2092   }
2093   return TRUE;
2094 }
2095
2096 FX_BOOL CJS_PublicMethods::AFExtractNums(IFXJS_Context* cc,
2097                                          const CJS_Parameters& params,
2098                                          CJS_Value& vRet,
2099                                          CFX_WideString& sError) {
2100   v8::Isolate* isolate = ::GetIsolate(cc);
2101   CJS_Context* pContext = (CJS_Context*)cc;
2102   ASSERT(pContext != NULL);
2103
2104   if (params.size() != 1) {
2105     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
2106     return FALSE;
2107   }
2108
2109   CJS_Array nums(isolate);
2110
2111   CFX_WideString str = params[0].ToCFXWideString();
2112   CFX_WideString sPart;
2113
2114   if (str.GetAt(0) == L'.' || str.GetAt(0) == L',')
2115     str = L"0" + str;
2116
2117   int nIndex = 0;
2118   for (int i = 0, sz = str.GetLength(); i < sz; i++) {
2119     FX_WCHAR wc = str.GetAt(i);
2120     if (IsDigit((wchar_t)wc)) {
2121       sPart += wc;
2122     } else {
2123       if (sPart.GetLength() > 0) {
2124         nums.SetElement(nIndex, CJS_Value(isolate, sPart.c_str()));
2125         sPart = L"";
2126         nIndex++;
2127       }
2128     }
2129   }
2130
2131   if (sPart.GetLength() > 0) {
2132     nums.SetElement(nIndex, CJS_Value(isolate, sPart.c_str()));
2133   }
2134
2135   if (nums.GetLength() > 0)
2136     vRet = nums;
2137   else
2138     vRet.SetNull();
2139
2140   return TRUE;
2141 }