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