1use std::collections::HashSet;
2
3use crate::{
4 tree::{
5 NodeCommon, XmlElementType, XmlGenericNodePtr, XmlNodePtr, XmlNsPtr, xml_free_node_list,
6 },
7 xpath::xml_xpath_node_set_free_ns,
8};
9
10use super::{
11 XmlXPathObject, xml_xpath_cast_node_to_string, xml_xpath_cmp_nodes_ext, xml_xpath_err_memory,
12 xml_xpath_new_node_set, xml_xpath_node_set_dup_ns,
13};
14
15const XPATH_MAX_NODESET_LENGTH: usize = 10000000;
21
22#[repr(C)]
24#[derive(Clone, PartialEq, Default)]
25pub struct XmlNodeSet {
26 pub node_tab: Vec<XmlGenericNodePtr>,
28 }
30
31impl XmlNodeSet {
32 pub fn with_value(val: Option<XmlGenericNodePtr>) -> Option<Self> {
33 let mut ret = Self::default();
34 if let Some(val) = val {
35 ret.node_tab = vec![];
36 if let Ok(ns) = XmlNsPtr::try_from(val) {
37 let ns_node =
38 xml_xpath_node_set_dup_ns(ns.node.or(ns.next.map(|next| next.into())), ns)?;
39
40 ret.node_tab.push(ns_node);
41 } else {
42 ret.node_tab.push(val);
43 }
44 }
45 Some(ret)
46 }
47
48 #[doc(alias = "xmlXPathNodeSetIsEmpty")]
52 pub(crate) fn is_empty(&self) -> bool {
53 self.node_tab.is_empty()
54 }
55
56 #[doc(alias = "xmlXPathNodeSetGetLength")]
60 pub(crate) fn len(&self) -> usize {
61 self.node_tab.len()
62 }
63
64 #[doc(alias = "xmlXPathNodeSetItem")]
69 pub(crate) fn get(&self, index: usize) -> Option<XmlGenericNodePtr> {
70 self.node_tab.get(index).copied()
71 }
72
73 #[doc(alias = "xmlXPathNodeSetContains")]
77 pub fn contains(&self, val: Option<XmlGenericNodePtr>) -> bool {
78 let Some(val) = val else {
79 return false;
80 };
81 let table = &self.node_tab;
82 if let Ok(ns1) = XmlNsPtr::try_from(val) {
83 for &node in table {
84 if let Ok(ns2) = XmlNsPtr::try_from(node) {
85 if ns1 == ns2 {
86 return true;
87 }
88 if ns1.node.is_some() && ns2.node == ns1.node && ns1.prefix() == ns2.prefix() {
89 return true;
90 }
91 }
92 }
93 } else {
94 for &node in table {
95 if val == node {
96 return true;
97 }
98 }
99 }
100 false
101 }
102
103 #[doc(alias = "xmlXPathHasSameNodes")]
108 pub unsafe fn has_same_nodes(&self, other: &XmlNodeSet) -> bool {
109 let t1 = &self.node_tab;
110 let t2 = &other.node_tab;
111 if t1.is_empty() || t2.is_empty() {
112 return false;
113 }
114 t1.iter().any(|node| t2.contains(node))
115 }
116
117 #[doc(alias = "xmlXPathIntersection")]
123 pub fn intersection(&self, other: &XmlNodeSet) -> Option<Box<XmlNodeSet>> {
124 let mut ret = xml_xpath_node_set_create(None)?;
125 let t1 = &self.node_tab;
126 let t2 = &other.node_tab;
127 if t1.is_empty() || t2.is_empty() {
128 return Some(ret);
129 }
130
131 for &node in t1 {
132 if t2.contains(&node) {
133 if ret.as_mut().add_unique(node) < 0 {
135 break;
136 }
137 }
138 }
139 Some(ret)
140 }
141
142 #[doc(alias = "xmlXPathFreeNodeSet", alias = "xmlXPathFreeValueTree")]
146 pub(crate) fn cleanup(&mut self, free_actual_tree: bool) {
147 unsafe {
148 let table = &mut self.node_tab;
149 while let Some(node) = table.pop() {
150 if let Ok(ns) = XmlNsPtr::try_from(node) {
151 xml_xpath_node_set_free_ns(ns);
152 } else if free_actual_tree {
153 xml_free_node_list(Some(node));
154 }
155 }
156 }
157 }
158
159 #[doc(alias = "xmlXPathNodeSetSort")]
161 pub fn sort(&mut self) {
162 let table = &mut self.node_tab;
165 let len = table.len();
169 let mut incr = len;
170 while {
171 incr /= 2;
172 incr > 0
173 } {
174 for i in incr..len {
175 let mut j = i as i32 - incr as i32;
176 while j >= 0 {
177 if xml_xpath_cmp_nodes_ext(table[j as usize], table[j as usize + incr])
178 .is_some_and(|f| f.is_gt())
179 {
180 table.swap(j as usize, j as usize + incr);
181 j -= incr as i32;
182 } else {
183 break;
184 }
185 }
186 }
187 }
188 }
189
190 #[doc(alias = "xmlXPathNodeSetRemove")]
192 pub fn remove(&mut self, val: i32) {
193 if val >= self.node_tab.len() as i32 {
194 return;
195 }
196 if let Ok(ns) = XmlNsPtr::try_from(self.node_tab[val as usize]) {
197 xml_xpath_node_set_free_ns(ns);
198 }
199 self.node_tab.remove(val as usize);
200 }
201
202 #[doc(alias = "xmlXPathNodeSetDel")]
204 pub fn delete(&mut self, val: XmlGenericNodePtr) {
205 let Some(pos) = self.node_tab.iter().position(|&node| node == val) else {
207 return;
208 };
209 if let Ok(ns) = XmlNsPtr::try_from(self.node_tab[pos]) {
210 xml_xpath_node_set_free_ns(ns);
211 }
212 self.node_tab.remove(pos);
213 }
214
215 #[doc(alias = "xmlXPathNodeSetClearFromPos")]
219 pub(super) fn truncate(&mut self, new_len: usize, has_ns_nodes: bool) {
220 if new_len >= self.node_tab.len() {
221 return;
222 }
223 if has_ns_nodes {
224 for &node in &self.node_tab[new_len..] {
225 if let Ok(ns) = XmlNsPtr::try_from(node) {
226 xml_xpath_node_set_free_ns(ns);
227 }
228 }
229 }
230 self.node_tab.truncate(new_len);
231 }
232
233 #[doc(alias = "xmlXPathNodeSetClear")]
236 pub(super) fn clear(&mut self, has_ns_nodes: bool) {
237 self.truncate(0, has_ns_nodes);
238 }
239
240 #[doc(alias = "xmlXPathNodeSetAdd")]
244 pub fn add(&mut self, val: XmlGenericNodePtr) -> i32 {
245 for &node in &self.node_tab {
248 if node == val {
249 return 0;
250 }
251 }
252
253 if self.node_tab.len() >= XPATH_MAX_NODESET_LENGTH {
255 xml_xpath_err_memory(None, Some("growing nodeset hit limit\n"));
256 return -1;
257 }
258 if let Ok(ns) = XmlNsPtr::try_from(val) {
259 let Some(ns_node) =
260 xml_xpath_node_set_dup_ns(ns.node.or(ns.next.map(|next| next.into())), ns)
261 else {
262 return -1;
263 };
264
265 self.node_tab.push(ns_node);
266 } else {
267 self.node_tab.push(val);
268 }
269 0
270 }
271
272 #[doc(alias = "xmlXPathNodeSetAddUnique")]
277 pub fn add_unique(&mut self, val: XmlGenericNodePtr) -> i32 {
278 if self.node_tab.len() >= XPATH_MAX_NODESET_LENGTH {
281 xml_xpath_err_memory(None, Some("growing nodeset hit limit\n"));
282 return -1;
283 }
284 if let Ok(ns) = XmlNsPtr::try_from(val) {
285 let Some(ns_node) =
286 xml_xpath_node_set_dup_ns(ns.node.or(ns.next.map(|next| next.into())), ns)
287 else {
288 return -1;
289 };
290
291 self.node_tab.push(ns_node);
292 } else {
293 self.node_tab.push(val);
294 }
295 0
296 }
297
298 #[doc(alias = "xmlXPathNodeSetAddNs")]
302 pub fn add_ns(&mut self, node: XmlNodePtr, ns: XmlNsPtr) -> i32 {
303 if !matches!(ns.typ, XmlElementType::XmlNamespaceDecl)
304 || !matches!(node.element_type(), XmlElementType::XmlElementNode)
305 {
306 return -1;
307 }
308
309 for &cur_node in &self.node_tab {
312 if XmlNsPtr::try_from(cur_node)
313 .ok()
314 .filter(|cur_node| cur_node.node == Some(node.into()))
315 .filter(|cur_node| ns.prefix() == cur_node.prefix())
316 .is_some()
317 {
318 return 0;
319 }
320 }
321
322 if self.node_tab.len() >= XPATH_MAX_NODESET_LENGTH {
324 xml_xpath_err_memory(None, Some("growing nodeset hit limit\n"));
325 return -1;
326 }
327 let Some(ns_node) = xml_xpath_node_set_dup_ns(Some(node.into()), ns) else {
328 return -1;
329 };
330 self.node_tab.push(ns_node);
331 0
332 }
333}
334
335#[doc(alias = "xmlXPathNodeSetCreate")]
339pub fn xml_xpath_node_set_create(val: Option<XmlGenericNodePtr>) -> Option<Box<XmlNodeSet>> {
340 let set = XmlNodeSet::with_value(val)?;
341 Some(Box::new(set))
342}
343
344#[doc(alias = "xmlXPathFreeNodeSet")]
346pub fn xml_xpath_free_node_set(obj: Option<Box<XmlNodeSet>>) {
347 if let Some(mut obj) = obj {
348 obj.as_mut().cleanup(false);
349 }
350}
351
352#[doc(alias = "xmlXPathFreeValueTree")]
354pub fn xml_xpath_free_value_tree(obj: Option<Box<XmlNodeSet>>) {
355 if let Some(mut obj) = obj {
356 obj.as_mut().cleanup(true);
357 }
358}
359
360#[doc(alias = "xmlXPathDifference")]
369pub fn xml_xpath_difference(
370 nodes1: Option<&XmlNodeSet>,
371 nodes2: Option<&XmlNodeSet>,
372) -> Option<Box<XmlNodeSet>> {
373 let Some(nodes2) = nodes2.filter(|n| !n.is_empty()) else {
374 return nodes1.cloned().map(Box::new);
375 };
376
377 let mut ret = xml_xpath_node_set_create(None);
379 let Some(nodes1) = nodes1 else {
380 return ret;
381 };
382 if nodes1.is_empty() {
383 return ret;
384 }
385
386 let l1 = nodes1.len();
387
388 if let Some(ret) = ret.as_mut() {
389 for i in 0..l1 {
390 let cur = nodes1.get(i).unwrap();
391 if !nodes2.contains(Some(cur)) {
392 if ret.add_unique(cur) < 0 {
394 break;
395 }
396 }
397 }
398 }
399 ret
400}
401
402#[doc(alias = "xmlXPathDistinctSorted")]
411pub fn xml_xpath_distinct_sorted(nodes: Option<&XmlNodeSet>) -> Option<Box<XmlNodeSet>> {
412 let nodes = nodes?;
413 let mut ret = xml_xpath_node_set_create(None)?;
414 if nodes.is_empty() {
415 return Some(ret);
416 }
417
418 let l = nodes.len();
419 let mut hash = HashSet::new();
420 for i in 0..l {
421 let cur = nodes.get(i).unwrap();
422 let strval = xml_xpath_cast_node_to_string(Some(cur));
423 if hash.insert(strval) && ret.as_mut().add_unique(cur) < 0 {
424 xml_xpath_free_node_set(Some(ret));
425 return None;
426 }
427 }
428 Some(ret)
429}
430
431#[doc(alias = "xmlXPathDistinct")]
442pub fn xml_xpath_distinct(nodes: Option<&mut XmlNodeSet>) -> Option<Box<XmlNodeSet>> {
443 let nodes = nodes?;
444 if nodes.is_empty() {
445 return Some(Box::new(nodes.clone()));
446 }
447
448 nodes.sort();
449 xml_xpath_distinct_sorted(Some(nodes))
450}
451
452#[doc(alias = "xmlXPathNodeLeadingSorted")]
462pub fn xml_xpath_node_leading_sorted(
463 nodes: Option<&XmlNodeSet>,
464 node: Option<XmlGenericNodePtr>,
465) -> Option<Box<XmlNodeSet>> {
466 let Some(node) = node else {
467 return nodes.cloned().map(Box::new);
468 };
469 let mut ret = xml_xpath_node_set_create(None)?;
470 let Some(nodes) = nodes.filter(|n| !n.is_empty() && n.contains(Some(node))) else {
471 return Some(ret);
472 };
473
474 let l = nodes.len();
475 for i in 0..l {
476 let cur = nodes.get(i).unwrap();
477 if cur == node {
478 break;
479 }
480 if ret.add_unique(cur) < 0 {
482 break;
483 }
484 }
485 Some(ret)
486}
487
488#[doc(alias = "xmlXPathLeadingSorted")]
498pub fn xml_xpath_leading_sorted(
499 nodes1: Option<&XmlNodeSet>,
500 nodes2: Option<&XmlNodeSet>,
501) -> Option<Box<XmlNodeSet>> {
502 let Some(nodes2) = nodes2.filter(|n| !n.is_empty()) else {
503 return nodes1.cloned().map(Box::new);
504 };
505 xml_xpath_node_leading_sorted(nodes1, nodes2.get(1))
506}
507
508#[doc(alias = "xmlXPathNodeLeading")]
520pub fn xml_xpath_node_leading(
521 mut nodes: Option<&mut XmlNodeSet>,
522 node: Option<XmlGenericNodePtr>,
523) -> Option<Box<XmlNodeSet>> {
524 if let Some(nodes) = nodes.as_deref_mut() {
525 nodes.sort();
526 }
527 xml_xpath_node_leading_sorted(nodes.map(|n| &*n), node)
528}
529
530#[doc(alias = "xmlXPathLeading")]
542pub fn xml_xpath_leading(
543 nodes1: Option<&mut XmlNodeSet>,
544 nodes2: Option<&mut XmlNodeSet>,
545) -> Option<Box<XmlNodeSet>> {
546 let Some(nodes2) = nodes2.filter(|n| !n.is_empty()) else {
547 return nodes1.cloned().map(Box::new);
548 };
549 let Some(nodes1) = nodes1.filter(|n| !n.is_empty()) else {
550 return xml_xpath_node_set_create(None);
551 };
552 nodes1.sort();
553 nodes2.sort();
554 xml_xpath_node_leading_sorted(Some(nodes1), nodes2.get(1))
555}
556
557#[doc(alias = "xmlXPathNodeTrailingSorted")]
567pub fn xml_xpath_node_trailing_sorted(
568 nodes: &XmlNodeSet,
569 node: Option<XmlGenericNodePtr>,
570) -> Option<Box<XmlNodeSet>> {
571 let Some(node) = node else {
572 return Some(Box::new(nodes.clone()));
573 };
574
575 let mut ret = xml_xpath_node_set_create(None)?;
576 if nodes.is_empty() || !nodes.contains(Some(node)) {
577 return Some(ret);
578 }
579
580 let l = nodes.len();
581 for i in (0..l).rev() {
582 let cur = nodes.get(i).unwrap();
583 if cur == node {
584 break;
585 }
586 if ret.as_mut().add_unique(cur) < 0 {
588 break;
589 }
590 }
591 ret.as_mut().sort(); Some(ret)
593}
594
595#[doc(alias = "xmlXPathTrailingSorted")]
606pub fn xml_xpath_trailing_sorted(
607 nodes1: &XmlNodeSet,
608 nodes2: Option<&XmlNodeSet>,
609) -> Option<Box<XmlNodeSet>> {
610 let Some(nodes2) = nodes2.filter(|n| !n.is_empty()) else {
611 return Some(Box::new(nodes1.clone()));
612 };
613 xml_xpath_node_trailing_sorted(nodes1, nodes2.get(0))
614}
615
616#[doc(alias = "xmlXPathNodeTrailing")]
628pub fn xml_xpath_node_trailing(
629 nodes: &mut XmlNodeSet,
630 node: Option<XmlGenericNodePtr>,
631) -> Option<Box<XmlNodeSet>> {
632 nodes.sort();
633 xml_xpath_node_trailing_sorted(nodes, node)
634}
635
636#[doc(alias = "xmlXPathTrailing")]
649pub fn xml_xpath_trailing(
650 nodes1: Option<&mut XmlNodeSet>,
651 nodes2: Option<&mut XmlNodeSet>,
652) -> Option<Box<XmlNodeSet>> {
653 let Some(nodes2) = nodes2.filter(|n| !n.is_empty()) else {
654 return nodes1.cloned().map(Box::new);
655 };
656 let Some(nodes1) = nodes1.filter(|n| !n.is_empty()) else {
657 return xml_xpath_node_set_create(None);
658 };
659 nodes1.sort();
660 nodes2.sort();
661 xml_xpath_node_trailing_sorted(nodes1, nodes2.get(0))
662}
663
664#[doc(alias = "xmlXPathNodeSetMergeAndClear")]
675pub(super) fn xml_xpath_node_set_merge_and_clear(
676 set1: Option<Box<XmlNodeSet>>,
677 set2: Option<&mut XmlNodeSet>,
678) -> Option<Box<XmlNodeSet>> {
679 let mut set1 = set1?;
680 let init_nb_set1 = set1.node_tab.len();
681 let set2 = set2?;
682 set2.node_tab.reverse();
683 'b: while let Some(n2) = set2.node_tab.pop() {
684 for &n1 in &set1.node_tab[..init_nb_set1] {
686 if n1 == n2 {
687 continue 'b;
689 }
690 if let Some((n1, n2)) = XmlNsPtr::try_from(n1).ok().zip(XmlNsPtr::try_from(n2).ok()) {
691 if n1.node == n2.node && n1.prefix() == n2.prefix() {
692 xml_xpath_node_set_free_ns(n2);
694 continue 'b;
696 }
697 }
698 }
699 if set1.node_tab.len() >= XPATH_MAX_NODESET_LENGTH {
701 xml_xpath_err_memory(None, Some("merging nodeset hit limit\n"));
702 xml_xpath_free_node_set(Some(set1));
704 set2.clear(true);
705 return None;
706 }
707 set1.node_tab.push(n2);
708 }
709 Some(set1)
710
711 }
716
717#[doc(alias = "xmlXPathNodeSetMergeAndClearNoDupls")]
724pub(super) fn xml_xpath_node_set_merge_and_clear_no_dupls(
725 set1: Option<Box<XmlNodeSet>>,
726 set2: Option<&mut XmlNodeSet>,
727) -> Option<Box<XmlNodeSet>> {
728 let mut set1 = set1?;
729 let set2 = set2?;
730 set2.node_tab.reverse();
731 while let Some(n2) = set2.node_tab.pop() {
732 if set1.node_tab.len() >= XPATH_MAX_NODESET_LENGTH {
733 xml_xpath_err_memory(None, Some("merging nodeset hit limit\n"));
734 xml_xpath_free_node_set(Some(set1));
736 set2.clear(true);
737 return None;
738 }
739 set1.node_tab.push(n2);
740 }
741 Some(set1)
742
743 }
748
749#[doc(alias = "xmlXPathNodeSetMerge")]
756pub fn xml_xpath_node_set_merge(
757 val1: Option<Box<XmlNodeSet>>,
758 val2: Option<&XmlNodeSet>,
759) -> Option<Box<XmlNodeSet>> {
760 let mut skip: i32;
761
762 let Some(val2) = val2 else {
763 return val1;
764 };
765 let mut val1 = val1.or_else(|| xml_xpath_node_set_create(None))?;
766
767 let init_nr = val1.as_ref().node_tab.len();
769
770 for &n2 in &val2.node_tab {
771 skip = 0;
773 for &n1 in &val1.node_tab[..init_nr] {
774 if n1 == n2
775 || XmlNsPtr::try_from(n1)
776 .ok()
777 .zip(XmlNsPtr::try_from(n2).ok())
778 .filter(|(n1, n2)| n1.node == n2.node)
779 .filter(|(n1, n2)| n1.prefix == n2.prefix)
780 .is_some()
781 {
782 skip = 1;
783 break;
784 }
785 }
786 if skip != 0 {
787 continue;
788 }
789
790 if val1.node_tab.len() >= XPATH_MAX_NODESET_LENGTH {
792 xml_xpath_err_memory(None, Some("merging nodeset hit limit\n"));
793 xml_xpath_free_node_set(Some(val1));
795 return None;
796 }
797 if let Ok(ns) = XmlNsPtr::try_from(n2) {
798 let Some(ns_node) =
799 xml_xpath_node_set_dup_ns(ns.node.or(ns.next.map(|next| next.into())), ns)
800 else {
801 xml_xpath_free_node_set(Some(val1));
802 return None;
803 };
804
805 val1.node_tab.push(ns_node);
806 } else {
807 val1.node_tab.push(n2);
808 }
809 }
810
811 Some(val1)
812
813 }
817
818#[doc(alias = "xmlXPathNewNodeSetList")]
823pub fn xml_xpath_new_node_set_list(val: Option<&mut XmlNodeSet>) -> Option<XmlXPathObject> {
824 if let Some(val) = val {
825 let mut ret = xml_xpath_new_node_set(Some(val.node_tab[0]));
826 if let Some(nodeset) = ret.nodesetval.as_deref_mut() {
827 for &node in &val.node_tab[1..] {
828 if nodeset.add_unique(node) < 0 {
830 break;
831 }
832 }
833 }
834 Some(ret)
835 } else {
836 None
837 }
838}