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
15namespace {
16
17const wchar_t RUNTIMEBLOCKTEMPARRAY[] = L"pfm_ary";
18
19const wchar_t RUNTIMEBLOCKTEMPARRAYINDEX[] = L"pfm_ary_idx";
20
21const wchar_t kLessEqual[] = L" <= ";
22const wchar_t kGreaterEqual[] = L" >= ";
23const wchar_t kPlusEqual[] = L" += ";
24const wchar_t kMinusEqual[] = L" -= ";
25
26}  // namespace
27
28CXFA_FMExpression::CXFA_FMExpression(uint32_t line)
29    : m_type(XFA_FM_EXPTYPE_UNKNOWN), m_line(line) {}
30
31CXFA_FMExpression::CXFA_FMExpression(uint32_t line, XFA_FM_EXPTYPE type)
32    : m_type(type), m_line(line) {}
33
34bool CXFA_FMExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
35  CXFA_FMToJavaScriptDepth depthManager;
36  return !CXFA_IsTooBig(javascript) && depthManager.IsWithinMaxDepth();
37}
38
39bool CXFA_FMExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
40  CXFA_FMToJavaScriptDepth depthManager;
41  return !CXFA_IsTooBig(javascript) && depthManager.IsWithinMaxDepth();
42}
43
44CXFA_FMFunctionDefinition::CXFA_FMFunctionDefinition(
45    uint32_t line,
46    bool isGlobal,
47    const WideStringView& wsName,
48    std::vector<WideStringView>&& arguments,
49    std::vector<std::unique_ptr<CXFA_FMExpression>>&& expressions)
50    : CXFA_FMExpression(line, XFA_FM_EXPTYPE_FUNC),
51      m_wsName(wsName),
52      m_pArguments(std::move(arguments)),
53      m_pExpressions(std::move(expressions)),
54      m_isGlobal(isGlobal) {}
55
56CXFA_FMFunctionDefinition::~CXFA_FMFunctionDefinition() {}
57
58bool CXFA_FMFunctionDefinition::ToJavaScript(CFX_WideTextBuf& javascript) {
59  CXFA_FMToJavaScriptDepth depthManager;
60  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
61    return false;
62
63  if (m_isGlobal && m_pExpressions.empty()) {
64    javascript << L"// comments only";
65    return !CXFA_IsTooBig(javascript);
66  }
67  if (m_isGlobal) {
68    javascript << L"(\n";
69  }
70  javascript << L"function ";
71  if (!m_wsName.IsEmpty() && m_wsName[0] == L'!') {
72    WideString tempName =
73        EXCLAMATION_IN_IDENTIFIER + m_wsName.Right(m_wsName.GetLength() - 1);
74    javascript << tempName;
75  } else {
76    javascript << m_wsName;
77  }
78  javascript << L"(";
79  bool bNeedComma = false;
80  for (const auto& identifier : m_pArguments) {
81    if (bNeedComma)
82      javascript << L", ";
83    if (identifier[0] == L'!') {
84      WideString tempIdentifier = EXCLAMATION_IN_IDENTIFIER +
85                                  identifier.Right(identifier.GetLength() - 1);
86      javascript << tempIdentifier;
87    } else {
88      javascript << identifier;
89    }
90    bNeedComma = true;
91  }
92  javascript << L")\n{\n";
93  javascript << L"var ";
94  javascript << RUNTIMEFUNCTIONRETURNVALUE;
95  javascript << L" = null;\n";
96  for (const auto& expr : m_pExpressions) {
97    bool ret;
98    if (expr == m_pExpressions.back())
99      ret = expr->ToImpliedReturnJS(javascript);
100    else
101      ret = expr->ToJavaScript(javascript);
102
103    if (!ret)
104      return false;
105  }
106  javascript << L"return ";
107  if (m_isGlobal) {
108    javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
109    javascript << L"(";
110    javascript << RUNTIMEFUNCTIONRETURNVALUE;
111    javascript << L")";
112  } else {
113    javascript << RUNTIMEFUNCTIONRETURNVALUE;
114  }
115  javascript << L";\n}\n";
116  if (m_isGlobal) {
117    javascript << L").call(this);\n";
118  }
119  return !CXFA_IsTooBig(javascript);
120}
121
122bool CXFA_FMFunctionDefinition::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
123  CXFA_FMToJavaScriptDepth depthManager;
124  return !CXFA_IsTooBig(javascript) && depthManager.IsWithinMaxDepth();
125}
126
127CXFA_FMVarExpression::CXFA_FMVarExpression(
128    uint32_t line,
129    const WideStringView& wsName,
130    std::unique_ptr<CXFA_FMExpression> pInit)
131    : CXFA_FMExpression(line, XFA_FM_EXPTYPE_VAR),
132      m_wsName(wsName),
133      m_pInit(std::move(pInit)) {}
134
135CXFA_FMVarExpression::~CXFA_FMVarExpression() {}
136
137bool CXFA_FMVarExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
138  CXFA_FMToJavaScriptDepth depthManager;
139  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
140    return false;
141
142  javascript << L"var ";
143  WideString tempName(m_wsName);
144  if (m_wsName[0] == L'!') {
145    tempName =
146        EXCLAMATION_IN_IDENTIFIER + m_wsName.Right(m_wsName.GetLength() - 1);
147  }
148  javascript << tempName;
149  javascript << L" = ";
150  if (m_pInit) {
151    if (!m_pInit->ToJavaScript(javascript))
152      return false;
153    javascript << tempName;
154    javascript << L" = ";
155    javascript << XFA_FM_EXPTypeToString(VARFILTER);
156    javascript << L"(";
157    javascript << tempName;
158    javascript << L");\n";
159  } else {
160    javascript << L"\"\";\n";
161  }
162  return !CXFA_IsTooBig(javascript);
163}
164
165bool CXFA_FMVarExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
166  CXFA_FMToJavaScriptDepth depthManager;
167  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
168    return false;
169
170  javascript << L"var ";
171  WideString tempName(m_wsName);
172  if (m_wsName[0] == L'!') {
173    tempName =
174        EXCLAMATION_IN_IDENTIFIER + m_wsName.Right(m_wsName.GetLength() - 1);
175  }
176  javascript << tempName;
177  javascript << L" = ";
178  if (m_pInit) {
179    if (!m_pInit->ToJavaScript(javascript))
180      return false;
181    javascript << tempName;
182    javascript << L" = ";
183    javascript << XFA_FM_EXPTypeToString(VARFILTER);
184    javascript << L"(";
185    javascript << tempName;
186    javascript << L");\n";
187  } else {
188    javascript << L"\"\";\n";
189  }
190  javascript << RUNTIMEFUNCTIONRETURNVALUE;
191  javascript << L" = ";
192  javascript << tempName;
193  javascript << L";\n";
194  return !CXFA_IsTooBig(javascript);
195}
196
197CXFA_FMExpExpression::CXFA_FMExpExpression(
198    uint32_t line,
199    std::unique_ptr<CXFA_FMSimpleExpression> pExpression)
200    : CXFA_FMExpression(line, XFA_FM_EXPTYPE_EXP),
201      m_pExpression(std::move(pExpression)) {}
202
203CXFA_FMExpExpression::~CXFA_FMExpExpression() {}
204
205bool CXFA_FMExpExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
206  CXFA_FMToJavaScriptDepth depthManager;
207  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
208    return false;
209
210  bool ret = m_pExpression->ToJavaScript(javascript);
211  if (m_pExpression->GetOperatorToken() != TOKassign)
212    javascript << L";\n";
213  return ret;
214}
215
216bool CXFA_FMExpExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
217  CXFA_FMToJavaScriptDepth depthManager;
218  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
219    return false;
220
221  if (m_pExpression->GetOperatorToken() == TOKassign)
222    return m_pExpression->ToImpliedReturnJS(javascript);
223
224  if (m_pExpression->GetOperatorToken() == TOKstar ||
225      m_pExpression->GetOperatorToken() == TOKdotstar ||
226      m_pExpression->GetOperatorToken() == TOKdotscream ||
227      m_pExpression->GetOperatorToken() == TOKdotdot ||
228      m_pExpression->GetOperatorToken() == TOKdot) {
229    javascript << RUNTIMEFUNCTIONRETURNVALUE;
230    javascript << L" = ";
231    javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
232    javascript << L"(";
233    if (!m_pExpression->ToJavaScript(javascript))
234      return false;
235    javascript << L");\n";
236    return !CXFA_IsTooBig(javascript);
237  }
238
239  javascript << RUNTIMEFUNCTIONRETURNVALUE;
240  javascript << L" = ";
241  if (!m_pExpression->ToJavaScript(javascript))
242    return false;
243  javascript << L";\n";
244  return !CXFA_IsTooBig(javascript);
245}
246
247CXFA_FMBlockExpression::CXFA_FMBlockExpression(
248    uint32_t line,
249    std::vector<std::unique_ptr<CXFA_FMExpression>>&& pExpressionList)
250    : CXFA_FMExpression(line, XFA_FM_EXPTYPE_BLOCK),
251      m_ExpressionList(std::move(pExpressionList)) {}
252
253CXFA_FMBlockExpression::~CXFA_FMBlockExpression() {}
254
255bool CXFA_FMBlockExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
256  CXFA_FMToJavaScriptDepth depthManager;
257  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
258    return false;
259
260  javascript << L"{\n";
261  for (const auto& expr : m_ExpressionList) {
262    if (!expr->ToJavaScript(javascript))
263      return false;
264  }
265  javascript << L"}\n";
266  return !CXFA_IsTooBig(javascript);
267}
268
269bool CXFA_FMBlockExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
270  CXFA_FMToJavaScriptDepth depthManager;
271  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
272    return false;
273
274  javascript << L"{\n";
275  for (const auto& expr : m_ExpressionList) {
276    bool ret;
277    if (expr == m_ExpressionList.back())
278      ret = expr->ToImpliedReturnJS(javascript);
279    else
280      ret = expr->ToJavaScript(javascript);
281
282    if (!ret)
283      return false;
284  }
285  javascript << L"}\n";
286  return !CXFA_IsTooBig(javascript);
287}
288
289CXFA_FMDoExpression::CXFA_FMDoExpression(
290    uint32_t line,
291    std::unique_ptr<CXFA_FMExpression> pList)
292    : CXFA_FMExpression(line), m_pList(std::move(pList)) {}
293
294CXFA_FMDoExpression::~CXFA_FMDoExpression() {}
295
296bool CXFA_FMDoExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
297  CXFA_FMToJavaScriptDepth depthManager;
298  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
299    return false;
300
301  return m_pList->ToJavaScript(javascript);
302}
303
304bool CXFA_FMDoExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
305  CXFA_FMToJavaScriptDepth depthManager;
306  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
307    return false;
308
309  return m_pList->ToImpliedReturnJS(javascript);
310}
311
312CXFA_FMIfExpression::CXFA_FMIfExpression(
313    uint32_t line,
314    std::unique_ptr<CXFA_FMSimpleExpression> pExpression,
315    std::unique_ptr<CXFA_FMExpression> pIfExpression,
316    std::unique_ptr<CXFA_FMExpression> pElseExpression)
317    : CXFA_FMExpression(line, XFA_FM_EXPTYPE_IF),
318      m_pExpression(std::move(pExpression)),
319      m_pIfExpression(std::move(pIfExpression)),
320      m_pElseExpression(std::move(pElseExpression)) {}
321
322CXFA_FMIfExpression::~CXFA_FMIfExpression() {}
323
324bool CXFA_FMIfExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
325  CXFA_FMToJavaScriptDepth depthManager;
326  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
327    return false;
328
329  javascript << L"if (";
330  if (m_pExpression) {
331    javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
332    javascript << L"(";
333    if (!m_pExpression->ToJavaScript(javascript))
334      return false;
335    javascript << L")";
336  }
337  javascript << L")\n";
338  if (CXFA_IsTooBig(javascript))
339    return false;
340
341  if (m_pIfExpression) {
342    if (!m_pIfExpression->ToJavaScript(javascript))
343      return false;
344    if (CXFA_IsTooBig(javascript))
345      return false;
346  }
347
348  if (m_pElseExpression) {
349    if (m_pElseExpression->GetExpType() == XFA_FM_EXPTYPE_IF) {
350      javascript << L"else\n";
351      javascript << L"{\n";
352      if (!m_pElseExpression->ToJavaScript(javascript))
353        return false;
354      javascript << L"}\n";
355    } else {
356      javascript << L"else\n";
357      if (!m_pElseExpression->ToJavaScript(javascript))
358        return false;
359    }
360  }
361  return !CXFA_IsTooBig(javascript);
362}
363
364bool CXFA_FMIfExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
365  CXFA_FMToJavaScriptDepth depthManager;
366  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
367    return false;
368
369  javascript << RUNTIMEFUNCTIONRETURNVALUE;
370  javascript << L" = 0;\n";
371  javascript << L"if (";
372  if (m_pExpression) {
373    javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
374    javascript << L"(";
375    if (!m_pExpression->ToJavaScript(javascript))
376      return false;
377    javascript << L")";
378  }
379  javascript << L")\n";
380  if (CXFA_IsTooBig(javascript))
381    return false;
382
383  if (m_pIfExpression) {
384    if (!m_pIfExpression->ToImpliedReturnJS(javascript))
385      return false;
386    if (CXFA_IsTooBig(javascript))
387      return false;
388  }
389  if (m_pElseExpression) {
390    if (m_pElseExpression->GetExpType() == XFA_FM_EXPTYPE_IF) {
391      javascript << L"else\n";
392      javascript << L"{\n";
393      if (!m_pElseExpression->ToImpliedReturnJS(javascript))
394        return false;
395      javascript << L"}\n";
396    } else {
397      javascript << L"else\n";
398      if (!m_pElseExpression->ToImpliedReturnJS(javascript))
399        return false;
400    }
401  }
402  return !CXFA_IsTooBig(javascript);
403}
404
405CXFA_FMLoopExpression::~CXFA_FMLoopExpression() {}
406
407bool CXFA_FMLoopExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
408  CXFA_FMToJavaScriptDepth depthManager;
409  return !CXFA_IsTooBig(javascript) && depthManager.IsWithinMaxDepth();
410}
411
412bool CXFA_FMLoopExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
413  CXFA_FMToJavaScriptDepth depthManager;
414  return !CXFA_IsTooBig(javascript) && depthManager.IsWithinMaxDepth();
415}
416
417CXFA_FMWhileExpression::CXFA_FMWhileExpression(
418    uint32_t line,
419    std::unique_ptr<CXFA_FMSimpleExpression> pCondition,
420    std::unique_ptr<CXFA_FMExpression> pExpression)
421    : CXFA_FMLoopExpression(line),
422      m_pCondition(std::move(pCondition)),
423      m_pExpression(std::move(pExpression)) {}
424
425CXFA_FMWhileExpression::~CXFA_FMWhileExpression() {}
426
427bool CXFA_FMWhileExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
428  CXFA_FMToJavaScriptDepth depthManager;
429  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
430    return false;
431
432  javascript << L"while (";
433  if (!m_pCondition->ToJavaScript(javascript))
434    return false;
435  javascript << L")\n";
436  if (CXFA_IsTooBig(javascript))
437    return false;
438
439  if (!m_pExpression->ToJavaScript(javascript))
440    return false;
441  return !CXFA_IsTooBig(javascript);
442}
443
444bool CXFA_FMWhileExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
445  CXFA_FMToJavaScriptDepth depthManager;
446  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
447    return false;
448
449  javascript << RUNTIMEFUNCTIONRETURNVALUE;
450  javascript << L" = 0;\n";
451  javascript << L"while (";
452  if (!m_pCondition->ToJavaScript(javascript))
453    return false;
454  javascript << L")\n";
455  if (CXFA_IsTooBig(javascript))
456    return false;
457
458  if (!m_pExpression->ToImpliedReturnJS(javascript))
459    return false;
460  return !CXFA_IsTooBig(javascript);
461}
462
463CXFA_FMBreakExpression::CXFA_FMBreakExpression(uint32_t line)
464    : CXFA_FMExpression(line, XFA_FM_EXPTYPE_BREAK) {}
465
466CXFA_FMBreakExpression::~CXFA_FMBreakExpression() {}
467
468bool CXFA_FMBreakExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
469  CXFA_FMToJavaScriptDepth depthManager;
470  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
471    return false;
472
473  javascript << RUNTIMEFUNCTIONRETURNVALUE;
474  javascript << L" = 0;\n";
475  javascript << L"break;\n";
476  return !CXFA_IsTooBig(javascript);
477}
478
479bool CXFA_FMBreakExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
480  CXFA_FMToJavaScriptDepth depthManager;
481  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
482    return false;
483
484  javascript << RUNTIMEFUNCTIONRETURNVALUE;
485  javascript << L" = 0;\n";
486  javascript << L"break;\n";
487  return !CXFA_IsTooBig(javascript);
488}
489
490CXFA_FMContinueExpression::CXFA_FMContinueExpression(uint32_t line)
491    : CXFA_FMExpression(line, XFA_FM_EXPTYPE_CONTINUE) {}
492
493CXFA_FMContinueExpression::~CXFA_FMContinueExpression() {}
494
495bool CXFA_FMContinueExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
496  CXFA_FMToJavaScriptDepth depthManager;
497  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
498    return false;
499
500  javascript << RUNTIMEFUNCTIONRETURNVALUE;
501  javascript << L" = 0;\n";
502  javascript << L"continue;\n";
503  return !CXFA_IsTooBig(javascript);
504}
505
506bool CXFA_FMContinueExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
507  CXFA_FMToJavaScriptDepth depthManager;
508  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
509    return false;
510
511  javascript << RUNTIMEFUNCTIONRETURNVALUE;
512  javascript << L" = 0;\n";
513  javascript << L"continue;\n";
514  return !CXFA_IsTooBig(javascript);
515}
516
517CXFA_FMForExpression::CXFA_FMForExpression(
518    uint32_t line,
519    const WideStringView& wsVariant,
520    std::unique_ptr<CXFA_FMSimpleExpression> pAssignment,
521    std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
522    int32_t iDirection,
523    std::unique_ptr<CXFA_FMSimpleExpression> pStep,
524    std::unique_ptr<CXFA_FMExpression> pList)
525    : CXFA_FMLoopExpression(line),
526      m_wsVariant(wsVariant),
527      m_pAssignment(std::move(pAssignment)),
528      m_pAccessor(std::move(pAccessor)),
529      m_bDirection(iDirection == 1),
530      m_pStep(std::move(pStep)),
531      m_pList(std::move(pList)) {}
532
533CXFA_FMForExpression::~CXFA_FMForExpression() {}
534
535bool CXFA_FMForExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
536  CXFA_FMToJavaScriptDepth depthManager;
537  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
538    return false;
539
540  javascript << L"{\nvar ";
541  WideString tempVariant;
542  if (m_wsVariant[0] == L'!') {
543    tempVariant = EXCLAMATION_IN_IDENTIFIER +
544                  m_wsVariant.Right(m_wsVariant.GetLength() - 1);
545    javascript << tempVariant;
546  } else {
547    tempVariant = m_wsVariant;
548    javascript << m_wsVariant;
549  }
550  javascript << L" = null;\n";
551  javascript << L"for (";
552  javascript << tempVariant;
553  javascript << L" = ";
554  javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
555  javascript << L"(";
556  if (!m_pAssignment->ToJavaScript(javascript))
557    return false;
558  javascript << L"); ";
559  javascript << tempVariant;
560
561  javascript << (m_bDirection ? kLessEqual : kGreaterEqual);
562  javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
563  javascript << L"(";
564  if (!m_pAccessor->ToJavaScript(javascript))
565    return false;
566  javascript << L"); ";
567  javascript << tempVariant;
568  javascript << (m_bDirection ? kPlusEqual : kMinusEqual);
569  if (CXFA_IsTooBig(javascript))
570    return false;
571
572  if (m_pStep) {
573    javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
574    javascript << L"(";
575    if (!m_pStep->ToJavaScript(javascript))
576      return false;
577    javascript << L")";
578  } else {
579    javascript << L"1";
580  }
581  javascript << L")\n";
582  if (!m_pList->ToJavaScript(javascript))
583    return false;
584  javascript << L"}\n";
585  return !CXFA_IsTooBig(javascript);
586}
587
588bool CXFA_FMForExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
589  CXFA_FMToJavaScriptDepth depthManager;
590  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
591    return false;
592
593  javascript << RUNTIMEFUNCTIONRETURNVALUE;
594  javascript << L" = 0;\n";
595  javascript << L"{\nvar ";
596  WideString tempVariant;
597  if (m_wsVariant[0] == L'!') {
598    tempVariant = EXCLAMATION_IN_IDENTIFIER +
599                  m_wsVariant.Right(m_wsVariant.GetLength() - 1);
600    javascript << tempVariant;
601  } else {
602    tempVariant = m_wsVariant;
603    javascript << m_wsVariant;
604  }
605  javascript << L" = null;\n";
606  javascript << L"for (";
607  javascript << tempVariant;
608  javascript << L" = ";
609  javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
610  javascript << L"(";
611  if (!m_pAssignment->ToJavaScript(javascript))
612    return false;
613  javascript << L"); ";
614  javascript << tempVariant;
615
616  javascript << (m_bDirection ? kLessEqual : kGreaterEqual);
617  javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
618  javascript << L"(";
619  if (!m_pAccessor->ToJavaScript(javascript))
620    return false;
621  javascript << L"); ";
622  javascript << tempVariant;
623  javascript << L" += ";
624  javascript << (m_bDirection ? kPlusEqual : kMinusEqual);
625  if (CXFA_IsTooBig(javascript))
626    return false;
627
628  if (m_pStep) {
629    javascript << XFA_FM_EXPTypeToString(GETFMVALUE);
630    javascript << L"(";
631    if (!m_pStep->ToJavaScript(javascript))
632      return false;
633    javascript << L")";
634    if (CXFA_IsTooBig(javascript))
635      return false;
636  } else {
637    javascript << L"1";
638  }
639  javascript << L")\n";
640  if (!m_pList->ToImpliedReturnJS(javascript))
641    return false;
642  javascript << L"}\n";
643  return !CXFA_IsTooBig(javascript);
644}
645
646CXFA_FMForeachExpression::CXFA_FMForeachExpression(
647    uint32_t line,
648    const WideStringView& wsIdentifier,
649    std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>&& pAccessors,
650    std::unique_ptr<CXFA_FMExpression> pList)
651    : CXFA_FMLoopExpression(line),
652      m_wsIdentifier(wsIdentifier),
653      m_pAccessors(std::move(pAccessors)),
654      m_pList(std::move(pList)) {}
655
656CXFA_FMForeachExpression::~CXFA_FMForeachExpression() {}
657
658bool CXFA_FMForeachExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
659  CXFA_FMToJavaScriptDepth depthManager;
660  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
661    return false;
662
663  javascript << L"{\n";
664  javascript << L"var ";
665  if (m_wsIdentifier[0] == L'!') {
666    WideString tempIdentifier =
667        EXCLAMATION_IN_IDENTIFIER +
668        m_wsIdentifier.Right(m_wsIdentifier.GetLength() - 1);
669    javascript << tempIdentifier;
670  } else {
671    javascript << m_wsIdentifier;
672  }
673  javascript << L" = null;\n";
674  javascript << L"var ";
675  javascript << RUNTIMEBLOCKTEMPARRAY;
676  javascript << L" = ";
677  javascript << XFA_FM_EXPTypeToString(CONCATFMOBJECT);
678  javascript << L"(";
679
680  for (const auto& expr : m_pAccessors) {
681    if (!expr->ToJavaScript(javascript))
682      return false;
683    if (expr != m_pAccessors.back())
684      javascript << L", ";
685  }
686  javascript << L");\n";
687  javascript << L"var ";
688  javascript << RUNTIMEBLOCKTEMPARRAYINDEX;
689  javascript << (L" = 0;\n");
690  javascript << L"while(";
691  javascript << RUNTIMEBLOCKTEMPARRAYINDEX;
692  javascript << L" < ";
693  javascript << RUNTIMEBLOCKTEMPARRAY;
694  javascript << L".length)\n{\n";
695  if (m_wsIdentifier[0] == L'!') {
696    WideString tempIdentifier =
697        EXCLAMATION_IN_IDENTIFIER +
698        m_wsIdentifier.Right(m_wsIdentifier.GetLength() - 1);
699    javascript << tempIdentifier;
700  } else {
701    javascript << m_wsIdentifier;
702  }
703  javascript << L" = ";
704  javascript << RUNTIMEBLOCKTEMPARRAY;
705  javascript << L"[";
706  javascript << RUNTIMEBLOCKTEMPARRAYINDEX;
707  javascript << L"++];\n";
708  if (!m_pList->ToJavaScript(javascript))
709    return false;
710  javascript << L"}\n";
711  javascript << L"}\n";
712  return !CXFA_IsTooBig(javascript);
713}
714
715bool CXFA_FMForeachExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
716  CXFA_FMToJavaScriptDepth depthManager;
717  if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
718    return false;
719
720  javascript << RUNTIMEFUNCTIONRETURNVALUE;
721  javascript << L" = 0;\n";
722  javascript << L"{\n";
723  javascript << L"var ";
724  if (m_wsIdentifier[0] == L'!') {
725    WideString tempIdentifier =
726        EXCLAMATION_IN_IDENTIFIER +
727        m_wsIdentifier.Right(m_wsIdentifier.GetLength() - 1);
728    javascript << tempIdentifier;
729  } else {
730    javascript << m_wsIdentifier;
731  }
732  javascript << L" = null;\n";
733  javascript << L"var ";
734  javascript << RUNTIMEBLOCKTEMPARRAY;
735  javascript << L" = ";
736  javascript << XFA_FM_EXPTypeToString(CONCATFMOBJECT);
737  javascript << L"(";
738  for (const auto& expr : m_pAccessors) {
739    if (!expr->ToJavaScript(javascript))
740      return false;
741    if (expr != m_pAccessors.back())
742      javascript << L", ";
743  }
744  javascript << L");\n";
745  javascript << L"var ";
746  javascript << RUNTIMEBLOCKTEMPARRAYINDEX;
747  javascript << L" = 0;\n";
748  javascript << L"while(";
749  javascript << RUNTIMEBLOCKTEMPARRAYINDEX;
750  javascript << L" < ";
751  javascript << RUNTIMEBLOCKTEMPARRAY;
752  javascript << L".length)\n{\n";
753  if (m_wsIdentifier[0] == L'!') {
754    WideString tempIdentifier =
755        EXCLAMATION_IN_IDENTIFIER +
756        m_wsIdentifier.Right(m_wsIdentifier.GetLength() - 1);
757    javascript << tempIdentifier;
758  } else {
759    javascript << m_wsIdentifier;
760  }
761  javascript << L" = ";
762  javascript << RUNTIMEBLOCKTEMPARRAY;
763  javascript << L"[";
764  javascript << RUNTIMEBLOCKTEMPARRAYINDEX;
765  javascript << L"++];\n";
766  if (!m_pList->ToImpliedReturnJS(javascript))
767    return false;
768  javascript << L"}\n";
769  javascript << L"}\n";
770  return !CXFA_IsTooBig(javascript);
771}
772