You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
428 lines
13 KiB
428 lines
13 KiB
// 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/parser/cxfa_nodehelper.h" |
|
|
|
#include "core/fxcrt/fx_ext.h" |
|
#include "xfa/fxfa/parser/cxfa_document.h" |
|
#include "xfa/fxfa/parser/cxfa_scriptcontext.h" |
|
#include "xfa/fxfa/parser/xfa_localemgr.h" |
|
#include "xfa/fxfa/parser/xfa_object.h" |
|
#include "xfa/fxfa/parser/xfa_resolvenode_rs.h" |
|
#include "xfa/fxfa/parser/xfa_utils.h" |
|
|
|
CXFA_NodeHelper::CXFA_NodeHelper() |
|
: m_eLastCreateType(XFA_Element::DataValue), |
|
m_pCreateParent(nullptr), |
|
m_iCreateCount(0), |
|
m_iCreateFlag(XFA_RESOLVENODE_RSTYPE_CreateNodeOne), |
|
m_iCurAllStart(-1), |
|
m_pAllStartParent(nullptr) {} |
|
|
|
CXFA_NodeHelper::~CXFA_NodeHelper() {} |
|
|
|
CXFA_Node* CXFA_NodeHelper::ResolveNodes_GetOneChild(CXFA_Node* parent, |
|
const FX_WCHAR* pwsName, |
|
bool bIsClassName) { |
|
if (!parent) { |
|
return nullptr; |
|
} |
|
CXFA_NodeArray siblings; |
|
uint32_t uNameHash = FX_HashCode_GetW(CFX_WideStringC(pwsName), false); |
|
NodeAcc_TraverseAnySiblings(parent, uNameHash, &siblings, bIsClassName); |
|
if (siblings.GetSize() == 0) { |
|
return nullptr; |
|
} |
|
return siblings[0]; |
|
} |
|
|
|
int32_t CXFA_NodeHelper::CountSiblings(CXFA_Node* pNode, |
|
XFA_LOGIC_TYPE eLogicType, |
|
CXFA_NodeArray* pSiblings, |
|
bool bIsClassName) { |
|
if (!pNode) |
|
return 0; |
|
CXFA_Node* parent = ResolveNodes_GetParent(pNode, XFA_LOGIC_NoTransparent); |
|
if (!parent) |
|
return 0; |
|
const XFA_PROPERTY* pProperty = XFA_GetPropertyOfElement( |
|
parent->GetElementType(), pNode->GetElementType(), XFA_XDPPACKET_UNKNOWN); |
|
if (!pProperty && eLogicType == XFA_LOGIC_Transparent) { |
|
parent = ResolveNodes_GetParent(pNode, XFA_LOGIC_Transparent); |
|
if (!parent) { |
|
return 0; |
|
} |
|
} |
|
if (bIsClassName) { |
|
return NodeAcc_TraverseSiblings(parent, pNode->GetClassHashCode(), |
|
pSiblings, eLogicType, bIsClassName); |
|
} else { |
|
return NodeAcc_TraverseSiblings(parent, pNode->GetNameHash(), pSiblings, |
|
eLogicType, bIsClassName); |
|
} |
|
} |
|
|
|
int32_t CXFA_NodeHelper::NodeAcc_TraverseAnySiblings(CXFA_Node* parent, |
|
uint32_t dNameHash, |
|
CXFA_NodeArray* pSiblings, |
|
bool bIsClassName) { |
|
if (!parent || !pSiblings) { |
|
return 0; |
|
} |
|
int32_t nCount = 0; |
|
int32_t i = 0; |
|
CXFA_NodeArray properties; |
|
parent->GetNodeList(properties, XFA_NODEFILTER_Properties); |
|
int32_t nProperties = properties.GetSize(); |
|
for (i = 0; i < nProperties; ++i) { |
|
CXFA_Node* child = properties[i]; |
|
if (bIsClassName) { |
|
if (child->GetClassHashCode() == dNameHash) { |
|
pSiblings->Add(child); |
|
nCount++; |
|
} |
|
} else { |
|
if (child->GetNameHash() == dNameHash) { |
|
pSiblings->Add(child); |
|
nCount++; |
|
} |
|
} |
|
if (nCount > 0) { |
|
return nCount; |
|
} |
|
nCount += |
|
NodeAcc_TraverseAnySiblings(child, dNameHash, pSiblings, bIsClassName); |
|
} |
|
CXFA_NodeArray children; |
|
parent->GetNodeList(children, XFA_NODEFILTER_Children); |
|
int32_t nChildren = children.GetSize(); |
|
for (i = 0; i < nChildren; i++) { |
|
CXFA_Node* child = children[i]; |
|
if (bIsClassName) { |
|
if (child->GetClassHashCode() == dNameHash) { |
|
if (pSiblings) { |
|
pSiblings->Add(child); |
|
} |
|
nCount++; |
|
} |
|
} else { |
|
if (child->GetNameHash() == dNameHash) { |
|
if (pSiblings) { |
|
pSiblings->Add(child); |
|
} |
|
nCount++; |
|
} |
|
} |
|
if (nCount > 0) { |
|
return nCount; |
|
} |
|
nCount += |
|
NodeAcc_TraverseAnySiblings(child, dNameHash, pSiblings, bIsClassName); |
|
} |
|
return nCount; |
|
} |
|
|
|
int32_t CXFA_NodeHelper::NodeAcc_TraverseSiblings(CXFA_Node* parent, |
|
uint32_t dNameHash, |
|
CXFA_NodeArray* pSiblings, |
|
XFA_LOGIC_TYPE eLogicType, |
|
bool bIsClassName, |
|
bool bIsFindProperty) { |
|
if (!parent || !pSiblings) { |
|
return 0; |
|
} |
|
int32_t nCount = 0; |
|
int32_t i = 0; |
|
if (bIsFindProperty) { |
|
CXFA_NodeArray properties; |
|
parent->GetNodeList(properties, XFA_NODEFILTER_Properties); |
|
int32_t nProperties = properties.GetSize(); |
|
for (i = 0; i < nProperties; ++i) { |
|
CXFA_Node* child = properties[i]; |
|
if (bIsClassName) { |
|
if (child->GetClassHashCode() == dNameHash) { |
|
pSiblings->Add(child); |
|
nCount++; |
|
} |
|
} else { |
|
if (child->GetNameHash() == dNameHash) { |
|
if (child->GetElementType() != XFA_Element::PageSet && |
|
child->GetElementType() != XFA_Element::Extras && |
|
child->GetElementType() != XFA_Element::Items) { |
|
pSiblings->Add(child); |
|
nCount++; |
|
} |
|
} |
|
} |
|
if (child->IsUnnamed() && |
|
child->GetElementType() == XFA_Element::PageSet) { |
|
nCount += NodeAcc_TraverseSiblings(child, dNameHash, pSiblings, |
|
eLogicType, bIsClassName, false); |
|
} |
|
} |
|
if (nCount > 0) { |
|
return nCount; |
|
} |
|
} |
|
CXFA_NodeArray children; |
|
parent->GetNodeList(children, XFA_NODEFILTER_Children); |
|
int32_t nChildren = children.GetSize(); |
|
for (i = 0; i < nChildren; i++) { |
|
CXFA_Node* child = children[i]; |
|
if (child->GetElementType() == XFA_Element::Variables) { |
|
continue; |
|
} |
|
if (bIsClassName) { |
|
if (child->GetClassHashCode() == dNameHash) { |
|
if (pSiblings) { |
|
pSiblings->Add(child); |
|
} |
|
nCount++; |
|
} |
|
} else { |
|
if (child->GetNameHash() == dNameHash) { |
|
if (pSiblings) { |
|
pSiblings->Add(child); |
|
} |
|
nCount++; |
|
} |
|
} |
|
if (eLogicType == XFA_LOGIC_NoTransparent) { |
|
continue; |
|
} |
|
if (NodeIsTransparent(child) && |
|
child->GetElementType() != XFA_Element::PageSet) { |
|
nCount += NodeAcc_TraverseSiblings(child, dNameHash, pSiblings, |
|
eLogicType, bIsClassName, false); |
|
} |
|
} |
|
return nCount; |
|
} |
|
|
|
CXFA_Node* CXFA_NodeHelper::ResolveNodes_GetParent(CXFA_Node* pNode, |
|
XFA_LOGIC_TYPE eLogicType) { |
|
if (!pNode) { |
|
return nullptr; |
|
} |
|
if (eLogicType == XFA_LOGIC_NoTransparent) { |
|
return pNode->GetNodeItem(XFA_NODEITEM_Parent); |
|
} |
|
CXFA_Node* parent; |
|
CXFA_Node* node = pNode; |
|
while (true) { |
|
parent = ResolveNodes_GetParent(node); |
|
if (!parent) { |
|
break; |
|
} |
|
XFA_Element parentType = parent->GetElementType(); |
|
if ((!parent->IsUnnamed() && parentType != XFA_Element::SubformSet) || |
|
parentType == XFA_Element::Variables) { |
|
break; |
|
} |
|
node = parent; |
|
} |
|
return parent; |
|
} |
|
|
|
int32_t CXFA_NodeHelper::GetIndex(CXFA_Node* pNode, |
|
XFA_LOGIC_TYPE eLogicType, |
|
bool bIsProperty, |
|
bool bIsClassIndex) { |
|
CXFA_Node* parent = ResolveNodes_GetParent(pNode, XFA_LOGIC_NoTransparent); |
|
if (!parent) { |
|
return 0; |
|
} |
|
if (!bIsProperty && eLogicType == XFA_LOGIC_Transparent) { |
|
parent = ResolveNodes_GetParent(pNode, XFA_LOGIC_Transparent); |
|
if (!parent) { |
|
return 0; |
|
} |
|
} |
|
uint32_t dwHashName = pNode->GetNameHash(); |
|
if (bIsClassIndex) { |
|
dwHashName = pNode->GetClassHashCode(); |
|
} |
|
CXFA_NodeArray siblings; |
|
int32_t iSize = NodeAcc_TraverseSiblings(parent, dwHashName, &siblings, |
|
eLogicType, bIsClassIndex); |
|
for (int32_t i = 0; i < iSize; ++i) { |
|
CXFA_Node* child = siblings[i]; |
|
if (child == pNode) { |
|
return i; |
|
} |
|
} |
|
return 0; |
|
} |
|
|
|
void CXFA_NodeHelper::GetNameExpression(CXFA_Node* refNode, |
|
CFX_WideString& wsName, |
|
bool bIsAllPath, |
|
XFA_LOGIC_TYPE eLogicType) { |
|
wsName.clear(); |
|
if (bIsAllPath) { |
|
GetNameExpression(refNode, wsName, false, eLogicType); |
|
CFX_WideString wsParent; |
|
CXFA_Node* parent = |
|
ResolveNodes_GetParent(refNode, XFA_LOGIC_NoTransparent); |
|
while (parent) { |
|
GetNameExpression(parent, wsParent, false, eLogicType); |
|
wsParent += L"."; |
|
wsParent += wsName; |
|
wsName = wsParent; |
|
parent = ResolveNodes_GetParent(parent, XFA_LOGIC_NoTransparent); |
|
} |
|
return; |
|
} |
|
|
|
CFX_WideString ws; |
|
bool bIsProperty = NodeIsProperty(refNode); |
|
if (refNode->IsUnnamed() || |
|
(bIsProperty && refNode->GetElementType() != XFA_Element::PageSet)) { |
|
ws = refNode->GetClassName(); |
|
wsName.Format(L"#%s[%d]", ws.c_str(), |
|
GetIndex(refNode, eLogicType, bIsProperty, true)); |
|
return; |
|
} |
|
ws = refNode->GetCData(XFA_ATTRIBUTE_Name); |
|
ws.Replace(L".", L"\\."); |
|
wsName.Format(L"%s[%d]", ws.c_str(), |
|
GetIndex(refNode, eLogicType, bIsProperty, false)); |
|
} |
|
|
|
bool CXFA_NodeHelper::NodeIsTransparent(CXFA_Node* refNode) { |
|
if (!refNode) { |
|
return false; |
|
} |
|
XFA_Element refNodeType = refNode->GetElementType(); |
|
if ((refNode->IsUnnamed() && refNode->IsContainerNode()) || |
|
refNodeType == XFA_Element::SubformSet || |
|
refNodeType == XFA_Element::Area || refNodeType == XFA_Element::Proto) { |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
bool CXFA_NodeHelper::CreateNode_ForCondition(CFX_WideString& wsCondition) { |
|
int32_t iLen = wsCondition.GetLength(); |
|
CFX_WideString wsIndex(L"0"); |
|
bool bAll = false; |
|
if (iLen == 0) { |
|
m_iCreateFlag = XFA_RESOLVENODE_RSTYPE_CreateNodeOne; |
|
return false; |
|
} |
|
if (wsCondition.GetAt(0) == '[') { |
|
int32_t i = 1; |
|
for (; i < iLen; ++i) { |
|
FX_WCHAR ch = wsCondition[i]; |
|
if (ch == ' ') { |
|
continue; |
|
} |
|
if (ch == '+' || ch == '-') { |
|
break; |
|
} else if (ch == '*') { |
|
bAll = true; |
|
break; |
|
} else { |
|
break; |
|
} |
|
} |
|
if (bAll) { |
|
wsIndex = L"1"; |
|
m_iCreateFlag = XFA_RESOLVENODE_RSTYPE_CreateNodeAll; |
|
} else { |
|
m_iCreateFlag = XFA_RESOLVENODE_RSTYPE_CreateNodeOne; |
|
wsIndex = wsCondition.Mid(i, iLen - 1 - i); |
|
} |
|
int32_t iIndex = wsIndex.GetInteger(); |
|
m_iCreateCount = iIndex; |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
bool CXFA_NodeHelper::ResolveNodes_CreateNode( |
|
CFX_WideString wsName, |
|
CFX_WideString wsCondition, |
|
bool bLastNode, |
|
CXFA_ScriptContext* pScriptContext) { |
|
if (!m_pCreateParent) { |
|
return false; |
|
} |
|
bool bIsClassName = false; |
|
bool bResult = false; |
|
if (wsName.GetAt(0) == '!') { |
|
wsName = wsName.Right(wsName.GetLength() - 1); |
|
m_pCreateParent = ToNode( |
|
pScriptContext->GetDocument()->GetXFAObject(XFA_HASHCODE_Datasets)); |
|
} |
|
if (wsName.GetAt(0) == '#') { |
|
bIsClassName = true; |
|
wsName = wsName.Right(wsName.GetLength() - 1); |
|
} |
|
if (m_iCreateCount == 0) { |
|
CreateNode_ForCondition(wsCondition); |
|
} |
|
if (bIsClassName) { |
|
XFA_Element eType = XFA_GetElementTypeForName(wsName.AsStringC()); |
|
if (eType == XFA_Element::Unknown) |
|
return false; |
|
|
|
for (int32_t iIndex = 0; iIndex < m_iCreateCount; iIndex++) { |
|
CXFA_Node* pNewNode = m_pCreateParent->CreateSamePacketNode(eType); |
|
if (pNewNode) { |
|
m_pCreateParent->InsertChild(pNewNode); |
|
if (iIndex == m_iCreateCount - 1) { |
|
m_pCreateParent = pNewNode; |
|
} |
|
bResult = true; |
|
} |
|
} |
|
} else { |
|
XFA_Element eClassType = XFA_Element::DataGroup; |
|
if (bLastNode) { |
|
eClassType = m_eLastCreateType; |
|
} |
|
for (int32_t iIndex = 0; iIndex < m_iCreateCount; iIndex++) { |
|
CXFA_Node* pNewNode = m_pCreateParent->CreateSamePacketNode(eClassType); |
|
if (pNewNode) { |
|
pNewNode->SetAttribute(XFA_ATTRIBUTE_Name, wsName.AsStringC()); |
|
pNewNode->CreateXMLMappingNode(); |
|
m_pCreateParent->InsertChild(pNewNode); |
|
if (iIndex == m_iCreateCount - 1) { |
|
m_pCreateParent = pNewNode; |
|
} |
|
bResult = true; |
|
} |
|
} |
|
} |
|
if (!bResult) { |
|
m_pCreateParent = nullptr; |
|
} |
|
return bResult; |
|
} |
|
|
|
void CXFA_NodeHelper::SetCreateNodeType(CXFA_Node* refNode) { |
|
if (!refNode) { |
|
return; |
|
} |
|
if (refNode->GetElementType() == XFA_Element::Subform) { |
|
m_eLastCreateType = XFA_Element::DataGroup; |
|
} else if (refNode->GetElementType() == XFA_Element::Field) { |
|
m_eLastCreateType = XFA_FieldIsMultiListBox(refNode) |
|
? XFA_Element::DataGroup |
|
: XFA_Element::DataValue; |
|
} else if (refNode->GetElementType() == XFA_Element::ExclGroup) { |
|
m_eLastCreateType = XFA_Element::DataValue; |
|
} |
|
} |
|
|
|
bool CXFA_NodeHelper::NodeIsProperty(CXFA_Node* refNode) { |
|
CXFA_Node* parent = ResolveNodes_GetParent(refNode, XFA_LOGIC_NoTransparent); |
|
return parent && refNode && |
|
XFA_GetPropertyOfElement(parent->GetElementType(), |
|
refNode->GetElementType(), |
|
XFA_XDPPACKET_UNKNOWN); |
|
}
|
|
|