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