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
25namespace {
26
27const double kFinancialPrecision = 0.00000001;
28
29struct XFA_FMHtmlReserveCode {
30  uint32_t m_uCode;
31  const FX_WCHAR* m_htmlReserve;
32};
33
34struct XFA_FMHtmlHashedReserveCode {
35  uint32_t m_uHash;
36  uint32_t m_uCode;
37};
38
39const 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
168const 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
255const 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
349const 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
363const 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};
368static_assert(FX_ArraySize(g_sAltTable_Date) == L'a' - L'A' + 1,
369              "Invalid g_sAltTable_Date size.");
370
371const 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};
376static_assert(FX_ArraySize(g_sAltTable_Time) == L'a' - L'A' + 1,
377              "Invalid g_sAltTable_Time size.");
378
379void 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
409bool 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
499CXFA_FM2JSContext* ToJSContext(CFXJSE_Value* pValue, CFXJSE_Class* pClass) {
500  return static_cast<CXFA_FM2JSContext*>(pValue->ToHostObject(pClass));
501}
502
503bool 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
511void 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
533void 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
600void 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
619void 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
673void 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
692void 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
766void 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
840void 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
875void 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
923void 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
998void 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(&currentTime);
1008  struct tm* pTmStruct = gmtime(&currentTime);
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
1022void 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
1072void 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
1110void 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
1131void 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
1189void 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
1227void 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
1265void 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
1406void 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
1454void 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
1501void 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
1518void 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
1608void 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
1645bool 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
1724bool 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
1871bool 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
1920bool 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
1957bool 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
1996bool 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
2034bool 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
2073bool 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
2112int32_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
2169void 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
2220void 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
2271void 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
2279void 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
2287void 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
2325void 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
2339void 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
2393void 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
2425void 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
2466void 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
2523void 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
2566void 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
2601void 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
2659void 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
2694void 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
2726void 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
2758void 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
2829void 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
2840void 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
2861void 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, &parameterValues, 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
2884void 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
2921void 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
2935void 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
2969void 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
3027void 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
3139void 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
3283void 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
3312void 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
3344void 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
3393void 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
3434void 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
3510void 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
3611void 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
3658void 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
3759void 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
3809void 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
3880bool 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
3902bool 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
3923void 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
4001void 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
4024void 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
4044void 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
4082void 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
4103void 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
4234void 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
4293void 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
4316void 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
4337void 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
4363void 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
4479void 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
4529void 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
4568void 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
4591void 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
4630void 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
4682void 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
4781void 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
4830void 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
4862void 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
4920void 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
4964void 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
5008void 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
5029void 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
5050void 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
5083void 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
5116bool 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
5143void 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
5170void 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
5198void 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
5225void 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
5253void 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
5275void 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
5296void 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
5317void 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
5344void 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
5361void 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
5378void 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
5397void 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
5516void 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
5635void 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
5667void 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
5680void 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
5693void 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
5728void 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
5754void 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
5808void 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
5849std::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
5890bool 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
5925int32_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
5937bool 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
5961void 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
6026void 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
6037bool 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
6048void 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
6079bool 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
6104int32_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
6150void 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
6194int32_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
6226FX_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
6260FX_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.
6293double 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
6328void 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.
6342int32_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
6360CXFA_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
6372CXFA_FM2JSContext::~CXFA_FM2JSContext() {}
6373
6374void CXFA_FM2JSContext::GlobalPropertyGetter(CFXJSE_Value* pValue) {
6375  pValue->Assign(m_pValue.get());
6376}
6377
6378void CXFA_FM2JSContext::ThrowNoDefaultPropertyException(
6379    const CFX_ByteStringC& name) const {
6380  ThrowException(L"%s doesn't have a default property.", name.c_str());
6381}
6382
6383void CXFA_FM2JSContext::ThrowCompilerErrorException() const {
6384  ThrowException(L"Compiler error.");
6385}
6386
6387void CXFA_FM2JSContext::ThrowDivideByZeroException() const {
6388  ThrowException(L"Divide by zero.");
6389}
6390
6391void CXFA_FM2JSContext::ThrowServerDeniedException() const {
6392  ThrowException(L"Server does not permit operation.");
6393}
6394
6395void 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
6404void 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
6410void CXFA_FM2JSContext::ThrowArgumentMismatchException() const {
6411  ThrowException(L"Argument mismatch in property or function argument.");
6412}
6413
6414void 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