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