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 "fxjs/xfa/cfxjse_resolveprocessor.h"
8 
9 #include <algorithm>
10 #include <utility>
11 #include <vector>
12 
13 #include "core/fxcrt/fx_extension.h"
14 #include "fxjs/xfa/cfxjse_engine.h"
15 #include "fxjs/xfa/cfxjse_value.h"
16 #include "fxjs/xfa/cjx_object.h"
17 #include "third_party/base/ptr_util.h"
18 #include "third_party/base/stl_util.h"
19 #include "xfa/fxfa/parser/cxfa_document.h"
20 #include "xfa/fxfa/parser/cxfa_localemgr.h"
21 #include "xfa/fxfa/parser/cxfa_node.h"
22 #include "xfa/fxfa/parser/cxfa_nodehelper.h"
23 #include "xfa/fxfa/parser/cxfa_object.h"
24 #include "xfa/fxfa/parser/cxfa_occur.h"
25 #include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
26 #include "xfa/fxfa/parser/xfa_utils.h"
27 
28 namespace {
29 
DoPredicateFilter(WideString wsCondition,size_t iFoundCount,CFXJSE_ResolveNodeData * pRnd)30 void DoPredicateFilter(WideString wsCondition,
31                        size_t iFoundCount,
32                        CFXJSE_ResolveNodeData* pRnd) {
33   ASSERT(iFoundCount == pRnd->m_Objects.size());
34   WideString wsExpression;
35   CXFA_Script::Type eLangType = CXFA_Script::Type::Unknown;
36   if (wsCondition.First(2).EqualsASCII(".[") && wsCondition.Back() == L']')
37     eLangType = CXFA_Script::Type::Formcalc;
38   else if (wsCondition.First(2).EqualsASCII(".(") && wsCondition.Back() == L')')
39     eLangType = CXFA_Script::Type::Javascript;
40   else
41     return;
42 
43   wsExpression = wsCondition.Substr(2, wsCondition.GetLength() - 3);
44   for (size_t i = iFoundCount; i > 0; --i) {
45     auto pRetValue =
46         pdfium::MakeUnique<CFXJSE_Value>(pRnd->m_pSC->GetIsolate());
47     bool bRet =
48         pRnd->m_pSC->RunScript(eLangType, wsExpression.AsStringView(),
49                                pRetValue.get(), pRnd->m_Objects[i - 1].Get());
50     if (!bRet || !pRetValue->ToBoolean())
51       pRnd->m_Objects.erase(pRnd->m_Objects.begin() + i - 1);
52   }
53 }
54 
55 }  // namespace
56 
CFXJSE_ResolveProcessor()57 CFXJSE_ResolveProcessor::CFXJSE_ResolveProcessor()
58     : m_pNodeHelper(pdfium::MakeUnique<CXFA_NodeHelper>()) {}
59 
60 CFXJSE_ResolveProcessor::~CFXJSE_ResolveProcessor() = default;
61 
Resolve(CFXJSE_ResolveNodeData & rnd)62 bool CFXJSE_ResolveProcessor::Resolve(CFXJSE_ResolveNodeData& rnd) {
63   if (!rnd.m_CurObject)
64     return false;
65 
66   if (!rnd.m_CurObject->IsNode()) {
67     if (rnd.m_dwStyles & XFA_RESOLVENODE_Attributes) {
68       return ResolveForAttributeRs(rnd.m_CurObject.Get(), rnd,
69                                    rnd.m_wsName.AsStringView());
70     }
71     return false;
72   }
73   if (rnd.m_dwStyles & XFA_RESOLVENODE_AnyChild)
74     return ResolveAnyChild(rnd);
75 
76   if (rnd.m_wsName.GetLength()) {
77     wchar_t wch = rnd.m_wsName[0];
78     switch (wch) {
79       case '$':
80         return ResolveDollar(rnd);
81       case '!':
82         return ResolveExcalmatory(rnd);
83       case '#':
84         return ResolveNumberSign(rnd);
85       case '*':
86         return ResolveAsterisk(rnd);
87       // TODO(dsinclair): We could probably remove this.
88       case '.':
89         return ResolveAnyChild(rnd);
90       default:
91         break;
92     }
93   }
94   if (rnd.m_uHashName == XFA_HASHCODE_This && rnd.m_nLevel == 0) {
95     rnd.m_Objects.emplace_back(rnd.m_pSC->GetThisObject());
96     return true;
97   }
98   if (rnd.m_CurObject->GetElementType() == XFA_Element::Xfa) {
99     CXFA_Object* pObjNode =
100         rnd.m_pSC->GetDocument()->GetXFAObject(rnd.m_uHashName);
101     if (pObjNode) {
102       rnd.m_Objects.emplace_back(pObjNode);
103     } else if (rnd.m_uHashName == XFA_HASHCODE_Xfa) {
104       rnd.m_Objects.push_back(rnd.m_CurObject);
105     } else if ((rnd.m_dwStyles & XFA_RESOLVENODE_Attributes) &&
106                ResolveForAttributeRs(rnd.m_CurObject.Get(), rnd,
107                                      rnd.m_wsName.AsStringView())) {
108       return true;
109     }
110     if (!rnd.m_Objects.empty())
111       FilterCondition(rnd.m_wsCondition, &rnd);
112 
113     return !rnd.m_Objects.empty();
114   }
115   if (!ResolveNormal(rnd) && rnd.m_uHashName == XFA_HASHCODE_Xfa)
116     rnd.m_Objects.emplace_back(rnd.m_pSC->GetDocument()->GetRoot());
117 
118   return !rnd.m_Objects.empty();
119 }
120 
ResolveAnyChild(CFXJSE_ResolveNodeData & rnd)121 bool CFXJSE_ResolveProcessor::ResolveAnyChild(CFXJSE_ResolveNodeData& rnd) {
122   CXFA_Node* pParent = ToNode(rnd.m_CurObject.Get());
123   if (!pParent)
124     return false;
125 
126   WideStringView wsName = rnd.m_wsName.AsStringView();
127   WideString wsCondition = rnd.m_wsCondition;
128   const bool bClassName = !wsName.IsEmpty() && wsName[0] == '#';
129   CXFA_Node* const pChild =
130       bClassName
131           ? pParent->GetOneChildOfClass(wsName.Last(wsName.GetLength() - 1))
132           : pParent->GetOneChildNamed(wsName);
133   if (!pChild)
134     return false;
135 
136   if (wsCondition.IsEmpty()) {
137     rnd.m_Objects.emplace_back(pChild);
138     return true;
139   }
140 
141   std::vector<CXFA_Node*> nodes;
142   for (const auto& pObject : rnd.m_Objects)
143     nodes.push_back(pObject->AsNode());
144 
145   std::vector<CXFA_Node*> siblings = pChild->GetSiblings(bClassName);
146   nodes.insert(nodes.end(), siblings.begin(), siblings.end());
147   rnd.m_Objects =
148       std::vector<UnownedPtr<CXFA_Object>>(nodes.begin(), nodes.end());
149   FilterCondition(wsCondition, &rnd);
150   return !rnd.m_Objects.empty();
151 }
152 
ResolveDollar(CFXJSE_ResolveNodeData & rnd)153 bool CFXJSE_ResolveProcessor::ResolveDollar(CFXJSE_ResolveNodeData& rnd) {
154   WideString wsName = rnd.m_wsName;
155   WideString wsCondition = rnd.m_wsCondition;
156   int32_t iNameLen = wsName.GetLength();
157   if (iNameLen == 1) {
158     rnd.m_Objects.push_back(rnd.m_CurObject);
159     return true;
160   }
161   if (rnd.m_nLevel > 0)
162     return false;
163 
164   XFA_HashCode dwNameHash = static_cast<XFA_HashCode>(
165       FX_HashCode_GetW(wsName.AsStringView().Last(iNameLen - 1), false));
166   if (dwNameHash == XFA_HASHCODE_Xfa) {
167     rnd.m_Objects.emplace_back(rnd.m_pSC->GetDocument()->GetRoot());
168   } else {
169     CXFA_Object* pObjNode = rnd.m_pSC->GetDocument()->GetXFAObject(dwNameHash);
170     if (pObjNode)
171       rnd.m_Objects.emplace_back(pObjNode);
172   }
173   if (!rnd.m_Objects.empty())
174     FilterCondition(wsCondition, &rnd);
175   return !rnd.m_Objects.empty();
176 }
177 
ResolveExcalmatory(CFXJSE_ResolveNodeData & rnd)178 bool CFXJSE_ResolveProcessor::ResolveExcalmatory(CFXJSE_ResolveNodeData& rnd) {
179   if (rnd.m_nLevel > 0)
180     return false;
181 
182   CXFA_Node* datasets =
183       ToNode(rnd.m_pSC->GetDocument()->GetXFAObject(XFA_HASHCODE_Datasets));
184   if (!datasets)
185     return false;
186 
187   CFXJSE_ResolveNodeData rndFind(rnd.m_pSC.Get());
188   rndFind.m_CurObject = datasets;
189   rndFind.m_wsName = rnd.m_wsName.Last(rnd.m_wsName.GetLength() - 1);
190   rndFind.m_uHashName = static_cast<XFA_HashCode>(
191       FX_HashCode_GetW(rndFind.m_wsName.AsStringView(), false));
192   rndFind.m_nLevel = rnd.m_nLevel + 1;
193   rndFind.m_dwStyles = XFA_RESOLVENODE_Children;
194   rndFind.m_wsCondition = rnd.m_wsCondition;
195   Resolve(rndFind);
196 
197   rnd.m_Objects.insert(rnd.m_Objects.end(), rndFind.m_Objects.begin(),
198                        rndFind.m_Objects.end());
199   return !rnd.m_Objects.empty();
200 }
201 
ResolveNumberSign(CFXJSE_ResolveNodeData & rnd)202 bool CFXJSE_ResolveProcessor::ResolveNumberSign(CFXJSE_ResolveNodeData& rnd) {
203   WideString wsName = rnd.m_wsName.Last(rnd.m_wsName.GetLength() - 1);
204   WideString wsCondition = rnd.m_wsCondition;
205   CXFA_Node* curNode = ToNode(rnd.m_CurObject.Get());
206   if (ResolveForAttributeRs(curNode, rnd, wsName.AsStringView()))
207     return true;
208 
209   CFXJSE_ResolveNodeData rndFind(rnd.m_pSC.Get());
210   rndFind.m_nLevel = rnd.m_nLevel + 1;
211   rndFind.m_dwStyles = rnd.m_dwStyles;
212   rndFind.m_dwStyles |= XFA_RESOLVENODE_TagName;
213   rndFind.m_dwStyles &= ~XFA_RESOLVENODE_Attributes;
214   rndFind.m_wsName = std::move(wsName);
215   rndFind.m_uHashName = static_cast<XFA_HashCode>(
216       FX_HashCode_GetW(rndFind.m_wsName.AsStringView(), false));
217   rndFind.m_wsCondition = wsCondition;
218   rndFind.m_CurObject = curNode;
219   ResolveNormal(rndFind);
220   if (rndFind.m_Objects.empty())
221     return false;
222 
223   if (wsCondition.IsEmpty() &&
224       pdfium::ContainsValue(rndFind.m_Objects, curNode)) {
225     rnd.m_Objects.emplace_back(curNode);
226   } else {
227     rnd.m_Objects.insert(rnd.m_Objects.end(), rndFind.m_Objects.begin(),
228                          rndFind.m_Objects.end());
229   }
230   return !rnd.m_Objects.empty();
231 }
232 
ResolveForAttributeRs(CXFA_Object * curNode,CFXJSE_ResolveNodeData & rnd,WideStringView strAttr)233 bool CFXJSE_ResolveProcessor::ResolveForAttributeRs(CXFA_Object* curNode,
234                                                     CFXJSE_ResolveNodeData& rnd,
235                                                     WideStringView strAttr) {
236   Optional<XFA_SCRIPTATTRIBUTEINFO> info =
237       XFA_GetScriptAttributeByName(curNode->GetElementType(), strAttr);
238   if (!info.has_value())
239     return false;
240 
241   rnd.m_ScriptAttribute = info.value();
242   rnd.m_Objects.emplace_back(curNode);
243   rnd.m_dwFlag = XFA_ResolveNode_RSType_Attribute;
244   return true;
245 }
246 
ResolveNormal(CFXJSE_ResolveNodeData & rnd)247 bool CFXJSE_ResolveProcessor::ResolveNormal(CFXJSE_ResolveNodeData& rnd) {
248   if (rnd.m_nLevel > 32 || !rnd.m_CurObject->IsNode())
249     return false;
250 
251   CXFA_Node* curNode = rnd.m_CurObject->AsNode();
252   size_t nNum = rnd.m_Objects.size();
253   uint32_t dwStyles = rnd.m_dwStyles;
254   WideString& wsName = rnd.m_wsName;
255   XFA_HashCode uNameHash = rnd.m_uHashName;
256   WideString& wsCondition = rnd.m_wsCondition;
257 
258   CFXJSE_ResolveNodeData rndFind(rnd.m_pSC.Get());
259   rndFind.m_wsName = rnd.m_wsName;
260   rndFind.m_wsCondition = rnd.m_wsCondition;
261   rndFind.m_nLevel = rnd.m_nLevel + 1;
262   rndFind.m_uHashName = uNameHash;
263 
264   std::vector<CXFA_Node*> children;
265   std::vector<CXFA_Node*> properties;
266   CXFA_Node* pVariablesNode = nullptr;
267   CXFA_Node* pPageSetNode = nullptr;
268   for (CXFA_Node* pChild = curNode->GetFirstChild(); pChild;
269        pChild = pChild->GetNextSibling()) {
270     if (pChild->GetElementType() == XFA_Element::Variables) {
271       pVariablesNode = pChild;
272       continue;
273     }
274     if (pChild->GetElementType() == XFA_Element::PageSet) {
275       pPageSetNode = pChild;
276       continue;
277     }
278     if (curNode->HasProperty(pChild->GetElementType()))
279       properties.push_back(pChild);
280     else
281       children.push_back(pChild);
282   }
283   if ((dwStyles & XFA_RESOLVENODE_Properties) && pVariablesNode) {
284     if (pVariablesNode->GetClassHashCode() == uNameHash) {
285       rnd.m_Objects.emplace_back(pVariablesNode);
286     } else {
287       rndFind.m_CurObject = pVariablesNode;
288       SetStylesForChild(dwStyles, rndFind);
289       WideString wsSaveCondition = std::move(rndFind.m_wsCondition);
290       ResolveNormal(rndFind);
291       rndFind.m_wsCondition = std::move(wsSaveCondition);
292       rnd.m_Objects.insert(rnd.m_Objects.end(), rndFind.m_Objects.begin(),
293                            rndFind.m_Objects.end());
294       rndFind.m_Objects.clear();
295     }
296     if (rnd.m_Objects.size() > nNum) {
297       FilterCondition(wsCondition, &rnd);
298       return !rnd.m_Objects.empty();
299     }
300   }
301 
302   if (dwStyles & XFA_RESOLVENODE_Children) {
303     bool bSetFlag = false;
304     if (pPageSetNode && (dwStyles & XFA_RESOLVENODE_Properties))
305       children.push_back(pPageSetNode);
306 
307     for (CXFA_Node* child : children) {
308       if (dwStyles & XFA_RESOLVENODE_TagName) {
309         if (child->GetClassHashCode() == uNameHash)
310           rnd.m_Objects.emplace_back(child);
311       } else if (child->GetNameHash() == uNameHash) {
312         rnd.m_Objects.emplace_back(child);
313       }
314 
315       if (child->GetElementType() != XFA_Element::PageSet &&
316           child->IsTransparent()) {
317         if (!bSetFlag) {
318           SetStylesForChild(dwStyles, rndFind);
319           bSetFlag = true;
320         }
321         rndFind.m_CurObject = child;
322 
323         WideString wsSaveCondition = std::move(rndFind.m_wsCondition);
324         ResolveNormal(rndFind);
325         rndFind.m_wsCondition = std::move(wsSaveCondition);
326         rnd.m_Objects.insert(rnd.m_Objects.end(), rndFind.m_Objects.begin(),
327                              rndFind.m_Objects.end());
328         rndFind.m_Objects.clear();
329       }
330     }
331     if (rnd.m_Objects.size() > nNum) {
332       if (!(dwStyles & XFA_RESOLVENODE_ALL)) {
333         std::vector<CXFA_Node*> upArrayNodes;
334         if (curNode->IsTransparent()) {
335           CXFA_Node* pCurrent = ToNode(rnd.m_Objects.front().Get());
336           if (pCurrent) {
337             upArrayNodes =
338                 pCurrent->GetSiblings(!!(dwStyles & XFA_RESOLVENODE_TagName));
339           }
340         }
341         if (upArrayNodes.size() > rnd.m_Objects.size()) {
342           CXFA_Object* pSaveObject = rnd.m_Objects.front().Get();
343           rnd.m_Objects = std::vector<UnownedPtr<CXFA_Object>>(
344               upArrayNodes.begin(), upArrayNodes.end());
345           rnd.m_Objects.front() = pSaveObject;
346         }
347       }
348       FilterCondition(wsCondition, &rnd);
349       return !rnd.m_Objects.empty();
350     }
351   }
352   if (dwStyles & XFA_RESOLVENODE_Attributes) {
353     if (ResolveForAttributeRs(curNode, rnd, wsName.AsStringView()))
354       return 1;
355   }
356   if (dwStyles & XFA_RESOLVENODE_Properties) {
357     for (CXFA_Node* pChildProperty : properties) {
358       if (pChildProperty->IsUnnamed()) {
359         if (pChildProperty->GetClassHashCode() == uNameHash)
360           rnd.m_Objects.emplace_back(pChildProperty);
361         continue;
362       }
363       if (pChildProperty->GetNameHash() == uNameHash &&
364           pChildProperty->GetElementType() != XFA_Element::Extras &&
365           pChildProperty->GetElementType() != XFA_Element::Items) {
366         rnd.m_Objects.emplace_back(pChildProperty);
367       }
368     }
369     if (rnd.m_Objects.size() > nNum) {
370       FilterCondition(wsCondition, &rnd);
371       return !rnd.m_Objects.empty();
372     }
373 
374     CXFA_Node* pProp = nullptr;
375     if (XFA_Element::Subform == curNode->GetElementType() &&
376         XFA_HASHCODE_Occur == uNameHash) {
377       CXFA_Node* pInstanceManager = curNode->GetInstanceMgrOfSubform();
378       if (pInstanceManager) {
379         pProp = pInstanceManager->JSObject()->GetOrCreateProperty<CXFA_Occur>(
380             0, XFA_Element::Occur);
381       }
382     } else {
383       XFA_Element eType = XFA_GetElementByName(wsName.AsStringView());
384       if (eType == XFA_Element::PageSet) {
385         pProp = curNode->JSObject()->GetProperty<CXFA_Node>(0, eType);
386       } else if (eType != XFA_Element::Unknown) {
387         pProp = curNode->JSObject()->GetOrCreateProperty<CXFA_Node>(0, eType);
388       }
389     }
390     if (pProp) {
391       rnd.m_Objects.emplace_back(pProp);
392       return !rnd.m_Objects.empty();
393     }
394   }
395 
396   CXFA_Node* const parentNode = curNode->GetParent();
397   uint32_t uCurClassHash = curNode->GetClassHashCode();
398   if (!parentNode) {
399     if (uCurClassHash == uNameHash) {
400       rnd.m_Objects.emplace_back(curNode);
401       FilterCondition(wsCondition, &rnd);
402       if (!rnd.m_Objects.empty())
403         return true;
404     }
405     return false;
406   }
407 
408   if (dwStyles & XFA_RESOLVENODE_Siblings) {
409     CXFA_Node* child = parentNode->GetFirstChild();
410     uint32_t dwSubStyles =
411         XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties;
412     if (dwStyles & XFA_RESOLVENODE_TagName)
413       dwSubStyles |= XFA_RESOLVENODE_TagName;
414     if (dwStyles & XFA_RESOLVENODE_ALL)
415       dwSubStyles |= XFA_RESOLVENODE_ALL;
416 
417     rndFind.m_dwStyles = dwSubStyles;
418     while (child) {
419       if (child == curNode) {
420         if (dwStyles & XFA_RESOLVENODE_TagName) {
421           if (uCurClassHash == uNameHash)
422             rnd.m_Objects.emplace_back(curNode);
423         } else {
424           if (child->GetNameHash() == uNameHash) {
425             rnd.m_Objects.emplace_back(curNode);
426             if (rnd.m_nLevel == 0 && wsCondition.IsEmpty()) {
427               rnd.m_Objects.clear();
428               rnd.m_Objects.emplace_back(curNode);
429               return true;
430             }
431           }
432         }
433         child = child->GetNextSibling();
434         continue;
435       }
436 
437       if (dwStyles & XFA_RESOLVENODE_TagName) {
438         if (child->GetClassHashCode() == uNameHash)
439           rnd.m_Objects.emplace_back(child);
440       } else if (child->GetNameHash() == uNameHash) {
441         rnd.m_Objects.emplace_back(child);
442       }
443 
444       bool bInnerSearch = false;
445       if (parentNode->HasProperty(child->GetElementType())) {
446         if ((child->GetElementType() == XFA_Element::Variables ||
447              child->GetElementType() == XFA_Element::PageSet)) {
448           bInnerSearch = true;
449         }
450       } else if (child->IsTransparent()) {
451         bInnerSearch = true;
452       }
453       if (bInnerSearch) {
454         rndFind.m_CurObject = child;
455         WideString wsOriginCondition = std::move(rndFind.m_wsCondition);
456         uint32_t dwOriginStyle = rndFind.m_dwStyles;
457         rndFind.m_dwStyles = dwOriginStyle | XFA_RESOLVENODE_ALL;
458         ResolveNormal(rndFind);
459         rndFind.m_dwStyles = dwOriginStyle;
460         rndFind.m_wsCondition = std::move(wsOriginCondition);
461         rnd.m_Objects.insert(rnd.m_Objects.end(), rndFind.m_Objects.begin(),
462                              rndFind.m_Objects.end());
463         rndFind.m_Objects.clear();
464       }
465       child = child->GetNextSibling();
466     }
467     if (rnd.m_Objects.size() > nNum) {
468       if (parentNode->IsTransparent()) {
469         std::vector<CXFA_Node*> upArrayNodes;
470         CXFA_Node* pCurrent = ToNode(rnd.m_Objects.front().Get());
471         if (pCurrent) {
472           upArrayNodes =
473               pCurrent->GetSiblings(!!(dwStyles & XFA_RESOLVENODE_TagName));
474         }
475         if (upArrayNodes.size() > rnd.m_Objects.size()) {
476           CXFA_Object* pSaveObject = rnd.m_Objects.front().Get();
477           rnd.m_Objects = std::vector<UnownedPtr<CXFA_Object>>(
478               upArrayNodes.begin(), upArrayNodes.end());
479           rnd.m_Objects.front() = pSaveObject;
480         }
481       }
482       FilterCondition(wsCondition, &rnd);
483       return !rnd.m_Objects.empty();
484     }
485   }
486 
487   if (dwStyles & XFA_RESOLVENODE_Parent) {
488     uint32_t dwSubStyles = XFA_RESOLVENODE_Siblings | XFA_RESOLVENODE_Parent |
489                            XFA_RESOLVENODE_Properties;
490     if (dwStyles & XFA_RESOLVENODE_TagName)
491       dwSubStyles |= XFA_RESOLVENODE_TagName;
492     if (dwStyles & XFA_RESOLVENODE_ALL)
493       dwSubStyles |= XFA_RESOLVENODE_ALL;
494 
495     rndFind.m_dwStyles = dwSubStyles;
496     rndFind.m_CurObject = parentNode;
497     rnd.m_pSC->GetUpObjectArray()->push_back(parentNode);
498     ResolveNormal(rndFind);
499     rnd.m_Objects.insert(rnd.m_Objects.end(), rndFind.m_Objects.begin(),
500                          rndFind.m_Objects.end());
501     rndFind.m_Objects.clear();
502     if (rnd.m_Objects.size() > nNum)
503       return true;
504   }
505   return false;
506 }
507 
ResolveAsterisk(CFXJSE_ResolveNodeData & rnd)508 bool CFXJSE_ResolveProcessor::ResolveAsterisk(CFXJSE_ResolveNodeData& rnd) {
509   CXFA_Node* curNode = ToNode(rnd.m_CurObject.Get());
510   std::vector<CXFA_Node*> array = curNode->GetNodeListWithFilter(
511       XFA_NODEFILTER_Children | XFA_NODEFILTER_Properties);
512   rnd.m_Objects.insert(rnd.m_Objects.end(), array.begin(), array.end());
513   return !rnd.m_Objects.empty();
514 }
515 
GetFilter(WideStringView wsExpression,int32_t nStart,CFXJSE_ResolveNodeData & rnd)516 int32_t CFXJSE_ResolveProcessor::GetFilter(WideStringView wsExpression,
517                                            int32_t nStart,
518                                            CFXJSE_ResolveNodeData& rnd) {
519   ASSERT(nStart > -1);
520 
521   int32_t iLength = wsExpression.GetLength();
522   if (nStart >= iLength)
523     return 0;
524 
525   WideString& wsName = rnd.m_wsName;
526   WideString& wsCondition = rnd.m_wsCondition;
527   int32_t nNameCount = 0;
528   int32_t nConditionCount = 0;
529   {
530     // Span's lifetime must end before ReleaseBuffer() below.
531     pdfium::span<wchar_t> pNameBuf = wsName.GetBuffer(iLength - nStart);
532     pdfium::span<wchar_t> pConditionBuf =
533         wsCondition.GetBuffer(iLength - nStart);
534     pdfium::span<const wchar_t> pSrc = wsExpression.span();
535     std::vector<int32_t> stack;
536     int32_t nType = -1;
537     wchar_t wPrev = 0;
538     wchar_t wCur;
539     bool bIsCondition = false;
540     while (nStart < iLength) {
541       wCur = pSrc[nStart++];
542       if (wCur == '.') {
543         if (nNameCount == 0) {
544           rnd.m_dwStyles |= XFA_RESOLVENODE_AnyChild;
545           continue;
546         }
547         if (wPrev == '\\') {
548           pNameBuf[nNameCount - 1] = wPrev = '.';
549           continue;
550         }
551 
552         wchar_t wLookahead = nStart < iLength ? pSrc[nStart] : 0;
553         if (wLookahead != '[' && wLookahead != '(' && nType < 0)
554           break;
555       }
556       if (wCur == '[' || wCur == '(') {
557         bIsCondition = true;
558       } else if (wCur == '.' && nStart < iLength &&
559                  (pSrc[nStart] == '[' || pSrc[nStart] == '(')) {
560         bIsCondition = true;
561       }
562       if (bIsCondition)
563         pConditionBuf[nConditionCount++] = wCur;
564       else
565         pNameBuf[nNameCount++] = wCur;
566 
567       if ((nType == 0 && wCur == ']') || (nType == 1 && wCur == ')') ||
568           (nType == 2 && wCur == '"')) {
569         nType = stack.empty() ? -1 : stack.back();
570         if (!stack.empty())
571           stack.pop_back();
572       } else if (wCur == '[') {
573         stack.push_back(nType);
574         nType = 0;
575       } else if (wCur == '(') {
576         stack.push_back(nType);
577         nType = 1;
578       } else if (wCur == '"') {
579         stack.push_back(nType);
580         nType = 2;
581       }
582       wPrev = wCur;
583     }
584     if (!stack.empty())
585       return -1;
586   }
587   wsName.ReleaseBuffer(nNameCount);
588   wsCondition.ReleaseBuffer(nConditionCount);
589   wsName.Trim();
590   wsCondition.Trim();
591   rnd.m_uHashName =
592       static_cast<XFA_HashCode>(FX_HashCode_GetW(wsName.AsStringView(), false));
593   return nStart;
594 }
595 
ConditionArray(size_t iCurIndex,WideString wsCondition,size_t iFoundCount,CFXJSE_ResolveNodeData * pRnd)596 void CFXJSE_ResolveProcessor::ConditionArray(size_t iCurIndex,
597                                              WideString wsCondition,
598                                              size_t iFoundCount,
599                                              CFXJSE_ResolveNodeData* pRnd) {
600   size_t iLen = wsCondition.GetLength();
601   bool bRelative = false;
602   bool bAll = false;
603   size_t i = 1;
604   for (; i < iLen; ++i) {
605     wchar_t ch = wsCondition[i];
606     if (ch == ' ')
607       continue;
608     if (ch == '+' || ch == '-')
609       bRelative = true;
610     else if (ch == '*')
611       bAll = true;
612 
613     break;
614   }
615   if (bAll) {
616     if (pRnd->m_dwStyles & XFA_RESOLVENODE_CreateNode) {
617       if (pRnd->m_dwStyles & XFA_RESOLVENODE_Bind) {
618         m_pNodeHelper->m_pCreateParent = ToNode(pRnd->m_CurObject.Get());
619         m_pNodeHelper->m_iCreateCount = 1;
620         pRnd->m_Objects.clear();
621         m_pNodeHelper->m_iCurAllStart = -1;
622         m_pNodeHelper->m_pAllStartParent = nullptr;
623       } else if (m_pNodeHelper->m_iCurAllStart == -1) {
624         m_pNodeHelper->m_iCurAllStart = m_iCurStart;
625         m_pNodeHelper->m_pAllStartParent = ToNode(pRnd->m_CurObject.Get());
626       }
627     } else if (pRnd->m_dwStyles & XFA_RESOLVENODE_BindNew) {
628       if (m_pNodeHelper->m_iCurAllStart == -1)
629         m_pNodeHelper->m_iCurAllStart = m_iCurStart;
630     }
631     return;
632   }
633   if (iFoundCount == 1 && !iLen)
634     return;
635 
636   int32_t iIndex = wsCondition.Substr(i, iLen - 1 - i).GetInteger();
637   if (bRelative)
638     iIndex += iCurIndex;
639 
640   if (iIndex < 0 || static_cast<size_t>(iIndex) >= iFoundCount) {
641     if (pRnd->m_dwStyles & XFA_RESOLVENODE_CreateNode) {
642       m_pNodeHelper->m_pCreateParent = ToNode(pRnd->m_CurObject.Get());
643       m_pNodeHelper->m_iCreateCount = iIndex - iFoundCount + 1;
644     }
645     pRnd->m_Objects.clear();
646   } else {
647     pRnd->m_Objects =
648         std::vector<UnownedPtr<CXFA_Object>>(1, pRnd->m_Objects[iIndex]);
649   }
650 }
651 
FilterCondition(WideString wsCondition,CFXJSE_ResolveNodeData * pRnd)652 void CFXJSE_ResolveProcessor::FilterCondition(WideString wsCondition,
653                                               CFXJSE_ResolveNodeData* pRnd) {
654   size_t iCurIndex = 0;
655   const std::vector<CXFA_Node*>* pArray = pRnd->m_pSC->GetUpObjectArray();
656   if (!pArray->empty()) {
657     CXFA_Node* pNode = pArray->back();
658     bool bIsProperty = pNode->IsProperty();
659     bool bIsClassIndex =
660         pNode->IsUnnamed() ||
661         (bIsProperty && pNode->GetElementType() != XFA_Element::PageSet);
662     iCurIndex = pNode->GetIndex(bIsProperty, bIsClassIndex);
663   }
664 
665   size_t iFoundCount = pRnd->m_Objects.size();
666   wsCondition.Trim();
667 
668   int32_t iLen = wsCondition.GetLength();
669   if (!iLen) {
670     if (pRnd->m_dwStyles & XFA_RESOLVENODE_ALL)
671       return;
672     if (iFoundCount == 1)
673       return;
674 
675     if (iFoundCount <= iCurIndex) {
676       if (pRnd->m_dwStyles & XFA_RESOLVENODE_CreateNode) {
677         m_pNodeHelper->m_pCreateParent = ToNode(pRnd->m_CurObject.Get());
678         m_pNodeHelper->m_iCreateCount = iCurIndex - iFoundCount + 1;
679       }
680       pRnd->m_Objects.clear();
681       return;
682     }
683 
684     pRnd->m_Objects =
685         std::vector<UnownedPtr<CXFA_Object>>(1, pRnd->m_Objects[iCurIndex]);
686     return;
687   }
688 
689   wchar_t wTypeChar = wsCondition[0];
690   switch (wTypeChar) {
691     case '[':
692       ConditionArray(iCurIndex, wsCondition, iFoundCount, pRnd);
693       return;
694     case '.':
695       if (iLen > 1 && (wsCondition[1] == '[' || wsCondition[1] == '('))
696         DoPredicateFilter(wsCondition, iFoundCount, pRnd);
697       return;
698     case '(':
699     case '"':
700     default:
701       return;
702   }
703 }
704 
SetStylesForChild(uint32_t dwParentStyles,CFXJSE_ResolveNodeData & rnd)705 void CFXJSE_ResolveProcessor::SetStylesForChild(uint32_t dwParentStyles,
706                                                 CFXJSE_ResolveNodeData& rnd) {
707   uint32_t dwSubStyles = XFA_RESOLVENODE_Children;
708   if (dwParentStyles & XFA_RESOLVENODE_TagName)
709     dwSubStyles |= XFA_RESOLVENODE_TagName;
710 
711   dwSubStyles &= ~XFA_RESOLVENODE_Parent;
712   dwSubStyles &= ~XFA_RESOLVENODE_Siblings;
713   dwSubStyles &= ~XFA_RESOLVENODE_Properties;
714   dwSubStyles |= XFA_RESOLVENODE_ALL;
715   rnd.m_dwStyles = dwSubStyles;
716 }
717 
SetIndexDataBind(WideString & wsNextCondition,int32_t & iIndex,int32_t iCount)718 void CFXJSE_ResolveProcessor::SetIndexDataBind(WideString& wsNextCondition,
719                                                int32_t& iIndex,
720                                                int32_t iCount) {
721   if (m_pNodeHelper->CreateNodeForCondition(wsNextCondition)) {
722     if (m_pNodeHelper->m_eLastCreateType == XFA_Element::DataGroup) {
723       iIndex = 0;
724     } else {
725       iIndex = iCount - 1;
726     }
727   } else {
728     iIndex = iCount - 1;
729   }
730 }
731 
CFXJSE_ResolveNodeData(CFXJSE_Engine * pSC)732 CFXJSE_ResolveNodeData::CFXJSE_ResolveNodeData(CFXJSE_Engine* pSC)
733     : m_pSC(pSC) {}
734 
735 CFXJSE_ResolveNodeData::~CFXJSE_ResolveNodeData() = default;
736