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