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