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