// Copyright 2014 PDFium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #include "xfa/fxfa/fm2js/cxfa_fmexpression.h" #include #include "core/fxcrt/cfx_widetextbuf.h" #include "xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h" #include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h" namespace { const wchar_t kLessEqual[] = L" <= "; const wchar_t kGreaterEqual[] = L" >= "; const wchar_t kPlusEqual[] = L" += "; const wchar_t kMinusEqual[] = L" -= "; WideString IdentifierToName(WideStringView ident) { if (ident.IsEmpty()) return WideString(); if (ident[0] != L'!') return WideString(ident); return L"pfm__excl__" + ident.Last(ident.GetLength() - 1); } } // namespace CXFA_FMExpression::CXFA_FMExpression() = default; CXFA_FMFunctionDefinition::CXFA_FMFunctionDefinition( WideStringView wsName, std::vector&& arguments, std::vector>&& expressions) : CXFA_FMExpression(), m_wsName(wsName), m_pArguments(std::move(arguments)), m_pExpressions(std::move(expressions)) { ASSERT(!wsName.IsEmpty()); } CXFA_FMFunctionDefinition::~CXFA_FMFunctionDefinition() = default; bool CXFA_FMFunctionDefinition::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) { CXFA_FMToJavaScriptDepth depthManager; if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth()) return false; if (m_wsName.IsEmpty()) return false; *js << "function " << IdentifierToName(m_wsName) << "("; for (const auto& identifier : m_pArguments) { if (identifier != m_pArguments.front()) *js << ", "; *js << IdentifierToName(identifier); } *js << ") {\n"; *js << "var pfm_ret = null;\n"; for (const auto& expr : m_pExpressions) { ReturnType ret_type = expr == m_pExpressions.back() ? ReturnType::kImplied : ReturnType::kInfered; if (!expr->ToJavaScript(js, ret_type)) return false; } *js << "return pfm_ret;\n"; *js << "}\n"; return !CXFA_IsTooBig(js); } CXFA_FMAST::CXFA_FMAST( std::vector> expressions) : expressions_(std::move(expressions)) {} CXFA_FMAST::~CXFA_FMAST() = default; bool CXFA_FMAST::ToJavaScript(CFX_WideTextBuf* js) { if (expressions_.empty()) { *js << "// comments only"; return !CXFA_IsTooBig(js); } *js << "(function() {\n"; *js << "let pfm_method_runner = function(obj, cb) {\n"; *js << " if (pfm_rt.is_ary(obj)) {\n"; *js << " let pfm_method_return = null;\n"; *js << " for (var idx = obj.length -1; idx > 1; idx--) {\n"; *js << " pfm_method_return = cb(obj[idx]);\n"; *js << " }\n"; *js << " return pfm_method_return;\n"; *js << " }\n"; *js << " return cb(obj);\n"; *js << "};\n"; *js << "var pfm_ret = null;\n"; for (const auto& expr : expressions_) { ReturnType ret_type = expr == expressions_.back() ? ReturnType::kImplied : ReturnType::kInfered; if (!expr->ToJavaScript(js, ret_type)) return false; } *js << "return pfm_rt.get_val(pfm_ret);\n"; *js << "}).call(this);"; return !CXFA_IsTooBig(js); } CXFA_FMVarExpression::CXFA_FMVarExpression( WideStringView wsName, std::unique_ptr pInit) : CXFA_FMExpression(), m_wsName(wsName), m_pInit(std::move(pInit)) {} CXFA_FMVarExpression::~CXFA_FMVarExpression() = default; bool CXFA_FMVarExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) { CXFA_FMToJavaScriptDepth depthManager; if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth()) return false; WideString tempName = IdentifierToName(m_wsName); *js << "var " << tempName << " = "; if (m_pInit) { if (!m_pInit->ToJavaScript(js, ReturnType::kInfered)) return false; *js << ";\n"; *js << tempName << " = pfm_rt.var_filter(" << tempName << ");\n"; } else { *js << "\"\";\n"; } if (type == ReturnType::kImplied) *js << "pfm_ret = " << tempName << ";\n"; return !CXFA_IsTooBig(js); } CXFA_FMExpExpression::CXFA_FMExpExpression( std::unique_ptr pExpression) : CXFA_FMExpression(), m_pExpression(std::move(pExpression)) {} CXFA_FMExpExpression::~CXFA_FMExpExpression() = default; bool CXFA_FMExpExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) { CXFA_FMToJavaScriptDepth depthManager; if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth()) return false; if (type == ReturnType::kInfered) { bool ret = m_pExpression->ToJavaScript(js, ReturnType::kInfered); if (m_pExpression->GetOperatorToken() != TOKassign) *js << ";\n"; return ret; } if (m_pExpression->GetOperatorToken() == TOKassign) return m_pExpression->ToJavaScript(js, ReturnType::kImplied); if (m_pExpression->GetOperatorToken() == TOKstar || m_pExpression->GetOperatorToken() == TOKdotstar || m_pExpression->GetOperatorToken() == TOKdotscream || m_pExpression->GetOperatorToken() == TOKdotdot || m_pExpression->GetOperatorToken() == TOKdot) { *js << "pfm_ret = pfm_rt.get_val("; if (!m_pExpression->ToJavaScript(js, ReturnType::kInfered)) return false; *js << ");\n"; return !CXFA_IsTooBig(js); } *js << "pfm_ret = "; if (!m_pExpression->ToJavaScript(js, ReturnType::kInfered)) return false; *js << ";\n"; return !CXFA_IsTooBig(js); } CXFA_FMBlockExpression::CXFA_FMBlockExpression( std::vector>&& pExpressionList) : CXFA_FMExpression(), m_ExpressionList(std::move(pExpressionList)) {} CXFA_FMBlockExpression::~CXFA_FMBlockExpression() = default; bool CXFA_FMBlockExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) { CXFA_FMToJavaScriptDepth depthManager; if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth()) return false; *js << "{\n"; for (const auto& expr : m_ExpressionList) { if (type == ReturnType::kInfered) { if (!expr->ToJavaScript(js, ReturnType::kInfered)) return false; } else { ReturnType ret_type = expr == m_ExpressionList.back() ? ReturnType::kImplied : ReturnType::kInfered; if (!expr->ToJavaScript(js, ret_type)) return false; } } *js << "}\n"; return !CXFA_IsTooBig(js); } CXFA_FMDoExpression::CXFA_FMDoExpression( std::unique_ptr pList) : CXFA_FMExpression(), m_pList(std::move(pList)) {} CXFA_FMDoExpression::~CXFA_FMDoExpression() = default; bool CXFA_FMDoExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) { CXFA_FMToJavaScriptDepth depthManager; if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth()) return false; return m_pList->ToJavaScript(js, type); } CXFA_FMIfExpression::CXFA_FMIfExpression( std::unique_ptr pExpression, std::unique_ptr pIfExpression, std::vector> pElseIfExpressions, std::unique_ptr pElseExpression) : CXFA_FMExpression(), m_pExpression(std::move(pExpression)), m_pIfExpression(std::move(pIfExpression)), m_pElseIfExpressions(std::move(pElseIfExpressions)), m_pElseExpression(std::move(pElseExpression)) { ASSERT(m_pExpression); } CXFA_FMIfExpression::~CXFA_FMIfExpression() = default; bool CXFA_FMIfExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) { CXFA_FMToJavaScriptDepth depthManager; if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth()) return false; if (type == ReturnType::kImplied) *js << "pfm_ret = 0;\n"; *js << "if (pfm_rt.get_val("; if (!m_pExpression->ToJavaScript(js, ReturnType::kInfered)) return false; *js << "))\n"; if (CXFA_IsTooBig(js)) return false; if (m_pIfExpression) { if (!m_pIfExpression->ToJavaScript(js, type)) return false; if (CXFA_IsTooBig(js)) return false; } for (auto& expr : m_pElseIfExpressions) { *js << "else "; if (!expr->ToJavaScript(js, ReturnType::kInfered)) return false; } if (m_pElseExpression) { *js << "else "; if (!m_pElseExpression->ToJavaScript(js, type)) return false; } return !CXFA_IsTooBig(js); } CXFA_FMWhileExpression::CXFA_FMWhileExpression( std::unique_ptr pCondition, std::unique_ptr pExpression) : CXFA_FMExpression(), m_pCondition(std::move(pCondition)), m_pExpression(std::move(pExpression)) {} CXFA_FMWhileExpression::~CXFA_FMWhileExpression() = default; bool CXFA_FMWhileExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) { CXFA_FMToJavaScriptDepth depthManager; if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth()) return false; if (type == ReturnType::kImplied) *js << "pfm_ret = 0;\n"; *js << "while ("; if (!m_pCondition->ToJavaScript(js, ReturnType::kInfered)) return false; *js << ")\n"; if (CXFA_IsTooBig(js)) return false; if (!m_pExpression->ToJavaScript(js, type)) return false; return !CXFA_IsTooBig(js); } CXFA_FMBreakExpression::CXFA_FMBreakExpression() : CXFA_FMExpression() {} CXFA_FMBreakExpression::~CXFA_FMBreakExpression() = default; bool CXFA_FMBreakExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) { CXFA_FMToJavaScriptDepth depthManager; if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth()) return false; *js << "pfm_ret = 0;\nbreak;\n"; return !CXFA_IsTooBig(js); } CXFA_FMContinueExpression::CXFA_FMContinueExpression() : CXFA_FMExpression() {} CXFA_FMContinueExpression::~CXFA_FMContinueExpression() = default; bool CXFA_FMContinueExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) { CXFA_FMToJavaScriptDepth depthManager; if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth()) return false; *js << "pfm_ret = 0;\ncontinue;\n"; return !CXFA_IsTooBig(js); } CXFA_FMForExpression::CXFA_FMForExpression( WideStringView wsVariant, std::unique_ptr pAssignment, std::unique_ptr pAccessor, int32_t iDirection, std::unique_ptr pStep, std::unique_ptr pList) : CXFA_FMExpression(), m_wsVariant(wsVariant), m_pAssignment(std::move(pAssignment)), m_pAccessor(std::move(pAccessor)), m_bDirection(iDirection == 1), m_pStep(std::move(pStep)), m_pList(std::move(pList)) {} CXFA_FMForExpression::~CXFA_FMForExpression() = default; bool CXFA_FMForExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) { CXFA_FMToJavaScriptDepth depthManager; if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth()) return false; if (type == ReturnType::kImplied) *js << "pfm_ret = 0;\n"; *js << "{\n"; WideString tmpName = IdentifierToName(m_wsVariant); *js << "var " << tmpName << " = null;\n"; *js << "for (" << tmpName << " = pfm_rt.get_val("; if (!m_pAssignment->ToJavaScript(js, ReturnType::kInfered)) return false; *js << "); "; *js << tmpName << (m_bDirection ? kLessEqual : kGreaterEqual); *js << "pfm_rt.get_val("; if (!m_pAccessor->ToJavaScript(js, ReturnType::kInfered)) return false; *js << "); "; *js << tmpName << (m_bDirection ? kPlusEqual : kMinusEqual); if (m_pStep) { *js << "pfm_rt.get_val("; if (!m_pStep->ToJavaScript(js, ReturnType::kInfered)) return false; *js << ")"; } else { *js << "1"; } *js << ")\n"; if (CXFA_IsTooBig(js)) return false; if (!m_pList->ToJavaScript(js, type)) return false; *js << "}\n"; return !CXFA_IsTooBig(js); } CXFA_FMForeachExpression::CXFA_FMForeachExpression( WideStringView wsIdentifier, std::vector>&& pAccessors, std::unique_ptr pList) : CXFA_FMExpression(), m_wsIdentifier(wsIdentifier), m_pAccessors(std::move(pAccessors)), m_pList(std::move(pList)) {} CXFA_FMForeachExpression::~CXFA_FMForeachExpression() = default; bool CXFA_FMForeachExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) { CXFA_FMToJavaScriptDepth depthManager; if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth()) return false; if (type == ReturnType::kImplied) *js << "pfm_ret = 0;\n"; *js << "{\n"; WideString tmpName = IdentifierToName(m_wsIdentifier); *js << "var " << tmpName << " = null;\n"; *js << "var pfm_ary = pfm_rt.concat_obj("; for (const auto& expr : m_pAccessors) { if (!expr->ToJavaScript(js, ReturnType::kInfered)) return false; if (expr != m_pAccessors.back()) *js << ", "; } *js << ");\n"; *js << "var pfm_ary_idx = 0;\n"; *js << "while(pfm_ary_idx < pfm_ary.length)\n{\n"; *js << tmpName << " = pfm_ary[pfm_ary_idx++];\n"; if (!m_pList->ToJavaScript(js, type)) return false; *js << "}\n"; // while *js << "}\n"; // block return !CXFA_IsTooBig(js); }