Home | History | Annotate | Download | only in fm2js
      1 // Copyright 2014 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h"
      8 
      9 #include <algorithm>
     10 #include <iostream>
     11 #include <utility>
     12 
     13 #include "core/fxcrt/autorestorer.h"
     14 #include "core/fxcrt/cfx_widetextbuf.h"
     15 #include "core/fxcrt/fx_extension.h"
     16 #include "third_party/base/logging.h"
     17 #include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h"
     18 
     19 namespace {
     20 
     21 // Indexed by XFA_FM_SimpleExpressionType
     22 const wchar_t* const gs_lpStrExpFuncName[] = {
     23     L"pfm_rt.asgn_val_op", L"pfm_rt.log_or_op",  L"pfm_rt.log_and_op",
     24     L"pfm_rt.eq_op",       L"pfm_rt.neq_op",     L"pfm_rt.lt_op",
     25     L"pfm_rt.le_op",       L"pfm_rt.gt_op",      L"pfm_rt.ge_op",
     26     L"pfm_rt.plus_op",     L"pfm_rt.minus_op",   L"pfm_rt.mul_op",
     27     L"pfm_rt.div_op",      L"pfm_rt.pos_op",     L"pfm_rt.neg_op",
     28     L"pfm_rt.log_not_op",  L"pfm_rt.",           L"pfm_rt.dot_acc",
     29     L"pfm_rt.dotdot_acc",  L"pfm_rt.concat_obj", L"pfm_rt.is_obj",
     30     L"pfm_rt.is_ary",      L"pfm_rt.get_val",    L"pfm_rt.get_jsobj",
     31     L"pfm_rt.var_filter",
     32 };
     33 
     34 const wchar_t* const g_BuiltInFuncs[] = {
     35     L"Abs",          L"Apr",       L"At",       L"Avg",
     36     L"Ceil",         L"Choose",    L"Concat",   L"Count",
     37     L"Cterm",        L"Date",      L"Date2Num", L"DateFmt",
     38     L"Decode",       L"Encode",    L"Eval",     L"Exists",
     39     L"Floor",        L"Format",    L"FV",       L"Get",
     40     L"HasValue",     L"If",        L"Ipmt",     L"IsoDate2Num",
     41     L"IsoTime2Num",  L"Left",      L"Len",      L"LocalDateFmt",
     42     L"LocalTimeFmt", L"Lower",     L"Ltrim",    L"Max",
     43     L"Min",          L"Mod",       L"NPV",      L"Num2Date",
     44     L"Num2GMTime",   L"Num2Time",  L"Oneof",    L"Parse",
     45     L"Pmt",          L"Post",      L"PPmt",     L"Put",
     46     L"PV",           L"Rate",      L"Ref",      L"Replace",
     47     L"Right",        L"Round",     L"Rtrim",    L"Space",
     48     L"Str",          L"Stuff",     L"Substr",   L"Sum",
     49     L"Term",         L"Time",      L"Time2Num", L"TimeFmt",
     50     L"UnitType",     L"UnitValue", L"Upper",    L"Uuid",
     51     L"Within",       L"WordNum",
     52 };
     53 
     54 const size_t g_BuiltInFuncsMaxLen = 12;
     55 
     56 struct XFA_FMSOMMethod {
     57   const wchar_t* m_wsSomMethodName;
     58   uint32_t m_dParameters;
     59 };
     60 
     61 const XFA_FMSOMMethod gs_FMSomMethods[] = {
     62     {L"absPage", 0x01},
     63     {L"absPageInBatch", 0x01},
     64     {L"absPageSpan", 0x01},
     65     {L"append", 0x01},
     66     {L"clear", 0x01},
     67     {L"formNodes", 0x01},
     68     {L"h", 0x01},
     69     {L"insert", 0x03},
     70     {L"isRecordGroup", 0x01},
     71     {L"page", 0x01},
     72     {L"pageSpan", 0x01},
     73     {L"remove", 0x01},
     74     {L"saveFilteredXML", 0x01},
     75     {L"setElement", 0x01},
     76     {L"sheet", 0x01},
     77     {L"sheetInBatch", 0x01},
     78     {L"sign", 0x61},
     79     {L"verify", 0x0d},
     80     {L"w", 0x01},
     81     {L"x", 0x01},
     82     {L"y", 0x01},
     83 };
     84 
     85 }  // namespace
     86 
     87 WideStringView XFA_FM_EXPTypeToString(
     88     XFA_FM_SimpleExpressionType simpleExpType) {
     89   return gs_lpStrExpFuncName[simpleExpType];
     90 }
     91 
     92 CXFA_FMSimpleExpression::CXFA_FMSimpleExpression(uint32_t line, XFA_FM_TOKEN op)
     93     : m_line(line), m_op(op) {}
     94 
     95 bool CXFA_FMSimpleExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
     96   CXFA_FMToJavaScriptDepth depthManager;
     97   return !CXFA_IsTooBig(javascript) && depthManager.IsWithinMaxDepth();
     98 }
     99 
    100 bool CXFA_FMSimpleExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
    101   CXFA_FMToJavaScriptDepth depthManager;
    102   return !CXFA_IsTooBig(javascript) && depthManager.IsWithinMaxDepth();
    103 }
    104 
    105 XFA_FM_TOKEN CXFA_FMSimpleExpression::GetOperatorToken() const {
    106   return m_op;
    107 }
    108 
    109 CXFA_FMNullExpression::CXFA_FMNullExpression(uint32_t line)
    110     : CXFA_FMSimpleExpression(line, TOKnull) {}
    111 
    112 bool CXFA_FMNullExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
    113   CXFA_FMToJavaScriptDepth depthManager;
    114   if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
    115     return false;
    116 
    117   javascript << L"null";
    118   return !CXFA_IsTooBig(javascript);
    119 }
    120 
    121 CXFA_FMNumberExpression::CXFA_FMNumberExpression(uint32_t line,
    122                                                  WideStringView wsNumber)
    123     : CXFA_FMSimpleExpression(line, TOKnumber), m_wsNumber(wsNumber) {}
    124 
    125 CXFA_FMNumberExpression::~CXFA_FMNumberExpression() {}
    126 
    127 bool CXFA_FMNumberExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
    128   CXFA_FMToJavaScriptDepth depthManager;
    129   if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
    130     return false;
    131 
    132   javascript << m_wsNumber;
    133   return !CXFA_IsTooBig(javascript);
    134 }
    135 
    136 CXFA_FMStringExpression::CXFA_FMStringExpression(uint32_t line,
    137                                                  WideStringView wsString)
    138     : CXFA_FMSimpleExpression(line, TOKstring), m_wsString(wsString) {}
    139 
    140 CXFA_FMStringExpression::~CXFA_FMStringExpression() {}
    141 
    142 bool CXFA_FMStringExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
    143   CXFA_FMToJavaScriptDepth depthManager;
    144   if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
    145     return false;
    146 
    147   WideString tempStr(m_wsString);
    148   if (tempStr.GetLength() <= 2) {
    149     javascript << tempStr;
    150     return !CXFA_IsTooBig(javascript);
    151   }
    152   javascript.AppendChar(L'\"');
    153   for (size_t i = 1; i < tempStr.GetLength() - 1; i++) {
    154     wchar_t oneChar = tempStr[i];
    155     switch (oneChar) {
    156       case L'\"':
    157         i++;
    158         javascript << L"\\\"";
    159         break;
    160       case 0x0d:
    161         break;
    162       case 0x0a:
    163         javascript << L"\\n";
    164         break;
    165       default:
    166         javascript.AppendChar(oneChar);
    167         break;
    168     }
    169   }
    170   javascript.AppendChar(L'\"');
    171   return !CXFA_IsTooBig(javascript);
    172 }
    173 
    174 CXFA_FMIdentifierExpression::CXFA_FMIdentifierExpression(
    175     uint32_t line,
    176     WideStringView wsIdentifier)
    177     : CXFA_FMSimpleExpression(line, TOKidentifier),
    178       m_wsIdentifier(wsIdentifier) {}
    179 
    180 CXFA_FMIdentifierExpression::~CXFA_FMIdentifierExpression() {}
    181 
    182 bool CXFA_FMIdentifierExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
    183   CXFA_FMToJavaScriptDepth depthManager;
    184   if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
    185     return false;
    186 
    187   WideString tempStr(m_wsIdentifier);
    188   if (tempStr == L"$") {
    189     tempStr = L"this";
    190   } else if (tempStr == L"!") {
    191     tempStr = L"xfa.datasets";
    192   } else if (tempStr == L"$data") {
    193     tempStr = L"xfa.datasets.data";
    194   } else if (tempStr == L"$event") {
    195     tempStr = L"xfa.event";
    196   } else if (tempStr == L"$form") {
    197     tempStr = L"xfa.form";
    198   } else if (tempStr == L"$host") {
    199     tempStr = L"xfa.host";
    200   } else if (tempStr == L"$layout") {
    201     tempStr = L"xfa.layout";
    202   } else if (tempStr == L"$template") {
    203     tempStr = L"xfa.template";
    204   } else if (tempStr[0] == L'!') {
    205     tempStr =
    206         EXCLAMATION_IN_IDENTIFIER + tempStr.Right(tempStr.GetLength() - 1);
    207   }
    208   javascript << tempStr;
    209   return !CXFA_IsTooBig(javascript);
    210 }
    211 
    212 CXFA_FMUnaryExpression::CXFA_FMUnaryExpression(
    213     uint32_t line,
    214     XFA_FM_TOKEN op,
    215     std::unique_ptr<CXFA_FMSimpleExpression> pExp)
    216     : CXFA_FMSimpleExpression(line, op), m_pExp(std::move(pExp)) {}
    217 
    218 CXFA_FMUnaryExpression::~CXFA_FMUnaryExpression() {}
    219 
    220 bool CXFA_FMUnaryExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
    221   CXFA_FMToJavaScriptDepth depthManager;
    222   return !CXFA_IsTooBig(javascript) && depthManager.IsWithinMaxDepth();
    223 }
    224 
    225 CXFA_FMBinExpression::CXFA_FMBinExpression(
    226     uint32_t line,
    227     XFA_FM_TOKEN op,
    228     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
    229     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
    230     : CXFA_FMSimpleExpression(line, op),
    231       m_pExp1(std::move(pExp1)),
    232       m_pExp2(std::move(pExp2)) {}
    233 
    234 CXFA_FMBinExpression::~CXFA_FMBinExpression() {}
    235 
    236 bool CXFA_FMBinExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
    237   CXFA_FMToJavaScriptDepth depthManager;
    238   return !CXFA_IsTooBig(javascript) && depthManager.IsWithinMaxDepth();
    239 }
    240 
    241 CXFA_FMAssignExpression::CXFA_FMAssignExpression(
    242     uint32_t line,
    243     XFA_FM_TOKEN op,
    244     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
    245     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
    246     : CXFA_FMBinExpression(line, op, std::move(pExp1), std::move(pExp2)) {}
    247 
    248 bool CXFA_FMAssignExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
    249   CXFA_FMToJavaScriptDepth depthManager;
    250   if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
    251     return false;
    252 
    253   javascript << L"if (";
    254   javascript << gs_lpStrExpFuncName[ISFMOBJECT];
    255   javascript << L"(";
    256   CFX_WideTextBuf tempExp1;
    257   if (!m_pExp1->ToJavaScript(tempExp1))
    258     return false;
    259   javascript << tempExp1;
    260   javascript << L"))\n{\n";
    261   javascript << gs_lpStrExpFuncName[ASSIGN];
    262   javascript << L"(";
    263   javascript << tempExp1;
    264   javascript << L", ";
    265 
    266   CFX_WideTextBuf tempExp2;
    267   if (!m_pExp2->ToJavaScript(tempExp2))
    268     return false;
    269   javascript << tempExp2;
    270   javascript << L");\n}\n";
    271   if (m_pExp1->GetOperatorToken() == TOKidentifier &&
    272       tempExp1.AsStringView() != L"this") {
    273     javascript << L"else\n{\n";
    274     javascript << tempExp1;
    275     javascript << L" = ";
    276     javascript << gs_lpStrExpFuncName[ASSIGN];
    277     javascript << L"(";
    278     javascript << tempExp1;
    279     javascript << L", ";
    280     javascript << tempExp2;
    281     javascript << L");\n}\n";
    282   }
    283   return !CXFA_IsTooBig(javascript);
    284 }
    285 
    286 bool CXFA_FMAssignExpression::ToImpliedReturnJS(CFX_WideTextBuf& javascript) {
    287   CXFA_FMToJavaScriptDepth depthManager;
    288   if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
    289     return false;
    290 
    291   javascript << L"if (";
    292   javascript << gs_lpStrExpFuncName[ISFMOBJECT];
    293   javascript << L"(";
    294   CFX_WideTextBuf tempExp1;
    295   if (!m_pExp1->ToJavaScript(tempExp1))
    296     return false;
    297   javascript << tempExp1;
    298   javascript << L"))\n{\n";
    299   javascript << RUNTIMEFUNCTIONRETURNVALUE;
    300   javascript << L" = ";
    301   javascript << gs_lpStrExpFuncName[ASSIGN];
    302   javascript << L"(";
    303   javascript << tempExp1;
    304   javascript << L", ";
    305 
    306   CFX_WideTextBuf tempExp2;
    307   if (!m_pExp2->ToJavaScript(tempExp2))
    308     return false;
    309   javascript << tempExp2;
    310   javascript << L");\n}\n";
    311   if (m_pExp1->GetOperatorToken() == TOKidentifier &&
    312       tempExp1.AsStringView() != L"this") {
    313     javascript << L"else\n{\n";
    314     javascript << RUNTIMEFUNCTIONRETURNVALUE;
    315     javascript << L" = ";
    316     javascript << tempExp1;
    317     javascript << L" = ";
    318     javascript << gs_lpStrExpFuncName[ASSIGN];
    319     javascript << L"(";
    320     javascript << tempExp1;
    321     javascript << L", ";
    322     javascript << tempExp2;
    323     javascript << L");\n}\n";
    324   }
    325   return !CXFA_IsTooBig(javascript);
    326 }
    327 
    328 CXFA_FMLogicalOrExpression::CXFA_FMLogicalOrExpression(
    329     uint32_t line,
    330     XFA_FM_TOKEN op,
    331     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
    332     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
    333     : CXFA_FMBinExpression(line, op, std::move(pExp1), std::move(pExp2)) {}
    334 
    335 bool CXFA_FMLogicalOrExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
    336   CXFA_FMToJavaScriptDepth depthManager;
    337   if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
    338     return false;
    339 
    340   javascript << gs_lpStrExpFuncName[LOGICALOR];
    341   javascript << L"(";
    342   if (!m_pExp1->ToJavaScript(javascript))
    343     return false;
    344   javascript << L", ";
    345   if (!m_pExp2->ToJavaScript(javascript))
    346     return false;
    347   javascript << L")";
    348   return !CXFA_IsTooBig(javascript);
    349 }
    350 
    351 CXFA_FMLogicalAndExpression::CXFA_FMLogicalAndExpression(
    352     uint32_t line,
    353     XFA_FM_TOKEN op,
    354     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
    355     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
    356     : CXFA_FMBinExpression(line, op, std::move(pExp1), std::move(pExp2)) {}
    357 
    358 bool CXFA_FMLogicalAndExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
    359   CXFA_FMToJavaScriptDepth depthManager;
    360   if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
    361     return false;
    362 
    363   javascript << gs_lpStrExpFuncName[LOGICALAND];
    364   javascript << L"(";
    365   if (!m_pExp1->ToJavaScript(javascript))
    366     return false;
    367   javascript << L", ";
    368   if (!m_pExp2->ToJavaScript(javascript))
    369     return false;
    370   javascript << L")";
    371   return !CXFA_IsTooBig(javascript);
    372 }
    373 
    374 CXFA_FMEqualityExpression::CXFA_FMEqualityExpression(
    375     uint32_t line,
    376     XFA_FM_TOKEN op,
    377     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
    378     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
    379     : CXFA_FMBinExpression(line, op, std::move(pExp1), std::move(pExp2)) {}
    380 
    381 bool CXFA_FMEqualityExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
    382   CXFA_FMToJavaScriptDepth depthManager;
    383   if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
    384     return false;
    385 
    386   switch (m_op) {
    387     case TOKeq:
    388     case TOKkseq:
    389       javascript << gs_lpStrExpFuncName[EQUALITY];
    390       break;
    391     case TOKne:
    392     case TOKksne:
    393       javascript << gs_lpStrExpFuncName[NOTEQUALITY];
    394       break;
    395     default:
    396       NOTREACHED();
    397       break;
    398   }
    399   javascript << L"(";
    400   if (!m_pExp1->ToJavaScript(javascript))
    401     return false;
    402   javascript << L", ";
    403   if (!m_pExp2->ToJavaScript(javascript))
    404     return false;
    405   javascript << L")";
    406   return !CXFA_IsTooBig(javascript);
    407 }
    408 
    409 CXFA_FMRelationalExpression::CXFA_FMRelationalExpression(
    410     uint32_t line,
    411     XFA_FM_TOKEN op,
    412     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
    413     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
    414     : CXFA_FMBinExpression(line, op, std::move(pExp1), std::move(pExp2)) {}
    415 
    416 bool CXFA_FMRelationalExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
    417   CXFA_FMToJavaScriptDepth depthManager;
    418   if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
    419     return false;
    420 
    421   switch (m_op) {
    422     case TOKlt:
    423     case TOKkslt:
    424       javascript << gs_lpStrExpFuncName[LESS];
    425       break;
    426     case TOKgt:
    427     case TOKksgt:
    428       javascript << gs_lpStrExpFuncName[GREATER];
    429       break;
    430     case TOKle:
    431     case TOKksle:
    432       javascript << gs_lpStrExpFuncName[LESSEQUAL];
    433       break;
    434     case TOKge:
    435     case TOKksge:
    436       javascript << gs_lpStrExpFuncName[GREATEREQUAL];
    437       break;
    438     default:
    439       NOTREACHED();
    440       break;
    441   }
    442   javascript << L"(";
    443   if (!m_pExp1->ToJavaScript(javascript))
    444     return false;
    445   javascript << L", ";
    446   if (!m_pExp2->ToJavaScript(javascript))
    447     return false;
    448   javascript << L")";
    449   return !CXFA_IsTooBig(javascript);
    450 }
    451 
    452 CXFA_FMAdditiveExpression::CXFA_FMAdditiveExpression(
    453     uint32_t line,
    454     XFA_FM_TOKEN op,
    455     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
    456     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
    457     : CXFA_FMBinExpression(line, op, std::move(pExp1), std::move(pExp2)) {}
    458 
    459 bool CXFA_FMAdditiveExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
    460   CXFA_FMToJavaScriptDepth depthManager;
    461   if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
    462     return false;
    463 
    464   switch (m_op) {
    465     case TOKplus:
    466       javascript << gs_lpStrExpFuncName[PLUS];
    467       break;
    468     case TOKminus:
    469       javascript << gs_lpStrExpFuncName[MINUS];
    470       break;
    471     default:
    472       NOTREACHED();
    473       break;
    474   }
    475   javascript << L"(";
    476   if (!m_pExp1->ToJavaScript(javascript))
    477     return false;
    478   javascript << L", ";
    479   if (!m_pExp2->ToJavaScript(javascript))
    480     return false;
    481   javascript << L")";
    482   return !CXFA_IsTooBig(javascript);
    483 }
    484 
    485 CXFA_FMMultiplicativeExpression::CXFA_FMMultiplicativeExpression(
    486     uint32_t line,
    487     XFA_FM_TOKEN op,
    488     std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
    489     std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
    490     : CXFA_FMBinExpression(line, op, std::move(pExp1), std::move(pExp2)) {}
    491 
    492 bool CXFA_FMMultiplicativeExpression::ToJavaScript(
    493     CFX_WideTextBuf& javascript) {
    494   CXFA_FMToJavaScriptDepth depthManager;
    495   if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
    496     return false;
    497 
    498   switch (m_op) {
    499     case TOKmul:
    500       javascript << gs_lpStrExpFuncName[MULTIPLE];
    501       break;
    502     case TOKdiv:
    503       javascript << gs_lpStrExpFuncName[DIVIDE];
    504       break;
    505     default:
    506       NOTREACHED();
    507       break;
    508   }
    509   javascript << L"(";
    510   if (!m_pExp1->ToJavaScript(javascript))
    511     return false;
    512   javascript << L", ";
    513   if (!m_pExp2->ToJavaScript(javascript))
    514     return false;
    515   javascript << L")";
    516   return !CXFA_IsTooBig(javascript);
    517 }
    518 
    519 CXFA_FMPosExpression::CXFA_FMPosExpression(
    520     uint32_t line,
    521     std::unique_ptr<CXFA_FMSimpleExpression> pExp)
    522     : CXFA_FMUnaryExpression(line, TOKplus, std::move(pExp)) {}
    523 
    524 bool CXFA_FMPosExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
    525   CXFA_FMToJavaScriptDepth depthManager;
    526   if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
    527     return false;
    528 
    529   javascript << gs_lpStrExpFuncName[POSITIVE];
    530   javascript << L"(";
    531   if (!m_pExp->ToJavaScript(javascript))
    532     return false;
    533   javascript << L")";
    534   return !CXFA_IsTooBig(javascript);
    535 }
    536 
    537 CXFA_FMNegExpression::CXFA_FMNegExpression(
    538     uint32_t line,
    539     std::unique_ptr<CXFA_FMSimpleExpression> pExp)
    540     : CXFA_FMUnaryExpression(line, TOKminus, std::move(pExp)) {}
    541 
    542 bool CXFA_FMNegExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
    543   CXFA_FMToJavaScriptDepth depthManager;
    544   if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
    545     return false;
    546 
    547   javascript << gs_lpStrExpFuncName[NEGATIVE];
    548   javascript << L"(";
    549   if (!m_pExp->ToJavaScript(javascript))
    550     return false;
    551   javascript << L")";
    552   return !CXFA_IsTooBig(javascript);
    553 }
    554 
    555 CXFA_FMNotExpression::CXFA_FMNotExpression(
    556     uint32_t line,
    557     std::unique_ptr<CXFA_FMSimpleExpression> pExp)
    558     : CXFA_FMUnaryExpression(line, TOKksnot, std::move(pExp)) {}
    559 
    560 bool CXFA_FMNotExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
    561   CXFA_FMToJavaScriptDepth depthManager;
    562   if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
    563     return false;
    564 
    565   javascript << gs_lpStrExpFuncName[NOT];
    566   javascript << L"(";
    567   if (!m_pExp->ToJavaScript(javascript))
    568     return false;
    569   javascript << L")";
    570   return !CXFA_IsTooBig(javascript);
    571 }
    572 
    573 CXFA_FMCallExpression::CXFA_FMCallExpression(
    574     uint32_t line,
    575     std::unique_ptr<CXFA_FMSimpleExpression> pExp,
    576     std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>&& pArguments,
    577     bool bIsSomMethod)
    578     : CXFA_FMUnaryExpression(line, TOKcall, std::move(pExp)),
    579       m_bIsSomMethod(bIsSomMethod),
    580       m_Arguments(std::move(pArguments)) {}
    581 
    582 CXFA_FMCallExpression::~CXFA_FMCallExpression() {}
    583 
    584 bool CXFA_FMCallExpression::IsBuiltInFunc(CFX_WideTextBuf* funcName) {
    585   if (funcName->GetLength() > g_BuiltInFuncsMaxLen)
    586     return false;
    587 
    588   auto cmpFunc = [](const wchar_t* iter, const WideString& val) -> bool {
    589     return val.CompareNoCase(iter) > 0;
    590   };
    591   WideString str = funcName->MakeString();
    592   const wchar_t* const* pMatchResult = std::lower_bound(
    593       std::begin(g_BuiltInFuncs), std::end(g_BuiltInFuncs), str, cmpFunc);
    594   if (pMatchResult != std::end(g_BuiltInFuncs) &&
    595       !str.CompareNoCase(*pMatchResult)) {
    596     funcName->Clear();
    597     *funcName << *pMatchResult;
    598     return true;
    599   }
    600   return false;
    601 }
    602 
    603 uint32_t CXFA_FMCallExpression::IsMethodWithObjParam(
    604     const WideString& methodName) {
    605   auto cmpFunc = [](const XFA_FMSOMMethod iter, const WideString& val) {
    606     return val.Compare(iter.m_wsSomMethodName) > 0;
    607   };
    608   const XFA_FMSOMMethod* result =
    609       std::lower_bound(std::begin(gs_FMSomMethods), std::end(gs_FMSomMethods),
    610                        methodName, cmpFunc);
    611   if (result != std::end(gs_FMSomMethods) &&
    612       !methodName.Compare(result->m_wsSomMethodName)) {
    613     return result->m_dParameters;
    614   }
    615   return 0;
    616 }
    617 
    618 bool CXFA_FMCallExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
    619   CXFA_FMToJavaScriptDepth depthManager;
    620   if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
    621     return false;
    622 
    623   CFX_WideTextBuf funcName;
    624   if (!m_pExp->ToJavaScript(funcName))
    625     return false;
    626   if (m_bIsSomMethod) {
    627     javascript << funcName;
    628     javascript << L"(";
    629     uint32_t methodPara = IsMethodWithObjParam(funcName.MakeString());
    630     if (methodPara > 0) {
    631       for (size_t i = 0; i < m_Arguments.size(); ++i) {
    632         // Currently none of our expressions use objects for a parameter over
    633         // the 6th. Make sure we don't overflow the shift when doing this
    634         // check. If we ever need more the 32 object params we can revisit.
    635         if (i < 32 && (methodPara & (0x01 << i)) > 0) {
    636           javascript << gs_lpStrExpFuncName[GETFMJSOBJ];
    637         } else {
    638           javascript << gs_lpStrExpFuncName[GETFMVALUE];
    639         }
    640         javascript << L"(";
    641         const auto& expr = m_Arguments[i];
    642         if (!expr->ToJavaScript(javascript))
    643           return false;
    644         javascript << L")";
    645         if (i + 1 < m_Arguments.size()) {
    646           javascript << L", ";
    647         }
    648       }
    649     } else {
    650       for (const auto& expr : m_Arguments) {
    651         javascript << gs_lpStrExpFuncName[GETFMVALUE];
    652         javascript << L"(";
    653         if (!expr->ToJavaScript(javascript))
    654           return false;
    655         javascript << L")";
    656         if (expr != m_Arguments.back())
    657           javascript << L", ";
    658       }
    659     }
    660     javascript << L")";
    661   } else {
    662     bool isEvalFunc = false;
    663     bool isExistsFunc = false;
    664     if (IsBuiltInFunc(&funcName)) {
    665       if (funcName.AsStringView() == L"Eval") {
    666         isEvalFunc = true;
    667         javascript << L"eval.call(this, ";
    668         javascript << gs_lpStrExpFuncName[CALL];
    669         javascript << L"Translate";
    670       } else if (funcName.AsStringView() == L"Exists") {
    671         isExistsFunc = true;
    672         javascript << gs_lpStrExpFuncName[CALL];
    673         javascript << funcName;
    674       } else {
    675         javascript << gs_lpStrExpFuncName[CALL];
    676         javascript << funcName;
    677       }
    678     } else {
    679       // If a function is not a SomMethod or a built-in then the input was
    680       // invalid, so failing. The scanner/lexer should catch this, but currently
    681       // doesn't. This failure will bubble up to the top-level and cause the
    682       // transpile to fail.
    683       return false;
    684     }
    685     javascript << L"(";
    686     if (isExistsFunc) {
    687       javascript << L"\n(\nfunction ()\n{\ntry\n{\n";
    688       if (!m_Arguments.empty()) {
    689         const auto& expr = m_Arguments[0];
    690         javascript << L"return ";
    691         if (!expr->ToJavaScript(javascript))
    692           return false;
    693         javascript << L";\n}\n";
    694       } else {
    695         javascript << L"return 0;\n}\n";
    696       }
    697       javascript << L"catch(accessExceptions)\n";
    698       javascript << L"{\nreturn 0;\n}\n}\n).call(this)\n";
    699     } else {
    700       for (const auto& expr : m_Arguments) {
    701         if (!expr->ToJavaScript(javascript))
    702           return false;
    703         if (expr != m_Arguments.back())
    704           javascript << L", ";
    705       }
    706     }
    707     javascript << L")";
    708     if (isEvalFunc) {
    709       javascript << L")";
    710     }
    711   }
    712   return !CXFA_IsTooBig(javascript);
    713 }
    714 
    715 CXFA_FMDotAccessorExpression::CXFA_FMDotAccessorExpression(
    716     uint32_t line,
    717     std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
    718     XFA_FM_TOKEN op,
    719     WideStringView wsIdentifier,
    720     std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp)
    721     : CXFA_FMBinExpression(line,
    722                            op,
    723                            std::move(pAccessor),
    724                            std::move(pIndexExp)),
    725       m_wsIdentifier(wsIdentifier) {}
    726 
    727 CXFA_FMDotAccessorExpression::~CXFA_FMDotAccessorExpression() {}
    728 
    729 bool CXFA_FMDotAccessorExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
    730   CXFA_FMToJavaScriptDepth depthManager;
    731   if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
    732     return false;
    733 
    734   javascript << gs_lpStrExpFuncName[DOT];
    735   javascript << L"(";
    736   CFX_WideTextBuf tempExp1;
    737   if (m_pExp1) {
    738     if (!m_pExp1->ToJavaScript(tempExp1))
    739       return false;
    740     javascript << tempExp1;
    741   } else {
    742     javascript << L"null";
    743   }
    744   javascript << L", ";
    745   javascript << L"\"";
    746 
    747   if (m_pExp1 && m_pExp1->GetOperatorToken() == TOKidentifier)
    748     javascript << tempExp1;
    749   javascript << L"\", ";
    750   if (m_op == TOKdotscream) {
    751     javascript << L"\"#";
    752     javascript << m_wsIdentifier;
    753     javascript << L"\", ";
    754   } else if (m_op == TOKdotstar) {
    755     javascript << L"\"*\", ";
    756   } else if (m_op == TOKcall) {
    757     javascript << L"\"\", ";
    758   } else {
    759     javascript << L"\"";
    760     javascript << m_wsIdentifier;
    761     javascript << L"\", ";
    762   }
    763   if (!m_pExp2->ToJavaScript(javascript))
    764     return false;
    765   javascript << L")";
    766   return !CXFA_IsTooBig(javascript);
    767 }
    768 
    769 CXFA_FMIndexExpression::CXFA_FMIndexExpression(
    770     uint32_t line,
    771     XFA_FM_AccessorIndex accessorIndex,
    772     std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp,
    773     bool bIsStarIndex)
    774     : CXFA_FMUnaryExpression(line, TOKlbracket, std::move(pIndexExp)),
    775       m_accessorIndex(accessorIndex),
    776       m_bIsStarIndex(bIsStarIndex) {}
    777 
    778 bool CXFA_FMIndexExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
    779   CXFA_FMToJavaScriptDepth depthManager;
    780   if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
    781     return false;
    782 
    783   switch (m_accessorIndex) {
    784     case ACCESSOR_NO_INDEX:
    785       javascript << L"0";
    786       break;
    787     case ACCESSOR_NO_RELATIVEINDEX:
    788       javascript << L"1";
    789       break;
    790     case ACCESSOR_POSITIVE_INDEX:
    791       javascript << L"2";
    792       break;
    793     case ACCESSOR_NEGATIVE_INDEX:
    794       javascript << L"3";
    795       break;
    796     default:
    797       javascript << L"0";
    798   }
    799   if (!m_bIsStarIndex) {
    800     javascript << L", ";
    801     if (m_pExp) {
    802       if (!m_pExp->ToJavaScript(javascript))
    803         return false;
    804     } else {
    805       javascript << L"0";
    806     }
    807   }
    808   return !CXFA_IsTooBig(javascript);
    809 }
    810 
    811 CXFA_FMDotDotAccessorExpression::CXFA_FMDotDotAccessorExpression(
    812     uint32_t line,
    813     std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
    814     XFA_FM_TOKEN op,
    815     WideStringView wsIdentifier,
    816     std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp)
    817     : CXFA_FMBinExpression(line,
    818                            op,
    819                            std::move(pAccessor),
    820                            std::move(pIndexExp)),
    821       m_wsIdentifier(wsIdentifier) {}
    822 
    823 CXFA_FMDotDotAccessorExpression::~CXFA_FMDotDotAccessorExpression() {}
    824 
    825 bool CXFA_FMDotDotAccessorExpression::ToJavaScript(
    826     CFX_WideTextBuf& javascript) {
    827   CXFA_FMToJavaScriptDepth depthManager;
    828   if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
    829     return false;
    830 
    831   javascript << gs_lpStrExpFuncName[DOTDOT];
    832   javascript << L"(";
    833   CFX_WideTextBuf tempExp1;
    834   if (!m_pExp1->ToJavaScript(tempExp1))
    835     return false;
    836   javascript << tempExp1;
    837   javascript << L", ";
    838   javascript << L"\"";
    839 
    840   if (m_pExp1->GetOperatorToken() == TOKidentifier)
    841     javascript << tempExp1;
    842   javascript << L"\", ";
    843   javascript << L"\"";
    844   javascript << m_wsIdentifier;
    845   javascript << L"\", ";
    846   if (!m_pExp2->ToJavaScript(javascript))
    847     return false;
    848   javascript << L")";
    849   return !CXFA_IsTooBig(javascript);
    850 }
    851 
    852 CXFA_FMMethodCallExpression::CXFA_FMMethodCallExpression(
    853     uint32_t line,
    854     std::unique_ptr<CXFA_FMSimpleExpression> pAccessorExp1,
    855     std::unique_ptr<CXFA_FMSimpleExpression> pCallExp)
    856     : CXFA_FMBinExpression(line,
    857                            TOKdot,
    858                            std::move(pAccessorExp1),
    859                            std::move(pCallExp)) {}
    860 
    861 bool CXFA_FMMethodCallExpression::ToJavaScript(CFX_WideTextBuf& javascript) {
    862   CXFA_FMToJavaScriptDepth depthManager;
    863   if (CXFA_IsTooBig(javascript) || !depthManager.IsWithinMaxDepth())
    864     return false;
    865 
    866   javascript << L"(\nfunction ()\n{\n";
    867   javascript << L"var method_return_value = null;\n";
    868   javascript << L"var accessor_object = ";
    869   if (!m_pExp1->ToJavaScript(javascript))
    870     return false;
    871   javascript << L";\n";
    872   javascript << L"if (";
    873   javascript << gs_lpStrExpFuncName[ISFMARRAY];
    874   javascript << L"(accessor_object))\n{\n";
    875   javascript << L"for(var index = accessor_object.length - 1; index > 1; "
    876                 L"index--)\n{\n";
    877   javascript << L"method_return_value = accessor_object[index].";
    878 
    879   CFX_WideTextBuf tempExp2;
    880   if (!m_pExp2->ToJavaScript(tempExp2))
    881     return false;
    882   javascript << tempExp2;
    883   javascript << L";\n}\n}\n";
    884   javascript << L"else\n{\nmethod_return_value = accessor_object.";
    885   javascript << tempExp2;
    886   javascript << L";\n}\n";
    887   javascript << L"return method_return_value;\n";
    888   javascript << L"}\n).call(this)";
    889   return !CXFA_IsTooBig(javascript);
    890 }
    891 
    892 bool CXFA_IsTooBig(const CFX_WideTextBuf& javascript) {
    893   return javascript.GetSize() >= 256 * 1024 * 1024;
    894 }
    895