1#![allow(
14 missing_docs,
15 non_snake_case,
16 non_camel_case_types,
17 non_upper_case_globals
18)]
19
20use core::ffi::c_void;
21use core::ptr;
22use std::os::raw::{c_char, c_double, c_int, c_long};
23
24use crate::abi::allocator::{xmlFreeImpl, xmlMallocImpl, xmlMallocZero};
25use crate::abi::structs::{
26 _xmlDoc, _xmlNode, _xmlNodeSet, _xmlNs, _xmlXPathContext, _xmlXPathObject,
27};
28use crate::abi::types::{xmlChar, xmlXPathObjectType};
29use crate::xml::string::xml_strdup;
30use crate::xml::xpath::types::{node_string_value, NodeSet, XPathValue};
31
32fn number_to_xmlstring(val: c_double) -> *mut xmlChar {
34 let s = crate::xml::xpath::types::number_to_string(val);
35 dup_rust_string(&s)
36}
37
38fn dup_rust_string(s: &str) -> *mut xmlChar {
42 let bytes = s.as_bytes();
43 let buf = unsafe { xmlMallocImpl(bytes.len() + 1) } as *mut xmlChar;
44 if buf.is_null() {
45 return ptr::null_mut();
46 }
47 unsafe {
48 ptr::copy_nonoverlapping(bytes.as_ptr(), buf, bytes.len());
49 *buf.add(bytes.len()) = 0;
50 }
51 buf
52}
53
54#[no_mangle]
64pub unsafe extern "C" fn xmlXPathNewString(val: *const xmlChar) -> *mut _xmlXPathObject {
65 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
66 if obj.is_null() {
67 return ptr::null_mut();
68 }
69 (*obj).type_ = xmlXPathObjectType::XPATH_STRING as c_int;
70 (*obj).stringval = if val.is_null() {
71 xml_strdup(b"\0".as_ptr() as *const xmlChar)
72 } else {
73 xml_strdup(val)
74 };
75 obj
76}
77
78#[no_mangle]
85pub unsafe extern "C" fn xmlXPathNewValueTree(val: *mut _xmlNode) -> *mut _xmlXPathObject {
86 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
87 if obj.is_null() {
88 return ptr::null_mut();
89 }
90 (*obj).type_ = xmlXPathObjectType::XPATH_XSLT_TREE as c_int;
91 let ns = xmlMallocZero(size_of::<_xmlNodeSet>()) as *mut _xmlNodeSet;
92 if ns.is_null() {
93 xmlFreeImpl(obj as *mut c_void);
94 return ptr::null_mut();
95 }
96 (*ns).nodeNr = 0;
97 (*ns).nodeMax = 1;
98 let tab = xmlMallocImpl(size_of::<*mut _xmlNode>()) as *mut *mut _xmlNode;
99 if tab.is_null() {
100 xmlFreeImpl(ns as *mut c_void);
101 xmlFreeImpl(obj as *mut c_void);
102 return ptr::null_mut();
103 }
104 if val.is_null() {
105 (*ns).nodeNr = 0;
106 (*ns).nodeMax = 0;
107 xmlFreeImpl(tab as *mut c_void);
108 (*ns).nodeTab = ptr::null_mut();
109 } else {
110 ptr::write(tab, val);
111 (*ns).nodeTab = tab;
112 (*ns).nodeNr = 1;
113 }
114 (*obj).nodesetval = ns as *mut c_void;
115 obj
116}
117
118#[no_mangle]
125pub unsafe extern "C" fn xmlXPathNewNodeSetList(val: *mut _xmlNodeSet) -> *mut _xmlXPathObject {
126 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
127 if obj.is_null() {
128 return ptr::null_mut();
129 }
130 (*obj).type_ = xmlXPathObjectType::XPATH_NODESET as c_int;
131 if val.is_null() {
132 (*obj).nodesetval = ptr::null_mut();
133 return obj;
134 }
135 let src = &*val;
136 let nr = src.nodeNr;
137 let ns = xmlMallocZero(size_of::<_xmlNodeSet>()) as *mut _xmlNodeSet;
138 if ns.is_null() {
139 xmlFreeImpl(obj as *mut c_void);
140 return ptr::null_mut();
141 }
142 (*ns).nodeNr = nr;
143 (*ns).nodeMax = nr;
144 if nr > 0 && !src.nodeTab.is_null() {
145 let tab = xmlMallocImpl((nr as usize) * size_of::<*mut _xmlNode>()) as *mut *mut _xmlNode;
146 if tab.is_null() {
147 xmlFreeImpl(ns as *mut c_void);
148 xmlFreeImpl(obj as *mut c_void);
149 return ptr::null_mut();
150 }
151 ptr::copy_nonoverlapping(src.nodeTab, tab, nr as usize);
152 (*ns).nodeTab = tab;
153 } else {
154 (*ns).nodeTab = ptr::null_mut();
155 }
156 (*obj).nodesetval = ns as *mut c_void;
157 obj
158}
159
160#[no_mangle]
167pub unsafe extern "C" fn xmlXPathWrapString(val: *mut xmlChar) -> *mut _xmlXPathObject {
168 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
169 if obj.is_null() {
170 if !val.is_null() {
171 xmlFreeImpl(val as *mut c_void);
172 }
173 return ptr::null_mut();
174 }
175 (*obj).type_ = xmlXPathObjectType::XPATH_STRING as c_int;
176 (*obj).stringval = val;
177 obj
178}
179
180#[no_mangle]
186pub unsafe extern "C" fn xmlXPathWrapCString(val: *mut c_char) -> *mut _xmlXPathObject {
187 unsafe { xmlXPathWrapString(val as *mut xmlChar) }
188}
189
190#[no_mangle]
197pub unsafe extern "C" fn xmlXPathWrapNodeSet(val: *mut _xmlNodeSet) -> *mut _xmlXPathObject {
198 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
199 if obj.is_null() {
200 if !val.is_null() {
201 xmlFreeImpl(val as *mut c_void);
202 }
203 return ptr::null_mut();
204 }
205 (*obj).type_ = xmlXPathObjectType::XPATH_NODESET as c_int;
206 (*obj).nodesetval = val as *mut c_void;
207 obj
208}
209
210#[no_mangle]
216pub unsafe extern "C" fn xmlXPathWrapExternal(val: *mut c_void) -> *mut _xmlXPathObject {
217 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
218 if obj.is_null() {
219 return ptr::null_mut();
220 }
221 (*obj).type_ = xmlXPathObjectType::XPATH_USERS as c_int;
222 (*obj).user = val;
223 obj
224}
225
226#[no_mangle]
233pub unsafe extern "C" fn xmlXPathFreeNodeSetList(obj: *mut _xmlXPathObject) {
234 if obj.is_null() {
235 return;
236 }
237 let typ = (*obj).type_;
238 if typ == xmlXPathObjectType::XPATH_NODESET as c_int
239 || typ == xmlXPathObjectType::XPATH_XSLT_TREE as c_int
240 {
241 let ns = (*obj).nodesetval as *mut _xmlNodeSet;
242 if !ns.is_null() {
243 if !(*ns).nodeTab.is_null() {
244 xmlFreeImpl((*ns).nodeTab as *mut c_void);
245 }
246 xmlFreeImpl(ns as *mut c_void);
247 }
248 }
249 xmlFreeImpl(obj as *mut c_void);
250}
251
252#[no_mangle]
263pub unsafe extern "C" fn xmlXPathConvertBoolean(val: *mut _xmlXPathObject) -> *mut _xmlXPathObject {
264 if val.is_null() {
265 return ptr::null_mut();
266 }
267 let typ = (*val).type_;
268 if typ == xmlXPathObjectType::XPATH_BOOLEAN as c_int {
269 return val;
270 }
271 let b = crate::abi::exports_xml2::object_to_xpathvalue_pub(val).as_boolean();
272 crate::abi::exports_xml2::xmlXPathFreeObject(val);
273 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
274 if obj.is_null() {
275 return ptr::null_mut();
276 }
277 (*obj).type_ = xmlXPathObjectType::XPATH_BOOLEAN as c_int;
278 (*obj).boolval = if b { 1 } else { 0 };
279 obj
280}
281
282#[no_mangle]
288pub unsafe extern "C" fn xmlXPathConvertNumber(val: *mut _xmlXPathObject) -> *mut _xmlXPathObject {
289 if val.is_null() {
290 return ptr::null_mut();
291 }
292 let typ = (*val).type_;
293 if typ == xmlXPathObjectType::XPATH_NUMBER as c_int {
294 return val;
295 }
296 let n = crate::abi::exports_xml2::object_to_xpathvalue_pub(val).as_number();
297 crate::abi::exports_xml2::xmlXPathFreeObject(val);
298 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
299 if obj.is_null() {
300 return ptr::null_mut();
301 }
302 (*obj).type_ = xmlXPathObjectType::XPATH_NUMBER as c_int;
303 (*obj).floatval = n;
304 obj
305}
306
307#[no_mangle]
313pub unsafe extern "C" fn xmlXPathConvertString(val: *mut _xmlXPathObject) -> *mut _xmlXPathObject {
314 if val.is_null() {
315 return unsafe { xmlXPathNewString(ptr::null()) };
316 }
317 let typ = (*val).type_;
318 if typ == xmlXPathObjectType::XPATH_STRING as c_int {
319 return val;
320 }
321 let s = crate::abi::exports_xml2::object_to_xpathvalue_pub(val).as_string();
322 crate::abi::exports_xml2::xmlXPathFreeObject(val);
323 let buf = dup_rust_string(&s);
324 unsafe { xmlXPathWrapString(buf) }
325}
326
327#[no_mangle]
337pub unsafe extern "C" fn xmlXPathCastToBoolean(val: *mut _xmlXPathObject) -> c_int {
338 if val.is_null() {
339 return 0;
340 }
341 crate::abi::exports_xml2::object_to_xpathvalue_pub(val).as_boolean() as c_int
342}
343
344#[no_mangle]
350pub unsafe extern "C" fn xmlXPathCastToNumber(val: *mut _xmlXPathObject) -> c_double {
351 if val.is_null() {
352 return f64::NAN;
353 }
354 crate::abi::exports_xml2::object_to_xpathvalue_pub(val).as_number()
355}
356
357#[no_mangle]
359pub unsafe extern "C" fn xmlXPathCastBooleanToNumber(val: c_int) -> c_double {
360 if val != 0 {
361 1.0
362 } else {
363 0.0
364 }
365}
366
367#[no_mangle]
369pub unsafe extern "C" fn xmlXPathCastBooleanToString(val: c_int) -> *mut xmlChar {
370 if val != 0 {
371 xml_strdup(b"true\0".as_ptr() as *const xmlChar)
372 } else {
373 xml_strdup(b"false\0".as_ptr() as *const xmlChar)
374 }
375}
376
377#[no_mangle]
383pub unsafe extern "C" fn xmlXPathCastNodeSetToBoolean(ns: *mut _xmlNodeSet) -> c_int {
384 if ns.is_null() {
385 return 0;
386 }
387 (unsafe { (*ns).nodeNr > 0 }) as c_int
388}
389
390#[no_mangle]
396pub unsafe extern "C" fn xmlXPathCastNodeSetToNumber(ns: *mut _xmlNodeSet) -> c_double {
397 unsafe {
398 let val = crate::abi::exports_xml2::object_to_xpathvalue_pub(xmlXPathWrapNodeSet(ns));
399 let n = val.as_number();
400 n
402 }
403}
404
405#[no_mangle]
411pub unsafe extern "C" fn xmlXPathCastNodeSetToString(ns: *mut _xmlNodeSet) -> *mut xmlChar {
412 let val = crate::xml::xpath::types::XPathValue::NodeSet(unsafe { node_set_to_internal(ns) });
413 let s = val.as_string();
414 dup_rust_string(&s)
415}
416
417unsafe fn node_set_to_internal(ns: *mut _xmlNodeSet) -> NodeSet {
419 let mut out = NodeSet::new();
420 if ns.is_null() {
421 return out;
422 }
423 let nr = unsafe { (*ns).nodeNr };
424 let tab = unsafe { (*ns).nodeTab };
425 if !tab.is_null() {
426 for i in 0..nr as isize {
427 out.push(unsafe { *tab.add(i as usize) });
428 }
429 }
430 out
431}
432
433#[no_mangle]
439pub unsafe extern "C" fn xmlXPathCastNodeToNumber(node: *mut _xmlNode) -> c_double {
440 let s = node_string_value(node);
441 crate::xml::xpath::types::string_to_number(&s)
442}
443
444#[no_mangle]
450pub unsafe extern "C" fn xmlXPathCastNodeToString(node: *mut _xmlNode) -> *mut xmlChar {
451 let s = node_string_value(node);
452 dup_rust_string(&s)
453}
454
455#[no_mangle]
457pub unsafe extern "C" fn xmlXPathCastNumberToBoolean(val: c_double) -> c_int {
458 (val != 0.0 && !val.is_nan()) as c_int
459}
460
461#[no_mangle]
463pub unsafe extern "C" fn xmlXPathCastNumberToString(val: c_double) -> *mut xmlChar {
464 number_to_xmlstring(val)
465}
466
467#[no_mangle]
473pub unsafe extern "C" fn xmlXPathCastStringToBoolean(val: *const xmlChar) -> c_int {
474 if val.is_null() || unsafe { *val } == 0 {
475 0
476 } else {
477 1
478 }
479}
480
481#[no_mangle]
483pub unsafe extern "C" fn xmlXPathIsNaN(val: c_double) -> c_int {
484 val.is_nan() as c_int
485}
486
487#[no_mangle]
489pub unsafe extern "C" fn xmlXPathIsInf(val: c_double) -> c_int {
490 if val.is_infinite() {
491 if val > 0.0 {
492 1
493 } else {
494 -1
495 }
496 } else {
497 0
498 }
499}
500
501#[no_mangle]
507pub unsafe extern "C" fn xmlXPathStringEvalNumber(str_: *const xmlChar) -> c_double {
508 if str_.is_null() {
509 return f64::NAN;
510 }
511 let s = unsafe { crate::xml::string::xmlstr_to_string(str_) };
512 crate::xml::xpath::types::string_to_number(&s)
513}
514
515#[no_mangle]
522pub unsafe extern "C" fn xmlXPathIsNodeType(name: *const xmlChar) -> c_int {
523 if name.is_null() {
524 return 0;
525 }
526 let s = unsafe { crate::xml::string::xmlstr_to_string(name) };
527 match s.as_str() {
528 "comment" | "text" | "processing-instruction" | "node" => 1,
529 _ => 0,
530 }
531}
532
533#[no_mangle]
535pub unsafe extern "C" fn xmlXPathInit() {}
536
537#[no_mangle]
544pub unsafe extern "C" fn xmlXPathErr(
545 ctxt: *mut crate::xml::xpath::parser_context::XmlXPathParserContext,
546 error: c_int,
547) {
548 if !ctxt.is_null() {
549 unsafe { (*ctxt).error = error };
550 }
551}
552
553#[no_mangle]
560pub unsafe extern "C" fn xmlXPatherror(
561 ctxt: *mut crate::xml::xpath::parser_context::XmlXPathParserContext,
562 _file: *const c_char,
563 _line: c_int,
564 _no: c_int,
565) {
566 if !ctxt.is_null() {
567 unsafe { (*ctxt).error = _no };
568 }
569}
570
571#[allow(unused)]
572fn _unused_doc(_d: *mut _xmlDoc) {}
573
574unsafe fn node_set_grow(ns: *mut _xmlNodeSet) {
580 if ns.is_null() {
581 return;
582 }
583 unsafe {
584 let nr = (*ns).nodeNr;
585 let max = (*ns).nodeMax;
586 if nr < max {
587 return;
588 }
589 let new_max = if max <= 0 { 8 } else { max * 2 };
590 let new_tab = crate::abi::allocator::xmlReallocImpl(
591 (*ns).nodeTab as *mut c_void,
592 (new_max as usize) * size_of::<*mut _xmlNode>(),
593 ) as *mut *mut _xmlNode;
594 if !new_tab.is_null() {
595 (*ns).nodeTab = new_tab;
596 (*ns).nodeMax = new_max;
597 }
598 }
599}
600
601#[no_mangle]
607pub unsafe extern "C" fn xmlXPathNodeSetContains(
608 cur: *mut _xmlNodeSet,
609 val: *mut _xmlNode,
610) -> c_int {
611 if cur.is_null() || val.is_null() {
612 return 0;
613 }
614 unsafe {
615 let nr = (*cur).nodeNr;
616 let tab = (*cur).nodeTab;
617 if !tab.is_null() {
618 for i in 0..nr as isize {
619 if *tab.add(i as usize) == val {
620 return 1;
621 }
622 }
623 }
624 }
625 0
626}
627
628#[no_mangle]
635pub unsafe extern "C" fn xmlXPathNodeSetAdd(cur: *mut _xmlNodeSet, val: *mut _xmlNode) -> c_int {
636 if cur.is_null() || val.is_null() {
637 return -1;
638 }
639 if xmlXPathNodeSetContains(cur, val) != 0 {
640 return 0;
641 }
642 unsafe {
643 node_set_grow(cur);
644 if (*cur).nodeNr >= (*cur).nodeMax {
645 return -1;
646 }
647 let idx = (*cur).nodeNr as usize;
648 ptr::write((*cur).nodeTab.add(idx), val);
649 (*cur).nodeNr += 1;
650 }
651 0
652}
653
654#[no_mangle]
661pub unsafe extern "C" fn xmlXPathNodeSetAddUnique(
662 cur: *mut _xmlNodeSet,
663 val: *mut _xmlNode,
664) -> c_int {
665 if cur.is_null() || val.is_null() {
666 return -1;
667 }
668 unsafe {
669 node_set_grow(cur);
670 if (*cur).nodeNr >= (*cur).nodeMax {
671 return -1;
672 }
673 let idx = (*cur).nodeNr as usize;
674 ptr::write((*cur).nodeTab.add(idx), val);
675 (*cur).nodeNr += 1;
676 }
677 0
678}
679
680#[no_mangle]
687pub unsafe extern "C" fn xmlXPathNodeSetAddNs(
688 cur: *mut _xmlNodeSet,
689 _node: *mut _xmlNode,
690 ns: *mut _xmlNs,
691) -> c_int {
692 if cur.is_null() || ns.is_null() {
693 return -1;
694 }
695 let ns_node = ns as *mut _xmlNode;
698 if xmlXPathNodeSetContains(cur, ns_node) != 0 {
699 return 0;
700 }
701 xmlXPathNodeSetAddUnique(cur, ns_node)
702}
703
704#[no_mangle]
710pub unsafe extern "C" fn xmlXPathNodeSetDel(cur: *mut _xmlNodeSet, val: *mut _xmlNode) -> c_int {
711 if cur.is_null() || val.is_null() {
712 return -1;
713 }
714 unsafe {
715 let nr = (*cur).nodeNr;
716 let tab = (*cur).nodeTab;
717 let mut found = -1;
718 if !tab.is_null() {
719 for i in 0..nr as isize {
720 if *tab.add(i as usize) == val {
721 found = i as c_int;
722 break;
723 }
724 }
725 }
726 if found >= 0 {
727 let fi = found as usize;
728 for i in fi..(nr as usize - 1) {
729 ptr::write(tab.add(i), *tab.add(i + 1));
730 }
731 (*cur).nodeNr -= 1;
732 }
733 }
734 0
735}
736
737#[no_mangle]
743pub unsafe extern "C" fn xmlXPathNodeSetRemove(cur: *mut _xmlNodeSet, val: c_int) -> c_int {
744 if cur.is_null() || val < 0 {
745 return -1;
746 }
747 unsafe {
748 let nr = (*cur).nodeNr;
749 if val >= nr {
750 return -1;
751 }
752 let tab = (*cur).nodeTab;
753 let vi = val as usize;
754 for i in vi..(nr as usize - 1) {
755 ptr::write(tab.add(i), *tab.add(i + 1));
756 }
757 (*cur).nodeNr -= 1;
758 }
759 0
760}
761
762#[no_mangle]
769pub unsafe extern "C" fn xmlXPathNodeSetSort(set: *mut _xmlNodeSet) {
770 if set.is_null() {
771 return;
772 }
773 unsafe {
774 let nr = (*set).nodeNr;
775 let tab = (*set).nodeTab;
776 if nr <= 1 || tab.is_null() {
777 return;
778 }
779 for i in 1..nr as usize {
782 let key = *tab.add(i);
783 let mut j = i;
784 while j > 0 {
785 let prev = *tab.add(j - 1);
786 if crate::xml::xpath::types::compare_document_order(prev, key)
787 == core::cmp::Ordering::Greater
788 {
789 ptr::write(tab.add(j), prev);
790 j -= 1;
791 } else {
792 break;
793 }
794 }
795 ptr::write(tab.add(j), key);
796 }
797 let mut w = 0usize;
799 for r in 0..nr as usize {
800 if w == 0 || *tab.add(w - 1) != *tab.add(r) {
801 ptr::write(tab.add(w), *tab.add(r));
802 w += 1;
803 }
804 }
805 (*set).nodeNr = w as c_int;
806 }
807}
808
809#[no_mangle]
816pub unsafe extern "C" fn xmlXPathNodeSetMerge(
817 val1: *mut _xmlNodeSet,
818 val2: *mut _xmlNodeSet,
819) -> *mut _xmlNodeSet {
820 if val1.is_null() && val2.is_null() {
821 return ptr::null_mut();
822 }
823 if val1.is_null() {
824 let obj = xmlXPathNewNodeSetList(val2);
826 let ns = unsafe { (*obj).nodesetval as *mut _xmlNodeSet };
827 if obj.is_null() {
828 return ptr::null_mut();
829 }
830 return ns;
831 }
832 if val2.is_null() {
833 return val1;
834 }
835 unsafe {
836 let nr2 = (*val2).nodeNr;
837 let tab2 = (*val2).nodeTab;
838 if !tab2.is_null() {
839 for i in 0..nr2 as isize {
840 let n = *tab2.add(i as usize);
841 if xmlXPathNodeSetContains(val1, n) == 0 {
842 xmlXPathNodeSetAddUnique(val1, n);
843 }
844 }
845 }
846 }
847 val1
848}
849
850#[no_mangle]
857pub unsafe extern "C" fn xmlXPathDifference(
858 nodes1: *mut _xmlNodeSet,
859 nodes2: *mut _xmlNodeSet,
860) -> *mut _xmlNodeSet {
861 if nodes1.is_null() {
862 return ptr::null_mut();
863 }
864 let mut a = unsafe { node_set_to_internal(nodes1) };
865 a.sort();
866 let b = unsafe { node_set_to_internal(nodes2) };
867 let mut out = NodeSet::new();
868 for n in a.iter() {
869 if !b.contains(n) {
870 out.push(n);
871 }
872 }
873 out.sort();
874 out.to_raw()
875}
876
877#[no_mangle]
883pub unsafe extern "C" fn xmlXPathIntersection(
884 nodes1: *mut _xmlNodeSet,
885 nodes2: *mut _xmlNodeSet,
886) -> *mut _xmlNodeSet {
887 let a = unsafe { node_set_to_internal(nodes1) };
888 let b = unsafe { node_set_to_internal(nodes2) };
889 let mut out = NodeSet::new();
890 for n in a.iter() {
891 if b.contains(n) {
892 out.push(n);
893 }
894 }
895 out.sort();
896 out.to_raw()
897}
898
899#[no_mangle]
905pub unsafe extern "C" fn xmlXPathDistinct(nodes: *mut _xmlNodeSet) -> *mut _xmlNodeSet {
906 if nodes.is_null() {
907 return ptr::null_mut();
908 }
909 unsafe {
910 xmlXPathNodeSetSort(nodes);
911 nodes
912 }
913}
914
915#[no_mangle]
921pub unsafe extern "C" fn xmlXPathDistinctSorted(nodes: *mut _xmlNodeSet) -> *mut _xmlNodeSet {
922 if nodes.is_null() {
923 return ptr::null_mut();
924 }
925 unsafe {
926 let nr = (*nodes).nodeNr;
927 let tab = (*nodes).nodeTab;
928 let mut w = 0usize;
929 if !tab.is_null() {
930 for r in 0..nr as usize {
931 if w == 0 || *tab.add(w - 1) != *tab.add(r) {
932 ptr::write(tab.add(w), *tab.add(r));
933 w += 1;
934 }
935 }
936 }
937 (*nodes).nodeNr = w as c_int;
938 nodes
939 }
940}
941
942#[no_mangle]
948pub unsafe extern "C" fn xmlXPathHasSameNodes(
949 nodes1: *mut _xmlNodeSet,
950 nodes2: *mut _xmlNodeSet,
951) -> c_int {
952 if nodes1.is_null() || nodes2.is_null() {
953 return 0;
954 }
955 unsafe {
956 let nr1 = (*nodes1).nodeNr;
957 let nr2 = (*nodes2).nodeNr;
958 if nr1 != nr2 {
959 return 0;
960 }
961 let tab1 = (*nodes1).nodeTab;
962 let tab2 = (*nodes2).nodeTab;
963 for i in 0..nr1 as isize {
964 let mut found = false;
965 for j in 0..nr2 as isize {
966 if *tab1.add(i as usize) == *tab2.add(j as usize) {
967 found = true;
968 break;
969 }
970 }
971 if !found {
972 return 0;
973 }
974 }
975 }
976 1
977}
978
979unsafe fn leading_nodes(nodes: &NodeSet, node: *mut _xmlNode) -> NodeSet {
981 let mut out = NodeSet::new();
982 for n in nodes.iter() {
983 if n == node {
984 break;
985 }
986 out.push(n);
987 }
988 out
989}
990
991unsafe fn trailing_nodes(nodes: &NodeSet, node: *mut _xmlNode) -> NodeSet {
992 let mut out = NodeSet::new();
993 let mut seen = false;
994 for n in nodes.iter() {
995 if n == node {
996 seen = true;
997 continue;
998 }
999 if seen {
1000 out.push(n);
1001 }
1002 }
1003 out
1004}
1005
1006#[no_mangle]
1012pub unsafe extern "C" fn xmlXPathLeading(
1013 nodes1: *mut _xmlNodeSet,
1014 nodes2: *mut _xmlNodeSet,
1015) -> *mut _xmlNodeSet {
1016 if nodes1.is_null() {
1017 return ptr::null_mut();
1018 }
1019 let mut a = unsafe { node_set_to_internal(nodes1) };
1020 a.sort();
1021 let b = unsafe { node_set_to_internal(nodes2) };
1022 if b.is_empty() {
1023 let raw = a.to_raw();
1024 return raw;
1025 }
1026 let first = b.first().unwrap();
1027 let out = unsafe { leading_nodes(&a, first) };
1028 out.to_raw()
1029}
1030
1031#[no_mangle]
1037pub unsafe extern "C" fn xmlXPathLeadingSorted(
1038 nodes1: *mut _xmlNodeSet,
1039 nodes2: *mut _xmlNodeSet,
1040) -> *mut _xmlNodeSet {
1041 unsafe { xmlXPathLeading(nodes1, nodes2) }
1042}
1043
1044#[no_mangle]
1050pub unsafe extern "C" fn xmlXPathTrailing(
1051 nodes1: *mut _xmlNodeSet,
1052 nodes2: *mut _xmlNodeSet,
1053) -> *mut _xmlNodeSet {
1054 if nodes1.is_null() {
1055 return ptr::null_mut();
1056 }
1057 let mut a = unsafe { node_set_to_internal(nodes1) };
1058 a.sort();
1059 let b = unsafe { node_set_to_internal(nodes2) };
1060 if b.is_empty() {
1061 return a.to_raw();
1062 }
1063 let last = b.last().unwrap();
1064 let out = unsafe { trailing_nodes(&a, last) };
1065 out.to_raw()
1066}
1067
1068#[no_mangle]
1074pub unsafe extern "C" fn xmlXPathTrailingSorted(
1075 nodes1: *mut _xmlNodeSet,
1076 nodes2: *mut _xmlNodeSet,
1077) -> *mut _xmlNodeSet {
1078 unsafe { xmlXPathTrailing(nodes1, nodes2) }
1079}
1080
1081#[no_mangle]
1087pub unsafe extern "C" fn xmlXPathNodeLeading(
1088 nodes: *mut _xmlNodeSet,
1089 node: *mut _xmlNode,
1090) -> *mut _xmlNodeSet {
1091 if nodes.is_null() {
1092 return ptr::null_mut();
1093 }
1094 let mut a = unsafe { node_set_to_internal(nodes) };
1095 a.sort();
1096 let out = unsafe { leading_nodes(&a, node) };
1097 out.to_raw()
1098}
1099
1100#[no_mangle]
1106pub unsafe extern "C" fn xmlXPathNodeLeadingSorted(
1107 nodes: *mut _xmlNodeSet,
1108 node: *mut _xmlNode,
1109) -> *mut _xmlNodeSet {
1110 unsafe { xmlXPathNodeLeading(nodes, node) }
1111}
1112
1113#[no_mangle]
1119pub unsafe extern "C" fn xmlXPathNodeTrailing(
1120 nodes: *mut _xmlNodeSet,
1121 node: *mut _xmlNode,
1122) -> *mut _xmlNodeSet {
1123 if nodes.is_null() {
1124 return ptr::null_mut();
1125 }
1126 let mut a = unsafe { node_set_to_internal(nodes) };
1127 a.sort();
1128 let out = unsafe { trailing_nodes(&a, node) };
1129 out.to_raw()
1130}
1131
1132#[no_mangle]
1138pub unsafe extern "C" fn xmlXPathNodeTrailingSorted(
1139 nodes: *mut _xmlNodeSet,
1140 node: *mut _xmlNode,
1141) -> *mut _xmlNodeSet {
1142 unsafe { xmlXPathNodeTrailing(nodes, node) }
1143}
1144
1145#[no_mangle]
1158pub unsafe extern "C" fn xmlXPathNodeSetFreeNs(ns: *mut _xmlNs) {
1159 unsafe {
1160 if ns.is_null() {
1161 return;
1162 }
1163 if (*ns).type_ != crate::abi::types::xmlElementType::XML_NAMESPACE_DECL as c_int {
1164 return;
1165 }
1166 if !(*ns).next.is_null()
1168 && (*(*ns).next).type_ != crate::abi::types::xmlElementType::XML_NAMESPACE_DECL as c_int
1169 {
1170 if !(*ns).href.is_null() {
1171 libc::free((*ns).href as *mut libc::c_void);
1172 }
1173 if !(*ns).prefix.is_null() {
1174 libc::free((*ns).prefix as *mut libc::c_void);
1175 }
1176 libc::free(ns as *mut libc::c_void);
1177 }
1178 }
1179}
1180
1181#[no_mangle]
1196pub unsafe extern "C" fn xmlXPathOrderDocElems(doc: *mut _xmlDoc) -> c_long {
1197 if doc.is_null() {
1198 return -1;
1199 }
1200 let mut count: c_long = 0;
1201 unsafe {
1202 let mut cur = (*doc).children;
1203 while !cur.is_null() {
1204 if (*cur).type_ == crate::abi::types::xmlElementType::XML_ELEMENT_NODE as c_int {
1205 count += 1;
1206 (*cur).content = (-count) as *mut xmlChar;
1210 if !(*cur).children.is_null() {
1211 cur = (*cur).children;
1212 continue;
1213 }
1214 }
1215 if !(*cur).next.is_null() {
1216 cur = (*cur).next;
1217 continue;
1218 }
1219 loop {
1220 cur = (*cur).parent;
1221 if cur.is_null() {
1222 break;
1223 }
1224 if cur == doc as *mut _xmlNode {
1225 cur = ptr::null_mut();
1226 break;
1227 }
1228 if !(*cur).next.is_null() {
1229 cur = (*cur).next;
1230 break;
1231 }
1232 }
1233 }
1234 }
1235 count
1236}
1237use std::collections::HashMap;
1238use std::ffi::{CStr, CString};
1239
1240use crate::abi::structs::_xmlAttr;
1241use crate::xml::validation::{get_id, is_xml_name_char, is_xml_name_start};
1242use crate::xml::xpath::context::XPathContext;
1243use crate::xml::xpath::parser_context::{
1244 cast_top_to_number, compare_values_impl, equal_values_impl, free_parser_context, new_bool,
1245 new_number, new_parser_context, pc_set_error, pop_boolean, pop_external, pop_node_set,
1246 pop_number, pop_string, value_pop, value_push, XmlXPathParserContext,
1247};
1248
1249unsafe fn pc_from(p: *mut c_void) -> *mut XmlXPathParserContext {
1253 p as *mut XmlXPathParserContext
1254}
1255
1256unsafe fn cstr_eq(a: *const xmlChar, b: *const xmlChar) -> bool {
1258 if a.is_null() || b.is_null() {
1259 return a == b;
1260 }
1261 let mut i = 0usize;
1262 loop {
1263 let ca = unsafe { *a.add(i) };
1264 let cb = unsafe { *b.add(i) };
1265 if ca != cb {
1266 return false;
1267 }
1268 if ca == 0 {
1269 return true;
1270 }
1271 i += 1;
1272 }
1273}
1274
1275unsafe fn is_blank_ch(c: xmlChar) -> bool {
1277 c == b' ' || c == b'\t' || c == b'\n' || c == b'\r'
1278}
1279
1280unsafe fn cast_top_to_string(pc: *mut XmlXPathParserContext) {
1286 unsafe {
1287 let val = (*pc).value;
1288 if val.is_null() {
1289 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
1290 return;
1291 }
1292 if (*val).type_ != xmlXPathObjectType::XPATH_STRING as c_int {
1293 let v = crate::abi::exports_xml2::object_to_xpathvalue_pub(val);
1294 let s = v.as_string();
1295 if !(*val).stringval.is_null() {
1296 xmlFreeImpl((*val).stringval as *mut c_void);
1297 }
1298 (*val).stringval = dup_rust_string(&s);
1299 (*val).type_ = xmlXPathObjectType::XPATH_STRING as c_int;
1300 }
1301 }
1302}
1303
1304unsafe fn cast_top_to_boolean(pc: *mut XmlXPathParserContext) {
1310 unsafe {
1311 let val = (*pc).value;
1312 if val.is_null() {
1313 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
1314 return;
1315 }
1316 if (*val).type_ != xmlXPathObjectType::XPATH_BOOLEAN as c_int {
1317 let v = crate::abi::exports_xml2::object_to_xpathvalue_pub(val);
1318 (*val).boolval = v.as_boolean() as c_int;
1319 (*val).type_ = xmlXPathObjectType::XPATH_BOOLEAN as c_int;
1320 }
1321 }
1322}
1323
1324unsafe fn check_arity(pc: *mut XmlXPathParserContext, n: c_int) -> bool {
1327 if pc.is_null() || (*pc).value_nr < n {
1328 pc_set_error(pc, crate::abi::types::XPATH_INVALID_ARITY as c_int);
1329 return false;
1330 }
1331 true
1332}
1333
1334unsafe fn scan_c_name(cur: *const xmlChar, nc: bool) -> usize {
1338 if cur.is_null() {
1339 return 0;
1340 }
1341 let mut i = 0usize;
1342 let mut first = true;
1343 loop {
1344 let b = unsafe { *cur.add(i) };
1345 if b == 0 {
1346 break;
1347 }
1348 if nc && b == b':' {
1349 break;
1350 }
1351 let (ch, adv): (char, usize) = if b < 0x80 {
1352 (b as char, 1)
1353 } else if b >= 0xC0 && b <= 0xDF {
1354 (
1355 unsafe {
1356 char::from_u32_unchecked(
1357 ((b as u32 & 0x1F) << 6) | (*cur.add(i + 1) as u32 & 0x3F),
1358 )
1359 },
1360 2,
1361 )
1362 } else if b >= 0xE0 && b <= 0xEF {
1363 (
1364 unsafe {
1365 char::from_u32_unchecked(
1366 ((b as u32 & 0x0F) << 12)
1367 | ((*cur.add(i + 1) as u32 & 0x3F) << 6)
1368 | (*cur.add(i + 2) as u32 & 0x3F),
1369 )
1370 },
1371 3,
1372 )
1373 } else if b >= 0xF0 && b <= 0xF7 {
1374 (
1375 unsafe {
1376 char::from_u32_unchecked(
1377 ((b as u32 & 0x07) << 18)
1378 | ((*cur.add(i + 1) as u32 & 0x3F) << 12)
1379 | ((*cur.add(i + 2) as u32 & 0x3F) << 6)
1380 | (*cur.add(i + 3) as u32 & 0x3F),
1381 )
1382 },
1383 4,
1384 )
1385 } else {
1386 break;
1387 };
1388 let ok = if first {
1389 is_xml_name_start(ch)
1390 } else {
1391 is_xml_name_char(ch)
1392 };
1393 if !ok {
1394 break;
1395 }
1396 first = false;
1397 i += adv;
1398 }
1399 i
1400}
1401
1402unsafe fn cstr_find(hay: *const xmlChar, needle: *const xmlChar) -> *const xmlChar {
1404 if hay.is_null() || needle.is_null() {
1405 return ptr::null();
1406 }
1407 if unsafe { *needle } == 0 {
1408 return hay;
1409 }
1410 let hlen = unsafe { crate::xml::string::xml_strlen(hay) };
1411 let nlen = unsafe { crate::xml::string::xml_strlen(needle) };
1412 if nlen > hlen {
1413 return ptr::null();
1414 }
1415 let hay_b = unsafe { core::slice::from_raw_parts(hay as *const u8, hlen) };
1416 let needle_b = unsafe { core::slice::from_raw_parts(needle as *const u8, nlen) };
1417 for off in 0..=hlen - nlen {
1418 if &hay_b[off..off + nlen] == needle_b {
1419 return unsafe { hay.add(off) };
1420 }
1421 }
1422 ptr::null()
1423}
1424
1425const XML_XML_NAMESPACE_BYTES: &[u8] = b"http://www.w3.org/XML/1998/namespace\0";
1427
1428struct XmlXPathXmlNs(_xmlNs);
1432unsafe impl Sync for XmlXPathXmlNs {}
1433static XML_XPATH_XML_NS: XmlXPathXmlNs = XmlXPathXmlNs(crate::abi::structs::_xmlNs {
1434 next: ptr::null_mut(),
1435 type_: crate::abi::types::xmlElementType::XML_NAMESPACE_DECL as c_int,
1436 href: XML_XML_NAMESPACE_BYTES.as_ptr() as *const xmlChar,
1437 prefix: b"xml\0".as_ptr() as *const xmlChar,
1438 _private: ptr::null_mut(),
1439 context: ptr::null_mut(),
1440});
1441
1442#[no_mangle]
1456pub unsafe extern "C" fn xmlXPathValuePush(
1457 ctxt: *mut c_void,
1458 value: *mut _xmlXPathObject,
1459) -> *mut _xmlXPathObject {
1460 value_push(pc_from(ctxt), value)
1461}
1462
1463#[no_mangle]
1469pub unsafe extern "C" fn xmlXPathValuePop(ctxt: *mut c_void) -> *mut _xmlXPathObject {
1470 value_pop(pc_from(ctxt))
1471}
1472
1473#[no_mangle]
1479pub unsafe extern "C" fn xmlXPathPopBoolean(ctxt: *mut c_void) -> c_int {
1480 pop_boolean(pc_from(ctxt))
1481}
1482
1483#[no_mangle]
1489pub unsafe extern "C" fn xmlXPathPopExternal(ctxt: *mut c_void) -> *mut c_void {
1490 pop_external(pc_from(ctxt))
1491}
1492
1493#[no_mangle]
1499pub unsafe extern "C" fn xmlXPathPopNodeSet(ctxt: *mut c_void) -> *mut _xmlNodeSet {
1500 pop_node_set(pc_from(ctxt))
1501}
1502
1503#[no_mangle]
1509pub unsafe extern "C" fn xmlXPathPopNumber(ctxt: *mut c_void) -> c_double {
1510 pop_number(pc_from(ctxt))
1511}
1512
1513#[no_mangle]
1519pub unsafe extern "C" fn xmlXPathPopString(ctxt: *mut c_void) -> *mut xmlChar {
1520 pop_string(pc_from(ctxt))
1521}
1522
1523unsafe fn binary_inplace(ctxt: *mut c_void, op: impl Fn(&mut f64, f64)) {
1528 let pc = pc_from(ctxt);
1529 if pc.is_null() {
1530 return;
1531 }
1532 let arg = value_pop(pc);
1533 if arg.is_null() {
1534 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
1535 return;
1536 }
1537 let val = crate::abi::exports_xml2::object_to_xpathvalue_pub(arg).as_number();
1538 crate::abi::exports_xml2::xmlXPathFreeObject(arg);
1539 if unsafe { (*pc).value.is_null() } {
1540 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
1541 return;
1542 }
1543 cast_top_to_number(pc);
1544 if (*pc).error != 0 {
1545 return;
1546 }
1547 unsafe {
1551 let float_ref: &mut f64 = &mut (*(*pc).value).floatval;
1552 op(float_ref, val);
1553 }
1554}
1555
1556#[no_mangle]
1558pub unsafe extern "C" fn xmlXPathAddValues(ctxt: *mut c_void) {
1559 binary_inplace(ctxt, |x, v| *x += v);
1560}
1561
1562#[no_mangle]
1564pub unsafe extern "C" fn xmlXPathSubValues(ctxt: *mut c_void) {
1565 binary_inplace(ctxt, |x, v| *x -= v);
1566}
1567
1568#[no_mangle]
1570pub unsafe extern "C" fn xmlXPathMultValues(ctxt: *mut c_void) {
1571 binary_inplace(ctxt, |x, v| *x *= v);
1572}
1573
1574#[no_mangle]
1576pub unsafe extern "C" fn xmlXPathDivValues(ctxt: *mut c_void) {
1577 binary_inplace(ctxt, |x, v| *x /= v);
1578}
1579
1580#[no_mangle]
1582pub unsafe extern "C" fn xmlXPathModValues(ctxt: *mut c_void) {
1583 binary_inplace(ctxt, |x, v| *x %= v);
1584}
1585
1586#[no_mangle]
1588pub unsafe extern "C" fn xmlXPathValueFlipSign(ctxt: *mut c_void) {
1589 let pc = pc_from(ctxt);
1590 if pc.is_null() {
1591 return;
1592 }
1593 cast_top_to_number(pc);
1594 if (*pc).error != 0 {
1595 return;
1596 }
1597 unsafe { (*(*pc).value).floatval = -(*(*pc).value).floatval };
1598}
1599
1600#[no_mangle]
1603pub unsafe extern "C" fn xmlXPathEqualValues(ctxt: *mut c_void) -> c_int {
1604 equal_values_impl(pc_from(ctxt), false)
1605}
1606
1607#[no_mangle]
1609pub unsafe extern "C" fn xmlXPathNotEqualValues(ctxt: *mut c_void) -> c_int {
1610 equal_values_impl(pc_from(ctxt), true)
1611}
1612
1613#[no_mangle]
1619pub unsafe extern "C" fn xmlXPathCompareValues(
1620 ctxt: *mut c_void,
1621 inf: c_int,
1622 strict: c_int,
1623) -> c_int {
1624 compare_values_impl(pc_from(ctxt), inf != 0, strict != 0)
1625}
1626
1627#[no_mangle]
1638pub unsafe extern "C" fn xmlXPathNewParserContext(
1639 str_: *const xmlChar,
1640 ctxt: *mut _xmlXPathContext,
1641) -> *mut c_void {
1642 new_parser_context(str_, ctxt) as *mut c_void
1643}
1644
1645#[no_mangle]
1651pub unsafe extern "C" fn xmlXPathFreeParserContext(ctxt: *mut c_void) {
1652 free_parser_context(pc_from(ctxt));
1653}
1654
1655#[no_mangle]
1662pub unsafe extern "C" fn xmlXPathParseNCName(ctxt: *mut c_void) -> *mut xmlChar {
1663 let pc = pc_from(ctxt);
1664 if pc.is_null() {
1665 return ptr::null_mut();
1666 }
1667 let cur = unsafe { (*pc).cur };
1668 if cur.is_null() {
1669 return ptr::null_mut();
1670 }
1671 let len = scan_c_name(cur, true);
1672 if len == 0 {
1673 return ptr::null_mut();
1674 }
1675 let ret = crate::xml::string::xml_strndup(cur, len);
1676 unsafe { (*pc).cur = cur.add(len) };
1677 ret
1678}
1679
1680#[no_mangle]
1687pub unsafe extern "C" fn xmlXPathParseName(ctxt: *mut c_void) -> *mut xmlChar {
1688 let pc = pc_from(ctxt);
1689 if pc.is_null() {
1690 return ptr::null_mut();
1691 }
1692 let cur = unsafe { (*pc).cur };
1693 if cur.is_null() {
1694 return ptr::null_mut();
1695 }
1696 let len = scan_c_name(cur, false);
1697 if len == 0 {
1698 return ptr::null_mut();
1699 }
1700 let ret = crate::xml::string::xml_strndup(cur, len);
1701 unsafe { (*pc).cur = cur.add(len) };
1702 ret
1703}
1704
1705#[no_mangle]
1712pub unsafe extern "C" fn xmlXPathRoot(ctxt: *mut c_void) {
1713 let pc = pc_from(ctxt);
1714 if pc.is_null() {
1715 return;
1716 }
1717 let ctx = unsafe { (*pc).context };
1718 if ctx.is_null() {
1719 return;
1720 }
1721 let ns = NodeSet::singleton(unsafe { (*ctx).doc } as *mut _xmlNode);
1722 let obj = crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(ns));
1723 value_push(pc, obj);
1724}
1725
1726#[no_mangle]
1734pub unsafe extern "C" fn xmlXPathEvalExpr(ctxt: *mut c_void) {
1735 let pc = pc_from(ctxt);
1736 if pc.is_null() {
1737 return;
1738 }
1739 let ctx = unsafe { (*pc).context };
1740 if ctx.is_null() {
1741 return;
1742 }
1743 let base = unsafe { (*pc).base };
1744 if base.is_null() {
1745 return;
1746 }
1747 let expr_str = match CStr::from_ptr(base as *const c_char).to_str() {
1748 Ok(s) => s,
1749 Err(_) => {
1750 pc_set_error(pc, crate::abi::types::XPATH_EXPR_ERROR as c_int);
1751 return;
1752 }
1753 };
1754 let internal = unsafe { (*ctx).extra } as *mut XPathContext;
1755 if internal.is_null() {
1756 return;
1757 }
1758 let internal = unsafe { &mut *internal };
1759 match crate::xml::xpath::evaluate_str(expr_str, internal) {
1760 Some(val) => {
1761 let obj = crate::abi::exports_xml2::xpath_to_object_pub(val);
1762 value_push(pc, obj);
1763 }
1764 None => {
1765 pc_set_error(pc, crate::abi::types::XPATH_EXPR_ERROR as c_int);
1766 }
1767 }
1768}
1769
1770unsafe fn eval_predicate_result(ctxt: *mut _xmlXPathContext, res: *mut _xmlXPathObject) -> c_int {
1772 if ctxt.is_null() || res.is_null() {
1773 return 0;
1774 }
1775 unsafe {
1776 let t = (*res).type_;
1777 if t == xmlXPathObjectType::XPATH_BOOLEAN as c_int {
1778 (*res).boolval
1779 } else if t == xmlXPathObjectType::XPATH_NUMBER as c_int {
1780 ((*res).floatval == (*ctxt).proximityPosition as f64) as c_int
1781 } else if t == xmlXPathObjectType::XPATH_NODESET as c_int
1782 || t == xmlXPathObjectType::XPATH_XSLT_TREE as c_int
1783 {
1784 let nsp = (*res).nodesetval as *mut _xmlNodeSet;
1785 if nsp.is_null() || (*nsp).nodeNr == 0 {
1786 0
1787 } else {
1788 1
1789 }
1790 } else if t == xmlXPathObjectType::XPATH_STRING as c_int {
1791 if (*res).stringval.is_null() || *(*res).stringval == 0 {
1792 0
1793 } else {
1794 1
1795 }
1796 } else {
1797 0
1798 }
1799 }
1800}
1801
1802#[no_mangle]
1809pub unsafe extern "C" fn xmlXPathEvalPredicate(
1810 ctxt: *mut _xmlXPathContext,
1811 res: *mut _xmlXPathObject,
1812) -> c_int {
1813 eval_predicate_result(ctxt, res)
1814}
1815
1816#[no_mangle]
1822pub unsafe extern "C" fn xmlXPathEvaluatePredicateResult(
1823 ctxt: *mut c_void,
1824 res: *mut _xmlXPathObject,
1825) -> c_int {
1826 let pc = pc_from(ctxt);
1827 if pc.is_null() {
1828 return 0;
1829 }
1830 let ctx = unsafe { (*pc).context };
1831 eval_predicate_result(ctx, res)
1832}
1833
1834#[no_mangle]
1840pub unsafe extern "C" fn xmlXPathNextSelf(ctxt: *mut c_void, cur: *mut _xmlNode) -> *mut _xmlNode {
1841 let pc = pc_from(ctxt);
1842 if pc.is_null() {
1843 return ptr::null_mut();
1844 }
1845 let ctx = unsafe { (*pc).context };
1846 if ctx.is_null() {
1847 return ptr::null_mut();
1848 }
1849 if cur.is_null() {
1850 return unsafe { (*ctx).node };
1851 }
1852 ptr::null_mut()
1853}
1854
1855#[no_mangle]
1857pub unsafe extern "C" fn xmlXPathNextChild(ctxt: *mut c_void, cur: *mut _xmlNode) -> *mut _xmlNode {
1858 let pc = pc_from(ctxt);
1859 if pc.is_null() {
1860 return ptr::null_mut();
1861 }
1862 let ctx = unsafe { (*pc).context };
1863 if ctx.is_null() {
1864 return ptr::null_mut();
1865 }
1866 use crate::abi::types::xmlElementType as ET;
1867 if cur.is_null() {
1868 let node = unsafe { (*ctx).node };
1869 if node.is_null() {
1870 return ptr::null_mut();
1871 }
1872 return match unsafe { (*node).type_ } {
1873 t if t == ET::XML_ELEMENT_NODE as c_int
1874 || t == ET::XML_TEXT_NODE as c_int
1875 || t == ET::XML_CDATA_SECTION_NODE as c_int
1876 || t == ET::XML_ENTITY_REF_NODE as c_int
1877 || t == ET::XML_ENTITY_NODE as c_int
1878 || t == ET::XML_PI_NODE as c_int
1879 || t == ET::XML_COMMENT_NODE as c_int
1880 || t == ET::XML_NOTATION_NODE as c_int
1881 || t == ET::XML_DTD_NODE as c_int =>
1882 unsafe { (*node).children },
1883 t if t == ET::XML_DOCUMENT_NODE as c_int
1884 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
1885 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
1886 || t == ET::XML_HTML_DOCUMENT_NODE as c_int =>
1887 unsafe { (*(node as *mut _xmlDoc)).children },
1888 _ => ptr::null_mut(),
1889 };
1890 }
1891 let t = unsafe { (*cur).type_ };
1892 if t == ET::XML_DOCUMENT_NODE as c_int || t == ET::XML_HTML_DOCUMENT_NODE as c_int {
1893 return ptr::null_mut();
1894 }
1895 unsafe { (*cur).next }
1896}
1897
1898#[no_mangle]
1900pub unsafe extern "C" fn xmlXPathNextDescendant(
1901 ctxt: *mut c_void,
1902 mut cur: *mut _xmlNode,
1903) -> *mut _xmlNode {
1904 let pc = pc_from(ctxt);
1905 if pc.is_null() {
1906 return ptr::null_mut();
1907 }
1908 let ctx = unsafe { (*pc).context };
1909 if ctx.is_null() {
1910 return ptr::null_mut();
1911 }
1912 use crate::abi::types::xmlElementType as ET;
1913 if cur.is_null() {
1914 let node = unsafe { (*ctx).node };
1915 if node.is_null() {
1916 return ptr::null_mut();
1917 }
1918 let t = unsafe { (*node).type_ };
1919 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
1920 return ptr::null_mut();
1921 }
1922 if node == unsafe { (*ctx).doc } as *mut _xmlNode {
1923 return unsafe { (*(*ctx).doc).children };
1924 }
1925 return unsafe { (*node).children };
1926 }
1927 unsafe {
1928 if (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
1929 return ptr::null_mut();
1930 }
1931 if !(*cur).children.is_null() {
1932 if (*(*cur).children).type_ != ET::XML_ENTITY_DECL as c_int {
1933 cur = (*cur).children;
1934 if (*cur).type_ != ET::XML_DTD_NODE as c_int {
1935 return cur;
1936 }
1937 }
1938 }
1939 if cur == (*ctx).node {
1940 return ptr::null_mut();
1941 }
1942 while !(*cur).next.is_null() {
1943 cur = (*cur).next;
1944 if (*cur).type_ != ET::XML_ENTITY_DECL as c_int
1945 && (*cur).type_ != ET::XML_DTD_NODE as c_int
1946 {
1947 return cur;
1948 }
1949 }
1950 loop {
1951 cur = (*cur).parent;
1952 if cur.is_null() {
1953 break;
1954 }
1955 if cur == (*ctx).node {
1956 return ptr::null_mut();
1957 }
1958 if !(*cur).next.is_null() {
1959 cur = (*cur).next;
1960 return cur;
1961 }
1962 }
1963 cur
1964 }
1965}
1966
1967#[no_mangle]
1969pub unsafe extern "C" fn xmlXPathNextDescendantOrSelf(
1970 ctxt: *mut c_void,
1971 cur: *mut _xmlNode,
1972) -> *mut _xmlNode {
1973 let pc = pc_from(ctxt);
1974 if pc.is_null() {
1975 return ptr::null_mut();
1976 }
1977 let ctx = unsafe { (*pc).context };
1978 if ctx.is_null() {
1979 return ptr::null_mut();
1980 }
1981 if cur.is_null() {
1982 return unsafe { (*ctx).node };
1983 }
1984 let node = unsafe { (*ctx).node };
1985 if node.is_null() {
1986 return ptr::null_mut();
1987 }
1988 use crate::abi::types::xmlElementType as ET;
1989 let t = unsafe { (*node).type_ };
1990 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
1991 return ptr::null_mut();
1992 }
1993 xmlXPathNextDescendant(ctxt, cur)
1994}
1995
1996#[no_mangle]
1998pub unsafe extern "C" fn xmlXPathNextParent(
1999 ctxt: *mut c_void,
2000 cur: *mut _xmlNode,
2001) -> *mut _xmlNode {
2002 let pc = pc_from(ctxt);
2003 if pc.is_null() {
2004 return ptr::null_mut();
2005 }
2006 let ctx = unsafe { (*pc).context };
2007 if ctx.is_null() {
2008 return ptr::null_mut();
2009 }
2010 if !cur.is_null() {
2011 return ptr::null_mut();
2012 }
2013 next_parent_impl(ctx)
2014}
2015
2016unsafe fn next_parent_impl(ctx: *mut _xmlXPathContext) -> *mut _xmlNode {
2018 use crate::abi::types::xmlElementType as ET;
2019 let node = unsafe { (*ctx).node };
2020 if node.is_null() {
2021 return ptr::null_mut();
2022 }
2023 match unsafe { (*node).type_ } {
2024 t if t == ET::XML_ELEMENT_NODE as c_int
2025 || t == ET::XML_TEXT_NODE as c_int
2026 || t == ET::XML_CDATA_SECTION_NODE as c_int
2027 || t == ET::XML_ENTITY_REF_NODE as c_int
2028 || t == ET::XML_ENTITY_NODE as c_int
2029 || t == ET::XML_PI_NODE as c_int
2030 || t == ET::XML_COMMENT_NODE as c_int
2031 || t == ET::XML_NOTATION_NODE as c_int
2032 || t == ET::XML_DTD_NODE as c_int
2033 || t == ET::XML_ELEMENT_DECL as c_int
2034 || t == ET::XML_ATTRIBUTE_DECL as c_int
2035 || t == ET::XML_ENTITY_DECL as c_int
2036 || t == ET::XML_XINCLUDE_START as c_int
2037 || t == ET::XML_XINCLUDE_END as c_int =>
2038 unsafe {
2039 let parent = (*node).parent;
2040 if parent.is_null() {
2041 return (*ctx).doc as *mut _xmlNode;
2042 }
2043 if (*parent).type_ == ET::XML_ELEMENT_NODE as c_int
2044 && ((*parent).name.is_null() || *(*parent).name == b' ')
2045 {
2046 return ptr::null_mut();
2047 }
2048 parent
2049 },
2050 t if t == ET::XML_ATTRIBUTE_NODE as c_int => unsafe { (*(node as *mut _xmlAttr)).parent },
2051 t if t == ET::XML_DOCUMENT_NODE as c_int
2052 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2053 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2054 || t == ET::XML_HTML_DOCUMENT_NODE as c_int =>
2055 {
2056 ptr::null_mut()
2057 }
2058 t if t == ET::XML_NAMESPACE_DECL as c_int => unsafe {
2059 let ns = node as *mut crate::abi::structs::_xmlNs;
2060 if !(*ns).next.is_null() && (*(*ns).next).type_ != ET::XML_NAMESPACE_DECL as c_int {
2061 (*ns).next as *mut _xmlNode
2062 } else {
2063 ptr::null_mut()
2064 }
2065 },
2066 _ => ptr::null_mut(),
2067 }
2068}
2069
2070#[no_mangle]
2072pub unsafe extern "C" fn xmlXPathNextAncestor(
2073 ctxt: *mut c_void,
2074 cur: *mut _xmlNode,
2075) -> *mut _xmlNode {
2076 let pc = pc_from(ctxt);
2077 if pc.is_null() {
2078 return ptr::null_mut();
2079 }
2080 let ctx = unsafe { (*pc).context };
2081 if ctx.is_null() {
2082 return ptr::null_mut();
2083 }
2084 use crate::abi::types::xmlElementType as ET;
2085 if cur.is_null() {
2086 let node = unsafe { (*ctx).node };
2087 if node.is_null() {
2088 return ptr::null_mut();
2089 }
2090 let t = unsafe { (*node).type_ };
2091 if t == ET::XML_ATTRIBUTE_NODE as c_int {
2092 return unsafe { (*(node as *mut _xmlAttr)).parent };
2093 }
2094 if t == ET::XML_NAMESPACE_DECL as c_int {
2095 let ns = node as *mut crate::abi::structs::_xmlNs;
2096 return unsafe {
2097 if !(*ns).next.is_null() && (*(*ns).next).type_ != ET::XML_NAMESPACE_DECL as c_int {
2098 (*ns).next as *mut _xmlNode
2099 } else {
2100 ptr::null_mut()
2101 }
2102 };
2103 }
2104 if t == ET::XML_DOCUMENT_NODE as c_int
2105 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2106 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2107 || t == ET::XML_HTML_DOCUMENT_NODE as c_int
2108 {
2109 return ptr::null_mut();
2110 }
2111 return next_parent_impl(ctx);
2113 }
2114 if cur == unsafe { (*ctx).doc } as *mut _xmlNode {
2115 return ptr::null_mut();
2116 }
2117 if cur == unsafe { (*(*ctx).doc).children } {
2118 return unsafe { (*ctx).doc } as *mut _xmlNode;
2119 }
2120 let t = unsafe { (*cur).type_ };
2121 if t == ET::XML_ATTRIBUTE_NODE as c_int {
2122 return unsafe { (*(cur as *mut _xmlAttr)).parent };
2123 }
2124 if t == ET::XML_NAMESPACE_DECL as c_int {
2125 let ns = cur as *mut crate::abi::structs::_xmlNs;
2126 return unsafe {
2127 if !(*ns).next.is_null() && (*(*ns).next).type_ != ET::XML_NAMESPACE_DECL as c_int {
2128 (*ns).next as *mut _xmlNode
2129 } else {
2130 ptr::null_mut()
2131 }
2132 };
2133 }
2134 if t == ET::XML_DOCUMENT_NODE as c_int
2135 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2136 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2137 || t == ET::XML_HTML_DOCUMENT_NODE as c_int
2138 {
2139 return ptr::null_mut();
2140 }
2141 unsafe {
2142 let parent = (*cur).parent;
2143 if parent.is_null() {
2144 return ptr::null_mut();
2145 }
2146 if (*parent).type_ == ET::XML_ELEMENT_NODE as c_int
2147 && ((*parent).name.is_null() || *(*parent).name == b' ')
2148 {
2149 return ptr::null_mut();
2150 }
2151 parent
2152 }
2153}
2154
2155#[no_mangle]
2157pub unsafe extern "C" fn xmlXPathNextAncestorOrSelf(
2158 ctxt: *mut c_void,
2159 cur: *mut _xmlNode,
2160) -> *mut _xmlNode {
2161 let pc = pc_from(ctxt);
2162 if pc.is_null() {
2163 return ptr::null_mut();
2164 }
2165 let ctx = unsafe { (*pc).context };
2166 if ctx.is_null() {
2167 return ptr::null_mut();
2168 }
2169 if cur.is_null() {
2170 return unsafe { (*ctx).node };
2171 }
2172 xmlXPathNextAncestor(ctxt, cur)
2173}
2174
2175#[no_mangle]
2177pub unsafe extern "C" fn xmlXPathNextFollowingSibling(
2178 ctxt: *mut c_void,
2179 mut cur: *mut _xmlNode,
2180) -> *mut _xmlNode {
2181 let pc = pc_from(ctxt);
2182 if pc.is_null() {
2183 return ptr::null_mut();
2184 }
2185 let ctx = unsafe { (*pc).context };
2186 if ctx.is_null() {
2187 return ptr::null_mut();
2188 }
2189 use crate::abi::types::xmlElementType as ET;
2190 unsafe {
2191 let cnode = (*ctx).node;
2192 if !cnode.is_null() {
2193 let t = (*cnode).type_;
2194 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
2195 return ptr::null_mut();
2196 }
2197 }
2198 if cur == (*ctx).doc as *mut _xmlNode {
2199 return ptr::null_mut();
2200 }
2201 if cur.is_null() {
2202 cur = cnode;
2203 }
2204 if cur.is_null() {
2205 return ptr::null_mut();
2206 }
2207 if (*cur).type_ == ET::XML_DOCUMENT_NODE as c_int {
2208 return ptr::null_mut();
2209 }
2210 (*cur).next
2211 }
2212}
2213
2214#[no_mangle]
2216pub unsafe extern "C" fn xmlXPathNextPrecedingSibling(
2217 ctxt: *mut c_void,
2218 mut cur: *mut _xmlNode,
2219) -> *mut _xmlNode {
2220 let pc = pc_from(ctxt);
2221 if pc.is_null() {
2222 return ptr::null_mut();
2223 }
2224 let ctx = unsafe { (*pc).context };
2225 if ctx.is_null() {
2226 return ptr::null_mut();
2227 }
2228 use crate::abi::types::xmlElementType as ET;
2229 unsafe {
2230 let cnode = (*ctx).node;
2231 if !cnode.is_null() {
2232 let t = (*cnode).type_;
2233 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
2234 return ptr::null_mut();
2235 }
2236 }
2237 if cur == (*ctx).doc as *mut _xmlNode {
2238 return ptr::null_mut();
2239 }
2240 if cur.is_null() {
2241 cur = cnode;
2242 } else if !(*cur).prev.is_null() && (*(*cur).prev).type_ == ET::XML_DTD_NODE as c_int {
2243 cur = (*cur).prev;
2244 if cur.is_null() {
2245 return ptr::null_mut();
2246 }
2247 }
2248 if cur.is_null() {
2249 return ptr::null_mut();
2250 }
2251 if (*cur).type_ == ET::XML_DOCUMENT_NODE as c_int {
2252 return ptr::null_mut();
2253 }
2254 (*cur).prev
2255 }
2256}
2257
2258#[no_mangle]
2260pub unsafe extern "C" fn xmlXPathNextFollowing(
2261 ctxt: *mut c_void,
2262 mut cur: *mut _xmlNode,
2263) -> *mut _xmlNode {
2264 let pc = pc_from(ctxt);
2265 if pc.is_null() {
2266 return ptr::null_mut();
2267 }
2268 let ctx = unsafe { (*pc).context };
2269 if ctx.is_null() {
2270 return ptr::null_mut();
2271 }
2272 use crate::abi::types::xmlElementType as ET;
2273 unsafe {
2274 if !cur.is_null()
2275 && (*cur).type_ != ET::XML_ATTRIBUTE_NODE as c_int
2276 && (*cur).type_ != ET::XML_NAMESPACE_DECL as c_int
2277 && !(*cur).children.is_null()
2278 {
2279 return (*cur).children;
2280 }
2281 if cur.is_null() {
2282 cur = (*ctx).node;
2283 if cur.is_null() {
2284 return ptr::null_mut();
2285 }
2286 if (*cur).type_ == ET::XML_ATTRIBUTE_NODE as c_int {
2287 cur = (*cur).parent;
2288 } else if (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2289 let ns = cur as *mut crate::abi::structs::_xmlNs;
2290 if (*ns).next.is_null() || (*(*ns).next).type_ == ET::XML_NAMESPACE_DECL as c_int {
2291 return ptr::null_mut();
2292 }
2293 cur = (*ns).next as *mut _xmlNode;
2294 }
2295 }
2296 if cur.is_null() {
2297 return ptr::null_mut();
2298 }
2299 if (*cur).type_ == ET::XML_DOCUMENT_NODE as c_int {
2300 return ptr::null_mut();
2301 }
2302 if !(*cur).next.is_null() {
2303 return (*cur).next;
2304 }
2305 loop {
2306 cur = (*cur).parent;
2307 if cur.is_null() {
2308 break;
2309 }
2310 if cur == (*ctx).doc as *mut _xmlNode {
2311 return ptr::null_mut();
2312 }
2313 if !(*cur).next.is_null() && (*cur).type_ != ET::XML_DOCUMENT_NODE as c_int {
2314 return (*cur).next;
2315 }
2316 }
2317 cur
2318 }
2319}
2320
2321#[no_mangle]
2323pub unsafe extern "C" fn xmlXPathNextPreceding(
2324 ctxt: *mut c_void,
2325 mut cur: *mut _xmlNode,
2326) -> *mut _xmlNode {
2327 let pc = pc_from(ctxt);
2328 if pc.is_null() {
2329 return ptr::null_mut();
2330 }
2331 let ctx = unsafe { (*pc).context };
2332 if ctx.is_null() {
2333 return ptr::null_mut();
2334 }
2335 use crate::abi::types::xmlElementType as ET;
2336 unsafe {
2337 let is_ancestor = |ancestor: *mut _xmlNode, node: *mut _xmlNode| -> bool {
2338 if ancestor.is_null() || node.is_null() {
2339 return false;
2340 }
2341 if (*node).type_ == ET::XML_NAMESPACE_DECL as c_int
2342 || (*ancestor).type_ == ET::XML_NAMESPACE_DECL as c_int
2343 {
2344 return false;
2345 }
2346 if (*ancestor).doc != (*node).doc {
2347 return false;
2348 }
2349 if ancestor == (*node).doc as *mut _xmlNode {
2350 return true;
2351 }
2352 if node == (*ancestor).doc as *mut _xmlNode {
2353 return false;
2354 }
2355 let mut n = node;
2356 while !(*n).parent.is_null() {
2357 if (*n).parent == ancestor {
2358 return true;
2359 }
2360 n = (*n).parent;
2361 }
2362 false
2363 };
2364 if cur.is_null() {
2365 cur = (*ctx).node;
2366 if cur.is_null() {
2367 return ptr::null_mut();
2368 }
2369 if (*cur).type_ == ET::XML_ATTRIBUTE_NODE as c_int {
2370 cur = (*cur).parent;
2371 } else if (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2372 let ns = cur as *mut crate::abi::structs::_xmlNs;
2373 if (*ns).next.is_null() || (*(*ns).next).type_ == ET::XML_NAMESPACE_DECL as c_int {
2374 return ptr::null_mut();
2375 }
2376 cur = (*ns).next as *mut _xmlNode;
2377 }
2378 }
2379 if cur.is_null() || (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2380 return ptr::null_mut();
2381 }
2382 if !(*cur).prev.is_null() && (*(*cur).prev).type_ == ET::XML_DTD_NODE as c_int {
2383 cur = (*cur).prev;
2384 }
2385 loop {
2386 if !(*cur).prev.is_null() {
2387 let mut n = (*cur).prev;
2388 while !(*n).last.is_null() {
2389 n = (*n).last;
2390 }
2391 return n;
2392 }
2393 cur = (*cur).parent;
2394 if cur.is_null() {
2395 return ptr::null_mut();
2396 }
2397 if cur == (*(*ctx).doc).children {
2398 return ptr::null_mut();
2399 }
2400 if !is_ancestor(cur, (*ctx).node) {
2401 return cur;
2402 }
2403 }
2404 }
2405}
2406
2407#[no_mangle]
2409pub unsafe extern "C" fn xmlXPathNextNamespace(
2410 ctxt: *mut c_void,
2411 cur: *mut _xmlNode,
2412) -> *mut _xmlNode {
2413 let pc = pc_from(ctxt);
2414 if pc.is_null() {
2415 return ptr::null_mut();
2416 }
2417 let ctx = unsafe { (*pc).context };
2418 if ctx.is_null() {
2419 return ptr::null_mut();
2420 }
2421 use crate::abi::types::xmlElementType as ET;
2422 unsafe {
2423 let cnode = (*ctx).node;
2424 if cnode.is_null() || (*cnode).type_ != ET::XML_ELEMENT_NODE as c_int {
2425 return ptr::null_mut();
2426 }
2427 if cur.is_null() {
2428 if !(*ctx).tmpNsList.is_null() {
2429 xmlFreeImpl((*ctx).tmpNsList as *mut c_void);
2430 }
2431 (*ctx).tmpNsNr = 0;
2432 (*ctx).tmpNsList = crate::xml::tree::get_ns_list((*ctx).doc, cnode);
2433 if !(*ctx).tmpNsList.is_null() {
2434 while !(*(*ctx).tmpNsList.add((*ctx).tmpNsNr as usize)).is_null() {
2435 (*ctx).tmpNsNr += 1;
2436 }
2437 }
2438 return (&XML_XPATH_XML_NS.0) as *const crate::abi::structs::_xmlNs as *mut _xmlNode;
2439 }
2440 if (*ctx).tmpNsNr > 0 {
2441 (*ctx).tmpNsNr -= 1;
2442 return (*(*ctx).tmpNsList.add((*ctx).tmpNsNr as usize)) as *mut _xmlNode;
2443 }
2444 if !(*ctx).tmpNsList.is_null() {
2445 xmlFreeImpl((*ctx).tmpNsList as *mut c_void);
2446 }
2447 (*ctx).tmpNsList = ptr::null_mut();
2448 ptr::null_mut()
2449 }
2450}
2451
2452#[no_mangle]
2454pub unsafe extern "C" fn xmlXPathNextAttribute(
2455 ctxt: *mut c_void,
2456 cur: *mut _xmlNode,
2457) -> *mut _xmlNode {
2458 let pc = pc_from(ctxt);
2459 if pc.is_null() {
2460 return ptr::null_mut();
2461 }
2462 let ctx = unsafe { (*pc).context };
2463 if ctx.is_null() {
2464 return ptr::null_mut();
2465 }
2466 use crate::abi::types::xmlElementType as ET;
2467 unsafe {
2468 let cnode = (*ctx).node;
2469 if cnode.is_null() || (*cnode).type_ != ET::XML_ELEMENT_NODE as c_int {
2470 return ptr::null_mut();
2471 }
2472 if cur.is_null() {
2473 if cnode == (*ctx).doc as *mut _xmlNode {
2474 return ptr::null_mut();
2475 }
2476 return (*cnode).properties as *mut _xmlNode;
2477 }
2478 (*cur).next
2479 }
2480}
2481
2482#[no_mangle]
2488pub unsafe extern "C" fn xmlXPathBooleanFunction(ctxt: *mut c_void, _nargs: c_int) {
2489 let pc = pc_from(ctxt);
2490 if pc.is_null() {
2491 return;
2492 }
2493 if !check_arity(pc, 1) {
2494 return;
2495 }
2496 let cur = value_pop(pc);
2497 if cur.is_null() {
2498 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
2499 return;
2500 }
2501 let b = crate::abi::exports_xml2::object_to_xpathvalue_pub(cur).as_boolean();
2502 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
2503 value_push(pc, new_bool(b));
2504}
2505
2506#[no_mangle]
2508pub unsafe extern "C" fn xmlXPathNotFunction(ctxt: *mut c_void, _nargs: c_int) {
2509 let pc = pc_from(ctxt);
2510 if pc.is_null() {
2511 return;
2512 }
2513 if !check_arity(pc, 1) {
2514 return;
2515 }
2516 cast_top_to_boolean(pc);
2517 if (*pc).error != 0 {
2518 return;
2519 }
2520 unsafe {
2521 (*(*pc).value).boolval = if (*(*pc).value).boolval == 0 { 1 } else { 0 };
2522 }
2523}
2524
2525#[no_mangle]
2527pub unsafe extern "C" fn xmlXPathTrueFunction(ctxt: *mut c_void, _nargs: c_int) {
2528 let pc = pc_from(ctxt);
2529 if pc.is_null() {
2530 return;
2531 }
2532
2533 value_push(pc, new_bool(true));
2534}
2535
2536#[no_mangle]
2538pub unsafe extern "C" fn xmlXPathFalseFunction(ctxt: *mut c_void, _nargs: c_int) {
2539 let pc = pc_from(ctxt);
2540 if pc.is_null() {
2541 return;
2542 }
2543
2544 value_push(pc, new_bool(false));
2545}
2546
2547unsafe fn lang_matches(lang: *const xmlChar, the_lang: *const xmlChar) -> bool {
2550 if lang.is_null() || the_lang.is_null() {
2551 return false;
2552 }
2553 let mut i = 0usize;
2554 loop {
2555 let lc = unsafe { *lang.add(i) };
2556 if lc == 0 {
2557 break;
2558 }
2559 let tc = unsafe { *the_lang.add(i) };
2560 if tc == 0 {
2561 return false;
2562 }
2563 if lc.to_ascii_uppercase() != tc.to_ascii_uppercase() {
2564 return false;
2565 }
2566 i += 1;
2567 }
2568 let c = unsafe { *the_lang.add(i) };
2569 c == 0 || c == b'-'
2570}
2571
2572#[no_mangle]
2574pub unsafe extern "C" fn xmlXPathLangFunction(ctxt: *mut c_void, _nargs: c_int) {
2575 let pc = pc_from(ctxt);
2576 if pc.is_null() {
2577 return;
2578 }
2579 let ctx = unsafe { (*pc).context };
2580 if ctx.is_null() {
2581 return;
2582 }
2583 if !check_arity(pc, 1) {
2584 return;
2585 }
2586 cast_top_to_string(pc);
2587 if (*pc).error != 0 {
2588 return;
2589 }
2590 let val = value_pop(pc);
2591 if val.is_null() {
2592 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
2593 return;
2594 }
2595 let lang = unsafe { (*val).stringval };
2596 let mut ret = 0;
2597 unsafe {
2598 let mut n = (*ctx).node;
2599 let mut found: *mut xmlChar = ptr::null_mut();
2600 while !n.is_null() {
2601 let got = crate::xml::tree::get_ns_prop(
2602 n,
2603 b"lang\0".as_ptr() as *const xmlChar,
2604 XML_XML_NAMESPACE_BYTES.as_ptr() as *const xmlChar,
2605 );
2606 if !got.is_null() {
2607 found = got;
2608 break;
2609 }
2610 n = (*n).parent;
2611 }
2612 if !found.is_null() && lang_matches(lang, found) {
2613 ret = 1;
2614 }
2615 if !found.is_null() {
2616 xmlFreeImpl(found as *mut c_void);
2617 }
2618 }
2619 crate::abi::exports_xml2::xmlXPathFreeObject(val);
2620 value_push(pc, new_bool(ret != 0));
2621}
2622
2623#[no_mangle]
2625pub unsafe extern "C" fn xmlXPathNumberFunction(ctxt: *mut c_void, nargs: c_int) {
2626 let pc = pc_from(ctxt);
2627 if pc.is_null() {
2628 return;
2629 }
2630 let ctx = unsafe { (*pc).context };
2631 if ctx.is_null() {
2632 return;
2633 }
2634 if nargs == 0 {
2635 let node = unsafe { (*ctx).node };
2636 let res = if node.is_null() {
2637 0.0
2638 } else {
2639 let sv = node_string_value(node);
2640 crate::xml::xpath::types::string_to_number(&sv)
2641 };
2642 value_push(pc, new_number(res));
2643 return;
2644 }
2645 if !check_arity(pc, 1) {
2646 return;
2647 }
2648 cast_top_to_number(pc);
2649}
2650
2651#[no_mangle]
2653pub unsafe extern "C" fn xmlXPathSumFunction(ctxt: *mut c_void, _nargs: c_int) {
2654 let pc = pc_from(ctxt);
2655 if pc.is_null() {
2656 return;
2657 }
2658 if !check_arity(pc, 1) {
2659 return;
2660 }
2661 let cur = value_pop(pc);
2662 if cur.is_null() {
2663 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
2664 return;
2665 }
2666 let typ = unsafe { (*cur).type_ };
2667 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
2668 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
2669 {
2670 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
2671 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
2672 return;
2673 }
2674 let mut res = 0.0;
2675 unsafe {
2676 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
2677 if !ns.is_null() {
2678 let nr = (*ns).nodeNr;
2679 let tab = (*ns).nodeTab;
2680 if !tab.is_null() {
2681 for i in 0..nr as isize {
2682 let node = *tab.add(i as usize);
2683 let sv = node_string_value(node);
2684 res += crate::xml::xpath::types::string_to_number(&sv);
2685 }
2686 }
2687 }
2688 }
2689 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
2690 value_push(pc, new_number(res));
2691}
2692
2693#[no_mangle]
2695pub unsafe extern "C" fn xmlXPathFloorFunction(ctxt: *mut c_void, _nargs: c_int) {
2696 let pc = pc_from(ctxt);
2697 if pc.is_null() {
2698 return;
2699 }
2700 if !check_arity(pc, 1) {
2701 return;
2702 }
2703 cast_top_to_number(pc);
2704 if (*pc).error != 0 {
2705 return;
2706 }
2707 unsafe {
2708 (*(*pc).value).floatval = (*(*pc).value).floatval.floor();
2709 }
2710}
2711
2712#[no_mangle]
2714pub unsafe extern "C" fn xmlXPathCeilingFunction(ctxt: *mut c_void, _nargs: c_int) {
2715 let pc = pc_from(ctxt);
2716 if pc.is_null() {
2717 return;
2718 }
2719 if !check_arity(pc, 1) {
2720 return;
2721 }
2722 cast_top_to_number(pc);
2723 if (*pc).error != 0 {
2724 return;
2725 }
2726 unsafe {
2727 (*(*pc).value).floatval = (*(*pc).value).floatval.ceil();
2728 }
2729}
2730
2731#[no_mangle]
2733pub unsafe extern "C" fn xmlXPathRoundFunction(ctxt: *mut c_void, _nargs: c_int) {
2734 let pc = pc_from(ctxt);
2735 if pc.is_null() {
2736 return;
2737 }
2738 if !check_arity(pc, 1) {
2739 return;
2740 }
2741 cast_top_to_number(pc);
2742 if (*pc).error != 0 {
2743 return;
2744 }
2745 unsafe {
2746 let f = (*(*pc).value).floatval;
2747 if f >= -0.5 && f < 0.5 {
2748 (*(*pc).value).floatval *= 0.0;
2750 } else {
2751 let mut rounded = f.floor();
2752 if f - rounded >= 0.5 {
2753 rounded += 1.0;
2754 }
2755 (*(*pc).value).floatval = rounded;
2756 }
2757 }
2758}
2759
2760#[no_mangle]
2762pub unsafe extern "C" fn xmlXPathLastFunction(ctxt: *mut c_void, _nargs: c_int) {
2763 let pc = pc_from(ctxt);
2764 if pc.is_null() {
2765 return;
2766 }
2767 let ctx = unsafe { (*pc).context };
2768 if ctx.is_null() {
2769 return;
2770 }
2771
2772 value_push(pc, new_number(unsafe { (*ctx).contextSize } as f64));
2773}
2774
2775#[no_mangle]
2777pub unsafe extern "C" fn xmlXPathPositionFunction(ctxt: *mut c_void, _nargs: c_int) {
2778 let pc = pc_from(ctxt);
2779 if pc.is_null() {
2780 return;
2781 }
2782 let ctx = unsafe { (*pc).context };
2783 if ctx.is_null() {
2784 return;
2785 }
2786
2787 value_push(pc, new_number(unsafe { (*ctx).proximityPosition } as f64));
2788}
2789
2790#[no_mangle]
2792pub unsafe extern "C" fn xmlXPathCountFunction(ctxt: *mut c_void, _nargs: c_int) {
2793 let pc = pc_from(ctxt);
2794 if pc.is_null() {
2795 return;
2796 }
2797 if !check_arity(pc, 1) {
2798 return;
2799 }
2800 let cur = value_pop(pc);
2801 if cur.is_null() {
2802 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
2803 return;
2804 }
2805 let typ = unsafe { (*cur).type_ };
2806 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
2807 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
2808 {
2809 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
2810 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
2811 return;
2812 }
2813 let count = unsafe {
2814 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
2815 if ns.is_null() {
2816 0
2817 } else {
2818 (*ns).nodeNr
2819 }
2820 };
2821 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
2822 value_push(pc, new_number(count as f64));
2823}
2824
2825unsafe fn get_elements_by_ids(doc: *mut _xmlDoc, ids: *const xmlChar) -> *mut _xmlNodeSet {
2828 use crate::abi::types::xmlElementType as ET;
2829 if ids.is_null() {
2830 return ptr::null_mut();
2831 }
2832 let mut out = NodeSet::new();
2833 unsafe {
2834 let mut p = ids;
2835 while *p != 0 {
2836 while is_blank_ch(*p) {
2837 p = p.add(1);
2838 }
2839 if *p == 0 {
2840 break;
2841 }
2842 let start = p;
2843 while *p != 0 && !is_blank_ch(*p) {
2844 p = p.add(1);
2845 }
2846 let id_c = crate::xml::string::xml_strndup(start, p.offset_from(start) as usize);
2847 if id_c.is_null() {
2848 break;
2849 }
2850 let attr = get_id(doc, id_c);
2851 xmlFreeImpl(id_c as *mut c_void);
2852 if !attr.is_null() {
2853 let t = (*attr).type_;
2854 let elem = if t == ET::XML_ATTRIBUTE_NODE as c_int {
2855 (*attr).parent
2856 } else if t == ET::XML_ELEMENT_NODE as c_int {
2857 attr as *mut _xmlNode
2858 } else {
2859 ptr::null_mut()
2860 };
2861 if !elem.is_null() {
2862 out.push(elem);
2863 }
2864 }
2865 }
2866 }
2867 out.to_raw()
2868}
2869
2870#[no_mangle]
2872pub unsafe extern "C" fn xmlXPathIdFunction(ctxt: *mut c_void, _nargs: c_int) {
2873 let pc = pc_from(ctxt);
2874 if pc.is_null() {
2875 return;
2876 }
2877 let ctx = unsafe { (*pc).context };
2878 if ctx.is_null() {
2879 return;
2880 }
2881 if !check_arity(pc, 1) {
2882 return;
2883 }
2884 let obj = value_pop(pc);
2885 if obj.is_null() {
2886 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
2887 return;
2888 }
2889 let doc = unsafe { (*ctx).doc };
2890 let v = crate::abi::exports_xml2::object_to_xpathvalue_pub(obj);
2891 crate::abi::exports_xml2::xmlXPathFreeObject(obj);
2892 match &v {
2893 XPathValue::NodeSet(ns) => {
2894 let mut merged = NodeSet::new();
2895 for n in ns.iter() {
2896 let sv = node_string_value(n);
2897 let c = dup_rust_string(&sv);
2898 let sub = get_elements_by_ids(doc, c);
2899 xmlFreeImpl(c as *mut c_void);
2900 if !sub.is_null() {
2901 let sub_internal = node_set_to_internal(sub);
2902 for m in sub_internal.iter() {
2903 if !merged.contains(m) {
2904 merged.push(m);
2905 }
2906 }
2907 crate::abi::exports_xml2::xmlXPathFreeNodeSet(sub);
2909 }
2910 }
2911 value_push(
2912 pc,
2913 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(merged)),
2914 );
2915 }
2916 _ => {
2917 let s = v.as_string();
2918 let c = dup_rust_string(&s);
2919 let ret = get_elements_by_ids(doc, c);
2920 xmlFreeImpl(c as *mut c_void);
2921 if ret.is_null() {
2922 value_push(
2923 pc,
2924 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(
2925 NodeSet::new(),
2926 )),
2927 );
2928 } else {
2929 let obj2 = crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(
2930 node_set_to_internal(ret),
2931 ));
2932 crate::abi::exports_xml2::xmlXPathFreeNodeSet(ret);
2933 value_push(pc, obj2);
2934 }
2935 }
2936 }
2937}
2938
2939unsafe fn node_local_name(node: *mut _xmlNode) -> String {
2942 use crate::abi::types::xmlElementType as ET;
2943 if node.is_null() {
2944 return String::new();
2945 }
2946 unsafe {
2947 match (*node).type_ {
2948 t if t == ET::XML_ELEMENT_NODE as c_int
2949 || t == ET::XML_ATTRIBUTE_NODE as c_int
2950 || t == ET::XML_PI_NODE as c_int =>
2951 {
2952 let name = (*node).name;
2953 if name.is_null() || *name == b' ' {
2954 String::new()
2955 } else {
2956 let s = CStr::from_ptr(name as *const c_char)
2957 .to_string_lossy()
2958 .into_owned();
2959 match s.split_once(':') {
2960 Some((_, local)) => local.to_string(),
2961 None => s,
2962 }
2963 }
2964 }
2965 t if t == ET::XML_NAMESPACE_DECL as c_int => {
2966 let ns = node as *mut crate::abi::structs::_xmlNs;
2967 let p = (*ns).prefix;
2968 if p.is_null() {
2969 String::new()
2970 } else {
2971 CStr::from_ptr(p as *const c_char)
2972 .to_string_lossy()
2973 .into_owned()
2974 }
2975 }
2976 _ => String::new(),
2977 }
2978 }
2979}
2980
2981#[no_mangle]
2983pub unsafe extern "C" fn xmlXPathLocalNameFunction(ctxt: *mut c_void, nargs: c_int) {
2984 let pc = pc_from(ctxt);
2985 if pc.is_null() {
2986 return;
2987 }
2988 let ctx = unsafe { (*pc).context };
2989 if ctx.is_null() {
2990 return;
2991 }
2992 if nargs == 0 {
2993 value_push(
2994 pc,
2995 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(NodeSet::singleton(
2996 unsafe { (*ctx).node },
2997 ))),
2998 );
2999 }
3001
3002 if !check_arity(pc, 1) {
3003 return;
3004 }
3005 let cur = value_pop(pc);
3006 if cur.is_null() {
3007 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3008 return;
3009 }
3010 let typ = unsafe { (*cur).type_ };
3011 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3012 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3013 {
3014 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3015 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3016 return;
3017 }
3018 let name = unsafe {
3019 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3020 if ns.is_null() || (*ns).nodeNr == 0 {
3021 String::new()
3022 } else {
3023 node_local_name(*(*ns).nodeTab)
3024 }
3025 };
3026 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3027 let out = dup_rust_string(&name);
3028 value_push(pc, xmlXPathWrapString(out));
3029}
3030
3031unsafe fn node_namespace_uri(node: *mut _xmlNode) -> String {
3033 use crate::abi::types::xmlElementType as ET;
3034 if node.is_null() {
3035 return String::new();
3036 }
3037 unsafe {
3038 match (*node).type_ {
3039 t if t == ET::XML_ELEMENT_NODE as c_int || t == ET::XML_ATTRIBUTE_NODE as c_int => {
3040 let ns = (*node).ns;
3041 if ns.is_null() || (*ns).href.is_null() {
3042 String::new()
3043 } else {
3044 CStr::from_ptr((*ns).href as *const c_char)
3045 .to_string_lossy()
3046 .into_owned()
3047 }
3048 }
3049 t if t == ET::XML_NAMESPACE_DECL as c_int => {
3050 let ns = node as *mut crate::abi::structs::_xmlNs;
3051 if (*ns).href.is_null() {
3052 String::new()
3053 } else {
3054 CStr::from_ptr((*ns).href as *const c_char)
3055 .to_string_lossy()
3056 .into_owned()
3057 }
3058 }
3059 _ => String::new(),
3060 }
3061 }
3062}
3063
3064#[no_mangle]
3066pub unsafe extern "C" fn xmlXPathNamespaceURIFunction(ctxt: *mut c_void, nargs: c_int) {
3067 let pc = pc_from(ctxt);
3068 if pc.is_null() {
3069 return;
3070 }
3071 let ctx = unsafe { (*pc).context };
3072 if ctx.is_null() {
3073 return;
3074 }
3075 if nargs == 0 {
3076 value_push(
3077 pc,
3078 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(NodeSet::singleton(
3079 unsafe { (*ctx).node },
3080 ))),
3081 );
3082 }
3083
3084 if !check_arity(pc, 1) {
3085 return;
3086 }
3087 let cur = value_pop(pc);
3088 if cur.is_null() {
3089 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3090 return;
3091 }
3092 let typ = unsafe { (*cur).type_ };
3093 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3094 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3095 {
3096 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3097 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3098 return;
3099 }
3100 let uri = unsafe {
3101 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3102 if ns.is_null() || (*ns).nodeNr == 0 {
3103 String::new()
3104 } else {
3105 node_namespace_uri(*(*ns).nodeTab)
3106 }
3107 };
3108 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3109 let out = dup_rust_string(&uri);
3110 value_push(pc, xmlXPathWrapString(out));
3111}
3112
3113#[no_mangle]
3115pub unsafe extern "C" fn xmlXPathStringFunction(ctxt: *mut c_void, nargs: c_int) {
3116 let pc = pc_from(ctxt);
3117 if pc.is_null() {
3118 return;
3119 }
3120 let ctx = unsafe { (*pc).context };
3121 if ctx.is_null() {
3122 return;
3123 }
3124 if nargs == 0 {
3125 let node = unsafe { (*ctx).node };
3126 let sv = if node.is_null() {
3127 String::new()
3128 } else {
3129 node_string_value(node)
3130 };
3131 let out = dup_rust_string(&sv);
3132 value_push(pc, xmlXPathWrapString(out));
3133 return;
3134 }
3135 if !check_arity(pc, 1) {
3136 return;
3137 }
3138 cast_top_to_string(pc);
3139}
3140
3141#[no_mangle]
3143pub unsafe extern "C" fn xmlXPathStringLengthFunction(ctxt: *mut c_void, nargs: c_int) {
3144 let pc = pc_from(ctxt);
3145 if pc.is_null() {
3146 return;
3147 }
3148 let ctx = unsafe { (*pc).context };
3149 if ctx.is_null() {
3150 return;
3151 }
3152 if nargs == 0 {
3153 let node = unsafe { (*ctx).node };
3154 let len = if node.is_null() {
3155 0
3156 } else {
3157 let sv = node_string_value(node);
3158 sv.chars().count()
3159 };
3160 value_push(pc, new_number(len as f64));
3161 return;
3162 }
3163 if !check_arity(pc, 1) {
3164 return;
3165 }
3166 cast_top_to_string(pc);
3167 if (*pc).error != 0 {
3168 return;
3169 }
3170 let len = unsafe {
3171 let s = (*(*pc).value).stringval;
3172 if s.is_null() {
3173 0
3174 } else {
3175 let sv = CStr::from_ptr(s as *const c_char).to_string_lossy();
3176 sv.chars().count()
3177 }
3178 };
3179 let cur = value_pop(pc);
3180 if !cur.is_null() {
3181 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3182 }
3183 value_push(pc, new_number(len as f64));
3184}
3185
3186#[no_mangle]
3188pub unsafe extern "C" fn xmlXPathConcatFunction(ctxt: *mut c_void, nargs: c_int) {
3189 let pc = pc_from(ctxt);
3190 if pc.is_null() {
3191 return;
3192 }
3193 if nargs < 2 {
3194 if !check_arity(pc, 2) {
3195 return;
3196 }
3197 }
3198 if !check_arity(pc, nargs) {
3199 return;
3200 }
3201 let mut parts: Vec<String> = Vec::with_capacity(nargs as usize);
3202 for _ in 0..nargs {
3203 cast_top_to_string(pc);
3204 if (*pc).error != 0 {
3205 return;
3206 }
3207 let v = crate::abi::exports_xml2::object_to_xpathvalue_pub(unsafe { (*pc).value });
3208 let s = v.as_string();
3209 let obj = value_pop(pc);
3210 if !obj.is_null() {
3211 crate::abi::exports_xml2::xmlXPathFreeObject(obj);
3212 }
3213 parts.push(s);
3214 }
3215 parts.reverse();
3216 let joined = parts.concat();
3217 let out = dup_rust_string(&joined);
3218 value_push(pc, xmlXPathWrapString(out));
3219}
3220
3221#[no_mangle]
3223pub unsafe extern "C" fn xmlXPathContainsFunction(ctxt: *mut c_void, _nargs: c_int) {
3224 let pc = pc_from(ctxt);
3225 if pc.is_null() {
3226 return;
3227 }
3228 if !check_arity(pc, 2) {
3229 return;
3230 }
3231 cast_top_to_string(pc);
3232 if (*pc).error != 0 {
3233 return;
3234 }
3235 let needle = value_pop(pc);
3236 cast_top_to_string(pc);
3237 if (*pc).error != 0 {
3238 if !needle.is_null() {
3239 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
3240 }
3241 return;
3242 }
3243 let hay = value_pop(pc);
3244 let found = if hay.is_null() || needle.is_null() {
3245 false
3246 } else {
3247 unsafe { !cstr_find((*hay).stringval, (*needle).stringval).is_null() }
3248 };
3249 if !hay.is_null() {
3250 crate::abi::exports_xml2::xmlXPathFreeObject(hay);
3251 }
3252 if !needle.is_null() {
3253 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
3254 }
3255 value_push(pc, new_bool(found));
3256}
3257
3258#[no_mangle]
3260pub unsafe extern "C" fn xmlXPathStartsWithFunction(ctxt: *mut c_void, _nargs: c_int) {
3261 let pc = pc_from(ctxt);
3262 if pc.is_null() {
3263 return;
3264 }
3265 if !check_arity(pc, 2) {
3266 return;
3267 }
3268 cast_top_to_string(pc);
3269 if (*pc).error != 0 {
3270 return;
3271 }
3272 let needle = value_pop(pc);
3273 cast_top_to_string(pc);
3274 if (*pc).error != 0 {
3275 if !needle.is_null() {
3276 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
3277 }
3278 return;
3279 }
3280 let hay = value_pop(pc);
3281 let found = if hay.is_null() || needle.is_null() {
3282 false
3283 } else {
3284 unsafe { crate::xml::string::xml_str_starts_with((*hay).stringval, (*needle).stringval) }
3285 };
3286 if !hay.is_null() {
3287 crate::abi::exports_xml2::xmlXPathFreeObject(hay);
3288 }
3289 if !needle.is_null() {
3290 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
3291 }
3292 value_push(pc, new_bool(found));
3293}
3294
3295#[no_mangle]
3297pub unsafe extern "C" fn xmlXPathSubstringFunction(ctxt: *mut c_void, nargs: c_int) {
3298 let pc = pc_from(ctxt);
3299 if pc.is_null() {
3300 return;
3301 }
3302 if nargs < 2 {
3303 if !check_arity(pc, 2) {
3304 return;
3305 }
3306 } else if nargs > 3 {
3307 if !check_arity(pc, 3) {
3308 return;
3309 }
3310 }
3311 let mut le = 0.0;
3312 if nargs == 3 {
3313 cast_top_to_number(pc);
3314 if (*pc).error != 0 {
3315 return;
3316 }
3317 let len_obj = value_pop(pc);
3318 if !len_obj.is_null() {
3319 le = unsafe { (*len_obj).floatval };
3320 crate::abi::exports_xml2::xmlXPathFreeObject(len_obj);
3321 }
3322 }
3323 cast_top_to_number(pc);
3324 if (*pc).error != 0 {
3325 return;
3326 }
3327 let start_obj = value_pop(pc);
3328 let in_ = if start_obj.is_null() {
3329 f64::NAN
3330 } else {
3331 let v = unsafe { (*start_obj).floatval };
3332 crate::abi::exports_xml2::xmlXPathFreeObject(start_obj);
3333 v
3334 };
3335 cast_top_to_string(pc);
3336 if (*pc).error != 0 {
3337 return;
3338 }
3339 let str_obj = value_pop(pc);
3340 let s = if str_obj.is_null() {
3341 String::new()
3342 } else {
3343 let v = unsafe { CStr::from_ptr((*str_obj).stringval as *const c_char) }
3344 .to_string_lossy()
3345 .into_owned();
3346 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
3347 v
3348 };
3349
3350 let int_max = i32::MAX as f64;
3351 let mut i: i64 = 1;
3352 let mut j: i64 = i32::MAX as i64;
3353 if !(in_ < int_max) {
3354 i = i32::MAX as i64;
3355 } else if in_ >= 1.0 {
3356 i = in_ as i64;
3357 if in_ - in_.floor() >= 0.5 {
3358 i += 1;
3359 }
3360 }
3361 if nargs == 3 {
3362 let mut rin = in_.floor();
3363 if in_ - rin >= 0.5 {
3364 rin += 1.0;
3365 }
3366 let mut rle = le.floor();
3367 if le - rle >= 0.5 {
3368 rle += 1.0;
3369 }
3370 let end = rin + rle;
3371 if !(end >= 1.0) {
3372 j = 1;
3373 } else if end < int_max {
3374 j = end as i64;
3375 }
3376 }
3377 i -= 1;
3378 j -= 1;
3379 let chars: Vec<char> = s.chars().collect();
3380 let slen = chars.len() as i64;
3381 let out = if i < j && i < slen {
3382 let start_i = i.max(0) as usize;
3383 let end_i = (j.min(slen)).max(start_i as i64) as usize;
3384 chars[start_i..end_i].iter().collect()
3385 } else {
3386 String::new()
3387 };
3388 let c = dup_rust_string(&out);
3389 value_push(pc, xmlXPathWrapString(c));
3390}
3391
3392#[no_mangle]
3394pub unsafe extern "C" fn xmlXPathSubstringBeforeFunction(ctxt: *mut c_void, _nargs: c_int) {
3395 let pc = pc_from(ctxt);
3396 if pc.is_null() {
3397 return;
3398 }
3399 if !check_arity(pc, 2) {
3400 return;
3401 }
3402 cast_top_to_string(pc);
3403 if (*pc).error != 0 {
3404 return;
3405 }
3406 let find = value_pop(pc);
3407 cast_top_to_string(pc);
3408 if (*pc).error != 0 {
3409 if !find.is_null() {
3410 crate::abi::exports_xml2::xmlXPathFreeObject(find);
3411 }
3412 return;
3413 }
3414 let str_obj = value_pop(pc);
3415 let out: String = if str_obj.is_null() || find.is_null() {
3416 String::new()
3417 } else {
3418 unsafe {
3419 let hay = (*str_obj).stringval;
3420 let needle = (*find).stringval;
3421 let point = cstr_find(hay, needle);
3422 if point.is_null() {
3423 String::new()
3424 } else {
3425 let len = point.offset_from(hay) as usize;
3426 let bytes = core::slice::from_raw_parts(hay as *const u8, len);
3427 String::from_utf8_lossy(bytes).into_owned()
3428 }
3429 }
3430 };
3431 if !str_obj.is_null() {
3432 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
3433 }
3434 if !find.is_null() {
3435 crate::abi::exports_xml2::xmlXPathFreeObject(find);
3436 }
3437 let c = dup_rust_string(&out);
3438 value_push(pc, xmlXPathWrapString(c));
3439}
3440
3441#[no_mangle]
3443pub unsafe extern "C" fn xmlXPathSubstringAfterFunction(ctxt: *mut c_void, _nargs: c_int) {
3444 let pc = pc_from(ctxt);
3445 if pc.is_null() {
3446 return;
3447 }
3448 if !check_arity(pc, 2) {
3449 return;
3450 }
3451 cast_top_to_string(pc);
3452 if (*pc).error != 0 {
3453 return;
3454 }
3455 let find = value_pop(pc);
3456 cast_top_to_string(pc);
3457 if (*pc).error != 0 {
3458 if !find.is_null() {
3459 crate::abi::exports_xml2::xmlXPathFreeObject(find);
3460 }
3461 return;
3462 }
3463 let str_obj = value_pop(pc);
3464 let out: String = if str_obj.is_null() || find.is_null() {
3465 String::new()
3466 } else {
3467 unsafe {
3468 let hay = (*str_obj).stringval;
3469 let needle = (*find).stringval;
3470 let point = cstr_find(hay, needle);
3471 if point.is_null() {
3472 String::new()
3473 } else {
3474 let nlen = crate::xml::string::xml_strlen(needle);
3475 let rest = point.add(nlen);
3476 let len = crate::xml::string::xml_strlen(rest);
3477 let bytes = core::slice::from_raw_parts(rest as *const u8, len);
3478 String::from_utf8_lossy(bytes).into_owned()
3479 }
3480 }
3481 };
3482 if !str_obj.is_null() {
3483 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
3484 }
3485 if !find.is_null() {
3486 crate::abi::exports_xml2::xmlXPathFreeObject(find);
3487 }
3488 let c = dup_rust_string(&out);
3489 value_push(pc, xmlXPathWrapString(c));
3490}
3491
3492#[no_mangle]
3494pub unsafe extern "C" fn xmlXPathNormalizeFunction(ctxt: *mut c_void, nargs: c_int) {
3495 let pc = pc_from(ctxt);
3496 if pc.is_null() {
3497 return;
3498 }
3499 let ctx = unsafe { (*pc).context };
3500 if ctx.is_null() {
3501 return;
3502 }
3503 if nargs == 0 {
3504 let node = unsafe { (*ctx).node };
3505 let sv = if node.is_null() {
3506 String::new()
3507 } else {
3508 node_string_value(node)
3509 };
3510 let c = dup_rust_string(&sv);
3511 value_push(pc, xmlXPathWrapString(c));
3512 }
3514
3515 if !check_arity(pc, 1) {
3516 return;
3517 }
3518 cast_top_to_string(pc);
3519 if (*pc).error != 0 {
3520 return;
3521 }
3522 let s = unsafe {
3523 let p = (*(*pc).value).stringval;
3524 if p.is_null() {
3525 String::new()
3526 } else {
3527 CStr::from_ptr(p as *const c_char)
3528 .to_string_lossy()
3529 .into_owned()
3530 }
3531 };
3532 let mut out = String::with_capacity(s.len());
3534 let mut blank = false;
3535 let mut started = false;
3536 for c in s.chars() {
3537 let is_b = c == ' ' || c == '\t' || c == '\n' || c == '\r';
3538 if is_b {
3539 if started {
3540 blank = true;
3541 }
3542 } else {
3543 if blank {
3544 out.push(' ');
3545 blank = false;
3546 }
3547 out.push(c);
3548 started = true;
3549 }
3550 }
3551 unsafe {
3552 let val = (*pc).value;
3553 if !(*val).stringval.is_null() {
3554 xmlFreeImpl((*val).stringval as *mut c_void);
3555 }
3556 (*val).stringval = dup_rust_string(&out);
3557 }
3558}
3559
3560#[no_mangle]
3562pub unsafe extern "C" fn xmlXPathTranslateFunction(ctxt: *mut c_void, _nargs: c_int) {
3563 let pc = pc_from(ctxt);
3564 if pc.is_null() {
3565 return;
3566 }
3567 if !check_arity(pc, 3) {
3568 return;
3569 }
3570 cast_top_to_string(pc);
3571 if (*pc).error != 0 {
3572 return;
3573 }
3574 let to = value_pop(pc);
3575 cast_top_to_string(pc);
3576 if (*pc).error != 0 {
3577 if !to.is_null() {
3578 crate::abi::exports_xml2::xmlXPathFreeObject(to);
3579 }
3580 return;
3581 }
3582 let from = value_pop(pc);
3583 cast_top_to_string(pc);
3584 if (*pc).error != 0 {
3585 if !to.is_null() {
3586 crate::abi::exports_xml2::xmlXPathFreeObject(to);
3587 }
3588 if !from.is_null() {
3589 crate::abi::exports_xml2::xmlXPathFreeObject(from);
3590 }
3591 return;
3592 }
3593 let str_obj = value_pop(pc);
3594 let (s, f, t) = unsafe {
3595 let s = if str_obj.is_null() || (*str_obj).stringval.is_null() {
3596 String::new()
3597 } else {
3598 CStr::from_ptr((*str_obj).stringval as *const c_char)
3599 .to_string_lossy()
3600 .into_owned()
3601 };
3602 let f = if from.is_null() || (*from).stringval.is_null() {
3603 String::new()
3604 } else {
3605 CStr::from_ptr((*from).stringval as *const c_char)
3606 .to_string_lossy()
3607 .into_owned()
3608 };
3609 let t = if to.is_null() || (*to).stringval.is_null() {
3610 String::new()
3611 } else {
3612 CStr::from_ptr((*to).stringval as *const c_char)
3613 .to_string_lossy()
3614 .into_owned()
3615 };
3616 (s, f, t)
3617 };
3618 if !str_obj.is_null() {
3619 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
3620 }
3621 if !from.is_null() {
3622 crate::abi::exports_xml2::xmlXPathFreeObject(from);
3623 }
3624 if !to.is_null() {
3625 crate::abi::exports_xml2::xmlXPathFreeObject(to);
3626 }
3627 let from_chars: Vec<char> = f.chars().collect();
3628 let to_chars: Vec<char> = t.chars().collect();
3629 let out: String = s
3632 .chars()
3633 .filter_map(|c| match from_chars.iter().position(|&x| x == c) {
3634 Some(i) if i < to_chars.len() => Some(to_chars[i]),
3635 Some(_) => None,
3636 _ => Some(c),
3637 })
3638 .collect();
3639 let c = dup_rust_string(&out);
3640 value_push(pc, xmlXPathWrapString(c));
3641}
3642
3643#[no_mangle]
3646pub unsafe extern "C" fn xmlXPathRegisterAllFunctions(_ctxt: *mut _xmlXPathContext) {}
3647
3648unsafe fn standard_function_pointer(
3651 name: &str,
3652) -> Option<unsafe extern "C" fn(*mut c_void, c_int)> {
3653 let f: unsafe extern "C" fn(*mut c_void, c_int) = match name {
3654 "boolean" => xmlXPathBooleanFunction,
3655 "not" => xmlXPathNotFunction,
3656 "true" => xmlXPathTrueFunction,
3657 "false" => xmlXPathFalseFunction,
3658 "lang" => xmlXPathLangFunction,
3659 "number" => xmlXPathNumberFunction,
3660 "sum" => xmlXPathSumFunction,
3661 "floor" => xmlXPathFloorFunction,
3662 "ceiling" => xmlXPathCeilingFunction,
3663 "round" => xmlXPathRoundFunction,
3664 "last" => xmlXPathLastFunction,
3665 "position" => xmlXPathPositionFunction,
3666 "count" => xmlXPathCountFunction,
3667 "id" => xmlXPathIdFunction,
3668 "local-name" => xmlXPathLocalNameFunction,
3669 "namespace-uri" => xmlXPathNamespaceURIFunction,
3670 "string" => xmlXPathStringFunction,
3671 "string-length" => xmlXPathStringLengthFunction,
3672 "concat" => xmlXPathConcatFunction,
3673 "contains" => xmlXPathContainsFunction,
3674 "starts-with" => xmlXPathStartsWithFunction,
3675 "substring" => xmlXPathSubstringFunction,
3676 "substring-before" => xmlXPathSubstringBeforeFunction,
3677 "substring-after" => xmlXPathSubstringAfterFunction,
3678 "normalize-space" => xmlXPathNormalizeFunction,
3679 "translate" => xmlXPathTranslateFunction,
3680 _ => return None,
3681 };
3682 Some(f)
3683}
3684
3685#[no_mangle]
3691pub unsafe extern "C" fn xmlXPathFunctionLookup(
3692 ctxt: *mut _xmlXPathContext,
3693 name: *const xmlChar,
3694) -> Option<unsafe extern "C" fn(*mut c_void, c_int)> {
3695 xmlXPathFunctionLookupNS(ctxt, name, ptr::null())
3696}
3697
3698#[no_mangle]
3704pub unsafe extern "C" fn xmlXPathFunctionLookupNS(
3705 ctxt: *mut _xmlXPathContext,
3706 name: *const xmlChar,
3707 ns_uri: *const xmlChar,
3708) -> Option<unsafe extern "C" fn(*mut c_void, c_int)> {
3709 if ctxt.is_null() || name.is_null() {
3710 return None;
3711 }
3712 let name_str = match CStr::from_ptr(name as *const c_char).to_str() {
3713 Ok(s) => s.to_string(),
3714 Err(_) => return None,
3715 };
3716 if ns_uri.is_null() {
3717 if let Some(f) = standard_function_pointer(&name_str) {
3718 return Some(f);
3719 }
3720 }
3721 if let Some(f) = (*ctxt).funcLookupFunc {
3723 let ret = f((*ctxt).funcLookupData, name, ns_uri);
3724 if !ret.is_null() {
3725 let fp =
3727 std::mem::transmute::<*mut c_void, unsafe extern "C" fn(*mut c_void, c_int)>(ret);
3728 return Some(fp);
3729 }
3730 }
3731 let qualified = if ns_uri.is_null() {
3732 name_str
3733 } else {
3734 let ns = match CStr::from_ptr(ns_uri as *const c_char).to_str() {
3735 Ok(s) => s,
3736 Err(_) => return None,
3737 };
3738 format!("{{{}}}{}", ns, name_str)
3739 };
3740 crate::abi::exports_xml2::xpath_cfunc_lookup((*ctxt).extra, &qualified)
3741}
3742
3743#[no_mangle]
3757pub unsafe extern "C" fn xmlXPathCtxtCompile(
3758 _ctxt: *mut _xmlXPathContext,
3759 str_: *const xmlChar,
3760) -> *mut c_void {
3761 crate::abi::exports_xml2::xmlXPathCompile(str_)
3762}
3763
3764#[no_mangle]
3770pub unsafe extern "C" fn xmlXPathCompiledEval(
3771 comp: *mut c_void,
3772 ctx: *mut _xmlXPathContext,
3773) -> *mut _xmlXPathObject {
3774 if comp.is_null() || ctx.is_null() {
3775 return ptr::null_mut();
3776 }
3777 let internal = (*ctx).extra as *mut XPathContext;
3778 if internal.is_null() {
3779 return ptr::null_mut();
3780 }
3781 let internal = &mut *internal;
3782 let registry = crate::abi::exports_xml2::xpath_compiled_registry();
3783 let map = registry.lock();
3784 match map.get(&(comp as u64)) {
3785 Some(compiled) => match crate::xml::xpath::evaluate(compiled, internal) {
3786 Some(val) => crate::abi::exports_xml2::xpath_to_object_pub(val),
3787 None => ptr::null_mut(),
3788 },
3789 None => ptr::null_mut(),
3790 }
3791}
3792
3793#[no_mangle]
3801pub unsafe extern "C" fn xmlXPathCompiledEvalToBoolean(
3802 comp: *mut c_void,
3803 ctxt: *mut _xmlXPathContext,
3804) -> c_int {
3805 let obj = xmlXPathCompiledEval(comp, ctxt);
3806 if obj.is_null() {
3807 return -1;
3808 }
3809 let b = crate::abi::exports_xml2::object_to_xpathvalue_pub(obj).as_boolean();
3810 crate::abi::exports_xml2::xmlXPathFreeObject(obj);
3811 b as c_int
3812}
3813
3814#[no_mangle]
3821pub unsafe extern "C" fn xmlXPathSetContextNode(
3822 node: *mut _xmlNode,
3823 ctx: *mut _xmlXPathContext,
3824) -> c_int {
3825 if node.is_null() || ctx.is_null() {
3826 return -1;
3827 }
3828 if (*node).doc != (*ctx).doc {
3829 return -1;
3830 }
3831 (*ctx).node = node;
3832 let internal = (*ctx).extra as *mut XPathContext;
3833 if !internal.is_null() {
3834 (*internal).context_node = node;
3835 }
3836 0
3837}
3838
3839#[no_mangle]
3845pub unsafe extern "C" fn xmlXPathNodeEval(
3846 node: *mut _xmlNode,
3847 str_: *const xmlChar,
3848 ctx: *mut _xmlXPathContext,
3849) -> *mut _xmlXPathObject {
3850 if str_.is_null() {
3851 return ptr::null_mut();
3852 }
3853 if xmlXPathSetContextNode(node, ctx) < 0 {
3854 return ptr::null_mut();
3855 }
3856 crate::abi::exports_xml2::xmlXPathEvalExpression(str_, ctx)
3857}
3858
3859#[no_mangle]
3868pub unsafe extern "C" fn xmlXPathContextSetCache(
3869 ctxt: *mut _xmlXPathContext,
3870 active: c_int,
3871 _value: c_int,
3872 _options: c_int,
3873) -> c_int {
3874 if ctxt.is_null() {
3875 return -1;
3876 }
3877 (*ctxt).cache = if active != 0 {
3878 (&XML_XPATH_XML_NS.0) as *const crate::abi::structs::_xmlNs as *mut c_void
3879 } else {
3880 ptr::null_mut()
3881 };
3882 0
3883}
3884
3885#[no_mangle]
3891pub unsafe extern "C" fn xmlXPathRegisterFuncLookup(
3892 ctxt: *mut _xmlXPathContext,
3893 f: Option<crate::abi::callbacks::xmlXPathFuncLookupFunc>,
3894 data: *mut c_void,
3895) {
3896 if ctxt.is_null() {
3897 return;
3898 }
3899 (*ctxt).funcLookupFunc = f;
3900 (*ctxt).funcLookupData = data;
3901 let internal = (*ctxt).extra as *mut XPathContext;
3902 if !internal.is_null() {
3903 (*internal).func_lookup_func = f;
3904 (*internal).func_lookup_data = data;
3905 }
3906}
3907
3908#[no_mangle]
3914pub unsafe extern "C" fn xmlXPathRegisterVariableLookup(
3915 ctxt: *mut _xmlXPathContext,
3916 f: Option<crate::abi::callbacks::xmlXPathVariableLookupFunc>,
3917 data: *mut c_void,
3918) {
3919 if ctxt.is_null() {
3920 return;
3921 }
3922 (*ctxt).varLookupFunc = f;
3923 (*ctxt).varLookupData = data;
3924 let internal = (*ctxt).extra as *mut XPathContext;
3925 if !internal.is_null() {
3926 (*internal).var_lookup_func = f;
3927 (*internal).var_lookup_data = data;
3928 }
3929}
3930
3931#[no_mangle]
3937pub unsafe extern "C" fn xmlXPathRegisterVariableNS(
3938 ctxt: *mut _xmlXPathContext,
3939 name: *const xmlChar,
3940 ns_uri: *const xmlChar,
3941 value: *mut _xmlXPathObject,
3942) -> c_int {
3943 if ctxt.is_null() || name.is_null() || value.is_null() {
3944 return -1;
3945 }
3946 let internal = (*ctxt).extra as *mut XPathContext;
3947 if internal.is_null() {
3948 return -1;
3949 }
3950 let internal = &mut *internal;
3951 let name_str = match CStr::from_ptr(name as *const c_char).to_str() {
3952 Ok(s) => s.to_string(),
3953 Err(_) => return -1,
3954 };
3955 let qualified = if ns_uri.is_null() {
3956 name_str
3957 } else {
3958 match CStr::from_ptr(ns_uri as *const c_char).to_str() {
3959 Ok(s) => format!("{{{}}}{}", s, name_str),
3960 Err(_) => return -1,
3961 }
3962 };
3963 let xpath_val = crate::abi::exports_xml2::object_to_xpathvalue_pub(value);
3964 internal.register_variable(&qualified, xpath_val);
3965 0
3966}
3967
3968#[no_mangle]
3974pub unsafe extern "C" fn xmlXPathVariableLookup(
3975 ctxt: *mut _xmlXPathContext,
3976 name: *const xmlChar,
3977) -> *mut _xmlXPathObject {
3978 if ctxt.is_null() {
3979 return ptr::null_mut();
3980 }
3981 if let Some(f) = (*ctxt).varLookupFunc {
3982 let ret = f((*ctxt).varLookupData, name, ptr::null());
3983 return ret;
3984 }
3985 xmlXPathVariableLookupNS(ctxt, name, ptr::null())
3986}
3987
3988#[no_mangle]
3994pub unsafe extern "C" fn xmlXPathVariableLookupNS(
3995 ctxt: *mut _xmlXPathContext,
3996 name: *const xmlChar,
3997 ns_uri: *const xmlChar,
3998) -> *mut _xmlXPathObject {
3999 if ctxt.is_null() || name.is_null() {
4000 return ptr::null_mut();
4001 }
4002 if let Some(f) = (*ctxt).varLookupFunc {
4003 let ret = f((*ctxt).varLookupData, name, ns_uri);
4004 if !ret.is_null() {
4005 return ret;
4006 }
4007 }
4008 let internal = (*ctxt).extra as *mut XPathContext;
4009 if internal.is_null() {
4010 return ptr::null_mut();
4011 }
4012 let internal = &*internal;
4013 let name_str = match CStr::from_ptr(name as *const c_char).to_str() {
4014 Ok(s) => s.to_string(),
4015 Err(_) => return ptr::null_mut(),
4016 };
4017 let qualified = if ns_uri.is_null() {
4018 name_str
4019 } else {
4020 match CStr::from_ptr(ns_uri as *const c_char).to_str() {
4021 Ok(s) => format!("{{{}}}{}", s, name_str),
4022 Err(_) => return ptr::null_mut(),
4023 }
4024 };
4025 match internal.variables.get(&qualified) {
4026 Some(v) => crate::abi::exports_xml2::xpath_to_object_pub(v.clone()),
4027 None => ptr::null_mut(),
4028 }
4029}
4030
4031#[no_mangle]
4037pub unsafe extern "C" fn xmlXPathNsLookup(
4038 ctxt: *mut _xmlXPathContext,
4039 prefix: *const xmlChar,
4040) -> *const xmlChar {
4041 if ctxt.is_null() || prefix.is_null() {
4042 return ptr::null();
4043 }
4044 if cstr_eq(prefix, b"xml\0".as_ptr() as *const xmlChar) {
4046 return XML_XML_NAMESPACE_BYTES.as_ptr() as *const xmlChar;
4047 }
4048 let namespaces = (*ctxt).namespaces;
4050 if !namespaces.is_null() {
4051 for i in 0..(*ctxt).nsNr as isize {
4052 let ns = *namespaces.add(i as usize);
4053 if !ns.is_null() && !(*ns).prefix.is_null() && cstr_eq((*ns).prefix, prefix) {
4054 return (*ns).href;
4055 }
4056 }
4057 }
4058 if !(*ctxt).nsHash.is_null() {
4061 let map = &*((*ctxt).nsHash as *const HashMap<String, CString>);
4062 let p = CStr::from_ptr(prefix as *const c_char)
4063 .to_string_lossy()
4064 .into_owned();
4065 if let Some(c) = map.get(&p) {
4066 return c.as_ptr() as *const xmlChar;
4067 }
4068 }
4069 ptr::null()
4070}
4071
4072#[no_mangle]
4078pub unsafe extern "C" fn xmlXPathRegisteredFuncsCleanup(ctxt: *mut _xmlXPathContext) {
4079 if ctxt.is_null() {
4080 return;
4081 }
4082 let internal = (*ctxt).extra as *mut XPathContext;
4083 if !internal.is_null() {
4084 (*internal).functions.clear();
4085 }
4086 crate::abi::exports_xml2::xpath_cfunc_cleanup((*ctxt).extra);
4087}
4088
4089#[no_mangle]
4095pub unsafe extern "C" fn xmlXPathRegisteredVariablesCleanup(ctxt: *mut _xmlXPathContext) {
4096 if ctxt.is_null() {
4097 return;
4098 }
4099 let internal = (*ctxt).extra as *mut XPathContext;
4100 if !internal.is_null() {
4101 (*internal).variables.clear();
4102 }
4103}
4104
4105#[no_mangle]
4111pub unsafe extern "C" fn xmlXPathRegisteredNsCleanup(ctxt: *mut _xmlXPathContext) {
4112 if ctxt.is_null() {
4113 return;
4114 }
4115 let internal = (*ctxt).extra as *mut XPathContext;
4116 if !internal.is_null() {
4117 (*internal).namespaces.clear();
4118 }
4119 if !(*ctxt).nsHash.is_null() {
4120 drop(Box::from_raw(
4121 (*ctxt).nsHash as *mut HashMap<String, CString>,
4122 ));
4123 (*ctxt).nsHash = ptr::null_mut();
4124 }
4125}
4126
4127#[no_mangle]
4133pub unsafe extern "C" fn xmlXPathSetErrorHandler(
4134 ctxt: *mut _xmlXPathContext,
4135 handler: Option<crate::abi::callbacks::xmlStructuredErrorFunc>,
4136 data: *mut c_void,
4137) {
4138 if ctxt.is_null() {
4139 return;
4140 }
4141 (*ctxt).error = handler;
4142 (*ctxt).userData = data;
4143}
4144
4145extern "C" {
4146 fn fwrite(ptr: *const c_void, size: usize, nmemb: usize, stream: *mut c_void) -> usize;
4147}
4148
4149unsafe fn dump_write(output: *mut c_void, s: &str) {
4150 unsafe {
4151 fwrite(s.as_ptr() as *const c_void, 1, s.len(), output);
4152 }
4153}
4154
4155#[no_mangle]
4161pub unsafe extern "C" fn xmlXPathDebugDumpObject(
4162 output: *mut c_void,
4163 cur: *mut _xmlXPathObject,
4164 depth: c_int,
4165) {
4166 if output.is_null() {
4167 return;
4168 }
4169 let mut s = String::new();
4170 for _ in 0..depth.min(25).max(0) {
4171 s.push_str(" ");
4172 }
4173 if cur.is_null() {
4174 s.push_str("Object is empty (NULL)\n");
4175 dump_write(output, &s);
4176 return;
4177 }
4178 unsafe {
4179 match (*cur).type_ {
4180 t if t == xmlXPathObjectType::XPATH_BOOLEAN as c_int => {
4181 s.push_str("Object is a Boolean : ");
4182 s.push_str(if (*cur).boolval != 0 {
4183 "true\n"
4184 } else {
4185 "false\n"
4186 });
4187 }
4188 t if t == xmlXPathObjectType::XPATH_NUMBER as c_int => {
4189 let f = (*cur).floatval;
4190 if f.is_nan() {
4191 s.push_str("Object is a number : NaN\n");
4192 } else if f == f64::INFINITY {
4193 s.push_str("Object is a number : Infinity\n");
4194 } else if f == f64::NEG_INFINITY {
4195 s.push_str("Object is a number : -Infinity\n");
4196 } else if f == 0.0 {
4197 s.push_str("Object is a number : 0\n");
4198 } else {
4199 s.push_str("Object is a number : ");
4200 s.push_str(&f.to_string());
4201 s.push('\n');
4202 }
4203 }
4204 t if t == xmlXPathObjectType::XPATH_STRING as c_int => {
4205 s.push_str("Object is a string : ");
4206 if (*cur).stringval.is_null() {
4207 s.push_str("(null)");
4208 } else {
4209 let sv = CStr::from_ptr((*cur).stringval as *const c_char).to_string_lossy();
4210 s.push_str(&sv);
4211 }
4212 s.push('\n');
4213 }
4214 t if t == xmlXPathObjectType::XPATH_NODESET as c_int => {
4215 s.push_str("Object is a Node Set :\n");
4216 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
4217 if !ns.is_null() {
4218 for _ in 0..=depth.min(24) {
4219 s.push_str(" ");
4220 }
4221 s.push_str(&format!("Object contains {} nodes\n", (*ns).nodeNr));
4222 }
4223 }
4224 t if t == xmlXPathObjectType::XPATH_XSLT_TREE as c_int => {
4225 s.push_str("Object is an XSLT value tree :\n");
4226 }
4227 t if t == xmlXPathObjectType::XPATH_USERS as c_int => {
4228 s.push_str("Object is user defined\n");
4229 }
4230 _ => {
4231 s.push_str("Object is uninitialized\n");
4232 }
4233 }
4234 }
4235 dump_write(output, &s);
4236}
4237
4238#[no_mangle]
4248pub unsafe extern "C" fn xmlXPathDebugDumpCompExpr(
4249 output: *mut c_void,
4250 comp: *mut c_void,
4251 depth: c_int,
4252) {
4253 if output.is_null() || comp.is_null() {
4254 return;
4255 }
4256 let registry = crate::abi::exports_xml2::xpath_compiled_registry();
4257 let map = registry.lock();
4258 if let Some(compiled) = map.get(&(comp as u64)) {
4259 let mut s = String::new();
4260 for _ in 0..depth.min(25).max(0) {
4261 s.push_str(" ");
4262 }
4263 s.push_str("Compiled Expression : ");
4264 s.push_str(&compiled.original);
4265 s.push('\n');
4266 dump_write(output, &s);
4267 }
4268}
4269
4270#[allow(unused)]
4271fn _unused_xpath_batch(_: *mut _xmlAttr) {}