xref: /aosp_15_r20/external/pdfium/xfa/fxfa/formcalc/cxfa_fmexpression.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2014 The PDFium Authors
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/formcalc/cxfa_fmexpression.h"
8 
9 #include <algorithm>
10 #include <utility>
11 
12 #include "core/fxcrt/autorestorer.h"
13 #include "core/fxcrt/fx_extension.h"
14 #include "core/fxcrt/widetext_buffer.h"
15 #include "fxjs/gc/container_trace.h"
16 #include "third_party/base/check.h"
17 #include "v8/include/cppgc/visitor.h"
18 #include "xfa/fxfa/formcalc/cxfa_fmtojavascriptdepth.h"
19 
20 namespace {
21 
22 const wchar_t kLessEqual[] = L" <= ";
23 const wchar_t kGreaterEqual[] = L" >= ";
24 const wchar_t kPlusEqual[] = L" += ";
25 const wchar_t kMinusEqual[] = L" -= ";
26 
27 const wchar_t* const kBuiltInFuncs[] = {
28     L"Abs",          L"Apr",       L"At",       L"Avg",
29     L"Ceil",         L"Choose",    L"Concat",   L"Count",
30     L"Cterm",        L"Date",      L"Date2Num", L"DateFmt",
31     L"Decode",       L"Encode",    L"Eval",     L"Exists",
32     L"Floor",        L"Format",    L"FV",       L"Get",
33     L"HasValue",     L"If",        L"Ipmt",     L"IsoDate2Num",
34     L"IsoTime2Num",  L"Left",      L"Len",      L"LocalDateFmt",
35     L"LocalTimeFmt", L"Lower",     L"Ltrim",    L"Max",
36     L"Min",          L"Mod",       L"NPV",      L"Num2Date",
37     L"Num2GMTime",   L"Num2Time",  L"Oneof",    L"Parse",
38     L"Pmt",          L"Post",      L"PPmt",     L"Put",
39     L"PV",           L"Rate",      L"Ref",      L"Replace",
40     L"Right",        L"Round",     L"Rtrim",    L"Space",
41     L"Str",          L"Stuff",     L"Substr",   L"Sum",
42     L"Term",         L"Time",      L"Time2Num", L"TimeFmt",
43     L"UnitType",     L"UnitValue", L"Upper",    L"Uuid",
44     L"Within",       L"WordNum",
45 };
46 
47 const size_t kBuiltInFuncsMaxLen = 12;
48 
49 struct XFA_FMSOMMethod {
50   const wchar_t* m_wsSomMethodName;  // Ok, POD struct.
51   uint32_t m_dParameters;
52 };
53 
54 const XFA_FMSOMMethod kFMSomMethods[] = {
55     {L"absPage", 0x01},
56     {L"absPageInBatch", 0x01},
57     {L"absPageSpan", 0x01},
58     {L"append", 0x01},
59     {L"clear", 0x01},
60     {L"formNodes", 0x01},
61     {L"h", 0x01},
62     {L"insert", 0x03},
63     {L"isRecordGroup", 0x01},
64     {L"page", 0x01},
65     {L"pageSpan", 0x01},
66     {L"remove", 0x01},
67     {L"saveFilteredXML", 0x01},
68     {L"setElement", 0x01},
69     {L"sheet", 0x01},
70     {L"sheetInBatch", 0x01},
71     {L"sign", 0x61},
72     {L"verify", 0x0d},
73     {L"w", 0x01},
74     {L"x", 0x01},
75     {L"y", 0x01},
76 };
77 
IdentifierToName(const WideString & ident)78 WideString IdentifierToName(const WideString& ident) {
79   if (ident.IsEmpty() || ident[0] != L'!')
80     return ident;
81   return L"pfm__excl__" + ident.Last(ident.GetLength() - 1);
82 }
83 
84 }  // namespace
85 
86 CXFA_FMExpression::CXFA_FMExpression() = default;
87 
88 CXFA_FMExpression::~CXFA_FMExpression() = default;
89 
Trace(cppgc::Visitor * visitor) const90 void CXFA_FMExpression::Trace(cppgc::Visitor* visitor) const {}
91 
CXFA_FMSimpleExpression(XFA_FM_TOKEN op)92 CXFA_FMSimpleExpression::CXFA_FMSimpleExpression(XFA_FM_TOKEN op) : m_op(op) {}
93 
94 CXFA_FMSimpleExpression::~CXFA_FMSimpleExpression() = default;
95 
CXFA_FMChainableExpression(XFA_FM_TOKEN op,CXFA_FMSimpleExpression * pExp1,CXFA_FMSimpleExpression * pExp2)96 CXFA_FMChainableExpression::CXFA_FMChainableExpression(
97     XFA_FM_TOKEN op,
98     CXFA_FMSimpleExpression* pExp1,
99     CXFA_FMSimpleExpression* pExp2)
100     : CXFA_FMSimpleExpression(op), m_pExp1(pExp1), m_pExp2(pExp2) {}
101 
102 CXFA_FMChainableExpression::~CXFA_FMChainableExpression() = default;
103 
Trace(cppgc::Visitor * visitor) const104 void CXFA_FMChainableExpression::Trace(cppgc::Visitor* visitor) const {
105   CXFA_FMSimpleExpression::Trace(visitor);
106   visitor->Trace(m_pExp1);
107   visitor->Trace(m_pExp2);
108 }
109 
CXFA_FMNullExpression()110 CXFA_FMNullExpression::CXFA_FMNullExpression()
111     : CXFA_FMSimpleExpression(TOKnull) {}
112 
113 CXFA_FMNullExpression::~CXFA_FMNullExpression() = default;
114 
ToJavaScript(WideTextBuffer * js,ReturnType type) const115 bool CXFA_FMNullExpression::ToJavaScript(WideTextBuffer* js,
116                                          ReturnType type) const {
117   CXFA_FMToJavaScriptDepth depthManager;
118   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
119     return false;
120 
121   *js << "null";
122   return !CXFA_IsTooBig(*js);
123 }
124 
CXFA_FMNumberExpression(WideString wsNumber)125 CXFA_FMNumberExpression::CXFA_FMNumberExpression(WideString wsNumber)
126     : CXFA_FMSimpleExpression(TOKnumber), m_wsNumber(std::move(wsNumber)) {}
127 
128 CXFA_FMNumberExpression::~CXFA_FMNumberExpression() = default;
129 
ToJavaScript(WideTextBuffer * js,ReturnType type) const130 bool CXFA_FMNumberExpression::ToJavaScript(WideTextBuffer* js,
131                                            ReturnType type) const {
132   CXFA_FMToJavaScriptDepth depthManager;
133   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
134     return false;
135 
136   *js << m_wsNumber;
137   return !CXFA_IsTooBig(*js);
138 }
139 
CXFA_FMStringExpression(WideString wsString)140 CXFA_FMStringExpression::CXFA_FMStringExpression(WideString wsString)
141     : CXFA_FMSimpleExpression(TOKstring), m_wsString(std::move(wsString)) {}
142 
143 CXFA_FMStringExpression::~CXFA_FMStringExpression() = default;
144 
ToJavaScript(WideTextBuffer * js,ReturnType type) const145 bool CXFA_FMStringExpression::ToJavaScript(WideTextBuffer* js,
146                                            ReturnType type) const {
147   CXFA_FMToJavaScriptDepth depthManager;
148   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
149     return false;
150 
151   WideString tempStr(m_wsString);
152   if (tempStr.GetLength() <= 2) {
153     *js << tempStr;
154     return !CXFA_IsTooBig(*js);
155   }
156 
157   *js << "\"";
158   for (size_t i = 1; i < tempStr.GetLength() - 1; i++) {
159     wchar_t oneChar = tempStr[i];
160     switch (oneChar) {
161       case L'\"':
162         ++i;
163         *js << "\\\"";
164         break;
165       case 0x0d:
166         break;
167       case 0x0a:
168         *js << "\\n";
169         break;
170       default:
171         js->AppendChar(oneChar);
172         break;
173     }
174   }
175   *js << "\"";
176   return !CXFA_IsTooBig(*js);
177 }
178 
CXFA_FMIdentifierExpression(WideString wsIdentifier)179 CXFA_FMIdentifierExpression::CXFA_FMIdentifierExpression(
180     WideString wsIdentifier)
181     : CXFA_FMSimpleExpression(TOKidentifier),
182       m_wsIdentifier(std::move(wsIdentifier)) {}
183 
184 CXFA_FMIdentifierExpression::~CXFA_FMIdentifierExpression() = default;
185 
ToJavaScript(WideTextBuffer * js,ReturnType type) const186 bool CXFA_FMIdentifierExpression::ToJavaScript(WideTextBuffer* js,
187                                                ReturnType type) const {
188   CXFA_FMToJavaScriptDepth depthManager;
189   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
190     return false;
191 
192   if (m_wsIdentifier.EqualsASCII("$"))
193     *js << "this";
194   else if (m_wsIdentifier.EqualsASCII("!"))
195     *js << "xfa.datasets";
196   else if (m_wsIdentifier.EqualsASCII("$data"))
197     *js << "xfa.datasets.data";
198   else if (m_wsIdentifier.EqualsASCII("$event"))
199     *js << "xfa.event";
200   else if (m_wsIdentifier.EqualsASCII("$form"))
201     *js << "xfa.form";
202   else if (m_wsIdentifier.EqualsASCII("$host"))
203     *js << "xfa.host";
204   else if (m_wsIdentifier.EqualsASCII("$layout"))
205     *js << "xfa.layout";
206   else if (m_wsIdentifier.EqualsASCII("$template"))
207     *js << "xfa.template";
208   else if (m_wsIdentifier[0] == L'!')
209     *js << "pfm__excl__" << m_wsIdentifier.Last(m_wsIdentifier.GetLength() - 1);
210   else
211     *js << m_wsIdentifier;
212 
213   return !CXFA_IsTooBig(*js);
214 }
215 
CXFA_FMAssignExpression(XFA_FM_TOKEN op,CXFA_FMSimpleExpression * pExp1,CXFA_FMSimpleExpression * pExp2)216 CXFA_FMAssignExpression::CXFA_FMAssignExpression(XFA_FM_TOKEN op,
217                                                  CXFA_FMSimpleExpression* pExp1,
218                                                  CXFA_FMSimpleExpression* pExp2)
219     : CXFA_FMChainableExpression(op, pExp1, pExp2) {}
220 
221 CXFA_FMAssignExpression::~CXFA_FMAssignExpression() = default;
222 
ToJavaScript(WideTextBuffer * js,ReturnType type) const223 bool CXFA_FMAssignExpression::ToJavaScript(WideTextBuffer* js,
224                                            ReturnType type) const {
225   CXFA_FMToJavaScriptDepth depthManager;
226   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
227     return false;
228 
229   WideTextBuffer tempExp1;
230   const CXFA_FMSimpleExpression* exp1 = GetFirstExpression();
231   if (!exp1->ToJavaScript(&tempExp1, ReturnType::kInferred))
232     return false;
233 
234   *js << "if (pfm_rt.is_obj(" << tempExp1 << "))\n{\n";
235   if (type == ReturnType::kImplied)
236     *js << "pfm_ret = ";
237 
238   WideTextBuffer tempExp2;
239   const CXFA_FMSimpleExpression* exp2 = GetSecondExpression();
240   if (!exp2->ToJavaScript(&tempExp2, ReturnType::kInferred))
241     return false;
242 
243   *js << "pfm_rt.asgn_val_op(" << tempExp1 << ", " << tempExp2 << ");\n}\n";
244 
245   if (exp1->GetOperatorToken() == TOKidentifier &&
246       !tempExp1.AsStringView().EqualsASCII("this")) {
247     *js << "else\n{\n";
248     if (type == ReturnType::kImplied)
249       *js << "pfm_ret = ";
250 
251     *js << tempExp1 << " = pfm_rt.asgn_val_op";
252     *js << "(" << tempExp1 << ", " << tempExp2 << ");\n";
253     *js << "}\n";
254   }
255   return !CXFA_IsTooBig(*js);
256 }
257 
CXFA_FMBinExpression(const WideString & opName,XFA_FM_TOKEN op,CXFA_FMSimpleExpression * pExp1,CXFA_FMSimpleExpression * pExp2)258 CXFA_FMBinExpression::CXFA_FMBinExpression(const WideString& opName,
259                                            XFA_FM_TOKEN op,
260                                            CXFA_FMSimpleExpression* pExp1,
261                                            CXFA_FMSimpleExpression* pExp2)
262     : CXFA_FMChainableExpression(op, pExp1, pExp2), m_OpName(opName) {}
263 
264 CXFA_FMBinExpression::~CXFA_FMBinExpression() = default;
265 
ToJavaScript(WideTextBuffer * js,ReturnType type) const266 bool CXFA_FMBinExpression::ToJavaScript(WideTextBuffer* js,
267                                         ReturnType type) const {
268   CXFA_FMToJavaScriptDepth depthManager;
269   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
270     return false;
271 
272   *js << "pfm_rt." << m_OpName << "(";
273   if (!GetFirstExpression()->ToJavaScript(js, ReturnType::kInferred))
274     return false;
275   *js << ", ";
276   if (!GetSecondExpression()->ToJavaScript(js, ReturnType::kInferred))
277     return false;
278   *js << ")";
279   return !CXFA_IsTooBig(*js);
280 }
281 
CXFA_FMLogicalOrExpression(XFA_FM_TOKEN op,CXFA_FMSimpleExpression * pExp1,CXFA_FMSimpleExpression * pExp2)282 CXFA_FMLogicalOrExpression::CXFA_FMLogicalOrExpression(
283     XFA_FM_TOKEN op,
284     CXFA_FMSimpleExpression* pExp1,
285     CXFA_FMSimpleExpression* pExp2)
286     : CXFA_FMBinExpression(L"log_or_op", op, pExp1, pExp2) {}
287 
288 CXFA_FMLogicalOrExpression::~CXFA_FMLogicalOrExpression() = default;
289 
CXFA_FMLogicalAndExpression(XFA_FM_TOKEN op,CXFA_FMSimpleExpression * pExp1,CXFA_FMSimpleExpression * pExp2)290 CXFA_FMLogicalAndExpression::CXFA_FMLogicalAndExpression(
291     XFA_FM_TOKEN op,
292     CXFA_FMSimpleExpression* pExp1,
293     CXFA_FMSimpleExpression* pExp2)
294     : CXFA_FMBinExpression(L"log_and_op", op, pExp1, pExp2) {}
295 
296 CXFA_FMLogicalAndExpression::~CXFA_FMLogicalAndExpression() = default;
297 
CXFA_FMEqualExpression(XFA_FM_TOKEN op,CXFA_FMSimpleExpression * pExp1,CXFA_FMSimpleExpression * pExp2)298 CXFA_FMEqualExpression::CXFA_FMEqualExpression(XFA_FM_TOKEN op,
299                                                CXFA_FMSimpleExpression* pExp1,
300                                                CXFA_FMSimpleExpression* pExp2)
301     : CXFA_FMBinExpression(L"eq_op", op, pExp1, pExp2) {}
302 
303 CXFA_FMEqualExpression::~CXFA_FMEqualExpression() = default;
304 
CXFA_FMNotEqualExpression(XFA_FM_TOKEN op,CXFA_FMSimpleExpression * pExp1,CXFA_FMSimpleExpression * pExp2)305 CXFA_FMNotEqualExpression::CXFA_FMNotEqualExpression(
306     XFA_FM_TOKEN op,
307     CXFA_FMSimpleExpression* pExp1,
308     CXFA_FMSimpleExpression* pExp2)
309     : CXFA_FMBinExpression(L"neq_op", op, pExp1, pExp2) {}
310 
311 CXFA_FMNotEqualExpression::~CXFA_FMNotEqualExpression() = default;
312 
CXFA_FMGtExpression(XFA_FM_TOKEN op,CXFA_FMSimpleExpression * pExp1,CXFA_FMSimpleExpression * pExp2)313 CXFA_FMGtExpression::CXFA_FMGtExpression(XFA_FM_TOKEN op,
314                                          CXFA_FMSimpleExpression* pExp1,
315                                          CXFA_FMSimpleExpression* pExp2)
316     : CXFA_FMBinExpression(L"gt_op", op, pExp1, pExp2) {}
317 
318 CXFA_FMGtExpression::~CXFA_FMGtExpression() = default;
319 
CXFA_FMGeExpression(XFA_FM_TOKEN op,CXFA_FMSimpleExpression * pExp1,CXFA_FMSimpleExpression * pExp2)320 CXFA_FMGeExpression::CXFA_FMGeExpression(XFA_FM_TOKEN op,
321                                          CXFA_FMSimpleExpression* pExp1,
322                                          CXFA_FMSimpleExpression* pExp2)
323     : CXFA_FMBinExpression(L"ge_op", op, pExp1, pExp2) {}
324 
325 CXFA_FMGeExpression::~CXFA_FMGeExpression() = default;
326 
CXFA_FMLtExpression(XFA_FM_TOKEN op,CXFA_FMSimpleExpression * pExp1,CXFA_FMSimpleExpression * pExp2)327 CXFA_FMLtExpression::CXFA_FMLtExpression(XFA_FM_TOKEN op,
328                                          CXFA_FMSimpleExpression* pExp1,
329                                          CXFA_FMSimpleExpression* pExp2)
330     : CXFA_FMBinExpression(L"lt_op", op, pExp1, pExp2) {}
331 
332 CXFA_FMLtExpression::~CXFA_FMLtExpression() = default;
333 
CXFA_FMLeExpression(XFA_FM_TOKEN op,CXFA_FMSimpleExpression * pExp1,CXFA_FMSimpleExpression * pExp2)334 CXFA_FMLeExpression::CXFA_FMLeExpression(XFA_FM_TOKEN op,
335                                          CXFA_FMSimpleExpression* pExp1,
336                                          CXFA_FMSimpleExpression* pExp2)
337     : CXFA_FMBinExpression(L"le_op", op, pExp1, pExp2) {}
338 
339 CXFA_FMLeExpression::~CXFA_FMLeExpression() = default;
340 
CXFA_FMPlusExpression(XFA_FM_TOKEN op,CXFA_FMSimpleExpression * pExp1,CXFA_FMSimpleExpression * pExp2)341 CXFA_FMPlusExpression::CXFA_FMPlusExpression(XFA_FM_TOKEN op,
342                                              CXFA_FMSimpleExpression* pExp1,
343                                              CXFA_FMSimpleExpression* pExp2)
344     : CXFA_FMBinExpression(L"plus_op", op, pExp1, pExp2) {}
345 
346 CXFA_FMPlusExpression::~CXFA_FMPlusExpression() = default;
347 
CXFA_FMMinusExpression(XFA_FM_TOKEN op,CXFA_FMSimpleExpression * pExp1,CXFA_FMSimpleExpression * pExp2)348 CXFA_FMMinusExpression::CXFA_FMMinusExpression(XFA_FM_TOKEN op,
349                                                CXFA_FMSimpleExpression* pExp1,
350                                                CXFA_FMSimpleExpression* pExp2)
351     : CXFA_FMBinExpression(L"minus_op", op, pExp1, pExp2) {}
352 
353 CXFA_FMMinusExpression::~CXFA_FMMinusExpression() = default;
354 
CXFA_FMMulExpression(XFA_FM_TOKEN op,CXFA_FMSimpleExpression * pExp1,CXFA_FMSimpleExpression * pExp2)355 CXFA_FMMulExpression::CXFA_FMMulExpression(XFA_FM_TOKEN op,
356                                            CXFA_FMSimpleExpression* pExp1,
357                                            CXFA_FMSimpleExpression* pExp2)
358     : CXFA_FMBinExpression(L"mul_op", op, pExp1, pExp2) {}
359 
360 CXFA_FMMulExpression::~CXFA_FMMulExpression() = default;
361 
CXFA_FMDivExpression(XFA_FM_TOKEN op,CXFA_FMSimpleExpression * pExp1,CXFA_FMSimpleExpression * pExp2)362 CXFA_FMDivExpression::CXFA_FMDivExpression(XFA_FM_TOKEN op,
363                                            CXFA_FMSimpleExpression* pExp1,
364                                            CXFA_FMSimpleExpression* pExp2)
365     : CXFA_FMBinExpression(L"div_op", op, pExp1, pExp2) {}
366 
367 CXFA_FMDivExpression::~CXFA_FMDivExpression() = default;
368 
CXFA_FMUnaryExpression(const WideString & opName,XFA_FM_TOKEN op,CXFA_FMSimpleExpression * pExp)369 CXFA_FMUnaryExpression::CXFA_FMUnaryExpression(const WideString& opName,
370                                                XFA_FM_TOKEN op,
371                                                CXFA_FMSimpleExpression* pExp)
372     : CXFA_FMSimpleExpression(op), m_OpName(opName), m_pExp(pExp) {}
373 
374 CXFA_FMUnaryExpression::~CXFA_FMUnaryExpression() = default;
375 
Trace(cppgc::Visitor * visitor) const376 void CXFA_FMUnaryExpression::Trace(cppgc::Visitor* visitor) const {
377   CXFA_FMSimpleExpression::Trace(visitor);
378   visitor->Trace(m_pExp);
379 }
380 
ToJavaScript(WideTextBuffer * js,ReturnType type) const381 bool CXFA_FMUnaryExpression::ToJavaScript(WideTextBuffer* js,
382                                           ReturnType type) const {
383   CXFA_FMToJavaScriptDepth depthManager;
384   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
385     return false;
386 
387   *js << "pfm_rt." << m_OpName << "(";
388   if (!m_pExp->ToJavaScript(js, ReturnType::kInferred))
389     return false;
390   *js << ")";
391   return !CXFA_IsTooBig(*js);
392 }
393 
CXFA_FMPosExpression(CXFA_FMSimpleExpression * pExp)394 CXFA_FMPosExpression::CXFA_FMPosExpression(CXFA_FMSimpleExpression* pExp)
395     : CXFA_FMUnaryExpression(L"pos_op", TOKplus, pExp) {}
396 
397 CXFA_FMPosExpression::~CXFA_FMPosExpression() = default;
398 
CXFA_FMNegExpression(CXFA_FMSimpleExpression * pExp)399 CXFA_FMNegExpression::CXFA_FMNegExpression(CXFA_FMSimpleExpression* pExp)
400     : CXFA_FMUnaryExpression(L"neg_op", TOKminus, pExp) {}
401 
402 CXFA_FMNegExpression::~CXFA_FMNegExpression() = default;
403 
CXFA_FMNotExpression(CXFA_FMSimpleExpression * pExp)404 CXFA_FMNotExpression::CXFA_FMNotExpression(CXFA_FMSimpleExpression* pExp)
405     : CXFA_FMUnaryExpression(L"log_not_op", TOKksnot, pExp) {}
406 
407 CXFA_FMNotExpression::~CXFA_FMNotExpression() = default;
408 
CXFA_FMCallExpression(CXFA_FMSimpleExpression * pExp,std::vector<cppgc::Member<CXFA_FMSimpleExpression>> && pArguments,bool bIsSomMethod)409 CXFA_FMCallExpression::CXFA_FMCallExpression(
410     CXFA_FMSimpleExpression* pExp,
411     std::vector<cppgc::Member<CXFA_FMSimpleExpression>>&& pArguments,
412     bool bIsSomMethod)
413     : CXFA_FMSimpleExpression(TOKcall),
414       m_pExp(pExp),
415       m_Arguments(std::move(pArguments)),
416       m_bIsSomMethod(bIsSomMethod) {}
417 
418 CXFA_FMCallExpression::~CXFA_FMCallExpression() = default;
419 
Trace(cppgc::Visitor * visitor) const420 void CXFA_FMCallExpression::Trace(cppgc::Visitor* visitor) const {
421   CXFA_FMSimpleExpression::Trace(visitor);
422   visitor->Trace(m_pExp);
423   ContainerTrace(visitor, m_Arguments);
424 }
425 
IsBuiltInFunc(WideTextBuffer * funcName) const426 bool CXFA_FMCallExpression::IsBuiltInFunc(WideTextBuffer* funcName) const {
427   if (funcName->GetLength() > kBuiltInFuncsMaxLen)
428     return false;
429 
430   WideString str = funcName->MakeString();
431   const wchar_t* const* pMatchResult =
432       std::lower_bound(std::begin(kBuiltInFuncs), std::end(kBuiltInFuncs), str,
433                        [](const wchar_t* iter, const WideString& val) -> bool {
434                          return val.CompareNoCase(iter) > 0;
435                        });
436   if (pMatchResult != std::end(kBuiltInFuncs) &&
437       !str.CompareNoCase(*pMatchResult)) {
438     funcName->Clear();
439     *funcName << *pMatchResult;
440     return true;
441   }
442   return false;
443 }
444 
IsMethodWithObjParam(const WideString & methodName) const445 uint32_t CXFA_FMCallExpression::IsMethodWithObjParam(
446     const WideString& methodName) const {
447   const XFA_FMSOMMethod* result = std::lower_bound(
448       std::begin(kFMSomMethods), std::end(kFMSomMethods), methodName,
449       [](const XFA_FMSOMMethod iter, const WideString& val) {
450         return val.Compare(iter.m_wsSomMethodName) > 0;
451       });
452   if (result != std::end(kFMSomMethods) &&
453       methodName == result->m_wsSomMethodName) {
454     return result->m_dParameters;
455   }
456   return 0;
457 }
458 
ToJavaScript(WideTextBuffer * js,ReturnType type) const459 bool CXFA_FMCallExpression::ToJavaScript(WideTextBuffer* js,
460                                          ReturnType type) const {
461   CXFA_FMToJavaScriptDepth depthManager;
462   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
463     return false;
464 
465   WideTextBuffer funcName;
466   if (!m_pExp->ToJavaScript(&funcName, ReturnType::kInferred))
467     return false;
468 
469   if (m_bIsSomMethod) {
470     *js << funcName << "(";
471     uint32_t methodPara = IsMethodWithObjParam(funcName.MakeString());
472     if (methodPara > 0) {
473       for (size_t i = 0; i < m_Arguments.size(); ++i) {
474         // Currently none of our expressions use objects for a parameter over
475         // the 6th. Make sure we don't overflow the shift when doing this
476         // check. If we ever need more the 32 object params we can revisit.
477         *js << "pfm_rt.get_";
478         if (i < 32 && (methodPara & (0x01 << i)) > 0)
479           *js << "jsobj";
480         else
481           *js << "val";
482 
483         *js << "(";
484         if (!m_Arguments[i]->ToJavaScript(js, ReturnType::kInferred))
485           return false;
486         *js << ")";
487         if (i + 1 < m_Arguments.size())
488           *js << ", ";
489       }
490     } else {
491       for (const auto& expr : m_Arguments) {
492         *js << "pfm_rt.get_val(";
493         if (!expr->ToJavaScript(js, ReturnType::kInferred))
494           return false;
495         *js << ")";
496         if (expr != m_Arguments.back())
497           *js << ", ";
498       }
499     }
500     *js << ")";
501     return !CXFA_IsTooBig(*js);
502   }
503 
504   bool isEvalFunc = false;
505   bool isExistsFunc = false;
506   if (!IsBuiltInFunc(&funcName)) {
507     // If a function is not a SomMethod or a built-in then the input was
508     // invalid, so failing. The scanner/lexer should catch this, but currently
509     // doesn't. This failure will bubble up to the top-level and cause the
510     // transpile to fail.
511     return false;
512   }
513 
514   if (funcName.AsStringView().EqualsASCII("Eval")) {
515     isEvalFunc = true;
516     *js << "eval.call(this, pfm_rt.Translate";
517   } else {
518     if (funcName.AsStringView().EqualsASCII("Exists"))
519       isExistsFunc = true;
520 
521     *js << "pfm_rt." << funcName;
522   }
523 
524   *js << "(";
525   if (isExistsFunc) {
526     *js << "\n(\nfunction ()\n{\ntry\n{\n";
527     if (!m_Arguments.empty()) {
528       *js << "return ";
529       if (!m_Arguments[0]->ToJavaScript(js, ReturnType::kInferred))
530         return false;
531       *js << ";\n}\n";
532     } else {
533       *js << "return 0;\n}\n";
534     }
535     *js << "catch(accessExceptions)\n";
536     *js << "{\nreturn 0;\n}\n}\n).call(this)\n";
537   } else {
538     for (const auto& expr : m_Arguments) {
539       if (!expr->ToJavaScript(js, ReturnType::kInferred))
540         return false;
541       if (expr != m_Arguments.back())
542         *js << ", ";
543     }
544   }
545   *js << ")";
546   if (isEvalFunc)
547     *js << ")";
548 
549   return !CXFA_IsTooBig(*js);
550 }
551 
CXFA_FMDotAccessorExpression(CXFA_FMSimpleExpression * pAccessor,XFA_FM_TOKEN op,WideString wsIdentifier,CXFA_FMSimpleExpression * pIndexExp)552 CXFA_FMDotAccessorExpression::CXFA_FMDotAccessorExpression(
553     CXFA_FMSimpleExpression* pAccessor,
554     XFA_FM_TOKEN op,
555     WideString wsIdentifier,
556     CXFA_FMSimpleExpression* pIndexExp)
557     : CXFA_FMChainableExpression(op, pAccessor, pIndexExp),
558       m_wsIdentifier(std::move(wsIdentifier)) {}
559 
560 CXFA_FMDotAccessorExpression::~CXFA_FMDotAccessorExpression() = default;
561 
ToJavaScript(WideTextBuffer * js,ReturnType type) const562 bool CXFA_FMDotAccessorExpression::ToJavaScript(WideTextBuffer* js,
563                                                 ReturnType type) const {
564   CXFA_FMToJavaScriptDepth depthManager;
565   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
566     return false;
567 
568   *js << "pfm_rt.dot_acc(";
569 
570   CXFA_FMSimpleExpression* exp1 = GetFirstExpression();
571   if (exp1) {
572     // Write directly to the buffer with each recursion. Creating
573     // and copying temporaries here becomes expensive when there
574     // is deep recursion, even though we may need to re-create the
575     // same thing again below. See https://crbug.com/1274018.
576     if (!exp1->ToJavaScript(js, ReturnType::kInferred))
577       return false;
578   } else {
579     *js << "null";
580   }
581   *js << ", \"";
582   if (exp1 && exp1->GetOperatorToken() == TOKidentifier) {
583     if (!exp1->ToJavaScript(js, ReturnType::kInferred))
584       return false;
585   }
586   *js << "\", ";
587   if (GetOperatorToken() == TOKdotscream)
588     *js << "\"#" << m_wsIdentifier << "\", ";
589   else if (GetOperatorToken() == TOKdotstar)
590     *js << "\"*\", ";
591   else if (GetOperatorToken() == TOKcall)
592     *js << "\"\", ";
593   else
594     *js << "\"" << m_wsIdentifier << "\", ";
595 
596   CXFA_FMSimpleExpression* exp2 = GetSecondExpression();
597   if (!exp2->ToJavaScript(js, ReturnType::kInferred))
598     return false;
599 
600   *js << ")";
601   return !CXFA_IsTooBig(*js);
602 }
603 
CXFA_FMIndexExpression(AccessorIndex accessorIndex,CXFA_FMSimpleExpression * pIndexExp,bool bIsStarIndex)604 CXFA_FMIndexExpression::CXFA_FMIndexExpression(
605     AccessorIndex accessorIndex,
606     CXFA_FMSimpleExpression* pIndexExp,
607     bool bIsStarIndex)
608     : CXFA_FMSimpleExpression(TOKlbracket),
609       m_pExp(pIndexExp),
610       m_accessorIndex(accessorIndex),
611       m_bIsStarIndex(bIsStarIndex) {}
612 
613 CXFA_FMIndexExpression::~CXFA_FMIndexExpression() = default;
614 
Trace(cppgc::Visitor * visitor) const615 void CXFA_FMIndexExpression::Trace(cppgc::Visitor* visitor) const {
616   CXFA_FMSimpleExpression::Trace(visitor);
617   visitor->Trace(m_pExp);
618 }
619 
ToJavaScript(WideTextBuffer * js,ReturnType type) const620 bool CXFA_FMIndexExpression::ToJavaScript(WideTextBuffer* js,
621                                           ReturnType type) const {
622   CXFA_FMToJavaScriptDepth depthManager;
623   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
624     return false;
625 
626   switch (m_accessorIndex) {
627     case AccessorIndex::kNoIndex:
628       *js << "0";
629       break;
630     case AccessorIndex::kNoRelativeIndex:
631       *js << "1";
632       break;
633     case AccessorIndex::kPositiveIndex:
634       *js << "2";
635       break;
636     case AccessorIndex::kNegativeIndex:
637       *js << "3";
638       break;
639   }
640   if (m_bIsStarIndex)
641     return !CXFA_IsTooBig(*js);
642 
643   *js << ", ";
644   if (m_pExp) {
645     if (!m_pExp->ToJavaScript(js, ReturnType::kInferred))
646       return false;
647   } else {
648     *js << "0";
649   }
650   return !CXFA_IsTooBig(*js);
651 }
652 
CXFA_FMDotDotAccessorExpression(CXFA_FMSimpleExpression * pAccessor,XFA_FM_TOKEN op,WideString wsIdentifier,CXFA_FMSimpleExpression * pIndexExp)653 CXFA_FMDotDotAccessorExpression::CXFA_FMDotDotAccessorExpression(
654     CXFA_FMSimpleExpression* pAccessor,
655     XFA_FM_TOKEN op,
656     WideString wsIdentifier,
657     CXFA_FMSimpleExpression* pIndexExp)
658     : CXFA_FMChainableExpression(op, pAccessor, pIndexExp),
659       m_wsIdentifier(std::move(wsIdentifier)) {}
660 
661 CXFA_FMDotDotAccessorExpression::~CXFA_FMDotDotAccessorExpression() = default;
662 
ToJavaScript(WideTextBuffer * js,ReturnType type) const663 bool CXFA_FMDotDotAccessorExpression::ToJavaScript(WideTextBuffer* js,
664                                                    ReturnType type) const {
665   CXFA_FMToJavaScriptDepth depthManager;
666   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
667     return false;
668 
669   CXFA_FMSimpleExpression* exp1 = GetFirstExpression();
670   *js << "pfm_rt.dotdot_acc(";
671   if (!exp1->ToJavaScript(js, ReturnType::kInferred))
672     return false;
673   *js << ", "
674       << "\"";
675   if (exp1->GetOperatorToken() == TOKidentifier) {
676     if (!exp1->ToJavaScript(js, ReturnType::kInferred))
677       return false;
678   }
679 
680   CXFA_FMSimpleExpression* exp2 = GetSecondExpression();
681   *js << "\", \"" << m_wsIdentifier << "\", ";
682   if (!exp2->ToJavaScript(js, ReturnType::kInferred))
683     return false;
684   *js << ")";
685   return !CXFA_IsTooBig(*js);
686 }
687 
CXFA_FMMethodCallExpression(CXFA_FMSimpleExpression * pAccessorExp1,CXFA_FMSimpleExpression * pCallExp)688 CXFA_FMMethodCallExpression::CXFA_FMMethodCallExpression(
689     CXFA_FMSimpleExpression* pAccessorExp1,
690     CXFA_FMSimpleExpression* pCallExp)
691     : CXFA_FMChainableExpression(TOKdot, pAccessorExp1, pCallExp) {}
692 
693 CXFA_FMMethodCallExpression::~CXFA_FMMethodCallExpression() = default;
694 
ToJavaScript(WideTextBuffer * js,ReturnType type) const695 bool CXFA_FMMethodCallExpression::ToJavaScript(WideTextBuffer* js,
696                                                ReturnType type) const {
697   CXFA_FMToJavaScriptDepth depthManager;
698   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
699     return false;
700 
701   *js << "(function() {\n";
702   *js << "  return pfm_method_runner(";
703   if (!GetFirstExpression()->ToJavaScript(js, ReturnType::kInferred))
704     return false;
705 
706   *js << ", function(obj) {\n";
707   *js << "    return obj.";
708   if (!GetSecondExpression()->ToJavaScript(js, ReturnType::kInferred))
709     return false;
710 
711   *js << ";\n";
712   *js << "  });\n";
713   *js << "}).call(this)";
714   return !CXFA_IsTooBig(*js);
715 }
716 
CXFA_FMFunctionDefinition(WideString wsName,std::vector<WideString> && arguments,std::vector<cppgc::Member<CXFA_FMExpression>> && expressions)717 CXFA_FMFunctionDefinition::CXFA_FMFunctionDefinition(
718     WideString wsName,
719     std::vector<WideString>&& arguments,
720     std::vector<cppgc::Member<CXFA_FMExpression>>&& expressions)
721     : m_wsName(std::move(wsName)),
722       m_pArguments(std::move(arguments)),
723       m_pExpressions(std::move(expressions)) {
724   DCHECK(!m_wsName.IsEmpty());
725 }
726 
727 CXFA_FMFunctionDefinition::~CXFA_FMFunctionDefinition() = default;
728 
Trace(cppgc::Visitor * visitor) const729 void CXFA_FMFunctionDefinition::Trace(cppgc::Visitor* visitor) const {
730   CXFA_FMExpression::Trace(visitor);
731   ContainerTrace(visitor, m_pExpressions);
732 }
733 
ToJavaScript(WideTextBuffer * js,ReturnType type) const734 bool CXFA_FMFunctionDefinition::ToJavaScript(WideTextBuffer* js,
735                                              ReturnType type) const {
736   CXFA_FMToJavaScriptDepth depthManager;
737   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
738     return false;
739 
740   if (m_wsName.IsEmpty())
741     return false;
742 
743   *js << "function " << IdentifierToName(m_wsName) << "(";
744   for (const auto& identifier : m_pArguments) {
745     if (identifier != m_pArguments.front())
746       *js << ", ";
747 
748     *js << IdentifierToName(identifier);
749   }
750   *js << ") {\n";
751 
752   *js << "var pfm_ret = null;\n";
753   for (const auto& expr : m_pExpressions) {
754     ReturnType ret_type = expr == m_pExpressions.back() ? ReturnType::kImplied
755                                                         : ReturnType::kInferred;
756     if (!expr->ToJavaScript(js, ret_type))
757       return false;
758   }
759 
760   *js << "return pfm_ret;\n";
761   *js << "}\n";
762 
763   return !CXFA_IsTooBig(*js);
764 }
765 
CXFA_FMAST(std::vector<cppgc::Member<CXFA_FMExpression>> expressions)766 CXFA_FMAST::CXFA_FMAST(
767     std::vector<cppgc::Member<CXFA_FMExpression>> expressions)
768     : expressions_(std::move(expressions)) {}
769 
770 CXFA_FMAST::~CXFA_FMAST() = default;
771 
Trace(cppgc::Visitor * visitor) const772 void CXFA_FMAST::Trace(cppgc::Visitor* visitor) const {
773   ContainerTrace(visitor, expressions_);
774 }
775 
ToJavaScript() const776 absl::optional<WideTextBuffer> CXFA_FMAST::ToJavaScript() const {
777   WideTextBuffer js;
778   if (expressions_.empty()) {
779     js << "// comments only";
780     return js;
781   }
782 
783   js << "(function() {\n";
784   js << "let pfm_method_runner = function(obj, cb) {\n";
785   js << "  if (pfm_rt.is_ary(obj)) {\n";
786   js << "    let pfm_method_return = null;\n";
787   js << "    for (var idx = obj.length -1; idx > 1; idx--) {\n";
788   js << "      pfm_method_return = cb(obj[idx]);\n";
789   js << "    }\n";
790   js << "    return pfm_method_return;\n";
791   js << "  }\n";
792   js << "  return cb(obj);\n";
793   js << "};\n";
794   js << "var pfm_ret = null;\n";
795   for (const auto& expr : expressions_) {
796     CXFA_FMAssignExpression::ReturnType ret_type =
797         expr == expressions_.back()
798             ? CXFA_FMAssignExpression::ReturnType::kImplied
799             : CXFA_FMAssignExpression::ReturnType::kInferred;
800     if (!expr->ToJavaScript(&js, ret_type))
801       return absl::nullopt;
802   }
803   js << "return pfm_rt.get_val(pfm_ret);\n";
804   js << "}).call(this);";
805 
806   if (CXFA_IsTooBig(js))
807     return absl::nullopt;
808 
809   return js;
810 }
811 
CXFA_FMVarExpression(WideString wsName,CXFA_FMSimpleExpression * pInit)812 CXFA_FMVarExpression::CXFA_FMVarExpression(WideString wsName,
813                                            CXFA_FMSimpleExpression* pInit)
814     : m_wsName(std::move(wsName)), m_pInit(pInit) {}
815 
816 CXFA_FMVarExpression::~CXFA_FMVarExpression() = default;
817 
Trace(cppgc::Visitor * visitor) const818 void CXFA_FMVarExpression::Trace(cppgc::Visitor* visitor) const {
819   CXFA_FMExpression::Trace(visitor);
820   visitor->Trace(m_pInit);
821 }
822 
ToJavaScript(WideTextBuffer * js,ReturnType type) const823 bool CXFA_FMVarExpression::ToJavaScript(WideTextBuffer* js,
824                                         ReturnType type) const {
825   CXFA_FMToJavaScriptDepth depthManager;
826   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
827     return false;
828 
829   WideString tempName = IdentifierToName(m_wsName);
830   *js << "var " << tempName << " = ";
831   if (m_pInit) {
832     if (!m_pInit->ToJavaScript(js, ReturnType::kInferred))
833       return false;
834 
835     *js << ";\n";
836     *js << tempName << " = pfm_rt.var_filter(" << tempName << ");\n";
837   } else {
838     *js << "\"\";\n";
839   }
840 
841   if (type == ReturnType::kImplied)
842     *js << "pfm_ret = " << tempName << ";\n";
843 
844   return !CXFA_IsTooBig(*js);
845 }
846 
CXFA_FMExpExpression(CXFA_FMSimpleExpression * pExpression)847 CXFA_FMExpExpression::CXFA_FMExpExpression(CXFA_FMSimpleExpression* pExpression)
848     : m_pExpression(pExpression) {}
849 
850 CXFA_FMExpExpression::~CXFA_FMExpExpression() = default;
851 
Trace(cppgc::Visitor * visitor) const852 void CXFA_FMExpExpression::Trace(cppgc::Visitor* visitor) const {
853   CXFA_FMExpression::Trace(visitor);
854   visitor->Trace(m_pExpression);
855 }
856 
ToJavaScript(WideTextBuffer * js,ReturnType type) const857 bool CXFA_FMExpExpression::ToJavaScript(WideTextBuffer* js,
858                                         ReturnType type) const {
859   CXFA_FMToJavaScriptDepth depthManager;
860   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
861     return false;
862 
863   if (type == ReturnType::kInferred) {
864     bool ret = m_pExpression->ToJavaScript(js, ReturnType::kInferred);
865     if (m_pExpression->GetOperatorToken() != TOKassign)
866       *js << ";\n";
867 
868     return ret;
869   }
870 
871   if (m_pExpression->GetOperatorToken() == TOKassign)
872     return m_pExpression->ToJavaScript(js, ReturnType::kImplied);
873 
874   if (m_pExpression->GetOperatorToken() == TOKstar ||
875       m_pExpression->GetOperatorToken() == TOKdotstar ||
876       m_pExpression->GetOperatorToken() == TOKdotscream ||
877       m_pExpression->GetOperatorToken() == TOKdotdot ||
878       m_pExpression->GetOperatorToken() == TOKdot) {
879     *js << "pfm_ret = pfm_rt.get_val(";
880     if (!m_pExpression->ToJavaScript(js, ReturnType::kInferred))
881       return false;
882 
883     *js << ");\n";
884     return !CXFA_IsTooBig(*js);
885   }
886 
887   *js << "pfm_ret = ";
888   if (!m_pExpression->ToJavaScript(js, ReturnType::kInferred))
889     return false;
890 
891   *js << ";\n";
892   return !CXFA_IsTooBig(*js);
893 }
894 
CXFA_FMBlockExpression(std::vector<cppgc::Member<CXFA_FMExpression>> && pExpressionList)895 CXFA_FMBlockExpression::CXFA_FMBlockExpression(
896     std::vector<cppgc::Member<CXFA_FMExpression>>&& pExpressionList)
897     : m_ExpressionList(std::move(pExpressionList)) {}
898 
899 CXFA_FMBlockExpression::~CXFA_FMBlockExpression() = default;
900 
Trace(cppgc::Visitor * visitor) const901 void CXFA_FMBlockExpression::Trace(cppgc::Visitor* visitor) const {
902   CXFA_FMExpression::Trace(visitor);
903   ContainerTrace(visitor, m_ExpressionList);
904 }
905 
ToJavaScript(WideTextBuffer * js,ReturnType type) const906 bool CXFA_FMBlockExpression::ToJavaScript(WideTextBuffer* js,
907                                           ReturnType type) const {
908   CXFA_FMToJavaScriptDepth depthManager;
909   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
910     return false;
911 
912   *js << "{\n";
913   for (const auto& expr : m_ExpressionList) {
914     if (type == ReturnType::kInferred) {
915       if (!expr->ToJavaScript(js, ReturnType::kInferred))
916         return false;
917     } else {
918       ReturnType ret_type = expr == m_ExpressionList.back()
919                                 ? ReturnType::kImplied
920                                 : ReturnType::kInferred;
921       if (!expr->ToJavaScript(js, ret_type))
922         return false;
923     }
924   }
925   *js << "}\n";
926 
927   return !CXFA_IsTooBig(*js);
928 }
929 
CXFA_FMDoExpression(CXFA_FMExpression * pList)930 CXFA_FMDoExpression::CXFA_FMDoExpression(CXFA_FMExpression* pList)
931     : m_pList(pList) {}
932 
933 CXFA_FMDoExpression::~CXFA_FMDoExpression() = default;
934 
Trace(cppgc::Visitor * visitor) const935 void CXFA_FMDoExpression::Trace(cppgc::Visitor* visitor) const {
936   CXFA_FMExpression::Trace(visitor);
937   visitor->Trace(m_pList);
938 }
939 
ToJavaScript(WideTextBuffer * js,ReturnType type) const940 bool CXFA_FMDoExpression::ToJavaScript(WideTextBuffer* js,
941                                        ReturnType type) const {
942   CXFA_FMToJavaScriptDepth depthManager;
943   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
944     return false;
945 
946   return m_pList->ToJavaScript(js, type);
947 }
948 
CXFA_FMIfExpression(CXFA_FMSimpleExpression * pExpression,CXFA_FMExpression * pIfExpression,std::vector<cppgc::Member<CXFA_FMIfExpression>> && pElseIfExpressions,CXFA_FMExpression * pElseExpression)949 CXFA_FMIfExpression::CXFA_FMIfExpression(
950     CXFA_FMSimpleExpression* pExpression,
951     CXFA_FMExpression* pIfExpression,
952     std::vector<cppgc::Member<CXFA_FMIfExpression>>&& pElseIfExpressions,
953     CXFA_FMExpression* pElseExpression)
954     : m_pExpression(pExpression),
955       m_pIfExpression(pIfExpression),
956       m_pElseIfExpressions(std::move(pElseIfExpressions)),
957       m_pElseExpression(pElseExpression) {
958   DCHECK(m_pExpression);
959 }
960 
961 CXFA_FMIfExpression::~CXFA_FMIfExpression() = default;
962 
Trace(cppgc::Visitor * visitor) const963 void CXFA_FMIfExpression::Trace(cppgc::Visitor* visitor) const {
964   CXFA_FMExpression::Trace(visitor);
965   visitor->Trace(m_pExpression);
966   visitor->Trace(m_pIfExpression);
967   ContainerTrace(visitor, m_pElseIfExpressions);
968   visitor->Trace(m_pElseExpression);
969 }
970 
ToJavaScript(WideTextBuffer * js,ReturnType type) const971 bool CXFA_FMIfExpression::ToJavaScript(WideTextBuffer* js,
972                                        ReturnType type) const {
973   CXFA_FMToJavaScriptDepth depthManager;
974   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
975     return false;
976 
977   if (type == ReturnType::kImplied)
978     *js << "pfm_ret = 0;\n";
979 
980   *js << "if (pfm_rt.get_val(";
981   if (!m_pExpression->ToJavaScript(js, ReturnType::kInferred))
982     return false;
983   *js << "))\n";
984 
985   if (CXFA_IsTooBig(*js))
986     return false;
987 
988   if (m_pIfExpression) {
989     if (!m_pIfExpression->ToJavaScript(js, type))
990       return false;
991     if (CXFA_IsTooBig(*js))
992       return false;
993   }
994 
995   for (auto& expr : m_pElseIfExpressions) {
996     *js << "else ";
997     if (!expr->ToJavaScript(js, ReturnType::kInferred))
998       return false;
999   }
1000 
1001   if (m_pElseExpression) {
1002     *js << "else ";
1003     if (!m_pElseExpression->ToJavaScript(js, type))
1004       return false;
1005   }
1006   return !CXFA_IsTooBig(*js);
1007 }
1008 
CXFA_FMWhileExpression(CXFA_FMSimpleExpression * pCondition,CXFA_FMExpression * pExpression)1009 CXFA_FMWhileExpression::CXFA_FMWhileExpression(
1010     CXFA_FMSimpleExpression* pCondition,
1011     CXFA_FMExpression* pExpression)
1012     : m_pCondition(pCondition), m_pExpression(pExpression) {}
1013 
1014 CXFA_FMWhileExpression::~CXFA_FMWhileExpression() = default;
1015 
Trace(cppgc::Visitor * visitor) const1016 void CXFA_FMWhileExpression::Trace(cppgc::Visitor* visitor) const {
1017   CXFA_FMExpression::Trace(visitor);
1018   visitor->Trace(m_pCondition);
1019   visitor->Trace(m_pExpression);
1020 }
1021 
ToJavaScript(WideTextBuffer * js,ReturnType type) const1022 bool CXFA_FMWhileExpression::ToJavaScript(WideTextBuffer* js,
1023                                           ReturnType type) const {
1024   CXFA_FMToJavaScriptDepth depthManager;
1025   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
1026     return false;
1027 
1028   if (type == ReturnType::kImplied)
1029     *js << "pfm_ret = 0;\n";
1030 
1031   *js << "while (";
1032   if (!m_pCondition->ToJavaScript(js, ReturnType::kInferred))
1033     return false;
1034 
1035   *js << ")\n";
1036   if (CXFA_IsTooBig(*js))
1037     return false;
1038 
1039   if (!m_pExpression->ToJavaScript(js, type))
1040     return false;
1041 
1042   return !CXFA_IsTooBig(*js);
1043 }
1044 
CXFA_FMBreakExpression()1045 CXFA_FMBreakExpression::CXFA_FMBreakExpression() : CXFA_FMExpression() {}
1046 
1047 CXFA_FMBreakExpression::~CXFA_FMBreakExpression() = default;
1048 
ToJavaScript(WideTextBuffer * js,ReturnType type) const1049 bool CXFA_FMBreakExpression::ToJavaScript(WideTextBuffer* js,
1050                                           ReturnType type) const {
1051   CXFA_FMToJavaScriptDepth depthManager;
1052   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
1053     return false;
1054 
1055   *js << "pfm_ret = 0;\nbreak;\n";
1056   return !CXFA_IsTooBig(*js);
1057 }
1058 
CXFA_FMContinueExpression()1059 CXFA_FMContinueExpression::CXFA_FMContinueExpression() : CXFA_FMExpression() {}
1060 
1061 CXFA_FMContinueExpression::~CXFA_FMContinueExpression() = default;
1062 
ToJavaScript(WideTextBuffer * js,ReturnType type) const1063 bool CXFA_FMContinueExpression::ToJavaScript(WideTextBuffer* js,
1064                                              ReturnType type) const {
1065   CXFA_FMToJavaScriptDepth depthManager;
1066   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
1067     return false;
1068 
1069   *js << "pfm_ret = 0;\ncontinue;\n";
1070   return !CXFA_IsTooBig(*js);
1071 }
1072 
CXFA_FMForExpression(WideString wsVariant,CXFA_FMSimpleExpression * pAssignment,CXFA_FMSimpleExpression * pAccessor,int32_t iDirection,CXFA_FMSimpleExpression * pStep,CXFA_FMExpression * pList)1073 CXFA_FMForExpression::CXFA_FMForExpression(WideString wsVariant,
1074                                            CXFA_FMSimpleExpression* pAssignment,
1075                                            CXFA_FMSimpleExpression* pAccessor,
1076                                            int32_t iDirection,
1077                                            CXFA_FMSimpleExpression* pStep,
1078                                            CXFA_FMExpression* pList)
1079     : m_wsVariant(std::move(wsVariant)),
1080       m_bDirection(iDirection == 1),
1081       m_pAssignment(pAssignment),
1082       m_pAccessor(pAccessor),
1083       m_pStep(pStep),
1084       m_pList(pList) {}
1085 
1086 CXFA_FMForExpression::~CXFA_FMForExpression() = default;
1087 
Trace(cppgc::Visitor * visitor) const1088 void CXFA_FMForExpression::Trace(cppgc::Visitor* visitor) const {
1089   CXFA_FMExpression::Trace(visitor);
1090   visitor->Trace(m_pAssignment);
1091   visitor->Trace(m_pAccessor);
1092   visitor->Trace(m_pStep);
1093   visitor->Trace(m_pList);
1094 }
1095 
ToJavaScript(WideTextBuffer * js,ReturnType type) const1096 bool CXFA_FMForExpression::ToJavaScript(WideTextBuffer* js,
1097                                         ReturnType type) const {
1098   CXFA_FMToJavaScriptDepth depthManager;
1099   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
1100     return false;
1101 
1102   if (type == ReturnType::kImplied)
1103     *js << "pfm_ret = 0;\n";
1104 
1105   *js << "{\n";
1106 
1107   WideString tmpName = IdentifierToName(m_wsVariant);
1108   *js << "var " << tmpName << " = null;\n";
1109 
1110   *js << "for (" << tmpName << " = pfm_rt.get_val(";
1111   if (!m_pAssignment->ToJavaScript(js, ReturnType::kInferred))
1112     return false;
1113   *js << "); ";
1114 
1115   *js << tmpName << (m_bDirection ? kLessEqual : kGreaterEqual);
1116   *js << "pfm_rt.get_val(";
1117   if (!m_pAccessor->ToJavaScript(js, ReturnType::kInferred))
1118     return false;
1119   *js << "); ";
1120 
1121   *js << tmpName << (m_bDirection ? kPlusEqual : kMinusEqual);
1122   if (m_pStep) {
1123     *js << "pfm_rt.get_val(";
1124     if (!m_pStep->ToJavaScript(js, ReturnType::kInferred))
1125       return false;
1126     *js << ")";
1127   } else {
1128     *js << "1";
1129   }
1130   *js << ")\n";
1131   if (CXFA_IsTooBig(*js))
1132     return false;
1133 
1134   if (!m_pList->ToJavaScript(js, type))
1135     return false;
1136 
1137   *js << "}\n";
1138   return !CXFA_IsTooBig(*js);
1139 }
1140 
CXFA_FMForeachExpression(WideString wsIdentifier,std::vector<cppgc::Member<CXFA_FMSimpleExpression>> && pAccessors,CXFA_FMExpression * pList)1141 CXFA_FMForeachExpression::CXFA_FMForeachExpression(
1142     WideString wsIdentifier,
1143     std::vector<cppgc::Member<CXFA_FMSimpleExpression>>&& pAccessors,
1144     CXFA_FMExpression* pList)
1145     : m_wsIdentifier(std::move(wsIdentifier)),
1146       m_pAccessors(std::move(pAccessors)),
1147       m_pList(pList) {}
1148 
1149 CXFA_FMForeachExpression::~CXFA_FMForeachExpression() = default;
1150 
Trace(cppgc::Visitor * visitor) const1151 void CXFA_FMForeachExpression::Trace(cppgc::Visitor* visitor) const {
1152   CXFA_FMExpression::Trace(visitor);
1153   ContainerTrace(visitor, m_pAccessors);
1154   visitor->Trace(m_pList);
1155 }
1156 
ToJavaScript(WideTextBuffer * js,ReturnType type) const1157 bool CXFA_FMForeachExpression::ToJavaScript(WideTextBuffer* js,
1158                                             ReturnType type) const {
1159   CXFA_FMToJavaScriptDepth depthManager;
1160   if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
1161     return false;
1162 
1163   if (type == ReturnType::kImplied)
1164     *js << "pfm_ret = 0;\n";
1165 
1166   *js << "{\n";
1167 
1168   WideString tmpName = IdentifierToName(m_wsIdentifier);
1169   *js << "var " << tmpName << " = null;\n";
1170   *js << "var pfm_ary = pfm_rt.concat_obj(";
1171   for (const auto& expr : m_pAccessors) {
1172     if (!expr->ToJavaScript(js, ReturnType::kInferred))
1173       return false;
1174     if (expr != m_pAccessors.back())
1175       *js << ", ";
1176   }
1177   *js << ");\n";
1178 
1179   *js << "var pfm_ary_idx = 0;\n";
1180   *js << "while(pfm_ary_idx < pfm_ary.length)\n{\n";
1181   *js << tmpName << " = pfm_ary[pfm_ary_idx++];\n";
1182   if (!m_pList->ToJavaScript(js, type))
1183     return false;
1184 
1185   *js << "}\n";  // while
1186   *js << "}\n";  // block
1187   return !CXFA_IsTooBig(*js);
1188 }
1189 
CXFA_IsTooBig(const WideTextBuffer & js)1190 bool CXFA_IsTooBig(const WideTextBuffer& js) {
1191   return js.GetSize() >= 256 * 1024 * 1024;
1192 }
1193