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 "fxjs/cjs_publicmethods.h"
8 
9 #include <algorithm>
10 #include <cmath>
11 #include <cwctype>
12 #include <iomanip>
13 #include <iterator>
14 #include <limits>
15 #include <sstream>
16 #include <string>
17 #include <utility>
18 #include <vector>
19 
20 #include "build/build_config.h"
21 #include "core/fpdfdoc/cpdf_formcontrol.h"
22 #include "core/fpdfdoc/cpdf_interactiveform.h"
23 #include "core/fxcrt/fx_extension.h"
24 #include "core/fxge/cfx_color.h"
25 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
26 #include "fpdfsdk/cpdfsdk_interactiveform.h"
27 #include "fxjs/cjs_color.h"
28 #include "fxjs/cjs_event_context.h"
29 #include "fxjs/cjs_eventrecorder.h"
30 #include "fxjs/cjs_field.h"
31 #include "fxjs/cjs_object.h"
32 #include "fxjs/cjs_runtime.h"
33 #include "fxjs/cjs_util.h"
34 #include "fxjs/fx_date_helpers.h"
35 #include "fxjs/js_define.h"
36 #include "fxjs/js_resources.h"
37 #include "third_party/base/optional.h"
38 #include "third_party/base/stl_util.h"
39 
40 // static
41 const JSMethodSpec CJS_PublicMethods::GlobalFunctionSpecs[] = {
42     {"AFDate_Format", AFDate_Format_static},
43     {"AFDate_FormatEx", AFDate_FormatEx_static},
44     {"AFDate_Keystroke", AFDate_Keystroke_static},
45     {"AFDate_KeystrokeEx", AFDate_KeystrokeEx_static},
46     {"AFExtractNums", AFExtractNums_static},
47     {"AFMakeNumber", AFMakeNumber_static},
48     {"AFMergeChange", AFMergeChange_static},
49     {"AFNumber_Format", AFNumber_Format_static},
50     {"AFNumber_Keystroke", AFNumber_Keystroke_static},
51     {"AFParseDateEx", AFParseDateEx_static},
52     {"AFPercent_Format", AFPercent_Format_static},
53     {"AFPercent_Keystroke", AFPercent_Keystroke_static},
54     {"AFRange_Validate", AFRange_Validate_static},
55     {"AFSimple", AFSimple_static},
56     {"AFSimple_Calculate", AFSimple_Calculate_static},
57     {"AFSpecial_Format", AFSpecial_Format_static},
58     {"AFSpecial_Keystroke", AFSpecial_Keystroke_static},
59     {"AFSpecial_KeystrokeEx", AFSpecial_KeystrokeEx_static},
60     {"AFTime_Format", AFTime_Format_static},
61     {"AFTime_FormatEx", AFTime_FormatEx_static},
62     {"AFTime_Keystroke", AFTime_Keystroke_static},
63     {"AFTime_KeystrokeEx", AFTime_KeystrokeEx_static},
64 };
65 
66 namespace {
67 
68 #if !defined(OS_ANDROID)
69 constexpr double kDoubleCorrect = 0.000000000000001;
70 #endif
71 
72 constexpr const wchar_t* kDateFormats[] = {L"m/d",
73                                            L"m/d/yy",
74                                            L"mm/dd/yy",
75                                            L"mm/yy",
76                                            L"d-mmm",
77                                            L"d-mmm-yy",
78                                            L"dd-mmm-yy",
79                                            L"yy-mm-dd",
80                                            L"mmm-yy",
81                                            L"mmmm-yy",
82                                            L"mmm d, yyyy",
83                                            L"mmmm d, yyyy",
84                                            L"m/d/yy h:MM tt",
85                                            L"m/d/yy HH:MM"};
86 
87 constexpr const wchar_t* kTimeFormats[] = {L"HH:MM", L"h:MM tt", L"HH:MM:ss",
88                                            L"h:MM:ss tt"};
89 
90 #if defined(__FreeBSD__) || defined(__DragonFly__)
91 /*
92  * cvt.c - IEEE floating point formatting routines for FreeBSD
93  * from GNU libc-4.6.27
94  */
95 
96 /*
97  *    ap_ecvt converts to decimal
98  *      the number of digits is specified by ndigit
99  *      decpt is set to the position of the decimal point
100  *      sign is set to 0 for positive, 1 for negative
101  */
102 
103 #define	NDIG	80
104 
105 static char *
ap_cvt(double arg,int ndigits,int * decpt,int * sign,int eflag)106      ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag)
107 {
108     register int r2;
109     double fi, fj;
110     register char *p, *p1;
111     static char buf[NDIG];
112 
113     if (ndigits >= NDIG - 1)
114 	ndigits = NDIG - 2;
115     r2 = 0;
116     *sign = 0;
117     p = &buf[0];
118     if (arg < 0) {
119 	*sign = 1;
120 	arg = -arg;
121     }
122     arg = modf(arg, &fi);
123     p1 = &buf[NDIG];
124     /*
125      * Do integer part
126      */
127     if (fi != 0) {
128 	p1 = &buf[NDIG];
129 	while (fi != 0) {
130 	    fj = modf(fi / 10, &fi);
131 	    *--p1 = (int) ((fj + .03) * 10) + '0';
132 	    r2++;
133 	}
134 	while (p1 < &buf[NDIG])
135 	    *p++ = *p1++;
136     }
137     else if (arg > 0) {
138 	while ((fj = arg * 10) < 1) {
139 	    arg = fj;
140 	    r2--;
141 	}
142     }
143     p1 = &buf[ndigits];
144     if (eflag == 0)
145 	p1 += r2;
146     *decpt = r2;
147     if (p1 < &buf[0]) {
148 	buf[0] = '\0';
149         return (buf);
150     }
151     while (p <= p1 && p < &buf[NDIG]) {
152 	arg *= 10;
153 	arg = modf(arg, &fj);
154 	*p++ = (int) fj + '0';
155     }
156     if (p1 >= &buf[NDIG]) {
157 	buf[NDIG - 1] = '\0';
158 	return (buf);
159     }
160     p = p1;
161     *p1 += 5;
162     while (*p1 > '9') {
163 	*p1 = '0';
164 	if (p1 > buf)
165 	    ++ * --p1;
166 	else {
167 	    *p1 = '1';
168 	    (*decpt)++;
169 	    if (eflag == 0) {
170 		if (p > buf)
171 		    *p = '0';
172 		p++;
173 	    }
174 	}
175     }
176     *p = '\0';
177     return (buf);
178 }
179 
180 static char *
fcvt(double arg,int ndigits,int * decpt,int * sign)181      fcvt(double arg, int ndigits, int *decpt, int *sign)
182 {
183      return (ap_cvt(arg, ndigits, decpt, sign, 0));
184 }
185 #endif // defined(__FreeBSD__)
186 
187 template <typename T>
StrTrim(const T & str)188 T StrTrim(const T& str) {
189   T result = str;
190   result.Trim(' ');
191   return result;
192 }
193 
AlertIfPossible(CJS_EventContext * pContext,const WideString & wsCaller,const WideString & wsMsg)194 void AlertIfPossible(CJS_EventContext* pContext,
195                      const WideString& wsCaller,
196                      const WideString& wsMsg) {
197   CPDFSDK_FormFillEnvironment* pFormFillEnv = pContext->GetFormFillEnv();
198   if (pFormFillEnv) {
199     pFormFillEnv->JS_appAlert(wsMsg, wsCaller, JSPLATFORM_ALERT_BUTTON_OK,
200                               JSPLATFORM_ALERT_ICON_STATUS);
201   }
202 }
203 
204 #if !defined(OS_ANDROID)
CalculateString(double dValue,int iDec,int * iDec2,bool * bNegative)205 ByteString CalculateString(double dValue,
206                            int iDec,
207                            int* iDec2,
208                            bool* bNegative) {
209   *bNegative = dValue < 0;
210   if (*bNegative)
211     dValue = -dValue;
212 
213   // Make sure the number of precision characters will fit.
214   iDec = std::min(iDec, std::numeric_limits<double>::digits10);
215 
216   std::stringstream ss;
217   ss << std::fixed << std::setprecision(iDec) << dValue;
218   std::string value = ss.str();
219   size_t pos = value.find('.');
220   *iDec2 = pos == std::string::npos ? value.size() : static_cast<int>(pos);
221   return ByteString(value.c_str());
222 }
223 #endif
224 
CalcMergedString(const CJS_EventRecorder * event,const WideString & value,const WideString & change)225 WideString CalcMergedString(const CJS_EventRecorder* event,
226                             const WideString& value,
227                             const WideString& change) {
228   WideString prefix = value.First(event->SelStart());
229   WideString postfix;
230   int end = event->SelEnd();
231   if (end >= 0 && static_cast<size_t>(end) < value.GetLength())
232     postfix = value.Last(value.GetLength() - static_cast<size_t>(end));
233   return prefix + change + postfix;
234 }
235 
236 template <CJS_Result (*F)(CJS_Runtime*,
237                           const std::vector<v8::Local<v8::Value>>&)>
JSGlobalFunc(const char * func_name_string,const v8::FunctionCallbackInfo<v8::Value> & info)238 void JSGlobalFunc(const char* func_name_string,
239                   const v8::FunctionCallbackInfo<v8::Value>& info) {
240   CJS_Object* pObj = CFXJS_Engine::GetObjectPrivate(info.Holder());
241   if (!pObj)
242     return;
243 
244   CJS_Runtime* pRuntime = pObj->GetRuntime();
245   if (!pRuntime)
246     return;
247 
248   std::vector<v8::Local<v8::Value>> parameters;
249   for (int i = 0; i < info.Length(); ++i)
250     parameters.push_back(info[i]);
251 
252   CJS_Result result = (*F)(pRuntime, parameters);
253   if (result.HasError()) {
254     pRuntime->Error(
255         JSFormatErrorString(func_name_string, nullptr, result.Error()));
256     return;
257   }
258 
259   if (result.HasReturn())
260     info.GetReturnValue().Set(result.Return());
261 }
262 
WithinBoundsOrZero(int value,size_t size)263 int WithinBoundsOrZero(int value, size_t size) {
264   return value >= 0 && static_cast<size_t>(value) < size ? value : 0;
265 }
266 
ValidStyleOrZero(int style)267 int ValidStyleOrZero(int style) {
268   return WithinBoundsOrZero(style, 4);
269 }
270 
IsDigitSeparatorOrDecimalMark(int c)271 bool IsDigitSeparatorOrDecimalMark(int c) {
272   return c == '.' || c == ',';
273 }
274 
275 #if !defined(OS_ANDROID)
IsStyleWithDigitSeparator(int style)276 bool IsStyleWithDigitSeparator(int style) {
277   return style == 0 || style == 2;
278 }
279 
DigitSeparatorForStyle(int style)280 char DigitSeparatorForStyle(int style) {
281   ASSERT(IsStyleWithDigitSeparator(style));
282   return style == 0 ? ',' : '.';
283 }
284 
IsStyleWithApostropheSeparator(int style)285 bool IsStyleWithApostropheSeparator(int style) {
286   return style >= 4;
287 }
288 #endif
289 
IsStyleWithCommaDecimalMark(int style)290 bool IsStyleWithCommaDecimalMark(int style) {
291   return style == 2 || style == 3;
292 }
293 
DecimalMarkForStyle(int style)294 char DecimalMarkForStyle(int style) {
295   return IsStyleWithCommaDecimalMark(style) ? ',' : '.';
296 }
297 
298 #if !defined(OS_ANDROID)
NormalizeDecimalMark(ByteString * str)299 void NormalizeDecimalMark(ByteString* str) {
300   str->Replace(",", ".");
301 }
302 #endif
303 
NormalizeDecimalMarkW(WideString * str)304 void NormalizeDecimalMarkW(WideString* str) {
305   str->Replace(L",", L".");
306 }
307 
ApplyNamedOperation(const wchar_t * sFunction,double dValue1,double dValue2)308 Optional<double> ApplyNamedOperation(const wchar_t* sFunction,
309                                      double dValue1,
310                                      double dValue2) {
311   if (FXSYS_wcsicmp(sFunction, L"AVG") == 0 ||
312       FXSYS_wcsicmp(sFunction, L"SUM") == 0) {
313     return dValue1 + dValue2;
314   }
315   if (FXSYS_wcsicmp(sFunction, L"PRD") == 0)
316     return dValue1 * dValue2;
317   if (FXSYS_wcsicmp(sFunction, L"MIN") == 0)
318     return std::min(dValue1, dValue2);
319   if (FXSYS_wcsicmp(sFunction, L"MAX") == 0)
320     return std::max(dValue1, dValue2);
321   return {};
322 }
323 
324 }  // namespace
325 
326 // static
DefineJSObjects(CFXJS_Engine * pEngine)327 void CJS_PublicMethods::DefineJSObjects(CFXJS_Engine* pEngine) {
328   for (const auto& spec : GlobalFunctionSpecs)
329     pEngine->DefineGlobalMethod(spec.pName, spec.pMethodCall);
330 }
331 
332 #define JS_STATIC_GLOBAL_FUN(fun_name)                   \
333   void CJS_PublicMethods::fun_name##_static(             \
334       const v8::FunctionCallbackInfo<v8::Value>& info) { \
335     JSGlobalFunc<fun_name>(#fun_name, info);             \
336   }
337 
338 JS_STATIC_GLOBAL_FUN(AFNumber_Format)
JS_STATIC_GLOBAL_FUN(AFNumber_Keystroke)339 JS_STATIC_GLOBAL_FUN(AFNumber_Keystroke)
340 JS_STATIC_GLOBAL_FUN(AFPercent_Format)
341 JS_STATIC_GLOBAL_FUN(AFPercent_Keystroke)
342 JS_STATIC_GLOBAL_FUN(AFDate_FormatEx)
343 JS_STATIC_GLOBAL_FUN(AFDate_KeystrokeEx)
344 JS_STATIC_GLOBAL_FUN(AFDate_Format)
345 JS_STATIC_GLOBAL_FUN(AFDate_Keystroke)
346 JS_STATIC_GLOBAL_FUN(AFTime_FormatEx)
347 JS_STATIC_GLOBAL_FUN(AFTime_KeystrokeEx)
348 JS_STATIC_GLOBAL_FUN(AFTime_Format)
349 JS_STATIC_GLOBAL_FUN(AFTime_Keystroke)
350 JS_STATIC_GLOBAL_FUN(AFSpecial_Format)
351 JS_STATIC_GLOBAL_FUN(AFSpecial_Keystroke)
352 JS_STATIC_GLOBAL_FUN(AFSpecial_KeystrokeEx)
353 JS_STATIC_GLOBAL_FUN(AFSimple)
354 JS_STATIC_GLOBAL_FUN(AFMakeNumber)
355 JS_STATIC_GLOBAL_FUN(AFSimple_Calculate)
356 JS_STATIC_GLOBAL_FUN(AFRange_Validate)
357 JS_STATIC_GLOBAL_FUN(AFMergeChange)
358 JS_STATIC_GLOBAL_FUN(AFParseDateEx)
359 JS_STATIC_GLOBAL_FUN(AFExtractNums)
360 
361 bool CJS_PublicMethods::IsNumber(const WideString& str) {
362   WideString sTrim = StrTrim(str);
363   const wchar_t* pTrim = sTrim.c_str();
364   const wchar_t* p = pTrim;
365   bool bDot = false;
366   bool bKXJS = false;
367 
368   wchar_t c;
369   while ((c = *p) != L'\0') {
370     if (IsDigitSeparatorOrDecimalMark(c)) {
371       if (bDot)
372         return false;
373       bDot = true;
374     } else if (c == L'-' || c == L'+') {
375       if (p != pTrim)
376         return false;
377     } else if (c == L'e' || c == L'E') {
378       if (bKXJS)
379         return false;
380 
381       p++;
382       c = *p;
383       if (c != L'+' && c != L'-')
384         return false;
385       bKXJS = true;
386     } else if (!FXSYS_IsDecimalDigit(c)) {
387       return false;
388     }
389     p++;
390   }
391 
392   return true;
393 }
394 
MaskSatisfied(wchar_t c_Change,wchar_t c_Mask)395 bool CJS_PublicMethods::MaskSatisfied(wchar_t c_Change, wchar_t c_Mask) {
396   switch (c_Mask) {
397     case L'9':
398       return !!FXSYS_IsDecimalDigit(c_Change);
399     case L'A':
400       return isascii(c_Change) && isalpha(c_Change);
401     case L'O':
402       return isascii(c_Change) && isalnum(c_Change);
403     case L'X':
404       return true;
405     default:
406       return (c_Change == c_Mask);
407   }
408 }
409 
IsReservedMaskChar(wchar_t ch)410 bool CJS_PublicMethods::IsReservedMaskChar(wchar_t ch) {
411   return ch == L'9' || ch == L'A' || ch == L'O' || ch == L'X';
412 }
413 
AF_MakeArrayFromList(CJS_Runtime * pRuntime,v8::Local<v8::Value> val)414 v8::Local<v8::Array> CJS_PublicMethods::AF_MakeArrayFromList(
415     CJS_Runtime* pRuntime,
416     v8::Local<v8::Value> val) {
417   ASSERT(!val.IsEmpty());
418   if (val->IsArray())
419     return pRuntime->ToArray(val);
420 
421   ASSERT(val->IsString());
422   WideString wsStr = pRuntime->ToWideString(val);
423   ByteString t = wsStr.ToDefANSI();
424   const char* p = t.c_str();
425 
426   int nIndex = 0;
427   v8::Local<v8::Array> StrArray = pRuntime->NewArray();
428   while (*p) {
429     const char* pTemp = strchr(p, ',');
430     if (!pTemp) {
431       pRuntime->PutArrayElement(
432           StrArray, nIndex,
433           pRuntime->NewString(StrTrim(ByteString(p)).AsStringView()));
434       break;
435     }
436 
437     pRuntime->PutArrayElement(
438         StrArray, nIndex,
439         pRuntime->NewString(StrTrim(ByteString(p, pTemp - p)).AsStringView()));
440 
441     nIndex++;
442     p = ++pTemp;
443   }
444   return StrArray;
445 }
446 
ParseDate(const WideString & value,bool * bWrongFormat)447 double CJS_PublicMethods::ParseDate(const WideString& value,
448                                     bool* bWrongFormat) {
449   double dt = FX_GetDateTime();
450   int nYear = FX_GetYearFromTime(dt);
451   int nMonth = FX_GetMonthFromTime(dt) + 1;
452   int nDay = FX_GetDayFromTime(dt);
453   int nHour = FX_GetHourFromTime(dt);
454   int nMin = FX_GetMinFromTime(dt);
455   int nSec = FX_GetSecFromTime(dt);
456 
457   int number[3];
458 
459   size_t nSkip = 0;
460   size_t nLen = value.GetLength();
461   size_t nIndex = 0;
462   size_t i = 0;
463   while (i < nLen) {
464     if (nIndex > 2)
465       break;
466 
467     wchar_t c = value[i];
468     if (FXSYS_IsDecimalDigit(c)) {
469       number[nIndex++] = FX_ParseStringInteger(value, i, &nSkip, 4);
470       i += nSkip;
471     } else {
472       i++;
473     }
474   }
475 
476   if (nIndex == 2) {
477     // TODO(thestig): Should the else case set |bWrongFormat| to true?
478     // case2: month/day
479     // case3: day/month
480     if (FX_IsValidMonth(number[0]) && FX_IsValidDay(number[1])) {
481       nMonth = number[0];
482       nDay = number[1];
483     } else if (FX_IsValidDay(number[0]) && FX_IsValidMonth(number[1])) {
484       nDay = number[0];
485       nMonth = number[1];
486     }
487 
488     if (bWrongFormat)
489       *bWrongFormat = false;
490   } else if (nIndex == 3) {
491     // TODO(thestig): Should the else case set |bWrongFormat| to true?
492     // case1: year/month/day
493     // case2: month/day/year
494     // case3: day/month/year
495     if (number[0] > 12 && FX_IsValidMonth(number[1]) &&
496         FX_IsValidDay(number[2])) {
497       nYear = number[0];
498       nMonth = number[1];
499       nDay = number[2];
500     } else if (FX_IsValidMonth(number[0]) && FX_IsValidDay(number[1]) &&
501                number[2] > 31) {
502       nMonth = number[0];
503       nDay = number[1];
504       nYear = number[2];
505     } else if (FX_IsValidDay(number[0]) && FX_IsValidMonth(number[1]) &&
506                number[2] > 31) {
507       nDay = number[0];
508       nMonth = number[1];
509       nYear = number[2];
510     }
511 
512     if (bWrongFormat)
513       *bWrongFormat = false;
514   } else {
515     if (bWrongFormat)
516       *bWrongFormat = true;
517     return dt;
518   }
519 
520   // TODO(thestig): Should we set |bWrongFormat| to false here too?
521   return JS_DateParse(WideString::Format(L"%d/%d/%d %d:%d:%d", nMonth, nDay,
522                                          nYear, nHour, nMin, nSec));
523 }
524 
ParseDateUsingFormat(const WideString & value,const WideString & format,bool * bWrongFormat)525 double CJS_PublicMethods::ParseDateUsingFormat(const WideString& value,
526                                                const WideString& format,
527                                                bool* bWrongFormat) {
528   double dRet = std::nan("");
529   fxjs::ConversionStatus status = FX_ParseDateUsingFormat(value, format, &dRet);
530   if (status == fxjs::ConversionStatus::kSuccess)
531     return dRet;
532 
533   if (status == fxjs::ConversionStatus::kBadDate) {
534     dRet = JS_DateParse(value);
535     if (!std::isnan(dRet))
536       return dRet;
537   }
538 
539   bool bBadFormat = false;
540   dRet = ParseDate(value, &bBadFormat);
541   if (bWrongFormat)
542     *bWrongFormat = bBadFormat;
543 
544   return dRet;
545 }
546 
PrintDateUsingFormat(double dDate,const WideString & format)547 WideString CJS_PublicMethods::PrintDateUsingFormat(double dDate,
548                                                    const WideString& format) {
549   WideString sRet;
550   WideString sPart;
551 
552   int nYear = FX_GetYearFromTime(dDate);
553   int nMonth = FX_GetMonthFromTime(dDate) + 1;
554   int nDay = FX_GetDayFromTime(dDate);
555   int nHour = FX_GetHourFromTime(dDate);
556   int nMin = FX_GetMinFromTime(dDate);
557   int nSec = FX_GetSecFromTime(dDate);
558 
559   size_t i = 0;
560   while (i < format.GetLength()) {
561     wchar_t c = format[i];
562     size_t remaining = format.GetLength() - i - 1;
563     sPart.clear();
564     switch (c) {
565       case 'y':
566       case 'm':
567       case 'd':
568       case 'H':
569       case 'h':
570       case 'M':
571       case 's':
572       case 't':
573         if (remaining == 0 || format[i + 1] != c) {
574           switch (c) {
575             case 'y':
576               sPart += c;
577               break;
578             case 'm':
579               sPart = WideString::Format(L"%d", nMonth);
580               break;
581             case 'd':
582               sPart = WideString::Format(L"%d", nDay);
583               break;
584             case 'H':
585               sPart = WideString::Format(L"%d", nHour);
586               break;
587             case 'h':
588               sPart =
589                   WideString::Format(L"%d", nHour > 12 ? nHour - 12 : nHour);
590               break;
591             case 'M':
592               sPart = WideString::Format(L"%d", nMin);
593               break;
594             case 's':
595               sPart = WideString::Format(L"%d", nSec);
596               break;
597             case 't':
598               sPart += nHour > 12 ? 'p' : 'a';
599               break;
600           }
601           i++;
602         } else if (remaining == 1 || format[i + 2] != c) {
603           switch (c) {
604             case 'y':
605               sPart = WideString::Format(L"%02d", nYear - (nYear / 100) * 100);
606               break;
607             case 'm':
608               sPart = WideString::Format(L"%02d", nMonth);
609               break;
610             case 'd':
611               sPart = WideString::Format(L"%02d", nDay);
612               break;
613             case 'H':
614               sPart = WideString::Format(L"%02d", nHour);
615               break;
616             case 'h':
617               sPart =
618                   WideString::Format(L"%02d", nHour > 12 ? nHour - 12 : nHour);
619               break;
620             case 'M':
621               sPart = WideString::Format(L"%02d", nMin);
622               break;
623             case 's':
624               sPart = WideString::Format(L"%02d", nSec);
625               break;
626             case 't':
627               sPart = nHour > 12 ? L"pm" : L"am";
628               break;
629           }
630           i += 2;
631         } else if (remaining == 2 || format[i + 3] != c) {
632           switch (c) {
633             case 'm':
634               i += 3;
635               if (FX_IsValidMonth(nMonth))
636                 sPart += fxjs::kMonths[nMonth - 1];
637               break;
638             default:
639               i += 3;
640               sPart += c;
641               sPart += c;
642               sPart += c;
643               break;
644           }
645         } else if (remaining == 3 || format[i + 4] != c) {
646           switch (c) {
647             case 'y':
648               sPart = WideString::Format(L"%04d", nYear);
649               i += 4;
650               break;
651             case 'm':
652               i += 4;
653               if (FX_IsValidMonth(nMonth))
654                 sPart += fxjs::kFullMonths[nMonth - 1];
655               break;
656             default:
657               i += 4;
658               sPart += c;
659               sPart += c;
660               sPart += c;
661               sPart += c;
662               break;
663           }
664         } else {
665           i++;
666           sPart += c;
667         }
668         break;
669       default:
670         i++;
671         sPart += c;
672         break;
673     }
674 
675     sRet += sPart;
676   }
677 
678   return sRet;
679 }
680 
681 // function AFNumber_Format(nDec, sepStyle, negStyle, currStyle, strCurrency,
682 // bCurrencyPrepend)
AFNumber_Format(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)683 CJS_Result CJS_PublicMethods::AFNumber_Format(
684     CJS_Runtime* pRuntime,
685     const std::vector<v8::Local<v8::Value>>& params) {
686 #if !defined(OS_ANDROID)
687   if (params.size() != 6)
688     return CJS_Result::Failure(JSMessage::kParamError);
689 
690   CJS_EventContext* pEventContext = pRuntime->GetCurrentEventContext();
691   CJS_EventRecorder* pEvent = pEventContext->GetEventRecorder();
692   if (!pEvent->HasValue())
693     return CJS_Result::Failure(WideString::FromASCII("No event handler"));
694 
695   WideString& Value = pEvent->Value();
696   ByteString strValue = StrTrim(Value.ToDefANSI());
697   if (strValue.IsEmpty())
698     return CJS_Result::Success();
699 
700   int iDec = abs(pRuntime->ToInt32(params[0]));
701   int iSepStyle = ValidStyleOrZero(pRuntime->ToInt32(params[1]));
702   int iNegStyle = ValidStyleOrZero(pRuntime->ToInt32(params[2]));
703   // params[3] is iCurrStyle, it's not used.
704   WideString wstrCurrency = pRuntime->ToWideString(params[4]);
705   bool bCurrencyPrepend = pRuntime->ToBoolean(params[5]);
706 
707   // Processing decimal places
708   NormalizeDecimalMark(&strValue);
709   double dValue = atof(strValue.c_str());
710   if (iDec > 0)
711     dValue += kDoubleCorrect;
712 
713   // Calculating number string
714   bool bNegative;
715   int iDec2;
716   strValue = CalculateString(dValue, iDec, &iDec2, &bNegative);
717   if (strValue.IsEmpty()) {
718     dValue = 0;
719     strValue = CalculateString(dValue, iDec, &iDec2, &bNegative);
720     if (strValue.IsEmpty()) {
721       strValue = "0";
722       iDec2 = 1;
723     }
724   }
725   ASSERT(iDec2 >= 0);
726 
727   // Processing separator style
728   if (static_cast<size_t>(iDec2) < strValue.GetLength()) {
729     if (IsStyleWithCommaDecimalMark(iSepStyle))
730       strValue.Replace(".", ",");
731 
732     if (iDec2 == 0)
733       strValue.Insert(iDec2, '0');
734   }
735   if (IsStyleWithDigitSeparator(iSepStyle)) {
736     char cSeparator = DigitSeparatorForStyle(iSepStyle);
737     for (int iDecPositive = iDec2 - 3; iDecPositive > 0; iDecPositive -= 3)
738       strValue.Insert(iDecPositive, cSeparator);
739   }
740 
741   // Processing currency string
742   Value = WideString::FromDefANSI(strValue.AsStringView());
743   if (bCurrencyPrepend)
744     Value = wstrCurrency + Value;
745   else
746     Value = Value + wstrCurrency;
747 
748   // Processing negative style
749   if (bNegative) {
750     if (iNegStyle == 0) {
751       Value.InsertAtFront(L'-');
752     } else if (iNegStyle == 2 || iNegStyle == 3) {
753       Value.InsertAtFront(L'(');
754       Value += L')';
755     }
756     if (iNegStyle == 1 || iNegStyle == 3) {
757       if (CJS_Field* fTarget = pEventContext->TargetField()) {
758         v8::Local<v8::Array> arColor = pRuntime->NewArray();
759         pRuntime->PutArrayElement(arColor, 0, pRuntime->NewString("RGB"));
760         pRuntime->PutArrayElement(arColor, 1, pRuntime->NewNumber(1));
761         pRuntime->PutArrayElement(arColor, 2, pRuntime->NewNumber(0));
762         pRuntime->PutArrayElement(arColor, 3, pRuntime->NewNumber(0));
763         fTarget->set_text_color(pRuntime, arColor);
764       }
765     }
766   } else {
767     if (iNegStyle == 1 || iNegStyle == 3) {
768       if (CJS_Field* fTarget = pEventContext->TargetField()) {
769         v8::Local<v8::Array> arColor = pRuntime->NewArray();
770         pRuntime->PutArrayElement(arColor, 0, pRuntime->NewString("RGB"));
771         pRuntime->PutArrayElement(arColor, 1, pRuntime->NewNumber(0));
772         pRuntime->PutArrayElement(arColor, 2, pRuntime->NewNumber(0));
773         pRuntime->PutArrayElement(arColor, 3, pRuntime->NewNumber(0));
774 
775         CJS_Result result = fTarget->get_text_color(pRuntime);
776         CFX_Color crProp = CJS_Color::ConvertArrayToPWLColor(
777             pRuntime, pRuntime->ToArray(result.Return()));
778         CFX_Color crColor =
779             CJS_Color::ConvertArrayToPWLColor(pRuntime, arColor);
780         if (crColor != crProp)
781           fTarget->set_text_color(pRuntime, arColor);
782       }
783     }
784   }
785 #endif
786   return CJS_Result::Success();
787 }
788 
789 // function AFNumber_Keystroke(nDec, sepStyle, negStyle, currStyle, strCurrency,
790 // bCurrencyPrepend)
AFNumber_Keystroke(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)791 CJS_Result CJS_PublicMethods::AFNumber_Keystroke(
792     CJS_Runtime* pRuntime,
793     const std::vector<v8::Local<v8::Value>>& params) {
794   if (params.size() < 2)
795     return CJS_Result::Failure(JSMessage::kParamError);
796 
797   CJS_EventContext* pContext = pRuntime->GetCurrentEventContext();
798   CJS_EventRecorder* pEvent = pContext->GetEventRecorder();
799   if (!pEvent->HasValue())
800     return CJS_Result::Failure(JSMessage::kBadObjectError);
801 
802   WideString& val = pEvent->Value();
803   WideString& wstrChange = pEvent->Change();
804   WideString wstrValue = val;
805 
806   if (pEvent->WillCommit()) {
807     WideString swTemp = StrTrim(wstrValue);
808     if (swTemp.IsEmpty())
809       return CJS_Result::Success();
810 
811     NormalizeDecimalMarkW(&swTemp);
812     if (!IsNumber(swTemp)) {
813       pEvent->Rc() = false;
814       WideString sError = JSGetStringFromID(JSMessage::kInvalidInputError);
815       AlertIfPossible(pContext, L"AFNumber_Keystroke", sError);
816       return CJS_Result::Failure(sError);
817     }
818     // It happens after the last keystroke and before validating,
819     return CJS_Result::Success();
820   }
821 
822   WideString wstrSelected;
823   if (pEvent->SelStart() != -1) {
824     wstrSelected = wstrValue.Substr(pEvent->SelStart(),
825                                     pEvent->SelEnd() - pEvent->SelStart());
826   }
827 
828   bool bHasSign = wstrValue.Contains(L'-') && !wstrSelected.Contains(L'-');
829   if (bHasSign) {
830     // can't insert "change" in front of sign position.
831     if (!wstrSelected.IsEmpty() && pEvent->SelStart() == 0) {
832       pEvent->Rc() = false;
833       return CJS_Result::Success();
834     }
835   }
836 
837   int iSepStyle = ValidStyleOrZero(pRuntime->ToInt32(params[1]));
838   const wchar_t cSep = DecimalMarkForStyle(iSepStyle);
839 
840   bool bHasSep = wstrValue.Contains(cSep);
841   for (size_t i = 0; i < wstrChange.GetLength(); ++i) {
842     if (wstrChange[i] == cSep) {
843       if (bHasSep) {
844         pEvent->Rc() = false;
845         return CJS_Result::Success();
846       }
847       bHasSep = true;
848       continue;
849     }
850     if (wstrChange[i] == L'-') {
851       if (bHasSign) {
852         pEvent->Rc() = false;
853         return CJS_Result::Success();
854       }
855       // sign's position is not correct
856       if (i != 0) {
857         pEvent->Rc() = false;
858         return CJS_Result::Success();
859       }
860       if (pEvent->SelStart() != 0) {
861         pEvent->Rc() = false;
862         return CJS_Result::Success();
863       }
864       bHasSign = true;
865       continue;
866     }
867 
868     if (!FXSYS_IsDecimalDigit(wstrChange[i])) {
869       pEvent->Rc() = false;
870       return CJS_Result::Success();
871     }
872   }
873 
874   val = CalcMergedString(pEvent, wstrValue, wstrChange);
875   return CJS_Result::Success();
876 }
877 
878 // function AFPercent_Format(nDec, sepStyle, bPercentPrepend)
AFPercent_Format(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)879 CJS_Result CJS_PublicMethods::AFPercent_Format(
880     CJS_Runtime* pRuntime,
881     const std::vector<v8::Local<v8::Value>>& params) {
882 #if !defined(OS_ANDROID)
883   if (params.size() < 2)
884     return CJS_Result::Failure(JSMessage::kParamError);
885 
886   CJS_EventRecorder* pEvent =
887       pRuntime->GetCurrentEventContext()->GetEventRecorder();
888   if (!pEvent->HasValue())
889     return CJS_Result::Failure(JSMessage::kBadObjectError);
890 
891   // Acrobat will accept this. Anything larger causes it to throw an error.
892   static constexpr int kMaxSepStyle = 49;
893 
894   int iDec = pRuntime->ToInt32(params[0]);
895   int iSepStyle = pRuntime->ToInt32(params[1]);
896   // TODO(thestig): How do we handle negative raw |bPercentPrepend| values?
897   bool bPercentPrepend = params.size() > 2 && pRuntime->ToBoolean(params[2]);
898   if (iDec < 0 || iSepStyle < 0 || iSepStyle > kMaxSepStyle)
899     return CJS_Result::Failure(JSMessage::kValueError);
900 
901   // When the |iDec| value is too big, Acrobat will just return "%".
902   static constexpr int kDecLimit = 512;
903   // This count must be in sync with |kDecLimit|.
904   static constexpr size_t kDigitsInDecLimit = 3;
905   WideString& Value = pEvent->Value();
906   if (iDec > kDecLimit) {
907     Value = L"%";
908     return CJS_Result::Success();
909   }
910 
911   ByteString strValue = StrTrim(Value.ToDefANSI());
912   if (strValue.IsEmpty())
913     strValue = "0";
914 
915   // for processing decimal places
916   double dValue = atof(strValue.c_str());
917   dValue *= 100;
918 
919   size_t szNewSize;
920   {
921     // Figure out the format to use with FXSYS_snprintf() below.
922     // |format| is small because |iDec| is limited in size.
923     char format[sizeof("%.f") + kDigitsInDecLimit];  // e.g. "%.512f"
924     FXSYS_snprintf(format, sizeof(format), "%%.%df", iDec);
925 
926     // Calculate the new size for |strValue| and get a span.
927     size_t szBufferSize = iDec + 3;  // Negative sign, decimal point, and NUL.
928     double dValueCopy = fabs(dValue);
929     while (dValueCopy > 1) {
930       dValueCopy /= 10;
931       ++szBufferSize;
932     }
933 
934     // Write into |strValue|.
935     pdfium::span<char> span = strValue.GetBuffer(szBufferSize);
936     FXSYS_snprintf(span.data(), szBufferSize, format, dValue);
937     szNewSize = strlen(span.data());
938   }
939   strValue.ReleaseBuffer(szNewSize);
940 
941   // for processing separator style
942   Optional<size_t> mark_pos = strValue.Find('.');
943   if (mark_pos.has_value()) {
944     char mark = DecimalMarkForStyle(iSepStyle);
945     if (mark != '.')
946       strValue.SetAt(mark_pos.value(), mark);
947   }
948   bool bUseDigitSeparator = IsStyleWithDigitSeparator(iSepStyle);
949   if (bUseDigitSeparator || IsStyleWithApostropheSeparator(iSepStyle)) {
950     char cSeparator =
951         bUseDigitSeparator ? DigitSeparatorForStyle(iSepStyle) : '\'';
952     int iEnd = mark_pos.value_or(strValue.GetLength());
953     int iStop = dValue < 0 ? 1 : 0;
954     for (int i = iEnd - 3; i > iStop; i -= 3)
955       strValue.Insert(i, cSeparator);
956   }
957 
958   if (bPercentPrepend)
959     strValue.InsertAtFront('%');
960   else
961     strValue.InsertAtBack('%');
962   Value = WideString::FromDefANSI(strValue.AsStringView());
963 #endif
964   return CJS_Result::Success();
965 }
966 
967 // AFPercent_Keystroke(nDec, sepStyle)
AFPercent_Keystroke(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)968 CJS_Result CJS_PublicMethods::AFPercent_Keystroke(
969     CJS_Runtime* pRuntime,
970     const std::vector<v8::Local<v8::Value>>& params) {
971   return AFNumber_Keystroke(pRuntime, params);
972 }
973 
974 // function AFDate_FormatEx(cFormat)
AFDate_FormatEx(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)975 CJS_Result CJS_PublicMethods::AFDate_FormatEx(
976     CJS_Runtime* pRuntime,
977     const std::vector<v8::Local<v8::Value>>& params) {
978   if (params.size() != 1)
979     return CJS_Result::Failure(JSMessage::kParamError);
980 
981   CJS_EventContext* pContext = pRuntime->GetCurrentEventContext();
982   CJS_EventRecorder* pEvent = pContext->GetEventRecorder();
983   if (!pEvent->HasValue())
984     return CJS_Result::Failure(JSMessage::kBadObjectError);
985 
986   WideString& val = pEvent->Value();
987   WideString strValue = val;
988   if (strValue.IsEmpty())
989     return CJS_Result::Success();
990 
991   WideString sFormat = pRuntime->ToWideString(params[0]);
992   double dDate;
993   if (strValue.Contains(L"GMT")) {
994     // e.g. "Tue Aug 11 14:24:16 GMT+08002009"
995     dDate = ParseDateAsGMT(strValue);
996   } else {
997     dDate = ParseDateUsingFormat(strValue, sFormat, nullptr);
998   }
999 
1000   if (std::isnan(dDate)) {
1001     WideString swMsg = WideString::Format(
1002         JSGetStringFromID(JSMessage::kParseDateError).c_str(), sFormat.c_str());
1003     AlertIfPossible(pContext, L"AFDate_FormatEx", swMsg);
1004     return CJS_Result::Failure(JSMessage::kParseDateError);
1005   }
1006 
1007   val = PrintDateUsingFormat(dDate, sFormat);
1008   return CJS_Result::Success();
1009 }
1010 
ParseDateAsGMT(const WideString & strValue)1011 double CJS_PublicMethods::ParseDateAsGMT(const WideString& strValue) {
1012   std::vector<WideString> wsArray;
1013   WideString sTemp;
1014   for (const auto& c : strValue) {
1015     if (c == L' ' || c == L':') {
1016       wsArray.push_back(std::move(sTemp));
1017       continue;
1018     }
1019     sTemp += c;
1020   }
1021   wsArray.push_back(std::move(sTemp));
1022   if (wsArray.size() != 8)
1023     return 0;
1024 
1025   int nMonth = 1;
1026   sTemp = wsArray[1];
1027   for (size_t i = 0; i < pdfium::size(fxjs::kMonths); ++i) {
1028     if (sTemp.Compare(fxjs::kMonths[i]) == 0) {
1029       nMonth = i + 1;
1030       break;
1031     }
1032   }
1033 
1034   int nDay = StringToFloat(wsArray[2].AsStringView());
1035   int nHour = StringToFloat(wsArray[3].AsStringView());
1036   int nMin = StringToFloat(wsArray[4].AsStringView());
1037   int nSec = StringToFloat(wsArray[5].AsStringView());
1038   int nYear = StringToFloat(wsArray[7].AsStringView());
1039   double dRet = FX_MakeDate(FX_MakeDay(nYear, nMonth - 1, nDay),
1040                             FX_MakeTime(nHour, nMin, nSec, 0));
1041   if (std::isnan(dRet))
1042     dRet = JS_DateParse(strValue);
1043 
1044   return dRet;
1045 }
1046 
1047 // AFDate_KeystrokeEx(cFormat)
AFDate_KeystrokeEx(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1048 CJS_Result CJS_PublicMethods::AFDate_KeystrokeEx(
1049     CJS_Runtime* pRuntime,
1050     const std::vector<v8::Local<v8::Value>>& params) {
1051   if (params.size() != 1) {
1052     return CJS_Result::Failure(WideString::FromASCII(
1053         "AFDate_KeystrokeEx's parameter size not correct"));
1054   }
1055 
1056   CJS_EventContext* pContext = pRuntime->GetCurrentEventContext();
1057   CJS_EventRecorder* pEvent = pContext->GetEventRecorder();
1058   if (!pEvent->WillCommit())
1059     return CJS_Result::Success();
1060 
1061   if (!pEvent->HasValue())
1062     return CJS_Result::Failure(JSMessage::kBadObjectError);
1063 
1064   const WideString& strValue = pEvent->Value();
1065   if (strValue.IsEmpty())
1066     return CJS_Result::Success();
1067 
1068   bool bWrongFormat = false;
1069   WideString sFormat = pRuntime->ToWideString(params[0]);
1070   double dRet = ParseDateUsingFormat(strValue, sFormat, &bWrongFormat);
1071   if (bWrongFormat || std::isnan(dRet)) {
1072     WideString swMsg = WideString::Format(
1073         JSGetStringFromID(JSMessage::kParseDateError).c_str(), sFormat.c_str());
1074     AlertIfPossible(pContext, L"AFDate_KeystrokeEx", swMsg);
1075     pEvent->Rc() = false;
1076   }
1077   return CJS_Result::Success();
1078 }
1079 
AFDate_Format(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1080 CJS_Result CJS_PublicMethods::AFDate_Format(
1081     CJS_Runtime* pRuntime,
1082     const std::vector<v8::Local<v8::Value>>& params) {
1083   if (params.size() != 1)
1084     return CJS_Result::Failure(JSMessage::kParamError);
1085 
1086   int iIndex = WithinBoundsOrZero(pRuntime->ToInt32(params[0]),
1087                                   pdfium::size(kDateFormats));
1088   std::vector<v8::Local<v8::Value>> newParams;
1089   newParams.push_back(pRuntime->NewString(kDateFormats[iIndex]));
1090   return AFDate_FormatEx(pRuntime, newParams);
1091 }
1092 
1093 // AFDate_KeystrokeEx(cFormat)
AFDate_Keystroke(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1094 CJS_Result CJS_PublicMethods::AFDate_Keystroke(
1095     CJS_Runtime* pRuntime,
1096     const std::vector<v8::Local<v8::Value>>& params) {
1097   if (params.size() != 1)
1098     return CJS_Result::Failure(JSMessage::kParamError);
1099 
1100   int iIndex = WithinBoundsOrZero(pRuntime->ToInt32(params[0]),
1101                                   pdfium::size(kDateFormats));
1102   std::vector<v8::Local<v8::Value>> newParams;
1103   newParams.push_back(pRuntime->NewString(kDateFormats[iIndex]));
1104   return AFDate_KeystrokeEx(pRuntime, newParams);
1105 }
1106 
1107 // function AFTime_Format(ptf)
AFTime_Format(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1108 CJS_Result CJS_PublicMethods::AFTime_Format(
1109     CJS_Runtime* pRuntime,
1110     const std::vector<v8::Local<v8::Value>>& params) {
1111   if (params.size() != 1)
1112     return CJS_Result::Failure(JSMessage::kParamError);
1113 
1114   int iIndex = WithinBoundsOrZero(pRuntime->ToInt32(params[0]),
1115                                   pdfium::size(kTimeFormats));
1116   std::vector<v8::Local<v8::Value>> newParams;
1117   newParams.push_back(pRuntime->NewString(kTimeFormats[iIndex]));
1118   return AFDate_FormatEx(pRuntime, newParams);
1119 }
1120 
AFTime_Keystroke(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1121 CJS_Result CJS_PublicMethods::AFTime_Keystroke(
1122     CJS_Runtime* pRuntime,
1123     const std::vector<v8::Local<v8::Value>>& params) {
1124   if (params.size() != 1)
1125     return CJS_Result::Failure(JSMessage::kParamError);
1126 
1127   int iIndex = WithinBoundsOrZero(pRuntime->ToInt32(params[0]),
1128                                   pdfium::size(kTimeFormats));
1129   std::vector<v8::Local<v8::Value>> newParams;
1130   newParams.push_back(pRuntime->NewString(kTimeFormats[iIndex]));
1131   return AFDate_KeystrokeEx(pRuntime, newParams);
1132 }
1133 
AFTime_FormatEx(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1134 CJS_Result CJS_PublicMethods::AFTime_FormatEx(
1135     CJS_Runtime* pRuntime,
1136     const std::vector<v8::Local<v8::Value>>& params) {
1137   return AFDate_FormatEx(pRuntime, params);
1138 }
1139 
AFTime_KeystrokeEx(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1140 CJS_Result CJS_PublicMethods::AFTime_KeystrokeEx(
1141     CJS_Runtime* pRuntime,
1142     const std::vector<v8::Local<v8::Value>>& params) {
1143   return AFDate_KeystrokeEx(pRuntime, params);
1144 }
1145 
1146 // function AFSpecial_Format(psf)
AFSpecial_Format(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1147 CJS_Result CJS_PublicMethods::AFSpecial_Format(
1148     CJS_Runtime* pRuntime,
1149     const std::vector<v8::Local<v8::Value>>& params) {
1150   if (params.size() != 1)
1151     return CJS_Result::Failure(JSMessage::kParamError);
1152 
1153   CJS_EventRecorder* pEvent =
1154       pRuntime->GetCurrentEventContext()->GetEventRecorder();
1155   if (!pEvent->HasValue())
1156     return CJS_Result::Failure(JSMessage::kBadObjectError);
1157 
1158   const WideString& wsSource = pEvent->Value();
1159   WideString wsFormat;
1160   switch (pRuntime->ToInt32(params[0])) {
1161     case 0:
1162       wsFormat = L"99999";
1163       break;
1164     case 1:
1165       wsFormat = L"99999-9999";
1166       break;
1167     case 2:
1168       if (CJS_Util::StringPrintx(L"9999999999", wsSource).GetLength() >= 10)
1169         wsFormat = L"(999) 999-9999";
1170       else
1171         wsFormat = L"999-9999";
1172       break;
1173     case 3:
1174       wsFormat = L"999-99-9999";
1175       break;
1176   }
1177 
1178   pEvent->Value() = CJS_Util::StringPrintx(wsFormat, wsSource);
1179   return CJS_Result::Success();
1180 }
1181 
1182 // function AFSpecial_KeystrokeEx(mask)
AFSpecial_KeystrokeEx(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1183 CJS_Result CJS_PublicMethods::AFSpecial_KeystrokeEx(
1184     CJS_Runtime* pRuntime,
1185     const std::vector<v8::Local<v8::Value>>& params) {
1186   if (params.size() < 1)
1187     return CJS_Result::Failure(JSMessage::kParamError);
1188 
1189   CJS_EventContext* pContext = pRuntime->GetCurrentEventContext();
1190   CJS_EventRecorder* pEvent = pContext->GetEventRecorder();
1191   if (!pEvent->HasValue())
1192     return CJS_Result::Failure(JSMessage::kBadObjectError);
1193 
1194   const WideString& valEvent = pEvent->Value();
1195   WideString wstrMask = pRuntime->ToWideString(params[0]);
1196   if (wstrMask.IsEmpty())
1197     return CJS_Result::Success();
1198 
1199   if (pEvent->WillCommit()) {
1200     if (valEvent.IsEmpty())
1201       return CJS_Result::Success();
1202 
1203     if (valEvent.GetLength() > wstrMask.GetLength()) {
1204       AlertIfPossible(pContext, L"AFSpecial_KeystrokeEx",
1205                       JSGetStringFromID(JSMessage::kParamTooLongError));
1206       pEvent->Rc() = false;
1207       return CJS_Result::Success();
1208     }
1209 
1210     size_t iIndex = 0;
1211     for (iIndex = 0; iIndex < valEvent.GetLength(); ++iIndex) {
1212       if (!MaskSatisfied(valEvent[iIndex], wstrMask[iIndex]))
1213         break;
1214     }
1215     if (iIndex != wstrMask.GetLength()) {
1216       AlertIfPossible(pContext, L"AFSpecial_KeystrokeEx",
1217                       JSGetStringFromID(JSMessage::kInvalidInputError));
1218       pEvent->Rc() = false;
1219     }
1220     return CJS_Result::Success();
1221   }
1222 
1223   WideString& wideChange = pEvent->Change();
1224   if (wideChange.IsEmpty())
1225     return CJS_Result::Success();
1226 
1227   WideString wChange = wideChange;
1228   size_t iIndexMask = pEvent->SelStart();
1229   size_t combined_len = valEvent.GetLength() + wChange.GetLength() +
1230                         pEvent->SelStart() - pEvent->SelEnd();
1231   if (combined_len > wstrMask.GetLength()) {
1232     AlertIfPossible(pContext, L"AFSpecial_KeystrokeEx",
1233                     JSGetStringFromID(JSMessage::kParamTooLongError));
1234     pEvent->Rc() = false;
1235     return CJS_Result::Success();
1236   }
1237 
1238   if (iIndexMask >= wstrMask.GetLength() && !wChange.IsEmpty()) {
1239     AlertIfPossible(pContext, L"AFSpecial_KeystrokeEx",
1240                     JSGetStringFromID(JSMessage::kParamTooLongError));
1241     pEvent->Rc() = false;
1242     return CJS_Result::Success();
1243   }
1244 
1245   for (size_t i = 0; i < wChange.GetLength(); ++i) {
1246     if (iIndexMask >= wstrMask.GetLength()) {
1247       AlertIfPossible(pContext, L"AFSpecial_KeystrokeEx",
1248                       JSGetStringFromID(JSMessage::kParamTooLongError));
1249       pEvent->Rc() = false;
1250       return CJS_Result::Success();
1251     }
1252     wchar_t wMask = wstrMask[iIndexMask];
1253     if (!IsReservedMaskChar(wMask))
1254       wChange.SetAt(i, wMask);
1255 
1256     if (!MaskSatisfied(wChange[i], wMask)) {
1257       pEvent->Rc() = false;
1258       return CJS_Result::Success();
1259     }
1260     iIndexMask++;
1261   }
1262   wideChange = std::move(wChange);
1263   return CJS_Result::Success();
1264 }
1265 
1266 // function AFSpecial_Keystroke(psf)
AFSpecial_Keystroke(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1267 CJS_Result CJS_PublicMethods::AFSpecial_Keystroke(
1268     CJS_Runtime* pRuntime,
1269     const std::vector<v8::Local<v8::Value>>& params) {
1270   if (params.size() != 1)
1271     return CJS_Result::Failure(JSMessage::kParamError);
1272 
1273   CJS_EventRecorder* pEvent =
1274       pRuntime->GetCurrentEventContext()->GetEventRecorder();
1275   if (!pEvent->HasValue())
1276     return CJS_Result::Failure(JSMessage::kBadObjectError);
1277 
1278   const char* cFormat = "";
1279   switch (pRuntime->ToInt32(params[0])) {
1280     case 0:
1281       cFormat = "99999";
1282       break;
1283     case 1:
1284       cFormat = "999999999";
1285       break;
1286     case 2:
1287       if (pEvent->Value().GetLength() + pEvent->Change().GetLength() > 7)
1288         cFormat = "9999999999";
1289       else
1290         cFormat = "9999999";
1291       break;
1292     case 3:
1293       cFormat = "999999999";
1294       break;
1295   }
1296 
1297   std::vector<v8::Local<v8::Value>> params2;
1298   params2.push_back(pRuntime->NewString(cFormat));
1299   return AFSpecial_KeystrokeEx(pRuntime, params2);
1300 }
1301 
AFMergeChange(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1302 CJS_Result CJS_PublicMethods::AFMergeChange(
1303     CJS_Runtime* pRuntime,
1304     const std::vector<v8::Local<v8::Value>>& params) {
1305   if (params.size() != 1)
1306     return CJS_Result::Failure(JSMessage::kParamError);
1307 
1308   CJS_EventRecorder* pEventRecorder =
1309       pRuntime->GetCurrentEventContext()->GetEventRecorder();
1310 
1311   WideString swValue;
1312   if (pEventRecorder->HasValue())
1313     swValue = pEventRecorder->Value();
1314 
1315   if (pEventRecorder->WillCommit())
1316     return CJS_Result::Success(pRuntime->NewString(swValue.AsStringView()));
1317 
1318   return CJS_Result::Success(pRuntime->NewString(
1319       CalcMergedString(pEventRecorder, swValue, pEventRecorder->Change())
1320           .AsStringView()));
1321 }
1322 
AFParseDateEx(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1323 CJS_Result CJS_PublicMethods::AFParseDateEx(
1324     CJS_Runtime* pRuntime,
1325     const std::vector<v8::Local<v8::Value>>& params) {
1326   if (params.size() != 2)
1327     return CJS_Result::Failure(JSMessage::kParamError);
1328 
1329   WideString sValue = pRuntime->ToWideString(params[0]);
1330   WideString sFormat = pRuntime->ToWideString(params[1]);
1331   double dDate = ParseDateUsingFormat(sValue, sFormat, nullptr);
1332   if (std::isnan(dDate)) {
1333     WideString swMsg = WideString::Format(
1334         JSGetStringFromID(JSMessage::kParseDateError).c_str(), sFormat.c_str());
1335     AlertIfPossible(pRuntime->GetCurrentEventContext(), L"AFParseDateEx",
1336                     swMsg);
1337     return CJS_Result::Failure(JSMessage::kParseDateError);
1338   }
1339   return CJS_Result::Success(pRuntime->NewNumber(dDate));
1340 }
1341 
AFSimple(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1342 CJS_Result CJS_PublicMethods::AFSimple(
1343     CJS_Runtime* pRuntime,
1344     const std::vector<v8::Local<v8::Value>>& params) {
1345   if (params.size() != 3)
1346     return CJS_Result::Failure(JSMessage::kParamError);
1347 
1348   WideString sFunction = pRuntime->ToWideString(params[0]);
1349   double arg1 = pRuntime->ToDouble(params[1]);
1350   double arg2 = pRuntime->ToDouble(params[2]);
1351   if (std::isnan(arg1) || std::isnan(arg2))
1352     return CJS_Result::Failure(JSMessage::kValueError);
1353 
1354   Optional<double> result = ApplyNamedOperation(sFunction.c_str(), arg1, arg2);
1355   if (!result.has_value())
1356     return CJS_Result::Failure(JSMessage::kValueError);
1357 
1358   double dValue = result.value();
1359   if (wcscmp(sFunction.c_str(), L"AVG") == 0)
1360     dValue /= 2.0;
1361 
1362   return CJS_Result::Success(pRuntime->NewNumber(dValue));
1363 }
1364 
AFMakeNumber(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1365 CJS_Result CJS_PublicMethods::AFMakeNumber(
1366     CJS_Runtime* pRuntime,
1367     const std::vector<v8::Local<v8::Value>>& params) {
1368   if (params.size() != 1)
1369     return CJS_Result::Failure(JSMessage::kParamError);
1370 
1371   WideString ws = pRuntime->ToWideString(params[0]);
1372   NormalizeDecimalMarkW(&ws);
1373 
1374   v8::Local<v8::Value> val =
1375       pRuntime->MaybeCoerceToNumber(pRuntime->NewString(ws.AsStringView()));
1376   if (!val->IsNumber())
1377     return CJS_Result::Success(pRuntime->NewNumber(0));
1378 
1379   return CJS_Result::Success(val);
1380 }
1381 
AFSimple_Calculate(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1382 CJS_Result CJS_PublicMethods::AFSimple_Calculate(
1383     CJS_Runtime* pRuntime,
1384     const std::vector<v8::Local<v8::Value>>& params) {
1385   if (params.size() != 2)
1386     return CJS_Result::Failure(JSMessage::kParamError);
1387 
1388   if (params[1].IsEmpty() || (!params[1]->IsArray() && !params[1]->IsString()))
1389     return CJS_Result::Failure(JSMessage::kParamError);
1390 
1391   WideString sFunction = pRuntime->ToWideString(params[0]);
1392   v8::Local<v8::Array> FieldNameArray =
1393       AF_MakeArrayFromList(pRuntime, params[1]);
1394 
1395   CPDFSDK_InteractiveForm* pReaderForm =
1396       pRuntime->GetFormFillEnv()->GetInteractiveForm();
1397   CPDF_InteractiveForm* pForm = pReaderForm->GetInteractiveForm();
1398 
1399   double dValue = wcscmp(sFunction.c_str(), L"PRD") == 0 ? 1.0 : 0.0;
1400   int nFieldsCount = 0;
1401   for (size_t i = 0; i < pRuntime->GetArrayLength(FieldNameArray); ++i) {
1402     WideString wsFieldName =
1403         pRuntime->ToWideString(pRuntime->GetArrayElement(FieldNameArray, i));
1404 
1405     for (size_t j = 0; j < pForm->CountFields(wsFieldName); ++j) {
1406       CPDF_FormField* pFormField = pForm->GetField(j, wsFieldName);
1407       if (!pFormField)
1408         continue;
1409 
1410       double dTemp = 0.0;
1411       switch (pFormField->GetFieldType()) {
1412         case FormFieldType::kTextField:
1413         case FormFieldType::kComboBox: {
1414           WideString trimmed = pFormField->GetValue();
1415           trimmed.TrimRight();
1416           trimmed.TrimLeft();
1417           dTemp = StringToDouble(trimmed.AsStringView());
1418           break;
1419         }
1420         case FormFieldType::kPushButton:
1421           break;
1422         case FormFieldType::kCheckBox:
1423         case FormFieldType::kRadioButton:
1424           for (int c = 0; c < pFormField->CountControls(); ++c) {
1425             CPDF_FormControl* pFormCtrl = pFormField->GetControl(c);
1426             if (!pFormField || !pFormCtrl->IsChecked())
1427               continue;
1428 
1429             WideString trimmed = pFormCtrl->GetExportValue();
1430             trimmed.TrimRight();
1431             trimmed.TrimLeft();
1432             dTemp = StringToFloat(trimmed.AsStringView());
1433             break;
1434           }
1435           break;
1436         case FormFieldType::kListBox:
1437           if (pFormField->CountSelectedItems() <= 1) {
1438             WideString trimmed = pFormField->GetValue();
1439             trimmed.TrimRight();
1440             trimmed.TrimLeft();
1441             dTemp = StringToFloat(trimmed.AsStringView());
1442           }
1443           break;
1444         default:
1445           break;
1446       }
1447 
1448       if (i == 0 && j == 0 &&
1449           (wcscmp(sFunction.c_str(), L"MIN") == 0 ||
1450            wcscmp(sFunction.c_str(), L"MAX") == 0)) {
1451         dValue = dTemp;
1452       }
1453       Optional<double> dResult =
1454           ApplyNamedOperation(sFunction.c_str(), dValue, dTemp);
1455       if (!dResult.has_value())
1456         return CJS_Result::Failure(JSMessage::kValueError);
1457 
1458       dValue = dResult.value();
1459       nFieldsCount++;
1460     }
1461   }
1462 
1463   if (wcscmp(sFunction.c_str(), L"AVG") == 0 && nFieldsCount > 0)
1464     dValue /= nFieldsCount;
1465 
1466   dValue = floor(dValue * FXSYS_pow(10, 6) + 0.49) / FXSYS_pow(10, 6);
1467 
1468   CJS_EventContext* pContext = pRuntime->GetCurrentEventContext();
1469   if (pContext->GetEventRecorder()->HasValue()) {
1470     pContext->GetEventRecorder()->Value() =
1471         pRuntime->ToWideString(pRuntime->NewNumber(dValue));
1472   }
1473 
1474   return CJS_Result::Success();
1475 }
1476 
1477 // This function validates the current event to ensure that its value is
1478 // within the specified range.
AFRange_Validate(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1479 CJS_Result CJS_PublicMethods::AFRange_Validate(
1480     CJS_Runtime* pRuntime,
1481     const std::vector<v8::Local<v8::Value>>& params) {
1482   if (params.size() != 4)
1483     return CJS_Result::Failure(JSMessage::kParamError);
1484 
1485   CJS_EventContext* pContext = pRuntime->GetCurrentEventContext();
1486   CJS_EventRecorder* pEvent = pContext->GetEventRecorder();
1487   if (!pEvent->HasValue())
1488     return CJS_Result::Failure(JSMessage::kBadObjectError);
1489 
1490   if (pEvent->Value().IsEmpty())
1491     return CJS_Result::Success();
1492 
1493   double dEentValue = atof(pEvent->Value().ToDefANSI().c_str());
1494   bool bGreaterThan = pRuntime->ToBoolean(params[0]);
1495   double dGreaterThan = pRuntime->ToDouble(params[1]);
1496   bool bLessThan = pRuntime->ToBoolean(params[2]);
1497   double dLessThan = pRuntime->ToDouble(params[3]);
1498   WideString swMsg;
1499 
1500   if (bGreaterThan && bLessThan) {
1501     if (dEentValue < dGreaterThan || dEentValue > dLessThan)
1502       swMsg = WideString::Format(
1503           JSGetStringFromID(JSMessage::kRangeBetweenError).c_str(),
1504           pRuntime->ToWideString(params[1]).c_str(),
1505           pRuntime->ToWideString(params[3]).c_str());
1506   } else if (bGreaterThan) {
1507     if (dEentValue < dGreaterThan)
1508       swMsg = WideString::Format(
1509           JSGetStringFromID(JSMessage::kRangeGreaterError).c_str(),
1510           pRuntime->ToWideString(params[1]).c_str());
1511   } else if (bLessThan) {
1512     if (dEentValue > dLessThan)
1513       swMsg = WideString::Format(
1514           JSGetStringFromID(JSMessage::kRangeLessError).c_str(),
1515           pRuntime->ToWideString(params[3]).c_str());
1516   }
1517 
1518   if (!swMsg.IsEmpty()) {
1519     AlertIfPossible(pContext, L"AFRange_Validate", swMsg);
1520     pEvent->Rc() = false;
1521   }
1522   return CJS_Result::Success();
1523 }
1524 
AFExtractNums(CJS_Runtime * pRuntime,const std::vector<v8::Local<v8::Value>> & params)1525 CJS_Result CJS_PublicMethods::AFExtractNums(
1526     CJS_Runtime* pRuntime,
1527     const std::vector<v8::Local<v8::Value>>& params) {
1528   if (params.size() != 1)
1529     return CJS_Result::Failure(JSMessage::kParamError);
1530 
1531   WideString str = pRuntime->ToWideString(params[0]);
1532   if (str.GetLength() > 0 && IsDigitSeparatorOrDecimalMark(str[0]))
1533     str.InsertAtFront(L'0');
1534 
1535   WideString sPart;
1536   v8::Local<v8::Array> nums = pRuntime->NewArray();
1537   int nIndex = 0;
1538   for (const auto& wc : str) {
1539     if (FXSYS_IsDecimalDigit(wc)) {
1540       sPart += wc;
1541     } else if (sPart.GetLength() > 0) {
1542       pRuntime->PutArrayElement(nums, nIndex,
1543                                 pRuntime->NewString(sPart.AsStringView()));
1544       sPart.clear();
1545       nIndex++;
1546     }
1547   }
1548   if (sPart.GetLength() > 0) {
1549     pRuntime->PutArrayElement(nums, nIndex,
1550                               pRuntime->NewString(sPart.AsStringView()));
1551   }
1552   if (pRuntime->GetArrayLength(nums) > 0)
1553     return CJS_Result::Success(nums);
1554 
1555   return CJS_Result::Success(pRuntime->NewUndefined());
1556 }
1557