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