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