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