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_fmexpression.h"
8
9 #include <utility>
10
11 #include "core/fxcrt/cfx_widetextbuf.h"
12 #include "xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h"
13 #include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h"
14
15 namespace {
16
17 const wchar_t kLessEqual[] = L" <= ";
18 const wchar_t kGreaterEqual[] = L" >= ";
19 const wchar_t kPlusEqual[] = L" += ";
20 const wchar_t kMinusEqual[] = L" -= ";
21
IdentifierToName(WideStringView ident)22 WideString IdentifierToName(WideStringView ident) {
23 if (ident.IsEmpty())
24 return WideString();
25 if (ident[0] != L'!')
26 return WideString(ident);
27 return L"pfm__excl__" + ident.Last(ident.GetLength() - 1);
28 }
29
30 } // namespace
31
32 CXFA_FMExpression::CXFA_FMExpression() = default;
33
CXFA_FMFunctionDefinition(WideStringView wsName,std::vector<WideStringView> && arguments,std::vector<std::unique_ptr<CXFA_FMExpression>> && expressions)34 CXFA_FMFunctionDefinition::CXFA_FMFunctionDefinition(
35 WideStringView wsName,
36 std::vector<WideStringView>&& arguments,
37 std::vector<std::unique_ptr<CXFA_FMExpression>>&& expressions)
38 : CXFA_FMExpression(),
39 m_wsName(wsName),
40 m_pArguments(std::move(arguments)),
41 m_pExpressions(std::move(expressions)) {
42 ASSERT(!wsName.IsEmpty());
43 }
44
45 CXFA_FMFunctionDefinition::~CXFA_FMFunctionDefinition() = default;
46
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)47 bool CXFA_FMFunctionDefinition::ToJavaScript(CFX_WideTextBuf* js,
48 ReturnType type) {
49 CXFA_FMToJavaScriptDepth depthManager;
50 if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
51 return false;
52
53 if (m_wsName.IsEmpty())
54 return false;
55
56 *js << "function " << IdentifierToName(m_wsName) << "(";
57 for (const auto& identifier : m_pArguments) {
58 if (identifier != m_pArguments.front())
59 *js << ", ";
60
61 *js << IdentifierToName(identifier);
62 }
63 *js << ") {\n";
64
65 *js << "var pfm_ret = null;\n";
66 for (const auto& expr : m_pExpressions) {
67 ReturnType ret_type = expr == m_pExpressions.back() ? ReturnType::kImplied
68 : ReturnType::kInfered;
69 if (!expr->ToJavaScript(js, ret_type))
70 return false;
71 }
72
73 *js << "return pfm_ret;\n";
74 *js << "}\n";
75
76 return !CXFA_IsTooBig(js);
77 }
78
CXFA_FMAST(std::vector<std::unique_ptr<CXFA_FMExpression>> expressions)79 CXFA_FMAST::CXFA_FMAST(
80 std::vector<std::unique_ptr<CXFA_FMExpression>> expressions)
81 : expressions_(std::move(expressions)) {}
82
83 CXFA_FMAST::~CXFA_FMAST() = default;
84
ToJavaScript(CFX_WideTextBuf * js)85 bool CXFA_FMAST::ToJavaScript(CFX_WideTextBuf* js) {
86 if (expressions_.empty()) {
87 *js << "// comments only";
88 return !CXFA_IsTooBig(js);
89 }
90
91 *js << "(function() {\n";
92 *js << "let pfm_method_runner = function(obj, cb) {\n";
93 *js << " if (pfm_rt.is_ary(obj)) {\n";
94 *js << " let pfm_method_return = null;\n";
95 *js << " for (var idx = obj.length -1; idx > 1; idx--) {\n";
96 *js << " pfm_method_return = cb(obj[idx]);\n";
97 *js << " }\n";
98 *js << " return pfm_method_return;\n";
99 *js << " }\n";
100 *js << " return cb(obj);\n";
101 *js << "};\n";
102 *js << "var pfm_ret = null;\n";
103
104 for (const auto& expr : expressions_) {
105 ReturnType ret_type = expr == expressions_.back() ? ReturnType::kImplied
106 : ReturnType::kInfered;
107 if (!expr->ToJavaScript(js, ret_type))
108 return false;
109 }
110
111 *js << "return pfm_rt.get_val(pfm_ret);\n";
112 *js << "}).call(this);";
113 return !CXFA_IsTooBig(js);
114 }
115
CXFA_FMVarExpression(WideStringView wsName,std::unique_ptr<CXFA_FMSimpleExpression> pInit)116 CXFA_FMVarExpression::CXFA_FMVarExpression(
117 WideStringView wsName,
118 std::unique_ptr<CXFA_FMSimpleExpression> pInit)
119 : CXFA_FMExpression(), m_wsName(wsName), m_pInit(std::move(pInit)) {}
120
121 CXFA_FMVarExpression::~CXFA_FMVarExpression() = default;
122
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)123 bool CXFA_FMVarExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) {
124 CXFA_FMToJavaScriptDepth depthManager;
125 if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
126 return false;
127
128 WideString tempName = IdentifierToName(m_wsName);
129 *js << "var " << tempName << " = ";
130 if (m_pInit) {
131 if (!m_pInit->ToJavaScript(js, ReturnType::kInfered))
132 return false;
133
134 *js << ";\n";
135 *js << tempName << " = pfm_rt.var_filter(" << tempName << ");\n";
136 } else {
137 *js << "\"\";\n";
138 }
139
140 if (type == ReturnType::kImplied)
141 *js << "pfm_ret = " << tempName << ";\n";
142
143 return !CXFA_IsTooBig(js);
144 }
145
CXFA_FMExpExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExpression)146 CXFA_FMExpExpression::CXFA_FMExpExpression(
147 std::unique_ptr<CXFA_FMSimpleExpression> pExpression)
148 : CXFA_FMExpression(), m_pExpression(std::move(pExpression)) {}
149
150 CXFA_FMExpExpression::~CXFA_FMExpExpression() = default;
151
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)152 bool CXFA_FMExpExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) {
153 CXFA_FMToJavaScriptDepth depthManager;
154 if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
155 return false;
156
157 if (type == ReturnType::kInfered) {
158 bool ret = m_pExpression->ToJavaScript(js, ReturnType::kInfered);
159 if (m_pExpression->GetOperatorToken() != TOKassign)
160 *js << ";\n";
161
162 return ret;
163 }
164
165 if (m_pExpression->GetOperatorToken() == TOKassign)
166 return m_pExpression->ToJavaScript(js, ReturnType::kImplied);
167
168 if (m_pExpression->GetOperatorToken() == TOKstar ||
169 m_pExpression->GetOperatorToken() == TOKdotstar ||
170 m_pExpression->GetOperatorToken() == TOKdotscream ||
171 m_pExpression->GetOperatorToken() == TOKdotdot ||
172 m_pExpression->GetOperatorToken() == TOKdot) {
173 *js << "pfm_ret = pfm_rt.get_val(";
174 if (!m_pExpression->ToJavaScript(js, ReturnType::kInfered))
175 return false;
176
177 *js << ");\n";
178 return !CXFA_IsTooBig(js);
179 }
180
181 *js << "pfm_ret = ";
182 if (!m_pExpression->ToJavaScript(js, ReturnType::kInfered))
183 return false;
184
185 *js << ";\n";
186 return !CXFA_IsTooBig(js);
187 }
188
CXFA_FMBlockExpression(std::vector<std::unique_ptr<CXFA_FMExpression>> && pExpressionList)189 CXFA_FMBlockExpression::CXFA_FMBlockExpression(
190 std::vector<std::unique_ptr<CXFA_FMExpression>>&& pExpressionList)
191 : CXFA_FMExpression(), m_ExpressionList(std::move(pExpressionList)) {}
192
193 CXFA_FMBlockExpression::~CXFA_FMBlockExpression() = default;
194
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)195 bool CXFA_FMBlockExpression::ToJavaScript(CFX_WideTextBuf* js,
196 ReturnType type) {
197 CXFA_FMToJavaScriptDepth depthManager;
198 if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
199 return false;
200
201 *js << "{\n";
202 for (const auto& expr : m_ExpressionList) {
203 if (type == ReturnType::kInfered) {
204 if (!expr->ToJavaScript(js, ReturnType::kInfered))
205 return false;
206 } else {
207 ReturnType ret_type = expr == m_ExpressionList.back()
208 ? ReturnType::kImplied
209 : ReturnType::kInfered;
210 if (!expr->ToJavaScript(js, ret_type))
211 return false;
212 }
213 }
214 *js << "}\n";
215
216 return !CXFA_IsTooBig(js);
217 }
218
CXFA_FMDoExpression(std::unique_ptr<CXFA_FMExpression> pList)219 CXFA_FMDoExpression::CXFA_FMDoExpression(
220 std::unique_ptr<CXFA_FMExpression> pList)
221 : CXFA_FMExpression(), m_pList(std::move(pList)) {}
222
223 CXFA_FMDoExpression::~CXFA_FMDoExpression() = default;
224
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)225 bool CXFA_FMDoExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) {
226 CXFA_FMToJavaScriptDepth depthManager;
227 if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
228 return false;
229
230 return m_pList->ToJavaScript(js, type);
231 }
232
CXFA_FMIfExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExpression,std::unique_ptr<CXFA_FMExpression> pIfExpression,std::vector<std::unique_ptr<CXFA_FMIfExpression>> pElseIfExpressions,std::unique_ptr<CXFA_FMExpression> pElseExpression)233 CXFA_FMIfExpression::CXFA_FMIfExpression(
234 std::unique_ptr<CXFA_FMSimpleExpression> pExpression,
235 std::unique_ptr<CXFA_FMExpression> pIfExpression,
236 std::vector<std::unique_ptr<CXFA_FMIfExpression>> pElseIfExpressions,
237 std::unique_ptr<CXFA_FMExpression> pElseExpression)
238 : CXFA_FMExpression(),
239 m_pExpression(std::move(pExpression)),
240 m_pIfExpression(std::move(pIfExpression)),
241 m_pElseIfExpressions(std::move(pElseIfExpressions)),
242 m_pElseExpression(std::move(pElseExpression)) {
243 ASSERT(m_pExpression);
244 }
245
246 CXFA_FMIfExpression::~CXFA_FMIfExpression() = default;
247
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)248 bool CXFA_FMIfExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) {
249 CXFA_FMToJavaScriptDepth depthManager;
250 if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
251 return false;
252
253 if (type == ReturnType::kImplied)
254 *js << "pfm_ret = 0;\n";
255
256 *js << "if (pfm_rt.get_val(";
257 if (!m_pExpression->ToJavaScript(js, ReturnType::kInfered))
258 return false;
259 *js << "))\n";
260
261 if (CXFA_IsTooBig(js))
262 return false;
263
264 if (m_pIfExpression) {
265 if (!m_pIfExpression->ToJavaScript(js, type))
266 return false;
267 if (CXFA_IsTooBig(js))
268 return false;
269 }
270
271 for (auto& expr : m_pElseIfExpressions) {
272 *js << "else ";
273 if (!expr->ToJavaScript(js, ReturnType::kInfered))
274 return false;
275 }
276
277 if (m_pElseExpression) {
278 *js << "else ";
279 if (!m_pElseExpression->ToJavaScript(js, type))
280 return false;
281 }
282 return !CXFA_IsTooBig(js);
283 }
284
CXFA_FMWhileExpression(std::unique_ptr<CXFA_FMSimpleExpression> pCondition,std::unique_ptr<CXFA_FMExpression> pExpression)285 CXFA_FMWhileExpression::CXFA_FMWhileExpression(
286 std::unique_ptr<CXFA_FMSimpleExpression> pCondition,
287 std::unique_ptr<CXFA_FMExpression> pExpression)
288 : CXFA_FMExpression(),
289 m_pCondition(std::move(pCondition)),
290 m_pExpression(std::move(pExpression)) {}
291
292 CXFA_FMWhileExpression::~CXFA_FMWhileExpression() = default;
293
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)294 bool CXFA_FMWhileExpression::ToJavaScript(CFX_WideTextBuf* js,
295 ReturnType type) {
296 CXFA_FMToJavaScriptDepth depthManager;
297 if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
298 return false;
299
300 if (type == ReturnType::kImplied)
301 *js << "pfm_ret = 0;\n";
302
303 *js << "while (";
304 if (!m_pCondition->ToJavaScript(js, ReturnType::kInfered))
305 return false;
306
307 *js << ")\n";
308 if (CXFA_IsTooBig(js))
309 return false;
310
311 if (!m_pExpression->ToJavaScript(js, type))
312 return false;
313
314 return !CXFA_IsTooBig(js);
315 }
316
CXFA_FMBreakExpression()317 CXFA_FMBreakExpression::CXFA_FMBreakExpression() : CXFA_FMExpression() {}
318
319 CXFA_FMBreakExpression::~CXFA_FMBreakExpression() = default;
320
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)321 bool CXFA_FMBreakExpression::ToJavaScript(CFX_WideTextBuf* js,
322 ReturnType type) {
323 CXFA_FMToJavaScriptDepth depthManager;
324 if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
325 return false;
326
327 *js << "pfm_ret = 0;\nbreak;\n";
328 return !CXFA_IsTooBig(js);
329 }
330
CXFA_FMContinueExpression()331 CXFA_FMContinueExpression::CXFA_FMContinueExpression() : CXFA_FMExpression() {}
332
333 CXFA_FMContinueExpression::~CXFA_FMContinueExpression() = default;
334
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)335 bool CXFA_FMContinueExpression::ToJavaScript(CFX_WideTextBuf* js,
336 ReturnType type) {
337 CXFA_FMToJavaScriptDepth depthManager;
338 if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
339 return false;
340
341 *js << "pfm_ret = 0;\ncontinue;\n";
342 return !CXFA_IsTooBig(js);
343 }
344
CXFA_FMForExpression(WideStringView wsVariant,std::unique_ptr<CXFA_FMSimpleExpression> pAssignment,std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,int32_t iDirection,std::unique_ptr<CXFA_FMSimpleExpression> pStep,std::unique_ptr<CXFA_FMExpression> pList)345 CXFA_FMForExpression::CXFA_FMForExpression(
346 WideStringView wsVariant,
347 std::unique_ptr<CXFA_FMSimpleExpression> pAssignment,
348 std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
349 int32_t iDirection,
350 std::unique_ptr<CXFA_FMSimpleExpression> pStep,
351 std::unique_ptr<CXFA_FMExpression> pList)
352 : CXFA_FMExpression(),
353 m_wsVariant(wsVariant),
354 m_pAssignment(std::move(pAssignment)),
355 m_pAccessor(std::move(pAccessor)),
356 m_bDirection(iDirection == 1),
357 m_pStep(std::move(pStep)),
358 m_pList(std::move(pList)) {}
359
360 CXFA_FMForExpression::~CXFA_FMForExpression() = default;
361
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)362 bool CXFA_FMForExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) {
363 CXFA_FMToJavaScriptDepth depthManager;
364 if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
365 return false;
366
367 if (type == ReturnType::kImplied)
368 *js << "pfm_ret = 0;\n";
369
370 *js << "{\n";
371
372 WideString tmpName = IdentifierToName(m_wsVariant);
373 *js << "var " << tmpName << " = null;\n";
374
375 *js << "for (" << tmpName << " = pfm_rt.get_val(";
376 if (!m_pAssignment->ToJavaScript(js, ReturnType::kInfered))
377 return false;
378 *js << "); ";
379
380 *js << tmpName << (m_bDirection ? kLessEqual : kGreaterEqual);
381 *js << "pfm_rt.get_val(";
382 if (!m_pAccessor->ToJavaScript(js, ReturnType::kInfered))
383 return false;
384 *js << "); ";
385
386 *js << tmpName << (m_bDirection ? kPlusEqual : kMinusEqual);
387 if (m_pStep) {
388 *js << "pfm_rt.get_val(";
389 if (!m_pStep->ToJavaScript(js, ReturnType::kInfered))
390 return false;
391 *js << ")";
392 } else {
393 *js << "1";
394 }
395 *js << ")\n";
396 if (CXFA_IsTooBig(js))
397 return false;
398
399 if (!m_pList->ToJavaScript(js, type))
400 return false;
401
402 *js << "}\n";
403 return !CXFA_IsTooBig(js);
404 }
405
CXFA_FMForeachExpression(WideStringView wsIdentifier,std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> && pAccessors,std::unique_ptr<CXFA_FMExpression> pList)406 CXFA_FMForeachExpression::CXFA_FMForeachExpression(
407 WideStringView wsIdentifier,
408 std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>&& pAccessors,
409 std::unique_ptr<CXFA_FMExpression> pList)
410 : CXFA_FMExpression(),
411 m_wsIdentifier(wsIdentifier),
412 m_pAccessors(std::move(pAccessors)),
413 m_pList(std::move(pList)) {}
414
415 CXFA_FMForeachExpression::~CXFA_FMForeachExpression() = default;
416
ToJavaScript(CFX_WideTextBuf * js,ReturnType type)417 bool CXFA_FMForeachExpression::ToJavaScript(CFX_WideTextBuf* js,
418 ReturnType type) {
419 CXFA_FMToJavaScriptDepth depthManager;
420 if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
421 return false;
422
423 if (type == ReturnType::kImplied)
424 *js << "pfm_ret = 0;\n";
425
426 *js << "{\n";
427
428 WideString tmpName = IdentifierToName(m_wsIdentifier);
429 *js << "var " << tmpName << " = null;\n";
430 *js << "var pfm_ary = pfm_rt.concat_obj(";
431 for (const auto& expr : m_pAccessors) {
432 if (!expr->ToJavaScript(js, ReturnType::kInfered))
433 return false;
434 if (expr != m_pAccessors.back())
435 *js << ", ";
436 }
437 *js << ");\n";
438
439 *js << "var pfm_ary_idx = 0;\n";
440 *js << "while(pfm_ary_idx < pfm_ary.length)\n{\n";
441 *js << tmpName << " = pfm_ary[pfm_ary_idx++];\n";
442 if (!m_pList->ToJavaScript(js, type))
443 return false;
444 *js << "}\n"; // while
445
446 *js << "}\n"; // block
447 return !CXFA_IsTooBig(js);
448 }
449