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