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