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