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