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