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