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