Home | History | Annotate | Download | only in xfa
      1 // Copyright 2017 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 "fxjs/xfa/cjx_tree.h"
      8 
      9 #include <vector>
     10 
     11 #include "fxjs/cfxjse_engine.h"
     12 #include "fxjs/cfxjse_value.h"
     13 #include "fxjs/js_resources.h"
     14 #include "third_party/base/ptr_util.h"
     15 #include "xfa/fxfa/parser/cxfa_arraynodelist.h"
     16 #include "xfa/fxfa/parser/cxfa_attachnodelist.h"
     17 #include "xfa/fxfa/parser/cxfa_document.h"
     18 #include "xfa/fxfa/parser/cxfa_node.h"
     19 #include "xfa/fxfa/parser/cxfa_object.h"
     20 #include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
     21 
     22 const CJX_MethodSpec CJX_Tree::MethodSpecs[] = {
     23     {"resolveNode", resolveNode_static},
     24     {"resolveNodes", resolveNodes_static}};
     25 
     26 CJX_Tree::CJX_Tree(CXFA_Object* obj) : CJX_Object(obj) {
     27   DefineMethods(MethodSpecs, FX_ArraySize(MethodSpecs));
     28 }
     29 
     30 CJX_Tree::~CJX_Tree() {}
     31 
     32 CJS_Return CJX_Tree::resolveNode(
     33     CJS_V8* runtime,
     34     const std::vector<v8::Local<v8::Value>>& params) {
     35   if (params.size() != 1)
     36     return CJS_Return(JSGetStringFromID(JSMessage::kParamError));
     37 
     38   WideString expression = runtime->ToWideString(params[0]);
     39   CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext();
     40   if (!pScriptContext)
     41     return CJS_Return(true);
     42 
     43   CXFA_Object* refNode = GetXFAObject();
     44   if (refNode->GetElementType() == XFA_Element::Xfa)
     45     refNode = pScriptContext->GetThisObject();
     46 
     47   uint32_t dwFlag = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Attributes |
     48                     XFA_RESOLVENODE_Properties | XFA_RESOLVENODE_Parent |
     49                     XFA_RESOLVENODE_Siblings;
     50   XFA_RESOLVENODE_RS resolveNodeRS;
     51   if (!pScriptContext->ResolveObjects(ToNode(refNode),
     52                                       expression.AsStringView(), &resolveNodeRS,
     53                                       dwFlag, nullptr)) {
     54     return CJS_Return(runtime->NewNull());
     55   }
     56 
     57   if (resolveNodeRS.dwFlags == XFA_ResolveNode_RSType_Nodes) {
     58     CXFA_Object* pObject = resolveNodeRS.objects.front();
     59     CFXJSE_Value* value =
     60         GetDocument()->GetScriptContext()->GetJSValueFromMap(pObject);
     61     if (!value)
     62       return CJS_Return(runtime->NewNull());
     63 
     64     return CJS_Return(value->DirectGetValue().Get(runtime->GetIsolate()));
     65   }
     66 
     67   const XFA_SCRIPTATTRIBUTEINFO* lpAttributeInfo =
     68       resolveNodeRS.pScriptAttribute;
     69   if (!lpAttributeInfo ||
     70       lpAttributeInfo->eValueType != XFA_ScriptType::Object) {
     71     return CJS_Return(runtime->NewNull());
     72   }
     73 
     74   auto pValue = pdfium::MakeUnique<CFXJSE_Value>(pScriptContext->GetIsolate());
     75   CJX_Object* jsObject = resolveNodeRS.objects.front()->JSObject();
     76   (jsObject->*(lpAttributeInfo->callback))(pValue.get(), false,
     77                                            lpAttributeInfo->attribute);
     78   return CJS_Return(pValue->DirectGetValue().Get(runtime->GetIsolate()));
     79 }
     80 
     81 CJS_Return CJX_Tree::resolveNodes(
     82     CJS_V8* runtime,
     83     const std::vector<v8::Local<v8::Value>>& params) {
     84   if (params.size() != 1)
     85     return CJS_Return(JSGetStringFromID(JSMessage::kParamError));
     86 
     87   CXFA_Object* refNode = GetXFAObject();
     88   if (refNode->GetElementType() == XFA_Element::Xfa)
     89     refNode = GetDocument()->GetScriptContext()->GetThisObject();
     90 
     91   CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext();
     92   if (!pScriptContext)
     93     return CJS_Return(true);
     94 
     95   auto pValue = pdfium::MakeUnique<CFXJSE_Value>(pScriptContext->GetIsolate());
     96   ResolveNodeList(pValue.get(), runtime->ToWideString(params[0]),
     97                   XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Attributes |
     98                       XFA_RESOLVENODE_Properties | XFA_RESOLVENODE_Parent |
     99                       XFA_RESOLVENODE_Siblings,
    100                   ToNode(refNode));
    101   return CJS_Return(pValue->DirectGetValue().Get(runtime->GetIsolate()));
    102 }
    103 
    104 void CJX_Tree::all(CFXJSE_Value* pValue,
    105                    bool bSetting,
    106                    XFA_Attribute eAttribute) {
    107   if (bSetting) {
    108     ThrowInvalidPropertyException();
    109     return;
    110   }
    111 
    112   uint32_t dwFlag = XFA_RESOLVENODE_Siblings | XFA_RESOLVENODE_ALL;
    113   WideString wsExpression = GetAttribute(XFA_Attribute::Name) + L"[*]";
    114   ResolveNodeList(pValue, wsExpression, dwFlag, nullptr);
    115 }
    116 
    117 void CJX_Tree::classAll(CFXJSE_Value* pValue,
    118                         bool bSetting,
    119                         XFA_Attribute eAttribute) {
    120   if (bSetting) {
    121     ThrowInvalidPropertyException();
    122     return;
    123   }
    124 
    125   WideString wsExpression = L"#" + GetXFAObject()->GetClassName() + L"[*]";
    126   ResolveNodeList(pValue, wsExpression,
    127                   XFA_RESOLVENODE_Siblings | XFA_RESOLVENODE_ALL, nullptr);
    128 }
    129 
    130 void CJX_Tree::name(CFXJSE_Value* pValue,
    131                     bool bSetting,
    132                     XFA_Attribute eAttribute) {
    133   Script_Attribute_String(pValue, bSetting, eAttribute);
    134 }
    135 
    136 void CJX_Tree::nodes(CFXJSE_Value* pValue,
    137                      bool bSetting,
    138                      XFA_Attribute eAttribute) {
    139   CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext();
    140   if (!pScriptContext)
    141     return;
    142 
    143   if (bSetting) {
    144     WideString wsMessage = L"Unable to set ";
    145     FXJSE_ThrowMessage(wsMessage.UTF8Encode().AsStringView());
    146     return;
    147   }
    148 
    149   CXFA_AttachNodeList* pNodeList =
    150       new CXFA_AttachNodeList(GetDocument(), ToNode(GetXFAObject()));
    151   pValue->SetObject(pNodeList, pScriptContext->GetJseNormalClass());
    152 }
    153 
    154 void CJX_Tree::parent(CFXJSE_Value* pValue,
    155                       bool bSetting,
    156                       XFA_Attribute eAttribute) {
    157   if (bSetting) {
    158     ThrowInvalidPropertyException();
    159     return;
    160   }
    161 
    162   CXFA_Node* pParent = ToNode(GetXFAObject())->GetParent();
    163   if (!pParent) {
    164     pValue->SetNull();
    165     return;
    166   }
    167 
    168   pValue->Assign(GetDocument()->GetScriptContext()->GetJSValueFromMap(pParent));
    169 }
    170 
    171 void CJX_Tree::index(CFXJSE_Value* pValue,
    172                      bool bSetting,
    173                      XFA_Attribute eAttribute) {
    174   if (bSetting) {
    175     ThrowInvalidPropertyException();
    176     return;
    177   }
    178   pValue->SetInteger(ToNode(GetXFAObject())->GetNodeSameNameIndex());
    179 }
    180 
    181 void CJX_Tree::classIndex(CFXJSE_Value* pValue,
    182                           bool bSetting,
    183                           XFA_Attribute eAttribute) {
    184   if (bSetting) {
    185     ThrowInvalidPropertyException();
    186     return;
    187   }
    188   pValue->SetInteger(ToNode(GetXFAObject())->GetNodeSameClassIndex());
    189 }
    190 
    191 void CJX_Tree::somExpression(CFXJSE_Value* pValue,
    192                              bool bSetting,
    193                              XFA_Attribute eAttribute) {
    194   if (bSetting) {
    195     ThrowInvalidPropertyException();
    196     return;
    197   }
    198 
    199   WideString wsSOMExpression = GetXFAObject()->GetSOMExpression();
    200   pValue->SetString(wsSOMExpression.UTF8Encode().AsStringView());
    201 }
    202 
    203 void CJX_Tree::ResolveNodeList(CFXJSE_Value* pValue,
    204                                WideString wsExpression,
    205                                uint32_t dwFlag,
    206                                CXFA_Node* refNode) {
    207   CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext();
    208   if (!pScriptContext)
    209     return;
    210   if (!refNode)
    211     refNode = ToNode(GetXFAObject());
    212 
    213   XFA_RESOLVENODE_RS resolveNodeRS;
    214   pScriptContext->ResolveObjects(refNode, wsExpression.AsStringView(),
    215                                  &resolveNodeRS, dwFlag, nullptr);
    216   CXFA_ArrayNodeList* pNodeList = new CXFA_ArrayNodeList(GetDocument());
    217   if (resolveNodeRS.dwFlags == XFA_ResolveNode_RSType_Nodes) {
    218     for (CXFA_Object* pObject : resolveNodeRS.objects) {
    219       if (pObject->IsNode())
    220         pNodeList->Append(pObject->AsNode());
    221     }
    222   } else {
    223     if (resolveNodeRS.pScriptAttribute &&
    224         resolveNodeRS.pScriptAttribute->eValueType == XFA_ScriptType::Object) {
    225       for (CXFA_Object* pObject : resolveNodeRS.objects) {
    226         auto pValue =
    227             pdfium::MakeUnique<CFXJSE_Value>(pScriptContext->GetIsolate());
    228         CJX_Object* jsObject = pObject->JSObject();
    229         (jsObject->*(resolveNodeRS.pScriptAttribute->callback))(
    230             pValue.get(), false, resolveNodeRS.pScriptAttribute->attribute);
    231 
    232         CXFA_Object* obj = CFXJSE_Engine::ToObject(pValue.get(), nullptr);
    233         if (obj->IsNode())
    234           pNodeList->Append(obj->AsNode());
    235       }
    236     }
    237   }
    238   pValue->SetObject(pNodeList, pScriptContext->GetJseNormalClass());
    239 }
    240