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