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