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/cxfa_fmsimpleexpression.h"
8 
9 #include <algorithm>
10 #include <utility>
11 
12 #include "core/fxcrt/autorestorer.h"
13 #include "core/fxcrt/cfx_widetextbuf.h"
14 #include "core/fxcrt/fx_extension.h"
15 #include "third_party/base/logging.h"
16 #include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h"
17 
18 namespace {
19 
20 const wchar_t* const g_BuiltInFuncs[] = {
21     L"Abs",          L"Apr",       L"At",       L"Avg",
22     L"Ceil",         L"Choose",    L"Concat",   L"Count",
23     L"Cterm",        L"Date",      L"Date2Num", L"DateFmt",
24     L"Decode",       L"Encode",    L"Eval",     L"Exists",
25     L"Floor",        L"Format",    L"FV",       L"Get",
26     L"HasValue",     L"If",        L"Ipmt",     L"IsoDate2Num",
27     L"IsoTime2Num",  L"Left",      L"Len",      L"LocalDateFmt",
28     L"LocalTimeFmt", L"Lower",     L"Ltrim",    L"Max",
29     L"Min",          L"Mod",       L"NPV",      L"Num2Date",
30     L"Num2GMTime",   L"Num2Time",  L"Oneof",    L"Parse",
31     L"Pmt",          L"Post",      L"PPmt",     L"Put",
32     L"PV",           L"Rate",      L"Ref",      L"Replace",
33     L"Right",        L"Round",     L"Rtrim",    L"Space",
34     L"Str",          L"Stuff",     L"Substr",   L"Sum",
35     L"Term",         L"Time",      L"Time2Num", L"TimeFmt",
36     L"UnitType",     L"UnitValue", L"Upper",    L"Uuid",
37     L"Within",       L"WordNum",
38 };
39 
40 const size_t g_BuiltInFuncsMaxLen = 12;
41 
42 struct XFA_FMSOMMethod {
43   const wchar_t* m_wsSomMethodName;
44   uint32_t m_dParameters;
45 };
46 
47 const XFA_FMSOMMethod gs_FMSomMethods[] = {
48     {L"absPage", 0x01},
49     {L"absPageInBatch", 0x01},
50     {L"absPageSpan", 0x01},
51     {L"append", 0x01},
52     {L"clear", 0x01},
53     {L"formNodes", 0x01},
54     {L"h", 0x01},
55     {L"insert", 0x03},
56     {L"isRecordGroup", 0x01},
57     {L"page", 0x01},
58     {L"pageSpan", 0x01},
59     {L"remove", 0x01},
60     {L"saveFilteredXML", 0x01},
61     {L"setElement", 0x01},
62     {L"sheet", 0x01},
63     {L"sheetInBatch", 0x01},
64     {L"sign", 0x61},
65     {L"verify", 0x0d},
66     {L"w", 0x01},
67     {L"x", 0x01},
68     {L"y", 0x01},
69 };
70 
71 }  // namespace
72 
CXFA_FMSimpleExpression(XFA_FM_TOKEN op)73 CXFA_FMSimpleExpression::CXFA_FMSimpleExpression(XFA_FM_TOKEN op) : m_op(op) {}
74 
GetOperatorToken() const75 XFA_FM_TOKEN CXFA_FMSimpleExpression::GetOperatorToken() const {
76   return m_op;
77 }
78 
CXFA_FMNullExpression()79 CXFA_FMNullExpression::CXFA_FMNullExpression()
80     : CXFA_FMSimpleExpression(TOKnull) {}
81 
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)82 bool CXFA_FMNullExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) {
83   CXFA_FMToJavaScriptDepth depthManager;
84   if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
85     return false;
86 
87   *js << "null";
88   return !CXFA_IsTooBig(js);
89 }
90 
CXFA_FMNumberExpression(WideStringView wsNumber)91 CXFA_FMNumberExpression::CXFA_FMNumberExpression(WideStringView wsNumber)
92     : CXFA_FMSimpleExpression(TOKnumber), m_wsNumber(wsNumber) {}
93 
94 CXFA_FMNumberExpression::~CXFA_FMNumberExpression() = default;
95 
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)96 bool CXFA_FMNumberExpression::ToJavaScript(CFX_WideTextBuf* js,
97                                            ReturnType type) {
98   CXFA_FMToJavaScriptDepth depthManager;
99   if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
100     return false;
101 
102   *js << m_wsNumber;
103   return !CXFA_IsTooBig(js);
104 }
105 
CXFA_FMStringExpression(WideStringView wsString)106 CXFA_FMStringExpression::CXFA_FMStringExpression(WideStringView wsString)
107     : CXFA_FMSimpleExpression(TOKstring), m_wsString(wsString) {}
108 
109 CXFA_FMStringExpression::~CXFA_FMStringExpression() = default;
110 
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)111 bool CXFA_FMStringExpression::ToJavaScript(CFX_WideTextBuf* js,
112                                            ReturnType type) {
113   CXFA_FMToJavaScriptDepth depthManager;
114   if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
115     return false;
116 
117   WideString tempStr(m_wsString);
118   if (tempStr.GetLength() <= 2) {
119     *js << tempStr;
120     return !CXFA_IsTooBig(js);
121   }
122 
123   *js << "\"";
124   for (size_t i = 1; i < tempStr.GetLength() - 1; i++) {
125     wchar_t oneChar = tempStr[i];
126     switch (oneChar) {
127       case L'\"':
128         ++i;
129         *js << "\\\"";
130         break;
131       case 0x0d:
132         break;
133       case 0x0a:
134         *js << "\\n";
135         break;
136       default:
137         js->AppendChar(oneChar);
138         break;
139     }
140   }
141   *js << "\"";
142   return !CXFA_IsTooBig(js);
143 }
144 
CXFA_FMIdentifierExpression(WideStringView wsIdentifier)145 CXFA_FMIdentifierExpression::CXFA_FMIdentifierExpression(
146     WideStringView wsIdentifier)
147     : CXFA_FMSimpleExpression(TOKidentifier), m_wsIdentifier(wsIdentifier) {}
148 
149 CXFA_FMIdentifierExpression::~CXFA_FMIdentifierExpression() = default;
150 
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)151 bool CXFA_FMIdentifierExpression::ToJavaScript(CFX_WideTextBuf* js,
152                                                ReturnType type) {
153   CXFA_FMToJavaScriptDepth depthManager;
154   if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
155     return false;
156 
157   if (m_wsIdentifier.EqualsASCII("$"))
158     *js << "this";
159   else if (m_wsIdentifier.EqualsASCII("!"))
160     *js << "xfa.datasets";
161   else if (m_wsIdentifier.EqualsASCII("$data"))
162     *js << "xfa.datasets.data";
163   else if (m_wsIdentifier.EqualsASCII("$event"))
164     *js << "xfa.event";
165   else if (m_wsIdentifier.EqualsASCII("$form"))
166     *js << "xfa.form";
167   else if (m_wsIdentifier.EqualsASCII("$host"))
168     *js << "xfa.host";
169   else if (m_wsIdentifier.EqualsASCII("$layout"))
170     *js << "xfa.layout";
171   else if (m_wsIdentifier.EqualsASCII("$template"))
172     *js << "xfa.template";
173   else if (m_wsIdentifier[0] == L'!')
174     *js << "pfm__excl__" << m_wsIdentifier.Last(m_wsIdentifier.GetLength() - 1);
175   else
176     *js << m_wsIdentifier;
177 
178   return !CXFA_IsTooBig(js);
179 }
180 
CXFA_FMAssignExpression(XFA_FM_TOKEN op,std::unique_ptr<CXFA_FMSimpleExpression> pExp1,std::unique_ptr<CXFA_FMSimpleExpression> pExp2)181 CXFA_FMAssignExpression::CXFA_FMAssignExpression(
182     XFA_FM_TOKEN op,
183     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
184     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
185     : CXFA_FMSimpleExpression(op),
186       m_pExp1(std::move(pExp1)),
187       m_pExp2(std::move(pExp2)) {}
188 
189 CXFA_FMAssignExpression::~CXFA_FMAssignExpression() = default;
190 
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)191 bool CXFA_FMAssignExpression::ToJavaScript(CFX_WideTextBuf* js,
192                                            ReturnType type) {
193   CXFA_FMToJavaScriptDepth depthManager;
194   if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
195     return false;
196 
197   CFX_WideTextBuf tempExp1;
198   if (!m_pExp1->ToJavaScript(&tempExp1, ReturnType::kInfered))
199     return false;
200 
201   *js << "if (pfm_rt.is_obj(" << tempExp1 << "))\n{\n";
202   if (type == ReturnType::kImplied)
203     *js << "pfm_ret = ";
204 
205   CFX_WideTextBuf tempExp2;
206   if (!m_pExp2->ToJavaScript(&tempExp2, ReturnType::kInfered))
207     return false;
208 
209   *js << "pfm_rt.asgn_val_op(" << tempExp1 << ", " << tempExp2 << ");\n}\n";
210 
211   if (m_pExp1->GetOperatorToken() == TOKidentifier &&
212       !tempExp1.AsStringView().EqualsASCII("this")) {
213     *js << "else\n{\n";
214     if (type == ReturnType::kImplied)
215       *js << "pfm_ret = ";
216 
217     *js << tempExp1 << " = pfm_rt.asgn_val_op";
218     *js << "(" << tempExp1 << ", " << tempExp2 << ");\n";
219     *js << "}\n";
220   }
221   return !CXFA_IsTooBig(js);
222 }
223 
CXFA_FMBinExpression(const WideString & opName,XFA_FM_TOKEN op,std::unique_ptr<CXFA_FMSimpleExpression> pExp1,std::unique_ptr<CXFA_FMSimpleExpression> pExp2)224 CXFA_FMBinExpression::CXFA_FMBinExpression(
225     const WideString& opName,
226     XFA_FM_TOKEN op,
227     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
228     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
229     : CXFA_FMSimpleExpression(op),
230       m_OpName(opName),
231       m_pExp1(std::move(pExp1)),
232       m_pExp2(std::move(pExp2)) {}
233 
234 CXFA_FMBinExpression::~CXFA_FMBinExpression() = default;
235 
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)236 bool CXFA_FMBinExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) {
237   CXFA_FMToJavaScriptDepth depthManager;
238   if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
239     return false;
240 
241   *js << "pfm_rt." << m_OpName << "(";
242   if (!m_pExp1->ToJavaScript(js, ReturnType::kInfered))
243     return false;
244   *js << ", ";
245   if (!m_pExp2->ToJavaScript(js, ReturnType::kInfered))
246     return false;
247   *js << ")";
248   return !CXFA_IsTooBig(js);
249 }
250 
CXFA_FMLogicalOrExpression(XFA_FM_TOKEN op,std::unique_ptr<CXFA_FMSimpleExpression> pExp1,std::unique_ptr<CXFA_FMSimpleExpression> pExp2)251 CXFA_FMLogicalOrExpression::CXFA_FMLogicalOrExpression(
252     XFA_FM_TOKEN op,
253     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
254     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
255     : CXFA_FMBinExpression(L"log_or_op",
256                            op,
257                            std::move(pExp1),
258                            std::move(pExp2)) {}
259 
CXFA_FMLogicalAndExpression(XFA_FM_TOKEN op,std::unique_ptr<CXFA_FMSimpleExpression> pExp1,std::unique_ptr<CXFA_FMSimpleExpression> pExp2)260 CXFA_FMLogicalAndExpression::CXFA_FMLogicalAndExpression(
261     XFA_FM_TOKEN op,
262     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
263     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
264     : CXFA_FMBinExpression(L"log_and_op",
265                            op,
266                            std::move(pExp1),
267                            std::move(pExp2)) {}
268 
CXFA_FMEqualExpression(XFA_FM_TOKEN op,std::unique_ptr<CXFA_FMSimpleExpression> pExp1,std::unique_ptr<CXFA_FMSimpleExpression> pExp2)269 CXFA_FMEqualExpression::CXFA_FMEqualExpression(
270     XFA_FM_TOKEN op,
271     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
272     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
273     : CXFA_FMBinExpression(L"eq_op",
274                            op,
275                            std::move(pExp1),
276                            std::move(pExp2)) {}
277 
CXFA_FMNotEqualExpression(XFA_FM_TOKEN op,std::unique_ptr<CXFA_FMSimpleExpression> pExp1,std::unique_ptr<CXFA_FMSimpleExpression> pExp2)278 CXFA_FMNotEqualExpression::CXFA_FMNotEqualExpression(
279     XFA_FM_TOKEN op,
280     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
281     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
282     : CXFA_FMBinExpression(L"neq_op",
283                            op,
284                            std::move(pExp1),
285                            std::move(pExp2)) {}
286 
CXFA_FMGtExpression(XFA_FM_TOKEN op,std::unique_ptr<CXFA_FMSimpleExpression> pExp1,std::unique_ptr<CXFA_FMSimpleExpression> pExp2)287 CXFA_FMGtExpression::CXFA_FMGtExpression(
288     XFA_FM_TOKEN op,
289     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
290     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
291     : CXFA_FMBinExpression(L"gt_op",
292                            op,
293                            std::move(pExp1),
294                            std::move(pExp2)) {}
295 
CXFA_FMGeExpression(XFA_FM_TOKEN op,std::unique_ptr<CXFA_FMSimpleExpression> pExp1,std::unique_ptr<CXFA_FMSimpleExpression> pExp2)296 CXFA_FMGeExpression::CXFA_FMGeExpression(
297     XFA_FM_TOKEN op,
298     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
299     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
300     : CXFA_FMBinExpression(L"ge_op",
301                            op,
302                            std::move(pExp1),
303                            std::move(pExp2)) {}
304 
CXFA_FMLtExpression(XFA_FM_TOKEN op,std::unique_ptr<CXFA_FMSimpleExpression> pExp1,std::unique_ptr<CXFA_FMSimpleExpression> pExp2)305 CXFA_FMLtExpression::CXFA_FMLtExpression(
306     XFA_FM_TOKEN op,
307     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
308     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
309     : CXFA_FMBinExpression(L"lt_op",
310                            op,
311                            std::move(pExp1),
312                            std::move(pExp2)) {}
313 
CXFA_FMLeExpression(XFA_FM_TOKEN op,std::unique_ptr<CXFA_FMSimpleExpression> pExp1,std::unique_ptr<CXFA_FMSimpleExpression> pExp2)314 CXFA_FMLeExpression::CXFA_FMLeExpression(
315     XFA_FM_TOKEN op,
316     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
317     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
318     : CXFA_FMBinExpression(L"le_op",
319                            op,
320                            std::move(pExp1),
321                            std::move(pExp2)) {}
322 
CXFA_FMPlusExpression(XFA_FM_TOKEN op,std::unique_ptr<CXFA_FMSimpleExpression> pExp1,std::unique_ptr<CXFA_FMSimpleExpression> pExp2)323 CXFA_FMPlusExpression::CXFA_FMPlusExpression(
324     XFA_FM_TOKEN op,
325     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
326     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
327     : CXFA_FMBinExpression(L"plus_op",
328                            op,
329                            std::move(pExp1),
330                            std::move(pExp2)) {}
331 
CXFA_FMMinusExpression(XFA_FM_TOKEN op,std::unique_ptr<CXFA_FMSimpleExpression> pExp1,std::unique_ptr<CXFA_FMSimpleExpression> pExp2)332 CXFA_FMMinusExpression::CXFA_FMMinusExpression(
333     XFA_FM_TOKEN op,
334     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
335     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
336     : CXFA_FMBinExpression(L"minus_op",
337                            op,
338                            std::move(pExp1),
339                            std::move(pExp2)) {}
340 
CXFA_FMMulExpression(XFA_FM_TOKEN op,std::unique_ptr<CXFA_FMSimpleExpression> pExp1,std::unique_ptr<CXFA_FMSimpleExpression> pExp2)341 CXFA_FMMulExpression::CXFA_FMMulExpression(
342     XFA_FM_TOKEN op,
343     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
344     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
345     : CXFA_FMBinExpression(L"mul_op",
346                            op,
347                            std::move(pExp1),
348                            std::move(pExp2)) {}
349 
CXFA_FMDivExpression(XFA_FM_TOKEN op,std::unique_ptr<CXFA_FMSimpleExpression> pExp1,std::unique_ptr<CXFA_FMSimpleExpression> pExp2)350 CXFA_FMDivExpression::CXFA_FMDivExpression(
351     XFA_FM_TOKEN op,
352     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
353     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
354     : CXFA_FMBinExpression(L"div_op",
355                            op,
356                            std::move(pExp1),
357                            std::move(pExp2)) {}
358 
CXFA_FMUnaryExpression(const WideString & opName,XFA_FM_TOKEN op,std::unique_ptr<CXFA_FMSimpleExpression> pExp)359 CXFA_FMUnaryExpression::CXFA_FMUnaryExpression(
360     const WideString& opName,
361     XFA_FM_TOKEN op,
362     std::unique_ptr<CXFA_FMSimpleExpression> pExp)
363     : CXFA_FMSimpleExpression(op), m_OpName(opName), m_pExp(std::move(pExp)) {}
364 
365 CXFA_FMUnaryExpression::~CXFA_FMUnaryExpression() = default;
366 
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)367 bool CXFA_FMUnaryExpression::ToJavaScript(CFX_WideTextBuf* js,
368                                           ReturnType type) {
369   CXFA_FMToJavaScriptDepth depthManager;
370   if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
371     return false;
372 
373   *js << "pfm_rt." << m_OpName.c_str() << "(";
374   if (!m_pExp->ToJavaScript(js, ReturnType::kInfered))
375     return false;
376   *js << ")";
377   return !CXFA_IsTooBig(js);
378 }
379 
CXFA_FMPosExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExp)380 CXFA_FMPosExpression::CXFA_FMPosExpression(
381     std::unique_ptr<CXFA_FMSimpleExpression> pExp)
382     : CXFA_FMUnaryExpression(L"pos_op", TOKplus, std::move(pExp)) {}
383 
CXFA_FMNegExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExp)384 CXFA_FMNegExpression::CXFA_FMNegExpression(
385     std::unique_ptr<CXFA_FMSimpleExpression> pExp)
386     : CXFA_FMUnaryExpression(L"neg_op", TOKminus, std::move(pExp)) {}
387 
CXFA_FMNotExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExp)388 CXFA_FMNotExpression::CXFA_FMNotExpression(
389     std::unique_ptr<CXFA_FMSimpleExpression> pExp)
390     : CXFA_FMUnaryExpression(L"log_not_op", TOKksnot, std::move(pExp)) {}
391 
CXFA_FMCallExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExp,std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> && pArguments,bool bIsSomMethod)392 CXFA_FMCallExpression::CXFA_FMCallExpression(
393     std::unique_ptr<CXFA_FMSimpleExpression> pExp,
394     std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>&& pArguments,
395     bool bIsSomMethod)
396     : CXFA_FMSimpleExpression(TOKcall),
397       m_pExp(std::move(pExp)),
398       m_bIsSomMethod(bIsSomMethod),
399       m_Arguments(std::move(pArguments)) {}
400 
~CXFA_FMCallExpression()401 CXFA_FMCallExpression::~CXFA_FMCallExpression() {}
402 
IsBuiltInFunc(CFX_WideTextBuf * funcName)403 bool CXFA_FMCallExpression::IsBuiltInFunc(CFX_WideTextBuf* funcName) {
404   if (funcName->GetLength() > g_BuiltInFuncsMaxLen)
405     return false;
406 
407   WideString str = funcName->MakeString();
408   const wchar_t* const* pMatchResult = std::lower_bound(
409       std::begin(g_BuiltInFuncs), std::end(g_BuiltInFuncs), str,
410       [](const wchar_t* iter, const WideString& val) -> bool {
411         return val.CompareNoCase(iter) > 0;
412       });
413   if (pMatchResult != std::end(g_BuiltInFuncs) &&
414       !str.CompareNoCase(*pMatchResult)) {
415     funcName->Clear();
416     *funcName << *pMatchResult;
417     return true;
418   }
419   return false;
420 }
421 
IsMethodWithObjParam(const WideString & methodName)422 uint32_t CXFA_FMCallExpression::IsMethodWithObjParam(
423     const WideString& methodName) {
424   const XFA_FMSOMMethod* result = std::lower_bound(
425       std::begin(gs_FMSomMethods), std::end(gs_FMSomMethods), methodName,
426       [](const XFA_FMSOMMethod iter, const WideString& val) {
427         return val.Compare(iter.m_wsSomMethodName) > 0;
428       });
429   if (result != std::end(gs_FMSomMethods) &&
430       !methodName.Compare(result->m_wsSomMethodName)) {
431     return result->m_dParameters;
432   }
433   return 0;
434 }
435 
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)436 bool CXFA_FMCallExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) {
437   CXFA_FMToJavaScriptDepth depthManager;
438   if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
439     return false;
440 
441   CFX_WideTextBuf funcName;
442   if (!m_pExp->ToJavaScript(&funcName, ReturnType::kInfered))
443     return false;
444 
445   if (m_bIsSomMethod) {
446     *js << funcName << "(";
447     uint32_t methodPara = IsMethodWithObjParam(funcName.MakeString());
448     if (methodPara > 0) {
449       for (size_t i = 0; i < m_Arguments.size(); ++i) {
450         // Currently none of our expressions use objects for a parameter over
451         // the 6th. Make sure we don't overflow the shift when doing this
452         // check. If we ever need more the 32 object params we can revisit.
453         *js << "pfm_rt.get_";
454         if (i < 32 && (methodPara & (0x01 << i)) > 0)
455           *js << "jsobj";
456         else
457           *js << "val";
458 
459         *js << "(";
460         if (!m_Arguments[i]->ToJavaScript(js, ReturnType::kInfered))
461           return false;
462         *js << ")";
463         if (i + 1 < m_Arguments.size())
464           *js << ", ";
465       }
466     } else {
467       for (const auto& expr : m_Arguments) {
468         *js << "pfm_rt.get_val(";
469         if (!expr->ToJavaScript(js, ReturnType::kInfered))
470           return false;
471         *js << ")";
472         if (expr != m_Arguments.back())
473           *js << ", ";
474       }
475     }
476     *js << ")";
477     return !CXFA_IsTooBig(js);
478   }
479 
480   bool isEvalFunc = false;
481   bool isExistsFunc = false;
482   if (!IsBuiltInFunc(&funcName)) {
483     // If a function is not a SomMethod or a built-in then the input was
484     // invalid, so failing. The scanner/lexer should catch this, but currently
485     // doesn't. This failure will bubble up to the top-level and cause the
486     // transpile to fail.
487     return false;
488   }
489 
490   if (funcName.AsStringView().EqualsASCII("Eval")) {
491     isEvalFunc = true;
492     *js << "eval.call(this, pfm_rt.Translate";
493   } else {
494     if (funcName.AsStringView().EqualsASCII("Exists"))
495       isExistsFunc = true;
496 
497     *js << "pfm_rt." << funcName;
498   }
499 
500   *js << "(";
501   if (isExistsFunc) {
502     *js << "\n(\nfunction ()\n{\ntry\n{\n";
503     if (!m_Arguments.empty()) {
504       *js << "return ";
505       if (!m_Arguments[0]->ToJavaScript(js, ReturnType::kInfered))
506         return false;
507       *js << ";\n}\n";
508     } else {
509       *js << "return 0;\n}\n";
510     }
511     *js << "catch(accessExceptions)\n";
512     *js << "{\nreturn 0;\n}\n}\n).call(this)\n";
513   } else {
514     for (const auto& expr : m_Arguments) {
515       if (!expr->ToJavaScript(js, ReturnType::kInfered))
516         return false;
517       if (expr != m_Arguments.back())
518         *js << ", ";
519     }
520   }
521   *js << ")";
522   if (isEvalFunc)
523     *js << ")";
524 
525   return !CXFA_IsTooBig(js);
526 }
527 
CXFA_FMDotAccessorExpression(std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,XFA_FM_TOKEN op,WideStringView wsIdentifier,std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp)528 CXFA_FMDotAccessorExpression::CXFA_FMDotAccessorExpression(
529     std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
530     XFA_FM_TOKEN op,
531     WideStringView wsIdentifier,
532     std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp)
533     : CXFA_FMSimpleExpression(op),
534       m_wsIdentifier(wsIdentifier),
535       m_pExp1(std::move(pAccessor)),
536       m_pExp2(std::move(pIndexExp)) {}
537 
538 CXFA_FMDotAccessorExpression::~CXFA_FMDotAccessorExpression() = default;
539 
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)540 bool CXFA_FMDotAccessorExpression::ToJavaScript(CFX_WideTextBuf* js,
541                                                 ReturnType type) {
542   CXFA_FMToJavaScriptDepth depthManager;
543   if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
544     return false;
545 
546   *js << "pfm_rt.dot_acc(";
547 
548   CFX_WideTextBuf tempExp1;
549   if (m_pExp1) {
550     if (!m_pExp1->ToJavaScript(&tempExp1, ReturnType::kInfered))
551       return false;
552 
553     *js << tempExp1;
554   } else {
555     *js << "null";
556   }
557   *js << ", \"";
558 
559   if (m_pExp1 && m_pExp1->GetOperatorToken() == TOKidentifier)
560     *js << tempExp1;
561 
562   *js << "\", ";
563   if (m_op == TOKdotscream)
564     *js << "\"#" << m_wsIdentifier << "\", ";
565   else if (m_op == TOKdotstar)
566     *js << "\"*\", ";
567   else if (m_op == TOKcall)
568     *js << "\"\", ";
569   else
570     *js << "\"" << m_wsIdentifier << "\", ";
571 
572   if (!m_pExp2->ToJavaScript(js, ReturnType::kInfered))
573     return false;
574 
575   *js << ")";
576   return !CXFA_IsTooBig(js);
577 }
578 
CXFA_FMIndexExpression(XFA_FM_AccessorIndex accessorIndex,std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp,bool bIsStarIndex)579 CXFA_FMIndexExpression::CXFA_FMIndexExpression(
580     XFA_FM_AccessorIndex accessorIndex,
581     std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp,
582     bool bIsStarIndex)
583     : CXFA_FMSimpleExpression(TOKlbracket),
584       m_pExp(std::move(pIndexExp)),
585       m_accessorIndex(accessorIndex),
586       m_bIsStarIndex(bIsStarIndex) {}
587 
588 CXFA_FMIndexExpression::~CXFA_FMIndexExpression() = default;
589 
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)590 bool CXFA_FMIndexExpression::ToJavaScript(CFX_WideTextBuf* js,
591                                           ReturnType type) {
592   CXFA_FMToJavaScriptDepth depthManager;
593   if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
594     return false;
595 
596   switch (m_accessorIndex) {
597     case ACCESSOR_NO_INDEX:
598       *js << "0";
599       break;
600     case ACCESSOR_NO_RELATIVEINDEX:
601       *js << "1";
602       break;
603     case ACCESSOR_POSITIVE_INDEX:
604       *js << "2";
605       break;
606     case ACCESSOR_NEGATIVE_INDEX:
607       *js << "3";
608       break;
609     default:
610       *js << "0";
611   }
612   if (m_bIsStarIndex)
613     return !CXFA_IsTooBig(js);
614 
615   *js << ", ";
616   if (m_pExp) {
617     if (!m_pExp->ToJavaScript(js, ReturnType::kInfered))
618       return false;
619   } else {
620     *js << "0";
621   }
622   return !CXFA_IsTooBig(js);
623 }
624 
CXFA_FMDotDotAccessorExpression(std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,XFA_FM_TOKEN op,WideStringView wsIdentifier,std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp)625 CXFA_FMDotDotAccessorExpression::CXFA_FMDotDotAccessorExpression(
626     std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
627     XFA_FM_TOKEN op,
628     WideStringView wsIdentifier,
629     std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp)
630     : CXFA_FMSimpleExpression(op),
631       m_wsIdentifier(wsIdentifier),
632       m_pExp1(std::move(pAccessor)),
633       m_pExp2(std::move(pIndexExp)) {}
634 
635 CXFA_FMDotDotAccessorExpression::~CXFA_FMDotDotAccessorExpression() = default;
636 
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)637 bool CXFA_FMDotDotAccessorExpression::ToJavaScript(CFX_WideTextBuf* js,
638                                                    ReturnType type) {
639   CXFA_FMToJavaScriptDepth depthManager;
640   if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
641     return false;
642 
643   *js << "pfm_rt.dotdot_acc(";
644   if (!m_pExp1->ToJavaScript(js, ReturnType::kInfered))
645     return false;
646   *js << ", "
647       << "\"";
648   if (m_pExp1->GetOperatorToken() == TOKidentifier) {
649     if (!m_pExp1->ToJavaScript(js, ReturnType::kInfered))
650       return false;
651   }
652 
653   *js << "\", \"" << m_wsIdentifier << "\", ";
654   if (!m_pExp2->ToJavaScript(js, ReturnType::kInfered))
655     return false;
656   *js << ")";
657   return !CXFA_IsTooBig(js);
658 }
659 
CXFA_FMMethodCallExpression(std::unique_ptr<CXFA_FMSimpleExpression> pAccessorExp1,std::unique_ptr<CXFA_FMSimpleExpression> pCallExp)660 CXFA_FMMethodCallExpression::CXFA_FMMethodCallExpression(
661     std::unique_ptr<CXFA_FMSimpleExpression> pAccessorExp1,
662     std::unique_ptr<CXFA_FMSimpleExpression> pCallExp)
663     : CXFA_FMSimpleExpression(TOKdot),
664       m_pExp1(std::move(pAccessorExp1)),
665       m_pExp2(std::move(pCallExp)) {}
666 
667 CXFA_FMMethodCallExpression::~CXFA_FMMethodCallExpression() = default;
668 
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)669 bool CXFA_FMMethodCallExpression::ToJavaScript(CFX_WideTextBuf* js,
670                                                ReturnType type) {
671   CXFA_FMToJavaScriptDepth depthManager;
672   if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
673     return false;
674 
675   CFX_WideTextBuf buf;
676   if (!m_pExp1->ToJavaScript(&buf, ReturnType::kInfered))
677     return false;
678 
679   *js << "(function() {\n";
680   *js << "  return pfm_method_runner(" << buf << ", function(obj) {\n";
681   *js << "    return obj.";
682   if (!m_pExp2->ToJavaScript(js, ReturnType::kInfered))
683     return false;
684   *js << ";\n";
685   *js << "  });\n";
686   *js << "}).call(this)";
687   return !CXFA_IsTooBig(js);
688 }
689 
CXFA_IsTooBig(const CFX_WideTextBuf * js)690 bool CXFA_IsTooBig(const CFX_WideTextBuf* js) {
691   return js->GetSize() >= 256 * 1024 * 1024;
692 }
693