7#include "fxjs/cjs_publicmethods.h"
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/containers/span.h"
41#include "third_party/base/numerics/safe_conversions.h"
42#include "v8/include/v8-container.h"
45const JSMethodSpec CJS_PublicMethods::GlobalFunctionSpecs[] = {
46 {
"AFDate_Format", AFDate_Format_static},
47 {
"AFDate_FormatEx", AFDate_FormatEx_static},
48 {
"AFDate_Keystroke", AFDate_Keystroke_static},
49 {
"AFDate_KeystrokeEx", AFDate_KeystrokeEx_static},
50 {
"AFExtractNums", AFExtractNums_static},
51 {
"AFMakeNumber", AFMakeNumber_static},
52 {
"AFMergeChange", AFMergeChange_static},
53 {
"AFNumber_Format", AFNumber_Format_static},
54 {
"AFNumber_Keystroke", AFNumber_Keystroke_static},
55 {
"AFParseDateEx", AFParseDateEx_static},
56 {
"AFPercent_Format", AFPercent_Format_static},
57 {
"AFPercent_Keystroke", AFPercent_Keystroke_static},
58 {
"AFRange_Validate", AFRange_Validate_static},
59 {
"AFSimple", AFSimple_static},
60 {
"AFSimple_Calculate", AFSimple_Calculate_static},
61 {
"AFSpecial_Format", AFSpecial_Format_static},
62 {
"AFSpecial_Keystroke", AFSpecial_Keystroke_static},
63 {
"AFSpecial_KeystrokeEx", AFSpecial_KeystrokeEx_static},
64 {
"AFTime_Format", AFTime_Format_static},
65 {
"AFTime_FormatEx", AFTime_FormatEx_static},
66 {
"AFTime_Keystroke", AFTime_Keystroke_static},
67 {
"AFTime_KeystrokeEx", AFTime_KeystrokeEx_static},
72#if !BUILDFLAG(IS_ANDROID)
73constexpr double kDoubleCorrect = 0.000000000000001;
76constexpr const wchar_t* kDateFormats[] = {L"m/d",
91constexpr const wchar_t* kTimeFormats[] = {L"HH:MM", L"h:MM tt", L"HH:MM:ss",
95T StrTrim(
const T& str) {
101void AlertIfPossible(CJS_EventContext* pContext,
102 const WideString& wsCaller,
103 const WideString& wsMsg) {
111#if !BUILDFLAG(IS_ANDROID)
112ByteString CalculateString(
double dValue,
116 *bNegative = dValue < 0;
121 iDec = std::min(iDec, std::numeric_limits<
double>::digits10);
123 fxcrt::ostringstream ss;
124 ss << std::fixed << std::setprecision(iDec) << dValue;
125 fxcrt::string value = ss.str();
126 size_t pos = value.find(
'.');
127 *iDec2 = pdfium::base::checked_cast<
int>(
128 pos == fxcrt::string::npos ? value.size() : pos);
129 return ByteString(value.c_str());
133WideString CalcMergedString(
const CJS_EventContext* event,
134 const WideString& value,
135 const WideString& change) {
139 if (end >= 0 &&
static_cast<size_t>(end) < value.GetLength())
140 postfix = value.Last(value.GetLength() -
static_cast<size_t>(end));
141 return prefix
+ change
+ postfix;
144template <
CJS_Result (*F)(CJS_Runtime*, pdfium::span<v8::Local<v8::Value>>)>
145void JSGlobalFunc(
const char* func_name_string,
146 const v8::FunctionCallbackInfo<v8::Value>& info) {
148 CFXJS_Engine::GetObjectPrivate(info.GetIsolate(), info.Holder());
156 v8::LocalVector<v8::Value> parameters(info.GetIsolate());
157 for (
int i = 0; i < info.Length(); ++i)
158 parameters.push_back(info[i]);
160 CJS_Result result = (*F)(pRuntime, parameters);
168 info.GetReturnValue().Set(result.Return());
171int WithinBoundsOrZero(
int value, size_t size) {
172 return value >= 0 &&
static_cast<size_t>(value) < size ? value : 0;
175int ValidStyleOrZero(
int style) {
176 return WithinBoundsOrZero(style, 4);
179bool IsDigitSeparatorOrDecimalMark(
int c) {
180 return c ==
'.' || c ==
',';
183#if !BUILDFLAG(IS_ANDROID)
184bool IsStyleWithDigitSeparator(
int style) {
185 return style == 0 || style == 2;
188char DigitSeparatorForStyle(
int style) {
189 DCHECK(IsStyleWithDigitSeparator(style));
190 return style == 0 ?
',' :
'.';
193bool IsStyleWithApostropheSeparator(
int style) {
198bool IsStyleWithCommaDecimalMark(
int style) {
199 return style == 2 || style == 3;
202char DecimalMarkForStyle(
int style) {
203 return IsStyleWithCommaDecimalMark(style) ?
',' :
'.';
206#if !BUILDFLAG(IS_ANDROID)
207void NormalizeDecimalMark(ByteString* str) {
208 str->Replace(
",",
".");
212void NormalizeDecimalMarkW(WideString* str) {
213 str->Replace(L",", L".");
216absl::optional<
double> ApplyNamedOperation(
const WideString& wsFunction,
221 return dValue1 + dValue2;
224 return dValue1 * dValue2;
226 return std::min(dValue1, dValue2);
228 return std::max(dValue1, dValue2);
229 return absl::nullopt;
236 for (
const auto& spec : GlobalFunctionSpecs)
237 pEngine->DefineGlobalMethod(spec.pName, spec.pMethodCall);
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);
269bool 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;
277 while ((c = *p) != L'\0') {
278 if (IsDigitSeparatorOrDecimalMark(c)) {
282 }
else if (c == L'-' || c == L'+') {
285 }
else if (c == L'e' || c == L'E') {
291 if (c != L'+' && c != L'-')
308 return isascii(c_Change) && isalpha(c_Change);
310 return isascii(c_Change) && isalnum(c_Change);
314 return (c_Change == c_Mask);
319 return ch == L'9' || ch == L'A' || ch == L'O' || ch == L'X';
322v8::Local<v8::Array> CJS_PublicMethods::AF_MakeArrayFromList(
323 CJS_Runtime* pRuntime,
324 v8::Local<v8::Value> val) {
325 DCHECK(!val.IsEmpty());
327 return pRuntime->ToArray(val);
329 DCHECK(val->IsString());
330 ByteString bsVal = pRuntime->ToByteString(val);
334 v8::Local<v8::Array> StrArray = pRuntime->NewArray();
336 const char* pTemp = strchr(p,
',');
338 pRuntime->PutArrayElement(
340 pRuntime->NewString(StrTrim(ByteString(p)).AsStringView()));
344 pRuntime->PutArrayElement(
346 pRuntime->NewString(StrTrim(ByteString(p, pTemp - p)).AsStringView()));
354double CJS_PublicMethods::ParseDate(v8::Isolate* isolate,
355 const WideString& value,
356 bool* bWrongFormat) {
368 size_t nLen = value.GetLength();
375 wchar_t c = value[i];
377 number[nIndex++] = FX_ParseStringInteger(value, i, &nSkip, 4);
397 *bWrongFormat =
false;
398 }
else if (nIndex == 3) {
421 *bWrongFormat =
false;
424 *bWrongFormat =
true;
430 isolate, WideString::Format(L"%d/%d/%d %d:%d:%d", nMonth, nDay, nYear,
434double CJS_PublicMethods::ParseDateUsingFormat(v8::Isolate* isolate,
435 const WideString& value,
436 const WideString& format,
437 bool* bWrongFormat) {
438 double dRet = nan(
"");
444 dRet = JS_DateParse(isolate, value);
449 bool bBadFormat =
false;
450 dRet = ParseDate(isolate, value, &bBadFormat);
452 *bWrongFormat = bBadFormat;
458 const WideString& format) {
470 while (i < format.GetLength()) {
471 wchar_t c = format[i];
472 size_t remaining = format.GetLength() - i - 1;
483 if (remaining == 0 || format[i + 1] != c) {
508 sPart
+= nHour > 12 ?
'p' :
'a';
512 }
else if (remaining == 1 || format[i + 2] != c) {
515 sPart
= WideString
::Format(L"%02d"
, nYear - (nYear / 100) * 100
);
528 WideString
::Format(L"%02d"
, nHour > 12 ? nHour - 12 : nHour
);
537 sPart
= nHour > 12 ? L"pm" : L"am";
541 }
else if (remaining == 2 || format[i + 3] != c) {
555 }
else if (remaining == 3 || format[i + 4] != c) {
594 CJS_Runtime* pRuntime,
595 pdfium::span<v8::Local<v8::Value>> params) {
596#if !BUILDFLAG(IS_ANDROID)
597 if (params.size() != 6)
598 return CJS_Result::Failure(JSMessage::kParamError);
600 CJS_EventContext* pEventContext = pRuntime->GetCurrentEventContext();
601 if (!pEventContext->HasValue())
602 return CJS_Result::Failure(WideString::FromASCII(
"No event handler"));
604 WideString& Value = pEventContext->Value();
605 ByteString strValue = StrTrim(Value.ToUTF8());
606 if (strValue.IsEmpty())
607 return CJS_Result::Success();
609 int iDec = abs(pRuntime->ToInt32(params[0]));
610 int iSepStyle = ValidStyleOrZero(pRuntime->ToInt32(params[1]));
611 int iNegStyle = ValidStyleOrZero(pRuntime->ToInt32(params[2]));
613 WideString wstrCurrency = pRuntime->ToWideString(params[4]);
614 bool bCurrencyPrepend = pRuntime->ToBoolean(params[5]);
617 NormalizeDecimalMark(&strValue);
618 double dValue = atof(strValue.c_str());
620 dValue += kDoubleCorrect;
625 strValue = CalculateString(dValue, iDec, &iDec2, &bNegative);
626 if (strValue.IsEmpty()) {
628 strValue = CalculateString(dValue, iDec, &iDec2, &bNegative);
629 if (strValue.IsEmpty()) {
637 if (
static_cast<size_t>(iDec2) < strValue.GetLength()) {
638 if (IsStyleWithCommaDecimalMark(iSepStyle))
639 strValue.Replace(
".",
",");
642 strValue.Insert(iDec2,
'0');
644 if (IsStyleWithDigitSeparator(iSepStyle)) {
645 char cSeparator = DigitSeparatorForStyle(iSepStyle);
646 for (
int iDecPositive = iDec2 - 3; iDecPositive > 0; iDecPositive -= 3)
647 strValue.Insert(iDecPositive, cSeparator);
651 Value = WideString::FromUTF8(strValue.AsStringView());
652 if (bCurrencyPrepend)
653 Value = wstrCurrency + Value;
655 Value = Value + wstrCurrency;
659 if (iNegStyle == 0) {
660 Value.InsertAtFront(L'-');
661 }
else if (iNegStyle == 2 || iNegStyle == 3) {
662 Value.InsertAtFront(L'(');
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);
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));
684 CJS_Result result = fTarget->get_text_color(pRuntime);
685 CFX_Color crProp = CJS_Color::ConvertArrayToPWLColor(
686 pRuntime, pRuntime->ToArray(result.Return()));
688 CJS_Color::ConvertArrayToPWLColor(pRuntime, arColor);
689 if (crColor != crProp)
690 fTarget->set_text_color(pRuntime, arColor);
701 CJS_Runtime* pRuntime,
702 pdfium::span<v8::Local<v8::Value>> params) {
703 if (params.size() < 2)
712 WideString wstrValue = val;
715 WideString swTemp = StrTrim(wstrValue);
719 NormalizeDecimalMarkW(&swTemp);
723 AlertIfPossible(pContext, L"AFNumber_Keystroke", sError);
730 WideString wstrSelected;
736 bool bHasSign = wstrValue.Contains(L'-') && !wstrSelected.Contains(L'-');
745 int iSepStyle = ValidStyleOrZero(pRuntime->ToInt32(params[1]));
746 const wchar_t cSep = DecimalMarkForStyle(iSepStyle);
748 bool bHasSep = wstrValue.Contains(cSep);
749 for (size_t i = 0; i < wstrChange.GetLength(); ++i) {
750 if (wstrChange[i] == cSep) {
758 if (wstrChange[i] == L'-') {
776 if (!FXSYS_IsDecimalDigit(wstrChange[i])) {
782 val
= CalcMergedString(pContext, wstrValue, wstrChange);
788 CJS_Runtime* pRuntime,
789 pdfium::span<v8::Local<v8::Value>> params) {
790#if !BUILDFLAG(IS_ANDROID)
791 if (params.size() < 2)
792 return CJS_Result::Failure(JSMessage::kParamError);
794 CJS_EventContext* pEvent = pRuntime->GetCurrentEventContext();
795 if (!pEvent->HasValue())
796 return CJS_Result::Failure(JSMessage::kBadObjectError);
799 static constexpr int kMaxSepStyle = 49;
801 int iDec = pRuntime->ToInt32(params[0]);
802 int iSepStyle = pRuntime->ToInt32(params[1]);
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);
809 static constexpr int kDecLimit = 512;
811 static constexpr size_t kDigitsInDecLimit = 3;
812 WideString& Value = pEvent->Value();
813 if (iDec > kDecLimit) {
815 return CJS_Result::Success();
818 ByteString strValue = StrTrim(Value.ToUTF8());
819 if (strValue.IsEmpty())
823 double dValue = atof(strValue.c_str());
830 char format[
sizeof(
"%.f") + kDigitsInDecLimit];
831 FXSYS_snprintf(format,
sizeof(format),
"%%.%df", iDec);
834 size_t szBufferSize = iDec + 3;
835 double dValueCopy = fabs(dValue);
836 while (dValueCopy > 1) {
842 pdfium::span<
char> span = strValue.GetBuffer(szBufferSize);
843 FXSYS_snprintf(span.data(), szBufferSize, format, dValue);
844 szNewSize = strlen(span.data());
846 strValue.ReleaseBuffer(szNewSize);
849 absl::optional<size_t> mark_pos = strValue.Find(
'.');
850 if (mark_pos.has_value()) {
851 char mark = DecimalMarkForStyle(iSepStyle);
853 strValue.SetAt(mark_pos.value(), mark);
855 bool bUseDigitSeparator = IsStyleWithDigitSeparator(iSepStyle);
856 if (bUseDigitSeparator || IsStyleWithApostropheSeparator(iSepStyle)) {
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);
866 strValue.InsertAtFront(
'%');
868 strValue.InsertAtBack(
'%');
869 Value = WideString::FromUTF8(strValue.AsStringView());
876 CJS_Runtime* pRuntime,
877 pdfium::span<v8::Local<v8::Value>> params) {
878 return AFNumber_Keystroke(pRuntime, params);
883 CJS_Runtime* pRuntime,
884 pdfium::span<v8::Local<v8::Value>> params) {
885 if (params.size() != 1)
893 WideString strValue = val;
897 WideString sFormat = pRuntime->ToWideString(params[0]);
899 if (strValue.Contains(L"GMT")) {
901 dDate = ParseDateAsGMT(pRuntime->GetIsolate(), strValue);
903 dDate = ParseDateUsingFormat(pRuntime->GetIsolate(), strValue, sFormat,
910 AlertIfPossible(pEvent, L"AFDate_FormatEx", swMsg);
918double CJS_PublicMethods::ParseDateAsGMT(v8::Isolate* isolate,
919 const WideString& strValue) {
920 std::vector<WideString> wsArray;
922 for (
const auto& c : strValue) {
923 if (c == L' ' || c == L':') {
924 wsArray.push_back(
std::move(sTemp));
929 wsArray.push_back(
std::move(sTemp));
930 if (wsArray.size() != 8)
937 nMonth =
static_cast<
int>(i) + 1;
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());
950 dRet = JS_DateParse(isolate, strValue);
957 CJS_Runtime* pRuntime,
958 pdfium::span<v8::Local<v8::Value>> params) {
959 if (params.size() != 1) {
961 "AFDate_KeystrokeEx's parameter size not correct"));
971 const WideString& strValue = pEvent
->Value();
975 bool bWrongFormat =
false;
976 WideString sFormat = pRuntime->ToWideString(params[0]);
977 double dRet = ParseDateUsingFormat(pRuntime->GetIsolate(), strValue, sFormat,
979 if (bWrongFormat || isnan(dRet)) {
982 AlertIfPossible(pEvent, L"AFDate_KeystrokeEx", swMsg);
989 CJS_Runtime* pRuntime,
990 pdfium::span<v8::Local<v8::Value>> params) {
991 if (params.size() != 1)
995 WithinBoundsOrZero(pRuntime->ToInt32(params[0]), std::size(kDateFormats));
996 v8::LocalVector<v8::Value> newParams(pRuntime->GetIsolate());
997 newParams.push_back(pRuntime->NewString(kDateFormats[iIndex]));
998 return AFDate_FormatEx(pRuntime, newParams);
1003 CJS_Runtime* pRuntime,
1004 pdfium::span<v8::Local<v8::Value>> params) {
1005 if (params.size() != 1)
1009 WithinBoundsOrZero(pRuntime->ToInt32(params[0]), std::size(kDateFormats));
1010 v8::LocalVector<v8::Value> newParams(pRuntime->GetIsolate());
1011 newParams.push_back(pRuntime->NewString(kDateFormats[iIndex]));
1012 return AFDate_KeystrokeEx(pRuntime, newParams);
1017 CJS_Runtime* pRuntime,
1018 pdfium::span<v8::Local<v8::Value>> params) {
1019 if (params.size() != 1)
1023 WithinBoundsOrZero(pRuntime->ToInt32(params[0]), std::size(kTimeFormats));
1024 v8::LocalVector<v8::Value> newParams(pRuntime->GetIsolate());
1025 newParams.push_back(pRuntime->NewString(kTimeFormats[iIndex]));
1026 return AFDate_FormatEx(pRuntime, newParams);
1030 CJS_Runtime* pRuntime,
1031 pdfium::span<v8::Local<v8::Value>> params) {
1032 if (params.size() != 1)
1036 WithinBoundsOrZero(pRuntime->ToInt32(params[0]), std::size(kTimeFormats));
1037 v8::LocalVector<v8::Value> newParams(pRuntime->GetIsolate());
1038 newParams.push_back(pRuntime->NewString(kTimeFormats[iIndex]));
1039 return AFDate_KeystrokeEx(pRuntime, newParams);
1043 CJS_Runtime* pRuntime,
1044 pdfium::span<v8::Local<v8::Value>> params) {
1045 return AFDate_FormatEx(pRuntime, params);
1049 CJS_Runtime* pRuntime,
1050 pdfium::span<v8::Local<v8::Value>> params) {
1051 return AFDate_KeystrokeEx(pRuntime, params);
1056 CJS_Runtime* pRuntime,
1057 pdfium::span<v8::Local<v8::Value>> params) {
1058 if (params.size() != 1)
1065 const WideString& wsSource = pEvent
->Value();
1066 WideString wsFormat;
1067 switch (pRuntime->ToInt32(params[0])) {
1069 wsFormat
= L"99999";
1072 wsFormat
= L"99999-9999";
1076 wsFormat
= L"(999) 999-9999";
1078 wsFormat
= L"999-9999";
1081 wsFormat
= L"999-99-9999";
1091 CJS_Runtime* pRuntime,
1092 pdfium::span<v8::Local<v8::Value>> params) {
1093 if (params.size() < 1)
1100 const WideString& valEvent = pEvent
->Value();
1101 WideString wstrMask = pRuntime->ToWideString(params[0]);
1109 if (valEvent.GetLength() > wstrMask.GetLength()) {
1110 AlertIfPossible(pEvent, L"AFSpecial_KeystrokeEx",
1117 for (iIndex = 0; iIndex < valEvent.GetLength(); ++iIndex) {
1121 if (iIndex != wstrMask.GetLength()) {
1122 AlertIfPossible(pEvent, L"AFSpecial_KeystrokeEx",
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",
1144 if (iIndexMask >= wstrMask.GetLength() && !wChange
.IsEmpty()) {
1145 AlertIfPossible(pEvent, L"AFSpecial_KeystrokeEx",
1151 for (size_t i = 0; i < wChange.GetLength(); ++i) {
1152 if (iIndexMask >= wstrMask.GetLength()) {
1153 AlertIfPossible(pEvent, L"AFSpecial_KeystrokeEx",
1158 wchar_t wMask = wstrMask[iIndexMask];
1160 wChange.SetAt(i, wMask);
1168 wideChange =
std::move(wChange);
1174 CJS_Runtime* pRuntime,
1175 pdfium::span<v8::Local<v8::Value>> params) {
1176 if (params.size() != 1)
1183 const char* cFormat =
"";
1184 switch (pRuntime->ToInt32(params[0])) {
1189 cFormat =
"999999999";
1193 cFormat =
"9999999999";
1195 cFormat =
"9999999";
1198 cFormat =
"999999999";
1202 v8::LocalVector<v8::Value> params2(pRuntime->GetIsolate());
1203 params2.push_back(pRuntime->NewString(cFormat));
1204 return AFSpecial_KeystrokeEx(pRuntime, params2);
1208 CJS_Runtime* pRuntime,
1209 pdfium::span<v8::Local<v8::Value>> params) {
1210 if (params.size() != 1)
1223 CalcMergedString(pEvent, swValue, pEvent
->Change()).AsStringView())
);
1227 CJS_Runtime* pRuntime,
1228 pdfium::span<v8::Local<v8::Value>> params) {
1229 if (params.size() != 2)
1232 WideString sValue = pRuntime->ToWideString(params[0]);
1233 WideString sFormat = pRuntime->ToWideString(params[1]);
1235 ParseDateUsingFormat(pRuntime->GetIsolate(), sValue, sFormat,
nullptr);
1247 CJS_Runtime* pRuntime,
1248 pdfium::span<v8::Local<v8::Value>> params) {
1249 if (params.size() != 3)
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))
1258 absl::optional<
double> result = ApplyNamedOperation(sFunction, arg1, arg2);
1259 if (!result.has_value())
1262 double dValue = result.value();
1263 if (wcscmp(sFunction
.c_str(), L"AVG") == 0)
1270 CJS_Runtime* pRuntime,
1271 pdfium::span<v8::Local<v8::Value>> params) {
1272 if (params.size() != 1)
1275 WideString ws = pRuntime->ToWideString(params[0]);
1276 NormalizeDecimalMarkW(&ws);
1278 v8::Local<v8::Value> val =
1279 pRuntime->MaybeCoerceToNumber(pRuntime->NewString(ws.AsStringView()));
1280 if (!val->IsNumber())
1283 return CJS_Result::Success(val);
1287 CJS_Runtime* pRuntime,
1288 pdfium::span<v8::Local<v8::Value>> params) {
1289 if (params.size() != 2)
1292 if (params[1].IsEmpty() || (!params[1]->IsArray() && !params[1]->IsString()))
1295 WideString sFunction = pRuntime->ToWideString(params[0]);
1296 v8::Local<v8::Array> FieldNameArray =
1297 AF_MakeArrayFromList(pRuntime, params[1]);
1299 CPDFSDK_InteractiveForm* pReaderForm =
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));
1309 for (size_t j = 0; j < pForm->CountFields(wsFieldName); ++j) {
1321 dTemp = StringToDouble(trimmed.AsStringView());
1336 dTemp = StringToFloat(trimmed.AsStringView());
1345 dTemp = StringToFloat(trimmed.AsStringView());
1352 if (i == 0 && j == 0 &&
1353 (wcscmp(sFunction
.c_str(), L"MIN") == 0 ||
1354 wcscmp(sFunction
.c_str(), L"MAX") == 0)) {
1357 absl::optional<
double> dResult =
1358 ApplyNamedOperation(sFunction, dValue, dTemp);
1359 if (!dResult.has_value())
1362 dValue = dResult.value();
1367 if (wcscmp(sFunction
.c_str(), L"AVG") == 0 && nFieldsCount > 0)
1368 dValue /= nFieldsCount;
1370 dValue = floor(dValue * powf(10, 6) + 0.49) / powf(10, 6);
1374 pContext
->Value() = pRuntime->ToWideString(pRuntime->NewNumber(dValue));
1382 CJS_Runtime* pRuntime,
1383 pdfium::span<v8::Local<v8::Value>> params) {
1384 if (params.size() != 4)
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]);
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());
1420 AlertIfPossible(pEvent, L"AFRange_Validate", swMsg);
1427 CJS_Runtime* pRuntime,
1428 pdfium::span<v8::Local<v8::Value>> params) {
1429 if (params.size() != 1)
1432 WideString str = pRuntime->ToWideString(params[0]);
1433 if (str.GetLength() > 0 && IsDigitSeparatorOrDecimalMark(str
[0
]))
1434 str.InsertAtFront(L'0');
1437 v8::Local<v8::Array> nums = pRuntime->NewArray();
1439 for (
const auto& wc : str) {
1442 }
else if (sPart.GetLength() > 0) {
1443 pRuntime->PutArrayElement(nums, nIndex,
1444 pRuntime->NewString(sPart.AsStringView()));
1449 if (sPart.GetLength() > 0) {
1450 pRuntime->PutArrayElement(nums, nIndex,
1451 pRuntime->NewString(sPart.AsStringView()));
1453 if (pRuntime->GetArrayLength(nums) > 0)
1454 return CJS_Result::Success(nums);
#define JS_STATIC_GLOBAL_FUN(fun_name)
void Error(const WideString &message)
CPDFSDK_FormFillEnvironment * GetFormFillEnv() const
CJS_Runtime * GetRuntime() const
static WideString PrintDateUsingFormat(double dDate, const WideString &format)
static void DefineJSObjects(CFXJS_Engine *pEngine)
static bool IsReservedMaskChar(wchar_t ch)
static bool IsNumber(const WideString &str)
static bool MaskSatisfied(wchar_t c_Change, wchar_t c_Mask)
static CJS_Result Success()
static CJS_Result Failure(JSMessage id)
const WideString & Error() const
static CJS_Result Failure(const WideString &str)
CJS_EventContext * GetCurrentEventContext() const
CPDFSDK_FormFillEnvironment * GetFormFillEnv() const override
static WideString StringPrintx(const WideString &cFormat, const WideString &cSource)
const char * c_str() const
WideString & operator+=(const WideString &str)
ByteString ToUTF8() const
static WideString Format(const wchar_t *pFormat,...)
WideString & operator=(WideString &&that) noexcept
WideString & operator+=(const wchar_t *str)
WideString & operator+=(wchar_t ch)
bool EqualsASCIINoCase(ByteStringView that) const
CharType operator[](const size_t index) const
const wchar_t * c_str() const
WideString & operator=(const WideString &that)
static WideString FromASCII(ByteStringView str)
WideString & operator=(const wchar_t *str)
static WideString FormatInteger(int i)
bool FXSYS_IsDecimalDigit(wchar_t c)
WideString JSFormatErrorString(const char *class_name, const char *property_name, const WideString &details)
WideString JSGetStringFromID(JSMessage msg)
WideString operator+(const WideString &str1, const WideString &str2)
int FX_GetMonthFromTime(double dt)
const wchar_t *const kMonths[12]
int FX_GetYearFromTime(double dt)
const wchar_t *const kFullMonths[12]
ConversionStatus FX_ParseDateUsingFormat(const WideString &value, const WideString &format, double *result)
double FX_MakeDate(double day, double time)
int FX_GetDayFromTime(double dt)
int FX_GetSecFromTime(double dt)
bool FX_IsValidMonth(int m)
int FX_GetHourFromTime(double dt)
double FX_MakeDay(int nYear, int nMonth, int nDay)
bool FX_IsValidDay(int d)
int FX_GetMinFromTime(double dt)
double FX_MakeTime(int nHour, int nMin, int nSec, int nMs)