7#include "fxjs/cjs_publicmethods.h"
22#include "build/build_config.h"
23#include "core/fpdfapi/parser/cpdf_stream.h"
24#include "core/fpdfdoc/cpdf_formcontrol.h"
25#include "core/fpdfdoc/cpdf_interactiveform.h"
26#include "core/fxcrt/check.h"
27#include "core/fxcrt/compiler_specific.h"
28#include "core/fxcrt/fx_extension.h"
29#include "core/fxcrt/fx_string_wrappers.h"
30#include "core/fxcrt/numerics/safe_conversions.h"
31#include "core/fxcrt/span.h"
32#include "core/fxge/cfx_color.h"
33#include "fpdfsdk/cpdfsdk_formfillenvironment.h"
34#include "fpdfsdk/cpdfsdk_interactiveform.h"
35#include "fxjs/cjs_color.h"
36#include "fxjs/cjs_event_context.h"
37#include "fxjs/cjs_field.h"
38#include "fxjs/cjs_object.h"
39#include "fxjs/cjs_runtime.h"
40#include "fxjs/cjs_util.h"
41#include "fxjs/fx_date_helpers.h"
42#include "fxjs/js_define.h"
43#include "fxjs/js_resources.h"
44#include "v8/include/v8-container.h"
47const JSMethodSpec CJS_PublicMethods::GlobalFunctionSpecs[] = {
48 {
"AFDate_Format", AFDate_Format_static},
49 {
"AFDate_FormatEx", AFDate_FormatEx_static},
50 {
"AFDate_Keystroke", AFDate_Keystroke_static},
51 {
"AFDate_KeystrokeEx", AFDate_KeystrokeEx_static},
52 {
"AFExtractNums", AFExtractNums_static},
53 {
"AFMakeNumber", AFMakeNumber_static},
54 {
"AFMergeChange", AFMergeChange_static},
55 {
"AFNumber_Format", AFNumber_Format_static},
56 {
"AFNumber_Keystroke", AFNumber_Keystroke_static},
57 {
"AFParseDateEx", AFParseDateEx_static},
58 {
"AFPercent_Format", AFPercent_Format_static},
59 {
"AFPercent_Keystroke", AFPercent_Keystroke_static},
60 {
"AFRange_Validate", AFRange_Validate_static},
61 {
"AFSimple", AFSimple_static},
62 {
"AFSimple_Calculate", AFSimple_Calculate_static},
63 {
"AFSpecial_Format", AFSpecial_Format_static},
64 {
"AFSpecial_Keystroke", AFSpecial_Keystroke_static},
65 {
"AFSpecial_KeystrokeEx", AFSpecial_KeystrokeEx_static},
66 {
"AFTime_Format", AFTime_Format_static},
67 {
"AFTime_FormatEx", AFTime_FormatEx_static},
68 {
"AFTime_Keystroke", AFTime_Keystroke_static},
69 {
"AFTime_KeystrokeEx", AFTime_KeystrokeEx_static},
74#if !BUILDFLAG(IS_ANDROID)
75constexpr double kDoubleCorrect = 0.000000000000001;
78constexpr std::array<
const char*, 14> kDateFormats = {
79 {
"m/d",
"m/d/yy",
"mm/dd/yy",
"mm/yy",
"d-mmm",
"d-mmm-yy",
"dd-mmm-yy",
80 "yy-mm-dd",
"mmm-yy",
"mmmm-yy",
"mmm d, yyyy",
"mmmm d, yyyy",
81 "m/d/yy h:MM tt",
"m/d/yy HH:MM"}};
83constexpr std::array<
const char*, 4> kTimeFormats = {
84 {
"HH:MM",
"h:MM tt",
"HH:MM:ss",
"h:MM:ss tt"}};
87T StrTrim(
const T& str) {
93void AlertIfPossible(CJS_EventContext* pContext,
103#if !BUILDFLAG(IS_ANDROID)
104ByteString CalculateString(
double dValue,
108 *bNegative = dValue < 0;
113 iDec = std::min(iDec, std::numeric_limits<
double>::digits10);
115 fxcrt::ostringstream ss;
116 ss << std::fixed << std::setprecision(iDec) << dValue;
117 fxcrt::string value = ss.str();
118 size_t pos = value.find(
'.');
119 *iDec2 = pdfium::checked_cast<
int>(pos == fxcrt::string::npos ? value.size()
121 return ByteString(value.c_str());
125WideString CalcMergedString(
const CJS_EventContext* event,
131 if (end >= 0 &&
static_cast<size_t>(end) < value.GetLength())
132 postfix = value.Last(value.GetLength() -
static_cast<size_t>(end));
133 return prefix
+ change
+ postfix;
136template <
CJS_Result (*F)(CJS_Runtime*, pdfium::span<v8::Local<v8::Value>>)>
137void JSGlobalFunc(
const char* func_name_string,
138 const v8::FunctionCallbackInfo<v8::Value>& info) {
140 CFXJS_Engine::GetBinding(info.GetIsolate(), info.This()));
144 CJS_Runtime* pRuntime = pObj->GetRuntime();
148 v8::LocalVector<v8::Value> parameters(info.GetIsolate());
149 for (
int i = 0; i < info.Length(); ++i)
150 parameters.push_back(info[i]);
152 CJS_Result result = (*F)(pRuntime, parameters);
160 info.GetReturnValue().Set(result.Return());
163int WithinBoundsOrZero(
int value, size_t size) {
164 return value >= 0 &&
static_cast<size_t>(value) < size ? value : 0;
167int ValidStyleOrZero(
int style) {
168 return WithinBoundsOrZero(style, 4);
171bool IsDigitSeparatorOrDecimalMark(
int c) {
172 return c ==
'.' || c ==
',';
175#if !BUILDFLAG(IS_ANDROID)
176bool IsStyleWithDigitSeparator(
int style) {
177 return style == 0 || style == 2;
180char DigitSeparatorForStyle(
int style) {
181 DCHECK(IsStyleWithDigitSeparator(style));
182 return style == 0 ?
',' :
'.';
185bool IsStyleWithApostropheSeparator(
int style) {
190bool IsStyleWithCommaDecimalMark(
int style) {
191 return style == 2 || style == 3;
194char DecimalMarkForStyle(
int style) {
195 return IsStyleWithCommaDecimalMark(style) ?
',' :
'.';
198#if !BUILDFLAG(IS_ANDROID)
199void NormalizeDecimalMark(ByteString* str) {
200 str->Replace(
",",
".");
205 str->Replace(L",", L".");
208std::optional<
double> ApplyNamedOperation(
const WideString& wsFunction,
213 return dValue1 + dValue2;
216 return dValue1 * dValue2;
218 return std::min(dValue1, dValue2);
220 return std::max(dValue1, dValue2);
228 for (
const auto& spec : GlobalFunctionSpecs)
229 pEngine->DefineGlobalMethod(spec.pName, spec.pMethodCall);
232#define JS_STATIC_GLOBAL_FUN(fun_name)
233 void CJS_PublicMethods::fun_name##_static(
234 const v8::FunctionCallbackInfo<v8::Value>& info) {
235 JSGlobalFunc<fun_name>(#fun_name, info);
263 const wchar_t* pTrim = sTrim.c_str();
264 const wchar_t* p = pTrim;
270 while ((c = *p) != L'\0') {
271 if (IsDigitSeparatorOrDecimalMark(c)) {
276 }
else if (c == L'-' || c == L'+') {
280 }
else if (c == L'e' || c == L'E') {
287 if (c != L'+' && c != L'-') {
305 return isascii(c_Change) && isalpha(c_Change);
307 return isascii(c_Change) && isalnum(c_Change);
311 return (c_Change == c_Mask);
316 return ch == L'9' || ch == L'A' || ch == L'O' || ch == L'X';
319v8::Local<v8::Array> CJS_PublicMethods::AF_MakeArrayFromList(
320 CJS_Runtime* pRuntime,
321 v8::Local<v8::Value> val) {
324 return pRuntime->ToArray(val);
327 ByteString bsVal = pRuntime->ToByteString(val);
328 const char* p = bsVal.c_str();
331 v8::Local<v8::Array> StrArray = pRuntime->NewArray();
335 const char* pTemp = strchr(p,
',');
337 pRuntime->PutArrayElement(
339 pRuntime->NewString(StrTrim(ByteString(p)).AsStringView()));
343 pRuntime->PutArrayElement(
346 StrTrim(ByteString(p, pTemp - p)).AsStringView()));
355double CJS_PublicMethods::ParseDate(v8::Isolate* isolate,
357 bool* bWrongFormat) {
366 std::array<
int, 3> number;
369 size_t nLen = value.GetLength();
376 wchar_t c = value[i];
378 number[nIndex++] = FX_ParseStringInteger(value, i, &nSkip, 4);
389 if (FX_IsValidMonth(number[0]) && FX_IsValidDay(number[1])) {
392 }
else if (FX_IsValidDay(number[0]) && FX_IsValidMonth(number[1])) {
398 *bWrongFormat =
false;
399 }
else if (nIndex == 3) {
404 if (number[0] > 12 && FX_IsValidMonth(number[1]) &&
405 FX_IsValidDay(number[2])) {
409 }
else if (FX_IsValidMonth(number[0]) && FX_IsValidDay(number[1]) &&
414 }
else if (FX_IsValidDay(number[0]) && FX_IsValidMonth(number[1]) &&
422 *bWrongFormat =
false;
425 *bWrongFormat =
true;
431 isolate, WideString::Format(L"%d/%d/%d %d:%d:%d", nMonth, nDay, nYear,
435double CJS_PublicMethods::ParseDateUsingFormat(v8::Isolate* isolate,
438 bool* bWrongFormat) {
439 double dRet = nan(
"");
445 dRet = JS_DateParse(isolate, value);
450 bool bBadFormat =
false;
451 dRet = ParseDate(isolate, value, &bBadFormat);
453 *bWrongFormat = bBadFormat;
471 while (i < format.GetLength()) {
472 wchar_t c = format[i];
473 size_t remaining = format.GetLength() - i - 1;
484 if (remaining == 0 || format[i + 1] != c) {
509 sPart
+= nHour > 12 ?
'p' :
'a';
513 }
else if (remaining == 1 || format[i + 2] != c) {
538 sPart
= nHour > 12 ? L"pm" : L"am";
542 }
else if (remaining == 2 || format[i + 3] != c) {
546 if (FX_IsValidMonth(nMonth))
547 sPart += WideString::FromASCII(fxjs::kMonths[nMonth - 1]);
556 }
else if (remaining == 3 || format[i + 4] != c) {
564 if (FX_IsValidMonth(nMonth))
565 sPart += WideString::FromASCII(fxjs::kFullMonths[nMonth - 1]);
595 CJS_Runtime* pRuntime,
596 pdfium::span<v8::Local<v8::Value>> params) {
597#if !BUILDFLAG(IS_ANDROID)
598 if (params.size() != 6)
599 return CJS_Result::Failure(JSMessage::kParamError);
601 CJS_EventContext* pEventContext = pRuntime->GetCurrentEventContext();
602 if (!pEventContext->HasValue())
603 return CJS_Result::Failure(WideString::FromASCII(
"No event handler"));
605 WideString& Value = pEventContext->Value();
606 ByteString strValue = StrTrim(Value.ToUTF8());
607 if (strValue.IsEmpty())
608 return CJS_Result::Success();
610 int iDec = abs(pRuntime->ToInt32(params[0]));
611 int iSepStyle = ValidStyleOrZero(pRuntime->ToInt32(params[1]));
612 int iNegStyle = ValidStyleOrZero(pRuntime->ToInt32(params[2]));
614 WideString wstrCurrency = pRuntime->ToWideString(params[4]);
615 bool bCurrencyPrepend = pRuntime->ToBoolean(params[5]);
618 NormalizeDecimalMark(&strValue);
619 double dValue = atof(strValue.c_str());
621 dValue += kDoubleCorrect;
626 strValue = CalculateString(dValue, iDec, &iDec2, &bNegative);
627 if (strValue.IsEmpty()) {
629 strValue = CalculateString(dValue, iDec, &iDec2, &bNegative);
630 if (strValue.IsEmpty()) {
638 if (
static_cast<size_t>(iDec2) < strValue.GetLength()) {
639 if (IsStyleWithCommaDecimalMark(iSepStyle))
640 strValue.Replace(
".",
",");
643 strValue.Insert(iDec2,
'0');
645 if (IsStyleWithDigitSeparator(iSepStyle)) {
646 char cSeparator = DigitSeparatorForStyle(iSepStyle);
647 for (
int iDecPositive = iDec2 - 3; iDecPositive > 0; iDecPositive -= 3)
648 strValue.Insert(iDecPositive, cSeparator);
652 Value = WideString::FromUTF8(strValue.AsStringView());
653 if (bCurrencyPrepend)
654 Value = wstrCurrency + Value;
656 Value = Value + wstrCurrency;
660 if (iNegStyle == 0) {
661 Value.InsertAtFront(L'-');
662 }
else if (iNegStyle == 2 || iNegStyle == 3) {
663 Value.InsertAtFront(L'(');
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(1));
671 pRuntime->PutArrayElement(arColor, 2, pRuntime->NewNumber(0));
672 pRuntime->PutArrayElement(arColor, 3, pRuntime->NewNumber(0));
673 fTarget->set_text_color(pRuntime, arColor);
677 if (iNegStyle == 1 || iNegStyle == 3) {
678 if (CJS_Field* fTarget = pEventContext->TargetField()) {
679 v8::Local<v8::Array> arColor = pRuntime->NewArray();
680 pRuntime->PutArrayElement(arColor, 0, pRuntime->NewString(
"RGB"));
681 pRuntime->PutArrayElement(arColor, 1, pRuntime->NewNumber(0));
682 pRuntime->PutArrayElement(arColor, 2, pRuntime->NewNumber(0));
683 pRuntime->PutArrayElement(arColor, 3, pRuntime->NewNumber(0));
685 CJS_Result result = fTarget->get_text_color(pRuntime);
686 CFX_Color crProp = CJS_Color::ConvertArrayToPWLColor(
687 pRuntime, pRuntime->ToArray(result.Return()));
689 CJS_Color::ConvertArrayToPWLColor(pRuntime, arColor);
690 if (crColor != crProp)
691 fTarget->set_text_color(pRuntime, arColor);
702 CJS_Runtime* pRuntime,
703 pdfium::span<v8::Local<v8::Value>> params) {
704 if (params.size() < 2)
717 if (swTemp.IsEmpty())
720 NormalizeDecimalMarkW(&swTemp);
738 bool bHasSign = wstrValue.Contains(L'-') && !wstrSelected.Contains(L'-');
741 if (!wstrSelected.IsEmpty() && pContext
->SelStart() == 0) {
747 int iSepStyle = ValidStyleOrZero(pRuntime->ToInt32(params[1]));
748 const wchar_t cSep = DecimalMarkForStyle(iSepStyle);
750 bool bHasSep = wstrValue.Contains(cSep);
751 for (size_t i = 0; i < wstrChange.GetLength(); ++i) {
752 if (wstrChange[i] == cSep) {
760 if (wstrChange[i] == L'-') {
778 if (!FXSYS_IsDecimalDigit(wstrChange[i])) {
784 val
= CalcMergedString(pContext, wstrValue, wstrChange);
790 CJS_Runtime* pRuntime,
791 pdfium::span<v8::Local<v8::Value>> params) {
792#if !BUILDFLAG(IS_ANDROID)
793 if (params.size() < 2)
794 return CJS_Result::Failure(JSMessage::kParamError);
796 CJS_EventContext* pEvent = pRuntime->GetCurrentEventContext();
797 if (!pEvent->HasValue())
798 return CJS_Result::Failure(JSMessage::kBadObjectError);
801 static constexpr int kMaxSepStyle = 49;
803 int iDec = pRuntime->ToInt32(params[0]);
804 int iSepStyle = pRuntime->ToInt32(params[1]);
806 bool bPercentPrepend = params.size() > 2 && pRuntime->ToBoolean(params[2]);
807 if (iDec < 0 || iSepStyle < 0 || iSepStyle > kMaxSepStyle)
808 return CJS_Result::Failure(JSMessage::kValueError);
811 static constexpr int kDecLimit = 512;
813 static constexpr size_t kDigitsInDecLimit = 3;
814 WideString& Value = pEvent->Value();
815 if (iDec > kDecLimit) {
817 return CJS_Result::Success();
820 ByteString strValue = StrTrim(Value.ToUTF8());
821 if (strValue.IsEmpty())
825 double dValue = atof(strValue.c_str());
832 char format[
sizeof(
"%.f") + kDigitsInDecLimit];
833 FXSYS_snprintf(format,
sizeof(format),
"%%.%df", iDec);
836 size_t szBufferSize = iDec + 3;
837 double dValueCopy = fabs(dValue);
838 while (dValueCopy > 1) {
844 pdfium::span<
char> span = strValue.GetBuffer(szBufferSize);
845 FXSYS_snprintf(span.data(), szBufferSize, format, dValue);
846 szNewSize = strlen(span.data());
848 strValue.ReleaseBuffer(szNewSize);
851 std::optional<size_t> mark_pos = strValue.Find(
'.');
852 if (mark_pos.has_value()) {
853 char mark = DecimalMarkForStyle(iSepStyle);
855 strValue.SetAt(mark_pos.value(), mark);
857 bool bUseDigitSeparator = IsStyleWithDigitSeparator(iSepStyle);
858 if (bUseDigitSeparator || IsStyleWithApostropheSeparator(iSepStyle)) {
860 bUseDigitSeparator ? DigitSeparatorForStyle(iSepStyle) :
'\'';
861 int iEnd = mark_pos.value_or(strValue.GetLength());
862 int iStop = dValue < 0 ? 1 : 0;
863 for (
int i = iEnd - 3; i > iStop; i -= 3)
864 strValue.Insert(i, cSeparator);
868 strValue.InsertAtFront(
'%');
870 strValue.InsertAtBack(
'%');
871 Value = WideString::FromUTF8(strValue.AsStringView());
878 CJS_Runtime* pRuntime,
879 pdfium::span<v8::Local<v8::Value>> params) {
880 return AFNumber_Keystroke(pRuntime, params);
885 CJS_Runtime* pRuntime,
886 pdfium::span<v8::Local<v8::Value>> params) {
887 if (params.size() != 1)
896 if (strValue.IsEmpty())
899 WideString sFormat = pRuntime->ToWideString(params[0]);
901 if (strValue.Contains(L"GMT")) {
903 dDate = ParseDateAsGMT(pRuntime->GetIsolate(), strValue);
905 dDate = ParseDateUsingFormat(pRuntime->GetIsolate(), strValue, sFormat,
920double CJS_PublicMethods::ParseDateAsGMT(v8::Isolate* isolate,
922 std::vector<WideString> wsArray;
924 for (
const auto& c : strValue) {
925 if (c == L' ' || c == L':') {
926 wsArray.push_back(std::move(sTemp));
931 wsArray.push_back(
std::move(sTemp));
932 if (wsArray.size() != 8)
939 nMonth =
static_cast<
int>(i) + 1;
944 int nDay = StringToFloat(wsArray[2].AsStringView());
945 int nHour = StringToFloat(wsArray[3].AsStringView());
946 int nMin = StringToFloat(wsArray[4].AsStringView());
947 int nSec = StringToFloat(wsArray[5].AsStringView());
948 int nYear = StringToFloat(wsArray[7].AsStringView());
952 dRet = JS_DateParse(isolate, strValue);
959 CJS_Runtime* pRuntime,
960 pdfium::span<v8::Local<v8::Value>> params) {
961 if (params.size() != 1) {
963 "AFDate_KeystrokeEx's parameter size not correct"));
974 if (strValue.IsEmpty())
977 bool bWrongFormat =
false;
978 WideString sFormat = pRuntime->ToWideString(params[0]);
979 double dRet = ParseDateUsingFormat(pRuntime->GetIsolate(), strValue, sFormat,
981 if (bWrongFormat || isnan(dRet)) {
991 CJS_Runtime* pRuntime,
992 pdfium::span<v8::Local<v8::Value>> params) {
993 if (params.size() != 1)
997 WithinBoundsOrZero(pRuntime->ToInt32(params[0]), std::size(kDateFormats));
998 v8::LocalVector<v8::Value> newParams(pRuntime->GetIsolate());
999 newParams.push_back(pRuntime->NewString(kDateFormats[iIndex]));
1000 return AFDate_FormatEx(pRuntime, newParams);
1005 CJS_Runtime* pRuntime,
1006 pdfium::span<v8::Local<v8::Value>> params) {
1007 if (params.size() != 1)
1011 WithinBoundsOrZero(pRuntime->ToInt32(params[0]), std::size(kDateFormats));
1012 v8::LocalVector<v8::Value> newParams(pRuntime->GetIsolate());
1013 newParams.push_back(pRuntime->NewString(kDateFormats[iIndex]));
1014 return AFDate_KeystrokeEx(pRuntime, newParams);
1019 CJS_Runtime* pRuntime,
1020 pdfium::span<v8::Local<v8::Value>> params) {
1021 if (params.size() != 1)
1025 WithinBoundsOrZero(pRuntime->ToInt32(params[0]), std::size(kTimeFormats));
1026 v8::LocalVector<v8::Value> newParams(pRuntime->GetIsolate());
1027 newParams.push_back(pRuntime->NewString(kTimeFormats[iIndex]));
1028 return AFDate_FormatEx(pRuntime, newParams);
1032 CJS_Runtime* pRuntime,
1033 pdfium::span<v8::Local<v8::Value>> params) {
1034 if (params.size() != 1)
1038 WithinBoundsOrZero(pRuntime->ToInt32(params[0]), std::size(kTimeFormats));
1039 v8::LocalVector<v8::Value> newParams(pRuntime->GetIsolate());
1040 newParams.push_back(pRuntime->NewString(kTimeFormats[iIndex]));
1041 return AFDate_KeystrokeEx(pRuntime, newParams);
1045 CJS_Runtime* pRuntime,
1046 pdfium::span<v8::Local<v8::Value>> params) {
1047 return AFDate_FormatEx(pRuntime, params);
1051 CJS_Runtime* pRuntime,
1052 pdfium::span<v8::Local<v8::Value>> params) {
1053 return AFDate_KeystrokeEx(pRuntime, params);
1058 CJS_Runtime* pRuntime,
1059 pdfium::span<v8::Local<v8::Value>> params) {
1060 if (params.size() != 1)
1069 switch (pRuntime->ToInt32(params[0])) {
1093 CJS_Runtime* pRuntime,
1094 pdfium::span<v8::Local<v8::Value>> params) {
1095 if (params.size() < 1)
1103 WideString wstrMask = pRuntime->ToWideString(params[0]);
1104 if (wstrMask.IsEmpty())
1108 if (valEvent.IsEmpty())
1111 if (valEvent.GetLength() > wstrMask.GetLength()) {
1119 for (iIndex = 0; iIndex < valEvent.GetLength(); ++iIndex) {
1123 if (iIndex != wstrMask.GetLength()) {
1132 if (wideChange.IsEmpty())
1137 size_t combined_len = valEvent.GetLength() + wChange.GetLength() +
1139 if (combined_len > wstrMask.GetLength()) {
1146 if (iIndexMask >= wstrMask.GetLength() && !wChange.IsEmpty()) {
1153 for (size_t i = 0; i < wChange.GetLength(); ++i) {
1154 if (iIndexMask >= wstrMask.GetLength()) {
1160 wchar_t wMask = wstrMask[iIndexMask];
1162 wChange.SetAt(i, wMask);
1170 wideChange =
std::move(wChange);
1176 CJS_Runtime* pRuntime,
1177 pdfium::span<v8::Local<v8::Value>> params) {
1178 if (params.size() != 1)
1185 const char* cFormat =
"";
1186 switch (pRuntime->ToInt32(params[0])) {
1191 cFormat =
"999999999";
1195 cFormat =
"9999999999";
1197 cFormat =
"9999999";
1200 cFormat =
"999999999";
1204 v8::LocalVector<v8::Value> params2(pRuntime->GetIsolate());
1205 params2.push_back(pRuntime->NewString(cFormat));
1206 return AFSpecial_KeystrokeEx(pRuntime, params2);
1210 CJS_Runtime* pRuntime,
1211 pdfium::span<v8::Local<v8::Value>> params) {
1212 if (params.size() != 1)
1225 CalcMergedString(pEvent, swValue, pEvent
->Change()).AsStringView())
);
1229 CJS_Runtime* pRuntime,
1230 pdfium::span<v8::Local<v8::Value>> params) {
1231 if (params.size() != 2)
1234 WideString sValue = pRuntime->ToWideString(params[0]);
1235 WideString sFormat = pRuntime->ToWideString(params[1]);
1237 ParseDateUsingFormat(pRuntime->GetIsolate(), sValue, sFormat,
nullptr);
1249 CJS_Runtime* pRuntime,
1250 pdfium::span<v8::Local<v8::Value>> params) {
1251 if (params.size() != 3)
1254 WideString sFunction = pRuntime->ToWideString(params[0]);
1255 double arg1 = pRuntime->ToDouble(params[1]);
1256 double arg2 = pRuntime->ToDouble(params[2]);
1257 if (isnan(arg1) || isnan(arg2))
1260 std::optional<
double> result = ApplyNamedOperation(sFunction, arg1, arg2);
1261 if (!result.has_value())
1264 double dValue = result.value();
1272 CJS_Runtime* pRuntime,
1273 pdfium::span<v8::Local<v8::Value>> params) {
1274 if (params.size() != 1)
1277 WideString ws = pRuntime->ToWideString(params[0]);
1278 NormalizeDecimalMarkW(&ws);
1280 v8::Local<v8::Value> val =
1281 pRuntime->MaybeCoerceToNumber(pRuntime->NewString(ws.AsStringView()));
1282 if (!val->IsNumber())
1285 return CJS_Result::Success(val);
1289 CJS_Runtime* pRuntime,
1290 pdfium::span<v8::Local<v8::Value>> params) {
1291 if (params.size() != 2)
1294 if (params[1].IsEmpty() || (!params[1]->IsArray() && !params[1]->IsString()))
1297 WideString sFunction = pRuntime->ToWideString(params[0]);
1298 v8::Local<v8::Array> FieldNameArray =
1299 AF_MakeArrayFromList(pRuntime, params[1]);
1301 CPDFSDK_InteractiveForm* pReaderForm =
1305 double dValue = sFunction
.EqualsASCII(
"PRD") ? 1.0 : 0.0;
1306 int nFieldsCount = 0;
1307 for (size_t i = 0; i < pRuntime->GetArrayLength(FieldNameArray); ++i) {
1309 pRuntime->ToWideString(pRuntime->GetArrayElement(FieldNameArray, i));
1311 for (size_t j = 0; j < pForm->CountFields(wsFieldName); ++j) {
1323 dTemp = StringToDouble(trimmed.AsStringView());
1338 dTemp = StringToFloat(trimmed.AsStringView());
1347 dTemp = StringToFloat(trimmed.AsStringView());
1354 if (i == 0 && j == 0 &&
1358 std::optional<
double> dResult =
1359 ApplyNamedOperation(sFunction, dValue, dTemp);
1360 if (!dResult.has_value())
1363 dValue = dResult.value();
1368 if (sFunction
.EqualsASCII(
"AVG") && nFieldsCount > 0) {
1369 dValue /= nFieldsCount;
1371 dValue = floor(dValue * powf(10, 6) + 0.49) / powf(10, 6);
1375 pContext
->Value() = pRuntime->ToWideString(pRuntime->NewNumber(dValue));
1383 CJS_Runtime* pRuntime,
1384 pdfium::span<v8::Local<v8::Value>> params) {
1385 if (params.size() != 4)
1396 bool bGreaterThan = pRuntime->ToBoolean(params[0]);
1397 double dGreaterThan = pRuntime->ToDouble(params[1]);
1398 bool bLessThan = pRuntime->ToBoolean(params[2]);
1399 double dLessThan = pRuntime->ToDouble(params[3]);
1402 if (bGreaterThan && bLessThan) {
1403 if (dEventValue < dGreaterThan || dEventValue > dLessThan)
1404 swMsg = WideString::Format(
1405 JSGetStringFromID(JSMessage::kRangeBetweenError).c_str(),
1406 pRuntime->ToWideString(params[1]).c_str(),
1407 pRuntime->ToWideString(params[3]).c_str());
1408 }
else if (bGreaterThan) {
1409 if (dEventValue < dGreaterThan)
1410 swMsg = WideString::Format(
1411 JSGetStringFromID(JSMessage::kRangeGreaterError).c_str(),
1412 pRuntime->ToWideString(params[1]).c_str());
1413 }
else if (bLessThan) {
1414 if (dEventValue > dLessThan)
1415 swMsg = WideString::Format(
1416 JSGetStringFromID(JSMessage::kRangeLessError).c_str(),
1417 pRuntime->ToWideString(params[3]).c_str());
1420 if (!swMsg.IsEmpty()) {
1428 CJS_Runtime* pRuntime,
1429 pdfium::span<v8::Local<v8::Value>> params) {
1430 if (params.size() != 1)
1433 WideString str = pRuntime->ToWideString(params[0]);
1434 if (str.GetLength() > 0 && IsDigitSeparatorOrDecimalMark(str[0]))
1435 str.InsertAtFront(L'0');
1438 v8::Local<v8::Array> nums = pRuntime->NewArray();
1440 for (
const auto& wc : str) {
1441 if (FXSYS_IsDecimalDigit(wc)) {
1443 }
else if (sPart.GetLength() > 0) {
1444 pRuntime->PutArrayElement(nums, nIndex,
1445 pRuntime->NewString(sPart.AsStringView()));
1450 if (sPart.GetLength() > 0) {
1451 pRuntime->PutArrayElement(nums, nIndex,
1452 pRuntime->NewString(sPart.AsStringView()));
1454 if (pRuntime->GetArrayLength(nums) > 0)
1455 return CJS_Result::Success(nums);
fxcrt::ByteString ByteString
#define JS_STATIC_GLOBAL_FUN(fun_name)
void Error(const WideString &message)
CPDFSDK_FormFillEnvironment * GetFormFillEnv() 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)
WideString & operator+=(const WideString &str)
void TrimWhitespaceFront()
ByteString ToUTF8() const
static WideString Format(const wchar_t *pFormat,...)
WideString & operator=(WideString &&that) noexcept
WideString & operator+=(wchar_t ch)
bool EqualsASCIINoCase(ByteStringView that) const
void TrimWhitespaceBack()
WideString & operator=(const WideString &that)
static WideString FromASCII(ByteStringView str)
WideString & operator=(const wchar_t *str)
static WideString FormatInteger(int i)
bool EqualsASCII(ByteStringView that) const
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)
int FX_GetYearFromTime(double dt)
ConversionStatus FX_ParseDateUsingFormat(const WideString &value, const WideString &format, double *result)
double FX_MakeDate(double day, double time)
const std::array< const char *, 12 > kMonths
int FX_GetDayFromTime(double dt)
int FX_GetSecFromTime(double dt)
int FX_GetHourFromTime(double dt)
double FX_MakeDay(int nYear, int nMonth, int nDay)
int FX_GetMinFromTime(double dt)
double FX_MakeTime(int nHour, int nMin, int nSec, int nMs)
fxcrt::WideString WideString