Make CFXA_FMSimpleExpression a subclass of CFXA_FMExpression. Having a tree with two distinct base classes seems dubious. -- add const along the way -- move some constructor implementations to .cpp file. Change-Id: I37caf46569a857048a745bf00092e946e710c0ee Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/73570 Reviewed-by: Lei Zhang <thestig@chromium.org> Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/xfa/fxfa/fm2js/BUILD.gn b/xfa/fxfa/fm2js/BUILD.gn index a6b2540..3e151b4 100644 --- a/xfa/fxfa/fm2js/BUILD.gn +++ b/xfa/fxfa/fm2js/BUILD.gn
@@ -15,8 +15,6 @@ "cxfa_fmlexer.h", "cxfa_fmparser.cpp", "cxfa_fmparser.h", - "cxfa_fmsimpleexpression.cpp", - "cxfa_fmsimpleexpression.h", "cxfa_fmtojavascriptdepth.cpp", "cxfa_fmtojavascriptdepth.h", ] @@ -33,7 +31,6 @@ "cxfa_fmexpression_unittest.cpp", "cxfa_fmlexer_unittest.cpp", "cxfa_fmparser_unittest.cpp", - "cxfa_fmsimpleexpression_unittest.cpp", ] deps = [ ":fm2js" ] pdfium_root_dir = "../../../"
diff --git a/xfa/fxfa/fm2js/cxfa_fmexpression.cpp b/xfa/fxfa/fm2js/cxfa_fmexpression.cpp index 98be02b..0a0fd7b 100644 --- a/xfa/fxfa/fm2js/cxfa_fmexpression.cpp +++ b/xfa/fxfa/fm2js/cxfa_fmexpression.cpp
@@ -6,10 +6,13 @@ #include "xfa/fxfa/fm2js/cxfa_fmexpression.h" +#include <algorithm> #include <utility> +#include "core/fxcrt/autorestorer.h" #include "core/fxcrt/cfx_widetextbuf.h" -#include "xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h" +#include "core/fxcrt/fx_extension.h" +#include "third_party/base/logging.h" #include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h" namespace { @@ -19,6 +22,57 @@ const wchar_t kPlusEqual[] = L" += "; const wchar_t kMinusEqual[] = L" -= "; +const wchar_t* const g_BuiltInFuncs[] = { + L"Abs", L"Apr", L"At", L"Avg", + L"Ceil", L"Choose", L"Concat", L"Count", + L"Cterm", L"Date", L"Date2Num", L"DateFmt", + L"Decode", L"Encode", L"Eval", L"Exists", + L"Floor", L"Format", L"FV", L"Get", + L"HasValue", L"If", L"Ipmt", L"IsoDate2Num", + L"IsoTime2Num", L"Left", L"Len", L"LocalDateFmt", + L"LocalTimeFmt", L"Lower", L"Ltrim", L"Max", + L"Min", L"Mod", L"NPV", L"Num2Date", + L"Num2GMTime", L"Num2Time", L"Oneof", L"Parse", + L"Pmt", L"Post", L"PPmt", L"Put", + L"PV", L"Rate", L"Ref", L"Replace", + L"Right", L"Round", L"Rtrim", L"Space", + L"Str", L"Stuff", L"Substr", L"Sum", + L"Term", L"Time", L"Time2Num", L"TimeFmt", + L"UnitType", L"UnitValue", L"Upper", L"Uuid", + L"Within", L"WordNum", +}; + +const size_t g_BuiltInFuncsMaxLen = 12; + +struct XFA_FMSOMMethod { + const wchar_t* m_wsSomMethodName; + uint32_t m_dParameters; +}; + +const XFA_FMSOMMethod gs_FMSomMethods[] = { + {L"absPage", 0x01}, + {L"absPageInBatch", 0x01}, + {L"absPageSpan", 0x01}, + {L"append", 0x01}, + {L"clear", 0x01}, + {L"formNodes", 0x01}, + {L"h", 0x01}, + {L"insert", 0x03}, + {L"isRecordGroup", 0x01}, + {L"page", 0x01}, + {L"pageSpan", 0x01}, + {L"remove", 0x01}, + {L"saveFilteredXML", 0x01}, + {L"setElement", 0x01}, + {L"sheet", 0x01}, + {L"sheetInBatch", 0x01}, + {L"sign", 0x61}, + {L"verify", 0x0d}, + {L"w", 0x01}, + {L"x", 0x01}, + {L"y", 0x01}, +}; + WideString IdentifierToName(WideStringView ident) { if (ident.IsEmpty()) return WideString(); @@ -31,6 +85,668 @@ CXFA_FMExpression::CXFA_FMExpression() = default; +CXFA_FMExpression::~CXFA_FMExpression() = default; + +CXFA_FMSimpleExpression::CXFA_FMSimpleExpression(XFA_FM_TOKEN op) + : m_op(op), m_bChainable(false) {} + +CXFA_FMSimpleExpression::CXFA_FMSimpleExpression(XFA_FM_TOKEN op, + bool chainable) + : m_op(op), m_bChainable(chainable) {} + +CXFA_FMSimpleExpression::~CXFA_FMSimpleExpression() = default; + +CXFA_FMChainableExpression::CXFA_FMChainableExpression( + XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2) + : CXFA_FMSimpleExpression(op, /*chainable=*/true), + m_pExp1(std::move(pExp1)), + m_pExp2(std::move(pExp2)) {} + +CXFA_FMChainableExpression::~CXFA_FMChainableExpression() { + DeleteChain(std::move(m_pExp1)); + DeleteChain(std::move(m_pExp2)); +} + +CXFA_FMSimpleExpression* CXFA_FMChainableExpression::GetFirstExpression() + const { + return m_pExp1.get(); +} + +CXFA_FMSimpleExpression* CXFA_FMChainableExpression::GetSecondExpression() + const { + return m_pExp2.get(); +} + +// static +void CXFA_FMChainableExpression::DeleteChain( + std::unique_ptr<CXFA_FMSimpleExpression> pRoot) { + while (pRoot && pRoot->chainable()) { + auto* pRootChain = static_cast<CXFA_FMChainableExpression*>(pRoot.get()); + + // If either child is not a chainable expression (i.e. a leaf node), simply + // delete it. + if (pRootChain->m_pExp1 && !pRootChain->m_pExp1->chainable()) + pRootChain->m_pExp1.reset(); + if (pRootChain->m_pExp2 && !pRootChain->m_pExp2->chainable()) + pRootChain->m_pExp2.reset(); + + // If the root is missing either child, delete the root and promote the only + // child to the root. + if (!pRootChain->m_pExp1) { + pRoot = std::move(pRootChain->m_pExp2); + continue; + } + if (!pRootChain->m_pExp2) { + pRoot = std::move(pRootChain->m_pExp1); + continue; + } + + // Otherwise, perform a right tree rotation. + std::unique_ptr<CXFA_FMSimpleExpression> pPivot( + std::move(pRootChain->m_pExp1)); + auto* pPivotChain = static_cast<CXFA_FMChainableExpression*>(pPivot.get()); + pRootChain->m_pExp1 = std::move(pPivotChain->m_pExp2); + pPivotChain->m_pExp2 = std::move(pRoot); + pRoot = std::move(pPivot); + } +} + +CXFA_FMNullExpression::CXFA_FMNullExpression() + : CXFA_FMSimpleExpression(TOKnull) {} + +bool CXFA_FMNullExpression::ToJavaScript(CFX_WideTextBuf* js, + ReturnType type) const { + CXFA_FMToJavaScriptDepth depthManager; + if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) + return false; + + *js << "null"; + return !CXFA_IsTooBig(*js); +} + +CXFA_FMNumberExpression::CXFA_FMNumberExpression(WideStringView wsNumber) + : CXFA_FMSimpleExpression(TOKnumber), m_wsNumber(wsNumber) {} + +CXFA_FMNumberExpression::~CXFA_FMNumberExpression() = default; + +bool CXFA_FMNumberExpression::ToJavaScript(CFX_WideTextBuf* js, + ReturnType type) const { + CXFA_FMToJavaScriptDepth depthManager; + if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) + return false; + + *js << m_wsNumber; + return !CXFA_IsTooBig(*js); +} + +CXFA_FMStringExpression::CXFA_FMStringExpression(WideStringView wsString) + : CXFA_FMSimpleExpression(TOKstring), m_wsString(wsString) {} + +CXFA_FMStringExpression::~CXFA_FMStringExpression() = default; + +bool CXFA_FMStringExpression::ToJavaScript(CFX_WideTextBuf* js, + ReturnType type) const { + CXFA_FMToJavaScriptDepth depthManager; + if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) + return false; + + WideString tempStr(m_wsString); + if (tempStr.GetLength() <= 2) { + *js << tempStr; + return !CXFA_IsTooBig(*js); + } + + *js << "\""; + for (size_t i = 1; i < tempStr.GetLength() - 1; i++) { + wchar_t oneChar = tempStr[i]; + switch (oneChar) { + case L'\"': + ++i; + *js << "\\\""; + break; + case 0x0d: + break; + case 0x0a: + *js << "\\n"; + break; + default: + js->AppendChar(oneChar); + break; + } + } + *js << "\""; + return !CXFA_IsTooBig(*js); +} + +CXFA_FMIdentifierExpression::CXFA_FMIdentifierExpression( + WideStringView wsIdentifier) + : CXFA_FMSimpleExpression(TOKidentifier), m_wsIdentifier(wsIdentifier) {} + +CXFA_FMIdentifierExpression::~CXFA_FMIdentifierExpression() = default; + +bool CXFA_FMIdentifierExpression::ToJavaScript(CFX_WideTextBuf* js, + ReturnType type) const { + CXFA_FMToJavaScriptDepth depthManager; + if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) + return false; + + if (m_wsIdentifier.EqualsASCII("$")) + *js << "this"; + else if (m_wsIdentifier.EqualsASCII("!")) + *js << "xfa.datasets"; + else if (m_wsIdentifier.EqualsASCII("$data")) + *js << "xfa.datasets.data"; + else if (m_wsIdentifier.EqualsASCII("$event")) + *js << "xfa.event"; + else if (m_wsIdentifier.EqualsASCII("$form")) + *js << "xfa.form"; + else if (m_wsIdentifier.EqualsASCII("$host")) + *js << "xfa.host"; + else if (m_wsIdentifier.EqualsASCII("$layout")) + *js << "xfa.layout"; + else if (m_wsIdentifier.EqualsASCII("$template")) + *js << "xfa.template"; + else if (m_wsIdentifier[0] == L'!') + *js << "pfm__excl__" << m_wsIdentifier.Last(m_wsIdentifier.GetLength() - 1); + else + *js << m_wsIdentifier; + + return !CXFA_IsTooBig(*js); +} + +CXFA_FMAssignExpression::CXFA_FMAssignExpression( + XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2) + : CXFA_FMChainableExpression(op, std::move(pExp1), std::move(pExp2)) {} + +CXFA_FMAssignExpression::~CXFA_FMAssignExpression() = default; + +bool CXFA_FMAssignExpression::ToJavaScript(CFX_WideTextBuf* js, + ReturnType type) const { + CXFA_FMToJavaScriptDepth depthManager; + if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) + return false; + + CFX_WideTextBuf tempExp1; + const CXFA_FMSimpleExpression* exp1 = GetFirstExpression(); + if (!exp1->ToJavaScript(&tempExp1, ReturnType::kInfered)) + return false; + + *js << "if (pfm_rt.is_obj(" << tempExp1 << "))\n{\n"; + if (type == ReturnType::kImplied) + *js << "pfm_ret = "; + + CFX_WideTextBuf tempExp2; + const CXFA_FMSimpleExpression* exp2 = GetSecondExpression(); + if (!exp2->ToJavaScript(&tempExp2, ReturnType::kInfered)) + return false; + + *js << "pfm_rt.asgn_val_op(" << tempExp1 << ", " << tempExp2 << ");\n}\n"; + + if (exp1->GetOperatorToken() == TOKidentifier && + !tempExp1.AsStringView().EqualsASCII("this")) { + *js << "else\n{\n"; + if (type == ReturnType::kImplied) + *js << "pfm_ret = "; + + *js << tempExp1 << " = pfm_rt.asgn_val_op"; + *js << "(" << tempExp1 << ", " << tempExp2 << ");\n"; + *js << "}\n"; + } + return !CXFA_IsTooBig(*js); +} + +CXFA_FMBinExpression::CXFA_FMBinExpression( + const WideString& opName, + XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2) + : CXFA_FMChainableExpression(op, std::move(pExp1), std::move(pExp2)), + m_OpName(opName) {} + +CXFA_FMBinExpression::~CXFA_FMBinExpression() = default; + +bool CXFA_FMBinExpression::ToJavaScript(CFX_WideTextBuf* js, + ReturnType type) const { + CXFA_FMToJavaScriptDepth depthManager; + if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) + return false; + + *js << "pfm_rt." << m_OpName << "("; + if (!GetFirstExpression()->ToJavaScript(js, ReturnType::kInfered)) + return false; + *js << ", "; + if (!GetSecondExpression()->ToJavaScript(js, ReturnType::kInfered)) + return false; + *js << ")"; + return !CXFA_IsTooBig(*js); +} + +CXFA_FMLogicalOrExpression::CXFA_FMLogicalOrExpression( + XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2) + : CXFA_FMBinExpression(L"log_or_op", + op, + std::move(pExp1), + std::move(pExp2)) {} + +CXFA_FMLogicalAndExpression::CXFA_FMLogicalAndExpression( + XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2) + : CXFA_FMBinExpression(L"log_and_op", + op, + std::move(pExp1), + std::move(pExp2)) {} + +CXFA_FMEqualExpression::CXFA_FMEqualExpression( + XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2) + : CXFA_FMBinExpression(L"eq_op", op, std::move(pExp1), std::move(pExp2)) {} + +CXFA_FMNotEqualExpression::CXFA_FMNotEqualExpression( + XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2) + : CXFA_FMBinExpression(L"neq_op", op, std::move(pExp1), std::move(pExp2)) {} + +CXFA_FMGtExpression::CXFA_FMGtExpression( + XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2) + : CXFA_FMBinExpression(L"gt_op", op, std::move(pExp1), std::move(pExp2)) {} + +CXFA_FMGeExpression::CXFA_FMGeExpression( + XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2) + : CXFA_FMBinExpression(L"ge_op", op, std::move(pExp1), std::move(pExp2)) {} + +CXFA_FMLtExpression::CXFA_FMLtExpression( + XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2) + : CXFA_FMBinExpression(L"lt_op", op, std::move(pExp1), std::move(pExp2)) {} + +CXFA_FMLeExpression::CXFA_FMLeExpression( + XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2) + : CXFA_FMBinExpression(L"le_op", op, std::move(pExp1), std::move(pExp2)) {} + +CXFA_FMPlusExpression::CXFA_FMPlusExpression( + XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2) + : CXFA_FMBinExpression(L"plus_op", op, std::move(pExp1), std::move(pExp2)) { +} + +CXFA_FMMinusExpression::CXFA_FMMinusExpression( + XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2) + : CXFA_FMBinExpression(L"minus_op", + op, + std::move(pExp1), + std::move(pExp2)) {} + +CXFA_FMMulExpression::CXFA_FMMulExpression( + XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2) + : CXFA_FMBinExpression(L"mul_op", op, std::move(pExp1), std::move(pExp2)) {} + +CXFA_FMDivExpression::CXFA_FMDivExpression( + XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2) + : CXFA_FMBinExpression(L"div_op", op, std::move(pExp1), std::move(pExp2)) {} + +CXFA_FMUnaryExpression::CXFA_FMUnaryExpression( + const WideString& opName, + XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp) + : CXFA_FMSimpleExpression(op), m_OpName(opName), m_pExp(std::move(pExp)) {} + +CXFA_FMUnaryExpression::~CXFA_FMUnaryExpression() = default; + +bool CXFA_FMUnaryExpression::ToJavaScript(CFX_WideTextBuf* js, + ReturnType type) const { + CXFA_FMToJavaScriptDepth depthManager; + if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) + return false; + + *js << "pfm_rt." << m_OpName.c_str() << "("; + if (!m_pExp->ToJavaScript(js, ReturnType::kInfered)) + return false; + *js << ")"; + return !CXFA_IsTooBig(*js); +} + +CXFA_FMPosExpression::CXFA_FMPosExpression( + std::unique_ptr<CXFA_FMSimpleExpression> pExp) + : CXFA_FMUnaryExpression(L"pos_op", TOKplus, std::move(pExp)) {} + +CXFA_FMNegExpression::CXFA_FMNegExpression( + std::unique_ptr<CXFA_FMSimpleExpression> pExp) + : CXFA_FMUnaryExpression(L"neg_op", TOKminus, std::move(pExp)) {} + +CXFA_FMNotExpression::CXFA_FMNotExpression( + std::unique_ptr<CXFA_FMSimpleExpression> pExp) + : CXFA_FMUnaryExpression(L"log_not_op", TOKksnot, std::move(pExp)) {} + +CXFA_FMCallExpression::CXFA_FMCallExpression( + std::unique_ptr<CXFA_FMSimpleExpression> pExp, + std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>&& pArguments, + bool bIsSomMethod) + : CXFA_FMSimpleExpression(TOKcall), + m_pExp(std::move(pExp)), + m_bIsSomMethod(bIsSomMethod), + m_Arguments(std::move(pArguments)) {} + +CXFA_FMCallExpression::~CXFA_FMCallExpression() = default; + +bool CXFA_FMCallExpression::IsBuiltInFunc(CFX_WideTextBuf* funcName) const { + if (funcName->GetLength() > g_BuiltInFuncsMaxLen) + return false; + + WideString str = funcName->MakeString(); + const wchar_t* const* pMatchResult = std::lower_bound( + std::begin(g_BuiltInFuncs), std::end(g_BuiltInFuncs), str, + [](const wchar_t* iter, const WideString& val) -> bool { + return val.CompareNoCase(iter) > 0; + }); + if (pMatchResult != std::end(g_BuiltInFuncs) && + !str.CompareNoCase(*pMatchResult)) { + funcName->Clear(); + *funcName << *pMatchResult; + return true; + } + return false; +} + +uint32_t CXFA_FMCallExpression::IsMethodWithObjParam( + const WideString& methodName) const { + const XFA_FMSOMMethod* result = std::lower_bound( + std::begin(gs_FMSomMethods), std::end(gs_FMSomMethods), methodName, + [](const XFA_FMSOMMethod iter, const WideString& val) { + return val.Compare(iter.m_wsSomMethodName) > 0; + }); + if (result != std::end(gs_FMSomMethods) && + !methodName.Compare(result->m_wsSomMethodName)) { + return result->m_dParameters; + } + return 0; +} + +bool CXFA_FMCallExpression::ToJavaScript(CFX_WideTextBuf* js, + ReturnType type) const { + CXFA_FMToJavaScriptDepth depthManager; + if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) + return false; + + CFX_WideTextBuf funcName; + if (!m_pExp->ToJavaScript(&funcName, ReturnType::kInfered)) + return false; + + if (m_bIsSomMethod) { + *js << funcName << "("; + uint32_t methodPara = IsMethodWithObjParam(funcName.MakeString()); + if (methodPara > 0) { + for (size_t i = 0; i < m_Arguments.size(); ++i) { + // Currently none of our expressions use objects for a parameter over + // the 6th. Make sure we don't overflow the shift when doing this + // check. If we ever need more the 32 object params we can revisit. + *js << "pfm_rt.get_"; + if (i < 32 && (methodPara & (0x01 << i)) > 0) + *js << "jsobj"; + else + *js << "val"; + + *js << "("; + if (!m_Arguments[i]->ToJavaScript(js, ReturnType::kInfered)) + return false; + *js << ")"; + if (i + 1 < m_Arguments.size()) + *js << ", "; + } + } else { + for (const auto& expr : m_Arguments) { + *js << "pfm_rt.get_val("; + if (!expr->ToJavaScript(js, ReturnType::kInfered)) + return false; + *js << ")"; + if (expr != m_Arguments.back()) + *js << ", "; + } + } + *js << ")"; + return !CXFA_IsTooBig(*js); + } + + bool isEvalFunc = false; + bool isExistsFunc = false; + if (!IsBuiltInFunc(&funcName)) { + // If a function is not a SomMethod or a built-in then the input was + // invalid, so failing. The scanner/lexer should catch this, but currently + // doesn't. This failure will bubble up to the top-level and cause the + // transpile to fail. + return false; + } + + if (funcName.AsStringView().EqualsASCII("Eval")) { + isEvalFunc = true; + *js << "eval.call(this, pfm_rt.Translate"; + } else { + if (funcName.AsStringView().EqualsASCII("Exists")) + isExistsFunc = true; + + *js << "pfm_rt." << funcName; + } + + *js << "("; + if (isExistsFunc) { + *js << "\n(\nfunction ()\n{\ntry\n{\n"; + if (!m_Arguments.empty()) { + *js << "return "; + if (!m_Arguments[0]->ToJavaScript(js, ReturnType::kInfered)) + return false; + *js << ";\n}\n"; + } else { + *js << "return 0;\n}\n"; + } + *js << "catch(accessExceptions)\n"; + *js << "{\nreturn 0;\n}\n}\n).call(this)\n"; + } else { + for (const auto& expr : m_Arguments) { + if (!expr->ToJavaScript(js, ReturnType::kInfered)) + return false; + if (expr != m_Arguments.back()) + *js << ", "; + } + } + *js << ")"; + if (isEvalFunc) + *js << ")"; + + return !CXFA_IsTooBig(*js); +} + +CXFA_FMDotAccessorExpression::CXFA_FMDotAccessorExpression( + std::unique_ptr<CXFA_FMSimpleExpression> pAccessor, + XFA_FM_TOKEN op, + WideStringView wsIdentifier, + std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp) + : CXFA_FMChainableExpression(op, + std::move(pAccessor), + std::move(pIndexExp)), + m_wsIdentifier(wsIdentifier) {} + +CXFA_FMDotAccessorExpression::~CXFA_FMDotAccessorExpression() = default; + +bool CXFA_FMDotAccessorExpression::ToJavaScript(CFX_WideTextBuf* js, + ReturnType type) const { + CXFA_FMToJavaScriptDepth depthManager; + if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) + return false; + + *js << "pfm_rt.dot_acc("; + + CFX_WideTextBuf tempExp1; + CXFA_FMSimpleExpression* exp1 = GetFirstExpression(); + if (exp1) { + if (!exp1->ToJavaScript(&tempExp1, ReturnType::kInfered)) + return false; + + *js << tempExp1; + } else { + *js << "null"; + } + *js << ", \""; + + if (exp1 && exp1->GetOperatorToken() == TOKidentifier) + *js << tempExp1; + + *js << "\", "; + if (GetOperatorToken() == TOKdotscream) + *js << "\"#" << m_wsIdentifier << "\", "; + else if (GetOperatorToken() == TOKdotstar) + *js << "\"*\", "; + else if (GetOperatorToken() == TOKcall) + *js << "\"\", "; + else + *js << "\"" << m_wsIdentifier << "\", "; + + CXFA_FMSimpleExpression* exp2 = GetSecondExpression(); + if (!exp2->ToJavaScript(js, ReturnType::kInfered)) + return false; + + *js << ")"; + return !CXFA_IsTooBig(*js); +} + +CXFA_FMIndexExpression::CXFA_FMIndexExpression( + XFA_FM_AccessorIndex accessorIndex, + std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp, + bool bIsStarIndex) + : CXFA_FMSimpleExpression(TOKlbracket), + m_pExp(std::move(pIndexExp)), + m_accessorIndex(accessorIndex), + m_bIsStarIndex(bIsStarIndex) {} + +CXFA_FMIndexExpression::~CXFA_FMIndexExpression() = default; + +bool CXFA_FMIndexExpression::ToJavaScript(CFX_WideTextBuf* js, + ReturnType type) const { + CXFA_FMToJavaScriptDepth depthManager; + if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) + return false; + + switch (m_accessorIndex) { + case ACCESSOR_NO_INDEX: + *js << "0"; + break; + case ACCESSOR_NO_RELATIVEINDEX: + *js << "1"; + break; + case ACCESSOR_POSITIVE_INDEX: + *js << "2"; + break; + case ACCESSOR_NEGATIVE_INDEX: + *js << "3"; + break; + default: + *js << "0"; + } + if (m_bIsStarIndex) + return !CXFA_IsTooBig(*js); + + *js << ", "; + if (m_pExp) { + if (!m_pExp->ToJavaScript(js, ReturnType::kInfered)) + return false; + } else { + *js << "0"; + } + return !CXFA_IsTooBig(*js); +} + +CXFA_FMDotDotAccessorExpression::CXFA_FMDotDotAccessorExpression( + std::unique_ptr<CXFA_FMSimpleExpression> pAccessor, + XFA_FM_TOKEN op, + WideStringView wsIdentifier, + std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp) + : CXFA_FMChainableExpression(op, + std::move(pAccessor), + std::move(pIndexExp)), + m_wsIdentifier(wsIdentifier) {} + +CXFA_FMDotDotAccessorExpression::~CXFA_FMDotDotAccessorExpression() = default; + +bool CXFA_FMDotDotAccessorExpression::ToJavaScript(CFX_WideTextBuf* js, + ReturnType type) const { + CXFA_FMToJavaScriptDepth depthManager; + if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) + return false; + + CXFA_FMSimpleExpression* exp1 = GetFirstExpression(); + *js << "pfm_rt.dotdot_acc("; + if (!exp1->ToJavaScript(js, ReturnType::kInfered)) + return false; + *js << ", " + << "\""; + if (exp1->GetOperatorToken() == TOKidentifier) { + if (!exp1->ToJavaScript(js, ReturnType::kInfered)) + return false; + } + + CXFA_FMSimpleExpression* exp2 = GetSecondExpression(); + *js << "\", \"" << m_wsIdentifier << "\", "; + if (!exp2->ToJavaScript(js, ReturnType::kInfered)) + return false; + *js << ")"; + return !CXFA_IsTooBig(*js); +} + +CXFA_FMMethodCallExpression::CXFA_FMMethodCallExpression( + std::unique_ptr<CXFA_FMSimpleExpression> pAccessorExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pCallExp) + : CXFA_FMChainableExpression(TOKdot, + std::move(pAccessorExp1), + std::move(pCallExp)) {} + +CXFA_FMMethodCallExpression::~CXFA_FMMethodCallExpression() = default; + +bool CXFA_FMMethodCallExpression::ToJavaScript(CFX_WideTextBuf* js, + ReturnType type) const { + CXFA_FMToJavaScriptDepth depthManager; + if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) + return false; + + CFX_WideTextBuf buf; + if (!GetFirstExpression()->ToJavaScript(&buf, ReturnType::kInfered)) + return false; + + *js << "(function() {\n"; + *js << " return pfm_method_runner(" << buf << ", function(obj) {\n"; + *js << " return obj."; + if (!GetSecondExpression()->ToJavaScript(js, ReturnType::kInfered)) + return false; + *js << ";\n"; + *js << " });\n"; + *js << "}).call(this)"; + return !CXFA_IsTooBig(*js); +} + +bool CXFA_IsTooBig(const CFX_WideTextBuf& js) { + return js.GetSize() >= 256 * 1024 * 1024; +} + CXFA_FMFunctionDefinition::CXFA_FMFunctionDefinition( WideStringView wsName, std::vector<WideStringView>&& arguments,
diff --git a/xfa/fxfa/fm2js/cxfa_fmexpression.h b/xfa/fxfa/fm2js/cxfa_fmexpression.h index f8f54b8..1a33eff 100644 --- a/xfa/fxfa/fm2js/cxfa_fmexpression.h +++ b/xfa/fxfa/fm2js/cxfa_fmexpression.h
@@ -11,19 +11,339 @@ #include <vector> #include "third_party/base/optional.h" -#include "xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h" +#include "xfa/fxfa/fm2js/cxfa_fmlexer.h" class CFX_WideTextBuf; +enum XFA_FM_AccessorIndex { + ACCESSOR_NO_INDEX, + ACCESSOR_NO_RELATIVEINDEX, + ACCESSOR_POSITIVE_INDEX, + ACCESSOR_NEGATIVE_INDEX +}; + +enum class ReturnType { kImplied, kInfered }; + class CXFA_FMExpression { public: - virtual ~CXFA_FMExpression() = default; + virtual ~CXFA_FMExpression(); virtual bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const = 0; protected: CXFA_FMExpression(); }; +class CXFA_FMSimpleExpression : public CXFA_FMExpression { + public: + ~CXFA_FMSimpleExpression() override; + + XFA_FM_TOKEN GetOperatorToken() const { return m_op; } + bool chainable() const { return m_bChainable; } + + protected: + explicit CXFA_FMSimpleExpression(XFA_FM_TOKEN op); + CXFA_FMSimpleExpression(XFA_FM_TOKEN op, bool chainable); + + private: + const XFA_FM_TOKEN m_op; + const bool m_bChainable; +}; + +class CXFA_FMChainableExpression : public CXFA_FMSimpleExpression { + public: + ~CXFA_FMChainableExpression() override; + + protected: + CXFA_FMChainableExpression(XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2); + + CXFA_FMSimpleExpression* GetFirstExpression() const; + CXFA_FMSimpleExpression* GetSecondExpression() const; + + private: + // Iteratively delete a chainable expression tree in linear time and constant + // space. + static void DeleteChain(std::unique_ptr<CXFA_FMSimpleExpression> pRoot); + + std::unique_ptr<CXFA_FMSimpleExpression> m_pExp1; + std::unique_ptr<CXFA_FMSimpleExpression> m_pExp2; +}; + +class CXFA_FMNullExpression final : public CXFA_FMSimpleExpression { + public: + CXFA_FMNullExpression(); + ~CXFA_FMNullExpression() override = default; + + bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override; +}; + +class CXFA_FMNumberExpression final : public CXFA_FMSimpleExpression { + public: + explicit CXFA_FMNumberExpression(WideStringView wsNumber); + ~CXFA_FMNumberExpression() override; + + bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override; + + private: + WideStringView m_wsNumber; +}; + +class CXFA_FMStringExpression final : public CXFA_FMSimpleExpression { + public: + explicit CXFA_FMStringExpression(WideStringView wsString); + ~CXFA_FMStringExpression() override; + + bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override; + + private: + WideStringView m_wsString; +}; + +class CXFA_FMIdentifierExpression final : public CXFA_FMSimpleExpression { + public: + explicit CXFA_FMIdentifierExpression(WideStringView wsIdentifier); + ~CXFA_FMIdentifierExpression() override; + + bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override; + + private: + WideStringView m_wsIdentifier; +}; + +class CXFA_FMAssignExpression final : public CXFA_FMChainableExpression { + public: + CXFA_FMAssignExpression(XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2); + ~CXFA_FMAssignExpression() override; + + bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override; +}; + +class CXFA_FMBinExpression : public CXFA_FMChainableExpression { + public: + ~CXFA_FMBinExpression() override; + + bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override; + + protected: + CXFA_FMBinExpression(const WideString& opName, + XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2); + + private: + WideString m_OpName; +}; + +class CXFA_FMLogicalOrExpression final : public CXFA_FMBinExpression { + public: + CXFA_FMLogicalOrExpression(XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2); + ~CXFA_FMLogicalOrExpression() override = default; +}; + +class CXFA_FMLogicalAndExpression final : public CXFA_FMBinExpression { + public: + CXFA_FMLogicalAndExpression(XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2); + ~CXFA_FMLogicalAndExpression() override = default; +}; + +class CXFA_FMEqualExpression final : public CXFA_FMBinExpression { + public: + CXFA_FMEqualExpression(XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2); + ~CXFA_FMEqualExpression() override = default; +}; + +class CXFA_FMNotEqualExpression final : public CXFA_FMBinExpression { + public: + CXFA_FMNotEqualExpression(XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2); + ~CXFA_FMNotEqualExpression() override = default; +}; + +class CXFA_FMGtExpression final : public CXFA_FMBinExpression { + public: + CXFA_FMGtExpression(XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2); + ~CXFA_FMGtExpression() override = default; +}; + +class CXFA_FMGeExpression final : public CXFA_FMBinExpression { + public: + CXFA_FMGeExpression(XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2); + ~CXFA_FMGeExpression() override = default; +}; + +class CXFA_FMLtExpression final : public CXFA_FMBinExpression { + public: + CXFA_FMLtExpression(XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2); + ~CXFA_FMLtExpression() override = default; +}; + +class CXFA_FMLeExpression final : public CXFA_FMBinExpression { + public: + CXFA_FMLeExpression(XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2); + ~CXFA_FMLeExpression() override = default; +}; + +class CXFA_FMPlusExpression final : public CXFA_FMBinExpression { + public: + CXFA_FMPlusExpression(XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2); + ~CXFA_FMPlusExpression() override = default; +}; + +class CXFA_FMMinusExpression final : public CXFA_FMBinExpression { + public: + CXFA_FMMinusExpression(XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2); + ~CXFA_FMMinusExpression() override = default; +}; + +class CXFA_FMMulExpression final : public CXFA_FMBinExpression { + public: + CXFA_FMMulExpression(XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2); + ~CXFA_FMMulExpression() override = default; +}; + +class CXFA_FMDivExpression final : public CXFA_FMBinExpression { + public: + CXFA_FMDivExpression(XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pExp2); + ~CXFA_FMDivExpression() override = default; +}; + +class CXFA_FMUnaryExpression : public CXFA_FMSimpleExpression { + public: + ~CXFA_FMUnaryExpression() override; + + bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override; + + protected: + CXFA_FMUnaryExpression(const WideString& opName, + XFA_FM_TOKEN op, + std::unique_ptr<CXFA_FMSimpleExpression> pExp); + + private: + WideString m_OpName; + std::unique_ptr<CXFA_FMSimpleExpression> m_pExp; +}; + +class CXFA_FMPosExpression final : public CXFA_FMUnaryExpression { + public: + explicit CXFA_FMPosExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExp); + ~CXFA_FMPosExpression() override = default; +}; + +class CXFA_FMNegExpression final : public CXFA_FMUnaryExpression { + public: + explicit CXFA_FMNegExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExp); + ~CXFA_FMNegExpression() override = default; +}; + +class CXFA_FMNotExpression final : public CXFA_FMUnaryExpression { + public: + explicit CXFA_FMNotExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExp); + ~CXFA_FMNotExpression() override = default; +}; + +class CXFA_FMCallExpression final : public CXFA_FMSimpleExpression { + public: + CXFA_FMCallExpression( + std::unique_ptr<CXFA_FMSimpleExpression> pExp, + std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>&& pArguments, + bool bIsSomMethod); + ~CXFA_FMCallExpression() override; + + bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override; + + bool IsBuiltInFunc(CFX_WideTextBuf* funcName) const; + uint32_t IsMethodWithObjParam(const WideString& methodName) const; + + private: + std::unique_ptr<CXFA_FMSimpleExpression> m_pExp; + bool m_bIsSomMethod; + std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> m_Arguments; +}; + +class CXFA_FMDotAccessorExpression final : public CXFA_FMChainableExpression { + public: + CXFA_FMDotAccessorExpression( + std::unique_ptr<CXFA_FMSimpleExpression> pAccessor, + XFA_FM_TOKEN op, + WideStringView wsIdentifier, + std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp); + ~CXFA_FMDotAccessorExpression() override; + + bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override; + + private: + WideStringView m_wsIdentifier; +}; + +class CXFA_FMIndexExpression final : public CXFA_FMSimpleExpression { + public: + CXFA_FMIndexExpression(XFA_FM_AccessorIndex accessorIndex, + std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp, + bool bIsStarIndex); + ~CXFA_FMIndexExpression() override; + + bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override; + + private: + std::unique_ptr<CXFA_FMSimpleExpression> m_pExp; + XFA_FM_AccessorIndex m_accessorIndex; + bool m_bIsStarIndex; +}; + +class CXFA_FMDotDotAccessorExpression final + : public CXFA_FMChainableExpression { + public: + CXFA_FMDotDotAccessorExpression( + std::unique_ptr<CXFA_FMSimpleExpression> pAccessor, + XFA_FM_TOKEN op, + WideStringView wsIdentifier, + std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp); + ~CXFA_FMDotDotAccessorExpression() override; + + bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override; + + private: + WideStringView m_wsIdentifier; +}; + +class CXFA_FMMethodCallExpression final : public CXFA_FMChainableExpression { + public: + CXFA_FMMethodCallExpression( + std::unique_ptr<CXFA_FMSimpleExpression> pAccessorExp1, + std::unique_ptr<CXFA_FMSimpleExpression> pCallExp); + ~CXFA_FMMethodCallExpression() override; + + bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override; +}; + +bool CXFA_IsTooBig(const CFX_WideTextBuf& js); + class CXFA_FMFunctionDefinition final : public CXFA_FMExpression { public: CXFA_FMFunctionDefinition(
diff --git a/xfa/fxfa/fm2js/cxfa_fmexpression_unittest.cpp b/xfa/fxfa/fm2js/cxfa_fmexpression_unittest.cpp index 70e87b1..6903a0f 100644 --- a/xfa/fxfa/fm2js/cxfa_fmexpression_unittest.cpp +++ b/xfa/fxfa/fm2js/cxfa_fmexpression_unittest.cpp
@@ -10,8 +10,81 @@ #include "core/fxcrt/cfx_widetextbuf.h" #include "core/fxcrt/fx_string.h" #include "testing/gtest/include/gtest/gtest.h" +#include "xfa/fxfa/fm2js/cxfa_fmlexer.h" #include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h" +TEST(FMCallExpressionTest, more_than_32_arguments) { + // Use sign as it has 3 object parameters at positions 0, 5, and 6. + auto exp = std::make_unique<CXFA_FMIdentifierExpression>(L"sign"); + + std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> args; + for (size_t i = 0; i < 50; i++) + args.push_back(std::make_unique<CXFA_FMNullExpression>()); + + CXFA_FMToJavaScriptDepth::Reset(); + CXFA_FMCallExpression callExp(std::move(exp), std::move(args), true); + + CFX_WideTextBuf js; + callExp.ToJavaScript(&js, ReturnType::kInfered); + + // Generate the result javascript string. + WideString result = L"sign("; + for (size_t i = 0; i < 50; i++) { + if (i > 0) + result += L", "; + + result += L"pfm_rt.get_"; + // Object positions for sign() method. + if (i == 0 || i == 5 || i == 6) + result += L"jsobj(null)"; + else + result += L"val(null)"; + } + result += L")"; + + EXPECT_EQ(result.AsStringView(), js.AsStringView()); +} + +TEST(FMStringExpressionTest, Empty) { + CXFA_FMToJavaScriptDepth::Reset(); + CFX_WideTextBuf accumulator; + CXFA_FMStringExpression(L"").ToJavaScript(&accumulator, ReturnType::kInfered); + EXPECT_EQ(L"", accumulator.AsStringView()); +} + +TEST(FMStringExpressionTest, Short) { + CXFA_FMToJavaScriptDepth::Reset(); + CFX_WideTextBuf accumulator; + CXFA_FMStringExpression(L"a").ToJavaScript(&accumulator, + ReturnType::kInfered); + EXPECT_EQ(L"a", accumulator.AsStringView()); +} + +TEST(FMStringExpressionTest, Medium) { + CXFA_FMToJavaScriptDepth::Reset(); + CFX_WideTextBuf accumulator; + CXFA_FMStringExpression(L".abcd.").ToJavaScript(&accumulator, + ReturnType::kInfered); + EXPECT_EQ(L"\"abcd\"", accumulator.AsStringView()); +} + +TEST(FMStringExpressionTest, Long) { + CXFA_FMToJavaScriptDepth::Reset(); + CFX_WideTextBuf accumulator; + std::vector<WideStringView::UnsignedType> vec(140000, L'A'); + CXFA_FMStringExpression(WideStringView(vec)) + .ToJavaScript(&accumulator, ReturnType::kInfered); + EXPECT_EQ(140000u, accumulator.GetLength()); +} + +TEST(FMStringExpressionTest, Quoted) { + CXFA_FMToJavaScriptDepth::Reset(); + CFX_WideTextBuf accumulator; + CXFA_FMStringExpression(L".Simon says \"\"run\"\".") + .ToJavaScript(&accumulator, ReturnType::kInfered); + EXPECT_EQ(L"\"Simon says \\\"run\\\"\"", accumulator.AsStringView()); +} + TEST(CXFA_FMExpressionTest, VarExpressionInitNull) { CXFA_FMToJavaScriptDepth::Reset(); CFX_WideTextBuf accumulator;
diff --git a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp b/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp deleted file mode 100644 index 2371c44..0000000 --- a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp +++ /dev/null
@@ -1,728 +0,0 @@ -// 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_fmsimpleexpression.h" - -#include <algorithm> -#include <utility> - -#include "core/fxcrt/autorestorer.h" -#include "core/fxcrt/cfx_widetextbuf.h" -#include "core/fxcrt/fx_extension.h" -#include "third_party/base/logging.h" -#include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h" - -namespace { - -const wchar_t* const g_BuiltInFuncs[] = { - L"Abs", L"Apr", L"At", L"Avg", - L"Ceil", L"Choose", L"Concat", L"Count", - L"Cterm", L"Date", L"Date2Num", L"DateFmt", - L"Decode", L"Encode", L"Eval", L"Exists", - L"Floor", L"Format", L"FV", L"Get", - L"HasValue", L"If", L"Ipmt", L"IsoDate2Num", - L"IsoTime2Num", L"Left", L"Len", L"LocalDateFmt", - L"LocalTimeFmt", L"Lower", L"Ltrim", L"Max", - L"Min", L"Mod", L"NPV", L"Num2Date", - L"Num2GMTime", L"Num2Time", L"Oneof", L"Parse", - L"Pmt", L"Post", L"PPmt", L"Put", - L"PV", L"Rate", L"Ref", L"Replace", - L"Right", L"Round", L"Rtrim", L"Space", - L"Str", L"Stuff", L"Substr", L"Sum", - L"Term", L"Time", L"Time2Num", L"TimeFmt", - L"UnitType", L"UnitValue", L"Upper", L"Uuid", - L"Within", L"WordNum", -}; - -const size_t g_BuiltInFuncsMaxLen = 12; - -struct XFA_FMSOMMethod { - const wchar_t* m_wsSomMethodName; - uint32_t m_dParameters; -}; - -const XFA_FMSOMMethod gs_FMSomMethods[] = { - {L"absPage", 0x01}, - {L"absPageInBatch", 0x01}, - {L"absPageSpan", 0x01}, - {L"append", 0x01}, - {L"clear", 0x01}, - {L"formNodes", 0x01}, - {L"h", 0x01}, - {L"insert", 0x03}, - {L"isRecordGroup", 0x01}, - {L"page", 0x01}, - {L"pageSpan", 0x01}, - {L"remove", 0x01}, - {L"saveFilteredXML", 0x01}, - {L"setElement", 0x01}, - {L"sheet", 0x01}, - {L"sheetInBatch", 0x01}, - {L"sign", 0x61}, - {L"verify", 0x0d}, - {L"w", 0x01}, - {L"x", 0x01}, - {L"y", 0x01}, -}; - -} // namespace - -CXFA_FMSimpleExpression::CXFA_FMSimpleExpression(XFA_FM_TOKEN op) - : m_op(op), m_bChainable(false) {} - -CXFA_FMSimpleExpression::CXFA_FMSimpleExpression(XFA_FM_TOKEN op, - bool chainable) - : m_op(op), m_bChainable(chainable) {} - -XFA_FM_TOKEN CXFA_FMSimpleExpression::GetOperatorToken() const { - return m_op; -} - -CXFA_FMChainableExpression::CXFA_FMChainableExpression( - XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2) - : CXFA_FMSimpleExpression(op, /*chainable=*/true), - m_pExp1(std::move(pExp1)), - m_pExp2(std::move(pExp2)) {} - -CXFA_FMChainableExpression::~CXFA_FMChainableExpression() { - DeleteChain(std::move(m_pExp1)); - DeleteChain(std::move(m_pExp2)); -} - -CXFA_FMSimpleExpression* CXFA_FMChainableExpression::GetFirstExpression() { - return m_pExp1.get(); -} - -CXFA_FMSimpleExpression* CXFA_FMChainableExpression::GetSecondExpression() { - return m_pExp2.get(); -} - -// static -void CXFA_FMChainableExpression::DeleteChain( - std::unique_ptr<CXFA_FMSimpleExpression> pRoot) { - while (pRoot && pRoot->chainable()) { - auto* pRootChain = static_cast<CXFA_FMChainableExpression*>(pRoot.get()); - - // If either child is not a chainable expression (i.e. a leaf node), simply - // delete it. - if (pRootChain->m_pExp1 && !pRootChain->m_pExp1->chainable()) - pRootChain->m_pExp1.reset(); - if (pRootChain->m_pExp2 && !pRootChain->m_pExp2->chainable()) - pRootChain->m_pExp2.reset(); - - // If the root is missing either child, delete the root and promote the only - // child to the root. - if (!pRootChain->m_pExp1) { - pRoot = std::move(pRootChain->m_pExp2); - continue; - } - if (!pRootChain->m_pExp2) { - pRoot = std::move(pRootChain->m_pExp1); - continue; - } - - // Otherwise, perform a right tree rotation. - std::unique_ptr<CXFA_FMSimpleExpression> pPivot( - std::move(pRootChain->m_pExp1)); - auto* pPivotChain = static_cast<CXFA_FMChainableExpression*>(pPivot.get()); - pRootChain->m_pExp1 = std::move(pPivotChain->m_pExp2); - pPivotChain->m_pExp2 = std::move(pRoot); - pRoot = std::move(pPivot); - } -} - -CXFA_FMNullExpression::CXFA_FMNullExpression() - : CXFA_FMSimpleExpression(TOKnull) {} - -bool CXFA_FMNullExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) { - CXFA_FMToJavaScriptDepth depthManager; - if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) - return false; - - *js << "null"; - return !CXFA_IsTooBig(*js); -} - -CXFA_FMNumberExpression::CXFA_FMNumberExpression(WideStringView wsNumber) - : CXFA_FMSimpleExpression(TOKnumber), m_wsNumber(wsNumber) {} - -CXFA_FMNumberExpression::~CXFA_FMNumberExpression() = default; - -bool CXFA_FMNumberExpression::ToJavaScript(CFX_WideTextBuf* js, - ReturnType type) { - CXFA_FMToJavaScriptDepth depthManager; - if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) - return false; - - *js << m_wsNumber; - return !CXFA_IsTooBig(*js); -} - -CXFA_FMStringExpression::CXFA_FMStringExpression(WideStringView wsString) - : CXFA_FMSimpleExpression(TOKstring), m_wsString(wsString) {} - -CXFA_FMStringExpression::~CXFA_FMStringExpression() = default; - -bool CXFA_FMStringExpression::ToJavaScript(CFX_WideTextBuf* js, - ReturnType type) { - CXFA_FMToJavaScriptDepth depthManager; - if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) - return false; - - WideString tempStr(m_wsString); - if (tempStr.GetLength() <= 2) { - *js << tempStr; - return !CXFA_IsTooBig(*js); - } - - *js << "\""; - for (size_t i = 1; i < tempStr.GetLength() - 1; i++) { - wchar_t oneChar = tempStr[i]; - switch (oneChar) { - case L'\"': - ++i; - *js << "\\\""; - break; - case 0x0d: - break; - case 0x0a: - *js << "\\n"; - break; - default: - js->AppendChar(oneChar); - break; - } - } - *js << "\""; - return !CXFA_IsTooBig(*js); -} - -CXFA_FMIdentifierExpression::CXFA_FMIdentifierExpression( - WideStringView wsIdentifier) - : CXFA_FMSimpleExpression(TOKidentifier), m_wsIdentifier(wsIdentifier) {} - -CXFA_FMIdentifierExpression::~CXFA_FMIdentifierExpression() = default; - -bool CXFA_FMIdentifierExpression::ToJavaScript(CFX_WideTextBuf* js, - ReturnType type) { - CXFA_FMToJavaScriptDepth depthManager; - if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) - return false; - - if (m_wsIdentifier.EqualsASCII("$")) - *js << "this"; - else if (m_wsIdentifier.EqualsASCII("!")) - *js << "xfa.datasets"; - else if (m_wsIdentifier.EqualsASCII("$data")) - *js << "xfa.datasets.data"; - else if (m_wsIdentifier.EqualsASCII("$event")) - *js << "xfa.event"; - else if (m_wsIdentifier.EqualsASCII("$form")) - *js << "xfa.form"; - else if (m_wsIdentifier.EqualsASCII("$host")) - *js << "xfa.host"; - else if (m_wsIdentifier.EqualsASCII("$layout")) - *js << "xfa.layout"; - else if (m_wsIdentifier.EqualsASCII("$template")) - *js << "xfa.template"; - else if (m_wsIdentifier[0] == L'!') - *js << "pfm__excl__" << m_wsIdentifier.Last(m_wsIdentifier.GetLength() - 1); - else - *js << m_wsIdentifier; - - return !CXFA_IsTooBig(*js); -} - -CXFA_FMAssignExpression::CXFA_FMAssignExpression( - XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2) - : CXFA_FMChainableExpression(op, std::move(pExp1), std::move(pExp2)) {} - -CXFA_FMAssignExpression::~CXFA_FMAssignExpression() = default; - -bool CXFA_FMAssignExpression::ToJavaScript(CFX_WideTextBuf* js, - ReturnType type) { - CXFA_FMToJavaScriptDepth depthManager; - if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) - return false; - - CFX_WideTextBuf tempExp1; - CXFA_FMSimpleExpression* exp1 = GetFirstExpression(); - if (!exp1->ToJavaScript(&tempExp1, ReturnType::kInfered)) - return false; - - *js << "if (pfm_rt.is_obj(" << tempExp1 << "))\n{\n"; - if (type == ReturnType::kImplied) - *js << "pfm_ret = "; - - CFX_WideTextBuf tempExp2; - CXFA_FMSimpleExpression* exp2 = GetSecondExpression(); - if (!exp2->ToJavaScript(&tempExp2, ReturnType::kInfered)) - return false; - - *js << "pfm_rt.asgn_val_op(" << tempExp1 << ", " << tempExp2 << ");\n}\n"; - - if (exp1->GetOperatorToken() == TOKidentifier && - !tempExp1.AsStringView().EqualsASCII("this")) { - *js << "else\n{\n"; - if (type == ReturnType::kImplied) - *js << "pfm_ret = "; - - *js << tempExp1 << " = pfm_rt.asgn_val_op"; - *js << "(" << tempExp1 << ", " << tempExp2 << ");\n"; - *js << "}\n"; - } - return !CXFA_IsTooBig(*js); -} - -CXFA_FMBinExpression::CXFA_FMBinExpression( - const WideString& opName, - XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2) - : CXFA_FMChainableExpression(op, std::move(pExp1), std::move(pExp2)), - m_OpName(opName) {} - -CXFA_FMBinExpression::~CXFA_FMBinExpression() = default; - -bool CXFA_FMBinExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) { - CXFA_FMToJavaScriptDepth depthManager; - if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) - return false; - - *js << "pfm_rt." << m_OpName << "("; - if (!GetFirstExpression()->ToJavaScript(js, ReturnType::kInfered)) - return false; - *js << ", "; - if (!GetSecondExpression()->ToJavaScript(js, ReturnType::kInfered)) - return false; - *js << ")"; - return !CXFA_IsTooBig(*js); -} - -CXFA_FMLogicalOrExpression::CXFA_FMLogicalOrExpression( - XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2) - : CXFA_FMBinExpression(L"log_or_op", - op, - std::move(pExp1), - std::move(pExp2)) {} - -CXFA_FMLogicalAndExpression::CXFA_FMLogicalAndExpression( - XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2) - : CXFA_FMBinExpression(L"log_and_op", - op, - std::move(pExp1), - std::move(pExp2)) {} - -CXFA_FMEqualExpression::CXFA_FMEqualExpression( - XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2) - : CXFA_FMBinExpression(L"eq_op", op, std::move(pExp1), std::move(pExp2)) {} - -CXFA_FMNotEqualExpression::CXFA_FMNotEqualExpression( - XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2) - : CXFA_FMBinExpression(L"neq_op", op, std::move(pExp1), std::move(pExp2)) {} - -CXFA_FMGtExpression::CXFA_FMGtExpression( - XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2) - : CXFA_FMBinExpression(L"gt_op", op, std::move(pExp1), std::move(pExp2)) {} - -CXFA_FMGeExpression::CXFA_FMGeExpression( - XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2) - : CXFA_FMBinExpression(L"ge_op", op, std::move(pExp1), std::move(pExp2)) {} - -CXFA_FMLtExpression::CXFA_FMLtExpression( - XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2) - : CXFA_FMBinExpression(L"lt_op", op, std::move(pExp1), std::move(pExp2)) {} - -CXFA_FMLeExpression::CXFA_FMLeExpression( - XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2) - : CXFA_FMBinExpression(L"le_op", op, std::move(pExp1), std::move(pExp2)) {} - -CXFA_FMPlusExpression::CXFA_FMPlusExpression( - XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2) - : CXFA_FMBinExpression(L"plus_op", op, std::move(pExp1), std::move(pExp2)) { -} - -CXFA_FMMinusExpression::CXFA_FMMinusExpression( - XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2) - : CXFA_FMBinExpression(L"minus_op", - op, - std::move(pExp1), - std::move(pExp2)) {} - -CXFA_FMMulExpression::CXFA_FMMulExpression( - XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2) - : CXFA_FMBinExpression(L"mul_op", op, std::move(pExp1), std::move(pExp2)) {} - -CXFA_FMDivExpression::CXFA_FMDivExpression( - XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2) - : CXFA_FMBinExpression(L"div_op", op, std::move(pExp1), std::move(pExp2)) {} - -CXFA_FMUnaryExpression::CXFA_FMUnaryExpression( - const WideString& opName, - XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp) - : CXFA_FMSimpleExpression(op), m_OpName(opName), m_pExp(std::move(pExp)) {} - -CXFA_FMUnaryExpression::~CXFA_FMUnaryExpression() = default; - -bool CXFA_FMUnaryExpression::ToJavaScript(CFX_WideTextBuf* js, - ReturnType type) { - CXFA_FMToJavaScriptDepth depthManager; - if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) - return false; - - *js << "pfm_rt." << m_OpName.c_str() << "("; - if (!m_pExp->ToJavaScript(js, ReturnType::kInfered)) - return false; - *js << ")"; - return !CXFA_IsTooBig(*js); -} - -CXFA_FMPosExpression::CXFA_FMPosExpression( - std::unique_ptr<CXFA_FMSimpleExpression> pExp) - : CXFA_FMUnaryExpression(L"pos_op", TOKplus, std::move(pExp)) {} - -CXFA_FMNegExpression::CXFA_FMNegExpression( - std::unique_ptr<CXFA_FMSimpleExpression> pExp) - : CXFA_FMUnaryExpression(L"neg_op", TOKminus, std::move(pExp)) {} - -CXFA_FMNotExpression::CXFA_FMNotExpression( - std::unique_ptr<CXFA_FMSimpleExpression> pExp) - : CXFA_FMUnaryExpression(L"log_not_op", TOKksnot, std::move(pExp)) {} - -CXFA_FMCallExpression::CXFA_FMCallExpression( - std::unique_ptr<CXFA_FMSimpleExpression> pExp, - std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>&& pArguments, - bool bIsSomMethod) - : CXFA_FMSimpleExpression(TOKcall), - m_pExp(std::move(pExp)), - m_bIsSomMethod(bIsSomMethod), - m_Arguments(std::move(pArguments)) {} - -CXFA_FMCallExpression::~CXFA_FMCallExpression() = default; - -bool CXFA_FMCallExpression::IsBuiltInFunc(CFX_WideTextBuf* funcName) { - if (funcName->GetLength() > g_BuiltInFuncsMaxLen) - return false; - - WideString str = funcName->MakeString(); - const wchar_t* const* pMatchResult = std::lower_bound( - std::begin(g_BuiltInFuncs), std::end(g_BuiltInFuncs), str, - [](const wchar_t* iter, const WideString& val) -> bool { - return val.CompareNoCase(iter) > 0; - }); - if (pMatchResult != std::end(g_BuiltInFuncs) && - !str.CompareNoCase(*pMatchResult)) { - funcName->Clear(); - *funcName << *pMatchResult; - return true; - } - return false; -} - -uint32_t CXFA_FMCallExpression::IsMethodWithObjParam( - const WideString& methodName) { - const XFA_FMSOMMethod* result = std::lower_bound( - std::begin(gs_FMSomMethods), std::end(gs_FMSomMethods), methodName, - [](const XFA_FMSOMMethod iter, const WideString& val) { - return val.Compare(iter.m_wsSomMethodName) > 0; - }); - if (result != std::end(gs_FMSomMethods) && - !methodName.Compare(result->m_wsSomMethodName)) { - return result->m_dParameters; - } - return 0; -} - -bool CXFA_FMCallExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) { - CXFA_FMToJavaScriptDepth depthManager; - if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) - return false; - - CFX_WideTextBuf funcName; - if (!m_pExp->ToJavaScript(&funcName, ReturnType::kInfered)) - return false; - - if (m_bIsSomMethod) { - *js << funcName << "("; - uint32_t methodPara = IsMethodWithObjParam(funcName.MakeString()); - if (methodPara > 0) { - for (size_t i = 0; i < m_Arguments.size(); ++i) { - // Currently none of our expressions use objects for a parameter over - // the 6th. Make sure we don't overflow the shift when doing this - // check. If we ever need more the 32 object params we can revisit. - *js << "pfm_rt.get_"; - if (i < 32 && (methodPara & (0x01 << i)) > 0) - *js << "jsobj"; - else - *js << "val"; - - *js << "("; - if (!m_Arguments[i]->ToJavaScript(js, ReturnType::kInfered)) - return false; - *js << ")"; - if (i + 1 < m_Arguments.size()) - *js << ", "; - } - } else { - for (const auto& expr : m_Arguments) { - *js << "pfm_rt.get_val("; - if (!expr->ToJavaScript(js, ReturnType::kInfered)) - return false; - *js << ")"; - if (expr != m_Arguments.back()) - *js << ", "; - } - } - *js << ")"; - return !CXFA_IsTooBig(*js); - } - - bool isEvalFunc = false; - bool isExistsFunc = false; - if (!IsBuiltInFunc(&funcName)) { - // If a function is not a SomMethod or a built-in then the input was - // invalid, so failing. The scanner/lexer should catch this, but currently - // doesn't. This failure will bubble up to the top-level and cause the - // transpile to fail. - return false; - } - - if (funcName.AsStringView().EqualsASCII("Eval")) { - isEvalFunc = true; - *js << "eval.call(this, pfm_rt.Translate"; - } else { - if (funcName.AsStringView().EqualsASCII("Exists")) - isExistsFunc = true; - - *js << "pfm_rt." << funcName; - } - - *js << "("; - if (isExistsFunc) { - *js << "\n(\nfunction ()\n{\ntry\n{\n"; - if (!m_Arguments.empty()) { - *js << "return "; - if (!m_Arguments[0]->ToJavaScript(js, ReturnType::kInfered)) - return false; - *js << ";\n}\n"; - } else { - *js << "return 0;\n}\n"; - } - *js << "catch(accessExceptions)\n"; - *js << "{\nreturn 0;\n}\n}\n).call(this)\n"; - } else { - for (const auto& expr : m_Arguments) { - if (!expr->ToJavaScript(js, ReturnType::kInfered)) - return false; - if (expr != m_Arguments.back()) - *js << ", "; - } - } - *js << ")"; - if (isEvalFunc) - *js << ")"; - - return !CXFA_IsTooBig(*js); -} - -CXFA_FMDotAccessorExpression::CXFA_FMDotAccessorExpression( - std::unique_ptr<CXFA_FMSimpleExpression> pAccessor, - XFA_FM_TOKEN op, - WideStringView wsIdentifier, - std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp) - : CXFA_FMChainableExpression(op, - std::move(pAccessor), - std::move(pIndexExp)), - m_wsIdentifier(wsIdentifier) {} - -CXFA_FMDotAccessorExpression::~CXFA_FMDotAccessorExpression() = default; - -bool CXFA_FMDotAccessorExpression::ToJavaScript(CFX_WideTextBuf* js, - ReturnType type) { - CXFA_FMToJavaScriptDepth depthManager; - if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) - return false; - - *js << "pfm_rt.dot_acc("; - - CFX_WideTextBuf tempExp1; - CXFA_FMSimpleExpression* exp1 = GetFirstExpression(); - if (exp1) { - if (!exp1->ToJavaScript(&tempExp1, ReturnType::kInfered)) - return false; - - *js << tempExp1; - } else { - *js << "null"; - } - *js << ", \""; - - if (exp1 && exp1->GetOperatorToken() == TOKidentifier) - *js << tempExp1; - - *js << "\", "; - if (m_op == TOKdotscream) - *js << "\"#" << m_wsIdentifier << "\", "; - else if (m_op == TOKdotstar) - *js << "\"*\", "; - else if (m_op == TOKcall) - *js << "\"\", "; - else - *js << "\"" << m_wsIdentifier << "\", "; - - CXFA_FMSimpleExpression* exp2 = GetSecondExpression(); - if (!exp2->ToJavaScript(js, ReturnType::kInfered)) - return false; - - *js << ")"; - return !CXFA_IsTooBig(*js); -} - -CXFA_FMIndexExpression::CXFA_FMIndexExpression( - XFA_FM_AccessorIndex accessorIndex, - std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp, - bool bIsStarIndex) - : CXFA_FMSimpleExpression(TOKlbracket), - m_pExp(std::move(pIndexExp)), - m_accessorIndex(accessorIndex), - m_bIsStarIndex(bIsStarIndex) {} - -CXFA_FMIndexExpression::~CXFA_FMIndexExpression() = default; - -bool CXFA_FMIndexExpression::ToJavaScript(CFX_WideTextBuf* js, - ReturnType type) { - CXFA_FMToJavaScriptDepth depthManager; - if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) - return false; - - switch (m_accessorIndex) { - case ACCESSOR_NO_INDEX: - *js << "0"; - break; - case ACCESSOR_NO_RELATIVEINDEX: - *js << "1"; - break; - case ACCESSOR_POSITIVE_INDEX: - *js << "2"; - break; - case ACCESSOR_NEGATIVE_INDEX: - *js << "3"; - break; - default: - *js << "0"; - } - if (m_bIsStarIndex) - return !CXFA_IsTooBig(*js); - - *js << ", "; - if (m_pExp) { - if (!m_pExp->ToJavaScript(js, ReturnType::kInfered)) - return false; - } else { - *js << "0"; - } - return !CXFA_IsTooBig(*js); -} - -CXFA_FMDotDotAccessorExpression::CXFA_FMDotDotAccessorExpression( - std::unique_ptr<CXFA_FMSimpleExpression> pAccessor, - XFA_FM_TOKEN op, - WideStringView wsIdentifier, - std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp) - : CXFA_FMChainableExpression(op, - std::move(pAccessor), - std::move(pIndexExp)), - m_wsIdentifier(wsIdentifier) {} - -CXFA_FMDotDotAccessorExpression::~CXFA_FMDotDotAccessorExpression() = default; - -bool CXFA_FMDotDotAccessorExpression::ToJavaScript(CFX_WideTextBuf* js, - ReturnType type) { - CXFA_FMToJavaScriptDepth depthManager; - if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) - return false; - - CXFA_FMSimpleExpression* exp1 = GetFirstExpression(); - *js << "pfm_rt.dotdot_acc("; - if (!exp1->ToJavaScript(js, ReturnType::kInfered)) - return false; - *js << ", " - << "\""; - if (exp1->GetOperatorToken() == TOKidentifier) { - if (!exp1->ToJavaScript(js, ReturnType::kInfered)) - return false; - } - - CXFA_FMSimpleExpression* exp2 = GetSecondExpression(); - *js << "\", \"" << m_wsIdentifier << "\", "; - if (!exp2->ToJavaScript(js, ReturnType::kInfered)) - return false; - *js << ")"; - return !CXFA_IsTooBig(*js); -} - -CXFA_FMMethodCallExpression::CXFA_FMMethodCallExpression( - std::unique_ptr<CXFA_FMSimpleExpression> pAccessorExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pCallExp) - : CXFA_FMChainableExpression(TOKdot, - std::move(pAccessorExp1), - std::move(pCallExp)) {} - -CXFA_FMMethodCallExpression::~CXFA_FMMethodCallExpression() = default; - -bool CXFA_FMMethodCallExpression::ToJavaScript(CFX_WideTextBuf* js, - ReturnType type) { - CXFA_FMToJavaScriptDepth depthManager; - if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) - return false; - - CFX_WideTextBuf buf; - if (!GetFirstExpression()->ToJavaScript(&buf, ReturnType::kInfered)) - return false; - - *js << "(function() {\n"; - *js << " return pfm_method_runner(" << buf << ", function(obj) {\n"; - *js << " return obj."; - if (!GetSecondExpression()->ToJavaScript(js, ReturnType::kInfered)) - return false; - *js << ";\n"; - *js << " });\n"; - *js << "}).call(this)"; - return !CXFA_IsTooBig(*js); -} - -bool CXFA_IsTooBig(const CFX_WideTextBuf& js) { - return js.GetSize() >= 256 * 1024 * 1024; -}
diff --git a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h b/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h deleted file mode 100644 index 81c341c..0000000 --- a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h +++ /dev/null
@@ -1,338 +0,0 @@ -// 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 - -#ifndef XFA_FXFA_FM2JS_CXFA_FMSIMPLEEXPRESSION_H_ -#define XFA_FXFA_FM2JS_CXFA_FMSIMPLEEXPRESSION_H_ - -#include <memory> -#include <vector> - -#include "xfa/fxfa/fm2js/cxfa_fmlexer.h" - -enum XFA_FM_AccessorIndex { - ACCESSOR_NO_INDEX, - ACCESSOR_NO_RELATIVEINDEX, - ACCESSOR_POSITIVE_INDEX, - ACCESSOR_NEGATIVE_INDEX -}; - -enum class ReturnType { kImplied, kInfered }; - -class CFX_WideTextBuf; - -class CXFA_FMSimpleExpression { - public: - virtual ~CXFA_FMSimpleExpression() = default; - virtual bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) = 0; - - XFA_FM_TOKEN GetOperatorToken() const; - bool chainable() const { return m_bChainable; } - - protected: - explicit CXFA_FMSimpleExpression(XFA_FM_TOKEN op); - CXFA_FMSimpleExpression(XFA_FM_TOKEN op, bool chainable); - - const XFA_FM_TOKEN m_op; - - private: - const bool m_bChainable; -}; - -class CXFA_FMChainableExpression : public CXFA_FMSimpleExpression { - public: - ~CXFA_FMChainableExpression() override; - - protected: - CXFA_FMChainableExpression(XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2); - - CXFA_FMSimpleExpression* GetFirstExpression(); - CXFA_FMSimpleExpression* GetSecondExpression(); - - private: - // Iteratively delete a chainable expression tree in linear time and constant - // space. - static void DeleteChain(std::unique_ptr<CXFA_FMSimpleExpression> pRoot); - - std::unique_ptr<CXFA_FMSimpleExpression> m_pExp1; - std::unique_ptr<CXFA_FMSimpleExpression> m_pExp2; -}; - -class CXFA_FMNullExpression final : public CXFA_FMSimpleExpression { - public: - CXFA_FMNullExpression(); - ~CXFA_FMNullExpression() override = default; - - bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override; -}; - -class CXFA_FMNumberExpression final : public CXFA_FMSimpleExpression { - public: - explicit CXFA_FMNumberExpression(WideStringView wsNumber); - ~CXFA_FMNumberExpression() override; - - bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override; - - private: - WideStringView m_wsNumber; -}; - -class CXFA_FMStringExpression final : public CXFA_FMSimpleExpression { - public: - explicit CXFA_FMStringExpression(WideStringView wsString); - ~CXFA_FMStringExpression() override; - - bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override; - - private: - WideStringView m_wsString; -}; - -class CXFA_FMIdentifierExpression final : public CXFA_FMSimpleExpression { - public: - explicit CXFA_FMIdentifierExpression(WideStringView wsIdentifier); - ~CXFA_FMIdentifierExpression() override; - - bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override; - - private: - WideStringView m_wsIdentifier; -}; - -class CXFA_FMAssignExpression final : public CXFA_FMChainableExpression { - public: - CXFA_FMAssignExpression(XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2); - ~CXFA_FMAssignExpression() override; - - bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override; -}; - -class CXFA_FMBinExpression : public CXFA_FMChainableExpression { - public: - ~CXFA_FMBinExpression() override; - - bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override; - - protected: - CXFA_FMBinExpression(const WideString& opName, - XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2); - - private: - WideString m_OpName; -}; - -class CXFA_FMLogicalOrExpression final : public CXFA_FMBinExpression { - public: - CXFA_FMLogicalOrExpression(XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2); - ~CXFA_FMLogicalOrExpression() override = default; -}; - -class CXFA_FMLogicalAndExpression final : public CXFA_FMBinExpression { - public: - CXFA_FMLogicalAndExpression(XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2); - ~CXFA_FMLogicalAndExpression() override = default; -}; - -class CXFA_FMEqualExpression final : public CXFA_FMBinExpression { - public: - CXFA_FMEqualExpression(XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2); - ~CXFA_FMEqualExpression() override = default; -}; - -class CXFA_FMNotEqualExpression final : public CXFA_FMBinExpression { - public: - CXFA_FMNotEqualExpression(XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2); - ~CXFA_FMNotEqualExpression() override = default; -}; - -class CXFA_FMGtExpression final : public CXFA_FMBinExpression { - public: - CXFA_FMGtExpression(XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2); - ~CXFA_FMGtExpression() override = default; -}; - -class CXFA_FMGeExpression final : public CXFA_FMBinExpression { - public: - CXFA_FMGeExpression(XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2); - ~CXFA_FMGeExpression() override = default; -}; - -class CXFA_FMLtExpression final : public CXFA_FMBinExpression { - public: - CXFA_FMLtExpression(XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2); - ~CXFA_FMLtExpression() override = default; -}; - -class CXFA_FMLeExpression final : public CXFA_FMBinExpression { - public: - CXFA_FMLeExpression(XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2); - ~CXFA_FMLeExpression() override = default; -}; - -class CXFA_FMPlusExpression final : public CXFA_FMBinExpression { - public: - CXFA_FMPlusExpression(XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2); - ~CXFA_FMPlusExpression() override = default; -}; - -class CXFA_FMMinusExpression final : public CXFA_FMBinExpression { - public: - CXFA_FMMinusExpression(XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2); - ~CXFA_FMMinusExpression() override = default; -}; - -class CXFA_FMMulExpression final : public CXFA_FMBinExpression { - public: - CXFA_FMMulExpression(XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2); - ~CXFA_FMMulExpression() override = default; -}; - -class CXFA_FMDivExpression final : public CXFA_FMBinExpression { - public: - CXFA_FMDivExpression(XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pExp2); - ~CXFA_FMDivExpression() override = default; -}; - -class CXFA_FMUnaryExpression : public CXFA_FMSimpleExpression { - public: - ~CXFA_FMUnaryExpression() override; - - bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override; - - protected: - CXFA_FMUnaryExpression(const WideString& opName, - XFA_FM_TOKEN op, - std::unique_ptr<CXFA_FMSimpleExpression> pExp); - - private: - WideString m_OpName; - std::unique_ptr<CXFA_FMSimpleExpression> m_pExp; -}; - -class CXFA_FMPosExpression final : public CXFA_FMUnaryExpression { - public: - explicit CXFA_FMPosExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExp); - ~CXFA_FMPosExpression() override = default; -}; - -class CXFA_FMNegExpression final : public CXFA_FMUnaryExpression { - public: - explicit CXFA_FMNegExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExp); - ~CXFA_FMNegExpression() override = default; -}; - -class CXFA_FMNotExpression final : public CXFA_FMUnaryExpression { - public: - explicit CXFA_FMNotExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExp); - ~CXFA_FMNotExpression() override = default; -}; - -class CXFA_FMCallExpression final : public CXFA_FMSimpleExpression { - public: - CXFA_FMCallExpression( - std::unique_ptr<CXFA_FMSimpleExpression> pExp, - std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>&& pArguments, - bool bIsSomMethod); - ~CXFA_FMCallExpression() override; - - bool IsBuiltInFunc(CFX_WideTextBuf* funcName); - uint32_t IsMethodWithObjParam(const WideString& methodName); - bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override; - - private: - std::unique_ptr<CXFA_FMSimpleExpression> m_pExp; - bool m_bIsSomMethod; - std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> m_Arguments; -}; - -class CXFA_FMDotAccessorExpression final : public CXFA_FMChainableExpression { - public: - CXFA_FMDotAccessorExpression( - std::unique_ptr<CXFA_FMSimpleExpression> pAccessor, - XFA_FM_TOKEN op, - WideStringView wsIdentifier, - std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp); - ~CXFA_FMDotAccessorExpression() override; - - bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override; - - private: - WideStringView m_wsIdentifier; -}; - -class CXFA_FMIndexExpression final : public CXFA_FMSimpleExpression { - public: - CXFA_FMIndexExpression(XFA_FM_AccessorIndex accessorIndex, - std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp, - bool bIsStarIndex); - ~CXFA_FMIndexExpression() override; - - bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override; - - private: - std::unique_ptr<CXFA_FMSimpleExpression> m_pExp; - XFA_FM_AccessorIndex m_accessorIndex; - bool m_bIsStarIndex; -}; - -class CXFA_FMDotDotAccessorExpression final - : public CXFA_FMChainableExpression { - public: - CXFA_FMDotDotAccessorExpression( - std::unique_ptr<CXFA_FMSimpleExpression> pAccessor, - XFA_FM_TOKEN op, - WideStringView wsIdentifier, - std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp); - ~CXFA_FMDotDotAccessorExpression() override; - - bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override; - - private: - WideStringView m_wsIdentifier; -}; - -class CXFA_FMMethodCallExpression final : public CXFA_FMChainableExpression { - public: - CXFA_FMMethodCallExpression( - std::unique_ptr<CXFA_FMSimpleExpression> pAccessorExp1, - std::unique_ptr<CXFA_FMSimpleExpression> pCallExp); - ~CXFA_FMMethodCallExpression() override; - - bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override; -}; - -bool CXFA_IsTooBig(const CFX_WideTextBuf& js); - -#endif // XFA_FXFA_FM2JS_CXFA_FMSIMPLEEXPRESSION_H_
diff --git a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression_unittest.cpp b/xfa/fxfa/fm2js/cxfa_fmsimpleexpression_unittest.cpp deleted file mode 100644 index 8831e05..0000000 --- a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression_unittest.cpp +++ /dev/null
@@ -1,86 +0,0 @@ -// Copyright 2016 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. - -#include "xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h" - -#include <memory> -#include <utility> - -#include "core/fxcrt/cfx_widetextbuf.h" -#include "core/fxcrt/fx_string.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "xfa/fxfa/fm2js/cxfa_fmlexer.h" -#include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h" - -TEST(FMCallExpressionTest, more_than_32_arguments) { - // Use sign as it has 3 object parameters at positions 0, 5, and 6. - auto exp = std::make_unique<CXFA_FMIdentifierExpression>(L"sign"); - - std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> args; - for (size_t i = 0; i < 50; i++) - args.push_back(std::make_unique<CXFA_FMNullExpression>()); - - CXFA_FMToJavaScriptDepth::Reset(); - CXFA_FMCallExpression callExp(std::move(exp), std::move(args), true); - - CFX_WideTextBuf js; - callExp.ToJavaScript(&js, ReturnType::kInfered); - - // Generate the result javascript string. - WideString result = L"sign("; - for (size_t i = 0; i < 50; i++) { - if (i > 0) - result += L", "; - - result += L"pfm_rt.get_"; - // Object positions for sign() method. - if (i == 0 || i == 5 || i == 6) - result += L"jsobj(null)"; - else - result += L"val(null)"; - } - result += L")"; - - EXPECT_EQ(result.AsStringView(), js.AsStringView()); -} - -TEST(FMStringExpressionTest, Empty) { - CXFA_FMToJavaScriptDepth::Reset(); - CFX_WideTextBuf accumulator; - CXFA_FMStringExpression(L"").ToJavaScript(&accumulator, ReturnType::kInfered); - EXPECT_EQ(L"", accumulator.AsStringView()); -} - -TEST(FMStringExpressionTest, Short) { - CXFA_FMToJavaScriptDepth::Reset(); - CFX_WideTextBuf accumulator; - CXFA_FMStringExpression(L"a").ToJavaScript(&accumulator, - ReturnType::kInfered); - EXPECT_EQ(L"a", accumulator.AsStringView()); -} - -TEST(FMStringExpressionTest, Medium) { - CXFA_FMToJavaScriptDepth::Reset(); - CFX_WideTextBuf accumulator; - CXFA_FMStringExpression(L".abcd.").ToJavaScript(&accumulator, - ReturnType::kInfered); - EXPECT_EQ(L"\"abcd\"", accumulator.AsStringView()); -} - -TEST(FMStringExpressionTest, Long) { - CXFA_FMToJavaScriptDepth::Reset(); - CFX_WideTextBuf accumulator; - std::vector<WideStringView::UnsignedType> vec(140000, L'A'); - CXFA_FMStringExpression(WideStringView(vec)) - .ToJavaScript(&accumulator, ReturnType::kInfered); - EXPECT_EQ(140000u, accumulator.GetLength()); -} - -TEST(FMStringExpressionTest, Quoted) { - CXFA_FMToJavaScriptDepth::Reset(); - CFX_WideTextBuf accumulator; - CXFA_FMStringExpression(L".Simon says \"\"run\"\".") - .ToJavaScript(&accumulator, ReturnType::kInfered); - EXPECT_EQ(L"\"Simon says \\\"run\\\"\"", accumulator.AsStringView()); -}