449 lines
13 KiB
C++
449 lines
13 KiB
C++
// 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 <utility>
|
|
|
|
#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<WideStringView>&& arguments,
|
|
std::vector<std::unique_ptr<CXFA_FMExpression>>&& 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<std::unique_ptr<CXFA_FMExpression>> 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<CXFA_FMSimpleExpression> 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<CXFA_FMSimpleExpression> 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<std::unique_ptr<CXFA_FMExpression>>&& 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<CXFA_FMExpression> 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<CXFA_FMSimpleExpression> pExpression,
|
|
std::unique_ptr<CXFA_FMExpression> pIfExpression,
|
|
std::vector<std::unique_ptr<CXFA_FMIfExpression>> pElseIfExpressions,
|
|
std::unique_ptr<CXFA_FMExpression> 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<CXFA_FMSimpleExpression> pCondition,
|
|
std::unique_ptr<CXFA_FMExpression> 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<CXFA_FMSimpleExpression> pAssignment,
|
|
std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
|
|
int32_t iDirection,
|
|
std::unique_ptr<CXFA_FMSimpleExpression> pStep,
|
|
std::unique_ptr<CXFA_FMExpression> 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<std::unique_ptr<CXFA_FMSimpleExpression>>&& pAccessors,
|
|
std::unique_ptr<CXFA_FMExpression> 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);
|
|
}
|