Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cfxjse_formcalc_context.cpp
Go to the documentation of this file.
1// Copyright 2014 The PDFium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "fxjs/xfa/cfxjse_formcalc_context.h"
8
9#include <ctype.h>
10#include <math.h>
11#include <stdint.h>
12#include <stdlib.h>
13
14#include <algorithm>
15#include <limits>
16#include <memory>
17#include <utility>
18#include <vector>
19
20#include "core/fxcrt/cfx_datetime.h"
21#include "core/fxcrt/code_point_view.h"
22#include "core/fxcrt/data_vector.h"
23#include "core/fxcrt/fx_extension.h"
24#include "core/fxcrt/fx_random.h"
25#include "core/fxcrt/fx_safe_types.h"
26#include "core/fxcrt/widetext_buffer.h"
27#include "fxjs/fxv8.h"
28#include "fxjs/xfa/cfxjse_class.h"
29#include "fxjs/xfa/cfxjse_context.h"
30#include "fxjs/xfa/cfxjse_engine.h"
31#include "fxjs/xfa/cfxjse_value.h"
32#include "fxjs/xfa/cjx_object.h"
33#include "third_party/abseil-cpp/absl/types/optional.h"
34#include "third_party/base/check_op.h"
35#include "third_party/base/numerics/safe_conversions.h"
36#include "v8/include/v8-container.h"
37#include "v8/include/v8-function-callback.h"
38#include "v8/include/v8-local-handle.h"
39#include "v8/include/v8-object.h"
40#include "v8/include/v8-primitive.h"
41#include "xfa/fgas/crt/cfgas_decimal.h"
42#include "xfa/fxfa/cxfa_ffnotify.h"
43#include "xfa/fxfa/formcalc/cxfa_fmparser.h"
44#include "xfa/fxfa/formcalc/cxfa_fmtojavascriptdepth.h"
45#include "xfa/fxfa/parser/cxfa_document.h"
46#include "xfa/fxfa/parser/cxfa_localevalue.h"
47#include "xfa/fxfa/parser/cxfa_node.h"
48#include "xfa/fxfa/parser/cxfa_thisproxy.h"
49#include "xfa/fxfa/parser/cxfa_timezoneprovider.h"
50#include "xfa/fxfa/parser/gced_locale_iface.h"
51#include "xfa/fxfa/parser/xfa_utils.h"
52
53using pdfium::fxjse::kClassTag;
54using pdfium::fxjse::kFuncTag;
55
56namespace {
57
58// Maximum number of characters Acrobat can fit in a text box.
59constexpr int kMaxCharCount = 15654908;
60
61const double kFinancialPrecision = 0.00000001;
62
63const wchar_t kStrCode[] = L"0123456789abcdef";
64
65struct XFA_FMHtmlReserveCode {
66 uint16_t m_uCode;
67 // Inline string data reduces size for small strings.
68 const char m_htmlReserve[10];
69};
70
71// Sorted by |m_htmlReserve|.
72const XFA_FMHtmlReserveCode kReservesForDecode[] = {
73 {198, "AElig"}, {193, "Aacute"}, {194, "Acirc"}, {192, "Agrave"},
74 {913, "Alpha"}, {197, "Aring"}, {195, "Atilde"}, {196, "Auml"},
75 {914, "Beta"}, {199, "Ccedil"}, {935, "Chi"}, {8225, "Dagger"},
76 {916, "Delta"}, {208, "ETH"}, {201, "Eacute"}, {202, "Ecirc"},
77 {200, "Egrave"}, {917, "Epsilon"}, {919, "Eta"}, {203, "Euml"},
78 {915, "Gamma"}, {922, "Kappa"}, {923, "Lambda"}, {924, "Mu"},
79 {209, "Ntilde"}, {925, "Nu"}, {338, "OElig"}, {211, "Oacute"},
80 {212, "Ocirc"}, {210, "Ograve"}, {937, "Omega"}, {927, "Omicron"},
81 {216, "Oslash"}, {213, "Otilde"}, {214, "Ouml"}, {934, "Phi"},
82 {928, "Pi"}, {936, "Psi"}, {929, "Rho"}, {352, "Scaron"},
83 {931, "Sigma"}, {222, "THORN"}, {932, "Tau"}, {920, "Theta"},
84 {218, "Uacute"}, {219, "Ucirc"}, {217, "Ugrave"}, {933, "Upsilon"},
85 {220, "Uuml"}, {926, "Xi"}, {221, "Yacute"}, {376, "Yuml"},
86 {918, "Zeta"}, {225, "aacute"}, {226, "acirc"}, {180, "acute"},
87 {230, "aelig"}, {224, "agrave"}, {8501, "alefsym"}, {945, "alpha"},
88 {38, "amp"}, {8743, "and"}, {8736, "ang"}, {39, "apos"},
89 {229, "aring"}, {8776, "asymp"}, {227, "atilde"}, {228, "auml"},
90 {8222, "bdquo"}, {946, "beta"}, {166, "brvbar"}, {8226, "bull"},
91 {8745, "cap"}, {231, "ccedil"}, {184, "cedil"}, {162, "cent"},
92 {967, "chi"}, {710, "circ"}, {9827, "clubs"}, {8773, "cong"},
93 {169, "copy"}, {8629, "crarr"}, {8746, "cup"}, {164, "current"},
94 {8659, "dArr"}, {8224, "dagger"}, {8595, "darr"}, {176, "deg"},
95 {948, "delta"}, {9830, "diams"}, {247, "divide"}, {233, "eacute"},
96 {234, "ecirc"}, {232, "egrave"}, {8709, "empty"}, {8195, "emsp"},
97 {8194, "ensp"}, {949, "epsilon"}, {8801, "equiv"}, {951, "eta"},
98 {240, "eth"}, {235, "euml"}, {8364, "euro"}, {8707, "exist"},
99 {402, "fnof"}, {8704, "forall"}, {189, "frac12"}, {188, "frac14"},
100 {190, "frac34"}, {8260, "frasl"}, {947, "gamma"}, {8805, "ge"},
101 {62, "gt"}, {8660, "hArr"}, {8596, "harr"}, {9829, "hearts"},
102 {8230, "hellip"}, {237, "iacute"}, {238, "icirc"}, {161, "iexcl"},
103 {236, "igrave"}, {8465, "image"}, {8734, "infin"}, {8747, "int"},
104 {953, "iota"}, {191, "iquest"}, {8712, "isin"}, {239, "iuml"},
105 {954, "kappa"}, {8656, "lArr"}, {205, "lacute"}, {955, "lambda"},
106 {9001, "lang"}, {171, "laquo"}, {8592, "larr"}, {8968, "lceil"},
107 {206, "lcirc"}, {8220, "ldquo"}, {8804, "le"}, {8970, "lfloor"},
108 {204, "lgrave"}, {921, "lota"}, {8727, "lowast"}, {9674, "loz"},
109 {8206, "lrm"}, {8249, "lsaquo"}, {8216, "lsquo"}, {60, "lt"},
110 {207, "luml"}, {175, "macr"}, {8212, "mdash"}, {181, "micro"},
111 {183, "middot"}, {8722, "minus"}, {956, "mu"}, {8711, "nabla"},
112 {160, "nbsp"}, {8211, "ndash"}, {8800, "ne"}, {8715, "ni"},
113 {172, "not"}, {8713, "notin"}, {8836, "nsub"}, {241, "ntilde"},
114 {957, "nu"}, {243, "oacute"}, {244, "ocirc"}, {339, "oelig"},
115 {242, "ograve"}, {8254, "oline"}, {969, "omega"}, {959, "omicron"},
116 {8853, "oplus"}, {8744, "or"}, {170, "ordf"}, {186, "ordm"},
117 {248, "oslash"}, {245, "otilde"}, {8855, "otimes"}, {246, "ouml"},
118 {182, "para"}, {8706, "part"}, {8240, "permil"}, {8869, "perp"},
119 {966, "phi"}, {960, "pi"}, {982, "piv"}, {177, "plusmn"},
120 {8242, "prime"}, {8719, "prod"}, {8733, "prop"}, {968, "psi"},
121 {163, "pund"}, {34, "quot"}, {8658, "rArr"}, {8730, "radic"},
122 {9002, "rang"}, {187, "raquo"}, {8594, "rarr"}, {8969, "rceil"},
123 {8476, "real"}, {174, "reg"}, {8971, "rfloor"}, {961, "rho"},
124 {8207, "rlm"}, {8250, "rsaquo"}, {8217, "rsquo"}, {353, "saron"},
125 {8218, "sbquo"}, {8901, "sdot"}, {167, "sect"}, {173, "shy"},
126 {963, "sigma"}, {962, "sigmaf"}, {8764, "sim"}, {9824, "spades"},
127 {8834, "sub"}, {8838, "sube"}, {8721, "sum"}, {8835, "sup"},
128 {185, "sup1"}, {178, "sup2"}, {179, "sup3"}, {8839, "supe"},
129 {223, "szlig"}, {964, "tau"}, {8221, "tdquo"}, {8756, "there4"},
130 {952, "theta"}, {977, "thetasym"}, {8201, "thinsp"}, {254, "thorn"},
131 {732, "tilde"}, {215, "times"}, {8482, "trade"}, {8657, "uArr"},
132 {250, "uacute"}, {8593, "uarr"}, {251, "ucirc"}, {249, "ugrave"},
133 {168, "uml"}, {978, "upsih"}, {965, "upsilon"}, {252, "uuml"},
134 {8472, "weierp"}, {958, "xi"}, {253, "yacute"}, {165, "yen"},
135 {255, "yuml"}, {950, "zeta"}, {8205, "zwj"}, {8204, "zwnj"},
136};
137
138// Sorted by |m_uCode|.
139const XFA_FMHtmlReserveCode kReservesForEncode[] = {
140 {34, "quot"}, {38, "amp"}, {39, "apos"}, {60, "lt"},
141 {62, "gt"}, {160, "nbsp"}, {161, "iexcl"}, {162, "cent"},
142 {163, "pund"}, {164, "current"}, {165, "yen"}, {166, "brvbar"},
143 {167, "sect"}, {168, "uml"}, {169, "copy"}, {170, "ordf"},
144 {171, "laquo"}, {172, "not"}, {173, "shy"}, {174, "reg"},
145 {175, "macr"}, {176, "deg"}, {177, "plusmn"}, {178, "sup2"},
146 {179, "sup3"}, {180, "acute"}, {181, "micro"}, {182, "para"},
147 {183, "middot"}, {184, "cedil"}, {185, "sup1"}, {186, "ordm"},
148 {187, "raquo"}, {188, "frac14"}, {189, "frac12"}, {190, "frac34"},
149 {191, "iquest"}, {192, "Agrave"}, {193, "Aacute"}, {194, "Acirc"},
150 {195, "Atilde"}, {196, "Auml"}, {197, "Aring"}, {198, "AElig"},
151 {199, "Ccedil"}, {200, "Egrave"}, {201, "Eacute"}, {202, "Ecirc"},
152 {203, "Euml"}, {204, "lgrave"}, {205, "lacute"}, {206, "lcirc"},
153 {207, "luml"}, {208, "ETH"}, {209, "Ntilde"}, {210, "Ograve"},
154 {211, "Oacute"}, {212, "Ocirc"}, {213, "Otilde"}, {214, "Ouml"},
155 {215, "times"}, {216, "Oslash"}, {217, "Ugrave"}, {218, "Uacute"},
156 {219, "Ucirc"}, {220, "Uuml"}, {221, "Yacute"}, {222, "THORN"},
157 {223, "szlig"}, {224, "agrave"}, {225, "aacute"}, {226, "acirc"},
158 {227, "atilde"}, {228, "auml"}, {229, "aring"}, {230, "aelig"},
159 {231, "ccedil"}, {232, "egrave"}, {233, "eacute"}, {234, "ecirc"},
160 {235, "euml"}, {236, "igrave"}, {237, "iacute"}, {238, "icirc"},
161 {239, "iuml"}, {240, "eth"}, {241, "ntilde"}, {242, "ograve"},
162 {243, "oacute"}, {244, "ocirc"}, {245, "otilde"}, {246, "ouml"},
163 {247, "divide"}, {248, "oslash"}, {249, "ugrave"}, {250, "uacute"},
164 {251, "ucirc"}, {252, "uuml"}, {253, "yacute"}, {254, "thorn"},
165 {255, "yuml"}, {338, "OElig"}, {339, "oelig"}, {352, "Scaron"},
166 {353, "saron"}, {376, "Yuml"}, {402, "fnof"}, {710, "circ"},
167 {732, "tilde"}, {913, "Alpha"}, {914, "Beta"}, {915, "Gamma"},
168 {916, "Delta"}, {917, "Epsilon"}, {918, "Zeta"}, {919, "Eta"},
169 {920, "Theta"}, {921, "lota"}, {922, "Kappa"}, {923, "Lambda"},
170 {924, "Mu"}, {925, "Nu"}, {926, "Xi"}, {927, "Omicron"},
171 {928, "Pi"}, {929, "Rho"}, {931, "Sigma"}, {932, "Tau"},
172 {933, "Upsilon"}, {934, "Phi"}, {935, "Chi"}, {936, "Psi"},
173 {937, "Omega"}, {945, "alpha"}, {946, "beta"}, {947, "gamma"},
174 {948, "delta"}, {949, "epsilon"}, {950, "zeta"}, {951, "eta"},
175 {952, "theta"}, {953, "iota"}, {954, "kappa"}, {955, "lambda"},
176 {956, "mu"}, {957, "nu"}, {958, "xi"}, {959, "omicron"},
177 {960, "pi"}, {961, "rho"}, {962, "sigmaf"}, {963, "sigma"},
178 {964, "tau"}, {965, "upsilon"}, {966, "phi"}, {967, "chi"},
179 {968, "psi"}, {969, "omega"}, {977, "thetasym"}, {978, "upsih"},
180 {982, "piv"}, {8194, "ensp"}, {8195, "emsp"}, {8201, "thinsp"},
181 {8204, "zwnj"}, {8205, "zwj"}, {8206, "lrm"}, {8207, "rlm"},
182 {8211, "ndash"}, {8212, "mdash"}, {8216, "lsquo"}, {8217, "rsquo"},
183 {8218, "sbquo"}, {8220, "ldquo"}, {8221, "tdquo"}, {8222, "bdquo"},
184 {8224, "dagger"}, {8225, "Dagger"}, {8226, "bull"}, {8230, "hellip"},
185 {8240, "permil"}, {8242, "prime"}, {8249, "lsaquo"}, {8250, "rsaquo"},
186 {8254, "oline"}, {8260, "frasl"}, {8364, "euro"}, {8465, "image"},
187 {8472, "weierp"}, {8476, "real"}, {8482, "trade"}, {8501, "alefsym"},
188 {8592, "larr"}, {8593, "uarr"}, {8594, "rarr"}, {8595, "darr"},
189 {8596, "harr"}, {8629, "crarr"}, {8656, "lArr"}, {8657, "uArr"},
190 {8658, "rArr"}, {8659, "dArr"}, {8660, "hArr"}, {8704, "forall"},
191 {8706, "part"}, {8707, "exist"}, {8709, "empty"}, {8711, "nabla"},
192 {8712, "isin"}, {8713, "notin"}, {8715, "ni"}, {8719, "prod"},
193 {8721, "sum"}, {8722, "minus"}, {8727, "lowast"}, {8730, "radic"},
194 {8733, "prop"}, {8734, "infin"}, {8736, "ang"}, {8743, "and"},
195 {8744, "or"}, {8745, "cap"}, {8746, "cup"}, {8747, "int"},
196 {8756, "there4"}, {8764, "sim"}, {8773, "cong"}, {8776, "asymp"},
197 {8800, "ne"}, {8801, "equiv"}, {8804, "le"}, {8805, "ge"},
198 {8834, "sub"}, {8835, "sup"}, {8836, "nsub"}, {8838, "sube"},
199 {8839, "supe"}, {8853, "oplus"}, {8855, "otimes"}, {8869, "perp"},
200 {8901, "sdot"}, {8968, "lceil"}, {8969, "rceil"}, {8970, "lfloor"},
201 {8971, "rfloor"}, {9001, "lang"}, {9002, "rang"}, {9674, "loz"},
202 {9824, "spades"}, {9827, "clubs"}, {9829, "hearts"}, {9830, "diams"},
203};
204
205const FXJSE_FUNCTION_DESCRIPTOR kFormCalcFunctions[] = {
206 {kFuncTag, "Abs", CFXJSE_FormCalcContext::Abs},
207 {kFuncTag, "Avg", CFXJSE_FormCalcContext::Avg},
208 {kFuncTag, "Ceil", CFXJSE_FormCalcContext::Ceil},
209 {kFuncTag, "Count", CFXJSE_FormCalcContext::Count},
210 {kFuncTag, "Floor", CFXJSE_FormCalcContext::Floor},
211 {kFuncTag, "Max", CFXJSE_FormCalcContext::Max},
212 {kFuncTag, "Min", CFXJSE_FormCalcContext::Min},
213 {kFuncTag, "Mod", CFXJSE_FormCalcContext::Mod},
214 {kFuncTag, "Round", CFXJSE_FormCalcContext::Round},
215 {kFuncTag, "Sum", CFXJSE_FormCalcContext::Sum},
216 {kFuncTag, "Date", CFXJSE_FormCalcContext::Date},
217 {kFuncTag, "Date2Num", CFXJSE_FormCalcContext::Date2Num},
218 {kFuncTag, "DateFmt", CFXJSE_FormCalcContext::DateFmt},
219 {kFuncTag, "IsoDate2Num", CFXJSE_FormCalcContext::IsoDate2Num},
220 {kFuncTag, "IsoTime2Num", CFXJSE_FormCalcContext::IsoTime2Num},
221 {kFuncTag, "LocalDateFmt", CFXJSE_FormCalcContext::LocalDateFmt},
222 {kFuncTag, "LocalTimeFmt", CFXJSE_FormCalcContext::LocalTimeFmt},
223 {kFuncTag, "Num2Date", CFXJSE_FormCalcContext::Num2Date},
224 {kFuncTag, "Num2GMTime", CFXJSE_FormCalcContext::Num2GMTime},
225 {kFuncTag, "Num2Time", CFXJSE_FormCalcContext::Num2Time},
226 {kFuncTag, "Time", CFXJSE_FormCalcContext::Time},
227 {kFuncTag, "Time2Num", CFXJSE_FormCalcContext::Time2Num},
228 {kFuncTag, "TimeFmt", CFXJSE_FormCalcContext::TimeFmt},
229 {kFuncTag, "Apr", CFXJSE_FormCalcContext::Apr},
230 {kFuncTag, "Cterm", CFXJSE_FormCalcContext::CTerm},
231 {kFuncTag, "FV", CFXJSE_FormCalcContext::FV},
232 {kFuncTag, "Ipmt", CFXJSE_FormCalcContext::IPmt},
233 {kFuncTag, "NPV", CFXJSE_FormCalcContext::NPV},
234 {kFuncTag, "Pmt", CFXJSE_FormCalcContext::Pmt},
235 {kFuncTag, "PPmt", CFXJSE_FormCalcContext::PPmt},
236 {kFuncTag, "PV", CFXJSE_FormCalcContext::PV},
237 {kFuncTag, "Rate", CFXJSE_FormCalcContext::Rate},
238 {kFuncTag, "Term", CFXJSE_FormCalcContext::Term},
239 {kFuncTag, "Choose", CFXJSE_FormCalcContext::Choose},
240 {kFuncTag, "Exists", CFXJSE_FormCalcContext::Exists},
241 {kFuncTag, "HasValue", CFXJSE_FormCalcContext::HasValue},
242 {kFuncTag, "Oneof", CFXJSE_FormCalcContext::Oneof},
243 {kFuncTag, "Within", CFXJSE_FormCalcContext::Within},
244 {kFuncTag, "If", CFXJSE_FormCalcContext::If},
245 {kFuncTag, "Eval", CFXJSE_FormCalcContext::Eval},
246 {kFuncTag, "Translate", CFXJSE_FormCalcContext::eval_translation},
247 {kFuncTag, "Ref", CFXJSE_FormCalcContext::Ref},
248 {kFuncTag, "UnitType", CFXJSE_FormCalcContext::UnitType},
249 {kFuncTag, "UnitValue", CFXJSE_FormCalcContext::UnitValue},
250 {kFuncTag, "At", CFXJSE_FormCalcContext::At},
251 {kFuncTag, "Concat", CFXJSE_FormCalcContext::Concat},
252 {kFuncTag, "Decode", CFXJSE_FormCalcContext::Decode},
253 {kFuncTag, "Encode", CFXJSE_FormCalcContext::Encode},
254 {kFuncTag, "Format", CFXJSE_FormCalcContext::Format},
255 {kFuncTag, "Left", CFXJSE_FormCalcContext::Left},
256 {kFuncTag, "Len", CFXJSE_FormCalcContext::Len},
257 {kFuncTag, "Lower", CFXJSE_FormCalcContext::Lower},
258 {kFuncTag, "Ltrim", CFXJSE_FormCalcContext::Ltrim},
259 {kFuncTag, "Parse", CFXJSE_FormCalcContext::Parse},
260 {kFuncTag, "Replace", CFXJSE_FormCalcContext::Replace},
261 {kFuncTag, "Right", CFXJSE_FormCalcContext::Right},
262 {kFuncTag, "Rtrim", CFXJSE_FormCalcContext::Rtrim},
263 {kFuncTag, "Space", CFXJSE_FormCalcContext::Space},
264 {kFuncTag, "Str", CFXJSE_FormCalcContext::Str},
265 {kFuncTag, "Stuff", CFXJSE_FormCalcContext::Stuff},
266 {kFuncTag, "Substr", CFXJSE_FormCalcContext::Substr},
267 {kFuncTag, "Uuid", CFXJSE_FormCalcContext::Uuid},
268 {kFuncTag, "Upper", CFXJSE_FormCalcContext::Upper},
269 {kFuncTag, "WordNum", CFXJSE_FormCalcContext::WordNum},
270 {kFuncTag, "Get", CFXJSE_FormCalcContext::Get},
271 {kFuncTag, "Post", CFXJSE_FormCalcContext::Post},
272 {kFuncTag, "Put", CFXJSE_FormCalcContext::Put},
273 {kFuncTag, "pos_op", CFXJSE_FormCalcContext::positive_operator},
274 {kFuncTag, "neg_op", CFXJSE_FormCalcContext::negative_operator},
275 {kFuncTag, "log_or_op", CFXJSE_FormCalcContext::logical_or_operator},
276 {kFuncTag, "log_and_op", CFXJSE_FormCalcContext::logical_and_operator},
277 {kFuncTag, "log_not_op", CFXJSE_FormCalcContext::logical_not_operator},
278 {kFuncTag, "eq_op", CFXJSE_FormCalcContext::equality_operator},
279 {kFuncTag, "neq_op", CFXJSE_FormCalcContext::notequality_operator},
280 {kFuncTag, "lt_op", CFXJSE_FormCalcContext::less_operator},
281 {kFuncTag, "le_op", CFXJSE_FormCalcContext::lessequal_operator},
282 {kFuncTag, "gt_op", CFXJSE_FormCalcContext::greater_operator},
283 {kFuncTag, "ge_op", CFXJSE_FormCalcContext::greaterequal_operator},
284 {kFuncTag, "plus_op", CFXJSE_FormCalcContext::plus_operator},
285 {kFuncTag, "minus_op", CFXJSE_FormCalcContext::minus_operator},
286 {kFuncTag, "mul_op", CFXJSE_FormCalcContext::multiple_operator},
287 {kFuncTag, "div_op", CFXJSE_FormCalcContext::divide_operator},
288 {kFuncTag, "asgn_val_op", CFXJSE_FormCalcContext::assign_value_operator},
289 {kFuncTag, "dot_acc", CFXJSE_FormCalcContext::dot_accessor},
290 {kFuncTag, "dotdot_acc", CFXJSE_FormCalcContext::dotdot_accessor},
291 {kFuncTag, "concat_obj", CFXJSE_FormCalcContext::concat_fm_object},
292 {kFuncTag, "is_obj", CFXJSE_FormCalcContext::is_fm_object},
293 {kFuncTag, "is_ary", CFXJSE_FormCalcContext::is_fm_array},
294 {kFuncTag, "get_val", CFXJSE_FormCalcContext::get_fm_value},
295 {kFuncTag, "get_jsobj", CFXJSE_FormCalcContext::get_fm_jsobj},
296 {kFuncTag, "var_filter", CFXJSE_FormCalcContext::fm_var_filter},
297};
298
299const uint8_t kAltTableDate[] = {
300 255, 255, 255, 3, 9, 255, 255, 255, 255, 255, 255,
301 255, 2, 255, 255, 255, 255, 255, 255, 255, 255, 255,
302 255, 255, 1, 255, 255, 255, 255, 255, 255, 255, 255,
303};
304static_assert(std::size(kAltTableDate) == L'a' - L'A' + 1,
305 "Invalid kAltTableDate size.");
306
307const uint8_t kAltTableTime[] = {
308 14, 255, 255, 3, 9, 255, 255, 15, 255, 255, 255,
309 255, 6, 255, 255, 255, 255, 255, 7, 255, 255, 255,
310 255, 255, 1, 17, 255, 255, 255, 255, 255, 255, 255,
311};
312static_assert(std::size(kAltTableTime) == L'a' - L'A' + 1,
313 "Invalid kAltTableTime size.");
314
315void AlternateDateTimeSymbols(WideString* pPattern,
316 const WideString& wsAltSymbols,
317 bool bIsDate) {
318 const uint8_t* pAltTable = bIsDate ? kAltTableDate : kAltTableTime;
319 int32_t nLength = pPattern->GetLength();
320 bool bInConstRange = false;
321 bool bEscape = false;
322 int32_t i = 0;
323 while (i < nLength) {
324 wchar_t wc = (*pPattern)[i];
325 if (wc == L'\'') {
326 bInConstRange = !bInConstRange;
327 if (bEscape) {
328 i++;
329 } else {
330 pPattern->Delete(i);
331 nLength--;
332 }
333 bEscape = !bEscape;
334 continue;
335 }
336 if (!bInConstRange && wc >= L'A' && wc <= L'a') {
337 uint8_t nAlt = pAltTable[wc - L'A'];
338 if (nAlt != 255)
339 pPattern->SetAt(i, wsAltSymbols[nAlt]);
340 }
341 i++;
342 bEscape = false;
343 }
344}
345
346std::pair<bool, CXFA_LocaleValue::ValueType> PatternStringType(
347 ByteStringView bsPattern) {
348 WideString wsPattern = WideString::FromUTF8(bsPattern);
349 if (L"datetime" == wsPattern.First(8))
351 if (L"date" == wsPattern.First(4)) {
352 auto pos = wsPattern.Find(L"time");
353 if (pos.has_value() && pos.value() != 0)
356 }
357 if (L"time" == wsPattern.First(4))
359 if (L"text" == wsPattern.First(4))
361 if (L"num" == wsPattern.First(3)) {
362 if (L"integer" == wsPattern.Substr(4, 7))
364 if (L"decimal" == wsPattern.Substr(4, 7))
366 if (L"currency" == wsPattern.Substr(4, 8))
368 if (L"percent" == wsPattern.Substr(4, 7))
371 }
372
374 wsPattern.MakeLower();
375 const wchar_t* pData = wsPattern.c_str();
376 int32_t iLength = wsPattern.GetLength();
377 int32_t iIndex = 0;
378 bool bSingleQuotation = false;
379 while (iIndex < iLength) {
380 wchar_t wsPatternChar = pData[iIndex];
381 if (wsPatternChar == 0x27) {
382 bSingleQuotation = !bSingleQuotation;
383 iIndex++;
384 continue;
385 }
386 if (bSingleQuotation) {
387 iIndex++;
388 continue;
389 }
390
391 if (wsPatternChar == 'h' || wsPatternChar == 'k')
393 if (wsPatternChar == 'x' || wsPatternChar == 'o' || wsPatternChar == '0')
395 if (wsPatternChar == 'v' || wsPatternChar == '8' || wsPatternChar == '$')
397 if (wsPatternChar == 'y' || wsPatternChar == 'j') {
398 iIndex++;
399 wchar_t timePatternChar;
400 while (iIndex < iLength) {
401 timePatternChar = pData[iIndex];
402 if (timePatternChar == 0x27) {
403 bSingleQuotation = !bSingleQuotation;
404 iIndex++;
405 continue;
406 }
407 if (!bSingleQuotation && timePatternChar == 't')
409 iIndex++;
410 }
412 }
413
414 if (wsPatternChar == 'a') {
416 } else if (wsPatternChar == 'z' || wsPatternChar == 's' ||
417 wsPatternChar == 'e' || wsPatternChar == ',' ||
418 wsPatternChar == '.') {
420 }
421 iIndex++;
422 }
423 return {false, type};
424}
425
426CFXJSE_FormCalcContext* ToFormCalcContext(CFXJSE_HostObject* pHostObj) {
427 return pHostObj ? pHostObj->AsFormCalcContext() : nullptr;
428}
429
430GCedLocaleIface* LocaleFromString(CXFA_Document* pDoc,
431 CXFA_LocaleMgr* pMgr,
432 ByteStringView bsLocale) {
433 if (!bsLocale.IsEmpty())
434 return pMgr->GetLocaleByName(WideString::FromUTF8(bsLocale));
435
437 return pThisNode->GetLocale();
438}
439
440WideString FormatFromString(LocaleIface* pLocale, ByteStringView bsFormat) {
441 if (!bsFormat.IsEmpty())
442 return WideString::FromUTF8(bsFormat);
443
445}
446
447LocaleIface::DateTimeSubcategory SubCategoryFromInt(int32_t iStyle) {
448 switch (iStyle) {
449 case 1:
451 case 3:
453 case 4:
455 case 0:
456 case 2:
457 default:
459 }
460}
461
462ByteString GetLocalDateTimeFormat(CXFA_Document* pDoc,
463 int32_t iStyle,
464 ByteStringView bsLocale,
465 bool bStandard,
466 bool bIsDate) {
467 CXFA_LocaleMgr* pMgr = pDoc->GetLocaleMgr();
468 LocaleIface* pLocale = LocaleFromString(pDoc, pMgr, bsLocale);
469 if (!pLocale)
470 return ByteString();
471
472 LocaleIface::DateTimeSubcategory category = SubCategoryFromInt(iStyle);
473 WideString wsLocal = bIsDate ? pLocale->GetDatePattern(category)
474 : pLocale->GetTimePattern(category);
475 if (!bStandard)
476 AlternateDateTimeSymbols(&wsLocal, pLocale->GetDateTimeSymbols(), bIsDate);
477 return wsLocal.ToUTF8();
478}
479
480bool IsWhitespace(char c) {
481 return c == 0x20 || c == 0x09 || c == 0x0B || c == 0x0C || c == 0x0A ||
482 c == 0x0D;
483}
484
485bool IsPartOfNumber(char ch) {
486 return isdigit(ch) || ch == '-' || ch == '.';
487}
488
489bool IsPartOfNumberW(wchar_t ch) {
490 return FXSYS_IsDecimalDigit(ch) || ch == L'-' || ch == L'.';
491}
492
493ByteString GUIDString(bool bSeparator) {
494 uint8_t data[16];
495 FX_Random_GenerateMT(reinterpret_cast<uint32_t*>(data), 4);
496 data[6] = (data[6] & 0x0F) | 0x40;
497
498 ByteString bsGUID;
499 {
500 // Span's lifetime must end before ReleaseBuffer() below.
501 pdfium::span<char> pBuf = bsGUID.GetBuffer(40);
502 size_t out_index = 0;
503 for (size_t i = 0; i < 16; ++i, out_index += 2) {
504 if (bSeparator && (i == 4 || i == 6 || i == 8 || i == 10))
505 pBuf[out_index++] = L'-';
506
507 FXSYS_IntToTwoHexChars(data[i], &pBuf[out_index]);
508 }
509 }
510 bsGUID.ReleaseBuffer(bSeparator ? 36 : 32);
511 return bsGUID;
512}
513
514void GetLocalTimeZone(int32_t* pHour, int32_t* pMin, int32_t* pSec) {
515 time_t now;
516 FXSYS_time(&now);
517
518 struct tm* pGmt = gmtime(&now);
519 struct tm* pLocal = FXSYS_localtime(&now);
520 *pHour = pLocal->tm_hour - pGmt->tm_hour;
521 *pMin = pLocal->tm_min - pGmt->tm_min;
522 *pSec = pLocal->tm_sec - pGmt->tm_sec;
523}
524
525bool HTMLSTR2Code(const WideString& pData, uint32_t* iCode) {
526 auto cmpFunc = [](const XFA_FMHtmlReserveCode& iter, ByteStringView val) {
527 return strcmp(val.unterminated_c_str(), iter.m_htmlReserve) > 0;
528 };
529 if (!pData.IsASCII())
530 return false;
531 ByteString temp = pData.ToASCII();
532 const XFA_FMHtmlReserveCode* result = std::lower_bound(
533 std::begin(kReservesForDecode), std::end(kReservesForDecode),
534 temp.AsStringView(), cmpFunc);
535 if (result != std::end(kReservesForDecode) &&
536 !strcmp(temp.c_str(), result->m_htmlReserve)) {
537 *iCode = result->m_uCode;
538 return true;
539 }
540 return false;
541}
542
543bool HTMLCode2STR(uint32_t iCode, WideString* wsHTMLReserve) {
544 auto cmpFunc = [](const XFA_FMHtmlReserveCode iter, const uint32_t& val) {
545 return iter.m_uCode < val;
546 };
547 const XFA_FMHtmlReserveCode* result =
548 std::lower_bound(std::begin(kReservesForEncode),
549 std::end(kReservesForEncode), iCode, cmpFunc);
550 if (result != std::end(kReservesForEncode) && result->m_uCode == iCode) {
551 *wsHTMLReserve = WideString::FromASCII(result->m_htmlReserve);
552 return true;
553 }
554 return false;
555}
556
557WideString DecodeURL(const WideString& wsURL) {
558 const wchar_t* pData = wsURL.c_str();
559 size_t iLen = wsURL.GetLength();
560 WideTextBuffer wsResultBuf;
561 for (size_t i = 0; i < iLen; ++i) {
562 wchar_t ch = pData[i];
563 if ('%' != ch) {
564 wsResultBuf.AppendChar(ch);
565 continue;
566 }
567
568 wchar_t chTemp = 0;
569 int32_t iCount = 0;
570 while (iCount < 2) {
571 if (++i >= iLen)
572 break;
573 chTemp *= 16;
574 ch = pData[i];
576 return WideString();
577 chTemp += FXSYS_WideHexCharToInt(ch);
578 ++iCount;
579 }
580 wsResultBuf.AppendChar(chTemp);
581 }
582 return wsResultBuf.MakeString();
583}
584
585WideString DecodeMLInternal(const WideString& wsHTML, bool bIsHTML) {
586 const wchar_t* pData = wsHTML.c_str();
587 size_t iLen = wsHTML.GetLength();
588 WideTextBuffer wsResultBuf;
589 for (size_t i = 0; i < iLen; ++i) {
590 wchar_t ch = pData[i];
591 if (ch != '&') {
592 wsResultBuf.AppendChar(ch);
593 continue;
594 }
595
596 if (++i >= iLen)
597 break;
598 ch = pData[i];
599 if (ch == '#') {
600 if (++i >= iLen)
601 break;
602 ch = pData[i];
603 if (ch != 'x' && ch != 'X')
604 return WideString();
605 if (++i >= iLen)
606 break;
607 ch = pData[i];
608 uint32_t iCode = 0;
609 while (ch != ';' && i < iLen) {
610 iCode *= 16;
612 return WideString();
613 iCode += FXSYS_WideHexCharToInt(ch);
614 if (++i >= iLen)
615 break;
616 ch = pData[i];
617 }
618 wsResultBuf.AppendChar(iCode);
619 continue;
620 }
621
622 wchar_t szBuffer[9];
623 size_t iStrIndex = 0;
624 while (ch != ';' && i < iLen) {
625 if (iStrIndex < 8)
626 szBuffer[iStrIndex++] = ch;
627 if (++i >= iLen)
628 break;
629 ch = pData[i];
630 }
631 szBuffer[iStrIndex] = 0;
632 if (bIsHTML) {
633 uint32_t iData = 0;
634 if (HTMLSTR2Code(szBuffer, &iData))
635 wsResultBuf.AppendChar((wchar_t)iData);
636 } else {
637 if (wcscmp(szBuffer, L"quot") == 0)
638 wsResultBuf.AppendChar('"');
639 else if (wcscmp(szBuffer, L"amp") == 0)
640 wsResultBuf.AppendChar('&');
641 else if (wcscmp(szBuffer, L"apos") == 0)
642 wsResultBuf.AppendChar('\'');
643 else if (wcscmp(szBuffer, L"lt") == 0)
644 wsResultBuf.AppendChar('<');
645 else if (wcscmp(szBuffer, L"gt") == 0)
646 wsResultBuf.AppendChar('>');
647 }
648 }
649 return wsResultBuf.MakeString();
650}
651
652WideString DecodeHTML(const WideString& wsHTML) {
653 return DecodeMLInternal(wsHTML, true);
654}
655
656WideString DecodeXML(const WideString& wsXML) {
657 return DecodeMLInternal(wsXML, false);
658}
659
660WideString EncodeURL(const ByteString& bsURL) {
661 static constexpr char32_t kStrUnsafe[] = {' ', '<', '>', '"', '#',
662 '%', '{', '}', '|', '\\',
663 '^', '~', '[', ']', '`'};
664 static constexpr char32_t kStrReserved[] = {';', '/', '?', ':',
665 '@', '=', '&'};
666 static constexpr char32_t kStrSpecial[] = {'$', '-', '+', '!', '*',
667 '\'', '(', ')', ','};
668
669 WideString wsURL = WideString::FromUTF8(bsURL.AsStringView());
670 WideTextBuffer wsResultBuf;
671 wchar_t encode_buffer[3];
672 encode_buffer[0] = '%';
673 for (char32_t ch : pdfium::CodePointView(wsURL.AsStringView())) {
674 size_t i = 0;
675 size_t iCount = std::size(kStrUnsafe);
676 while (i < iCount) {
677 if (ch == kStrUnsafe[i]) {
678 int32_t iIndex = ch / 16;
679 encode_buffer[1] = kStrCode[iIndex];
680 encode_buffer[2] = kStrCode[ch - iIndex * 16];
681 wsResultBuf << WideStringView(encode_buffer, 3);
682 break;
683 }
684 ++i;
685 }
686 if (i < iCount)
687 continue;
688
689 i = 0;
690 iCount = std::size(kStrReserved);
691 while (i < iCount) {
692 if (ch == kStrReserved[i]) {
693 int32_t iIndex = ch / 16;
694 encode_buffer[1] = kStrCode[iIndex];
695 encode_buffer[2] = kStrCode[ch - iIndex * 16];
696 wsResultBuf << WideStringView(encode_buffer, 3);
697 break;
698 }
699 ++i;
700 }
701 if (i < iCount)
702 continue;
703
704 i = 0;
705 iCount = std::size(kStrSpecial);
706 while (i < iCount) {
707 if (ch == kStrSpecial[i]) {
708 wsResultBuf.AppendChar(ch);
709 break;
710 }
711 ++i;
712 }
713 if (i < iCount)
714 continue;
715
716 if ((ch >= 0x80 && ch <= 0xff) || ch <= 0x1f || ch == 0x7f) {
717 int32_t iIndex = ch / 16;
718 encode_buffer[1] = kStrCode[iIndex];
719 encode_buffer[2] = kStrCode[ch - iIndex * 16];
720 wsResultBuf << WideStringView(encode_buffer, 3);
721 } else if (ch >= 0x20 && ch <= 0x7e) {
722 wsResultBuf.AppendChar(ch);
723 } else {
724 const wchar_t iRadix = 16;
725 WideString wsBuffer;
726 while (ch >= iRadix) {
727 wchar_t tmp = kStrCode[ch % iRadix];
728 ch /= iRadix;
729 wsBuffer += tmp;
730 }
731 wsBuffer += kStrCode[ch];
732 int32_t iLen = wsBuffer.GetLength();
733 if (iLen < 2)
734 break;
735
736 int32_t iIndex = 0;
737 if (iLen % 2 != 0) {
738 encode_buffer[1] = '0';
739 encode_buffer[2] = wsBuffer[iLen - 1];
740 iIndex = iLen - 2;
741 } else {
742 encode_buffer[1] = wsBuffer[iLen - 1];
743 encode_buffer[2] = wsBuffer[iLen - 2];
744 iIndex = iLen - 3;
745 }
746 wsResultBuf << WideStringView(encode_buffer, 3);
747 while (iIndex > 0) {
748 encode_buffer[1] = wsBuffer[iIndex];
749 encode_buffer[2] = wsBuffer[iIndex - 1];
750 iIndex -= 2;
751 wsResultBuf << WideStringView(encode_buffer, 3);
752 }
753 }
754 }
755 return wsResultBuf.MakeString();
756}
757
758WideString EncodeHTML(const ByteString& bsHTML) {
759 WideString wsHTML = WideString::FromUTF8(bsHTML.AsStringView());
760 wchar_t encode_buffer[8];
761 encode_buffer[0] = '&';
762 encode_buffer[1] = '#';
763 encode_buffer[2] = 'x';
764 WideTextBuffer wsResultBuf;
765 for (char32_t ch : pdfium::CodePointView(wsHTML.AsStringView())) {
766 WideString htmlReserve;
767 if (HTMLCode2STR(ch, &htmlReserve)) {
768 wsResultBuf.AppendChar(L'&');
769 wsResultBuf << htmlReserve;
770 wsResultBuf.AppendChar(L';');
771 } else if (ch >= 32 && ch <= 126) {
772 wsResultBuf.AppendChar(static_cast<wchar_t>(ch));
773 } else if (ch < 256) {
774 int32_t iIndex = ch / 16;
775 encode_buffer[3] = kStrCode[iIndex];
776 encode_buffer[4] = kStrCode[ch - iIndex * 16];
777 encode_buffer[5] = ';';
778 wsResultBuf << WideStringView(encode_buffer, 6);
779 } else if (ch < 65536) {
780 int32_t iBigByte = ch / 256;
781 int32_t iLittleByte = ch % 256;
782 encode_buffer[3] = kStrCode[iBigByte / 16];
783 encode_buffer[4] = kStrCode[iBigByte % 16];
784 encode_buffer[5] = kStrCode[iLittleByte / 16];
785 encode_buffer[6] = kStrCode[iLittleByte % 16];
786 encode_buffer[7] = ';';
787 wsResultBuf << WideStringView(encode_buffer, 8);
788 } else {
789 // TODO(tsepez): Handle codepoint not in BMP.
790 }
791 }
792 return wsResultBuf.MakeString();
793}
794
795WideString EncodeXML(const ByteString& bsXML) {
796 WideString wsXML = WideString::FromUTF8(bsXML.AsStringView());
797 WideTextBuffer wsResultBuf;
798 wchar_t encode_buffer[8];
799 encode_buffer[0] = '&';
800 encode_buffer[1] = '#';
801 encode_buffer[2] = 'x';
802 for (char32_t ch : pdfium::CodePointView(wsXML.AsStringView())) {
803 switch (ch) {
804 case '"':
805 wsResultBuf.AppendChar('&');
806 wsResultBuf << WideStringView(L"quot");
807 wsResultBuf.AppendChar(';');
808 break;
809 case '&':
810 wsResultBuf.AppendChar('&');
811 wsResultBuf << WideStringView(L"amp");
812 wsResultBuf.AppendChar(';');
813 break;
814 case '\'':
815 wsResultBuf.AppendChar('&');
816 wsResultBuf << WideStringView(L"apos");
817 wsResultBuf.AppendChar(';');
818 break;
819 case '<':
820 wsResultBuf.AppendChar('&');
821 wsResultBuf << WideStringView(L"lt");
822 wsResultBuf.AppendChar(';');
823 break;
824 case '>':
825 wsResultBuf.AppendChar('&');
826 wsResultBuf << WideStringView(L"gt");
827 wsResultBuf.AppendChar(';');
828 break;
829 default: {
830 if (ch >= 32 && ch <= 126) {
831 wsResultBuf.AppendChar(static_cast<wchar_t>(ch));
832 } else if (ch < 256) {
833 int32_t iIndex = ch / 16;
834 encode_buffer[3] = kStrCode[iIndex];
835 encode_buffer[4] = kStrCode[ch - iIndex * 16];
836 encode_buffer[5] = ';';
837 wsResultBuf << WideStringView(encode_buffer, 6);
838 } else if (ch < 65536) {
839 int32_t iBigByte = ch / 256;
840 int32_t iLittleByte = ch % 256;
841 encode_buffer[3] = kStrCode[iBigByte / 16];
842 encode_buffer[4] = kStrCode[iBigByte % 16];
843 encode_buffer[5] = kStrCode[iLittleByte / 16];
844 encode_buffer[6] = kStrCode[iLittleByte % 16];
845 encode_buffer[7] = ';';
846 wsResultBuf << WideStringView(encode_buffer, 8);
847 } else {
848 // TODO(tsepez): Handle codepoint not in BMP.
849 }
850 break;
851 }
852 }
853 }
854 return wsResultBuf.MakeString();
855}
856
857ByteString TrillionUS(ByteStringView bsData) {
858 static const char kUnits[][6] = {"zero", "one", "two", "three", "four",
859 "five", "six", "seven", "eight", "nine"};
860 static const char kCapUnits[][6] = {"Zero", "One", "Two", "Three", "Four",
861 "Five", "Six", "Seven", "Eight", "Nine"};
862 static const char kTens[][10] = {
863 "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen",
864 "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"};
865 static const char kLastTens[][8] = {"Twenty", "Thirty", "Forty", "Fifty",
866 "Sixty", "Seventy", "Eighty", "Ninety"};
867 static const char kComm[][11] = {" Hundred ", " Thousand ", " Million ",
868 " Billion ", "Trillion"};
869 const char* pData = bsData.unterminated_c_str();
870 int32_t iLength = bsData.GetLength();
871 int32_t iComm = 0;
872 if (iLength > 12)
873 iComm = 4;
874 else if (iLength > 9)
875 iComm = 3;
876 else if (iLength > 6)
877 iComm = 2;
878 else if (iLength > 3)
879 iComm = 1;
880
881 int32_t iFirstCount = iLength % 3;
882 if (iFirstCount == 0)
883 iFirstCount = 3;
884
885 ByteString strBuf;
886 int32_t iIndex = 0;
887 if (iFirstCount == 3) {
888 if (pData[iIndex] != '0') {
889 strBuf += kCapUnits[pData[iIndex] - '0'];
890 strBuf += kComm[0];
891 }
892 if (pData[iIndex + 1] == '0') {
893 strBuf += kCapUnits[pData[iIndex + 2] - '0'];
894 } else {
895 if (pData[iIndex + 1] > '1') {
896 strBuf += kLastTens[pData[iIndex + 1] - '2'];
897 strBuf += "-";
898 strBuf += kUnits[pData[iIndex + 2] - '0'];
899 } else if (pData[iIndex + 1] == '1') {
900 strBuf += kTens[pData[iIndex + 2] - '0'];
901 } else if (pData[iIndex + 1] == '0') {
902 strBuf += kCapUnits[pData[iIndex + 2] - '0'];
903 }
904 }
905 iIndex += 3;
906 } else if (iFirstCount == 2) {
907 if (pData[iIndex] == '0') {
908 strBuf += kCapUnits[pData[iIndex + 1] - '0'];
909 } else {
910 if (pData[iIndex] > '1') {
911 strBuf += kLastTens[pData[iIndex] - '2'];
912 strBuf += "-";
913 strBuf += kUnits[pData[iIndex + 1] - '0'];
914 } else if (pData[iIndex] == '1') {
915 strBuf += kTens[pData[iIndex + 1] - '0'];
916 } else if (pData[iIndex] == '0') {
917 strBuf += kCapUnits[pData[iIndex + 1] - '0'];
918 }
919 }
920 iIndex += 2;
921 } else if (iFirstCount == 1) {
922 strBuf += kCapUnits[pData[iIndex] - '0'];
923 ++iIndex;
924 }
925 if (iLength > 3 && iFirstCount > 0) {
926 strBuf += kComm[iComm];
927 --iComm;
928 }
929 while (iIndex < iLength) {
930 if (pData[iIndex] != '0') {
931 strBuf += kCapUnits[pData[iIndex] - '0'];
932 strBuf += kComm[0];
933 }
934 if (pData[iIndex + 1] == '0') {
935 strBuf += kCapUnits[pData[iIndex + 2] - '0'];
936 } else {
937 if (pData[iIndex + 1] > '1') {
938 strBuf += kLastTens[pData[iIndex + 1] - '2'];
939 strBuf += "-";
940 strBuf += kUnits[pData[iIndex + 2] - '0'];
941 } else if (pData[iIndex + 1] == '1') {
942 strBuf += kTens[pData[iIndex + 2] - '0'];
943 } else if (pData[iIndex + 1] == '0') {
944 strBuf += kCapUnits[pData[iIndex + 2] - '0'];
945 }
946 }
947 if (iIndex < iLength - 3) {
948 strBuf += kComm[iComm];
949 --iComm;
950 }
951 iIndex += 3;
952 }
953 return strBuf;
954}
955
956ByteString WordUS(ByteStringView bsData, int32_t iStyle) {
957 if (iStyle < 0 || iStyle > 2)
958 return ByteString();
959
960 int32_t iLength = bsData.GetLength();
961 ByteString strBuf;
962 int32_t iIndex = 0;
963 while (iIndex < iLength) {
964 if (bsData[iIndex] == '.')
965 break;
966 ++iIndex;
967 }
968 int32_t iInteger = iIndex;
969 iIndex = 0;
970 while (iIndex < iInteger) {
971 int32_t iCount = (iInteger - iIndex) % 12;
972 if (!iCount && iInteger - iIndex > 0)
973 iCount = 12;
974
975 strBuf += TrillionUS(bsData.Substr(iIndex, iCount));
976 iIndex += iCount;
977 if (iIndex < iInteger)
978 strBuf += " Trillion ";
979 }
980
981 if (iStyle > 0)
982 strBuf += " Dollars";
983
984 if (iStyle > 1 && iInteger < iLength) {
985 strBuf += " And ";
986 iIndex = iInteger + 1;
987 while (iIndex < iLength) {
988 int32_t iCount = (iLength - iIndex) % 12;
989 if (!iCount && iLength - iIndex > 0)
990 iCount = 12;
991
992 strBuf += TrillionUS(bsData.Substr(iIndex, iCount));
993 iIndex += iCount;
994 if (iIndex < iLength)
995 strBuf += " Trillion ";
996 }
997 strBuf += " Cents";
998 }
999 return strBuf;
1000}
1001
1002v8::Local<v8::Value> GetObjectDefaultValue(v8::Isolate* pIsolate,
1003 v8::Local<v8::Object> pObject) {
1004 CXFA_Node* pNode = ToNode(CFXJSE_Engine::ToObject(pIsolate, pObject));
1005 if (!pNode)
1006 return fxv8::NewNullHelper(pIsolate);
1007
1008 v8::Local<v8::Value> value;
1009 pNode->JSObject()->ScriptSomDefaultValue(pIsolate, &value, false,
1010 XFA_Attribute::Unknown);
1011 return value;
1012}
1013
1014bool SetObjectDefaultValue(v8::Isolate* pIsolate,
1015 v8::Local<v8::Object> pObject,
1016 v8::Local<v8::Value> hNewValue) {
1017 CXFA_Node* pNode = ToNode(CFXJSE_Engine::ToObject(pIsolate, pObject));
1018 if (!pNode)
1019 return false;
1020
1021 pNode->JSObject()->ScriptSomDefaultValue(pIsolate, &hNewValue, true,
1023 return true;
1024}
1025
1026v8::Local<v8::Value> GetExtractedValue(v8::Isolate* pIsolate,
1027 v8::Local<v8::Value> pValue) {
1028 if (pValue.IsEmpty())
1029 return v8::Local<v8::Value>();
1030
1031 if (fxv8::IsArray(pValue)) {
1032 v8::Local<v8::Array> arr = pValue.As<v8::Array>();
1033 uint32_t iLength = fxv8::GetArrayLengthHelper(arr);
1034 if (iLength < 3)
1035 return fxv8::NewUndefinedHelper(pIsolate);
1036
1037 v8::Local<v8::Value> propertyValue =
1038 fxv8::ReentrantGetArrayElementHelper(pIsolate, arr, 1);
1039 v8::Local<v8::Value> jsValue =
1040 fxv8::ReentrantGetArrayElementHelper(pIsolate, arr, 2);
1041 if (!fxv8::IsObject(jsValue))
1042 return fxv8::NewUndefinedHelper(pIsolate);
1043
1044 v8::Local<v8::Object> jsObjectValue = jsValue.As<v8::Object>();
1045 if (fxv8::IsNull(propertyValue))
1046 return GetObjectDefaultValue(pIsolate, jsObjectValue);
1047
1048 ByteString bsName =
1049 fxv8::ReentrantToByteStringHelper(pIsolate, propertyValue);
1050 return fxv8::ReentrantGetObjectPropertyHelper(pIsolate, jsObjectValue,
1051 bsName.AsStringView());
1052 }
1053
1054 if (fxv8::IsObject(pValue))
1055 return GetObjectDefaultValue(pIsolate, pValue.As<v8::Object>());
1056
1057 return pValue;
1058}
1059
1060v8::Local<v8::Value> GetSimpleValue(
1061 const v8::FunctionCallbackInfo<v8::Value>& info,
1062 uint32_t index) {
1063 DCHECK(index < static_cast<uint32_t>(info.Length()));
1064 return GetExtractedValue(info.GetIsolate(), info[index]);
1065}
1066
1067bool ValueIsNull(v8::Isolate* pIsolate, v8::Local<v8::Value> arg) {
1068 v8::Local<v8::Value> extracted = GetExtractedValue(pIsolate, arg);
1069 return extracted.IsEmpty() || fxv8::IsNull(extracted);
1070}
1071
1072int32_t ValueToInteger(v8::Isolate* pIsolate, v8::Local<v8::Value> arg) {
1073 v8::Local<v8::Value> extracted = GetExtractedValue(pIsolate, arg);
1074 if (extracted.IsEmpty())
1075 return 0;
1076
1077 if (fxv8::IsObject(extracted) || fxv8::IsArray(extracted))
1078 return ValueToInteger(pIsolate, extracted);
1079
1080 if (fxv8::IsString(extracted)) {
1081 ByteString bsValue = fxv8::ReentrantToByteStringHelper(pIsolate, extracted);
1082 return FXSYS_atoi(bsValue.c_str());
1083 }
1084
1085 return fxv8::ReentrantToInt32Helper(pIsolate, extracted);
1086}
1087
1088float ValueToFloat(v8::Isolate* pIsolate, v8::Local<v8::Value> arg) {
1089 v8::Local<v8::Value> extracted = GetExtractedValue(pIsolate, arg);
1090 if (extracted.IsEmpty())
1091 return 0.0f;
1092
1093 if (fxv8::IsUndefined(extracted))
1094 return 0.0f;
1095
1096 if (fxv8::IsObject(extracted) || fxv8::IsArray(extracted))
1097 return ValueToFloat(pIsolate, extracted);
1098
1099 if (fxv8::IsString(extracted)) {
1100 ByteString bsValue = fxv8::ReentrantToByteStringHelper(pIsolate, extracted);
1101 return strtof(bsValue.c_str(), nullptr);
1102 }
1103
1104 return fxv8::ReentrantToFloatHelper(pIsolate, extracted);
1105}
1106
1107double ValueToDouble(v8::Isolate* pIsolate, v8::Local<v8::Value> arg) {
1108 v8::Local<v8::Value> extracted = GetExtractedValue(pIsolate, arg);
1109 if (extracted.IsEmpty())
1110 return 0.0;
1111
1112 if (fxv8::IsUndefined(extracted))
1113 return 0.0;
1114
1115 if (fxv8::IsObject(extracted) || fxv8::IsArray(extracted))
1116 return ValueToDouble(pIsolate, extracted);
1117
1118 if (fxv8::IsString(extracted)) {
1119 ByteString bsValue = fxv8::ReentrantToByteStringHelper(pIsolate, extracted);
1120 return strtod(bsValue.c_str(), nullptr);
1121 }
1122
1123 return fxv8::ReentrantToDoubleHelper(pIsolate, extracted);
1124}
1125
1126absl::optional<double> ExtractDouble(v8::Isolate* pIsolate,
1127 v8::Local<v8::Value> src) {
1128 if (src.IsEmpty())
1129 return 0.0;
1130
1131 if (!fxv8::IsArray(src))
1132 return ValueToDouble(pIsolate, src);
1133
1134 v8::Local<v8::Array> arr = src.As<v8::Array>();
1135 uint32_t iLength = fxv8::GetArrayLengthHelper(arr);
1136 if (iLength < 3)
1137 return absl::nullopt;
1138
1139 v8::Local<v8::Value> propertyValue =
1140 fxv8::ReentrantGetArrayElementHelper(pIsolate, arr, 1);
1141 v8::Local<v8::Value> jsValue =
1142 fxv8::ReentrantGetArrayElementHelper(pIsolate, arr, 2);
1143 if (fxv8::IsNull(propertyValue) || !fxv8::IsObject(jsValue))
1144 return ValueToDouble(pIsolate, jsValue);
1145
1146 ByteString bsName =
1147 fxv8::ReentrantToByteStringHelper(pIsolate, propertyValue);
1148 return ValueToDouble(
1149 pIsolate, fxv8::ReentrantGetObjectPropertyHelper(
1150 pIsolate, jsValue.As<v8::Object>(), bsName.AsStringView()));
1151}
1152
1153ByteString ValueToUTF8String(v8::Isolate* pIsolate, v8::Local<v8::Value> arg) {
1154 if (arg.IsEmpty())
1155 return ByteString();
1156
1158 return ByteString();
1159
1160 if (fxv8::IsBoolean(arg))
1161 return fxv8::ReentrantToBooleanHelper(pIsolate, arg) ? "1" : "0";
1162
1163 return fxv8::ReentrantToByteStringHelper(pIsolate, arg);
1164}
1165
1166bool SimpleValueCompare(v8::Isolate* pIsolate,
1167 v8::Local<v8::Value> firstValue,
1168 v8::Local<v8::Value> secondValue) {
1169 if (firstValue.IsEmpty())
1170 return false;
1171
1172 if (fxv8::IsString(firstValue)) {
1173 const ByteString first = ValueToUTF8String(pIsolate, firstValue);
1174 const ByteString second = ValueToUTF8String(pIsolate, secondValue);
1175 return first == second;
1176 }
1177 if (fxv8::IsNumber(firstValue)) {
1178 const float first = ValueToFloat(pIsolate, firstValue);
1179 const float second = ValueToFloat(pIsolate, secondValue);
1180 return first == second;
1181 }
1182 if (fxv8::IsBoolean(firstValue)) {
1183 const bool first = fxv8::ReentrantToBooleanHelper(pIsolate, firstValue);
1184 const bool second = fxv8::ReentrantToBooleanHelper(pIsolate, secondValue);
1185 return first == second;
1186 }
1187 return fxv8::IsNull(firstValue) && fxv8::IsNull(secondValue);
1188}
1189
1190v8::LocalVector<v8::Value> UnfoldArgs(
1191 const v8::FunctionCallbackInfo<v8::Value>& info) {
1192 v8::LocalVector<v8::Value> results(info.GetIsolate());
1193 v8::Isolate* pIsolate = info.GetIsolate();
1194 for (int i = 1; i < info.Length(); ++i) {
1195 v8::Local<v8::Value> arg = info[i];
1196 if (fxv8::IsArray(arg)) {
1197 v8::Local<v8::Array> arr = arg.As<v8::Array>();
1198 uint32_t iLength = fxv8::GetArrayLengthHelper(arr);
1199 if (iLength < 3)
1200 continue;
1201
1202 v8::Local<v8::Value> propertyValue =
1203 fxv8::ReentrantGetArrayElementHelper(pIsolate, arr, 1);
1204
1205 for (uint32_t j = 2; j < iLength; j++) {
1206 v8::Local<v8::Value> jsValue =
1207 fxv8::ReentrantGetArrayElementHelper(pIsolate, arr, j);
1208
1209 if (!fxv8::IsObject(jsValue)) {
1210 results.push_back(fxv8::NewUndefinedHelper(pIsolate));
1211 } else if (fxv8::IsNull(propertyValue)) {
1212 results.push_back(
1213 GetObjectDefaultValue(pIsolate, jsValue.As<v8::Object>()));
1214 } else {
1215 ByteString bsName =
1216 fxv8::ReentrantToByteStringHelper(pIsolate, propertyValue);
1217 results.push_back(fxv8::ReentrantGetObjectPropertyHelper(
1218 pIsolate, jsValue.As<v8::Object>(), bsName.AsStringView()));
1219 }
1220 }
1221 } else if (fxv8::IsObject(arg)) {
1222 results.push_back(GetObjectDefaultValue(pIsolate, arg.As<v8::Object>()));
1223 } else {
1224 results.push_back(arg);
1225 }
1226 }
1227 return results;
1228}
1229
1230// Returns empty value on failure.
1231v8::Local<v8::Value> GetObjectForName(CFXJSE_HostObject* pHostObject,
1232 ByteStringView bsAccessorName) {
1233 CXFA_Document* pDoc = ToFormCalcContext(pHostObject)->GetDocument();
1234 if (!pDoc)
1235 return v8::Local<v8::Value>();
1236
1237 CFXJSE_Engine* pScriptContext = pDoc->GetScriptContext();
1238 absl::optional<CFXJSE_Engine::ResolveResult> maybeResult =
1239 pScriptContext->ResolveObjects(
1240 pScriptContext->GetThisObject(),
1241 WideString::FromUTF8(bsAccessorName).AsStringView(),
1242 Mask<XFA_ResolveFlag>{
1243 XFA_ResolveFlag::kChildren, XFA_ResolveFlag::kProperties,
1244 XFA_ResolveFlag::kSiblings, XFA_ResolveFlag::kParent});
1245 if (!maybeResult.has_value() ||
1246 maybeResult.value().type != CFXJSE_Engine::ResolveResult::Type::kNodes ||
1247 maybeResult.value().objects.empty()) {
1248 return v8::Local<v8::Value>();
1249 }
1250 return pScriptContext->GetOrCreateJSBindingFromMap(
1251 maybeResult.value().objects.front().Get());
1252}
1253
1254absl::optional<CFXJSE_Engine::ResolveResult> ResolveObjects(
1255 CFXJSE_HostObject* pHostObject,
1256 v8::Local<v8::Value> pRefValue,
1257 ByteStringView bsSomExp,
1258 bool bDotAccessor,
1259 bool bHasNoResolveName) {
1260 CXFA_Document* pDoc = ToFormCalcContext(pHostObject)->GetDocument();
1261 if (!pDoc)
1262 return absl::nullopt;
1263
1264 v8::Isolate* pIsolate = ToFormCalcContext(pHostObject)->GetIsolate();
1265 WideString wsSomExpression = WideString::FromUTF8(bsSomExp);
1266 CFXJSE_Engine* pScriptContext = pDoc->GetScriptContext();
1267 CXFA_Object* pNode = nullptr;
1268 Mask<XFA_ResolveFlag> dwFlags;
1269 if (bDotAccessor) {
1270 if (fxv8::IsNull(pRefValue)) {
1271 pNode = pScriptContext->GetThisObject();
1273 } else {
1274 pNode = CFXJSE_Engine::ToObject(pIsolate, pRefValue);
1275 if (!pNode)
1276 return absl::nullopt;
1277
1278 if (bHasNoResolveName) {
1279 WideString wsName;
1280 if (CXFA_Node* pXFANode = pNode->AsNode()) {
1281 absl::optional<WideString> ret =
1282 pXFANode->JSObject()->TryAttribute(XFA_Attribute::Name, false);
1283 if (ret.has_value())
1284 wsName = ret.value();
1285 }
1286 if (wsName.IsEmpty())
1287 wsName = L"#" + WideString::FromASCII(pNode->GetClassName());
1288
1289 wsSomExpression = wsName + wsSomExpression;
1291 } else {
1292 dwFlags = (bsSomExp == "*")
1293 ? Mask<XFA_ResolveFlag>{XFA_ResolveFlag::kChildren}
1294 : Mask<XFA_ResolveFlag>{XFA_ResolveFlag::kChildren,
1297 }
1298 }
1299 } else {
1300 pNode = CFXJSE_Engine::ToObject(pIsolate, pRefValue);
1302 }
1303 return pScriptContext->ResolveObjects(pNode, wsSomExpression.AsStringView(),
1304 dwFlags);
1305}
1306
1307v8::LocalVector<v8::Value> ParseResolveResult(
1308 CFXJSE_HostObject* pHostObject,
1309 const CFXJSE_Engine::ResolveResult& resolveNodeRS,
1310 v8::Local<v8::Value> pParentValue,
1311 bool* bAttribute) {
1312 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pHostObject);
1313 v8::Isolate* pIsolate = pContext->GetIsolate();
1314 v8::LocalVector<v8::Value> resultValues(pIsolate);
1315
1317 *bAttribute = false;
1318 CFXJSE_Engine* pScriptContext = pContext->GetDocument()->GetScriptContext();
1319 for (auto& pObject : resolveNodeRS.objects) {
1320 resultValues.push_back(
1321 pScriptContext->GetOrCreateJSBindingFromMap(pObject.Get()));
1322 }
1323 return resultValues;
1324 }
1325
1326 *bAttribute = true;
1327 if (resolveNodeRS.script_attribute.callback &&
1329 for (auto& pObject : resolveNodeRS.objects) {
1330 v8::Local<v8::Value> pValue;
1331 CJX_Object* jsObject = pObject->JSObject();
1332 (*resolveNodeRS.script_attribute.callback)(
1333 pIsolate, jsObject, &pValue, false,
1334 resolveNodeRS.script_attribute.attribute);
1335 resultValues.push_back(pValue);
1336 *bAttribute = false;
1337 }
1338 }
1339 if (*bAttribute && fxv8::IsObject(pParentValue))
1340 resultValues.push_back(pParentValue);
1341
1342 return resultValues;
1343}
1344
1345// Returns 0 if the provided `arg` is an invalid payment period count.
1346int GetValidatedPaymentPeriods(v8::Isolate* isolate, v8::Local<v8::Value> arg) {
1347 double periods = ValueToDouble(isolate, arg);
1348 if (periods < 1 ||
1349 periods > static_cast<double>(std::numeric_limits<int32_t>::max())) {
1350 return 0;
1351 }
1352
1353 return static_cast<int>(periods);
1354}
1355
1356} // namespace
1357
1359 kClassTag, // tag
1360 "XFA_FormCalcClass", // name
1361 kFormCalcFunctions, // methods
1362 std::size(kFormCalcFunctions), // number of methods
1363 nullptr, // dynamic prop type
1364 nullptr, // dynamic prop getter
1365 nullptr, // dynamic prop setter
1366 nullptr, // dynamic prop method call
1367};
1368
1369// static
1370void CFXJSE_FormCalcContext::Abs(
1371 CFXJSE_HostObject* pThis,
1372 const v8::FunctionCallbackInfo<v8::Value>& info) {
1373 if (info.Length() != 1) {
1374 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Abs");
1375 return;
1376 }
1377
1378 if (ValueIsNull(info.GetIsolate(), info[0])) {
1379 info.GetReturnValue().SetNull();
1380 return;
1381 }
1382 double dValue = ValueToDouble(info.GetIsolate(), info[0]);
1383 if (dValue < 0)
1384 dValue = -dValue;
1385
1386 info.GetReturnValue().Set(dValue);
1387}
1388
1389// static
1390void CFXJSE_FormCalcContext::Avg(
1391 CFXJSE_HostObject* pThis,
1392 const v8::FunctionCallbackInfo<v8::Value>& info) {
1393 uint32_t uCount = 0;
1394 double dSum = 0.0;
1395 auto fn = [&uCount, &dSum](v8::Isolate* pIsolate,
1396 v8::Local<v8::Value> pValue) {
1397 dSum += ValueToDouble(pIsolate, pValue);
1398 uCount++;
1399 };
1400 if (!ToFormCalcContext(pThis)->ApplyToExpansion(fn, info, /*bStrict=*/false))
1401 return;
1402
1403 if (uCount == 0) {
1404 info.GetReturnValue().SetNull();
1405 return;
1406 }
1407 info.GetReturnValue().Set(dSum / uCount);
1408}
1409
1410// static
1411void CFXJSE_FormCalcContext::Ceil(
1412 CFXJSE_HostObject* pThis,
1413 const v8::FunctionCallbackInfo<v8::Value>& info) {
1414 if (info.Length() != 1) {
1415 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Ceil");
1416 return;
1417 }
1418
1419 v8::Local<v8::Value> argValue = GetSimpleValue(info, 0);
1420 if (ValueIsNull(info.GetIsolate(), argValue)) {
1421 info.GetReturnValue().SetNull();
1422 return;
1423 }
1424
1425 info.GetReturnValue().Set(ceil(ValueToFloat(info.GetIsolate(), argValue)));
1426}
1427
1428// static
1429void CFXJSE_FormCalcContext::Count(
1430 CFXJSE_HostObject* pThis,
1431 const v8::FunctionCallbackInfo<v8::Value>& info) {
1432 uint32_t iCount = 0;
1433 auto fn = [&iCount](v8::Isolate* pIsolate, v8::Local<v8::Value> pvalue) {
1434 ++iCount;
1435 };
1436 if (!ToFormCalcContext(pThis)->ApplyToExpansion(fn, info, /*bStrict=*/true))
1437 return;
1438
1439 info.GetReturnValue().Set(iCount);
1440}
1441
1442// static
1443void CFXJSE_FormCalcContext::Floor(
1444 CFXJSE_HostObject* pThis,
1445 const v8::FunctionCallbackInfo<v8::Value>& info) {
1446 if (info.Length() != 1) {
1447 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Floor");
1448 return;
1449 }
1450
1451 v8::Local<v8::Value> argValue = GetSimpleValue(info, 0);
1452 if (ValueIsNull(info.GetIsolate(), argValue)) {
1453 info.GetReturnValue().SetNull();
1454 return;
1455 }
1456
1457 info.GetReturnValue().Set(floor(ValueToFloat(info.GetIsolate(), argValue)));
1458}
1459
1460// static
1461void CFXJSE_FormCalcContext::Max(
1462 CFXJSE_HostObject* pThis,
1463 const v8::FunctionCallbackInfo<v8::Value>& info) {
1464 uint32_t uCount = 0;
1465 double dMaxValue = 0.0;
1466 auto fn = [&uCount, &dMaxValue](v8::Isolate* pIsolate,
1467 v8::Local<v8::Value> pValue) {
1468 ++uCount;
1469 double dValue = ValueToDouble(pIsolate, pValue);
1470 dMaxValue = uCount == 1 ? dValue : std::max(dMaxValue, dValue);
1471 };
1472 if (!ToFormCalcContext(pThis)->ApplyToExpansion(fn, info, /*bStrict=*/true))
1473 return;
1474
1475 if (uCount == 0) {
1476 info.GetReturnValue().SetNull();
1477 return;
1478 }
1479 info.GetReturnValue().Set(dMaxValue);
1480}
1481
1482// static
1483void CFXJSE_FormCalcContext::Min(
1484 CFXJSE_HostObject* pThis,
1485 const v8::FunctionCallbackInfo<v8::Value>& info) {
1486 uint32_t uCount = 0;
1487 double dMinValue = 0.0;
1488 auto fn = [&uCount, &dMinValue](v8::Isolate* pIsolate,
1489 v8::Local<v8::Value> pValue) {
1490 ++uCount;
1491 double dValue = ValueToDouble(pIsolate, pValue);
1492 dMinValue = uCount == 1 ? dValue : std::min(dMinValue, dValue);
1493 };
1494 if (!ToFormCalcContext(pThis)->ApplyToExpansion(fn, info, /*bStrict=*/true))
1495 return;
1496
1497 if (uCount == 0) {
1498 info.GetReturnValue().SetNull();
1499 return;
1500 }
1501 info.GetReturnValue().Set(dMinValue);
1502}
1503
1504// static
1505void CFXJSE_FormCalcContext::Mod(
1506 CFXJSE_HostObject* pThis,
1507 const v8::FunctionCallbackInfo<v8::Value>& info) {
1508 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
1509 if (info.Length() != 2) {
1510 pContext->ThrowParamCountMismatchException("Mod");
1511 return;
1512 }
1513
1514 if (fxv8::IsNull(info[0]) || fxv8::IsNull(info[1])) {
1515 info.GetReturnValue().SetNull();
1516 return;
1517 }
1518
1519 absl::optional<double> maybe_dividend =
1520 ExtractDouble(info.GetIsolate(), info[0]);
1521 absl::optional<double> maybe_divisor =
1522 ExtractDouble(info.GetIsolate(), info[1]);
1523 if (!maybe_dividend.has_value() || !maybe_divisor.has_value()) {
1524 pContext->ThrowArgumentMismatchException();
1525 return;
1526 }
1527
1528 double dividend = maybe_dividend.value();
1529 double divisor = maybe_divisor.value();
1530 if (divisor == 0.0) {
1531 pContext->ThrowDivideByZeroException();
1532 return;
1533 }
1534
1535 info.GetReturnValue().Set(dividend -
1536 divisor * static_cast<int32_t>(dividend / divisor));
1537}
1538
1539// static
1540void CFXJSE_FormCalcContext::Round(
1541 CFXJSE_HostObject* pThis,
1542 const v8::FunctionCallbackInfo<v8::Value>& info) {
1543 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
1544 int32_t argc = info.Length();
1545 if (argc < 1 || argc > 2) {
1546 pContext->ThrowParamCountMismatchException("Round");
1547 return;
1548 }
1549
1550 if (fxv8::IsNull(info[0])) {
1551 info.GetReturnValue().SetNull();
1552 return;
1553 }
1554
1555 absl::optional<double> maybe_value =
1556 ExtractDouble(info.GetIsolate(), info[0]);
1557 if (!maybe_value.has_value()) {
1558 pContext->ThrowArgumentMismatchException();
1559 return;
1560 }
1561
1562 double dValue = maybe_value.value();
1563 uint8_t uPrecision = 0;
1564 if (argc > 1) {
1565 if (fxv8::IsNull(info[1])) {
1566 info.GetReturnValue().SetNull();
1567 return;
1568 }
1569 absl::optional<double> maybe_precision =
1570 ExtractDouble(info.GetIsolate(), info[1]);
1571 if (!maybe_precision.has_value()) {
1572 pContext->ThrowArgumentMismatchException();
1573 return;
1574 }
1575 double dPrecision = maybe_precision.value();
1576 uPrecision = static_cast<uint8_t>(std::clamp(dPrecision, 0.0, 12.0));
1577 }
1578
1579 CFGAS_Decimal decimalValue(static_cast<float>(dValue), uPrecision);
1580 info.GetReturnValue().Set(decimalValue.ToDouble());
1581}
1582
1583// static
1584void CFXJSE_FormCalcContext::Sum(
1585 CFXJSE_HostObject* pThis,
1586 const v8::FunctionCallbackInfo<v8::Value>& info) {
1587 uint32_t uCount = 0;
1588 double dSum = 0.0;
1589 auto fn = [&uCount, &dSum](v8::Isolate* pIsolate,
1590 v8::Local<v8::Value> pValue) {
1591 ++uCount;
1592 dSum += ValueToDouble(pIsolate, pValue);
1593 };
1594 if (!ToFormCalcContext(pThis)->ApplyToExpansion(fn, info, /*bStrict=*/true))
1595 return;
1596
1597 if (uCount == 0) {
1598 info.GetReturnValue().SetNull();
1599 return;
1600 }
1601 info.GetReturnValue().Set(dSum);
1602}
1603
1604// static
1605void CFXJSE_FormCalcContext::Date(
1606 CFXJSE_HostObject* pThis,
1607 const v8::FunctionCallbackInfo<v8::Value>& info) {
1608 if (info.Length() != 0) {
1609 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Date");
1610 return;
1611 }
1612
1613 time_t currentTime;
1614 FXSYS_time(&currentTime);
1615 struct tm* pTmStruct = gmtime(&currentTime);
1616
1617 info.GetReturnValue().Set(DateString2Num(
1618 ByteString::Format("%d%02d%02d", pTmStruct->tm_year + 1900,
1619 pTmStruct->tm_mon + 1, pTmStruct->tm_mday)
1620 .AsStringView()));
1621}
1622
1623// static
1624void CFXJSE_FormCalcContext::Date2Num(
1625 CFXJSE_HostObject* pThis,
1626 const v8::FunctionCallbackInfo<v8::Value>& info) {
1627 int32_t argc = info.Length();
1628 if (argc < 1 || argc > 3) {
1629 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Date2Num");
1630 return;
1631 }
1632
1633 v8::Local<v8::Value> dateValue = GetSimpleValue(info, 0);
1634 if (ValueIsNull(info.GetIsolate(), dateValue)) {
1635 info.GetReturnValue().SetNull();
1636 return;
1637 }
1638
1639 ByteString bsDate = ValueToUTF8String(info.GetIsolate(), dateValue);
1640 ByteString bsFormat;
1641 if (argc > 1) {
1642 v8::Local<v8::Value> formatValue = GetSimpleValue(info, 1);
1643 if (ValueIsNull(info.GetIsolate(), formatValue)) {
1644 info.GetReturnValue().SetNull();
1645 return;
1646 }
1647 bsFormat = ValueToUTF8String(info.GetIsolate(), formatValue);
1648 }
1649
1650 ByteString bsLocale;
1651 if (argc > 2) {
1652 v8::Local<v8::Value> localeValue = GetSimpleValue(info, 2);
1653 if (ValueIsNull(info.GetIsolate(), localeValue)) {
1654 info.GetReturnValue().SetNull();
1655 return;
1656 }
1657 bsLocale = ValueToUTF8String(info.GetIsolate(), localeValue);
1658 }
1659
1660 ByteString bsIsoDate =
1661 Local2IsoDate(pThis, bsDate.AsStringView(), bsFormat.AsStringView(),
1662 bsLocale.AsStringView());
1663 info.GetReturnValue().Set(DateString2Num(bsIsoDate.AsStringView()));
1664}
1665
1666// static
1667void CFXJSE_FormCalcContext::DateFmt(
1668 CFXJSE_HostObject* pThis,
1669 const v8::FunctionCallbackInfo<v8::Value>& info) {
1670 int32_t argc = info.Length();
1671 if (argc > 2) {
1672 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Date2Num");
1673 return;
1674 }
1675
1676 int32_t iStyle = 0;
1677 if (argc > 0) {
1678 v8::Local<v8::Value> infotyle = GetSimpleValue(info, 0);
1679 if (fxv8::IsNull(infotyle)) {
1680 info.GetReturnValue().SetNull();
1681 return;
1682 }
1683
1684 iStyle = static_cast<int32_t>(ValueToFloat(info.GetIsolate(), infotyle));
1685 if (iStyle < 0 || iStyle > 4)
1686 iStyle = 0;
1687 }
1688
1689 ByteString bsLocale;
1690 if (argc > 1) {
1691 v8::Local<v8::Value> argLocale = GetSimpleValue(info, 1);
1692 if (fxv8::IsNull(argLocale)) {
1693 info.GetReturnValue().SetNull();
1694 return;
1695 }
1696 bsLocale = ValueToUTF8String(info.GetIsolate(), argLocale);
1697 }
1698
1699 ByteString bsFormat =
1700 GetStandardDateFormat(pThis, iStyle, bsLocale.AsStringView());
1701 info.GetReturnValue().Set(
1702 fxv8::NewStringHelper(info.GetIsolate(), bsFormat.AsStringView()));
1703}
1704
1705// static
1706void CFXJSE_FormCalcContext::IsoDate2Num(
1707 CFXJSE_HostObject* pThis,
1708 const v8::FunctionCallbackInfo<v8::Value>& info) {
1709 if (info.Length() != 1) {
1710 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("IsoDate2Num");
1711 return;
1712 }
1713 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
1714 if (fxv8::IsNull(argOne)) {
1715 info.GetReturnValue().SetNull();
1716 return;
1717 }
1718 ByteString bsArg = ValueToUTF8String(info.GetIsolate(), argOne);
1719 info.GetReturnValue().Set(DateString2Num(bsArg.AsStringView()));
1720}
1721
1722// static
1723void CFXJSE_FormCalcContext::IsoTime2Num(
1724 CFXJSE_HostObject* pThis,
1725 const v8::FunctionCallbackInfo<v8::Value>& info) {
1726 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
1727 if (info.Length() != 1) {
1728 pContext->ThrowParamCountMismatchException("IsoTime2Num");
1729 return;
1730 }
1731
1732 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
1733 if (ValueIsNull(info.GetIsolate(), argOne)) {
1734 info.GetReturnValue().SetNull();
1735 return;
1736 }
1737
1738 CXFA_Document* pDoc = pContext->GetDocument();
1739 CXFA_LocaleMgr* pMgr = pDoc->GetLocaleMgr();
1740 ByteString bsArg = ValueToUTF8String(info.GetIsolate(), argOne);
1741 auto pos = bsArg.Find('T', 0);
1742 if (!pos.has_value() || pos.value() == bsArg.GetLength() - 1) {
1743 info.GetReturnValue().Set(0);
1744 return;
1745 }
1746 bsArg = bsArg.Last(bsArg.GetLength() - (pos.value() + 1));
1747
1749 WideString::FromUTF8(bsArg.AsStringView()), pMgr);
1750 if (!timeValue.IsValid()) {
1751 info.GetReturnValue().Set(0);
1752 return;
1753 }
1754
1755 CFX_DateTime uniTime = timeValue.GetTime();
1756 int32_t hour = uniTime.GetHour();
1757 int32_t min = uniTime.GetMinute();
1758 int32_t second = uniTime.GetSecond();
1759 int32_t milSecond = uniTime.GetMillisecond();
1760
1761 // TODO(dsinclair): See if there is other time conversion code in pdfium and
1762 // consolidate.
1763 int32_t mins = hour * 60 + min;
1765 while (mins > 1440)
1766 mins -= 1440;
1767 while (mins < 0)
1768 mins += 1440;
1769 hour = mins / 60;
1770 min = mins % 60;
1771
1772 info.GetReturnValue().Set(hour * 3600000 + min * 60000 + second * 1000 +
1773 milSecond + 1);
1774}
1775
1776// static
1777void CFXJSE_FormCalcContext::LocalDateFmt(
1778 CFXJSE_HostObject* pThis,
1779 const v8::FunctionCallbackInfo<v8::Value>& info) {
1780 int32_t argc = info.Length();
1781 if (argc > 2) {
1782 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("LocalDateFmt");
1783 return;
1784 }
1785
1786 int32_t iStyle = 0;
1787 if (argc > 0) {
1788 v8::Local<v8::Value> infotyle = GetSimpleValue(info, 0);
1789 if (fxv8::IsNull(infotyle)) {
1790 info.GetReturnValue().SetNull();
1791 return;
1792 }
1793 iStyle = static_cast<int32_t>(ValueToFloat(info.GetIsolate(), infotyle));
1794 if (iStyle > 4 || iStyle < 0)
1795 iStyle = 0;
1796 }
1797
1798 ByteString bsLocale;
1799 if (argc > 1) {
1800 v8::Local<v8::Value> argLocale = GetSimpleValue(info, 1);
1801 if (fxv8::IsNull(argLocale)) {
1802 info.GetReturnValue().SetNull();
1803 return;
1804 }
1805 bsLocale = ValueToUTF8String(info.GetIsolate(), argLocale);
1806 }
1807
1808 ByteString bsFormat =
1809 GetLocalDateFormat(pThis, iStyle, bsLocale.AsStringView(), false);
1810 info.GetReturnValue().Set(
1811 fxv8::NewStringHelper(info.GetIsolate(), bsFormat.AsStringView()));
1812}
1813
1814// static
1815void CFXJSE_FormCalcContext::LocalTimeFmt(
1816 CFXJSE_HostObject* pThis,
1817 const v8::FunctionCallbackInfo<v8::Value>& info) {
1818 int32_t argc = info.Length();
1819 if (argc > 2) {
1820 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("LocalTimeFmt");
1821 return;
1822 }
1823
1824 int32_t iStyle = 0;
1825 if (argc > 0) {
1826 v8::Local<v8::Value> infotyle = GetSimpleValue(info, 0);
1827 if (fxv8::IsNull(infotyle)) {
1828 info.GetReturnValue().SetNull();
1829 return;
1830 }
1831 iStyle = static_cast<int32_t>(ValueToFloat(info.GetIsolate(), infotyle));
1832 if (iStyle > 4 || iStyle < 0)
1833 iStyle = 0;
1834 }
1835
1836 ByteString bsLocale;
1837 if (argc > 1) {
1838 v8::Local<v8::Value> argLocale = GetSimpleValue(info, 1);
1839 if (fxv8::IsNull(argLocale)) {
1840 info.GetReturnValue().SetNull();
1841 return;
1842 }
1843 bsLocale = ValueToUTF8String(info.GetIsolate(), argLocale);
1844 }
1845
1846 ByteString bsFormat =
1847 GetLocalTimeFormat(pThis, iStyle, bsLocale.AsStringView(), false);
1848 info.GetReturnValue().Set(
1849 fxv8::NewStringHelper(info.GetIsolate(), bsFormat.AsStringView()));
1850}
1851
1852// static
1853void CFXJSE_FormCalcContext::Num2Date(
1854 CFXJSE_HostObject* pThis,
1855 const v8::FunctionCallbackInfo<v8::Value>& info) {
1856 int32_t argc = info.Length();
1857 if (argc < 1 || argc > 3) {
1858 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Num2Date");
1859 return;
1860 }
1861
1862 v8::Local<v8::Value> dateValue = GetSimpleValue(info, 0);
1863 if (ValueIsNull(info.GetIsolate(), dateValue)) {
1864 info.GetReturnValue().SetNull();
1865 return;
1866 }
1867 int32_t dDate =
1868 static_cast<int32_t>(ValueToFloat(info.GetIsolate(), dateValue));
1869 if (dDate < 1) {
1870 info.GetReturnValue().SetNull();
1871 return;
1872 }
1873
1874 ByteString bsFormat;
1875 if (argc > 1) {
1876 v8::Local<v8::Value> formatValue = GetSimpleValue(info, 1);
1877 if (ValueIsNull(info.GetIsolate(), formatValue)) {
1878 info.GetReturnValue().SetNull();
1879 return;
1880 }
1881 bsFormat = ValueToUTF8String(info.GetIsolate(), formatValue);
1882 }
1883
1884 ByteString bsLocale;
1885 if (argc > 2) {
1886 v8::Local<v8::Value> localeValue = GetSimpleValue(info, 2);
1887 if (ValueIsNull(info.GetIsolate(), localeValue)) {
1888 info.GetReturnValue().SetNull();
1889 return;
1890 }
1891 bsLocale = ValueToUTF8String(info.GetIsolate(), localeValue);
1892 }
1893
1894 int32_t iYear = 1900;
1895 int32_t iMonth = 1;
1896 int32_t iDay = 1;
1897 int32_t i = 0;
1898 while (dDate > 0) {
1899 if (iMonth == 2) {
1900 if ((!((iYear + i) % 4) && ((iYear + i) % 100)) || !((iYear + i) % 400)) {
1901 if (dDate > 29) {
1902 ++iMonth;
1903 if (iMonth > 12) {
1904 iMonth = 1;
1905 ++i;
1906 }
1907 iDay = 1;
1908 dDate -= 29;
1909 } else {
1910 iDay += static_cast<int32_t>(dDate) - 1;
1911 dDate = 0;
1912 }
1913 } else {
1914 if (dDate > 28) {
1915 ++iMonth;
1916 if (iMonth > 12) {
1917 iMonth = 1;
1918 ++i;
1919 }
1920 iDay = 1;
1921 dDate -= 28;
1922 } else {
1923 iDay += static_cast<int32_t>(dDate) - 1;
1924 dDate = 0;
1925 }
1926 }
1927 } else if (iMonth < 8) {
1928 if ((iMonth % 2 == 0)) {
1929 if (dDate > 30) {
1930 ++iMonth;
1931 if (iMonth > 12) {
1932 iMonth = 1;
1933 ++i;
1934 }
1935 iDay = 1;
1936 dDate -= 30;
1937 } else {
1938 iDay += static_cast<int32_t>(dDate) - 1;
1939 dDate = 0;
1940 }
1941 } else {
1942 if (dDate > 31) {
1943 ++iMonth;
1944 if (iMonth > 12) {
1945 iMonth = 1;
1946 ++i;
1947 }
1948 iDay = 1;
1949 dDate -= 31;
1950 } else {
1951 iDay += static_cast<int32_t>(dDate) - 1;
1952 dDate = 0;
1953 }
1954 }
1955 } else {
1956 if (iMonth % 2 != 0) {
1957 if (dDate > 30) {
1958 ++iMonth;
1959 if (iMonth > 12) {
1960 iMonth = 1;
1961 ++i;
1962 }
1963 iDay = 1;
1964 dDate -= 30;
1965 } else {
1966 iDay += static_cast<int32_t>(dDate) - 1;
1967 dDate = 0;
1968 }
1969 } else {
1970 if (dDate > 31) {
1971 ++iMonth;
1972 if (iMonth > 12) {
1973 iMonth = 1;
1974 ++i;
1975 }
1976 iDay = 1;
1977 dDate -= 31;
1978 } else {
1979 iDay += static_cast<int32_t>(dDate) - 1;
1980 dDate = 0;
1981 }
1982 }
1983 }
1984 }
1985
1986 ByteString bsLocalDate = IsoDate2Local(
1987 pThis,
1988 ByteString::Format("%d%02d%02d", iYear + i, iMonth, iDay).AsStringView(),
1989 bsFormat.AsStringView(), bsLocale.AsStringView());
1990 info.GetReturnValue().Set(
1991 fxv8::NewStringHelper(info.GetIsolate(), bsLocalDate.AsStringView()));
1992}
1993
1994// static
1995void CFXJSE_FormCalcContext::Num2GMTime(
1996 CFXJSE_HostObject* pThis,
1997 const v8::FunctionCallbackInfo<v8::Value>& info) {
1998 int32_t argc = info.Length();
1999 if (argc < 1 || argc > 3) {
2000 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Num2GMTime");
2001 return;
2002 }
2003
2004 v8::Local<v8::Value> timeValue = GetSimpleValue(info, 0);
2005 if (fxv8::IsNull(timeValue)) {
2006 info.GetReturnValue().SetNull();
2007 return;
2008 }
2009 int32_t iTime =
2010 static_cast<int32_t>(ValueToFloat(info.GetIsolate(), timeValue));
2011 if (abs(iTime) < 1.0) {
2012 info.GetReturnValue().SetNull();
2013 return;
2014 }
2015
2016 ByteString bsFormat;
2017 if (argc > 1) {
2018 v8::Local<v8::Value> formatValue = GetSimpleValue(info, 1);
2019 if (fxv8::IsNull(formatValue)) {
2020 info.GetReturnValue().SetNull();
2021 return;
2022 }
2023 bsFormat = ValueToUTF8String(info.GetIsolate(), formatValue);
2024 }
2025
2026 ByteString bsLocale;
2027 if (argc > 2) {
2028 v8::Local<v8::Value> localeValue = GetSimpleValue(info, 2);
2029 if (fxv8::IsNull(localeValue)) {
2030 info.GetReturnValue().SetNull();
2031 return;
2032 }
2033 bsLocale = ValueToUTF8String(info.GetIsolate(), localeValue);
2034 }
2035
2036 ByteString bsGMTTime = Num2AllTime(pThis, iTime, bsFormat.AsStringView(),
2037 bsLocale.AsStringView(), true);
2038 info.GetReturnValue().Set(
2039 fxv8::NewStringHelper(info.GetIsolate(), bsGMTTime.AsStringView()));
2040}
2041
2042// static
2043void CFXJSE_FormCalcContext::Num2Time(
2044 CFXJSE_HostObject* pThis,
2045 const v8::FunctionCallbackInfo<v8::Value>& info) {
2046 int32_t argc = info.Length();
2047 if (argc < 1 || argc > 3) {
2048 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Num2Time");
2049 return;
2050 }
2051
2052 v8::Local<v8::Value> timeValue = GetSimpleValue(info, 0);
2053 if (fxv8::IsNull(timeValue)) {
2054 info.GetReturnValue().SetNull();
2055 return;
2056 }
2057 float fTime = ValueToFloat(info.GetIsolate(), timeValue);
2058 if (fabs(fTime) < 1.0) {
2059 info.GetReturnValue().SetNull();
2060 return;
2061 }
2062
2063 ByteString bsFormat;
2064 if (argc > 1) {
2065 v8::Local<v8::Value> formatValue = GetSimpleValue(info, 1);
2066 if (fxv8::IsNull(formatValue)) {
2067 info.GetReturnValue().SetNull();
2068 return;
2069 }
2070 bsFormat = ValueToUTF8String(info.GetIsolate(), formatValue);
2071 }
2072
2073 ByteString bsLocale;
2074 if (argc > 2) {
2075 v8::Local<v8::Value> localeValue = GetSimpleValue(info, 2);
2076 if (fxv8::IsNull(localeValue)) {
2077 info.GetReturnValue().SetNull();
2078 return;
2079 }
2080 bsLocale = ValueToUTF8String(info.GetIsolate(), localeValue);
2081 }
2082
2083 ByteString bsLocalTime =
2084 Num2AllTime(pThis, static_cast<int32_t>(fTime), bsFormat.AsStringView(),
2085 bsLocale.AsStringView(), false);
2086 info.GetReturnValue().Set(
2087 fxv8::NewStringHelper(info.GetIsolate(), bsLocalTime.AsStringView()));
2088}
2089
2090// static
2091void CFXJSE_FormCalcContext::Time(
2092 CFXJSE_HostObject* pThis,
2093 const v8::FunctionCallbackInfo<v8::Value>& info) {
2094 if (info.Length() != 0) {
2095 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Time");
2096 return;
2097 }
2098
2099 time_t now;
2100 FXSYS_time(&now);
2101 struct tm* pGmt = gmtime(&now);
2102 info.GetReturnValue().Set(
2103 (pGmt->tm_hour * 3600 + pGmt->tm_min * 60 + pGmt->tm_sec) * 1000);
2104}
2105
2106// static
2107void CFXJSE_FormCalcContext::Time2Num(
2108 CFXJSE_HostObject* pThis,
2109 const v8::FunctionCallbackInfo<v8::Value>& info) {
2110 int32_t argc = info.Length();
2111 if (argc < 1 || argc > 3) {
2112 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Time2Num");
2113 return;
2114 }
2115
2116 ByteString bsTime;
2117 v8::Local<v8::Value> timeValue = GetSimpleValue(info, 0);
2118 if (ValueIsNull(info.GetIsolate(), timeValue)) {
2119 info.GetReturnValue().SetNull();
2120 return;
2121 }
2122 bsTime = ValueToUTF8String(info.GetIsolate(), timeValue);
2123
2124 ByteString bsFormat;
2125 if (argc > 1) {
2126 v8::Local<v8::Value> formatValue = GetSimpleValue(info, 1);
2127 if (ValueIsNull(info.GetIsolate(), formatValue)) {
2128 info.GetReturnValue().SetNull();
2129 return;
2130 }
2131 bsFormat = ValueToUTF8String(info.GetIsolate(), formatValue);
2132 }
2133
2134 ByteString bsLocale;
2135 if (argc > 2) {
2136 v8::Local<v8::Value> localeValue = GetSimpleValue(info, 2);
2137 if (ValueIsNull(info.GetIsolate(), localeValue)) {
2138 info.GetReturnValue().SetNull();
2139 return;
2140 }
2141 bsLocale = ValueToUTF8String(info.GetIsolate(), localeValue);
2142 }
2143
2144 CXFA_Document* pDoc = ToFormCalcContext(pThis)->GetDocument();
2145 CXFA_LocaleMgr* pMgr = pDoc->GetLocaleMgr();
2146 GCedLocaleIface* pLocale = nullptr;
2147 if (!bsLocale.IsEmpty()) {
2148 pLocale =
2149 pMgr->GetLocaleByName(WideString::FromUTF8(bsLocale.AsStringView()));
2150 }
2151 if (!pLocale) {
2153 pLocale = pThisNode->GetLocale();
2154 }
2155
2156 WideString wsFormat;
2157 if (bsFormat.IsEmpty()) {
2158 wsFormat =
2160 } else {
2161 wsFormat = WideString::FromUTF8(bsFormat.AsStringView());
2162 }
2163 wsFormat = L"time{" + wsFormat + L"}";
2165 WideString::FromUTF8(bsTime.AsStringView()),
2166 wsFormat, pLocale, pMgr);
2167 if (!localeValue.IsValid()) {
2168 info.GetReturnValue().Set(0);
2169 return;
2170 }
2171
2172 CFX_DateTime uniTime = localeValue.GetTime();
2173 int32_t hour = uniTime.GetHour();
2174 int32_t minute = uniTime.GetMinute();
2175 const int32_t second = uniTime.GetSecond();
2176 const int32_t millisecond = uniTime.GetMillisecond();
2177
2178 constexpr int kMinutesInDay = 24 * 60;
2179 int32_t minutes_with_tz =
2181 minutes_with_tz %= kMinutesInDay;
2182 if (minutes_with_tz < 0)
2183 minutes_with_tz += kMinutesInDay;
2184
2185 hour = minutes_with_tz / 60;
2186 minute = minutes_with_tz % 60;
2187 info.GetReturnValue().Set(hour * 3600000 + minute * 60000 + second * 1000 +
2188 millisecond + 1);
2189}
2190
2191// static
2192void CFXJSE_FormCalcContext::TimeFmt(
2193 CFXJSE_HostObject* pThis,
2194 const v8::FunctionCallbackInfo<v8::Value>& info) {
2195 int32_t argc = info.Length();
2196 if (argc > 2) {
2197 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("TimeFmt");
2198 return;
2199 }
2200
2201 int32_t iStyle = 0;
2202 if (argc > 0) {
2203 v8::Local<v8::Value> infotyle = GetSimpleValue(info, 0);
2204 if (fxv8::IsNull(infotyle)) {
2205 info.GetReturnValue().SetNull();
2206 return;
2207 }
2208 iStyle = static_cast<int32_t>(ValueToFloat(info.GetIsolate(), infotyle));
2209 if (iStyle > 4 || iStyle < 0)
2210 iStyle = 0;
2211 }
2212
2213 ByteString bsLocale;
2214 if (argc > 1) {
2215 v8::Local<v8::Value> argLocale = GetSimpleValue(info, 1);
2216 if (fxv8::IsNull(argLocale)) {
2217 info.GetReturnValue().SetNull();
2218 return;
2219 }
2220 bsLocale = ValueToUTF8String(info.GetIsolate(), argLocale);
2221 }
2222
2223 ByteString bsFormat =
2224 GetStandardTimeFormat(pThis, iStyle, bsLocale.AsStringView());
2225 info.GetReturnValue().Set(
2226 fxv8::NewStringHelper(info.GetIsolate(), bsFormat.AsStringView()));
2227}
2228
2229// static
2230ByteString CFXJSE_FormCalcContext::Local2IsoDate(CFXJSE_HostObject* pThis,
2231 ByteStringView bsDate,
2232 ByteStringView bsFormat,
2233 ByteStringView bsLocale) {
2234 CXFA_Document* pDoc = ToFormCalcContext(pThis)->GetDocument();
2235 if (!pDoc)
2236 return ByteString();
2237
2238 CXFA_LocaleMgr* pMgr = pDoc->GetLocaleMgr();
2239 GCedLocaleIface* pLocale = LocaleFromString(pDoc, pMgr, bsLocale);
2240 if (!pLocale)
2241 return ByteString();
2242
2243 WideString wsFormat = FormatFromString(pLocale, bsFormat);
2244 CFX_DateTime dt =
2246 WideString::FromUTF8(bsDate), wsFormat, pLocale, pMgr)
2247 .GetDate();
2248
2249 return ByteString::Format("%4d-%02d-%02d", dt.GetYear(), dt.GetMonth(),
2250 dt.GetDay());
2251}
2252
2253// static
2254ByteString CFXJSE_FormCalcContext::IsoDate2Local(CFXJSE_HostObject* pThis,
2255 ByteStringView bsDate,
2256 ByteStringView bsFormat,
2257 ByteStringView bsLocale) {
2258 CXFA_Document* pDoc = ToFormCalcContext(pThis)->GetDocument();
2259 if (!pDoc)
2260 return ByteString();
2261
2262 CXFA_LocaleMgr* pMgr = pDoc->GetLocaleMgr();
2263 GCedLocaleIface* pLocale = LocaleFromString(pDoc, pMgr, bsLocale);
2264 if (!pLocale)
2265 return ByteString();
2266
2267 WideString wsFormat = FormatFromString(pLocale, bsFormat);
2268 WideString wsRet;
2270 WideString::FromUTF8(bsDate), pMgr)
2272 return wsRet.ToUTF8();
2273}
2274
2275// static
2276ByteString CFXJSE_FormCalcContext::IsoTime2Local(CFXJSE_HostObject* pThis,
2277 ByteStringView bsTime,
2278 ByteStringView bsFormat,
2279 ByteStringView bsLocale) {
2280 CXFA_Document* pDoc = ToFormCalcContext(pThis)->GetDocument();
2281 if (!pDoc)
2282 return ByteString();
2283
2284 CXFA_LocaleMgr* pMgr = pDoc->GetLocaleMgr();
2285 GCedLocaleIface* pLocale = LocaleFromString(pDoc, pMgr, bsLocale);
2286 if (!pLocale)
2287 return ByteString();
2288
2289 WideString wsFormat = {
2290 L"time{", FormatFromString(pLocale, bsFormat).AsStringView(), L"}"};
2292 WideString::FromUTF8(bsTime), pMgr);
2293 WideString wsRet;
2294 widgetValue.FormatPatterns(wsRet, wsFormat, pLocale,
2296 return wsRet.ToUTF8();
2297}
2298
2299// static
2300ByteString CFXJSE_FormCalcContext::GetLocalDateFormat(CFXJSE_HostObject* pThis,
2301 int32_t iStyle,
2302 ByteStringView bsLocale,
2303 bool bStandard) {
2304 CXFA_Document* pDoc = ToFormCalcContext(pThis)->GetDocument();
2305 if (!pDoc)
2306 return ByteString();
2307
2308 return GetLocalDateTimeFormat(pDoc, iStyle, bsLocale, bStandard,
2309 /*bIsDate=*/true);
2310}
2311
2312// static
2313ByteString CFXJSE_FormCalcContext::GetLocalTimeFormat(CFXJSE_HostObject* pThis,
2314 int32_t iStyle,
2315 ByteStringView bsLocale,
2316 bool bStandard) {
2317 CXFA_Document* pDoc = ToFormCalcContext(pThis)->GetDocument();
2318 if (!pDoc)
2319 return ByteString();
2320
2321 return GetLocalDateTimeFormat(pDoc, iStyle, bsLocale, bStandard,
2322 /*bIsDate=*/false);
2323}
2324
2325// static
2326ByteString CFXJSE_FormCalcContext::GetStandardDateFormat(
2327 CFXJSE_HostObject* pThis,
2328 int32_t iStyle,
2329 ByteStringView bsLocale) {
2330 return GetLocalDateFormat(pThis, iStyle, bsLocale, true);
2331}
2332
2333// static
2334ByteString CFXJSE_FormCalcContext::GetStandardTimeFormat(
2335 CFXJSE_HostObject* pThis,
2336 int32_t iStyle,
2337 ByteStringView bsLocale) {
2338 return GetLocalTimeFormat(pThis, iStyle, bsLocale, true);
2339}
2340
2341// static
2342ByteString CFXJSE_FormCalcContext::Num2AllTime(CFXJSE_HostObject* pThis,
2343 int32_t iTime,
2344 ByteStringView bsFormat,
2345 ByteStringView bsLocale,
2346 bool bGM) {
2347 int32_t iHour = 0;
2348 int32_t iMin = 0;
2349 int32_t iSec = 0;
2350 iHour = static_cast<int>(iTime) / 3600000;
2351 iMin = (static_cast<int>(iTime) - iHour * 3600000) / 60000;
2352 iSec = (static_cast<int>(iTime) - iHour * 3600000 - iMin * 60000) / 1000;
2353
2354 if (!bGM) {
2355 int32_t iZoneHour;
2356 int32_t iZoneMin;
2357 int32_t iZoneSec;
2358 GetLocalTimeZone(&iZoneHour, &iZoneMin, &iZoneSec);
2359 iHour += iZoneHour;
2360 iMin += iZoneMin;
2361 iSec += iZoneSec;
2362 }
2363
2364 return IsoTime2Local(
2365 pThis,
2366 ByteString::Format("%02d:%02d:%02d", iHour, iMin, iSec).AsStringView(),
2367 bsFormat, bsLocale);
2368}
2369
2370// static
2371void CFXJSE_FormCalcContext::Apr(
2372 CFXJSE_HostObject* pThis,
2373 const v8::FunctionCallbackInfo<v8::Value>& info) {
2374 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
2375 if (info.Length() != 3) {
2376 pContext->ThrowParamCountMismatchException("Apr");
2377 return;
2378 }
2379
2380 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
2381 v8::Local<v8::Value> argTwo = GetSimpleValue(info, 1);
2382 v8::Local<v8::Value> argThree = GetSimpleValue(info, 2);
2383 if (ValueIsNull(info.GetIsolate(), argOne) ||
2384 ValueIsNull(info.GetIsolate(), argTwo) ||
2385 ValueIsNull(info.GetIsolate(), argThree)) {
2386 info.GetReturnValue().SetNull();
2387 return;
2388 }
2389
2390 double nPrincipal = ValueToDouble(info.GetIsolate(), argOne);
2391 double nPayment = ValueToDouble(info.GetIsolate(), argTwo);
2392 int nPeriods = GetValidatedPaymentPeriods(info.GetIsolate(), argThree);
2393 if (nPrincipal <= 0 || nPayment <= 0 || nPeriods == 0) {
2394 pContext->ThrowArgumentMismatchException();
2395 return;
2396 }
2397
2398 double r = 2 * (nPeriods * nPayment - nPrincipal) / (nPeriods * nPrincipal);
2399 double nTemp = 1;
2400 for (int32_t i = 0; i < nPeriods; ++i)
2401 nTemp *= (1 + r);
2402
2403 double nRet = r * nTemp / (nTemp - 1) - nPayment / nPrincipal;
2404 while (fabs(nRet) > kFinancialPrecision) {
2405 double nDerivative =
2406 ((nTemp + r * nPeriods * (nTemp / (1 + r))) * (nTemp - 1) -
2407 (r * nTemp * nPeriods * (nTemp / (1 + r)))) /
2408 ((nTemp - 1) * (nTemp - 1));
2409 if (nDerivative == 0) {
2410 info.GetReturnValue().SetNull();
2411 return;
2412 }
2413
2414 r = r - nRet / nDerivative;
2415 nTemp = 1;
2416 for (int32_t i = 0; i < nPeriods; ++i) {
2417 nTemp *= (1 + r);
2418 }
2419 nRet = r * nTemp / (nTemp - 1) - nPayment / nPrincipal;
2420 }
2421 info.GetReturnValue().Set(r * 12);
2422}
2423
2424// static
2425void CFXJSE_FormCalcContext::CTerm(
2426 CFXJSE_HostObject* pThis,
2427 const v8::FunctionCallbackInfo<v8::Value>& info) {
2428 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
2429 if (info.Length() != 3) {
2430 pContext->ThrowParamCountMismatchException("CTerm");
2431 return;
2432 }
2433
2434 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
2435 v8::Local<v8::Value> argTwo = GetSimpleValue(info, 1);
2436 v8::Local<v8::Value> argThree = GetSimpleValue(info, 2);
2437 if (ValueIsNull(info.GetIsolate(), argOne) ||
2438 ValueIsNull(info.GetIsolate(), argTwo) ||
2439 ValueIsNull(info.GetIsolate(), argThree)) {
2440 info.GetReturnValue().SetNull();
2441 return;
2442 }
2443
2444 float nRate = ValueToFloat(info.GetIsolate(), argOne);
2445 float nFutureValue = ValueToFloat(info.GetIsolate(), argTwo);
2446 float nInitAmount = ValueToFloat(info.GetIsolate(), argThree);
2447 if ((nRate <= 0) || (nFutureValue <= 0) || (nInitAmount <= 0)) {
2448 pContext->ThrowArgumentMismatchException();
2449 return;
2450 }
2451
2452 info.GetReturnValue().Set(log((float)(nFutureValue / nInitAmount)) /
2453 log((float)(1 + nRate)));
2454}
2455
2456// static
2457void CFXJSE_FormCalcContext::FV(
2458 CFXJSE_HostObject* pThis,
2459 const v8::FunctionCallbackInfo<v8::Value>& info) {
2460 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
2461 if (info.Length() != 3) {
2462 pContext->ThrowParamCountMismatchException("FV");
2463 return;
2464 }
2465
2466 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
2467 v8::Local<v8::Value> argTwo = GetSimpleValue(info, 1);
2468 v8::Local<v8::Value> argThree = GetSimpleValue(info, 2);
2469 if (ValueIsNull(info.GetIsolate(), argOne) ||
2470 ValueIsNull(info.GetIsolate(), argTwo) ||
2471 ValueIsNull(info.GetIsolate(), argThree)) {
2472 info.GetReturnValue().SetNull();
2473 return;
2474 }
2475
2476 double nAmount = ValueToDouble(info.GetIsolate(), argOne);
2477 double nRate = ValueToDouble(info.GetIsolate(), argTwo);
2478 int nPeriods = GetValidatedPaymentPeriods(info.GetIsolate(), argThree);
2479 if (nAmount <= 0 || nRate < 0 || nPeriods == 0) {
2480 pContext->ThrowArgumentMismatchException();
2481 return;
2482 }
2483
2484 double dResult = 0;
2485 if (nRate) {
2486 double nTemp = 1;
2487 for (int i = 0; i < nPeriods; ++i) {
2488 nTemp *= 1 + nRate;
2489 }
2490 dResult = nAmount * (nTemp - 1) / nRate;
2491 } else {
2492 dResult = nAmount * nPeriods;
2493 }
2494
2495 info.GetReturnValue().Set(dResult);
2496}
2497
2498// static
2499void CFXJSE_FormCalcContext::IPmt(
2500 CFXJSE_HostObject* pThis,
2501 const v8::FunctionCallbackInfo<v8::Value>& info) {
2502 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
2503 if (info.Length() != 5) {
2504 pContext->ThrowParamCountMismatchException("IPmt");
2505 return;
2506 }
2507
2508 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
2509 v8::Local<v8::Value> argTwo = GetSimpleValue(info, 1);
2510 v8::Local<v8::Value> argThree = GetSimpleValue(info, 2);
2511 v8::Local<v8::Value> argFour = GetSimpleValue(info, 3);
2512 v8::Local<v8::Value> argFive = GetSimpleValue(info, 4);
2513 if (ValueIsNull(info.GetIsolate(), argOne) ||
2514 ValueIsNull(info.GetIsolate(), argTwo) ||
2515 ValueIsNull(info.GetIsolate(), argThree) ||
2516 ValueIsNull(info.GetIsolate(), argFour) ||
2517 ValueIsNull(info.GetIsolate(), argFive)) {
2518 info.GetReturnValue().SetNull();
2519 return;
2520 }
2521
2522 float nPrincipalAmount = ValueToFloat(info.GetIsolate(), argOne);
2523 float nRate = ValueToFloat(info.GetIsolate(), argTwo);
2524 float nPayment = ValueToFloat(info.GetIsolate(), argThree);
2525 float nFirstMonth = ValueToFloat(info.GetIsolate(), argFour);
2526 float nNumberOfMonths = ValueToFloat(info.GetIsolate(), argFive);
2527 if ((nPrincipalAmount <= 0) || (nRate <= 0) || (nPayment <= 0) ||
2528 (nFirstMonth < 0) || (nNumberOfMonths < 0)) {
2529 pContext->ThrowArgumentMismatchException();
2530 return;
2531 }
2532
2533 float nRateOfMonth = nRate / 12;
2534 int32_t iNums = static_cast<int32_t>(
2535 (log10((float)(nPayment / nPrincipalAmount)) -
2536 log10((float)(nPayment / nPrincipalAmount - nRateOfMonth))) /
2537 log10((float)(1 + nRateOfMonth)));
2538 int32_t iEnd =
2539 std::min(static_cast<int32_t>(nFirstMonth + nNumberOfMonths - 1), iNums);
2540
2541 if (nPayment < nPrincipalAmount * nRateOfMonth) {
2542 info.GetReturnValue().Set(0);
2543 return;
2544 }
2545
2546 int32_t i = 0;
2547 for (i = 0; i < nFirstMonth - 1; ++i)
2548 nPrincipalAmount -= nPayment - nPrincipalAmount * nRateOfMonth;
2549
2550 float nSum = 0;
2551 for (; i < iEnd; ++i) {
2552 nSum += nPrincipalAmount * nRateOfMonth;
2553 nPrincipalAmount -= nPayment - nPrincipalAmount * nRateOfMonth;
2554 }
2555 info.GetReturnValue().Set(nSum);
2556}
2557
2558// static
2559void CFXJSE_FormCalcContext::NPV(
2560 CFXJSE_HostObject* pThis,
2561 const v8::FunctionCallbackInfo<v8::Value>& info) {
2562 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
2563 int32_t argc = info.Length();
2564 if (argc < 2) {
2565 pContext->ThrowParamCountMismatchException("NPV");
2566 return;
2567 }
2568
2569 v8::Local<v8::Value> argValue = GetSimpleValue(info, 0);
2570 if (ValueIsNull(info.GetIsolate(), argValue)) {
2571 info.GetReturnValue().SetNull();
2572 return;
2573 }
2574
2575 double nRate = ValueToDouble(info.GetIsolate(), argValue);
2576 if (nRate <= 0) {
2577 pContext->ThrowArgumentMismatchException();
2578 return;
2579 }
2580
2581 std::vector<double> data;
2582 for (int32_t i = 1; i < argc; i++) {
2583 argValue = GetSimpleValue(info, i);
2584 if (ValueIsNull(info.GetIsolate(), argValue)) {
2585 info.GetReturnValue().SetNull();
2586 return;
2587 }
2588 data.push_back(ValueToDouble(info.GetIsolate(), argValue));
2589 }
2590
2591 double nSum = 0;
2592 double nDivisor = 1.0 + nRate;
2593 while (!data.empty()) {
2594 nSum += data.back();
2595 nSum /= nDivisor;
2596 data.pop_back();
2597 }
2598 info.GetReturnValue().Set(nSum);
2599}
2600
2601// static
2602void CFXJSE_FormCalcContext::Pmt(
2603 CFXJSE_HostObject* pThis,
2604 const v8::FunctionCallbackInfo<v8::Value>& info) {
2605 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
2606 if (info.Length() != 3) {
2607 pContext->ThrowParamCountMismatchException("Pmt");
2608 return;
2609 }
2610
2611 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
2612 v8::Local<v8::Value> argTwo = GetSimpleValue(info, 1);
2613 v8::Local<v8::Value> argThree = GetSimpleValue(info, 2);
2614 if (ValueIsNull(info.GetIsolate(), argOne) ||
2615 ValueIsNull(info.GetIsolate(), argTwo) ||
2616 ValueIsNull(info.GetIsolate(), argThree)) {
2617 info.GetReturnValue().SetNull();
2618 return;
2619 }
2620
2621 double nPrincipal = ValueToDouble(info.GetIsolate(), argOne);
2622 double nRate = ValueToDouble(info.GetIsolate(), argTwo);
2623 int nPeriods = GetValidatedPaymentPeriods(info.GetIsolate(), argThree);
2624 if (nPrincipal <= 0 || nRate <= 0 || nPeriods == 0) {
2625 pContext->ThrowArgumentMismatchException();
2626 return;
2627 }
2628
2629 double nSum = pow(1.0 + nRate, nPeriods);
2630 info.GetReturnValue().Set((nPrincipal * nRate * nSum) / (nSum - 1));
2631}
2632
2633// static
2634void CFXJSE_FormCalcContext::PPmt(
2635 CFXJSE_HostObject* pThis,
2636 const v8::FunctionCallbackInfo<v8::Value>& info) {
2637 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
2638 if (info.Length() != 5) {
2639 pContext->ThrowParamCountMismatchException("PPmt");
2640 return;
2641 }
2642
2643 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
2644 v8::Local<v8::Value> argTwo = GetSimpleValue(info, 1);
2645 v8::Local<v8::Value> argThree = GetSimpleValue(info, 2);
2646 v8::Local<v8::Value> argFour = GetSimpleValue(info, 3);
2647 v8::Local<v8::Value> argFive = GetSimpleValue(info, 4);
2648 if (ValueIsNull(info.GetIsolate(), argOne) ||
2649 ValueIsNull(info.GetIsolate(), argTwo) ||
2650 ValueIsNull(info.GetIsolate(), argThree) ||
2651 ValueIsNull(info.GetIsolate(), argFour) ||
2652 ValueIsNull(info.GetIsolate(), argFive)) {
2653 info.GetReturnValue().SetNull();
2654 return;
2655 }
2656
2657 float nPrincipalAmount = ValueToFloat(info.GetIsolate(), argOne);
2658 float nRate = ValueToFloat(info.GetIsolate(), argTwo);
2659 float nPayment = ValueToFloat(info.GetIsolate(), argThree);
2660 float nFirstMonth = ValueToFloat(info.GetIsolate(), argFour);
2661 float nNumberOfMonths = ValueToFloat(info.GetIsolate(), argFive);
2662 if ((nPrincipalAmount <= 0) || (nRate <= 0) || (nPayment <= 0) ||
2663 (nFirstMonth < 0) || (nNumberOfMonths < 0)) {
2664 pContext->ThrowArgumentMismatchException();
2665 return;
2666 }
2667
2668 float nRateOfMonth = nRate / 12;
2669 int32_t iNums = static_cast<int32_t>(
2670 (log10((float)(nPayment / nPrincipalAmount)) -
2671 log10((float)(nPayment / nPrincipalAmount - nRateOfMonth))) /
2672 log10((float)(1 + nRateOfMonth)));
2673 int32_t iEnd =
2674 std::min(static_cast<int32_t>(nFirstMonth + nNumberOfMonths - 1), iNums);
2675 if (nPayment < nPrincipalAmount * nRateOfMonth) {
2676 pContext->ThrowArgumentMismatchException();
2677 return;
2678 }
2679
2680 int32_t i = 0;
2681 for (i = 0; i < nFirstMonth - 1; ++i)
2682 nPrincipalAmount -= nPayment - nPrincipalAmount * nRateOfMonth;
2683
2684 float nTemp = 0;
2685 float nSum = 0;
2686 for (; i < iEnd; ++i) {
2687 nTemp = nPayment - nPrincipalAmount * nRateOfMonth;
2688 nSum += nTemp;
2689 nPrincipalAmount -= nTemp;
2690 }
2691 info.GetReturnValue().Set(nSum);
2692}
2693
2694// static
2695void CFXJSE_FormCalcContext::PV(
2696 CFXJSE_HostObject* pThis,
2697 const v8::FunctionCallbackInfo<v8::Value>& info) {
2698 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
2699 if (info.Length() != 3) {
2700 pContext->ThrowParamCountMismatchException("PV");
2701 return;
2702 }
2703
2704 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
2705 v8::Local<v8::Value> argTwo = GetSimpleValue(info, 1);
2706 v8::Local<v8::Value> argThree = GetSimpleValue(info, 2);
2707 if (ValueIsNull(info.GetIsolate(), argOne) ||
2708 ValueIsNull(info.GetIsolate(), argTwo) ||
2709 ValueIsNull(info.GetIsolate(), argThree)) {
2710 info.GetReturnValue().SetNull();
2711 return;
2712 }
2713
2714 double nAmount = ValueToDouble(info.GetIsolate(), argOne);
2715 double nRate = ValueToDouble(info.GetIsolate(), argTwo);
2716 int nPeriods = GetValidatedPaymentPeriods(info.GetIsolate(), argThree);
2717 if (nAmount <= 0 || nRate < 0 || nPeriods == 0) {
2718 pContext->ThrowArgumentMismatchException();
2719 return;
2720 }
2721
2722 double nTemp = 1 / pow(1.0 + nRate, nPeriods);
2723 info.GetReturnValue().Set(nAmount * ((1.0 - nTemp) / nRate));
2724}
2725
2726// static
2727void CFXJSE_FormCalcContext::Rate(
2728 CFXJSE_HostObject* pThis,
2729 const v8::FunctionCallbackInfo<v8::Value>& info) {
2730 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
2731 if (info.Length() != 3) {
2732 pContext->ThrowParamCountMismatchException("Rate");
2733 return;
2734 }
2735
2736 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
2737 v8::Local<v8::Value> argTwo = GetSimpleValue(info, 1);
2738 v8::Local<v8::Value> argThree = GetSimpleValue(info, 2);
2739 if (ValueIsNull(info.GetIsolate(), argOne) ||
2740 ValueIsNull(info.GetIsolate(), argTwo) ||
2741 ValueIsNull(info.GetIsolate(), argThree)) {
2742 info.GetReturnValue().SetNull();
2743 return;
2744 }
2745
2746 float nFuture = ValueToFloat(info.GetIsolate(), argOne);
2747 float nPresent = ValueToFloat(info.GetIsolate(), argTwo);
2748 int nPeriods = GetValidatedPaymentPeriods(info.GetIsolate(), argThree);
2749 if (nFuture <= 0 || nPresent < 0 || nPeriods == 0) {
2750 pContext->ThrowArgumentMismatchException();
2751 return;
2752 }
2753
2754 info.GetReturnValue().Set(powf(nFuture / nPresent, 1.0f / nPeriods) - 1.0f);
2755}
2756
2757// static
2758void CFXJSE_FormCalcContext::Term(
2759 CFXJSE_HostObject* pThis,
2760 const v8::FunctionCallbackInfo<v8::Value>& info) {
2761 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
2762 if (info.Length() != 3) {
2763 pContext->ThrowParamCountMismatchException("Term");
2764 return;
2765 }
2766
2767 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
2768 v8::Local<v8::Value> argTwo = GetSimpleValue(info, 1);
2769 v8::Local<v8::Value> argThree = GetSimpleValue(info, 2);
2770 if (ValueIsNull(info.GetIsolate(), argOne) ||
2771 ValueIsNull(info.GetIsolate(), argTwo) ||
2772 ValueIsNull(info.GetIsolate(), argThree)) {
2773 info.GetReturnValue().SetNull();
2774 return;
2775 }
2776
2777 float nMount = ValueToFloat(info.GetIsolate(), argOne);
2778 float nRate = ValueToFloat(info.GetIsolate(), argTwo);
2779 float nFuture = ValueToFloat(info.GetIsolate(), argThree);
2780 if ((nMount <= 0) || (nRate <= 0) || (nFuture <= 0)) {
2781 pContext->ThrowArgumentMismatchException();
2782 return;
2783 }
2784
2785 info.GetReturnValue().Set(log((float)(nFuture / nMount * nRate) + 1) /
2786 log((float)(1 + nRate)));
2787}
2788
2789// static
2790void CFXJSE_FormCalcContext::Choose(
2791 CFXJSE_HostObject* pThis,
2792 const v8::FunctionCallbackInfo<v8::Value>& info) {
2793 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
2794 int32_t argc = info.Length();
2795 if (argc < 2) {
2796 pContext->ThrowParamCountMismatchException("Choose");
2797 return;
2798 }
2799
2800 if (ValueIsNull(info.GetIsolate(), info[0])) {
2801 info.GetReturnValue().SetNull();
2802 return;
2803 }
2804
2805 int32_t iIndex =
2806 static_cast<int32_t>(ValueToFloat(info.GetIsolate(), info[0]));
2807 if (iIndex < 1) {
2808 info.GetReturnValue().SetEmptyString();
2809 return;
2810 }
2811
2812 bool bFound = false;
2813 bool bStopCounterFlags = false;
2814 int32_t iArgIndex = 1;
2815 int32_t iValueIndex = 0;
2816 while (!bFound && !bStopCounterFlags && (iArgIndex < argc)) {
2817 v8::Local<v8::Value> argIndexValue = info[iArgIndex];
2818 if (fxv8::IsArray(argIndexValue)) {
2819 v8::Local<v8::Array> arr = argIndexValue.As<v8::Array>();
2820 uint32_t iLength = fxv8::GetArrayLengthHelper(arr);
2821 if (iLength > 3)
2822 bStopCounterFlags = true;
2823
2824 iValueIndex += (iLength - 2);
2825 if (iValueIndex >= iIndex) {
2826 v8::Local<v8::Value> propertyValue =
2827 fxv8::ReentrantGetArrayElementHelper(info.GetIsolate(), arr, 1);
2828 v8::Local<v8::Value> jsValue = fxv8::ReentrantGetArrayElementHelper(
2829 info.GetIsolate(), arr, (iLength - 1) - (iValueIndex - iIndex));
2830 v8::Local<v8::Value> newPropertyValue;
2831 if (fxv8::IsObject(jsValue)) {
2832 v8::Local<v8::Object> jsObjectValue = jsValue.As<v8::Object>();
2833 if (fxv8::IsNull(propertyValue)) {
2834 newPropertyValue =
2835 GetObjectDefaultValue(info.GetIsolate(), jsObjectValue);
2836 } else {
2837 ByteString bsName = fxv8::ReentrantToByteStringHelper(
2838 info.GetIsolate(), propertyValue);
2839 newPropertyValue = fxv8::ReentrantGetObjectPropertyHelper(
2840 info.GetIsolate(), jsObjectValue, bsName.AsStringView());
2841 }
2842 }
2843 ByteString bsChosen =
2844 ValueToUTF8String(info.GetIsolate(), newPropertyValue);
2845 info.GetReturnValue().Set(
2846 fxv8::NewStringHelper(info.GetIsolate(), bsChosen.AsStringView()));
2847 bFound = true;
2848 }
2849 } else {
2850 iValueIndex++;
2851 if (iValueIndex == iIndex) {
2852 ByteString bsChosen =
2853 ValueToUTF8String(info.GetIsolate(), argIndexValue);
2854 info.GetReturnValue().Set(
2855 fxv8::NewStringHelper(info.GetIsolate(), bsChosen.AsStringView()));
2856 bFound = true;
2857 }
2858 }
2859 iArgIndex++;
2860 }
2861 if (!bFound)
2862 info.GetReturnValue().SetEmptyString();
2863}
2864
2865// static
2866void CFXJSE_FormCalcContext::Exists(
2867 CFXJSE_HostObject* pThis,
2868 const v8::FunctionCallbackInfo<v8::Value>& info) {
2869 if (info.Length() != 1) {
2870 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Exists");
2871 return;
2872 }
2873 info.GetReturnValue().Set(fxv8::IsObject(info[0]));
2874}
2875
2876// static
2877void CFXJSE_FormCalcContext::HasValue(
2878 CFXJSE_HostObject* pThis,
2879 const v8::FunctionCallbackInfo<v8::Value>& info) {
2880 if (info.Length() != 1) {
2881 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("HasValue");
2882 return;
2883 }
2884
2885 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
2886 if (!fxv8::IsString(argOne)) {
2887 info.GetReturnValue().Set(
2888 static_cast<int>(fxv8::IsNumber(argOne) || fxv8::IsBoolean(argOne)));
2889 return;
2890 }
2891
2892 ByteString bsValue =
2893 fxv8::ReentrantToByteStringHelper(info.GetIsolate(), argOne);
2894 bsValue.TrimLeft();
2895 info.GetReturnValue().Set(static_cast<int>(!bsValue.IsEmpty()));
2896}
2897
2898// static
2899void CFXJSE_FormCalcContext::Oneof(
2900 CFXJSE_HostObject* pThis,
2901 const v8::FunctionCallbackInfo<v8::Value>& info) {
2902 if (info.Length() < 2) {
2903 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Oneof");
2904 return;
2905 }
2906
2907 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
2908 for (const auto& value : UnfoldArgs(info)) {
2909 if (SimpleValueCompare(info.GetIsolate(), argOne, value)) {
2910 info.GetReturnValue().Set(1);
2911 return;
2912 }
2913 }
2914 info.GetReturnValue().Set(0);
2915}
2916
2917// static
2918void CFXJSE_FormCalcContext::Within(
2919 CFXJSE_HostObject* pThis,
2920 const v8::FunctionCallbackInfo<v8::Value>& info) {
2921 if (info.Length() != 3) {
2922 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Within");
2923 return;
2924 }
2925
2926 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
2927 if (fxv8::IsNull(argOne)) {
2928 info.GetReturnValue().SetUndefined();
2929 return;
2930 }
2931
2932 v8::Local<v8::Value> argLow = GetSimpleValue(info, 1);
2933 v8::Local<v8::Value> argHigh = GetSimpleValue(info, 2);
2934 if (fxv8::IsNumber(argOne)) {
2935 float oneNumber = ValueToFloat(info.GetIsolate(), argOne);
2936 float lowNumber = ValueToFloat(info.GetIsolate(), argLow);
2937 float heightNumber = ValueToFloat(info.GetIsolate(), argHigh);
2938 info.GetReturnValue().Set(static_cast<int>((oneNumber >= lowNumber) &&
2939 (oneNumber <= heightNumber)));
2940 return;
2941 }
2942
2943 ByteString bsOne = ValueToUTF8String(info.GetIsolate(), argOne);
2944 ByteString bsLow = ValueToUTF8String(info.GetIsolate(), argLow);
2945 ByteString bsHeight = ValueToUTF8String(info.GetIsolate(), argHigh);
2946 info.GetReturnValue().Set(
2947 static_cast<int>((bsOne.Compare(bsLow.AsStringView()) >= 0) &&
2948 (bsOne.Compare(bsHeight.AsStringView()) <= 0)));
2949}
2950
2951// static
2952void CFXJSE_FormCalcContext::If(
2953 CFXJSE_HostObject* pThis,
2954 const v8::FunctionCallbackInfo<v8::Value>& info) {
2955 if (info.Length() != 3) {
2956 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("If");
2957 return;
2958 }
2959
2960 const bool condition = fxv8::ReentrantToBooleanHelper(
2961 info.GetIsolate(), GetSimpleValue(info, 0));
2962
2963 info.GetReturnValue().Set(GetSimpleValue(info, condition ? 1 : 2));
2964}
2965
2966// static
2967void CFXJSE_FormCalcContext::Eval(
2968 CFXJSE_HostObject* pThis,
2969 const v8::FunctionCallbackInfo<v8::Value>& info) {
2970 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
2971 if (info.Length() != 1) {
2972 pContext->ThrowParamCountMismatchException("Eval");
2973 return;
2974 }
2975
2976 v8::Isolate* pIsolate = pContext->GetIsolate();
2977 v8::Local<v8::Value> scriptValue = GetSimpleValue(info, 0);
2978 ByteString bsUtf8Script = ValueToUTF8String(info.GetIsolate(), scriptValue);
2979 if (bsUtf8Script.IsEmpty()) {
2980 info.GetReturnValue().SetNull();
2981 return;
2982 }
2983
2984 WideString wsCalcScript = WideString::FromUTF8(bsUtf8Script.AsStringView());
2985 absl::optional<WideTextBuffer> wsJavaScriptBuf =
2986 CFXJSE_FormCalcContext::Translate(pContext->GetDocument()->GetHeap(),
2987 wsCalcScript.AsStringView());
2988 if (!wsJavaScriptBuf.has_value()) {
2989 pContext->ThrowCompilerErrorException();
2990 return;
2991 }
2992 std::unique_ptr<CFXJSE_Context> pNewContext =
2993 CFXJSE_Context::Create(pIsolate, nullptr, nullptr, nullptr);
2994
2995 ByteString bsScript = FX_UTF8Encode(wsJavaScriptBuf.value().AsStringView());
2996 CFXJSE_Context::ExecutionResult result = pNewContext->ExecuteScript(
2997 bsScript.AsStringView(), v8::Local<v8::Object>());
2998
2999 info.GetReturnValue().Set(result.value->DirectGetValue());
3000}
3001
3002// static
3003void CFXJSE_FormCalcContext::Ref(
3004 CFXJSE_HostObject* pThis,
3005 const v8::FunctionCallbackInfo<v8::Value>& info) {
3006 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
3007 if (info.Length() != 1) {
3008 pContext->ThrowParamCountMismatchException("Ref");
3009 return;
3010 }
3011
3012 v8::Local<v8::Value> argOne = info[0];
3013 if (fxv8::IsBoolean(argOne) || fxv8::IsString(argOne) ||
3014 fxv8::IsNumber(argOne)) {
3015 info.GetReturnValue().Set(argOne);
3016 return;
3017 }
3018
3019 v8::LocalVector<v8::Value> values(info.GetIsolate(), 3);
3020 int intVal = 3;
3021 if (fxv8::IsNull(argOne)) {
3022 // TODO(dsinclair): Why is this 4 when the others are all 3?
3023 intVal = 4;
3024 values[2] = fxv8::NewNullHelper(info.GetIsolate());
3025 } else if (fxv8::IsArray(argOne)) {
3026 v8::Local<v8::Array> arr = argOne.As<v8::Array>();
3027 v8::Local<v8::Value> propertyValue =
3028 fxv8::ReentrantGetArrayElementHelper(info.GetIsolate(), arr, 1);
3029 v8::Local<v8::Value> jsObjectValue =
3030 fxv8::ReentrantGetArrayElementHelper(info.GetIsolate(), arr, 2);
3031 if (!fxv8::IsNull(propertyValue) || fxv8::IsNull(jsObjectValue)) {
3032 pContext->ThrowArgumentMismatchException();
3033 return;
3034 }
3035 values[2] = jsObjectValue;
3036 } else if (fxv8::IsObject(argOne)) {
3037 values[2] = argOne;
3038 } else {
3039 pContext->ThrowArgumentMismatchException();
3040 return;
3041 }
3042
3043 values[0] = fxv8::NewNumberHelper(info.GetIsolate(), intVal);
3044 values[1] = fxv8::NewNullHelper(info.GetIsolate());
3045 info.GetReturnValue().Set(fxv8::NewArrayHelper(info.GetIsolate(), values));
3046}
3047
3048// static
3049void CFXJSE_FormCalcContext::UnitType(
3050 CFXJSE_HostObject* pThis,
3051 const v8::FunctionCallbackInfo<v8::Value>& info) {
3052 if (info.Length() != 1) {
3053 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("UnitType");
3054 return;
3055 }
3056
3057 v8::Local<v8::Value> unitspanValue = GetSimpleValue(info, 0);
3058 if (fxv8::IsNull(unitspanValue)) {
3059 info.GetReturnValue().SetNull();
3060 return;
3061 }
3062
3063 ByteString bsUnitspan = ValueToUTF8String(info.GetIsolate(), unitspanValue);
3064 if (bsUnitspan.IsEmpty()) {
3065 info.GetReturnValue().SetEmptyString();
3066 return;
3067 }
3068
3069 enum XFA_FormCalc_VALUETYPE_ParserStatus {
3070 VALUETYPE_START,
3071 VALUETYPE_HAVEINVALIDCHAR,
3072 VALUETYPE_HAVEDIGIT,
3073 VALUETYPE_HAVEDIGITWHITE,
3074 VALUETYPE_ISCM,
3075 VALUETYPE_ISMM,
3076 VALUETYPE_ISPT,
3077 VALUETYPE_ISMP,
3078 VALUETYPE_ISIN,
3079 };
3080 bsUnitspan.MakeLower();
3081 WideString wsType = WideString::FromUTF8(bsUnitspan.AsStringView());
3082 const wchar_t* pData = wsType.c_str();
3083 int32_t u = 0;
3084 int32_t uLen = wsType.GetLength();
3085 while (IsWhitespace(pData[u]))
3086 u++;
3087
3088 XFA_FormCalc_VALUETYPE_ParserStatus eParserStatus = VALUETYPE_START;
3089 wchar_t typeChar;
3090 // TODO(dsinclair): Cleanup this parser, figure out what the various checks
3091 // are for.
3092 while (u < uLen) {
3093 typeChar = pData[u];
3094 if (IsWhitespace(typeChar)) {
3095 if (eParserStatus != VALUETYPE_HAVEDIGIT &&
3096 eParserStatus != VALUETYPE_HAVEDIGITWHITE) {
3097 eParserStatus = VALUETYPE_ISIN;
3098 break;
3099 }
3100 eParserStatus = VALUETYPE_HAVEDIGITWHITE;
3101 } else if (IsPartOfNumberW(typeChar)) {
3102 if (eParserStatus == VALUETYPE_HAVEDIGITWHITE) {
3103 eParserStatus = VALUETYPE_ISIN;
3104 break;
3105 }
3106 eParserStatus = VALUETYPE_HAVEDIGIT;
3107 } else if ((typeChar == 'c' || typeChar == 'p') && (u + 1 < uLen)) {
3108 wchar_t nextChar = pData[u + 1];
3109 if ((eParserStatus == VALUETYPE_START ||
3110 eParserStatus == VALUETYPE_HAVEDIGIT ||
3111 eParserStatus == VALUETYPE_HAVEDIGITWHITE) &&
3112 !IsPartOfNumberW(nextChar)) {
3113 eParserStatus = (typeChar == 'c') ? VALUETYPE_ISCM : VALUETYPE_ISPT;
3114 break;
3115 }
3116 eParserStatus = VALUETYPE_HAVEINVALIDCHAR;
3117 } else if (typeChar == 'm' && (u + 1 < uLen)) {
3118 wchar_t nextChar = pData[u + 1];
3119 if ((eParserStatus == VALUETYPE_START ||
3120 eParserStatus == VALUETYPE_HAVEDIGIT ||
3121 eParserStatus == VALUETYPE_HAVEDIGITWHITE) &&
3122 !IsPartOfNumberW(nextChar)) {
3123 eParserStatus = VALUETYPE_ISMM;
3124 if (nextChar == 'p' || ((u + 5 < uLen) && pData[u + 1] == 'i' &&
3125 pData[u + 2] == 'l' && pData[u + 3] == 'l' &&
3126 pData[u + 4] == 'i' && pData[u + 5] == 'p')) {
3127 eParserStatus = VALUETYPE_ISMP;
3128 }
3129 break;
3130 }
3131 } else {
3132 eParserStatus = VALUETYPE_HAVEINVALIDCHAR;
3133 }
3134 u++;
3135 }
3136 switch (eParserStatus) {
3137 case VALUETYPE_ISCM:
3138 info.GetReturnValue().Set(fxv8::NewStringHelper(info.GetIsolate(), "cm"));
3139 break;
3140 case VALUETYPE_ISMM:
3141 info.GetReturnValue().Set(fxv8::NewStringHelper(info.GetIsolate(), "mm"));
3142 break;
3143 case VALUETYPE_ISPT:
3144 info.GetReturnValue().Set(fxv8::NewStringHelper(info.GetIsolate(), "pt"));
3145 break;
3146 case VALUETYPE_ISMP:
3147 info.GetReturnValue().Set(fxv8::NewStringHelper(info.GetIsolate(), "mp"));
3148 break;
3149 default:
3150 info.GetReturnValue().Set(fxv8::NewStringHelper(info.GetIsolate(), "in"));
3151 break;
3152 }
3153}
3154
3155// static
3156void CFXJSE_FormCalcContext::UnitValue(
3157 CFXJSE_HostObject* pThis,
3158 const v8::FunctionCallbackInfo<v8::Value>& info) {
3159 int32_t argc = info.Length();
3160 if (argc < 1 || argc > 2) {
3161 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("UnitValue");
3162 return;
3163 }
3164
3165 v8::Local<v8::Value> unitspanValue = GetSimpleValue(info, 0);
3166 if (fxv8::IsNull(unitspanValue)) {
3167 info.GetReturnValue().SetNull();
3168 return;
3169 }
3170
3171 ByteString bsUnitspan = ValueToUTF8String(info.GetIsolate(), unitspanValue);
3172 const char* pData = bsUnitspan.c_str();
3173 if (!pData) {
3174 info.GetReturnValue().Set(0);
3175 return;
3176 }
3177
3178 size_t u = 0;
3179 while (IsWhitespace(pData[u]))
3180 ++u;
3181
3182 while (u < bsUnitspan.GetLength()) {
3183 if (!IsPartOfNumber(pData[u]))
3184 break;
3185 ++u;
3186 }
3187
3188 char* pTemp = nullptr;
3189 double dFirstNumber = strtod(pData, &pTemp);
3190 while (IsWhitespace(pData[u]))
3191 ++u;
3192
3193 size_t uLen = bsUnitspan.GetLength();
3194 ByteString bsFirstUnit;
3195 while (u < uLen) {
3196 if (pData[u] == ' ')
3197 break;
3198
3199 bsFirstUnit += pData[u];
3200 ++u;
3201 }
3202 bsFirstUnit.MakeLower();
3203
3204 ByteString bsUnit;
3205 if (argc > 1) {
3206 v8::Local<v8::Value> unitValue = GetSimpleValue(info, 1);
3207 ByteString bsUnitTemp = ValueToUTF8String(info.GetIsolate(), unitValue);
3208 const char* pChar = bsUnitTemp.c_str();
3209 size_t uVal = 0;
3210 while (IsWhitespace(pChar[uVal]))
3211 ++uVal;
3212
3213 while (uVal < bsUnitTemp.GetLength()) {
3214 if (!isdigit(pChar[uVal]) && pChar[uVal] != '.')
3215 break;
3216 ++uVal;
3217 }
3218 while (IsWhitespace(pChar[uVal]))
3219 ++uVal;
3220
3221 size_t uValLen = bsUnitTemp.GetLength();
3222 while (uVal < uValLen) {
3223 if (pChar[uVal] == ' ')
3224 break;
3225
3226 bsUnit += pChar[uVal];
3227 ++uVal;
3228 }
3229 bsUnit.MakeLower();
3230 } else {
3231 bsUnit = bsFirstUnit;
3232 }
3233
3234 double dResult = 0;
3235 if (bsFirstUnit == "in" || bsFirstUnit == "inches") {
3236 if (bsUnit == "mm" || bsUnit == "millimeters")
3237 dResult = dFirstNumber * 25.4;
3238 else if (bsUnit == "cm" || bsUnit == "centimeters")
3239 dResult = dFirstNumber * 2.54;
3240 else if (bsUnit == "pt" || bsUnit == "points")
3241 dResult = dFirstNumber / 72;
3242 else if (bsUnit == "mp" || bsUnit == "millipoints")
3243 dResult = dFirstNumber / 72000;
3244 else
3245 dResult = dFirstNumber;
3246 } else if (bsFirstUnit == "mm" || bsFirstUnit == "millimeters") {
3247 if (bsUnit == "mm" || bsUnit == "millimeters")
3248 dResult = dFirstNumber;
3249 else if (bsUnit == "cm" || bsUnit == "centimeters")
3250 dResult = dFirstNumber / 10;
3251 else if (bsUnit == "pt" || bsUnit == "points")
3252 dResult = dFirstNumber / 25.4 / 72;
3253 else if (bsUnit == "mp" || bsUnit == "millipoints")
3254 dResult = dFirstNumber / 25.4 / 72000;
3255 else
3256 dResult = dFirstNumber / 25.4;
3257 } else if (bsFirstUnit == "cm" || bsFirstUnit == "centimeters") {
3258 if (bsUnit == "mm" || bsUnit == "millimeters")
3259 dResult = dFirstNumber * 10;
3260 else if (bsUnit == "cm" || bsUnit == "centimeters")
3261 dResult = dFirstNumber;
3262 else if (bsUnit == "pt" || bsUnit == "points")
3263 dResult = dFirstNumber / 2.54 / 72;
3264 else if (bsUnit == "mp" || bsUnit == "millipoints")
3265 dResult = dFirstNumber / 2.54 / 72000;
3266 else
3267 dResult = dFirstNumber / 2.54;
3268 } else if (bsFirstUnit == "pt" || bsFirstUnit == "points") {
3269 if (bsUnit == "mm" || bsUnit == "millimeters")
3270 dResult = dFirstNumber / 72 * 25.4;
3271 else if (bsUnit == "cm" || bsUnit == "centimeters")
3272 dResult = dFirstNumber / 72 * 2.54;
3273 else if (bsUnit == "pt" || bsUnit == "points")
3274 dResult = dFirstNumber;
3275 else if (bsUnit == "mp" || bsUnit == "millipoints")
3276 dResult = dFirstNumber * 1000;
3277 else
3278 dResult = dFirstNumber / 72;
3279 } else if (bsFirstUnit == "mp" || bsFirstUnit == "millipoints") {
3280 if (bsUnit == "mm" || bsUnit == "millimeters")
3281 dResult = dFirstNumber / 72000 * 25.4;
3282 else if (bsUnit == "cm" || bsUnit == "centimeters")
3283 dResult = dFirstNumber / 72000 * 2.54;
3284 else if (bsUnit == "pt" || bsUnit == "points")
3285 dResult = dFirstNumber / 1000;
3286 else if (bsUnit == "mp" || bsUnit == "millipoints")
3287 dResult = dFirstNumber;
3288 else
3289 dResult = dFirstNumber / 72000;
3290 }
3291 info.GetReturnValue().Set(dResult);
3292}
3293
3294// static
3295void CFXJSE_FormCalcContext::At(
3296 CFXJSE_HostObject* pThis,
3297 const v8::FunctionCallbackInfo<v8::Value>& info) {
3298 if (info.Length() != 2) {
3299 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("At");
3300 return;
3301 }
3302
3303 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
3304 v8::Local<v8::Value> argTwo = GetSimpleValue(info, 1);
3305 if (ValueIsNull(info.GetIsolate(), argOne) ||
3306 ValueIsNull(info.GetIsolate(), argTwo)) {
3307 info.GetReturnValue().SetNull();
3308 return;
3309 }
3310
3311 ByteString stringTwo = ValueToUTF8String(info.GetIsolate(), argTwo);
3312 if (stringTwo.IsEmpty()) {
3313 info.GetReturnValue().Set(1);
3314 return;
3315 }
3316
3317 ByteString stringOne = ValueToUTF8String(info.GetIsolate(), argOne);
3318 auto pos = stringOne.Find(stringTwo.AsStringView());
3319 info.GetReturnValue().Set(
3320 static_cast<int>(pos.has_value() ? pos.value() + 1 : 0));
3321}
3322
3323// static
3324void CFXJSE_FormCalcContext::Concat(
3325 CFXJSE_HostObject* pThis,
3326 const v8::FunctionCallbackInfo<v8::Value>& info) {
3327 int32_t argc = info.Length();
3328 if (argc < 1) {
3329 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Concat");
3330 return;
3331 }
3332
3333 ByteString bsResult;
3334 bool bAllNull = true;
3335 for (int32_t i = 0; i < argc; i++) {
3336 v8::Local<v8::Value> value = GetSimpleValue(info, i);
3337 if (ValueIsNull(info.GetIsolate(), value))
3338 continue;
3339
3340 bAllNull = false;
3341 bsResult += ValueToUTF8String(info.GetIsolate(), value);
3342 }
3343
3344 if (bAllNull) {
3345 info.GetReturnValue().SetNull();
3346 return;
3347 }
3348 info.GetReturnValue().Set(
3349 fxv8::NewStringHelper(info.GetIsolate(), bsResult.AsStringView()));
3350}
3351
3352// static
3353void CFXJSE_FormCalcContext::Decode(
3354 CFXJSE_HostObject* pThis,
3355 const v8::FunctionCallbackInfo<v8::Value>& info) {
3356 int32_t argc = info.Length();
3357 if (argc < 1 || argc > 2) {
3358 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Decode");
3359 return;
3360 }
3361
3362 if (argc == 1) {
3363 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
3364 if (ValueIsNull(info.GetIsolate(), argOne)) {
3365 info.GetReturnValue().SetNull();
3366 return;
3367 }
3368
3369 WideString decoded = DecodeURL(WideString::FromUTF8(
3370 ValueToUTF8String(info.GetIsolate(), argOne).AsStringView()));
3371 auto result = FX_UTF8Encode(decoded.AsStringView());
3372 info.GetReturnValue().Set(
3373 fxv8::NewStringHelper(info.GetIsolate(), result.AsStringView()));
3374 return;
3375 }
3376
3377 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
3378 v8::Local<v8::Value> argTwo = GetSimpleValue(info, 1);
3379 if (ValueIsNull(info.GetIsolate(), argOne) ||
3380 ValueIsNull(info.GetIsolate(), argTwo)) {
3381 info.GetReturnValue().SetNull();
3382 return;
3383 }
3384
3385 ByteString bsToDecode = ValueToUTF8String(info.GetIsolate(), argOne);
3386 ByteString bsIdentify = ValueToUTF8String(info.GetIsolate(), argTwo);
3387 WideString decoded;
3388
3389 WideString wsToDecode = WideString::FromUTF8(bsToDecode.AsStringView());
3390
3391 if (bsIdentify.EqualNoCase("html"))
3392 decoded = DecodeHTML(wsToDecode);
3393 else if (bsIdentify.EqualNoCase("xml"))
3394 decoded = DecodeXML(wsToDecode);
3395 else
3396 decoded = DecodeURL(wsToDecode);
3397
3398 auto result = FX_UTF8Encode(decoded.AsStringView());
3399 info.GetReturnValue().Set(
3400 fxv8::NewStringHelper(info.GetIsolate(), result.AsStringView()));
3401}
3402
3403// static
3404void CFXJSE_FormCalcContext::Encode(
3405 CFXJSE_HostObject* pThis,
3406 const v8::FunctionCallbackInfo<v8::Value>& info) {
3407 int32_t argc = info.Length();
3408 if (argc < 1 || argc > 2) {
3409 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Encode");
3410 return;
3411 }
3412
3413 if (argc == 1) {
3414 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
3415 if (ValueIsNull(info.GetIsolate(), argOne)) {
3416 info.GetReturnValue().SetNull();
3417 return;
3418 }
3419 WideString encoded =
3420 EncodeURL(ValueToUTF8String(info.GetIsolate(), argOne));
3421 auto result = FX_UTF8Encode(encoded.AsStringView());
3422 info.GetReturnValue().Set(
3423 fxv8::NewStringHelper(info.GetIsolate(), result.AsStringView()));
3424 return;
3425 }
3426
3427 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
3428 v8::Local<v8::Value> argTwo = GetSimpleValue(info, 1);
3429 if (ValueIsNull(info.GetIsolate(), argOne) ||
3430 ValueIsNull(info.GetIsolate(), argTwo)) {
3431 info.GetReturnValue().SetNull();
3432 return;
3433 }
3434
3435 ByteString bsToEncode = ValueToUTF8String(info.GetIsolate(), argOne);
3436 ByteString bsIdentify = ValueToUTF8String(info.GetIsolate(), argTwo);
3437 WideString encoded;
3438 if (bsIdentify.EqualNoCase("html"))
3439 encoded = EncodeHTML(bsToEncode);
3440 else if (bsIdentify.EqualNoCase("xml"))
3441 encoded = EncodeXML(bsToEncode);
3442 else
3443 encoded = EncodeURL(bsToEncode);
3444
3445 auto result = FX_UTF8Encode(encoded.AsStringView());
3446 info.GetReturnValue().Set(
3447 fxv8::NewStringHelper(info.GetIsolate(), result.AsStringView()));
3448}
3449
3450// static
3451void CFXJSE_FormCalcContext::Format(
3452 CFXJSE_HostObject* pThis,
3453 const v8::FunctionCallbackInfo<v8::Value>& info) {
3454 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
3455 if (info.Length() < 2) {
3456 pContext->ThrowParamCountMismatchException("Format");
3457 return;
3458 }
3459
3460 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
3461 ByteString bsPattern = ValueToUTF8String(info.GetIsolate(), argOne);
3462
3463 v8::Local<v8::Value> argTwo = GetSimpleValue(info, 1);
3464 ByteString bsValue = ValueToUTF8String(info.GetIsolate(), argTwo);
3465
3466 CXFA_Document* pDoc = pContext->GetDocument();
3467 CXFA_LocaleMgr* pMgr = pDoc->GetLocaleMgr();
3469 GCedLocaleIface* pLocale = pThisNode->GetLocale();
3470 WideString wsPattern = WideString::FromUTF8(bsPattern.AsStringView());
3471 WideString wsValue = WideString::FromUTF8(bsValue.AsStringView());
3472 bool bPatternIsString;
3473 CXFA_LocaleValue::ValueType dwPatternType;
3474 std::tie(bPatternIsString, dwPatternType) =
3475 PatternStringType(bsPattern.AsStringView());
3476 if (!bPatternIsString) {
3477 switch (dwPatternType) {
3479 auto iTChar = wsPattern.Find(L'T');
3480 if (!iTChar.has_value()) {
3481 info.GetReturnValue().SetEmptyString();
3482 return;
3483 }
3484 WideString wsDatePattern(L"date{");
3485 wsDatePattern += wsPattern.First(iTChar.value()) + L"} ";
3486
3487 WideString wsTimePattern(L"time{");
3488 wsTimePattern +=
3489 wsPattern.Last(wsPattern.GetLength() - (iTChar.value() + 1)) + L"}";
3490 wsPattern = wsDatePattern + wsTimePattern;
3491 } break;
3493 wsPattern = L"date{" + wsPattern + L"}";
3494 } break;
3496 wsPattern = L"time{" + wsPattern + L"}";
3497 } break;
3499 wsPattern = L"text{" + wsPattern + L"}";
3500 } break;
3502 wsPattern = L"num{" + wsPattern + L"}";
3503 } break;
3504 default: {
3505 WideString wsTestPattern = L"num{" + wsPattern + L"}";
3507 wsValue, wsTestPattern, pLocale, pMgr);
3508 if (tempLocaleValue.IsValid()) {
3509 wsPattern = std::move(wsTestPattern);
3511 } else {
3512 wsPattern = L"text{" + wsPattern + L"}";
3513 dwPatternType = CXFA_LocaleValue::ValueType::kText;
3514 }
3515 } break;
3516 }
3517 }
3518 CXFA_LocaleValue localeValue(dwPatternType, wsValue, wsPattern, pLocale,
3519 pMgr);
3520 WideString wsRet;
3521 if (!localeValue.FormatPatterns(wsRet, wsPattern, pLocale,
3523 info.GetReturnValue().SetEmptyString();
3524 return;
3525 }
3526 info.GetReturnValue().Set(
3527 fxv8::NewStringHelper(info.GetIsolate(), wsRet.ToUTF8().AsStringView()));
3528}
3529
3530// static
3531void CFXJSE_FormCalcContext::Left(
3532 CFXJSE_HostObject* pThis,
3533 const v8::FunctionCallbackInfo<v8::Value>& info) {
3534 if (info.Length() != 2) {
3535 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Left");
3536 return;
3537 }
3538
3539 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
3540 v8::Local<v8::Value> argTwo = GetSimpleValue(info, 1);
3541 if ((ValueIsNull(info.GetIsolate(), argOne)) ||
3542 (ValueIsNull(info.GetIsolate(), argTwo))) {
3543 info.GetReturnValue().SetNull();
3544 return;
3545 }
3546
3547 ByteString bsSource = ValueToUTF8String(info.GetIsolate(), argOne);
3548 int32_t count = std::max(0, ValueToInteger(info.GetIsolate(), argTwo));
3549 info.GetReturnValue().Set(fxv8::NewStringHelper(
3550 info.GetIsolate(), bsSource.First(count).AsStringView()));
3551}
3552
3553// static
3554void CFXJSE_FormCalcContext::Len(
3555 CFXJSE_HostObject* pThis,
3556 const v8::FunctionCallbackInfo<v8::Value>& info) {
3557 if (info.Length() != 1) {
3558 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Len");
3559 return;
3560 }
3561
3562 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
3563 if (ValueIsNull(info.GetIsolate(), argOne)) {
3564 info.GetReturnValue().SetNull();
3565 return;
3566 }
3567
3568 ByteString bsSource = ValueToUTF8String(info.GetIsolate(), argOne);
3569 info.GetReturnValue().Set(static_cast<int>(bsSource.GetLength()));
3570}
3571
3572// static
3573void CFXJSE_FormCalcContext::Lower(
3574 CFXJSE_HostObject* pThis,
3575 const v8::FunctionCallbackInfo<v8::Value>& info) {
3576 int32_t argc = info.Length();
3577 if (argc < 1 || argc > 2) {
3578 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Lower");
3579 return;
3580 }
3581
3582 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
3583 if (ValueIsNull(info.GetIsolate(), argOne)) {
3584 info.GetReturnValue().SetNull();
3585 return;
3586 }
3587
3588 WideTextBuffer szLowBuf;
3589 ByteString bsArg = ValueToUTF8String(info.GetIsolate(), argOne);
3590 WideString wsArg = WideString::FromUTF8(bsArg.AsStringView());
3591 for (wchar_t ch : wsArg) {
3592 if ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0xC0 && ch <= 0xDE))
3593 ch += 32;
3594 else if (ch == 0x100 || ch == 0x102 || ch == 0x104)
3595 ch += 1;
3596 szLowBuf.AppendChar(ch);
3597 }
3598 auto result = FX_UTF8Encode(szLowBuf.AsStringView());
3599 info.GetReturnValue().Set(
3600 fxv8::NewStringHelper(info.GetIsolate(), result.AsStringView()));
3601}
3602
3603// static
3604void CFXJSE_FormCalcContext::Ltrim(
3605 CFXJSE_HostObject* pThis,
3606 const v8::FunctionCallbackInfo<v8::Value>& info) {
3607 if (info.Length() != 1) {
3608 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Ltrim");
3609 return;
3610 }
3611
3612 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
3613 if (ValueIsNull(info.GetIsolate(), argOne)) {
3614 info.GetReturnValue().SetNull();
3615 return;
3616 }
3617
3618 ByteString bsSource = ValueToUTF8String(info.GetIsolate(), argOne);
3619 bsSource.TrimLeft();
3620 info.GetReturnValue().Set(
3621 fxv8::NewStringHelper(info.GetIsolate(), bsSource.AsStringView()));
3622}
3623
3624// static
3625void CFXJSE_FormCalcContext::Parse(
3626 CFXJSE_HostObject* pThis,
3627 const v8::FunctionCallbackInfo<v8::Value>& info) {
3628 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
3629 if (info.Length() != 2) {
3630 pContext->ThrowParamCountMismatchException("Parse");
3631 return;
3632 }
3633
3634 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
3635 v8::Local<v8::Value> argTwo = GetSimpleValue(info, 1);
3636 if (ValueIsNull(info.GetIsolate(), argTwo)) {
3637 info.GetReturnValue().SetNull();
3638 return;
3639 }
3640
3641 ByteString bsPattern = ValueToUTF8String(info.GetIsolate(), argOne);
3642 ByteString bsValue = ValueToUTF8String(info.GetIsolate(), argTwo);
3643 CXFA_Document* pDoc = pContext->GetDocument();
3644 CXFA_LocaleMgr* pMgr = pDoc->GetLocaleMgr();
3646 GCedLocaleIface* pLocale = pThisNode->GetLocale();
3647 WideString wsPattern = WideString::FromUTF8(bsPattern.AsStringView());
3648 WideString wsValue = WideString::FromUTF8(bsValue.AsStringView());
3649 bool bPatternIsString;
3650 CXFA_LocaleValue::ValueType dwPatternType;
3651 std::tie(bPatternIsString, dwPatternType) =
3652 PatternStringType(bsPattern.AsStringView());
3653 if (bPatternIsString) {
3654 CXFA_LocaleValue localeValue(dwPatternType, wsValue, wsPattern, pLocale,
3655 pMgr);
3656 if (!localeValue.IsValid()) {
3657 info.GetReturnValue().SetEmptyString();
3658 return;
3659 }
3660 auto result = localeValue.GetValue().ToUTF8();
3661 info.GetReturnValue().Set(
3662 fxv8::NewStringHelper(info.GetIsolate(), result.AsStringView()));
3663 return;
3664 }
3665
3666 switch (dwPatternType) {
3668 auto iTChar = wsPattern.Find(L'T');
3669 if (!iTChar.has_value()) {
3670 info.GetReturnValue().SetEmptyString();
3671 return;
3672 }
3673 WideString wsDatePattern(L"date{" + wsPattern.First(iTChar.value()) +
3674 L"} ");
3675 WideString wsTimePattern(
3676 L"time{" +
3677 wsPattern.Last(wsPattern.GetLength() - (iTChar.value() + 1)) + L"}");
3678 wsPattern = wsDatePattern + wsTimePattern;
3679 CXFA_LocaleValue localeValue(dwPatternType, wsValue, wsPattern, pLocale,
3680 pMgr);
3681 if (!localeValue.IsValid()) {
3682 info.GetReturnValue().SetEmptyString();
3683 return;
3684 }
3685 auto result = localeValue.GetValue().ToUTF8();
3686 info.GetReturnValue().Set(
3687 fxv8::NewStringHelper(info.GetIsolate(), result.AsStringView()));
3688 return;
3689 }
3691 wsPattern = L"date{" + wsPattern + L"}";
3692 CXFA_LocaleValue localeValue(dwPatternType, wsValue, wsPattern, pLocale,
3693 pMgr);
3694 if (!localeValue.IsValid()) {
3695 info.GetReturnValue().SetEmptyString();
3696 return;
3697 }
3698 auto result = localeValue.GetValue().ToUTF8();
3699 info.GetReturnValue().Set(
3700 fxv8::NewStringHelper(info.GetIsolate(), result.AsStringView()));
3701 return;
3702 }
3704 wsPattern = L"time{" + wsPattern + L"}";
3705 CXFA_LocaleValue localeValue(dwPatternType, wsValue, wsPattern, pLocale,
3706 pMgr);
3707 if (!localeValue.IsValid()) {
3708 info.GetReturnValue().SetEmptyString();
3709 return;
3710 }
3711 auto result = localeValue.GetValue().ToUTF8();
3712 info.GetReturnValue().Set(
3713 fxv8::NewStringHelper(info.GetIsolate(), result.AsStringView()));
3714 return;
3715 }
3717 wsPattern = L"text{" + wsPattern + L"}";
3719 wsPattern, pLocale, pMgr);
3720 if (!localeValue.IsValid()) {
3721 info.GetReturnValue().SetEmptyString();
3722 return;
3723 }
3724 auto result = localeValue.GetValue().ToUTF8();
3725 info.GetReturnValue().Set(
3726 fxv8::NewStringHelper(info.GetIsolate(), result.AsStringView()));
3727 return;
3728 }
3730 wsPattern = L"num{" + wsPattern + L"}";
3732 wsPattern, pLocale, pMgr);
3733 if (!localeValue.IsValid()) {
3734 info.GetReturnValue().SetEmptyString();
3735 return;
3736 }
3737 info.GetReturnValue().Set(localeValue.GetDoubleNum());
3738 return;
3739 }
3740 default: {
3741 {
3742 WideString wsTestPattern = L"num{" + wsPattern + L"}";
3744 wsValue, wsTestPattern, pLocale, pMgr);
3745 if (localeValue.IsValid()) {
3746 info.GetReturnValue().Set(localeValue.GetDoubleNum());
3747 return;
3748 }
3749 }
3750
3751 {
3752 WideString wsTestPattern = L"text{" + wsPattern + L"}";
3754 wsValue, wsTestPattern, pLocale, pMgr);
3755 if (localeValue.IsValid()) {
3756 auto result = localeValue.GetValue().ToUTF8();
3757 info.GetReturnValue().Set(
3758 fxv8::NewStringHelper(info.GetIsolate(), result.AsStringView()));
3759 return;
3760 }
3761 }
3762 info.GetReturnValue().SetEmptyString();
3763 return;
3764 }
3765 }
3766}
3767
3768// static
3769void CFXJSE_FormCalcContext::Replace(
3770 CFXJSE_HostObject* pThis,
3771 const v8::FunctionCallbackInfo<v8::Value>& info) {
3772 int32_t argc = info.Length();
3773 if (argc < 2 || argc > 3) {
3774 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Replace");
3775 return;
3776 }
3777
3778 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
3779 v8::Local<v8::Value> argTwo = GetSimpleValue(info, 1);
3780 ByteString bsOne;
3781 ByteString bsTwo;
3782 if (!ValueIsNull(info.GetIsolate(), argOne) &&
3783 !ValueIsNull(info.GetIsolate(), argTwo)) {
3784 bsOne = ValueToUTF8String(info.GetIsolate(), argOne);
3785 bsTwo = ValueToUTF8String(info.GetIsolate(), argTwo);
3786 }
3787
3788 ByteString bsThree;
3789 if (argc > 2) {
3790 v8::Local<v8::Value> argThree = GetSimpleValue(info, 2);
3791 bsThree = ValueToUTF8String(info.GetIsolate(), argThree);
3792 }
3793
3794 bsOne.Replace(bsTwo.AsStringView(), bsThree.AsStringView());
3795 info.GetReturnValue().Set(
3796 fxv8::NewStringHelper(info.GetIsolate(), bsOne.AsStringView()));
3797}
3798
3799// static
3800void CFXJSE_FormCalcContext::Right(
3801 CFXJSE_HostObject* pThis,
3802 const v8::FunctionCallbackInfo<v8::Value>& info) {
3803 if (info.Length() != 2) {
3804 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Right");
3805 return;
3806 }
3807
3808 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
3809 v8::Local<v8::Value> argTwo = GetSimpleValue(info, 1);
3810 if ((ValueIsNull(info.GetIsolate(), argOne)) ||
3811 (ValueIsNull(info.GetIsolate(), argTwo))) {
3812 info.GetReturnValue().SetNull();
3813 return;
3814 }
3815
3816 ByteString bsSource = ValueToUTF8String(info.GetIsolate(), argOne);
3817 int32_t count = std::max(0, ValueToInteger(info.GetIsolate(), argTwo));
3818 info.GetReturnValue().Set(fxv8::NewStringHelper(
3819 info.GetIsolate(), bsSource.Last(count).AsStringView()));
3820}
3821
3822// static
3823void CFXJSE_FormCalcContext::Rtrim(
3824 CFXJSE_HostObject* pThis,
3825 const v8::FunctionCallbackInfo<v8::Value>& info) {
3826 if (info.Length() != 1) {
3827 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Rtrim");
3828 return;
3829 }
3830
3831 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
3832 if (ValueIsNull(info.GetIsolate(), argOne)) {
3833 info.GetReturnValue().SetNull();
3834 return;
3835 }
3836
3837 ByteString bsSource = ValueToUTF8String(info.GetIsolate(), argOne);
3838 bsSource.TrimRight();
3839 info.GetReturnValue().Set(
3840 fxv8::NewStringHelper(info.GetIsolate(), bsSource.AsStringView()));
3841}
3842
3843// static
3844void CFXJSE_FormCalcContext::Space(
3845 CFXJSE_HostObject* pThis,
3846 const v8::FunctionCallbackInfo<v8::Value>& info) {
3847 if (info.Length() != 1) {
3848 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Space");
3849 return;
3850 }
3851
3852 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
3853 if (fxv8::IsNull(argOne)) {
3854 info.GetReturnValue().SetNull();
3855 return;
3856 }
3857
3858 int count = std::max(0, ValueToInteger(info.GetIsolate(), argOne));
3859 if (count > kMaxCharCount) {
3860 ToFormCalcContext(pThis)->ThrowException("String too long.");
3861 return;
3862 }
3863 DataVector<char> space_string(count, ' ');
3864 info.GetReturnValue().Set(
3865 fxv8::NewStringHelper(info.GetIsolate(), ByteStringView(space_string)));
3866}
3867
3868// static
3869void CFXJSE_FormCalcContext::Str(
3870 CFXJSE_HostObject* pThis,
3871 const v8::FunctionCallbackInfo<v8::Value>& info) {
3872 int32_t argc = info.Length();
3873 if (argc < 1 || argc > 3) {
3874 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Str");
3875 return;
3876 }
3877
3878 v8::Local<v8::Value> numberValue = GetSimpleValue(info, 0);
3879 if (fxv8::IsNull(numberValue)) {
3880 info.GetReturnValue().SetNull();
3881 return;
3882 }
3883 float fNumber = ValueToFloat(info.GetIsolate(), numberValue);
3884
3885 constexpr int32_t kDefaultWidth = 10;
3886 int32_t iWidth = kDefaultWidth;
3887 if (argc > 1) {
3888 v8::Local<v8::Value> widthValue = GetSimpleValue(info, 1);
3889 iWidth = static_cast<int32_t>(ValueToFloat(info.GetIsolate(), widthValue));
3890 if (iWidth > kMaxCharCount) {
3891 ToFormCalcContext(pThis)->ThrowException("String too long.");
3892 return;
3893 }
3894 }
3895
3896 constexpr int32_t kDefaultPrecision = 0;
3897 int32_t iPrecision = kDefaultPrecision;
3898 if (argc > 2) {
3899 constexpr int32_t kMaxPrecision = 15;
3900 v8::Local<v8::Value> precision_value = GetSimpleValue(info, 2);
3901 iPrecision = std::max(0, static_cast<int32_t>(ValueToFloat(
3902 info.GetIsolate(), precision_value)));
3903 iPrecision = std::min(iPrecision, kMaxPrecision);
3904 }
3905
3906 ByteString bsFormat = "%";
3907 if (iPrecision) {
3908 bsFormat += ".";
3909 bsFormat += ByteString::FormatInteger(iPrecision);
3910 }
3911 bsFormat += "f";
3912 ByteString bsNumber = ByteString::Format(bsFormat.c_str(), fNumber);
3913
3914 const char* pData = bsNumber.c_str();
3915 int32_t iLength = bsNumber.GetLength();
3916 int32_t u = 0;
3917 while (u < iLength) {
3918 if (pData[u] == '.')
3919 break;
3920
3921 ++u;
3922 }
3923
3924 if (u > iWidth || (iPrecision + u) >= iWidth) {
3925 DataVector<char> stars(std::max(iWidth, 0), '*');
3926 info.GetReturnValue().Set(
3927 fxv8::NewStringHelper(info.GetIsolate(), ByteStringView(stars)));
3928 return;
3929 }
3930
3931 ByteString resultBuf;
3932 if (u == iLength) {
3933 if (iLength > iWidth) {
3934 int32_t i = 0;
3935 while (i < iWidth) {
3936 resultBuf += '*';
3937 ++i;
3938 }
3939 } else {
3940 int32_t i = 0;
3941 while (i < iWidth - iLength) {
3942 resultBuf += ' ';
3943 ++i;
3944 }
3945 resultBuf += pData;
3946 }
3947 info.GetReturnValue().Set(
3948 fxv8::NewStringHelper(info.GetIsolate(), resultBuf.AsStringView()));
3949 return;
3950 }
3951
3952 int32_t iLeavingSpace = iWidth - u - iPrecision;
3953 if (iPrecision != 0)
3954 iLeavingSpace--;
3955
3956 int32_t i = 0;
3957 while (i < iLeavingSpace) {
3958 resultBuf += ' ';
3959 ++i;
3960 }
3961 i = 0;
3962 while (i < u) {
3963 resultBuf += pData[i];
3964 ++i;
3965 }
3966 if (iPrecision != 0)
3967 resultBuf += '.';
3968
3969 u++;
3970 i = 0;
3971 while (u < iLength) {
3972 if (i >= iPrecision)
3973 break;
3974
3975 resultBuf += pData[u];
3976 ++i;
3977 ++u;
3978 }
3979 while (i < iPrecision) {
3980 resultBuf += '0';
3981 ++i;
3982 }
3983 info.GetReturnValue().Set(
3984 fxv8::NewStringHelper(info.GetIsolate(), resultBuf.AsStringView()));
3985}
3986
3987// static
3988void CFXJSE_FormCalcContext::Stuff(
3989 CFXJSE_HostObject* pThis,
3990 const v8::FunctionCallbackInfo<v8::Value>& info) {
3991 int32_t argc = info.Length();
3992 if (argc < 3 || argc > 4) {
3993 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Stuff");
3994 return;
3995 }
3996
3997 v8::Local<v8::Value> sourceValue = GetSimpleValue(info, 0);
3998 v8::Local<v8::Value> startValue = GetSimpleValue(info, 1);
3999 v8::Local<v8::Value> deleteValue = GetSimpleValue(info, 2);
4000 if (fxv8::IsNull(sourceValue) || fxv8::IsNull(startValue) ||
4001 fxv8::IsNull(deleteValue)) {
4002 info.GetReturnValue().SetNull();
4003 return;
4004 }
4005
4006 int32_t iStart = 1; // one-based character indexing.
4007 int32_t iDelete = 0;
4008 ByteString bsSource = ValueToUTF8String(info.GetIsolate(), sourceValue);
4009 int32_t iLength = pdfium::base::checked_cast<int32_t>(bsSource.GetLength());
4010 if (iLength) {
4011 iStart = std::clamp(
4012 static_cast<int32_t>(ValueToFloat(info.GetIsolate(), startValue)), 1,
4013 iLength);
4014 iDelete = std::clamp(
4015 static_cast<int32_t>(ValueToFloat(info.GetIsolate(), deleteValue)), 0,
4016 iLength - iStart + 1);
4017 }
4018
4019 ByteString bsInsert;
4020 if (argc > 3) {
4021 v8::Local<v8::Value> insertValue = GetSimpleValue(info, 3);
4022 bsInsert = ValueToUTF8String(info.GetIsolate(), insertValue);
4023 }
4024
4025 --iStart; // now zero-based.
4026 ByteString bsResult = {bsSource.AsStringView().First(iStart),
4027 bsInsert.AsStringView(),
4028 bsSource.AsStringView().Substr(iStart + iDelete)};
4029 info.GetReturnValue().Set(
4030 fxv8::NewStringHelper(info.GetIsolate(), bsResult.AsStringView()));
4031}
4032
4033// static
4034void CFXJSE_FormCalcContext::Substr(
4035 CFXJSE_HostObject* pThis,
4036 const v8::FunctionCallbackInfo<v8::Value>& info) {
4037 if (info.Length() != 3) {
4038 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Substr");
4039 return;
4040 }
4041
4042 v8::Local<v8::Value> string_value = GetSimpleValue(info, 0);
4043 v8::Local<v8::Value> start_value = GetSimpleValue(info, 1);
4044 v8::Local<v8::Value> end_value = GetSimpleValue(info, 2);
4045 if (ValueIsNull(info.GetIsolate(), string_value) ||
4046 ValueIsNull(info.GetIsolate(), start_value) ||
4047 ValueIsNull(info.GetIsolate(), end_value)) {
4048 info.GetReturnValue().SetNull();
4049 return;
4050 }
4051
4052 ByteString bsSource = ValueToUTF8String(info.GetIsolate(), string_value);
4053 size_t iLength = bsSource.GetLength();
4054 if (iLength == 0) {
4055 info.GetReturnValue().SetEmptyString();
4056 return;
4057 }
4058
4059 // |start_value| is 1-based. Assume first character if |start_value| is less
4060 // than 1, per spec. Subtract 1 since |iStart| is 0-based.
4061 size_t iStart =
4062 std::max(ValueToInteger(info.GetIsolate(), start_value), 1) - 1;
4063 if (iStart >= iLength) {
4064 info.GetReturnValue().SetEmptyString();
4065 return;
4066 }
4067
4068 // Negative values are treated as 0. Can't clamp() due to sign mismatches.
4069 size_t iCount = std::max(ValueToInteger(info.GetIsolate(), end_value), 0);
4070 iCount = std::min(iCount, iLength - iStart);
4071 info.GetReturnValue().Set(fxv8::NewStringHelper(
4072 info.GetIsolate(), bsSource.Substr(iStart, iCount).AsStringView()));
4073}
4074
4075// static
4076void CFXJSE_FormCalcContext::Uuid(
4077 CFXJSE_HostObject* pThis,
4078 const v8::FunctionCallbackInfo<v8::Value>& info) {
4079 int32_t argc = info.Length();
4080 if (argc < 0 || argc > 1) {
4081 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Uuid");
4082 return;
4083 }
4084
4085 int32_t iNum = 0;
4086 if (argc > 0) {
4087 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
4088 iNum = static_cast<int32_t>(ValueToFloat(info.GetIsolate(), argOne));
4089 }
4090 info.GetReturnValue().Set(fxv8::NewStringHelper(
4091 info.GetIsolate(), GUIDString(!!iNum).AsStringView()));
4092}
4093
4094// static
4095void CFXJSE_FormCalcContext::Upper(
4096 CFXJSE_HostObject* pThis,
4097 const v8::FunctionCallbackInfo<v8::Value>& info) {
4098 int32_t argc = info.Length();
4099 if (argc < 1 || argc > 2) {
4100 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("Upper");
4101 return;
4102 }
4103
4104 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
4105 if (ValueIsNull(info.GetIsolate(), argOne)) {
4106 info.GetReturnValue().SetNull();
4107 return;
4108 }
4109
4110 ByteString bsArg = ValueToUTF8String(info.GetIsolate(), argOne);
4111 WideString wsArg = WideString::FromUTF8(bsArg.AsStringView());
4112 WideString upperStringBuf;
4113 upperStringBuf.Reserve(wsArg.GetLength());
4114 for (wchar_t ch : wsArg) {
4115 if ((ch >= 0x61 && ch <= 0x7A) || (ch >= 0xE0 && ch <= 0xFE))
4116 ch -= 32;
4117 else if (ch == 0x101 || ch == 0x103 || ch == 0x105)
4118 ch -= 1;
4119
4120 upperStringBuf += ch;
4121 }
4122 info.GetReturnValue().Set(fxv8::NewStringHelper(
4123 info.GetIsolate(),
4124 FX_UTF8Encode(upperStringBuf.AsStringView()).AsStringView()));
4125}
4126
4127// static
4128void CFXJSE_FormCalcContext::WordNum(
4129 CFXJSE_HostObject* pThis,
4130 const v8::FunctionCallbackInfo<v8::Value>& info) {
4131 int32_t argc = info.Length();
4132 if (argc < 1 || argc > 3) {
4133 ToFormCalcContext(pThis)->ThrowParamCountMismatchException("WordNum");
4134 return;
4135 }
4136
4137 v8::Local<v8::Value> numberValue = GetSimpleValue(info, 0);
4138 if (fxv8::IsNull(numberValue)) {
4139 info.GetReturnValue().SetNull();
4140 return;
4141 }
4142 float fNumber = ValueToFloat(info.GetIsolate(), numberValue);
4143
4144 int32_t iIdentifier = 0;
4145 if (argc > 1) {
4146 v8::Local<v8::Value> identifierValue = GetSimpleValue(info, 1);
4147 if (fxv8::IsNull(identifierValue)) {
4148 info.GetReturnValue().SetNull();
4149 return;
4150 }
4151 iIdentifier =
4152 static_cast<int32_t>(ValueToFloat(info.GetIsolate(), identifierValue));
4153 }
4154
4155 ByteString bsLocale;
4156 if (argc > 2) {
4157 v8::Local<v8::Value> localeValue = GetSimpleValue(info, 2);
4158 if (fxv8::IsNull(localeValue)) {
4159 info.GetReturnValue().SetNull();
4160 return;
4161 }
4162 bsLocale = ValueToUTF8String(info.GetIsolate(), localeValue);
4163 }
4164
4165 if (isnan(fNumber) || fNumber < 0.0f || fNumber > 922337203685477550.0f) {
4166 info.GetReturnValue().Set(fxv8::NewStringHelper(info.GetIsolate(), "*"));
4167 return;
4168 }
4169 ByteString bsFormatted = ByteString::Format("%.2f", fNumber);
4170 ByteString bsWorded = WordUS(bsFormatted.AsStringView(), iIdentifier);
4171 info.GetReturnValue().Set(
4172 fxv8::NewStringHelper(info.GetIsolate(), bsWorded.AsStringView()));
4173}
4174
4175// static
4176void CFXJSE_FormCalcContext::Get(
4177 CFXJSE_HostObject* pThis,
4178 const v8::FunctionCallbackInfo<v8::Value>& info) {
4179 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
4180 if (info.Length() != 1) {
4181 pContext->ThrowParamCountMismatchException("Get");
4182 return;
4183 }
4184
4185 CXFA_Document* pDoc = pContext->GetDocument();
4186 if (!pDoc)
4187 return;
4188
4189 CXFA_FFApp::CallbackIface* pAppProvider = pDoc->GetNotify()->GetAppProvider();
4190 if (!pAppProvider)
4191 return;
4192
4193 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
4194 ByteString bsUrl = ValueToUTF8String(info.GetIsolate(), argOne);
4196 pAppProvider->DownloadURL(WideString::FromUTF8(bsUrl.AsStringView()));
4197 if (!pFile)
4198 return;
4199
4200 FX_FILESIZE size = pFile->GetSize();
4201 DataVector<uint8_t> dataBuf(size);
4202
4203 // TODO(tsepez): check return value?
4204 (void)pFile->ReadBlock(dataBuf);
4205 info.GetReturnValue().Set(
4206 fxv8::NewStringHelper(info.GetIsolate(), ByteStringView(dataBuf)));
4207}
4208
4209// static
4210void CFXJSE_FormCalcContext::Post(
4211 CFXJSE_HostObject* pThis,
4212 const v8::FunctionCallbackInfo<v8::Value>& info) {
4213 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
4214 int32_t argc = info.Length();
4215 if (argc < 2 || argc > 5) {
4216 pContext->ThrowParamCountMismatchException("Post");
4217 return;
4218 }
4219
4220 CXFA_Document* pDoc = pContext->GetDocument();
4221 if (!pDoc)
4222 return;
4223
4224 CXFA_FFApp::CallbackIface* pAppProvider = pDoc->GetNotify()->GetAppProvider();
4225 if (!pAppProvider)
4226 return;
4227
4228 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
4229 ByteString bsURL = ValueToUTF8String(info.GetIsolate(), argOne);
4230
4231 v8::Local<v8::Value> argTwo = GetSimpleValue(info, 1);
4232 ByteString bsData = ValueToUTF8String(info.GetIsolate(), argTwo);
4233
4234 ByteString bsContentType;
4235 if (argc > 2) {
4236 v8::Local<v8::Value> argThree = GetSimpleValue(info, 2);
4237 bsContentType = ValueToUTF8String(info.GetIsolate(), argThree);
4238 }
4239
4240 ByteString bsEncode;
4241 if (argc > 3) {
4242 v8::Local<v8::Value> argFour = GetSimpleValue(info, 3);
4243 bsEncode = ValueToUTF8String(info.GetIsolate(), argFour);
4244 }
4245
4246 ByteString bsHeader;
4247 if (argc > 4) {
4248 v8::Local<v8::Value> argFive = GetSimpleValue(info, 4);
4249 bsHeader = ValueToUTF8String(info.GetIsolate(), argFive);
4250 }
4251
4252 WideString decodedResponse;
4253 if (!pAppProvider->PostRequestURL(
4254 WideString::FromUTF8(bsURL.AsStringView()),
4255 WideString::FromUTF8(bsData.AsStringView()),
4256 WideString::FromUTF8(bsContentType.AsStringView()),
4257 WideString::FromUTF8(bsEncode.AsStringView()),
4258 WideString::FromUTF8(bsHeader.AsStringView()), decodedResponse)) {
4259 pContext->ThrowServerDeniedException();
4260 return;
4261 }
4262 info.GetReturnValue().Set(fxv8::NewStringHelper(
4263 info.GetIsolate(), decodedResponse.ToUTF8().AsStringView()));
4264}
4265
4266// static
4267void CFXJSE_FormCalcContext::Put(
4268 CFXJSE_HostObject* pThis,
4269 const v8::FunctionCallbackInfo<v8::Value>& info) {
4270 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
4271 int32_t argc = info.Length();
4272 if (argc < 2 || argc > 3) {
4273 pContext->ThrowParamCountMismatchException("Put");
4274 return;
4275 }
4276
4277 CXFA_Document* pDoc = pContext->GetDocument();
4278 if (!pDoc)
4279 return;
4280
4281 CXFA_FFApp::CallbackIface* pAppProvider = pDoc->GetNotify()->GetAppProvider();
4282 if (!pAppProvider)
4283 return;
4284
4285 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
4286 ByteString bsURL = ValueToUTF8String(info.GetIsolate(), argOne);
4287
4288 v8::Local<v8::Value> argTwo = GetSimpleValue(info, 1);
4289 ByteString bsData = ValueToUTF8String(info.GetIsolate(), argTwo);
4290
4291 ByteString bsEncode;
4292 if (argc > 2) {
4293 v8::Local<v8::Value> argThree = GetSimpleValue(info, 2);
4294 bsEncode = ValueToUTF8String(info.GetIsolate(), argThree);
4295 }
4296 if (!pAppProvider->PutRequestURL(
4297 WideString::FromUTF8(bsURL.AsStringView()),
4298 WideString::FromUTF8(bsData.AsStringView()),
4299 WideString::FromUTF8(bsEncode.AsStringView()))) {
4300 pContext->ThrowServerDeniedException();
4301 return;
4302 }
4303 info.GetReturnValue().SetEmptyString();
4304}
4305
4306// static
4307void CFXJSE_FormCalcContext::assign_value_operator(
4308 CFXJSE_HostObject* pThis,
4309 const v8::FunctionCallbackInfo<v8::Value>& info) {
4310 v8::Isolate* pIsolate = info.GetIsolate();
4311 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
4312 if (info.Length() != 2) {
4313 pContext->ThrowCompilerErrorException();
4314 return;
4315 }
4316 ByteStringView bsFuncName("asgn_val_op");
4317 v8::Local<v8::Value> lValue = info[0];
4318 v8::Local<v8::Value> rValue = GetSimpleValue(info, 1);
4319 if (fxv8::IsArray(lValue)) {
4320 v8::Local<v8::Array> arr = lValue.As<v8::Array>();
4321 uint32_t iLeftLength = fxv8::GetArrayLengthHelper(arr);
4322 v8::Local<v8::Value> propertyValue =
4323 fxv8::ReentrantGetArrayElementHelper(pIsolate, arr, 1);
4324 for (uint32_t i = 2; i < iLeftLength; i++) {
4325 v8::Local<v8::Value> jsValue =
4326 fxv8::ReentrantGetArrayElementHelper(pIsolate, arr, i);
4327 if (!fxv8::IsObject(jsValue)) {
4328 pContext->ThrowNoDefaultPropertyException(bsFuncName);
4329 return;
4330 }
4331 v8::Local<v8::Object> jsObjectValue = jsValue.As<v8::Object>();
4332 if (fxv8::IsNull(propertyValue)) {
4333 if (!SetObjectDefaultValue(pIsolate, jsObjectValue, rValue)) {
4334 pContext->ThrowNoDefaultPropertyException(bsFuncName);
4335 return;
4336 }
4337 } else {
4338 fxv8::ReentrantPutObjectPropertyHelper(
4339 pIsolate, jsObjectValue,
4340 fxv8::ReentrantToByteStringHelper(pIsolate, propertyValue)
4341 .AsStringView(),
4342 rValue);
4343 }
4344 }
4345 } else if (fxv8::IsObject(lValue)) {
4346 if (!SetObjectDefaultValue(pIsolate, lValue.As<v8::Object>(), rValue)) {
4347 pContext->ThrowNoDefaultPropertyException(bsFuncName);
4348 return;
4349 }
4350 }
4351 info.GetReturnValue().Set(rValue);
4352}
4353
4354// static
4355void CFXJSE_FormCalcContext::logical_or_operator(
4356 CFXJSE_HostObject* pThis,
4357 const v8::FunctionCallbackInfo<v8::Value>& info) {
4358 if (info.Length() != 2) {
4359 ToFormCalcContext(pThis)->ThrowCompilerErrorException();
4360 return;
4361 }
4362
4363 v8::Local<v8::Value> argFirst = GetSimpleValue(info, 0);
4364 v8::Local<v8::Value> argSecond = GetSimpleValue(info, 1);
4365 if (fxv8::IsNull(argFirst) && fxv8::IsNull(argSecond)) {
4366 info.GetReturnValue().SetNull();
4367 return;
4368 }
4369
4370 float first = ValueToFloat(info.GetIsolate(), argFirst);
4371 float second = ValueToFloat(info.GetIsolate(), argSecond);
4372 info.GetReturnValue().Set(static_cast<int>(first || second));
4373}
4374
4375// static
4376void CFXJSE_FormCalcContext::logical_and_operator(
4377 CFXJSE_HostObject* pThis,
4378 const v8::FunctionCallbackInfo<v8::Value>& info) {
4379 if (info.Length() != 2) {
4380 ToFormCalcContext(pThis)->ThrowCompilerErrorException();
4381 return;
4382 }
4383
4384 v8::Local<v8::Value> argFirst = GetSimpleValue(info, 0);
4385 v8::Local<v8::Value> argSecond = GetSimpleValue(info, 1);
4386 if (fxv8::IsNull(argFirst) && fxv8::IsNull(argSecond)) {
4387 info.GetReturnValue().SetNull();
4388 return;
4389 }
4390
4391 float first = ValueToFloat(info.GetIsolate(), argFirst);
4392 float second = ValueToFloat(info.GetIsolate(), argSecond);
4393 info.GetReturnValue().Set(static_cast<int>(first && second));
4394}
4395
4396// static
4397void CFXJSE_FormCalcContext::equality_operator(
4398 CFXJSE_HostObject* pThis,
4399 const v8::FunctionCallbackInfo<v8::Value>& info) {
4400 if (info.Length() != 2) {
4401 ToFormCalcContext(pThis)->ThrowCompilerErrorException();
4402 return;
4403 }
4404
4405 if (fm_ref_equal(pThis, info)) {
4406 info.GetReturnValue().Set(1);
4407 return;
4408 }
4409
4410 v8::Local<v8::Value> argFirst = GetSimpleValue(info, 0);
4411 v8::Local<v8::Value> argSecond = GetSimpleValue(info, 1);
4412 if (fxv8::IsNull(argFirst) || fxv8::IsNull(argSecond)) {
4413 info.GetReturnValue().Set(
4414 static_cast<int>(fxv8::IsNull(argFirst) && fxv8::IsNull(argSecond)));
4415 return;
4416 }
4417
4418 if (fxv8::IsString(argFirst) && fxv8::IsString(argSecond)) {
4419 info.GetReturnValue().Set(static_cast<int>(
4420 fxv8::ReentrantToByteStringHelper(info.GetIsolate(), argFirst) ==
4421 fxv8::ReentrantToByteStringHelper(info.GetIsolate(), argSecond)));
4422 return;
4423 }
4424
4425 double first = ValueToDouble(info.GetIsolate(), argFirst);
4426 double second = ValueToDouble(info.GetIsolate(), argSecond);
4427 info.GetReturnValue().Set(static_cast<int>(first == second));
4428}
4429
4430// static
4431void CFXJSE_FormCalcContext::notequality_operator(
4432 CFXJSE_HostObject* pThis,
4433 const v8::FunctionCallbackInfo<v8::Value>& info) {
4434 if (info.Length() != 2) {
4435 ToFormCalcContext(pThis)->ThrowCompilerErrorException();
4436 return;
4437 }
4438
4439 if (fm_ref_equal(pThis, info)) {
4440 info.GetReturnValue().Set(0);
4441 return;
4442 }
4443
4444 v8::Local<v8::Value> argFirst = GetSimpleValue(info, 0);
4445 v8::Local<v8::Value> argSecond = GetSimpleValue(info, 1);
4446 if (fxv8::IsNull(argFirst) || fxv8::IsNull(argSecond)) {
4447 info.GetReturnValue().Set(
4448 static_cast<int>(!fxv8::IsNull(argFirst) || !fxv8::IsNull(argSecond)));
4449 return;
4450 }
4451
4452 if (fxv8::IsString(argFirst) && fxv8::IsString(argSecond)) {
4453 info.GetReturnValue().Set(static_cast<int>(
4454 fxv8::ReentrantToByteStringHelper(info.GetIsolate(), argFirst) !=
4455 fxv8::ReentrantToByteStringHelper(info.GetIsolate(), argSecond)));
4456 return;
4457 }
4458
4459 double first = ValueToDouble(info.GetIsolate(), argFirst);
4460 double second = ValueToDouble(info.GetIsolate(), argSecond);
4461 info.GetReturnValue().Set(static_cast<int>(first != second));
4462}
4463
4464// static
4465bool CFXJSE_FormCalcContext::fm_ref_equal(
4466 CFXJSE_HostObject* pThis,
4467 const v8::FunctionCallbackInfo<v8::Value>& info) {
4468 v8::Local<v8::Value> argFirst = info[0];
4469 v8::Local<v8::Value> argSecond = info[1];
4470 if (!fxv8::IsArray(argFirst) || !fxv8::IsArray(argSecond))
4471 return false;
4472
4473 v8::Local<v8::Array> firstArr = argFirst.As<v8::Array>();
4474 v8::Local<v8::Array> secondArr = argSecond.As<v8::Array>();
4475 v8::Local<v8::Value> firstFlag =
4476 fxv8::ReentrantGetArrayElementHelper(info.GetIsolate(), firstArr, 0);
4477 v8::Local<v8::Value> secondFlag =
4478 fxv8::ReentrantGetArrayElementHelper(info.GetIsolate(), secondArr, 0);
4479 if (fxv8::ReentrantToInt32Helper(info.GetIsolate(), firstFlag) != 3 ||
4480 fxv8::ReentrantToInt32Helper(info.GetIsolate(), secondFlag) != 3) {
4481 return false;
4482 }
4483
4484 v8::Local<v8::Value> firstValue =
4485 fxv8::ReentrantGetArrayElementHelper(info.GetIsolate(), firstArr, 2);
4486 v8::Local<v8::Value> secondValue =
4487 fxv8::ReentrantGetArrayElementHelper(info.GetIsolate(), secondArr, 2);
4488
4489 if (fxv8::IsNull(firstValue) || fxv8::IsNull(secondValue))
4490 return false;
4491
4492 return FXJSE_RetrieveObjectBinding(firstValue) ==
4493 FXJSE_RetrieveObjectBinding(secondValue);
4494}
4495
4496// static
4497void CFXJSE_FormCalcContext::less_operator(
4498 CFXJSE_HostObject* pThis,
4499 const v8::FunctionCallbackInfo<v8::Value>& info) {
4500 if (info.Length() != 2) {
4501 ToFormCalcContext(pThis)->ThrowCompilerErrorException();
4502 return;
4503 }
4504
4505 v8::Local<v8::Value> argFirst = GetSimpleValue(info, 0);
4506 v8::Local<v8::Value> argSecond = GetSimpleValue(info, 1);
4507 if (fxv8::IsNull(argFirst) || fxv8::IsNull(argSecond)) {
4508 info.GetReturnValue().Set(0);
4509 return;
4510 }
4511
4512 if (fxv8::IsString(argFirst) && fxv8::IsString(argSecond)) {
4513 ByteString bs1 =
4514 fxv8::ReentrantToByteStringHelper(info.GetIsolate(), argFirst);
4515 ByteString bs2 =
4516 fxv8::ReentrantToByteStringHelper(info.GetIsolate(), argSecond);
4517 info.GetReturnValue().Set(bs1.Compare(bs2.AsStringView()) < 0);
4518 return;
4519 }
4520
4521 double first = ValueToDouble(info.GetIsolate(), argFirst);
4522 double second = ValueToDouble(info.GetIsolate(), argSecond);
4523 info.GetReturnValue().Set(static_cast<int>(first < second));
4524}
4525
4526// static
4527void CFXJSE_FormCalcContext::lessequal_operator(
4528 CFXJSE_HostObject* pThis,
4529 const v8::FunctionCallbackInfo<v8::Value>& info) {
4530 if (info.Length() != 2) {
4531 ToFormCalcContext(pThis)->ThrowCompilerErrorException();
4532 return;
4533 }
4534
4535 v8::Local<v8::Value> argFirst = GetSimpleValue(info, 0);
4536 v8::Local<v8::Value> argSecond = GetSimpleValue(info, 1);
4537 if (fxv8::IsNull(argFirst) || fxv8::IsNull(argSecond)) {
4538 info.GetReturnValue().Set(
4539 static_cast<int>(fxv8::IsNull(argFirst) && fxv8::IsNull(argSecond)));
4540 return;
4541 }
4542
4543 if (fxv8::IsString(argFirst) && fxv8::IsString(argSecond)) {
4544 auto bs1 = fxv8::ReentrantToByteStringHelper(info.GetIsolate(), argFirst);
4545 auto bs2 = fxv8::ReentrantToByteStringHelper(info.GetIsolate(), argSecond);
4546 info.GetReturnValue().Set(bs1.Compare(bs2.AsStringView()) <= 0);
4547 return;
4548 }
4549
4550 double first = ValueToDouble(info.GetIsolate(), argFirst);
4551 double second = ValueToDouble(info.GetIsolate(), argSecond);
4552 info.GetReturnValue().Set(static_cast<int>(first <= second));
4553}
4554
4555// static
4556void CFXJSE_FormCalcContext::greater_operator(
4557 CFXJSE_HostObject* pThis,
4558 const v8::FunctionCallbackInfo<v8::Value>& info) {
4559 if (info.Length() != 2) {
4560 ToFormCalcContext(pThis)->ThrowCompilerErrorException();
4561 return;
4562 }
4563
4564 v8::Local<v8::Value> argFirst = GetSimpleValue(info, 0);
4565 v8::Local<v8::Value> argSecond = GetSimpleValue(info, 1);
4566 if (fxv8::IsNull(argFirst) || fxv8::IsNull(argSecond)) {
4567 info.GetReturnValue().Set(0);
4568 return;
4569 }
4570
4571 if (fxv8::IsString(argFirst) && fxv8::IsString(argSecond)) {
4572 auto bs1 = fxv8::ReentrantToByteStringHelper(info.GetIsolate(), argFirst);
4573 auto bs2 = fxv8::ReentrantToByteStringHelper(info.GetIsolate(), argSecond);
4574 info.GetReturnValue().Set(bs1.Compare(bs2.AsStringView()) > 0);
4575 return;
4576 }
4577
4578 double first = ValueToDouble(info.GetIsolate(), argFirst);
4579 double second = ValueToDouble(info.GetIsolate(), argSecond);
4580 info.GetReturnValue().Set(static_cast<int>(first > second));
4581}
4582
4583// static
4584void CFXJSE_FormCalcContext::greaterequal_operator(
4585 CFXJSE_HostObject* pThis,
4586 const v8::FunctionCallbackInfo<v8::Value>& info) {
4587 if (info.Length() != 2) {
4588 ToFormCalcContext(pThis)->ThrowCompilerErrorException();
4589 return;
4590 }
4591
4592 v8::Local<v8::Value> argFirst = GetSimpleValue(info, 0);
4593 v8::Local<v8::Value> argSecond = GetSimpleValue(info, 1);
4594 if (fxv8::IsNull(argFirst) || fxv8::IsNull(argSecond)) {
4595 info.GetReturnValue().Set(
4596 static_cast<int>(fxv8::IsNull(argFirst) && fxv8::IsNull(argSecond)));
4597 return;
4598 }
4599
4600 if (fxv8::IsString(argFirst) && fxv8::IsString(argSecond)) {
4601 auto bs1 = fxv8::ReentrantToByteStringHelper(info.GetIsolate(), argFirst);
4602 auto bs2 = fxv8::ReentrantToByteStringHelper(info.GetIsolate(), argSecond);
4603 info.GetReturnValue().Set(bs1.Compare(bs2.AsStringView()) >= 0);
4604 return;
4605 }
4606
4607 double first = ValueToDouble(info.GetIsolate(), argFirst);
4608 double second = ValueToDouble(info.GetIsolate(), argSecond);
4609 info.GetReturnValue().Set(static_cast<int>(first >= second));
4610}
4611
4612// static
4613void CFXJSE_FormCalcContext::plus_operator(
4614 CFXJSE_HostObject* pThis,
4615 const v8::FunctionCallbackInfo<v8::Value>& info) {
4616 if (info.Length() != 2) {
4617 ToFormCalcContext(pThis)->ThrowCompilerErrorException();
4618 return;
4619 }
4620
4621 if (ValueIsNull(info.GetIsolate(), info[0]) &&
4622 ValueIsNull(info.GetIsolate(), info[1])) {
4623 info.GetReturnValue().SetNull();
4624 return;
4625 }
4626
4627 const double first = ValueToDouble(info.GetIsolate(), info[0]);
4628 const double second = ValueToDouble(info.GetIsolate(), info[1]);
4629 info.GetReturnValue().Set(first + second);
4630}
4631
4632// static
4633void CFXJSE_FormCalcContext::minus_operator(
4634 CFXJSE_HostObject* pThis,
4635 const v8::FunctionCallbackInfo<v8::Value>& info) {
4636 if (info.Length() != 2) {
4637 ToFormCalcContext(pThis)->ThrowCompilerErrorException();
4638 return;
4639 }
4640
4641 v8::Local<v8::Value> argFirst = GetSimpleValue(info, 0);
4642 v8::Local<v8::Value> argSecond = GetSimpleValue(info, 1);
4643 if (fxv8::IsNull(argFirst) && fxv8::IsNull(argSecond)) {
4644 info.GetReturnValue().SetNull();
4645 return;
4646 }
4647
4648 double first = ValueToDouble(info.GetIsolate(), argFirst);
4649 double second = ValueToDouble(info.GetIsolate(), argSecond);
4650 info.GetReturnValue().Set(first - second);
4651}
4652
4653// static
4654void CFXJSE_FormCalcContext::multiple_operator(
4655 CFXJSE_HostObject* pThis,
4656 const v8::FunctionCallbackInfo<v8::Value>& info) {
4657 if (info.Length() != 2) {
4658 ToFormCalcContext(pThis)->ThrowCompilerErrorException();
4659 return;
4660 }
4661
4662 v8::Local<v8::Value> argFirst = GetSimpleValue(info, 0);
4663 v8::Local<v8::Value> argSecond = GetSimpleValue(info, 1);
4664 if (fxv8::IsNull(argFirst) && fxv8::IsNull(argSecond)) {
4665 info.GetReturnValue().SetNull();
4666 return;
4667 }
4668
4669 double first = ValueToDouble(info.GetIsolate(), argFirst);
4670 double second = ValueToDouble(info.GetIsolate(), argSecond);
4671 info.GetReturnValue().Set(first * second);
4672}
4673
4674// static
4675void CFXJSE_FormCalcContext::divide_operator(
4676 CFXJSE_HostObject* pThis,
4677 const v8::FunctionCallbackInfo<v8::Value>& info) {
4678 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
4679 if (info.Length() != 2) {
4680 pContext->ThrowCompilerErrorException();
4681 return;
4682 }
4683
4684 v8::Local<v8::Value> argFirst = GetSimpleValue(info, 0);
4685 v8::Local<v8::Value> argSecond = GetSimpleValue(info, 1);
4686 if (fxv8::IsNull(argFirst) && fxv8::IsNull(argSecond)) {
4687 info.GetReturnValue().SetNull();
4688 return;
4689 }
4690
4691 double second = ValueToDouble(info.GetIsolate(), argSecond);
4692 if (second == 0.0) {
4693 pContext->ThrowDivideByZeroException();
4694 return;
4695 }
4696
4697 double first = ValueToDouble(info.GetIsolate(), argFirst);
4698 info.GetReturnValue().Set(first / second);
4699}
4700
4701// static
4702void CFXJSE_FormCalcContext::positive_operator(
4703 CFXJSE_HostObject* pThis,
4704 const v8::FunctionCallbackInfo<v8::Value>& info) {
4705 if (info.Length() != 1) {
4706 ToFormCalcContext(pThis)->ThrowCompilerErrorException();
4707 return;
4708 }
4709
4710 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
4711 if (fxv8::IsNull(argOne)) {
4712 info.GetReturnValue().SetNull();
4713 return;
4714 }
4715 info.GetReturnValue().Set(0.0 + ValueToDouble(info.GetIsolate(), argOne));
4716}
4717
4718// static
4719void CFXJSE_FormCalcContext::negative_operator(
4720 CFXJSE_HostObject* pThis,
4721 const v8::FunctionCallbackInfo<v8::Value>& info) {
4722 if (info.Length() != 1) {
4723 ToFormCalcContext(pThis)->ThrowCompilerErrorException();
4724 return;
4725 }
4726
4727 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
4728 if (fxv8::IsNull(argOne)) {
4729 info.GetReturnValue().SetNull();
4730 return;
4731 }
4732 info.GetReturnValue().Set(0.0 - ValueToDouble(info.GetIsolate(), argOne));
4733}
4734
4735// static
4736void CFXJSE_FormCalcContext::logical_not_operator(
4737 CFXJSE_HostObject* pThis,
4738 const v8::FunctionCallbackInfo<v8::Value>& info) {
4739 if (info.Length() != 1) {
4740 ToFormCalcContext(pThis)->ThrowCompilerErrorException();
4741 return;
4742 }
4743
4744 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
4745 if (fxv8::IsNull(argOne)) {
4746 info.GetReturnValue().SetNull();
4747 return;
4748 }
4749
4750 double first = ValueToDouble(info.GetIsolate(), argOne);
4751 info.GetReturnValue().Set((first == 0.0) ? 1 : 0);
4752}
4753
4754// static
4755void CFXJSE_FormCalcContext::dot_accessor(
4756 CFXJSE_HostObject* pThis,
4757 const v8::FunctionCallbackInfo<v8::Value>& info) {
4758 DotAccessorCommon(pThis, info, /*bDotAccessor=*/true);
4759}
4760
4761// static
4762void CFXJSE_FormCalcContext::dotdot_accessor(
4763 CFXJSE_HostObject* pThis,
4764 const v8::FunctionCallbackInfo<v8::Value>& info) {
4765 DotAccessorCommon(pThis, info, /*bDotAccessor=*/false);
4766}
4767
4768// static
4769void CFXJSE_FormCalcContext::eval_translation(
4770 CFXJSE_HostObject* pThis,
4771 const v8::FunctionCallbackInfo<v8::Value>& info) {
4772 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
4773 if (info.Length() != 1) {
4774 pContext->ThrowParamCountMismatchException("Eval");
4775 return;
4776 }
4777
4778 v8::Local<v8::Value> argOne = GetSimpleValue(info, 0);
4779 ByteString bsArg = ValueToUTF8String(info.GetIsolate(), argOne);
4780 if (bsArg.IsEmpty()) {
4781 pContext->ThrowArgumentMismatchException();
4782 return;
4783 }
4784
4785 WideString wsCalcScript = WideString::FromUTF8(bsArg.AsStringView());
4786 absl::optional<WideTextBuffer> wsJavaScriptBuf =
4787 CFXJSE_FormCalcContext::Translate(pContext->GetDocument()->GetHeap(),
4788 wsCalcScript.AsStringView());
4789 if (!wsJavaScriptBuf.has_value()) {
4790 pContext->ThrowCompilerErrorException();
4791 return;
4792 }
4793 info.GetReturnValue().Set(fxv8::NewStringHelper(
4794 info.GetIsolate(),
4795 FX_UTF8Encode(wsJavaScriptBuf.value().AsStringView()).AsStringView()));
4796}
4797
4798// static
4799void CFXJSE_FormCalcContext::is_fm_object(
4800 CFXJSE_HostObject* pThis,
4801 const v8::FunctionCallbackInfo<v8::Value>& info) {
4802 const bool result = info.Length() == 1 && fxv8::IsObject(info[0]);
4803 info.GetReturnValue().Set(result);
4804}
4805
4806// static
4807void CFXJSE_FormCalcContext::is_fm_array(
4808 CFXJSE_HostObject* pThis,
4809 const v8::FunctionCallbackInfo<v8::Value>& info) {
4810 const bool result = info.Length() == 1 && fxv8::IsArray(info[0]);
4811 info.GetReturnValue().Set(result);
4812}
4813
4814// static
4815void CFXJSE_FormCalcContext::get_fm_value(
4816 CFXJSE_HostObject* pThis,
4817 const v8::FunctionCallbackInfo<v8::Value>& info) {
4818 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
4819 if (info.Length() != 1) {
4820 pContext->ThrowCompilerErrorException();
4821 return;
4822 }
4823
4824 v8::Local<v8::Value> argOne = info[0];
4825 if (fxv8::IsArray(argOne)) {
4826 v8::Local<v8::Array> arr = argOne.As<v8::Array>();
4827 v8::Local<v8::Value> propertyValue =
4828 fxv8::ReentrantGetArrayElementHelper(info.GetIsolate(), arr, 1);
4829 v8::Local<v8::Value> jsValue =
4830 fxv8::ReentrantGetArrayElementHelper(info.GetIsolate(), arr, 2);
4831 if (!fxv8::IsObject(jsValue)) {
4832 info.GetReturnValue().Set(fxv8::NewUndefinedHelper(info.GetIsolate()));
4833 return;
4834 }
4835 v8::Local<v8::Object> jsObjectValue = jsValue.As<v8::Object>();
4836 if (fxv8::IsNull(propertyValue)) {
4837 info.GetReturnValue().Set(
4838 GetObjectDefaultValue(info.GetIsolate(), jsObjectValue));
4839 return;
4840 }
4841 ByteString bsName =
4842 fxv8::ReentrantToByteStringHelper(info.GetIsolate(), propertyValue);
4843 info.GetReturnValue().Set(fxv8::ReentrantGetObjectPropertyHelper(
4844 info.GetIsolate(), jsObjectValue, bsName.AsStringView()));
4845 return;
4846 }
4847
4848 if (fxv8::IsObject(argOne)) {
4849 v8::Local<v8::Object> obj = argOne.As<v8::Object>();
4850 info.GetReturnValue().Set(GetObjectDefaultValue(info.GetIsolate(), obj));
4851 return;
4852 }
4853
4854 info.GetReturnValue().Set(argOne);
4855}
4856
4857// static
4858void CFXJSE_FormCalcContext::get_fm_jsobj(
4859 CFXJSE_HostObject* pThis,
4860 const v8::FunctionCallbackInfo<v8::Value>& info) {
4861 if (info.Length() != 1) {
4862 ToFormCalcContext(pThis)->ThrowCompilerErrorException();
4863 return;
4864 }
4865
4866 v8::Local<v8::Value> argOne = info[0];
4867 if (!fxv8::IsArray(argOne)) {
4868 info.GetReturnValue().Set(argOne);
4869 return;
4870 }
4871
4872 v8::Local<v8::Array> arr = argOne.As<v8::Array>();
4873 info.GetReturnValue().Set(
4874 fxv8::ReentrantGetArrayElementHelper(info.GetIsolate(), arr, 2));
4875}
4876
4877// static
4878void CFXJSE_FormCalcContext::fm_var_filter(
4879 CFXJSE_HostObject* pThis,
4880 const v8::FunctionCallbackInfo<v8::Value>& info) {
4881 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
4882 if (info.Length() != 1) {
4883 pContext->ThrowCompilerErrorException();
4884 return;
4885 }
4886
4887 v8::Local<v8::Value> argOne = info[0];
4888 if (!fxv8::IsArray(argOne)) {
4889 info.GetReturnValue().Set(GetSimpleValue(info, 0));
4890 return;
4891 }
4892
4893 v8::Local<v8::Array> arr = argOne.As<v8::Array>();
4894 v8::Local<v8::Value> flagsValue =
4895 fxv8::ReentrantGetArrayElementHelper(info.GetIsolate(), arr, 0);
4896 int32_t iFlags = fxv8::ReentrantToInt32Helper(info.GetIsolate(), flagsValue);
4897 if (iFlags != 3 && iFlags != 4) {
4898 info.GetReturnValue().Set(GetSimpleValue(info, 0));
4899 return;
4900 }
4901
4902 if (iFlags == 4) {
4903 v8::LocalVector<v8::Value> values(info.GetIsolate(), 3);
4904 values[0] = fxv8::NewNumberHelper(info.GetIsolate(), 3);
4905 values[1] = fxv8::NewNullHelper(info.GetIsolate());
4906 values[2] = fxv8::NewNullHelper(info.GetIsolate());
4907 info.GetReturnValue().Set(fxv8::NewArrayHelper(info.GetIsolate(), values));
4908 return;
4909 }
4910
4911 v8::Local<v8::Value> objectValue =
4912 fxv8::ReentrantGetArrayElementHelper(info.GetIsolate(), arr, 2);
4913 if (fxv8::IsNull(objectValue)) {
4914 pContext->ThrowCompilerErrorException();
4915 return;
4916 }
4917 info.GetReturnValue().Set(argOne);
4918}
4919
4920// static
4921void CFXJSE_FormCalcContext::concat_fm_object(
4922 CFXJSE_HostObject* pThis,
4923 const v8::FunctionCallbackInfo<v8::Value>& info) {
4924 v8::Isolate* pIsolate = ToFormCalcContext(pThis)->GetIsolate();
4925 v8::LocalVector<v8::Value> returnValues(pIsolate);
4926 for (int i = 0; i < info.Length(); ++i) {
4927 if (fxv8::IsArray(info[i])) {
4928 v8::Local<v8::Array> arr = info[i].As<v8::Array>();
4929 uint32_t length = fxv8::GetArrayLengthHelper(arr);
4930 for (uint32_t j = 2; j < length; j++) {
4931 returnValues.push_back(
4932 fxv8::ReentrantGetArrayElementHelper(info.GetIsolate(), arr, j));
4933 }
4934 }
4935 returnValues.push_back(info[i]);
4936 }
4937 info.GetReturnValue().Set(fxv8::NewArrayHelper(pIsolate, returnValues));
4938}
4939
4940// static
4941ByteString CFXJSE_FormCalcContext::GenerateSomExpression(ByteStringView bsName,
4942 int32_t iIndexFlags,
4943 int32_t iIndexValue,
4944 bool bIsStar) {
4945 if (bIsStar)
4946 return ByteString(bsName, "[*]");
4947
4948 // `iIndexFlags` values are the same as enum class
4949 // `CXFA_FMIndexExpression::AccessorIndex` values.
4950 if (iIndexFlags == 0)
4951 return ByteString(bsName);
4952
4953 if (iIndexFlags == 1 || iIndexValue == 0) {
4954 return ByteString(bsName, "[") + ByteString::FormatInteger(iIndexValue) +
4955 "]";
4956 }
4957
4958 const bool bNegative = iIndexValue < 0;
4959 ByteString bsSomExp(bsName);
4960 if (iIndexFlags == 2) {
4961 bsSomExp += bNegative ? "[-" : "[+";
4962 } else {
4963 DCHECK_EQ(iIndexFlags, 3);
4964 bsSomExp += bNegative ? "[" : "[-";
4965 }
4966
4967 FX_SAFE_INT32 safe_index = iIndexValue;
4968 if (bNegative)
4969 safe_index = -safe_index;
4970 bsSomExp += ByteString::FormatInteger(safe_index.ValueOrDefault(0));
4971 bsSomExp += "]";
4972 return bsSomExp;
4973}
4974
4975absl::optional<WideTextBuffer> CFXJSE_FormCalcContext::Translate(
4976 cppgc::Heap* pHeap,
4977 WideStringView wsFormcalc) {
4978 if (wsFormcalc.IsEmpty())
4979 return WideTextBuffer();
4980
4981 CXFA_FMLexer lexer(wsFormcalc);
4982 CXFA_FMParser parser(pHeap, &lexer);
4983 CXFA_FMAST* ast = parser.Parse();
4984 if (!ast || parser.HasError())
4985 return absl::nullopt;
4986
4988 absl::optional<WideTextBuffer> wsJavaScript = ast->ToJavaScript();
4989 if (!wsJavaScript.has_value())
4990 return absl::nullopt;
4991
4992 if (CXFA_IsTooBig(wsJavaScript.value()))
4993 return absl::nullopt;
4994
4995 return wsJavaScript;
4996}
4997
4998CFXJSE_FormCalcContext::CFXJSE_FormCalcContext(v8::Isolate* pIsolate,
4999 CFXJSE_Context* pScriptContext,
5000 CXFA_Document* pDoc)
5002 m_Value.Reset(m_pIsolate,
5003 NewBoundV8Object(
5004 m_pIsolate, CFXJSE_Class::Create(
5005 pScriptContext, &kFormCalcDescriptor, false)
5006 ->GetTemplate(m_pIsolate)));
5007}
5008
5009CFXJSE_FormCalcContext::~CFXJSE_FormCalcContext() = default;
5010
5011CFXJSE_FormCalcContext* CFXJSE_FormCalcContext::AsFormCalcContext() {
5012 return this;
5013}
5014
5015v8::Local<v8::Value> CFXJSE_FormCalcContext::GlobalPropertyGetter() {
5016 return v8::Local<v8::Value>::New(m_pIsolate, m_Value);
5017}
5018
5019// static
5020void CFXJSE_FormCalcContext::DotAccessorCommon(
5021 CFXJSE_HostObject* pThis,
5022 const v8::FunctionCallbackInfo<v8::Value>& info,
5023 bool bDotAccessor) {
5024 CFXJSE_FormCalcContext* pContext = ToFormCalcContext(pThis);
5025 v8::Isolate* pIsolate = pContext->GetIsolate();
5026 int32_t argc = info.Length();
5027 if (argc < 4 || argc > 5) {
5028 pContext->ThrowCompilerErrorException();
5029 return;
5030 }
5031
5032 bool bIsStar = true;
5033 int32_t iIndexValue = 0;
5034 if (argc > 4) {
5035 bIsStar = false;
5036 iIndexValue = ValueToInteger(info.GetIsolate(), info[4]);
5037 }
5038
5039 const ByteString bsName =
5040 fxv8::ReentrantToByteStringHelper(info.GetIsolate(), info[2]);
5041 const bool bHasNoResolveName = bDotAccessor && bsName.IsEmpty();
5042 ByteString bsSomExp = GenerateSomExpression(
5043 bsName.AsStringView(),
5044 fxv8::ReentrantToInt32Helper(info.GetIsolate(), info[3]), iIndexValue,
5045 bIsStar);
5046
5047 v8::Local<v8::Value> argAccessor = info[0];
5048 if (fxv8::IsArray(argAccessor)) {
5049 v8::Local<v8::Array> arr = argAccessor.As<v8::Array>();
5050 uint32_t iLength = fxv8::GetArrayLengthHelper(arr);
5051 if (iLength < 3) {
5052 pContext->ThrowArgumentMismatchException();
5053 return;
5054 }
5055
5056 // TODO(crbug.com/pdfium/2090) - doublecheck use of std::vector
5057 std::vector<v8::LocalVector<v8::Value>> resolveValues(
5058 iLength - 2, v8::LocalVector<v8::Value>(info.GetIsolate()));
5059
5060 bool bAttribute = false;
5061 bool bAllEmpty = true;
5062 for (uint32_t i = 2; i < iLength; i++) {
5063 v8::Local<v8::Value> hJSObjValue =
5064 fxv8::ReentrantGetArrayElementHelper(info.GetIsolate(), arr, i);
5065 absl::optional<CFXJSE_Engine::ResolveResult> maybeResult =
5066 ResolveObjects(pThis, hJSObjValue, bsSomExp.AsStringView(),
5067 bDotAccessor, bHasNoResolveName);
5068 if (maybeResult.has_value()) {
5069 resolveValues[i - 2] = ParseResolveResult(pThis, maybeResult.value(),
5070 hJSObjValue, &bAttribute);
5071 bAllEmpty = bAllEmpty && resolveValues[i - 2].empty();
5072 }
5073 }
5074 if (bAllEmpty) {
5075 pContext->ThrowPropertyNotInObjectException(bsName.AsStringView(),
5076 bsSomExp.AsStringView());
5077 return;
5078 }
5079
5080 v8::LocalVector<v8::Value> values(pIsolate);
5081 values.push_back(fxv8::NewNumberHelper(pIsolate, 1));
5082 values.push_back(
5083 bAttribute ? fxv8::NewStringHelper(pIsolate, bsName.AsStringView())
5084 .As<v8::Value>()
5085 : fxv8::NewNullHelper(pIsolate).As<v8::Value>());
5086 for (uint32_t i = 0; i < iLength - 2; i++) {
5087 for (size_t j = 0; j < resolveValues[i].size(); j++)
5088 values.push_back(resolveValues[i][j]);
5089 }
5090 info.GetReturnValue().Set(fxv8::NewArrayHelper(pIsolate, values));
5091 return;
5092 }
5093
5094 absl::optional<CFXJSE_Engine::ResolveResult> maybeResult;
5095 ByteString bsAccessorName =
5096 fxv8::ReentrantToByteStringHelper(info.GetIsolate(), info[1]);
5097 if (fxv8::IsObject(argAccessor) ||
5098 (fxv8::IsNull(argAccessor) && bsAccessorName.IsEmpty())) {
5099 maybeResult = ResolveObjects(pThis, argAccessor, bsSomExp.AsStringView(),
5100 bDotAccessor, bHasNoResolveName);
5101 } else if (!fxv8::IsObject(argAccessor) && !bsAccessorName.IsEmpty()) {
5102 v8::Local<v8::Value> obj =
5103 GetObjectForName(pThis, bsAccessorName.AsStringView());
5104 if (!obj.IsEmpty()) {
5105 argAccessor = obj;
5106 maybeResult = ResolveObjects(pThis, argAccessor, bsSomExp.AsStringView(),
5107 bDotAccessor, bHasNoResolveName);
5108 }
5109 }
5110 if (!maybeResult.has_value()) {
5111 pContext->ThrowPropertyNotInObjectException(bsName.AsStringView(),
5112 bsSomExp.AsStringView());
5113 return;
5114 }
5115
5116 bool bAttribute = false;
5117 v8::LocalVector<v8::Value> resolveValues =
5118 ParseResolveResult(pThis, maybeResult.value(), argAccessor, &bAttribute);
5119
5120 v8::LocalVector<v8::Value> values(pIsolate, resolveValues.size() + 2);
5121 values[0] = fxv8::NewNumberHelper(pIsolate, 1);
5122 values[1] = bAttribute
5123 ? fxv8::NewStringHelper(pIsolate, bsName.AsStringView())
5124 .As<v8::Value>()
5125 : fxv8::NewNullHelper(pIsolate).As<v8::Value>();
5126
5127 for (size_t i = 0; i < resolveValues.size(); i++)
5128 values[i + 2] = resolveValues[i];
5129
5130 info.GetReturnValue().Set(fxv8::NewArrayHelper(pIsolate, values));
5131}
5132
5133// static
5134bool CFXJSE_FormCalcContext::IsIsoDateFormat(ByteStringView bsData,
5135 int32_t* pYear,
5136 int32_t* pMonth,
5137 int32_t* pDay) {
5138 pdfium::span<const char> pData = bsData.span();
5139
5140 int32_t& iYear = *pYear;
5141 int32_t& iMonth = *pMonth;
5142 int32_t& iDay = *pDay;
5143
5144 iYear = 0;
5145 iMonth = 1;
5146 iDay = 1;
5147
5148 if (pData.size() < 4) {
5149 return false;
5150 }
5151
5152 char szYear[5];
5153 szYear[4] = '\0';
5154 for (int32_t i = 0; i < 4; ++i) {
5155 if (!isdigit(pData[i])) {
5156 return false;
5157 }
5158
5159 szYear[i] = pData[i];
5160 }
5161 iYear = FXSYS_atoi(szYear);
5162 if (pData.size() == 4) {
5163 return true;
5164 }
5165
5166 int32_t iStyle = pData[4] == '-' ? 1 : 0;
5167 size_t iPosOff = iStyle == 0 ? 4 : 5;
5168 if (!isdigit(pData[iPosOff]) || !isdigit(pData[iPosOff + 1])) {
5169 return false;
5170 }
5171
5172 char szBuffer[3] = {};
5173 szBuffer[0] = pData[iPosOff];
5174 szBuffer[1] = pData[iPosOff + 1];
5175 iMonth = FXSYS_atoi(szBuffer);
5176 if (iMonth > 12 || iMonth < 1) {
5177 return false;
5178 }
5179
5180 if (iStyle == 0) {
5181 iPosOff += 2;
5182 if (pData.size() == 6) {
5183 return true;
5184 }
5185 } else {
5186 iPosOff += 3;
5187 if (pData.size() == 7) {
5188 return true;
5189 }
5190 }
5191 if (!isdigit(pData[iPosOff]) || !isdigit(pData[iPosOff + 1])) {
5192 return false;
5193 }
5194
5195 szBuffer[0] = pData[iPosOff];
5196 szBuffer[1] = pData[iPosOff + 1];
5197 iDay = FXSYS_atoi(szBuffer);
5198 if (iPosOff + 2 < pData.size()) {
5199 return false;
5200 }
5201
5202 if (iMonth == 2) {
5203 bool bIsLeap = (!(iYear % 4) && (iYear % 100)) || !(iYear % 400);
5204 return iDay <= (bIsLeap ? 29 : 28);
5205 }
5206
5207 if (iMonth < 8) {
5208 return iDay <= (iMonth % 2 == 0 ? 30 : 31);
5209 }
5210 return iDay <= (iMonth % 2 == 0 ? 31 : 30);
5211}
5212
5213// static
5214bool CFXJSE_FormCalcContext::IsIsoTimeFormat(ByteStringView bsData) {
5215 enum State { kHour, kMinute, kSecond, kZoneHour, kZoneMinute, kFinished };
5216
5217 pdfium::span<const char> pData = bsData.span();
5218 if (pData.empty()) {
5219 return false;
5220 }
5221
5222 size_t iZone = 0;
5223 size_t i = 0;
5224 while (i < pData.size()) {
5225 if (!isdigit(pData[i]) && pData[i] != ':') {
5226 iZone = i;
5227 break;
5228 }
5229 ++i;
5230 }
5231 if (i == pData.size()) {
5232 iZone = pData.size();
5233 }
5234
5235 char szBuffer[3] = {}; // Last char always stays NUL for termination.
5236 State state = kHour;
5237 size_t iIndex = 0;
5238 while (iIndex + 1 < iZone) {
5239 szBuffer[0] = pData[iIndex];
5240 szBuffer[1] = pData[iIndex + 1];
5241 if (!isdigit(szBuffer[0]) || !isdigit(szBuffer[1])) {
5242 return false;
5243 }
5244 int32_t value = FXSYS_atoi(szBuffer);
5245 if (state == kHour) {
5246 if (value >= 24) {
5247 return false;
5248 }
5249 state = kMinute;
5250 } else if (state == kMinute) {
5251 if (value >= 60) {
5252 return false;
5253 }
5254 state = kSecond;
5255 } else if (state == kSecond) {
5256 // Allow leap second.
5257 if (value > 60) {
5258 return false;
5259 }
5260 state = kFinished;
5261 } else {
5262 return false;
5263 }
5264 iIndex += 2;
5265 if (iIndex < iZone && pData[iIndex] == ':') {
5266 ++iIndex;
5267 }
5268 }
5269
5270 if (iIndex < pData.size() && pData[iIndex] == '.') {
5271 constexpr int kSubSecondLength = 3;
5272 if (iIndex + kSubSecondLength >= pData.size()) {
5273 return false;
5274 }
5275
5276 ++iIndex;
5277 char szMilliSeconds[kSubSecondLength + 1] = {};
5278 for (int j = 0; j < kSubSecondLength; ++j) {
5279 char c = pData[iIndex + j];
5280 if (!isdigit(c)) {
5281 return false;
5282 }
5283 szMilliSeconds[j] = c;
5284 }
5285 if (FXSYS_atoi(szMilliSeconds) >= 1000) {
5286 return false;
5287 }
5288 iIndex += kSubSecondLength;
5289 }
5290
5291 if (iIndex < pData.size() && FXSYS_towlower(pData[iIndex]) == 'z') {
5292 return true;
5293 }
5294
5295 if (iIndex < pData.size()) {
5296 if (pData[iIndex] == '+') {
5297 ++iIndex;
5298 } else if (pData[iIndex] == '-') {
5299 ++iIndex;
5300 }
5301 }
5302 state = kZoneHour;
5303 while (iIndex + 1 < pData.size()) {
5304 szBuffer[0] = pData[iIndex];
5305 szBuffer[1] = pData[iIndex + 1];
5306 if (!isdigit(szBuffer[0]) || !isdigit(szBuffer[1])) {
5307 return false;
5308 }
5309 int32_t value = FXSYS_atoi(szBuffer);
5310 if (state == kZoneHour) {
5311 if (value >= 24) {
5312 return false;
5313 }
5314 state = kZoneMinute;
5315 } else if (state == kZoneMinute) {
5316 if (value >= 60) {
5317 return false;
5318 }
5319 state = kFinished;
5320 } else {
5321 return false;
5322 }
5323 iIndex += 2;
5324 if (iIndex < pData.size() && pData[iIndex] == ':') {
5325 ++iIndex;
5326 }
5327 }
5328
5329 // Success if all input was processed.
5330 return iIndex == pData.size();
5331}
5332
5333bool CFXJSE_FormCalcContext::IsIsoDateTimeFormat(ByteStringView bsData,
5334 int32_t* pYear,
5335 int32_t* pMonth,
5336 int32_t* pDay) {
5337 *pYear = 0;
5338 *pMonth = 0;
5339 *pDay = 0;
5340
5341 size_t iIndex = 0;
5342 while (iIndex < bsData.GetLength()) {
5343 if (bsData[iIndex] == 'T' || bsData[iIndex] == 't') {
5344 break;
5345 }
5346 ++iIndex;
5347 }
5348 if (iIndex == bsData.GetLength() || (iIndex != 8 && iIndex != 10)) {
5349 return false;
5350 }
5351
5352 ByteStringView date_part = bsData.First(iIndex);
5353 ByteStringView time_part = bsData.Substr(iIndex + 1);
5354 return IsIsoDateFormat(date_part, pYear, pMonth, pDay) &&
5355 IsIsoTimeFormat(time_part);
5356}
5357
5358// static
5359int32_t CFXJSE_FormCalcContext::DateString2Num(ByteStringView bsDate) {
5360 int32_t iYear = 0;
5361 int32_t iMonth = 0;
5362 int32_t iDay = 0;
5363 if (bsDate.GetLength() <= 10) {
5364 if (!IsIsoDateFormat(bsDate, &iYear, &iMonth, &iDay)) {
5365 return 0;
5366 }
5367 } else {
5368 if (!IsIsoDateTimeFormat(bsDate, &iYear, &iMonth, &iDay)) {
5369 return 0;
5370 }
5371 }
5372
5373 float dDays = 0;
5374 int32_t i = 1;
5375 if (iYear < 1900) {
5376 return 0;
5377 }
5378
5379 while (iYear - i >= 1900) {
5380 dDays +=
5381 ((!((iYear - i) % 4) && ((iYear - i) % 100)) || !((iYear - i) % 400))
5382 ? 366
5383 : 365;
5384 ++i;
5385 }
5386 i = 1;
5387 while (i < iMonth) {
5388 if (i == 2) {
5389 dDays += ((!(iYear % 4) && (iYear % 100)) || !(iYear % 400)) ? 29 : 28;
5390 } else if (i <= 7) {
5391 dDays += (i % 2 == 0) ? 30 : 31;
5392 } else {
5393 dDays += (i % 2 == 0) ? 31 : 30;
5394 }
5395
5396 ++i;
5397 }
5398 i = 0;
5399 while (iDay - i > 0) {
5400 ++dDays;
5401 ++i;
5402 }
5403 return static_cast<int32_t>(dDays);
5404}
5405
5406bool CFXJSE_FormCalcContext::ApplyToExpansion(
5407 std::function<void(v8::Isolate*, v8::Local<v8::Value>)> fn,
5408 const v8::FunctionCallbackInfo<v8::Value>& info,
5409 bool bStrict) {
5410 v8::Isolate* pIsolate = info.GetIsolate();
5411 for (int32_t i = 0; i < info.Length(); i++) {
5412 v8::Local<v8::Value> argValue = info[i];
5413 if (fxv8::IsArray(argValue)) {
5414 if (!ApplyToArray(pIsolate, fn, argValue.As<v8::Array>()) && bStrict) {
5415 ThrowArgumentMismatchException();
5416 return false;
5417 }
5418 } else if (fxv8::IsObject(argValue)) {
5419 ApplyToObject(pIsolate, fn, argValue.As<v8::Object>());
5420 } else if (!fxv8::IsNull(argValue)) {
5421 fn(pIsolate, argValue);
5422 }
5423 }
5424 return true;
5425}
5426
5427bool CFXJSE_FormCalcContext::ApplyToArray(
5428 v8::Isolate* pIsolate,
5429 std::function<void(v8::Isolate*, v8::Local<v8::Value>)> fn,
5430 v8::Local<v8::Array> pArray) {
5431 uint32_t iLength = fxv8::GetArrayLengthHelper(pArray);
5432 if (iLength < 3)
5433 return false;
5434
5435 v8::Local<v8::Value> propertyValue =
5436 fxv8::ReentrantGetArrayElementHelper(pIsolate, pArray, 1);
5437
5438 ByteString bsName;
5439 const bool nullprop = fxv8::IsNull(propertyValue);
5440 if (!nullprop)
5441 bsName = fxv8::ReentrantToByteStringHelper(pIsolate, propertyValue);
5442
5443 for (uint32_t j = 2; j < iLength; j++) {
5444 v8::Local<v8::Value> jsValue =
5445 fxv8::ReentrantGetArrayElementHelper(pIsolate, pArray, j);
5446 if (!fxv8::IsObject(jsValue))
5447 continue;
5448
5449 v8::Local<v8::Object> jsObjectValue = jsValue.As<v8::Object>();
5450 v8::Local<v8::Value> newPropertyValue =
5451 nullprop ? GetObjectDefaultValue(pIsolate, jsObjectValue)
5452 : fxv8::ReentrantGetObjectPropertyHelper(
5453 pIsolate, jsObjectValue, bsName.AsStringView());
5454 if (!fxv8::IsNull(newPropertyValue))
5455 fn(pIsolate, newPropertyValue);
5456 }
5457 return true;
5458}
5459
5460void CFXJSE_FormCalcContext::ApplyToObject(
5461 v8::Isolate* pIsolate,
5462 std::function<void(v8::Isolate*, v8::Local<v8::Value>)> fn,
5463 v8::Local<v8::Object> pObject) {
5464 v8::Local<v8::Value> newPropertyValue =
5465 GetObjectDefaultValue(pIsolate, pObject);
5466 if (!fxv8::IsNull(newPropertyValue))
5467 fn(pIsolate, newPropertyValue);
5468}
5469
5470void CFXJSE_FormCalcContext::ThrowNoDefaultPropertyException(
5471 ByteStringView name) const {
5472 ByteString msg(name);
5473 msg += " doesn't have a default property.";
5474 ThrowException(msg.AsStringView());
5475}
5476
5477void CFXJSE_FormCalcContext::ThrowCompilerErrorException() const {
5478 ThrowException("Compiler error.");
5479}
5480
5481void CFXJSE_FormCalcContext::ThrowDivideByZeroException() const {
5482 ThrowException("Divide by zero.");
5483}
5484
5485void CFXJSE_FormCalcContext::ThrowServerDeniedException() const {
5486 ThrowException("Server does not permit operation.");
5487}
5488
5489void CFXJSE_FormCalcContext::ThrowPropertyNotInObjectException(
5490 ByteStringView name,
5491 ByteStringView exp) const {
5492 ByteString msg("An attempt was made to reference property '");
5493 msg += name;
5494 msg += "' of a non-object in SOM expression ";
5495 msg += exp;
5496 msg += ".";
5497 ThrowException(msg.AsStringView());
5498}
5499
5500void CFXJSE_FormCalcContext::ThrowParamCountMismatchException(
5501 ByteStringView method) const {
5502 ByteString msg("Incorrect number of parameters calling method '");
5503 msg += method;
5504 msg += "'.";
5505 ThrowException(msg.AsStringView());
5506}
5507
5508void CFXJSE_FormCalcContext::ThrowArgumentMismatchException() const {
5509 ThrowException("Argument mismatch in property or function argument.");
5510}
5511
5512void CFXJSE_FormCalcContext::ThrowException(ByteStringView str) const {
5513 DCHECK(!str.IsEmpty());
5514 FXJSE_ThrowMessage(GetIsolate(), str);
5515}
XFA_ResolveFlag
const FXJSE_CLASS_DESCRIPTOR kFormCalcDescriptor
CFGAS_Decimal(float val, uint8_t scale)
double ToDouble() const
XFA_SCRIPTATTRIBUTEINFO script_attribute
CXFA_Object * GetThisObject() const
friend class EventParamScope
v8::Local< v8::Value > GlobalPropertyGetter()
static ByteString Local2IsoDate(CFXJSE_HostObject *pThis, ByteStringView bsDate, ByteStringView bsFormat, ByteStringView bsLocale)
static ByteString Num2AllTime(CFXJSE_HostObject *pThis, int32_t iTime, ByteStringView bsFormat, ByteStringView bsLocale, bool bGM)
CXFA_Document * GetDocument() const
static ByteString GetStandardTimeFormat(CFXJSE_HostObject *pThis, int32_t iStyle, ByteStringView bsLocale)
static ByteString GetStandardDateFormat(CFXJSE_HostObject *pThis, int32_t iStyle, ByteStringView bsLocale)
CFXJSE_FormCalcContext * AsFormCalcContext() override
static ByteString GetLocalDateFormat(CFXJSE_HostObject *pThis, int32_t iStyle, ByteStringView bsLocale, bool bStandard)
~CFXJSE_FormCalcContext() override
CFXJSE_FormCalcContext(v8::Isolate *pIsolate, CFXJSE_Context *pScriptContext, CXFA_Document *pDoc)
static ByteString GetLocalTimeFormat(CFXJSE_HostObject *pThis, int32_t iStyle, ByteStringView bsLocale, bool bStandard)
static ByteString IsoDate2Local(CFXJSE_HostObject *pThis, ByteStringView bsDate, ByteStringView bsFormat, ByteStringView bsLocale)
static ByteString IsoTime2Local(CFXJSE_HostObject *pThis, ByteStringView bsTime, ByteStringView bsFormat, ByteStringView bsLocale)
virtual CFXJSE_FormCalcContext * AsFormCalcContext()
Definition fxjse.cpp:34
int32_t GetYear() const
uint8_t GetSecond() const
uint8_t GetHour() const
uint8_t GetDay() const
uint8_t GetMinute() const
uint16_t GetMillisecond() const
uint8_t GetMonth() const
CXFA_FFNotify * GetNotify() const
CXFA_LocaleMgr * GetLocaleMgr()
CFXJSE_Engine * GetScriptContext() const
virtual bool PostRequestURL(const WideString &wsURL, const WideString &wsData, const WideString &wsContentType, const WideString &wsEncode, const WideString &wsHeader, WideString &wsResponse)=0
virtual bool PutRequestURL(const WideString &wsURL, const WideString &wsData, const WideString &wsEncode)=0
CXFA_FFApp::CallbackIface * GetAppProvider()
CXFA_FMParser(cppgc::Heap *heap, CXFA_FMLexer *pLexer)
CXFA_FMAST * Parse()
GCedLocaleIface * GetDefLocale() override
GCedLocaleIface * GetLocaleByName(const WideString &wsLocaleName) override
CXFA_LocaleValue(ValueType dwType, const WideString &wsValue, const WideString &wsFormat, GCedLocaleIface *pLocale, CXFA_LocaleMgr *pLocaleMgr)
double GetDoubleNum() const
CFX_DateTime GetTime() const
const WideString & GetValue() const
CFX_DateTime GetDate() const
bool FormatPatterns(WideString &wsResult, const WideString &wsFormat, GCedLocaleIface *pLocale, XFA_ValuePicture eValueType) const
bool IsValid() const
GCedLocaleIface * GetLocale()
CXFA_Node * AsNode()
virtual WideString GetDatePattern(DateTimeSubcategory eType) const =0
virtual int GetTimeZoneInMinutes() const =0
virtual WideString GetDateTimeSymbols() const =0
virtual WideString GetTimePattern(DateTimeSubcategory eType) const =0
ByteString(const char *ptr)
bool EqualNoCase(ByteStringView str) const
static ByteString Format(const char *pFormat,...)
ByteString & operator+=(const ByteString &str)
ByteString & operator+=(char ch)
static ByteString FormatInteger(int i)
bool operator==(const ByteString &other) const
bool operator==(const char *ptr) const
ByteString & operator+=(const char *str)
const char * c_str() const
Definition bytestring.h:76
ByteString & operator=(const ByteString &that)
bool IsEmpty() const
Definition bytestring.h:119
int Compare(ByteStringView str) const
ByteString ToUTF8() const
WideString & operator=(WideString &&that) noexcept
static WideString FromUTF8(ByteStringView str)
CharType operator[](const size_t index) const
Definition widestring.h:146
bool IsEmpty() const
Definition widestring.h:118
const wchar_t * c_str() const
Definition widestring.h:81
WideString(const wchar_t *ptr)
bool IsASCII() const
Definition widestring.h:215
ByteString ToASCII() const
static WideString FromASCII(ByteStringView str)
void AppendChar(wchar_t wch)
WideString MakeString() const
WideStringView AsStringView() const
XFA_ValuePicture
Definition cxfa_node.h:70
CXFA_Node * ToNode(CXFA_Object *pObj)
time_t FXSYS_time(time_t *tloc)
int FXSYS_WideHexCharToInt(wchar_t c)
bool FXSYS_IsDecimalDigit(wchar_t c)
bool FXSYS_IsWideHexDigit(wchar_t c)
struct tm * FXSYS_localtime(const time_t *tp)
void FX_Random_GenerateMT(uint32_t *pBuffer, int32_t iCount)
int32_t FXSYS_atoi(const char *str)
#define FX_FILESIZE
Definition fx_types.h:19
XFA_Attribute
Definition fxfa_basic.h:67
XFA_ScriptType
Definition fxfa_basic.h:104
Definition heap.h:12
ByteString operator+(const ByteString &str1, const ByteString &str2)
Definition bytestring.h:270
WideString operator+(const WideString &str1, const WideString &str2)
Definition widestring.h:269
ByteString operator+(const ByteString &str1, const char *str2)
Definition bytestring.h:279
WideString operator+(const wchar_t *str1, const WideString &str2)
Definition widestring.h:281
WideString operator+(const WideString &str1, const wchar_t *str2)
Definition widestring.h:278
Definition fxv8.h:22
bool IsBoolean(v8::Local< v8::Value > value)
Definition fxv8.cpp:27
bool IsArray(v8::Local< v8::Value > value)
Definition fxv8.cpp:47
bool IsUndefined(v8::Local< v8::Value > value)
Definition fxv8.cpp:19
bool IsNumber(v8::Local< v8::Value > value)
Definition fxv8.cpp:35
bool IsObject(v8::Local< v8::Value > value)
Definition fxv8.cpp:43
bool IsString(v8::Local< v8::Value > value)
Definition fxv8.cpp:31
ByteString ReentrantToByteStringHelper(v8::Isolate *pIsolate, v8::Local< v8::Value > pValue)
Definition fxv8.cpp:173
bool ReentrantToBooleanHelper(v8::Isolate *pIsolate, v8::Local< v8::Value > pValue)
Definition fxv8.cpp:138
bool IsNull(v8::Local< v8::Value > value)
Definition fxv8.cpp:23
int32_t ReentrantToInt32Helper(v8::Isolate *pIsolate, v8::Local< v8::Value > pValue)
Definition fxv8.cpp:131
const char kClassTag[]
Definition fxjse.cpp:18
const char kFuncTag[]
Definition fxjse.cpp:17
XFA_ScriptType eValueType
XFA_ATTRIBUTE_CALLBACK callback