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(c"".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]
369pub const unsafe extern "C" fn xmlXPathCastBooleanToNumber(val: c_int) -> c_double {
370 if val != 0 {
371 1.0
372 } else {
373 0.0
374 }
375}
376
377#[no_mangle]
389pub unsafe extern "C" fn xmlXPathCastBooleanToString(val: c_int) -> *mut xmlChar {
390 if val != 0 {
391 xml_strdup(c"true".as_ptr() as *const xmlChar)
392 } else {
393 xml_strdup(c"false".as_ptr() as *const xmlChar)
394 }
395}
396
397#[no_mangle]
403pub unsafe extern "C" fn xmlXPathCastNodeSetToBoolean(ns: *mut _xmlNodeSet) -> c_int {
404 if ns.is_null() {
405 return 0;
406 }
407 (unsafe { (*ns).nodeNr > 0 }) as c_int
408}
409
410#[no_mangle]
416pub unsafe extern "C" fn xmlXPathCastNodeSetToNumber(ns: *mut _xmlNodeSet) -> c_double {
417 unsafe {
418 let val = crate::abi::exports_xml2::object_to_xpathvalue_pub(xmlXPathWrapNodeSet(ns));
419 let n = val.as_number();
420 n
422 }
423}
424
425#[no_mangle]
431pub unsafe extern "C" fn xmlXPathCastNodeSetToString(ns: *mut _xmlNodeSet) -> *mut xmlChar {
432 let val = crate::xml::xpath::types::XPathValue::NodeSet(unsafe { node_set_to_internal(ns) });
433 let s = val.as_string();
434 dup_rust_string(&s)
435}
436
437unsafe fn node_set_to_internal(ns: *mut _xmlNodeSet) -> NodeSet {
439 let mut out = NodeSet::new();
440 if ns.is_null() {
441 return out;
442 }
443 let nr = unsafe { (*ns).nodeNr };
444 let tab = unsafe { (*ns).nodeTab };
445 if !tab.is_null() {
446 for i in 0..nr as isize {
447 out.push(unsafe { *tab.add(i as usize) });
448 }
449 }
450 out
451}
452
453#[no_mangle]
459pub unsafe extern "C" fn xmlXPathCastNodeToNumber(node: *mut _xmlNode) -> c_double {
460 let s = node_string_value(node);
461 crate::xml::xpath::types::string_to_number(&s)
462}
463
464#[no_mangle]
470pub unsafe extern "C" fn xmlXPathCastNodeToString(node: *mut _xmlNode) -> *mut xmlChar {
471 let s = node_string_value(node);
472 dup_rust_string(&s)
473}
474
475#[no_mangle]
487pub unsafe extern "C" fn xmlXPathCastNumberToBoolean(val: c_double) -> c_int {
488 (val != 0.0 && !val.is_nan()) as c_int
489}
490
491#[no_mangle]
503pub unsafe extern "C" fn xmlXPathCastNumberToString(val: c_double) -> *mut xmlChar {
504 number_to_xmlstring(val)
505}
506
507#[no_mangle]
513pub const unsafe extern "C" fn xmlXPathCastStringToBoolean(val: *const xmlChar) -> c_int {
514 if val.is_null() || unsafe { *val } == 0 {
515 0
516 } else {
517 1
518 }
519}
520
521#[no_mangle]
533pub const unsafe extern "C" fn xmlXPathIsNaN(val: c_double) -> c_int {
534 val.is_nan() as c_int
535}
536
537#[no_mangle]
549pub unsafe extern "C" fn xmlXPathIsInf(val: c_double) -> c_int {
550 if val.is_infinite() {
551 if val > 0.0 {
552 1
553 } else {
554 -1
555 }
556 } else {
557 0
558 }
559}
560
561#[no_mangle]
567pub unsafe extern "C" fn xmlXPathStringEvalNumber(str_: *const xmlChar) -> c_double {
568 if str_.is_null() {
569 return f64::NAN;
570 }
571 let s = unsafe { crate::xml::string::xmlstr_to_string(str_) };
572 crate::xml::xpath::types::string_to_number(&s)
573}
574
575#[no_mangle]
582pub unsafe extern "C" fn xmlXPathIsNodeType(name: *const xmlChar) -> c_int {
583 if name.is_null() {
584 return 0;
585 }
586 let s = unsafe { crate::xml::string::xmlstr_to_string(name) };
587 match s.as_str() {
588 "comment" | "text" | "processing-instruction" | "node" => 1,
589 _ => 0,
590 }
591}
592
593#[no_mangle]
605pub const unsafe extern "C" fn xmlXPathInit() {}
606
607#[no_mangle]
614pub unsafe extern "C" fn xmlXPathErr(
615 ctxt: *mut crate::xml::xpath::parser_context::XmlXPathParserContext,
616 error: c_int,
617) {
618 if !ctxt.is_null() {
619 unsafe { (*ctxt).error = error };
620 }
621}
622
623#[no_mangle]
630pub unsafe extern "C" fn xmlXPatherror(
631 ctxt: *mut crate::xml::xpath::parser_context::XmlXPathParserContext,
632 _file: *const c_char,
633 _line: c_int,
634 _no: c_int,
635) {
636 if !ctxt.is_null() {
637 unsafe { (*ctxt).error = _no };
638 }
639}
640
641#[allow(unused)]
642const fn _unused_doc(_d: *mut _xmlDoc) {}
643
644unsafe fn node_set_grow(ns: *mut _xmlNodeSet) {
650 if ns.is_null() {
651 return;
652 }
653 unsafe {
654 let nr = (*ns).nodeNr;
655 let max = (*ns).nodeMax;
656 if nr < max {
657 return;
658 }
659 let new_max = if max <= 0 { 8 } else { max * 2 };
660 let new_tab = crate::abi::allocator::xmlReallocImpl(
661 (*ns).nodeTab as *mut c_void,
662 (new_max as usize) * size_of::<*mut _xmlNode>(),
663 ) as *mut *mut _xmlNode;
664 if !new_tab.is_null() {
665 (*ns).nodeTab = new_tab;
666 (*ns).nodeMax = new_max;
667 }
668 }
669}
670
671#[no_mangle]
677pub unsafe extern "C" fn xmlXPathNodeSetContains(
678 cur: *mut _xmlNodeSet,
679 val: *mut _xmlNode,
680) -> c_int {
681 if cur.is_null() || val.is_null() {
682 return 0;
683 }
684 unsafe {
685 let nr = (*cur).nodeNr;
686 let tab = (*cur).nodeTab;
687 if !tab.is_null() {
688 for i in 0..nr as isize {
689 if *tab.add(i as usize) == val {
690 return 1;
691 }
692 }
693 }
694 }
695 0
696}
697
698#[no_mangle]
705pub unsafe extern "C" fn xmlXPathNodeSetAdd(cur: *mut _xmlNodeSet, val: *mut _xmlNode) -> c_int {
706 if cur.is_null() || val.is_null() {
707 return -1;
708 }
709 if xmlXPathNodeSetContains(cur, val) != 0 {
710 return 0;
711 }
712 unsafe {
713 node_set_grow(cur);
714 if (*cur).nodeNr >= (*cur).nodeMax {
715 return -1;
716 }
717 let idx = (*cur).nodeNr as usize;
718 ptr::write((*cur).nodeTab.add(idx), val);
719 (*cur).nodeNr += 1;
720 }
721 0
722}
723
724#[no_mangle]
731pub unsafe extern "C" fn xmlXPathNodeSetAddUnique(
732 cur: *mut _xmlNodeSet,
733 val: *mut _xmlNode,
734) -> c_int {
735 if cur.is_null() || val.is_null() {
736 return -1;
737 }
738 unsafe {
739 node_set_grow(cur);
740 if (*cur).nodeNr >= (*cur).nodeMax {
741 return -1;
742 }
743 let idx = (*cur).nodeNr as usize;
744 ptr::write((*cur).nodeTab.add(idx), val);
745 (*cur).nodeNr += 1;
746 }
747 0
748}
749
750#[no_mangle]
757pub unsafe extern "C" fn xmlXPathNodeSetAddNs(
758 cur: *mut _xmlNodeSet,
759 _node: *mut _xmlNode,
760 ns: *mut _xmlNs,
761) -> c_int {
762 if cur.is_null() || ns.is_null() {
763 return -1;
764 }
765 let ns_node = ns as *mut _xmlNode;
768 if xmlXPathNodeSetContains(cur, ns_node) != 0 {
769 return 0;
770 }
771 xmlXPathNodeSetAddUnique(cur, ns_node)
772}
773
774#[no_mangle]
780pub unsafe extern "C" fn xmlXPathNodeSetDel(cur: *mut _xmlNodeSet, val: *mut _xmlNode) -> c_int {
781 if cur.is_null() || val.is_null() {
782 return -1;
783 }
784 unsafe {
785 let nr = (*cur).nodeNr;
786 let tab = (*cur).nodeTab;
787 let mut found = -1;
788 if !tab.is_null() {
789 for i in 0..nr as isize {
790 if *tab.add(i as usize) == val {
791 found = i as c_int;
792 break;
793 }
794 }
795 }
796 if found >= 0 {
797 let fi = found as usize;
798 for i in fi..(nr as usize - 1) {
799 ptr::write(tab.add(i), *tab.add(i + 1));
800 }
801 (*cur).nodeNr -= 1;
802 }
803 }
804 0
805}
806
807#[no_mangle]
813pub unsafe extern "C" fn xmlXPathNodeSetRemove(cur: *mut _xmlNodeSet, val: c_int) -> c_int {
814 if cur.is_null() || val < 0 {
815 return -1;
816 }
817 unsafe {
818 let nr = (*cur).nodeNr;
819 if val >= nr {
820 return -1;
821 }
822 let tab = (*cur).nodeTab;
823 let vi = val as usize;
824 for i in vi..(nr as usize - 1) {
825 ptr::write(tab.add(i), *tab.add(i + 1));
826 }
827 (*cur).nodeNr -= 1;
828 }
829 0
830}
831
832#[no_mangle]
839pub unsafe extern "C" fn xmlXPathNodeSetSort(set: *mut _xmlNodeSet) {
840 if set.is_null() {
841 return;
842 }
843 unsafe {
844 let nr = (*set).nodeNr;
845 let tab = (*set).nodeTab;
846 if nr <= 1 || tab.is_null() {
847 return;
848 }
849 for i in 1..nr as usize {
852 let key = *tab.add(i);
853 let mut j = i;
854 while j > 0 {
855 let prev = *tab.add(j - 1);
856 if crate::xml::xpath::types::compare_document_order(prev, key)
857 == core::cmp::Ordering::Greater
858 {
859 ptr::write(tab.add(j), prev);
860 j -= 1;
861 } else {
862 break;
863 }
864 }
865 ptr::write(tab.add(j), key);
866 }
867 let mut w = 0usize;
869 for r in 0..nr as usize {
870 if w == 0 || *tab.add(w - 1) != *tab.add(r) {
871 ptr::write(tab.add(w), *tab.add(r));
872 w += 1;
873 }
874 }
875 (*set).nodeNr = w as c_int;
876 }
877}
878
879#[no_mangle]
886pub unsafe extern "C" fn xmlXPathNodeSetMerge(
887 val1: *mut _xmlNodeSet,
888 val2: *mut _xmlNodeSet,
889) -> *mut _xmlNodeSet {
890 if val1.is_null() && val2.is_null() {
891 return ptr::null_mut();
892 }
893 if val1.is_null() {
894 let obj = xmlXPathNewNodeSetList(val2);
896 let ns = unsafe { (*obj).nodesetval as *mut _xmlNodeSet };
897 if obj.is_null() {
898 return ptr::null_mut();
899 }
900 return ns;
901 }
902 if val2.is_null() {
903 return val1;
904 }
905 unsafe {
906 let nr2 = (*val2).nodeNr;
907 let tab2 = (*val2).nodeTab;
908 if !tab2.is_null() {
909 for i in 0..nr2 as isize {
910 let n = *tab2.add(i as usize);
911 if xmlXPathNodeSetContains(val1, n) == 0 {
912 xmlXPathNodeSetAddUnique(val1, n);
913 }
914 }
915 }
916 }
917 val1
918}
919
920#[no_mangle]
927pub unsafe extern "C" fn xmlXPathDifference(
928 nodes1: *mut _xmlNodeSet,
929 nodes2: *mut _xmlNodeSet,
930) -> *mut _xmlNodeSet {
931 if nodes1.is_null() {
932 return ptr::null_mut();
933 }
934 let mut a = unsafe { node_set_to_internal(nodes1) };
935 a.sort();
936 let b = unsafe { node_set_to_internal(nodes2) };
937 let mut out = NodeSet::new();
938 for n in a.iter() {
939 if !b.contains(n) {
940 out.push(n);
941 }
942 }
943 out.sort();
944 out.to_raw()
945}
946
947#[no_mangle]
953pub unsafe extern "C" fn xmlXPathIntersection(
954 nodes1: *mut _xmlNodeSet,
955 nodes2: *mut _xmlNodeSet,
956) -> *mut _xmlNodeSet {
957 let a = unsafe { node_set_to_internal(nodes1) };
958 let b = unsafe { node_set_to_internal(nodes2) };
959 let mut out = NodeSet::new();
960 for n in a.iter() {
961 if b.contains(n) {
962 out.push(n);
963 }
964 }
965 out.sort();
966 out.to_raw()
967}
968
969#[no_mangle]
975pub unsafe extern "C" fn xmlXPathDistinct(nodes: *mut _xmlNodeSet) -> *mut _xmlNodeSet {
976 if nodes.is_null() {
977 return ptr::null_mut();
978 }
979 unsafe {
980 xmlXPathNodeSetSort(nodes);
981 nodes
982 }
983}
984
985#[no_mangle]
991pub unsafe extern "C" fn xmlXPathDistinctSorted(nodes: *mut _xmlNodeSet) -> *mut _xmlNodeSet {
992 if nodes.is_null() {
993 return ptr::null_mut();
994 }
995 unsafe {
996 let nr = (*nodes).nodeNr;
997 let tab = (*nodes).nodeTab;
998 let mut w = 0usize;
999 if !tab.is_null() {
1000 for r in 0..nr as usize {
1001 if w == 0 || *tab.add(w - 1) != *tab.add(r) {
1002 ptr::write(tab.add(w), *tab.add(r));
1003 w += 1;
1004 }
1005 }
1006 }
1007 (*nodes).nodeNr = w as c_int;
1008 nodes
1009 }
1010}
1011
1012#[no_mangle]
1018pub unsafe extern "C" fn xmlXPathHasSameNodes(
1019 nodes1: *mut _xmlNodeSet,
1020 nodes2: *mut _xmlNodeSet,
1021) -> c_int {
1022 if nodes1.is_null() || nodes2.is_null() {
1023 return 0;
1024 }
1025 unsafe {
1026 let nr1 = (*nodes1).nodeNr;
1027 let nr2 = (*nodes2).nodeNr;
1028 if nr1 != nr2 {
1029 return 0;
1030 }
1031 let tab1 = (*nodes1).nodeTab;
1032 let tab2 = (*nodes2).nodeTab;
1033 for i in 0..nr1 as isize {
1034 let mut found = false;
1035 for j in 0..nr2 as isize {
1036 if *tab1.add(i as usize) == *tab2.add(j as usize) {
1037 found = true;
1038 break;
1039 }
1040 }
1041 if !found {
1042 return 0;
1043 }
1044 }
1045 }
1046 1
1047}
1048
1049unsafe fn leading_nodes(nodes: &NodeSet, node: *mut _xmlNode) -> NodeSet {
1051 let mut out = NodeSet::new();
1052 for n in nodes.iter() {
1053 if n == node {
1054 break;
1055 }
1056 out.push(n);
1057 }
1058 out
1059}
1060
1061unsafe fn trailing_nodes(nodes: &NodeSet, node: *mut _xmlNode) -> NodeSet {
1062 let mut out = NodeSet::new();
1063 let mut seen = false;
1064 for n in nodes.iter() {
1065 if n == node {
1066 seen = true;
1067 continue;
1068 }
1069 if seen {
1070 out.push(n);
1071 }
1072 }
1073 out
1074}
1075
1076#[no_mangle]
1082pub unsafe extern "C" fn xmlXPathLeading(
1083 nodes1: *mut _xmlNodeSet,
1084 nodes2: *mut _xmlNodeSet,
1085) -> *mut _xmlNodeSet {
1086 if nodes1.is_null() {
1087 return ptr::null_mut();
1088 }
1089 let mut a = unsafe { node_set_to_internal(nodes1) };
1090 a.sort();
1091 let b = unsafe { node_set_to_internal(nodes2) };
1092 if b.is_empty() {
1093 let raw = a.to_raw();
1094 return raw;
1095 }
1096 let first = b.first().unwrap();
1097 let out = unsafe { leading_nodes(&a, first) };
1098 out.to_raw()
1099}
1100
1101#[no_mangle]
1107pub unsafe extern "C" fn xmlXPathLeadingSorted(
1108 nodes1: *mut _xmlNodeSet,
1109 nodes2: *mut _xmlNodeSet,
1110) -> *mut _xmlNodeSet {
1111 unsafe { xmlXPathLeading(nodes1, nodes2) }
1112}
1113
1114#[no_mangle]
1120pub unsafe extern "C" fn xmlXPathTrailing(
1121 nodes1: *mut _xmlNodeSet,
1122 nodes2: *mut _xmlNodeSet,
1123) -> *mut _xmlNodeSet {
1124 if nodes1.is_null() {
1125 return ptr::null_mut();
1126 }
1127 let mut a = unsafe { node_set_to_internal(nodes1) };
1128 a.sort();
1129 let b = unsafe { node_set_to_internal(nodes2) };
1130 if b.is_empty() {
1131 return a.to_raw();
1132 }
1133 let last = b.last().unwrap();
1134 let out = unsafe { trailing_nodes(&a, last) };
1135 out.to_raw()
1136}
1137
1138#[no_mangle]
1144pub unsafe extern "C" fn xmlXPathTrailingSorted(
1145 nodes1: *mut _xmlNodeSet,
1146 nodes2: *mut _xmlNodeSet,
1147) -> *mut _xmlNodeSet {
1148 unsafe { xmlXPathTrailing(nodes1, nodes2) }
1149}
1150
1151#[no_mangle]
1157pub unsafe extern "C" fn xmlXPathNodeLeading(
1158 nodes: *mut _xmlNodeSet,
1159 node: *mut _xmlNode,
1160) -> *mut _xmlNodeSet {
1161 if nodes.is_null() {
1162 return ptr::null_mut();
1163 }
1164 let mut a = unsafe { node_set_to_internal(nodes) };
1165 a.sort();
1166 let out = unsafe { leading_nodes(&a, node) };
1167 out.to_raw()
1168}
1169
1170#[no_mangle]
1176pub unsafe extern "C" fn xmlXPathNodeLeadingSorted(
1177 nodes: *mut _xmlNodeSet,
1178 node: *mut _xmlNode,
1179) -> *mut _xmlNodeSet {
1180 unsafe { xmlXPathNodeLeading(nodes, node) }
1181}
1182
1183#[no_mangle]
1189pub unsafe extern "C" fn xmlXPathNodeTrailing(
1190 nodes: *mut _xmlNodeSet,
1191 node: *mut _xmlNode,
1192) -> *mut _xmlNodeSet {
1193 if nodes.is_null() {
1194 return ptr::null_mut();
1195 }
1196 let mut a = unsafe { node_set_to_internal(nodes) };
1197 a.sort();
1198 let out = unsafe { trailing_nodes(&a, node) };
1199 out.to_raw()
1200}
1201
1202#[no_mangle]
1208pub unsafe extern "C" fn xmlXPathNodeTrailingSorted(
1209 nodes: *mut _xmlNodeSet,
1210 node: *mut _xmlNode,
1211) -> *mut _xmlNodeSet {
1212 unsafe { xmlXPathNodeTrailing(nodes, node) }
1213}
1214
1215#[no_mangle]
1228pub unsafe extern "C" fn xmlXPathNodeSetFreeNs(ns: *mut _xmlNs) {
1229 unsafe {
1230 if ns.is_null() {
1231 return;
1232 }
1233 if (*ns).type_ != crate::abi::types::xmlElementType::XML_NAMESPACE_DECL as c_int {
1234 return;
1235 }
1236 if !(*ns).next.is_null()
1238 && (*(*ns).next).type_ != crate::abi::types::xmlElementType::XML_NAMESPACE_DECL as c_int
1239 {
1240 if !(*ns).href.is_null() {
1241 libc::free((*ns).href as *mut libc::c_void);
1242 }
1243 if !(*ns).prefix.is_null() {
1244 libc::free((*ns).prefix as *mut libc::c_void);
1245 }
1246 libc::free(ns as *mut libc::c_void);
1247 }
1248 }
1249}
1250
1251#[no_mangle]
1266pub unsafe extern "C" fn xmlXPathOrderDocElems(doc: *mut _xmlDoc) -> c_long {
1267 if doc.is_null() {
1268 return -1;
1269 }
1270 let mut count: c_long = 0;
1271 unsafe {
1272 let mut cur = (*doc).children;
1273 while !cur.is_null() {
1274 if (*cur).type_ == crate::abi::types::xmlElementType::XML_ELEMENT_NODE as c_int {
1275 count += 1;
1276 (*cur).content = (-count) as *mut xmlChar;
1280 if !(*cur).children.is_null() {
1281 cur = (*cur).children;
1282 continue;
1283 }
1284 }
1285 if !(*cur).next.is_null() {
1286 cur = (*cur).next;
1287 continue;
1288 }
1289 loop {
1290 cur = (*cur).parent;
1291 if cur.is_null() {
1292 break;
1293 }
1294 if cur == doc as *mut _xmlNode {
1295 cur = ptr::null_mut();
1296 break;
1297 }
1298 if !(*cur).next.is_null() {
1299 cur = (*cur).next;
1300 break;
1301 }
1302 }
1303 }
1304 }
1305 count
1306}
1307use std::collections::HashMap;
1308use std::ffi::{CStr, CString};
1309
1310use crate::abi::structs::_xmlAttr;
1311use crate::xml::validation::{get_id, is_xml_name_char, is_xml_name_start};
1312use crate::xml::xpath::context::XPathContext;
1313use crate::xml::xpath::parser_context::{
1314 cast_top_to_number, compare_values_impl, equal_values_impl, free_parser_context, new_bool,
1315 new_number, new_parser_context, pc_set_error, pop_boolean, pop_external, pop_node_set,
1316 pop_number, pop_string, value_pop, value_push, XmlXPathParserContext,
1317};
1318
1319const unsafe fn pc_from(p: *mut c_void) -> *mut XmlXPathParserContext {
1323 p as *mut XmlXPathParserContext
1324}
1325
1326unsafe fn cstr_eq(a: *const xmlChar, b: *const xmlChar) -> bool {
1328 if a.is_null() || b.is_null() {
1329 return a == b;
1330 }
1331 let mut i = 0usize;
1332 loop {
1333 let ca = unsafe { *a.add(i) };
1334 let cb = unsafe { *b.add(i) };
1335 if ca != cb {
1336 return false;
1337 }
1338 if ca == 0 {
1339 return true;
1340 }
1341 i += 1;
1342 }
1343}
1344
1345const unsafe fn is_blank_ch(c: xmlChar) -> bool {
1347 c == b' ' || c == b'\t' || c == b'\n' || c == b'\r'
1348}
1349
1350unsafe fn cast_top_to_string(pc: *mut XmlXPathParserContext) {
1356 unsafe {
1357 let val = (*pc).value;
1358 if val.is_null() {
1359 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
1360 return;
1361 }
1362 if (*val).type_ != xmlXPathObjectType::XPATH_STRING as c_int {
1363 let v = crate::abi::exports_xml2::object_to_xpathvalue_pub(val);
1364 let s = v.as_string();
1365 if !(*val).stringval.is_null() {
1366 xmlFreeImpl((*val).stringval as *mut c_void);
1367 }
1368 (*val).stringval = dup_rust_string(&s);
1369 (*val).type_ = xmlXPathObjectType::XPATH_STRING as c_int;
1370 }
1371 }
1372}
1373
1374unsafe fn cast_top_to_boolean(pc: *mut XmlXPathParserContext) {
1380 unsafe {
1381 let val = (*pc).value;
1382 if val.is_null() {
1383 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
1384 return;
1385 }
1386 if (*val).type_ != xmlXPathObjectType::XPATH_BOOLEAN as c_int {
1387 let v = crate::abi::exports_xml2::object_to_xpathvalue_pub(val);
1388 (*val).boolval = v.as_boolean() as c_int;
1389 (*val).type_ = xmlXPathObjectType::XPATH_BOOLEAN as c_int;
1390 }
1391 }
1392}
1393
1394unsafe fn check_arity(pc: *mut XmlXPathParserContext, n: c_int) -> bool {
1397 if pc.is_null() || (*pc).value_nr < n {
1398 pc_set_error(pc, crate::abi::types::XPATH_INVALID_ARITY as c_int);
1399 return false;
1400 }
1401 true
1402}
1403
1404const unsafe fn scan_c_name(cur: *const xmlChar, nc: bool) -> usize {
1408 if cur.is_null() {
1409 return 0;
1410 }
1411 let mut i = 0usize;
1412 let mut first = true;
1413 loop {
1414 let b = unsafe { *cur.add(i) };
1415 if b == 0 {
1416 break;
1417 }
1418 if nc && b == b':' {
1419 break;
1420 }
1421 let (ch, adv): (char, usize) = if b < 0x80 {
1422 (b as char, 1)
1423 } else if b >= 0xC0 && b <= 0xDF {
1424 (
1425 unsafe {
1426 char::from_u32_unchecked(
1427 ((b as u32 & 0x1F) << 6) | (*cur.add(i + 1) as u32 & 0x3F),
1428 )
1429 },
1430 2,
1431 )
1432 } else if b >= 0xE0 && b <= 0xEF {
1433 (
1434 unsafe {
1435 char::from_u32_unchecked(
1436 ((b as u32 & 0x0F) << 12)
1437 | ((*cur.add(i + 1) as u32 & 0x3F) << 6)
1438 | (*cur.add(i + 2) as u32 & 0x3F),
1439 )
1440 },
1441 3,
1442 )
1443 } else if b >= 0xF0 && b <= 0xF7 {
1444 (
1445 unsafe {
1446 char::from_u32_unchecked(
1447 ((b as u32 & 0x07) << 18)
1448 | ((*cur.add(i + 1) as u32 & 0x3F) << 12)
1449 | ((*cur.add(i + 2) as u32 & 0x3F) << 6)
1450 | (*cur.add(i + 3) as u32 & 0x3F),
1451 )
1452 },
1453 4,
1454 )
1455 } else {
1456 break;
1457 };
1458 let ok = if first {
1459 is_xml_name_start(ch)
1460 } else {
1461 is_xml_name_char(ch)
1462 };
1463 if !ok {
1464 break;
1465 }
1466 first = false;
1467 i += adv;
1468 }
1469 i
1470}
1471
1472unsafe fn cstr_find(hay: *const xmlChar, needle: *const xmlChar) -> *const xmlChar {
1474 if hay.is_null() || needle.is_null() {
1475 return ptr::null();
1476 }
1477 if unsafe { *needle } == 0 {
1478 return hay;
1479 }
1480 let hlen = unsafe { crate::xml::string::xml_strlen(hay) };
1481 let nlen = unsafe { crate::xml::string::xml_strlen(needle) };
1482 if nlen > hlen {
1483 return ptr::null();
1484 }
1485 let hay_b = unsafe { core::slice::from_raw_parts(hay, hlen) };
1486 let needle_b = unsafe { core::slice::from_raw_parts(needle, nlen) };
1487 for off in 0..=hlen - nlen {
1488 if &hay_b[off..off + nlen] == needle_b {
1489 return unsafe { hay.add(off) };
1490 }
1491 }
1492 ptr::null()
1493}
1494
1495const XML_XML_NAMESPACE_BYTES: &[u8] = b"http://www.w3.org/XML/1998/namespace\0";
1497
1498struct XmlXPathXmlNs(_xmlNs);
1502unsafe impl Sync for XmlXPathXmlNs {}
1503static XML_XPATH_XML_NS: XmlXPathXmlNs = XmlXPathXmlNs(crate::abi::structs::_xmlNs {
1504 next: ptr::null_mut(),
1505 type_: crate::abi::types::xmlElementType::XML_NAMESPACE_DECL as c_int,
1506 href: XML_XML_NAMESPACE_BYTES.as_ptr() as *const xmlChar,
1507 prefix: c"xml".as_ptr() as *const xmlChar,
1508 _private: ptr::null_mut(),
1509 context: ptr::null_mut(),
1510});
1511
1512#[no_mangle]
1525pub unsafe extern "C" fn xmlXPathValuePush(
1526 ctxt: *mut c_void,
1527 value: *mut _xmlXPathObject,
1528) -> *mut _xmlXPathObject {
1529 value_push(pc_from(ctxt), value)
1530}
1531
1532#[no_mangle]
1538pub unsafe extern "C" fn xmlXPathValuePop(ctxt: *mut c_void) -> *mut _xmlXPathObject {
1539 value_pop(pc_from(ctxt))
1540}
1541
1542#[no_mangle]
1548pub unsafe extern "C" fn xmlXPathPopBoolean(ctxt: *mut c_void) -> c_int {
1549 pop_boolean(pc_from(ctxt))
1550}
1551
1552#[no_mangle]
1558pub unsafe extern "C" fn xmlXPathPopExternal(ctxt: *mut c_void) -> *mut c_void {
1559 pop_external(pc_from(ctxt))
1560}
1561
1562#[no_mangle]
1568pub unsafe extern "C" fn xmlXPathPopNodeSet(ctxt: *mut c_void) -> *mut _xmlNodeSet {
1569 pop_node_set(pc_from(ctxt))
1570}
1571
1572#[no_mangle]
1578pub unsafe extern "C" fn xmlXPathPopNumber(ctxt: *mut c_void) -> c_double {
1579 pop_number(pc_from(ctxt))
1580}
1581
1582#[no_mangle]
1588pub unsafe extern "C" fn xmlXPathPopString(ctxt: *mut c_void) -> *mut xmlChar {
1589 pop_string(pc_from(ctxt))
1590}
1591
1592unsafe fn binary_inplace(ctxt: *mut c_void, op: impl Fn(&mut f64, f64)) {
1597 let pc = pc_from(ctxt);
1598 if pc.is_null() {
1599 return;
1600 }
1601 let arg = value_pop(pc);
1602 if arg.is_null() {
1603 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
1604 return;
1605 }
1606 let val = crate::abi::exports_xml2::object_to_xpathvalue_pub(arg).as_number();
1607 crate::abi::exports_xml2::xmlXPathFreeObject(arg);
1608 if unsafe { (*pc).value.is_null() } {
1609 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
1610 return;
1611 }
1612 cast_top_to_number(pc);
1613 if (*pc).error != 0 {
1614 return;
1615 }
1616 unsafe {
1620 let float_ref: &mut f64 = &mut (*(*pc).value).floatval;
1621 op(float_ref, val);
1622 }
1623}
1624
1625#[no_mangle]
1642pub unsafe extern "C" fn xmlXPathAddValues(ctxt: *mut c_void) {
1643 binary_inplace(ctxt, |x, v| *x += v);
1644}
1645
1646#[no_mangle]
1663pub unsafe extern "C" fn xmlXPathSubValues(ctxt: *mut c_void) {
1664 binary_inplace(ctxt, |x, v| *x -= v);
1665}
1666
1667#[no_mangle]
1684pub unsafe extern "C" fn xmlXPathMultValues(ctxt: *mut c_void) {
1685 binary_inplace(ctxt, |x, v| *x *= v);
1686}
1687
1688#[no_mangle]
1705pub unsafe extern "C" fn xmlXPathDivValues(ctxt: *mut c_void) {
1706 binary_inplace(ctxt, |x, v| *x /= v);
1707}
1708
1709#[no_mangle]
1726pub unsafe extern "C" fn xmlXPathModValues(ctxt: *mut c_void) {
1727 binary_inplace(ctxt, |x, v| *x %= v);
1728}
1729
1730#[no_mangle]
1747pub unsafe extern "C" fn xmlXPathValueFlipSign(ctxt: *mut c_void) {
1748 let pc = pc_from(ctxt);
1749 if pc.is_null() {
1750 return;
1751 }
1752 cast_top_to_number(pc);
1753 if (*pc).error != 0 {
1754 return;
1755 }
1756 unsafe { (*(*pc).value).floatval = -(*(*pc).value).floatval };
1757}
1758
1759#[no_mangle]
1777pub unsafe extern "C" fn xmlXPathEqualValues(ctxt: *mut c_void) -> c_int {
1778 equal_values_impl(pc_from(ctxt), false)
1779}
1780
1781#[no_mangle]
1798pub unsafe extern "C" fn xmlXPathNotEqualValues(ctxt: *mut c_void) -> c_int {
1799 equal_values_impl(pc_from(ctxt), true)
1800}
1801
1802#[no_mangle]
1823pub unsafe extern "C" fn xmlXPathCompareValues(
1824 ctxt: *mut c_void,
1825 inf: c_int,
1826 strict: c_int,
1827) -> c_int {
1828 compare_values_impl(pc_from(ctxt), inf != 0, strict != 0)
1829}
1830
1831#[no_mangle]
1842pub unsafe extern "C" fn xmlXPathNewParserContext(
1843 str_: *const xmlChar,
1844 ctxt: *mut _xmlXPathContext,
1845) -> *mut c_void {
1846 new_parser_context(str_, ctxt) as *mut c_void
1847}
1848
1849#[no_mangle]
1855pub unsafe extern "C" fn xmlXPathFreeParserContext(ctxt: *mut c_void) {
1856 free_parser_context(pc_from(ctxt));
1857}
1858
1859#[no_mangle]
1866pub unsafe extern "C" fn xmlXPathParseNCName(ctxt: *mut c_void) -> *mut xmlChar {
1867 let pc = pc_from(ctxt);
1868 if pc.is_null() {
1869 return ptr::null_mut();
1870 }
1871 let cur = unsafe { (*pc).cur };
1872 if cur.is_null() {
1873 return ptr::null_mut();
1874 }
1875 let len = scan_c_name(cur, true);
1876 if len == 0 {
1877 return ptr::null_mut();
1878 }
1879 let ret = crate::xml::string::xml_strndup(cur, len);
1880 unsafe { (*pc).cur = cur.add(len) };
1881 ret
1882}
1883
1884#[no_mangle]
1891pub unsafe extern "C" fn xmlXPathParseName(ctxt: *mut c_void) -> *mut xmlChar {
1892 let pc = pc_from(ctxt);
1893 if pc.is_null() {
1894 return ptr::null_mut();
1895 }
1896 let cur = unsafe { (*pc).cur };
1897 if cur.is_null() {
1898 return ptr::null_mut();
1899 }
1900 let len = scan_c_name(cur, false);
1901 if len == 0 {
1902 return ptr::null_mut();
1903 }
1904 let ret = crate::xml::string::xml_strndup(cur, len);
1905 unsafe { (*pc).cur = cur.add(len) };
1906 ret
1907}
1908
1909#[no_mangle]
1916pub unsafe extern "C" fn xmlXPathRoot(ctxt: *mut c_void) {
1917 let pc = pc_from(ctxt);
1918 if pc.is_null() {
1919 return;
1920 }
1921 let ctx = unsafe { (*pc).context };
1922 if ctx.is_null() {
1923 return;
1924 }
1925 let ns = NodeSet::singleton(unsafe { (*ctx).doc } as *mut _xmlNode);
1926 let obj = crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(ns));
1927 value_push(pc, obj);
1928}
1929
1930#[no_mangle]
1938pub unsafe extern "C" fn xmlXPathEvalExpr(ctxt: *mut c_void) {
1939 let pc = pc_from(ctxt);
1940 if pc.is_null() {
1941 return;
1942 }
1943 let ctx = unsafe { (*pc).context };
1944 if ctx.is_null() {
1945 return;
1946 }
1947 let base = unsafe { (*pc).base };
1948 if base.is_null() {
1949 return;
1950 }
1951 let expr_str = match CStr::from_ptr(base as *const c_char).to_str() {
1952 Ok(s) => s,
1953 Err(_) => {
1954 pc_set_error(pc, crate::abi::types::XPATH_EXPR_ERROR as c_int);
1955 return;
1956 }
1957 };
1958 let internal = unsafe { (*ctx).extra } as *mut XPathContext;
1959 if internal.is_null() {
1960 return;
1961 }
1962 let internal = unsafe { &mut *internal };
1963 match crate::xml::xpath::evaluate_str(expr_str, internal) {
1964 Some(val) => {
1965 let obj = crate::abi::exports_xml2::xpath_to_object_pub(val);
1966 value_push(pc, obj);
1967 }
1968 None => {
1969 pc_set_error(pc, crate::abi::types::XPATH_EXPR_ERROR as c_int);
1970 }
1971 }
1972}
1973
1974unsafe fn eval_predicate_result(ctxt: *mut _xmlXPathContext, res: *mut _xmlXPathObject) -> c_int {
1976 if ctxt.is_null() || res.is_null() {
1977 return 0;
1978 }
1979 unsafe {
1980 let t = (*res).type_;
1981 if t == xmlXPathObjectType::XPATH_BOOLEAN as c_int {
1982 (*res).boolval
1983 } else if t == xmlXPathObjectType::XPATH_NUMBER as c_int {
1984 ((*res).floatval == (*ctxt).proximityPosition as f64) as c_int
1985 } else if t == xmlXPathObjectType::XPATH_NODESET as c_int
1986 || t == xmlXPathObjectType::XPATH_XSLT_TREE as c_int
1987 {
1988 let nsp = (*res).nodesetval as *mut _xmlNodeSet;
1989 if nsp.is_null() || (*nsp).nodeNr == 0 {
1990 0
1991 } else {
1992 1
1993 }
1994 } else if t == xmlXPathObjectType::XPATH_STRING as c_int {
1995 if (*res).stringval.is_null() || *(*res).stringval == 0 {
1996 0
1997 } else {
1998 1
1999 }
2000 } else {
2001 0
2002 }
2003 }
2004}
2005
2006#[no_mangle]
2013pub unsafe extern "C" fn xmlXPathEvalPredicate(
2014 ctxt: *mut _xmlXPathContext,
2015 res: *mut _xmlXPathObject,
2016) -> c_int {
2017 eval_predicate_result(ctxt, res)
2018}
2019
2020#[no_mangle]
2026pub unsafe extern "C" fn xmlXPathEvaluatePredicateResult(
2027 ctxt: *mut c_void,
2028 res: *mut _xmlXPathObject,
2029) -> c_int {
2030 let pc = pc_from(ctxt);
2031 if pc.is_null() {
2032 return 0;
2033 }
2034 let ctx = unsafe { (*pc).context };
2035 eval_predicate_result(ctx, res)
2036}
2037
2038#[no_mangle]
2059pub unsafe extern "C" fn xmlXPathNextSelf(ctxt: *mut c_void, cur: *mut _xmlNode) -> *mut _xmlNode {
2060 let pc = pc_from(ctxt);
2061 if pc.is_null() {
2062 return ptr::null_mut();
2063 }
2064 let ctx = unsafe { (*pc).context };
2065 if ctx.is_null() {
2066 return ptr::null_mut();
2067 }
2068 if cur.is_null() {
2069 return unsafe { (*ctx).node };
2070 }
2071 ptr::null_mut()
2072}
2073
2074#[no_mangle]
2091pub unsafe extern "C" fn xmlXPathNextChild(ctxt: *mut c_void, cur: *mut _xmlNode) -> *mut _xmlNode {
2092 let pc = pc_from(ctxt);
2093 if pc.is_null() {
2094 return ptr::null_mut();
2095 }
2096 let ctx = unsafe { (*pc).context };
2097 if ctx.is_null() {
2098 return ptr::null_mut();
2099 }
2100 use crate::abi::types::xmlElementType as ET;
2101 if cur.is_null() {
2102 let node = unsafe { (*ctx).node };
2103 if node.is_null() {
2104 return ptr::null_mut();
2105 }
2106 return match unsafe { (*node).type_ } {
2107 t if t == ET::XML_ELEMENT_NODE as c_int
2108 || t == ET::XML_TEXT_NODE as c_int
2109 || t == ET::XML_CDATA_SECTION_NODE as c_int
2110 || t == ET::XML_ENTITY_REF_NODE as c_int
2111 || t == ET::XML_ENTITY_NODE as c_int
2112 || t == ET::XML_PI_NODE as c_int
2113 || t == ET::XML_COMMENT_NODE as c_int
2114 || t == ET::XML_NOTATION_NODE as c_int
2115 || t == ET::XML_DTD_NODE as c_int =>
2116 unsafe { (*node).children },
2117 t if t == ET::XML_DOCUMENT_NODE as c_int
2118 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2119 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2120 || t == ET::XML_HTML_DOCUMENT_NODE as c_int =>
2121 unsafe { (*(node as *mut _xmlDoc)).children },
2122 _ => ptr::null_mut(),
2123 };
2124 }
2125 let t = unsafe { (*cur).type_ };
2126 if t == ET::XML_DOCUMENT_NODE as c_int || t == ET::XML_HTML_DOCUMENT_NODE as c_int {
2127 return ptr::null_mut();
2128 }
2129 unsafe { (*cur).next }
2130}
2131
2132#[no_mangle]
2149pub unsafe extern "C" fn xmlXPathNextDescendant(
2150 ctxt: *mut c_void,
2151 mut cur: *mut _xmlNode,
2152) -> *mut _xmlNode {
2153 let pc = pc_from(ctxt);
2154 if pc.is_null() {
2155 return ptr::null_mut();
2156 }
2157 let ctx = unsafe { (*pc).context };
2158 if ctx.is_null() {
2159 return ptr::null_mut();
2160 }
2161 use crate::abi::types::xmlElementType as ET;
2162 if cur.is_null() {
2163 let node = unsafe { (*ctx).node };
2164 if node.is_null() {
2165 return ptr::null_mut();
2166 }
2167 let t = unsafe { (*node).type_ };
2168 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
2169 return ptr::null_mut();
2170 }
2171 if node == unsafe { (*ctx).doc } as *mut _xmlNode {
2172 return unsafe { (*(*ctx).doc).children };
2173 }
2174 return unsafe { (*node).children };
2175 }
2176 unsafe {
2177 if (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2178 return ptr::null_mut();
2179 }
2180 if !(*cur).children.is_null() && (*(*cur).children).type_ != ET::XML_ENTITY_DECL as c_int {
2181 cur = (*cur).children;
2182 if (*cur).type_ != ET::XML_DTD_NODE as c_int {
2183 return cur;
2184 }
2185 }
2186 if cur == (*ctx).node {
2187 return ptr::null_mut();
2188 }
2189 while !(*cur).next.is_null() {
2190 cur = (*cur).next;
2191 if (*cur).type_ != ET::XML_ENTITY_DECL as c_int
2192 && (*cur).type_ != ET::XML_DTD_NODE as c_int
2193 {
2194 return cur;
2195 }
2196 }
2197 loop {
2198 cur = (*cur).parent;
2199 if cur.is_null() {
2200 break;
2201 }
2202 if cur == (*ctx).node {
2203 return ptr::null_mut();
2204 }
2205 if !(*cur).next.is_null() {
2206 cur = (*cur).next;
2207 return cur;
2208 }
2209 }
2210 cur
2211 }
2212}
2213
2214#[no_mangle]
2231pub unsafe extern "C" fn xmlXPathNextDescendantOrSelf(
2232 ctxt: *mut c_void,
2233 cur: *mut _xmlNode,
2234) -> *mut _xmlNode {
2235 let pc = pc_from(ctxt);
2236 if pc.is_null() {
2237 return ptr::null_mut();
2238 }
2239 let ctx = unsafe { (*pc).context };
2240 if ctx.is_null() {
2241 return ptr::null_mut();
2242 }
2243 if cur.is_null() {
2244 return unsafe { (*ctx).node };
2245 }
2246 let node = unsafe { (*ctx).node };
2247 if node.is_null() {
2248 return ptr::null_mut();
2249 }
2250 use crate::abi::types::xmlElementType as ET;
2251 let t = unsafe { (*node).type_ };
2252 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
2253 return ptr::null_mut();
2254 }
2255 xmlXPathNextDescendant(ctxt, cur)
2256}
2257
2258#[no_mangle]
2275pub unsafe extern "C" fn xmlXPathNextParent(
2276 ctxt: *mut c_void,
2277 cur: *mut _xmlNode,
2278) -> *mut _xmlNode {
2279 let pc = pc_from(ctxt);
2280 if pc.is_null() {
2281 return ptr::null_mut();
2282 }
2283 let ctx = unsafe { (*pc).context };
2284 if ctx.is_null() {
2285 return ptr::null_mut();
2286 }
2287 if !cur.is_null() {
2288 return ptr::null_mut();
2289 }
2290 next_parent_impl(ctx)
2291}
2292
2293unsafe fn next_parent_impl(ctx: *mut _xmlXPathContext) -> *mut _xmlNode {
2295 use crate::abi::types::xmlElementType as ET;
2296 let node = unsafe { (*ctx).node };
2297 if node.is_null() {
2298 return ptr::null_mut();
2299 }
2300 match unsafe { (*node).type_ } {
2301 t if t == ET::XML_ELEMENT_NODE as c_int
2302 || t == ET::XML_TEXT_NODE as c_int
2303 || t == ET::XML_CDATA_SECTION_NODE as c_int
2304 || t == ET::XML_ENTITY_REF_NODE as c_int
2305 || t == ET::XML_ENTITY_NODE as c_int
2306 || t == ET::XML_PI_NODE as c_int
2307 || t == ET::XML_COMMENT_NODE as c_int
2308 || t == ET::XML_NOTATION_NODE as c_int
2309 || t == ET::XML_DTD_NODE as c_int
2310 || t == ET::XML_ELEMENT_DECL as c_int
2311 || t == ET::XML_ATTRIBUTE_DECL as c_int
2312 || t == ET::XML_ENTITY_DECL as c_int
2313 || t == ET::XML_XINCLUDE_START as c_int
2314 || t == ET::XML_XINCLUDE_END as c_int =>
2315 unsafe {
2316 let parent = (*node).parent;
2317 if parent.is_null() {
2318 return (*ctx).doc as *mut _xmlNode;
2319 }
2320 if (*parent).type_ == ET::XML_ELEMENT_NODE as c_int
2321 && ((*parent).name.is_null() || *(*parent).name == b' ')
2322 {
2323 return ptr::null_mut();
2324 }
2325 parent
2326 },
2327 t if t == ET::XML_ATTRIBUTE_NODE as c_int => unsafe { (*(node as *mut _xmlAttr)).parent },
2328 t if t == ET::XML_DOCUMENT_NODE as c_int
2329 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2330 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2331 || t == ET::XML_HTML_DOCUMENT_NODE as c_int =>
2332 {
2333 ptr::null_mut()
2334 }
2335 t if t == ET::XML_NAMESPACE_DECL as c_int => unsafe {
2336 let ns = node as *mut crate::abi::structs::_xmlNs;
2337 if !(*ns).next.is_null() && (*(*ns).next).type_ != ET::XML_NAMESPACE_DECL as c_int {
2338 (*ns).next as *mut _xmlNode
2339 } else {
2340 ptr::null_mut()
2341 }
2342 },
2343 _ => ptr::null_mut(),
2344 }
2345}
2346
2347#[no_mangle]
2364pub unsafe extern "C" fn xmlXPathNextAncestor(
2365 ctxt: *mut c_void,
2366 cur: *mut _xmlNode,
2367) -> *mut _xmlNode {
2368 let pc = pc_from(ctxt);
2369 if pc.is_null() {
2370 return ptr::null_mut();
2371 }
2372 let ctx = unsafe { (*pc).context };
2373 if ctx.is_null() {
2374 return ptr::null_mut();
2375 }
2376 use crate::abi::types::xmlElementType as ET;
2377 if cur.is_null() {
2378 let node = unsafe { (*ctx).node };
2379 if node.is_null() {
2380 return ptr::null_mut();
2381 }
2382 let t = unsafe { (*node).type_ };
2383 if t == ET::XML_ATTRIBUTE_NODE as c_int {
2384 return unsafe { (*(node as *mut _xmlAttr)).parent };
2385 }
2386 if t == ET::XML_NAMESPACE_DECL as c_int {
2387 let ns = node as *mut crate::abi::structs::_xmlNs;
2388 return unsafe {
2389 if !(*ns).next.is_null() && (*(*ns).next).type_ != ET::XML_NAMESPACE_DECL as c_int {
2390 (*ns).next as *mut _xmlNode
2391 } else {
2392 ptr::null_mut()
2393 }
2394 };
2395 }
2396 if t == ET::XML_DOCUMENT_NODE as c_int
2397 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2398 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2399 || t == ET::XML_HTML_DOCUMENT_NODE as c_int
2400 {
2401 return ptr::null_mut();
2402 }
2403 return next_parent_impl(ctx);
2405 }
2406 if cur == unsafe { (*ctx).doc } as *mut _xmlNode {
2407 return ptr::null_mut();
2408 }
2409 if cur == unsafe { (*(*ctx).doc).children } {
2410 return unsafe { (*ctx).doc } as *mut _xmlNode;
2411 }
2412 let t = unsafe { (*cur).type_ };
2413 if t == ET::XML_ATTRIBUTE_NODE as c_int {
2414 return unsafe { (*(cur as *mut _xmlAttr)).parent };
2415 }
2416 if t == ET::XML_NAMESPACE_DECL as c_int {
2417 let ns = cur as *mut crate::abi::structs::_xmlNs;
2418 return unsafe {
2419 if !(*ns).next.is_null() && (*(*ns).next).type_ != ET::XML_NAMESPACE_DECL as c_int {
2420 (*ns).next as *mut _xmlNode
2421 } else {
2422 ptr::null_mut()
2423 }
2424 };
2425 }
2426 if t == ET::XML_DOCUMENT_NODE as c_int
2427 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2428 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2429 || t == ET::XML_HTML_DOCUMENT_NODE as c_int
2430 {
2431 return ptr::null_mut();
2432 }
2433 unsafe {
2434 let parent = (*cur).parent;
2435 if parent.is_null() {
2436 return ptr::null_mut();
2437 }
2438 if (*parent).type_ == ET::XML_ELEMENT_NODE as c_int
2439 && ((*parent).name.is_null() || *(*parent).name == b' ')
2440 {
2441 return ptr::null_mut();
2442 }
2443 parent
2444 }
2445}
2446
2447#[no_mangle]
2464pub unsafe extern "C" fn xmlXPathNextAncestorOrSelf(
2465 ctxt: *mut c_void,
2466 cur: *mut _xmlNode,
2467) -> *mut _xmlNode {
2468 let pc = pc_from(ctxt);
2469 if pc.is_null() {
2470 return ptr::null_mut();
2471 }
2472 let ctx = unsafe { (*pc).context };
2473 if ctx.is_null() {
2474 return ptr::null_mut();
2475 }
2476 if cur.is_null() {
2477 return unsafe { (*ctx).node };
2478 }
2479 xmlXPathNextAncestor(ctxt, cur)
2480}
2481
2482#[no_mangle]
2499pub unsafe extern "C" fn xmlXPathNextFollowingSibling(
2500 ctxt: *mut c_void,
2501 mut cur: *mut _xmlNode,
2502) -> *mut _xmlNode {
2503 let pc = pc_from(ctxt);
2504 if pc.is_null() {
2505 return ptr::null_mut();
2506 }
2507 let ctx = unsafe { (*pc).context };
2508 if ctx.is_null() {
2509 return ptr::null_mut();
2510 }
2511 use crate::abi::types::xmlElementType as ET;
2512 unsafe {
2513 let cnode = (*ctx).node;
2514 if !cnode.is_null() {
2515 let t = (*cnode).type_;
2516 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
2517 return ptr::null_mut();
2518 }
2519 }
2520 if cur == (*ctx).doc as *mut _xmlNode {
2521 return ptr::null_mut();
2522 }
2523 if cur.is_null() {
2524 cur = cnode;
2525 }
2526 if cur.is_null() {
2527 return ptr::null_mut();
2528 }
2529 if (*cur).type_ == ET::XML_DOCUMENT_NODE as c_int {
2530 return ptr::null_mut();
2531 }
2532 (*cur).next
2533 }
2534}
2535
2536#[no_mangle]
2553pub unsafe extern "C" fn xmlXPathNextPrecedingSibling(
2554 ctxt: *mut c_void,
2555 mut cur: *mut _xmlNode,
2556) -> *mut _xmlNode {
2557 let pc = pc_from(ctxt);
2558 if pc.is_null() {
2559 return ptr::null_mut();
2560 }
2561 let ctx = unsafe { (*pc).context };
2562 if ctx.is_null() {
2563 return ptr::null_mut();
2564 }
2565 use crate::abi::types::xmlElementType as ET;
2566 unsafe {
2567 let cnode = (*ctx).node;
2568 if !cnode.is_null() {
2569 let t = (*cnode).type_;
2570 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
2571 return ptr::null_mut();
2572 }
2573 }
2574 if cur == (*ctx).doc as *mut _xmlNode {
2575 return ptr::null_mut();
2576 }
2577 if cur.is_null() {
2578 cur = cnode;
2579 } else if !(*cur).prev.is_null() && (*(*cur).prev).type_ == ET::XML_DTD_NODE as c_int {
2580 cur = (*cur).prev;
2581 if cur.is_null() {
2582 return ptr::null_mut();
2583 }
2584 }
2585 if cur.is_null() {
2586 return ptr::null_mut();
2587 }
2588 if (*cur).type_ == ET::XML_DOCUMENT_NODE as c_int {
2589 return ptr::null_mut();
2590 }
2591 (*cur).prev
2592 }
2593}
2594
2595#[no_mangle]
2612pub unsafe extern "C" fn xmlXPathNextFollowing(
2613 ctxt: *mut c_void,
2614 mut cur: *mut _xmlNode,
2615) -> *mut _xmlNode {
2616 let pc = pc_from(ctxt);
2617 if pc.is_null() {
2618 return ptr::null_mut();
2619 }
2620 let ctx = unsafe { (*pc).context };
2621 if ctx.is_null() {
2622 return ptr::null_mut();
2623 }
2624 use crate::abi::types::xmlElementType as ET;
2625 unsafe {
2626 if !cur.is_null()
2627 && (*cur).type_ != ET::XML_ATTRIBUTE_NODE as c_int
2628 && (*cur).type_ != ET::XML_NAMESPACE_DECL as c_int
2629 && !(*cur).children.is_null()
2630 {
2631 return (*cur).children;
2632 }
2633 if cur.is_null() {
2634 cur = (*ctx).node;
2635 if cur.is_null() {
2636 return ptr::null_mut();
2637 }
2638 if (*cur).type_ == ET::XML_ATTRIBUTE_NODE as c_int {
2639 cur = (*cur).parent;
2640 } else if (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2641 let ns = cur as *mut crate::abi::structs::_xmlNs;
2642 if (*ns).next.is_null() || (*(*ns).next).type_ == ET::XML_NAMESPACE_DECL as c_int {
2643 return ptr::null_mut();
2644 }
2645 cur = (*ns).next as *mut _xmlNode;
2646 }
2647 }
2648 if cur.is_null() {
2649 return ptr::null_mut();
2650 }
2651 if (*cur).type_ == ET::XML_DOCUMENT_NODE as c_int {
2652 return ptr::null_mut();
2653 }
2654 if !(*cur).next.is_null() {
2655 return (*cur).next;
2656 }
2657 loop {
2658 cur = (*cur).parent;
2659 if cur.is_null() {
2660 break;
2661 }
2662 if cur == (*ctx).doc as *mut _xmlNode {
2663 return ptr::null_mut();
2664 }
2665 if !(*cur).next.is_null() && (*cur).type_ != ET::XML_DOCUMENT_NODE as c_int {
2666 return (*cur).next;
2667 }
2668 }
2669 cur
2670 }
2671}
2672
2673#[no_mangle]
2690pub unsafe extern "C" fn xmlXPathNextPreceding(
2691 ctxt: *mut c_void,
2692 mut cur: *mut _xmlNode,
2693) -> *mut _xmlNode {
2694 let pc = pc_from(ctxt);
2695 if pc.is_null() {
2696 return ptr::null_mut();
2697 }
2698 let ctx = unsafe { (*pc).context };
2699 if ctx.is_null() {
2700 return ptr::null_mut();
2701 }
2702 use crate::abi::types::xmlElementType as ET;
2703 unsafe {
2704 let is_ancestor = |ancestor: *mut _xmlNode, node: *mut _xmlNode| -> bool {
2705 if ancestor.is_null() || node.is_null() {
2706 return false;
2707 }
2708 if (*node).type_ == ET::XML_NAMESPACE_DECL as c_int
2709 || (*ancestor).type_ == ET::XML_NAMESPACE_DECL as c_int
2710 {
2711 return false;
2712 }
2713 if (*ancestor).doc != (*node).doc {
2714 return false;
2715 }
2716 if ancestor == (*node).doc as *mut _xmlNode {
2717 return true;
2718 }
2719 if node == (*ancestor).doc as *mut _xmlNode {
2720 return false;
2721 }
2722 let mut n = node;
2723 while !(*n).parent.is_null() {
2724 if (*n).parent == ancestor {
2725 return true;
2726 }
2727 n = (*n).parent;
2728 }
2729 false
2730 };
2731 if cur.is_null() {
2732 cur = (*ctx).node;
2733 if cur.is_null() {
2734 return ptr::null_mut();
2735 }
2736 if (*cur).type_ == ET::XML_ATTRIBUTE_NODE as c_int {
2737 cur = (*cur).parent;
2738 } else if (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2739 let ns = cur as *mut crate::abi::structs::_xmlNs;
2740 if (*ns).next.is_null() || (*(*ns).next).type_ == ET::XML_NAMESPACE_DECL as c_int {
2741 return ptr::null_mut();
2742 }
2743 cur = (*ns).next as *mut _xmlNode;
2744 }
2745 }
2746 if cur.is_null() || (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2747 return ptr::null_mut();
2748 }
2749 if !(*cur).prev.is_null() && (*(*cur).prev).type_ == ET::XML_DTD_NODE as c_int {
2750 cur = (*cur).prev;
2751 }
2752 loop {
2753 if !(*cur).prev.is_null() {
2754 let mut n = (*cur).prev;
2755 while !(*n).last.is_null() {
2756 n = (*n).last;
2757 }
2758 return n;
2759 }
2760 cur = (*cur).parent;
2761 if cur.is_null() {
2762 return ptr::null_mut();
2763 }
2764 if cur == (*(*ctx).doc).children {
2765 return ptr::null_mut();
2766 }
2767 if !is_ancestor(cur, (*ctx).node) {
2768 return cur;
2769 }
2770 }
2771 }
2772}
2773
2774#[no_mangle]
2791pub unsafe extern "C" fn xmlXPathNextNamespace(
2792 ctxt: *mut c_void,
2793 cur: *mut _xmlNode,
2794) -> *mut _xmlNode {
2795 let pc = pc_from(ctxt);
2796 if pc.is_null() {
2797 return ptr::null_mut();
2798 }
2799 let ctx = unsafe { (*pc).context };
2800 if ctx.is_null() {
2801 return ptr::null_mut();
2802 }
2803 use crate::abi::types::xmlElementType as ET;
2804 unsafe {
2805 let cnode = (*ctx).node;
2806 if cnode.is_null() || (*cnode).type_ != ET::XML_ELEMENT_NODE as c_int {
2807 return ptr::null_mut();
2808 }
2809 if cur.is_null() {
2810 if !(*ctx).tmpNsList.is_null() {
2811 xmlFreeImpl((*ctx).tmpNsList as *mut c_void);
2812 }
2813 (*ctx).tmpNsNr = 0;
2814 (*ctx).tmpNsList = crate::xml::tree::get_ns_list((*ctx).doc, cnode);
2815 if !(*ctx).tmpNsList.is_null() {
2816 while !(*(*ctx).tmpNsList.add((*ctx).tmpNsNr as usize)).is_null() {
2817 (*ctx).tmpNsNr += 1;
2818 }
2819 }
2820 return (&XML_XPATH_XML_NS.0) as *const crate::abi::structs::_xmlNs as *mut _xmlNode;
2821 }
2822 if (*ctx).tmpNsNr > 0 {
2823 (*ctx).tmpNsNr -= 1;
2824 return (*(*ctx).tmpNsList.add((*ctx).tmpNsNr as usize)) as *mut _xmlNode;
2825 }
2826 if !(*ctx).tmpNsList.is_null() {
2827 xmlFreeImpl((*ctx).tmpNsList as *mut c_void);
2828 }
2829 (*ctx).tmpNsList = ptr::null_mut();
2830 ptr::null_mut()
2831 }
2832}
2833
2834#[no_mangle]
2851pub unsafe extern "C" fn xmlXPathNextAttribute(
2852 ctxt: *mut c_void,
2853 cur: *mut _xmlNode,
2854) -> *mut _xmlNode {
2855 let pc = pc_from(ctxt);
2856 if pc.is_null() {
2857 return ptr::null_mut();
2858 }
2859 let ctx = unsafe { (*pc).context };
2860 if ctx.is_null() {
2861 return ptr::null_mut();
2862 }
2863 use crate::abi::types::xmlElementType as ET;
2864 unsafe {
2865 let cnode = (*ctx).node;
2866 if cnode.is_null() || (*cnode).type_ != ET::XML_ELEMENT_NODE as c_int {
2867 return ptr::null_mut();
2868 }
2869 if cur.is_null() {
2870 if cnode == (*ctx).doc as *mut _xmlNode {
2871 return ptr::null_mut();
2872 }
2873 return (*cnode).properties as *mut _xmlNode;
2874 }
2875 (*cur).next
2876 }
2877}
2878
2879#[no_mangle]
2900pub unsafe extern "C" fn xmlXPathBooleanFunction(ctxt: *mut c_void, _nargs: c_int) {
2901 let pc = pc_from(ctxt);
2902 if pc.is_null() {
2903 return;
2904 }
2905 if !check_arity(pc, 1) {
2906 return;
2907 }
2908 let cur = value_pop(pc);
2909 if cur.is_null() {
2910 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
2911 return;
2912 }
2913 let b = crate::abi::exports_xml2::object_to_xpathvalue_pub(cur).as_boolean();
2914 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
2915 value_push(pc, new_bool(b));
2916}
2917
2918#[no_mangle]
2935pub unsafe extern "C" fn xmlXPathNotFunction(ctxt: *mut c_void, _nargs: c_int) {
2936 let pc = pc_from(ctxt);
2937 if pc.is_null() {
2938 return;
2939 }
2940 if !check_arity(pc, 1) {
2941 return;
2942 }
2943 cast_top_to_boolean(pc);
2944 if (*pc).error != 0 {
2945 return;
2946 }
2947 unsafe {
2948 (*(*pc).value).boolval = if (*(*pc).value).boolval == 0 { 1 } else { 0 };
2949 }
2950}
2951
2952#[no_mangle]
2969pub unsafe extern "C" fn xmlXPathTrueFunction(ctxt: *mut c_void, _nargs: c_int) {
2970 let pc = pc_from(ctxt);
2971 if pc.is_null() {
2972 return;
2973 }
2974
2975 value_push(pc, new_bool(true));
2976}
2977
2978#[no_mangle]
2995pub unsafe extern "C" fn xmlXPathFalseFunction(ctxt: *mut c_void, _nargs: c_int) {
2996 let pc = pc_from(ctxt);
2997 if pc.is_null() {
2998 return;
2999 }
3000
3001 value_push(pc, new_bool(false));
3002}
3003
3004const unsafe fn lang_matches(lang: *const xmlChar, the_lang: *const xmlChar) -> bool {
3007 if lang.is_null() || the_lang.is_null() {
3008 return false;
3009 }
3010 let mut i = 0usize;
3011 loop {
3012 let lc = unsafe { *lang.add(i) };
3013 if lc == 0 {
3014 break;
3015 }
3016 let tc = unsafe { *the_lang.add(i) };
3017 if tc == 0 {
3018 return false;
3019 }
3020 if !lc.eq_ignore_ascii_case(&tc) {
3021 return false;
3022 }
3023 i += 1;
3024 }
3025 let c = unsafe { *the_lang.add(i) };
3026 c == 0 || c == b'-'
3027}
3028
3029#[no_mangle]
3046pub unsafe extern "C" fn xmlXPathLangFunction(ctxt: *mut c_void, _nargs: c_int) {
3047 let pc = pc_from(ctxt);
3048 if pc.is_null() {
3049 return;
3050 }
3051 let ctx = unsafe { (*pc).context };
3052 if ctx.is_null() {
3053 return;
3054 }
3055 if !check_arity(pc, 1) {
3056 return;
3057 }
3058 cast_top_to_string(pc);
3059 if (*pc).error != 0 {
3060 return;
3061 }
3062 let val = value_pop(pc);
3063 if val.is_null() {
3064 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3065 return;
3066 }
3067 let lang = unsafe { (*val).stringval };
3068 let mut ret = 0;
3069 unsafe {
3070 let mut n = (*ctx).node;
3071 let mut found: *mut xmlChar = ptr::null_mut();
3072 while !n.is_null() {
3073 let got = crate::xml::tree::get_ns_prop(
3074 n,
3075 c"lang".as_ptr() as *const xmlChar,
3076 XML_XML_NAMESPACE_BYTES.as_ptr() as *const xmlChar,
3077 );
3078 if !got.is_null() {
3079 found = got;
3080 break;
3081 }
3082 n = (*n).parent;
3083 }
3084 if !found.is_null() && lang_matches(lang, found) {
3085 ret = 1;
3086 }
3087 if !found.is_null() {
3088 xmlFreeImpl(found as *mut c_void);
3089 }
3090 }
3091 crate::abi::exports_xml2::xmlXPathFreeObject(val);
3092 value_push(pc, new_bool(ret != 0));
3093}
3094
3095#[no_mangle]
3112pub unsafe extern "C" fn xmlXPathNumberFunction(ctxt: *mut c_void, nargs: c_int) {
3113 let pc = pc_from(ctxt);
3114 if pc.is_null() {
3115 return;
3116 }
3117 let ctx = unsafe { (*pc).context };
3118 if ctx.is_null() {
3119 return;
3120 }
3121 if nargs == 0 {
3122 let node = unsafe { (*ctx).node };
3123 let res = if node.is_null() {
3124 0.0
3125 } else {
3126 let sv = node_string_value(node);
3127 crate::xml::xpath::types::string_to_number(&sv)
3128 };
3129 value_push(pc, new_number(res));
3130 return;
3131 }
3132 if !check_arity(pc, 1) {
3133 return;
3134 }
3135 cast_top_to_number(pc);
3136}
3137
3138#[no_mangle]
3155pub unsafe extern "C" fn xmlXPathSumFunction(ctxt: *mut c_void, _nargs: c_int) {
3156 let pc = pc_from(ctxt);
3157 if pc.is_null() {
3158 return;
3159 }
3160 if !check_arity(pc, 1) {
3161 return;
3162 }
3163 let cur = value_pop(pc);
3164 if cur.is_null() {
3165 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3166 return;
3167 }
3168 let typ = unsafe { (*cur).type_ };
3169 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3170 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3171 {
3172 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3173 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3174 return;
3175 }
3176 let mut res = 0.0;
3177 unsafe {
3178 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3179 if !ns.is_null() {
3180 let nr = (*ns).nodeNr;
3181 let tab = (*ns).nodeTab;
3182 if !tab.is_null() {
3183 for i in 0..nr as isize {
3184 let node = *tab.add(i as usize);
3185 let sv = node_string_value(node);
3186 res += crate::xml::xpath::types::string_to_number(&sv);
3187 }
3188 }
3189 }
3190 }
3191 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3192 value_push(pc, new_number(res));
3193}
3194
3195#[no_mangle]
3212pub unsafe extern "C" fn xmlXPathFloorFunction(ctxt: *mut c_void, _nargs: c_int) {
3213 let pc = pc_from(ctxt);
3214 if pc.is_null() {
3215 return;
3216 }
3217 if !check_arity(pc, 1) {
3218 return;
3219 }
3220 cast_top_to_number(pc);
3221 if (*pc).error != 0 {
3222 return;
3223 }
3224 unsafe {
3225 (*(*pc).value).floatval = (*(*pc).value).floatval.floor();
3226 }
3227}
3228
3229#[no_mangle]
3246pub unsafe extern "C" fn xmlXPathCeilingFunction(ctxt: *mut c_void, _nargs: c_int) {
3247 let pc = pc_from(ctxt);
3248 if pc.is_null() {
3249 return;
3250 }
3251 if !check_arity(pc, 1) {
3252 return;
3253 }
3254 cast_top_to_number(pc);
3255 if (*pc).error != 0 {
3256 return;
3257 }
3258 unsafe {
3259 (*(*pc).value).floatval = (*(*pc).value).floatval.ceil();
3260 }
3261}
3262
3263#[no_mangle]
3280pub unsafe extern "C" fn xmlXPathRoundFunction(ctxt: *mut c_void, _nargs: c_int) {
3281 let pc = pc_from(ctxt);
3282 if pc.is_null() {
3283 return;
3284 }
3285 if !check_arity(pc, 1) {
3286 return;
3287 }
3288 cast_top_to_number(pc);
3289 if (*pc).error != 0 {
3290 return;
3291 }
3292 unsafe {
3293 let f = (*(*pc).value).floatval;
3294 if (-0.5..0.5).contains(&f) {
3295 (*(*pc).value).floatval *= 0.0;
3297 } else {
3298 let mut rounded = f.floor();
3299 if f - rounded >= 0.5 {
3300 rounded += 1.0;
3301 }
3302 (*(*pc).value).floatval = rounded;
3303 }
3304 }
3305}
3306
3307#[no_mangle]
3324pub unsafe extern "C" fn xmlXPathLastFunction(ctxt: *mut c_void, _nargs: c_int) {
3325 let pc = pc_from(ctxt);
3326 if pc.is_null() {
3327 return;
3328 }
3329 let ctx = unsafe { (*pc).context };
3330 if ctx.is_null() {
3331 return;
3332 }
3333
3334 value_push(pc, new_number(unsafe { (*ctx).contextSize } as f64));
3335}
3336
3337#[no_mangle]
3354pub unsafe extern "C" fn xmlXPathPositionFunction(ctxt: *mut c_void, _nargs: c_int) {
3355 let pc = pc_from(ctxt);
3356 if pc.is_null() {
3357 return;
3358 }
3359 let ctx = unsafe { (*pc).context };
3360 if ctx.is_null() {
3361 return;
3362 }
3363
3364 value_push(pc, new_number(unsafe { (*ctx).proximityPosition } as f64));
3365}
3366
3367#[no_mangle]
3384pub unsafe extern "C" fn xmlXPathCountFunction(ctxt: *mut c_void, _nargs: c_int) {
3385 let pc = pc_from(ctxt);
3386 if pc.is_null() {
3387 return;
3388 }
3389 if !check_arity(pc, 1) {
3390 return;
3391 }
3392 let cur = value_pop(pc);
3393 if cur.is_null() {
3394 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3395 return;
3396 }
3397 let typ = unsafe { (*cur).type_ };
3398 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3399 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3400 {
3401 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3402 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3403 return;
3404 }
3405 let count = unsafe {
3406 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3407 if ns.is_null() {
3408 0
3409 } else {
3410 (*ns).nodeNr
3411 }
3412 };
3413 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3414 value_push(pc, new_number(count as f64));
3415}
3416
3417unsafe fn get_elements_by_ids(doc: *mut _xmlDoc, ids: *const xmlChar) -> *mut _xmlNodeSet {
3420 use crate::abi::types::xmlElementType as ET;
3421 if ids.is_null() {
3422 return ptr::null_mut();
3423 }
3424 let mut out = NodeSet::new();
3425 unsafe {
3426 let mut p = ids;
3427 while *p != 0 {
3428 while is_blank_ch(*p) {
3429 p = p.add(1);
3430 }
3431 if *p == 0 {
3432 break;
3433 }
3434 let start = p;
3435 while *p != 0 && !is_blank_ch(*p) {
3436 p = p.add(1);
3437 }
3438 let id_c = crate::xml::string::xml_strndup(start, p.offset_from(start) as usize);
3439 if id_c.is_null() {
3440 break;
3441 }
3442 let attr = get_id(doc, id_c);
3443 xmlFreeImpl(id_c as *mut c_void);
3444 if !attr.is_null() {
3445 let t = (*attr).type_;
3446 let elem = if t == ET::XML_ATTRIBUTE_NODE as c_int {
3447 (*attr).parent
3448 } else if t == ET::XML_ELEMENT_NODE as c_int {
3449 attr as *mut _xmlNode
3450 } else {
3451 ptr::null_mut()
3452 };
3453 if !elem.is_null() {
3454 out.push(elem);
3455 }
3456 }
3457 }
3458 }
3459 out.to_raw()
3460}
3461
3462#[no_mangle]
3479pub unsafe extern "C" fn xmlXPathIdFunction(ctxt: *mut c_void, _nargs: c_int) {
3480 let pc = pc_from(ctxt);
3481 if pc.is_null() {
3482 return;
3483 }
3484 let ctx = unsafe { (*pc).context };
3485 if ctx.is_null() {
3486 return;
3487 }
3488 if !check_arity(pc, 1) {
3489 return;
3490 }
3491 let obj = value_pop(pc);
3492 if obj.is_null() {
3493 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3494 return;
3495 }
3496 let doc = unsafe { (*ctx).doc };
3497 let v = crate::abi::exports_xml2::object_to_xpathvalue_pub(obj);
3498 crate::abi::exports_xml2::xmlXPathFreeObject(obj);
3499 match &v {
3500 XPathValue::NodeSet(ns) => {
3501 let mut merged = NodeSet::new();
3502 for n in ns.iter() {
3503 let sv = node_string_value(n);
3504 let c = dup_rust_string(&sv);
3505 let sub = get_elements_by_ids(doc, c);
3506 xmlFreeImpl(c as *mut c_void);
3507 if !sub.is_null() {
3508 let sub_internal = node_set_to_internal(sub);
3509 for m in sub_internal.iter() {
3510 if !merged.contains(m) {
3511 merged.push(m);
3512 }
3513 }
3514 crate::abi::exports_xml2::xmlXPathFreeNodeSet(sub);
3516 }
3517 }
3518 value_push(
3519 pc,
3520 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(merged)),
3521 );
3522 }
3523 _ => {
3524 let s = v.as_string();
3525 let c = dup_rust_string(&s);
3526 let ret = get_elements_by_ids(doc, c);
3527 xmlFreeImpl(c as *mut c_void);
3528 if ret.is_null() {
3529 value_push(
3530 pc,
3531 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(
3532 NodeSet::new(),
3533 )),
3534 );
3535 } else {
3536 let obj2 = crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(
3537 node_set_to_internal(ret),
3538 ));
3539 crate::abi::exports_xml2::xmlXPathFreeNodeSet(ret);
3540 value_push(pc, obj2);
3541 }
3542 }
3543 }
3544}
3545
3546unsafe fn node_local_name(node: *mut _xmlNode) -> String {
3549 use crate::abi::types::xmlElementType as ET;
3550 if node.is_null() {
3551 return String::new();
3552 }
3553 unsafe {
3554 match (*node).type_ {
3555 t if t == ET::XML_ELEMENT_NODE as c_int
3556 || t == ET::XML_ATTRIBUTE_NODE as c_int
3557 || t == ET::XML_PI_NODE as c_int =>
3558 {
3559 let name = (*node).name;
3560 if name.is_null() || *name == b' ' {
3561 String::new()
3562 } else {
3563 let s = CStr::from_ptr(name as *const c_char)
3564 .to_string_lossy()
3565 .into_owned();
3566 match s.split_once(':') {
3567 Some((_, local)) => local.to_string(),
3568 None => s,
3569 }
3570 }
3571 }
3572 t if t == ET::XML_NAMESPACE_DECL as c_int => {
3573 let ns = node as *mut crate::abi::structs::_xmlNs;
3574 let p = (*ns).prefix;
3575 if p.is_null() {
3576 String::new()
3577 } else {
3578 CStr::from_ptr(p as *const c_char)
3579 .to_string_lossy()
3580 .into_owned()
3581 }
3582 }
3583 _ => String::new(),
3584 }
3585 }
3586}
3587
3588#[no_mangle]
3605pub unsafe extern "C" fn xmlXPathLocalNameFunction(ctxt: *mut c_void, nargs: c_int) {
3606 let pc = pc_from(ctxt);
3607 if pc.is_null() {
3608 return;
3609 }
3610 let ctx = unsafe { (*pc).context };
3611 if ctx.is_null() {
3612 return;
3613 }
3614 if nargs == 0 {
3615 value_push(
3616 pc,
3617 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(NodeSet::singleton(
3618 unsafe { (*ctx).node },
3619 ))),
3620 );
3621 }
3623
3624 if !check_arity(pc, 1) {
3625 return;
3626 }
3627 let cur = value_pop(pc);
3628 if cur.is_null() {
3629 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3630 return;
3631 }
3632 let typ = unsafe { (*cur).type_ };
3633 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3634 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3635 {
3636 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3637 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3638 return;
3639 }
3640 let name = unsafe {
3641 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3642 if ns.is_null() || (*ns).nodeNr == 0 {
3643 String::new()
3644 } else {
3645 node_local_name(*(*ns).nodeTab)
3646 }
3647 };
3648 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3649 let out = dup_rust_string(&name);
3650 value_push(pc, xmlXPathWrapString(out));
3651}
3652
3653unsafe fn node_namespace_uri(node: *mut _xmlNode) -> String {
3655 use crate::abi::types::xmlElementType as ET;
3656 if node.is_null() {
3657 return String::new();
3658 }
3659 unsafe {
3660 match (*node).type_ {
3661 t if t == ET::XML_ELEMENT_NODE as c_int || t == ET::XML_ATTRIBUTE_NODE as c_int => {
3662 let ns = (*node).ns;
3663 if ns.is_null() || (*ns).href.is_null() {
3664 String::new()
3665 } else {
3666 CStr::from_ptr((*ns).href as *const c_char)
3667 .to_string_lossy()
3668 .into_owned()
3669 }
3670 }
3671 t if t == ET::XML_NAMESPACE_DECL as c_int => {
3672 let ns = node as *mut crate::abi::structs::_xmlNs;
3673 if (*ns).href.is_null() {
3674 String::new()
3675 } else {
3676 CStr::from_ptr((*ns).href as *const c_char)
3677 .to_string_lossy()
3678 .into_owned()
3679 }
3680 }
3681 _ => String::new(),
3682 }
3683 }
3684}
3685
3686#[no_mangle]
3703pub unsafe extern "C" fn xmlXPathNamespaceURIFunction(ctxt: *mut c_void, nargs: c_int) {
3704 let pc = pc_from(ctxt);
3705 if pc.is_null() {
3706 return;
3707 }
3708 let ctx = unsafe { (*pc).context };
3709 if ctx.is_null() {
3710 return;
3711 }
3712 if nargs == 0 {
3713 value_push(
3714 pc,
3715 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(NodeSet::singleton(
3716 unsafe { (*ctx).node },
3717 ))),
3718 );
3719 }
3720
3721 if !check_arity(pc, 1) {
3722 return;
3723 }
3724 let cur = value_pop(pc);
3725 if cur.is_null() {
3726 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3727 return;
3728 }
3729 let typ = unsafe { (*cur).type_ };
3730 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3731 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3732 {
3733 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3734 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3735 return;
3736 }
3737 let uri = unsafe {
3738 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3739 if ns.is_null() || (*ns).nodeNr == 0 {
3740 String::new()
3741 } else {
3742 node_namespace_uri(*(*ns).nodeTab)
3743 }
3744 };
3745 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3746 let out = dup_rust_string(&uri);
3747 value_push(pc, xmlXPathWrapString(out));
3748}
3749
3750#[no_mangle]
3767pub unsafe extern "C" fn xmlXPathStringFunction(ctxt: *mut c_void, nargs: c_int) {
3768 let pc = pc_from(ctxt);
3769 if pc.is_null() {
3770 return;
3771 }
3772 let ctx = unsafe { (*pc).context };
3773 if ctx.is_null() {
3774 return;
3775 }
3776 if nargs == 0 {
3777 let node = unsafe { (*ctx).node };
3778 let sv = if node.is_null() {
3779 String::new()
3780 } else {
3781 node_string_value(node)
3782 };
3783 let out = dup_rust_string(&sv);
3784 value_push(pc, xmlXPathWrapString(out));
3785 return;
3786 }
3787 if !check_arity(pc, 1) {
3788 return;
3789 }
3790 cast_top_to_string(pc);
3791}
3792
3793#[no_mangle]
3810pub unsafe extern "C" fn xmlXPathStringLengthFunction(ctxt: *mut c_void, nargs: c_int) {
3811 let pc = pc_from(ctxt);
3812 if pc.is_null() {
3813 return;
3814 }
3815 let ctx = unsafe { (*pc).context };
3816 if ctx.is_null() {
3817 return;
3818 }
3819 if nargs == 0 {
3820 let node = unsafe { (*ctx).node };
3821 let len = if node.is_null() {
3822 0
3823 } else {
3824 let sv = node_string_value(node);
3825 sv.chars().count()
3826 };
3827 value_push(pc, new_number(len as f64));
3828 return;
3829 }
3830 if !check_arity(pc, 1) {
3831 return;
3832 }
3833 cast_top_to_string(pc);
3834 if (*pc).error != 0 {
3835 return;
3836 }
3837 let len = unsafe {
3838 let s = (*(*pc).value).stringval;
3839 if s.is_null() {
3840 0
3841 } else {
3842 let sv = CStr::from_ptr(s as *const c_char).to_string_lossy();
3843 sv.chars().count()
3844 }
3845 };
3846 let cur = value_pop(pc);
3847 if !cur.is_null() {
3848 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3849 }
3850 value_push(pc, new_number(len as f64));
3851}
3852
3853#[no_mangle]
3870pub unsafe extern "C" fn xmlXPathConcatFunction(ctxt: *mut c_void, nargs: c_int) {
3871 let pc = pc_from(ctxt);
3872 if pc.is_null() {
3873 return;
3874 }
3875 if nargs < 2 && !check_arity(pc, 2) {
3876 return;
3877 }
3878 if !check_arity(pc, nargs) {
3879 return;
3880 }
3881 let mut parts: Vec<String> = Vec::with_capacity(nargs as usize);
3882 for _ in 0..nargs {
3883 cast_top_to_string(pc);
3884 if (*pc).error != 0 {
3885 return;
3886 }
3887 let v = crate::abi::exports_xml2::object_to_xpathvalue_pub(unsafe { (*pc).value });
3888 let s = v.as_string();
3889 let obj = value_pop(pc);
3890 if !obj.is_null() {
3891 crate::abi::exports_xml2::xmlXPathFreeObject(obj);
3892 }
3893 parts.push(s);
3894 }
3895 parts.reverse();
3896 let joined = parts.concat();
3897 let out = dup_rust_string(&joined);
3898 value_push(pc, xmlXPathWrapString(out));
3899}
3900
3901#[no_mangle]
3918pub unsafe extern "C" fn xmlXPathContainsFunction(ctxt: *mut c_void, _nargs: c_int) {
3919 let pc = pc_from(ctxt);
3920 if pc.is_null() {
3921 return;
3922 }
3923 if !check_arity(pc, 2) {
3924 return;
3925 }
3926 cast_top_to_string(pc);
3927 if (*pc).error != 0 {
3928 return;
3929 }
3930 let needle = value_pop(pc);
3931 cast_top_to_string(pc);
3932 if (*pc).error != 0 {
3933 if !needle.is_null() {
3934 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
3935 }
3936 return;
3937 }
3938 let hay = value_pop(pc);
3939 let found = if hay.is_null() || needle.is_null() {
3940 false
3941 } else {
3942 unsafe { !cstr_find((*hay).stringval, (*needle).stringval).is_null() }
3943 };
3944 if !hay.is_null() {
3945 crate::abi::exports_xml2::xmlXPathFreeObject(hay);
3946 }
3947 if !needle.is_null() {
3948 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
3949 }
3950 value_push(pc, new_bool(found));
3951}
3952
3953#[no_mangle]
3970pub unsafe extern "C" fn xmlXPathStartsWithFunction(ctxt: *mut c_void, _nargs: c_int) {
3971 let pc = pc_from(ctxt);
3972 if pc.is_null() {
3973 return;
3974 }
3975 if !check_arity(pc, 2) {
3976 return;
3977 }
3978 cast_top_to_string(pc);
3979 if (*pc).error != 0 {
3980 return;
3981 }
3982 let needle = value_pop(pc);
3983 cast_top_to_string(pc);
3984 if (*pc).error != 0 {
3985 if !needle.is_null() {
3986 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
3987 }
3988 return;
3989 }
3990 let hay = value_pop(pc);
3991 let found = if hay.is_null() || needle.is_null() {
3992 false
3993 } else {
3994 unsafe { crate::xml::string::xml_str_starts_with((*hay).stringval, (*needle).stringval) }
3995 };
3996 if !hay.is_null() {
3997 crate::abi::exports_xml2::xmlXPathFreeObject(hay);
3998 }
3999 if !needle.is_null() {
4000 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
4001 }
4002 value_push(pc, new_bool(found));
4003}
4004
4005#[no_mangle]
4022pub unsafe extern "C" fn xmlXPathSubstringFunction(ctxt: *mut c_void, nargs: c_int) {
4023 let pc = pc_from(ctxt);
4024 if pc.is_null() {
4025 return;
4026 }
4027 if nargs < 2 {
4028 if !check_arity(pc, 2) {
4029 return;
4030 }
4031 } else if nargs > 3 && !check_arity(pc, 3) {
4032 return;
4033 }
4034 let mut le = 0.0;
4035 if nargs == 3 {
4036 cast_top_to_number(pc);
4037 if (*pc).error != 0 {
4038 return;
4039 }
4040 let len_obj = value_pop(pc);
4041 if !len_obj.is_null() {
4042 le = unsafe { (*len_obj).floatval };
4043 crate::abi::exports_xml2::xmlXPathFreeObject(len_obj);
4044 }
4045 }
4046 cast_top_to_number(pc);
4047 if (*pc).error != 0 {
4048 return;
4049 }
4050 let start_obj = value_pop(pc);
4051 let in_ = if start_obj.is_null() {
4052 f64::NAN
4053 } else {
4054 let v = unsafe { (*start_obj).floatval };
4055 crate::abi::exports_xml2::xmlXPathFreeObject(start_obj);
4056 v
4057 };
4058 cast_top_to_string(pc);
4059 if (*pc).error != 0 {
4060 return;
4061 }
4062 let str_obj = value_pop(pc);
4063 let s = if str_obj.is_null() {
4064 String::new()
4065 } else {
4066 let v = unsafe { CStr::from_ptr((*str_obj).stringval as *const c_char) }
4067 .to_string_lossy()
4068 .into_owned();
4069 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
4070 v
4071 };
4072
4073 let int_max = i32::MAX as f64;
4074 let mut i: i64 = 1;
4075 let mut j: i64 = i32::MAX as i64;
4076 #[allow(clippy::neg_cmp_op_on_partial_ord)]
4080 if !(in_ < int_max) {
4081 i = i32::MAX as i64;
4082 } else if in_ >= 1.0 {
4083 i = in_ as i64;
4084 if in_ - in_.floor() >= 0.5 {
4085 i += 1;
4086 }
4087 }
4088 if nargs == 3 {
4089 let mut rin = in_.floor();
4090 if in_ - rin >= 0.5 {
4091 rin += 1.0;
4092 }
4093 let mut rle = le.floor();
4094 if le - rle >= 0.5 {
4095 rle += 1.0;
4096 }
4097 let end = rin + rle;
4098 #[allow(clippy::neg_cmp_op_on_partial_ord)]
4099 if !(end >= 1.0) {
4100 j = 1;
4101 } else if end < int_max {
4102 j = end as i64;
4103 }
4104 }
4105 i -= 1;
4106 j -= 1;
4107 let chars: Vec<char> = s.chars().collect();
4108 let slen = chars.len() as i64;
4109 let out = if i < j && i < slen {
4110 let start_i = i.max(0) as usize;
4111 let end_i = (j.min(slen)).max(start_i as i64) as usize;
4112 chars[start_i..end_i].iter().collect()
4113 } else {
4114 String::new()
4115 };
4116 let c = dup_rust_string(&out);
4117 value_push(pc, xmlXPathWrapString(c));
4118}
4119
4120#[no_mangle]
4137pub unsafe extern "C" fn xmlXPathSubstringBeforeFunction(ctxt: *mut c_void, _nargs: c_int) {
4138 let pc = pc_from(ctxt);
4139 if pc.is_null() {
4140 return;
4141 }
4142 if !check_arity(pc, 2) {
4143 return;
4144 }
4145 cast_top_to_string(pc);
4146 if (*pc).error != 0 {
4147 return;
4148 }
4149 let find = value_pop(pc);
4150 cast_top_to_string(pc);
4151 if (*pc).error != 0 {
4152 if !find.is_null() {
4153 crate::abi::exports_xml2::xmlXPathFreeObject(find);
4154 }
4155 return;
4156 }
4157 let str_obj = value_pop(pc);
4158 let out: String = if str_obj.is_null() || find.is_null() {
4159 String::new()
4160 } else {
4161 unsafe {
4162 let hay = (*str_obj).stringval;
4163 let needle = (*find).stringval;
4164 let point = cstr_find(hay, needle);
4165 if point.is_null() {
4166 String::new()
4167 } else {
4168 let len = point.offset_from(hay) as usize;
4169 let bytes = core::slice::from_raw_parts(hay as *const u8, len);
4170 String::from_utf8_lossy(bytes).into_owned()
4171 }
4172 }
4173 };
4174 if !str_obj.is_null() {
4175 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
4176 }
4177 if !find.is_null() {
4178 crate::abi::exports_xml2::xmlXPathFreeObject(find);
4179 }
4180 let c = dup_rust_string(&out);
4181 value_push(pc, xmlXPathWrapString(c));
4182}
4183
4184#[no_mangle]
4201pub unsafe extern "C" fn xmlXPathSubstringAfterFunction(ctxt: *mut c_void, _nargs: c_int) {
4202 let pc = pc_from(ctxt);
4203 if pc.is_null() {
4204 return;
4205 }
4206 if !check_arity(pc, 2) {
4207 return;
4208 }
4209 cast_top_to_string(pc);
4210 if (*pc).error != 0 {
4211 return;
4212 }
4213 let find = value_pop(pc);
4214 cast_top_to_string(pc);
4215 if (*pc).error != 0 {
4216 if !find.is_null() {
4217 crate::abi::exports_xml2::xmlXPathFreeObject(find);
4218 }
4219 return;
4220 }
4221 let str_obj = value_pop(pc);
4222 let out: String = if str_obj.is_null() || find.is_null() {
4223 String::new()
4224 } else {
4225 unsafe {
4226 let hay = (*str_obj).stringval;
4227 let needle = (*find).stringval;
4228 let point = cstr_find(hay, needle);
4229 if point.is_null() {
4230 String::new()
4231 } else {
4232 let nlen = crate::xml::string::xml_strlen(needle);
4233 let rest = point.add(nlen);
4234 let len = crate::xml::string::xml_strlen(rest);
4235 let bytes = core::slice::from_raw_parts(rest, len);
4236 String::from_utf8_lossy(bytes).into_owned()
4237 }
4238 }
4239 };
4240 if !str_obj.is_null() {
4241 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
4242 }
4243 if !find.is_null() {
4244 crate::abi::exports_xml2::xmlXPathFreeObject(find);
4245 }
4246 let c = dup_rust_string(&out);
4247 value_push(pc, xmlXPathWrapString(c));
4248}
4249
4250#[no_mangle]
4267pub unsafe extern "C" fn xmlXPathNormalizeFunction(ctxt: *mut c_void, nargs: c_int) {
4268 let pc = pc_from(ctxt);
4269 if pc.is_null() {
4270 return;
4271 }
4272 let ctx = unsafe { (*pc).context };
4273 if ctx.is_null() {
4274 return;
4275 }
4276 if nargs == 0 {
4277 let node = unsafe { (*ctx).node };
4278 let sv = if node.is_null() {
4279 String::new()
4280 } else {
4281 node_string_value(node)
4282 };
4283 let c = dup_rust_string(&sv);
4284 value_push(pc, xmlXPathWrapString(c));
4285 }
4287
4288 if !check_arity(pc, 1) {
4289 return;
4290 }
4291 cast_top_to_string(pc);
4292 if (*pc).error != 0 {
4293 return;
4294 }
4295 let s = unsafe {
4296 let p = (*(*pc).value).stringval;
4297 if p.is_null() {
4298 String::new()
4299 } else {
4300 CStr::from_ptr(p as *const c_char)
4301 .to_string_lossy()
4302 .into_owned()
4303 }
4304 };
4305 let mut out = String::with_capacity(s.len());
4307 let mut blank = false;
4308 let mut started = false;
4309 for c in s.chars() {
4310 let is_b = c == ' ' || c == '\t' || c == '\n' || c == '\r';
4311 if is_b {
4312 if started {
4313 blank = true;
4314 }
4315 } else {
4316 if blank {
4317 out.push(' ');
4318 blank = false;
4319 }
4320 out.push(c);
4321 started = true;
4322 }
4323 }
4324 unsafe {
4325 let val = (*pc).value;
4326 if !(*val).stringval.is_null() {
4327 xmlFreeImpl((*val).stringval as *mut c_void);
4328 }
4329 (*val).stringval = dup_rust_string(&out);
4330 }
4331}
4332
4333#[no_mangle]
4350pub unsafe extern "C" fn xmlXPathTranslateFunction(ctxt: *mut c_void, _nargs: c_int) {
4351 let pc = pc_from(ctxt);
4352 if pc.is_null() {
4353 return;
4354 }
4355 if !check_arity(pc, 3) {
4356 return;
4357 }
4358 cast_top_to_string(pc);
4359 if (*pc).error != 0 {
4360 return;
4361 }
4362 let to = value_pop(pc);
4363 cast_top_to_string(pc);
4364 if (*pc).error != 0 {
4365 if !to.is_null() {
4366 crate::abi::exports_xml2::xmlXPathFreeObject(to);
4367 }
4368 return;
4369 }
4370 let from = value_pop(pc);
4371 cast_top_to_string(pc);
4372 if (*pc).error != 0 {
4373 if !to.is_null() {
4374 crate::abi::exports_xml2::xmlXPathFreeObject(to);
4375 }
4376 if !from.is_null() {
4377 crate::abi::exports_xml2::xmlXPathFreeObject(from);
4378 }
4379 return;
4380 }
4381 let str_obj = value_pop(pc);
4382 let (s, f, t) = unsafe {
4383 let s = if str_obj.is_null() || (*str_obj).stringval.is_null() {
4384 String::new()
4385 } else {
4386 CStr::from_ptr((*str_obj).stringval as *const c_char)
4387 .to_string_lossy()
4388 .into_owned()
4389 };
4390 let f = if from.is_null() || (*from).stringval.is_null() {
4391 String::new()
4392 } else {
4393 CStr::from_ptr((*from).stringval as *const c_char)
4394 .to_string_lossy()
4395 .into_owned()
4396 };
4397 let t = if to.is_null() || (*to).stringval.is_null() {
4398 String::new()
4399 } else {
4400 CStr::from_ptr((*to).stringval as *const c_char)
4401 .to_string_lossy()
4402 .into_owned()
4403 };
4404 (s, f, t)
4405 };
4406 if !str_obj.is_null() {
4407 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
4408 }
4409 if !from.is_null() {
4410 crate::abi::exports_xml2::xmlXPathFreeObject(from);
4411 }
4412 if !to.is_null() {
4413 crate::abi::exports_xml2::xmlXPathFreeObject(to);
4414 }
4415 let from_chars: Vec<char> = f.chars().collect();
4416 let to_chars: Vec<char> = t.chars().collect();
4417 let out: String = s
4420 .chars()
4421 .filter_map(|c| match from_chars.iter().position(|&x| x == c) {
4422 Some(i) if i < to_chars.len() => Some(to_chars[i]),
4423 Some(_) => None,
4424 _ => Some(c),
4425 })
4426 .collect();
4427 let c = dup_rust_string(&out);
4428 value_push(pc, xmlXPathWrapString(c));
4429}
4430
4431#[no_mangle]
4449pub const unsafe extern "C" fn xmlXPathRegisterAllFunctions(_ctxt: *mut _xmlXPathContext) {}
4450
4451unsafe fn standard_function_pointer(
4454 name: &str,
4455) -> Option<unsafe extern "C" fn(*mut c_void, c_int)> {
4456 let f: unsafe extern "C" fn(*mut c_void, c_int) = match name {
4457 "boolean" => xmlXPathBooleanFunction,
4458 "not" => xmlXPathNotFunction,
4459 "true" => xmlXPathTrueFunction,
4460 "false" => xmlXPathFalseFunction,
4461 "lang" => xmlXPathLangFunction,
4462 "number" => xmlXPathNumberFunction,
4463 "sum" => xmlXPathSumFunction,
4464 "floor" => xmlXPathFloorFunction,
4465 "ceiling" => xmlXPathCeilingFunction,
4466 "round" => xmlXPathRoundFunction,
4467 "last" => xmlXPathLastFunction,
4468 "position" => xmlXPathPositionFunction,
4469 "count" => xmlXPathCountFunction,
4470 "id" => xmlXPathIdFunction,
4471 "local-name" => xmlXPathLocalNameFunction,
4472 "namespace-uri" => xmlXPathNamespaceURIFunction,
4473 "string" => xmlXPathStringFunction,
4474 "string-length" => xmlXPathStringLengthFunction,
4475 "concat" => xmlXPathConcatFunction,
4476 "contains" => xmlXPathContainsFunction,
4477 "starts-with" => xmlXPathStartsWithFunction,
4478 "substring" => xmlXPathSubstringFunction,
4479 "substring-before" => xmlXPathSubstringBeforeFunction,
4480 "substring-after" => xmlXPathSubstringAfterFunction,
4481 "normalize-space" => xmlXPathNormalizeFunction,
4482 "translate" => xmlXPathTranslateFunction,
4483 _ => return None,
4484 };
4485 Some(f)
4486}
4487
4488#[no_mangle]
4494pub unsafe extern "C" fn xmlXPathFunctionLookup(
4495 ctxt: *mut _xmlXPathContext,
4496 name: *const xmlChar,
4497) -> Option<unsafe extern "C" fn(*mut c_void, c_int)> {
4498 xmlXPathFunctionLookupNS(ctxt, name, ptr::null())
4499}
4500
4501#[no_mangle]
4507pub unsafe extern "C" fn xmlXPathFunctionLookupNS(
4508 ctxt: *mut _xmlXPathContext,
4509 name: *const xmlChar,
4510 ns_uri: *const xmlChar,
4511) -> Option<unsafe extern "C" fn(*mut c_void, c_int)> {
4512 if ctxt.is_null() || name.is_null() {
4513 return None;
4514 }
4515 let name_str = match CStr::from_ptr(name as *const c_char).to_str() {
4516 Ok(s) => s.to_string(),
4517 Err(_) => return None,
4518 };
4519 if ns_uri.is_null() {
4520 if let Some(f) = standard_function_pointer(&name_str) {
4521 return Some(f);
4522 }
4523 }
4524 if let Some(f) = (*ctxt).funcLookupFunc {
4526 let ret = f((*ctxt).funcLookupData, name, ns_uri);
4527 if !ret.is_null() {
4528 let fp =
4530 std::mem::transmute::<*mut c_void, unsafe extern "C" fn(*mut c_void, c_int)>(ret);
4531 return Some(fp);
4532 }
4533 }
4534 let qualified = if ns_uri.is_null() {
4535 name_str
4536 } else {
4537 let ns = match CStr::from_ptr(ns_uri as *const c_char).to_str() {
4538 Ok(s) => s,
4539 Err(_) => return None,
4540 };
4541 format!("{{{}}}{}", ns, name_str)
4542 };
4543 crate::abi::exports_xml2::xpath_cfunc_lookup((*ctxt).extra, &qualified)
4544}
4545
4546#[no_mangle]
4560pub unsafe extern "C" fn xmlXPathCtxtCompile(
4561 _ctxt: *mut _xmlXPathContext,
4562 str_: *const xmlChar,
4563) -> *mut c_void {
4564 crate::abi::exports_xml2::xmlXPathCompile(str_)
4565}
4566
4567#[no_mangle]
4573pub unsafe extern "C" fn xmlXPathCompiledEval(
4574 comp: *mut c_void,
4575 ctx: *mut _xmlXPathContext,
4576) -> *mut _xmlXPathObject {
4577 if comp.is_null() || ctx.is_null() {
4578 return ptr::null_mut();
4579 }
4580 let internal = (*ctx).extra as *mut XPathContext;
4581 if internal.is_null() {
4582 return ptr::null_mut();
4583 }
4584 let internal = &mut *internal;
4585 let registry = crate::abi::exports_xml2::xpath_compiled_registry();
4586 let map = registry.lock();
4587 match map.get(&(comp as u64)) {
4588 Some(compiled) => match crate::xml::xpath::evaluate(compiled, internal) {
4589 Some(val) => crate::abi::exports_xml2::xpath_to_object_pub(val),
4590 None => ptr::null_mut(),
4591 },
4592 None => ptr::null_mut(),
4593 }
4594}
4595
4596#[no_mangle]
4604pub unsafe extern "C" fn xmlXPathCompiledEvalToBoolean(
4605 comp: *mut c_void,
4606 ctxt: *mut _xmlXPathContext,
4607) -> c_int {
4608 let obj = xmlXPathCompiledEval(comp, ctxt);
4609 if obj.is_null() {
4610 return -1;
4611 }
4612 let b = crate::abi::exports_xml2::object_to_xpathvalue_pub(obj).as_boolean();
4613 crate::abi::exports_xml2::xmlXPathFreeObject(obj);
4614 b as c_int
4615}
4616
4617#[no_mangle]
4624pub unsafe extern "C" fn xmlXPathSetContextNode(
4625 node: *mut _xmlNode,
4626 ctx: *mut _xmlXPathContext,
4627) -> c_int {
4628 if node.is_null() || ctx.is_null() {
4629 return -1;
4630 }
4631 if (*node).doc != (*ctx).doc {
4632 return -1;
4633 }
4634 (*ctx).node = node;
4635 let internal = (*ctx).extra as *mut XPathContext;
4636 if !internal.is_null() {
4637 (*internal).context_node = node;
4638 }
4639 0
4640}
4641
4642#[no_mangle]
4648pub unsafe extern "C" fn xmlXPathNodeEval(
4649 node: *mut _xmlNode,
4650 str_: *const xmlChar,
4651 ctx: *mut _xmlXPathContext,
4652) -> *mut _xmlXPathObject {
4653 if str_.is_null() {
4654 return ptr::null_mut();
4655 }
4656 if xmlXPathSetContextNode(node, ctx) < 0 {
4657 return ptr::null_mut();
4658 }
4659 crate::abi::exports_xml2::xmlXPathEvalExpression(str_, ctx)
4660}
4661
4662#[no_mangle]
4671pub unsafe extern "C" fn xmlXPathContextSetCache(
4672 ctxt: *mut _xmlXPathContext,
4673 active: c_int,
4674 _value: c_int,
4675 _options: c_int,
4676) -> c_int {
4677 if ctxt.is_null() {
4678 return -1;
4679 }
4680 (*ctxt).cache = if active != 0 {
4681 (&XML_XPATH_XML_NS.0) as *const crate::abi::structs::_xmlNs as *mut c_void
4682 } else {
4683 ptr::null_mut()
4684 };
4685 0
4686}
4687
4688#[no_mangle]
4694pub unsafe extern "C" fn xmlXPathRegisterFuncLookup(
4695 ctxt: *mut _xmlXPathContext,
4696 f: Option<crate::abi::callbacks::xmlXPathFuncLookupFunc>,
4697 data: *mut c_void,
4698) {
4699 if ctxt.is_null() {
4700 return;
4701 }
4702 (*ctxt).funcLookupFunc = f;
4703 (*ctxt).funcLookupData = data;
4704 let internal = (*ctxt).extra as *mut XPathContext;
4705 if !internal.is_null() {
4706 (*internal).func_lookup_func = f;
4707 (*internal).func_lookup_data = data;
4708 }
4709}
4710
4711#[no_mangle]
4717pub unsafe extern "C" fn xmlXPathRegisterVariableLookup(
4718 ctxt: *mut _xmlXPathContext,
4719 f: Option<crate::abi::callbacks::xmlXPathVariableLookupFunc>,
4720 data: *mut c_void,
4721) {
4722 if ctxt.is_null() {
4723 return;
4724 }
4725 (*ctxt).varLookupFunc = f;
4726 (*ctxt).varLookupData = data;
4727 let internal = (*ctxt).extra as *mut XPathContext;
4728 if !internal.is_null() {
4729 (*internal).var_lookup_func = f;
4730 (*internal).var_lookup_data = data;
4731 }
4732}
4733
4734#[no_mangle]
4740pub unsafe extern "C" fn xmlXPathRegisterVariableNS(
4741 ctxt: *mut _xmlXPathContext,
4742 name: *const xmlChar,
4743 ns_uri: *const xmlChar,
4744 value: *mut _xmlXPathObject,
4745) -> c_int {
4746 if ctxt.is_null() || name.is_null() || value.is_null() {
4747 return -1;
4748 }
4749 let internal = (*ctxt).extra as *mut XPathContext;
4750 if internal.is_null() {
4751 return -1;
4752 }
4753 let internal = &mut *internal;
4754 let name_str = match CStr::from_ptr(name as *const c_char).to_str() {
4755 Ok(s) => s.to_string(),
4756 Err(_) => return -1,
4757 };
4758 let qualified = if ns_uri.is_null() {
4759 name_str
4760 } else {
4761 match CStr::from_ptr(ns_uri as *const c_char).to_str() {
4762 Ok(s) => format!("{{{}}}{}", s, name_str),
4763 Err(_) => return -1,
4764 }
4765 };
4766 let xpath_val = crate::abi::exports_xml2::object_to_xpathvalue_pub(value);
4767 internal.register_variable(&qualified, xpath_val);
4768 0
4769}
4770
4771#[no_mangle]
4777pub unsafe extern "C" fn xmlXPathVariableLookup(
4778 ctxt: *mut _xmlXPathContext,
4779 name: *const xmlChar,
4780) -> *mut _xmlXPathObject {
4781 if ctxt.is_null() {
4782 return ptr::null_mut();
4783 }
4784 if let Some(f) = (*ctxt).varLookupFunc {
4785 let ret = f((*ctxt).varLookupData, name, ptr::null());
4786 return ret;
4787 }
4788 xmlXPathVariableLookupNS(ctxt, name, ptr::null())
4789}
4790
4791#[no_mangle]
4797pub unsafe extern "C" fn xmlXPathVariableLookupNS(
4798 ctxt: *mut _xmlXPathContext,
4799 name: *const xmlChar,
4800 ns_uri: *const xmlChar,
4801) -> *mut _xmlXPathObject {
4802 if ctxt.is_null() || name.is_null() {
4803 return ptr::null_mut();
4804 }
4805 if let Some(f) = (*ctxt).varLookupFunc {
4806 let ret = f((*ctxt).varLookupData, name, ns_uri);
4807 if !ret.is_null() {
4808 return ret;
4809 }
4810 }
4811 let internal = (*ctxt).extra as *mut XPathContext;
4812 if internal.is_null() {
4813 return ptr::null_mut();
4814 }
4815 let internal = &*internal;
4816 let name_str = match CStr::from_ptr(name as *const c_char).to_str() {
4817 Ok(s) => s.to_string(),
4818 Err(_) => return ptr::null_mut(),
4819 };
4820 let qualified = if ns_uri.is_null() {
4821 name_str
4822 } else {
4823 match CStr::from_ptr(ns_uri as *const c_char).to_str() {
4824 Ok(s) => format!("{{{}}}{}", s, name_str),
4825 Err(_) => return ptr::null_mut(),
4826 }
4827 };
4828 match internal.variables.get(&qualified) {
4829 Some(v) => crate::abi::exports_xml2::xpath_to_object_pub(v.clone()),
4830 None => ptr::null_mut(),
4831 }
4832}
4833
4834#[no_mangle]
4840pub unsafe extern "C" fn xmlXPathNsLookup(
4841 ctxt: *mut _xmlXPathContext,
4842 prefix: *const xmlChar,
4843) -> *const xmlChar {
4844 if ctxt.is_null() || prefix.is_null() {
4845 return ptr::null();
4846 }
4847 if cstr_eq(prefix, c"xml".as_ptr() as *const xmlChar) {
4849 return XML_XML_NAMESPACE_BYTES.as_ptr() as *const xmlChar;
4850 }
4851 let namespaces = (*ctxt).namespaces;
4853 if !namespaces.is_null() {
4854 for i in 0..(*ctxt).nsNr as isize {
4855 let ns = *namespaces.add(i as usize);
4856 if !ns.is_null() && !(*ns).prefix.is_null() && cstr_eq((*ns).prefix, prefix) {
4857 return (*ns).href;
4858 }
4859 }
4860 }
4861 if !(*ctxt).nsHash.is_null() {
4864 let map = &*((*ctxt).nsHash as *const HashMap<String, CString>);
4865 let p = CStr::from_ptr(prefix as *const c_char)
4866 .to_string_lossy()
4867 .into_owned();
4868 if let Some(c) = map.get(&p) {
4869 return c.as_ptr() as *const xmlChar;
4870 }
4871 }
4872 ptr::null()
4873}
4874
4875#[no_mangle]
4881pub unsafe extern "C" fn xmlXPathRegisteredFuncsCleanup(ctxt: *mut _xmlXPathContext) {
4882 if ctxt.is_null() {
4883 return;
4884 }
4885 let internal = (*ctxt).extra as *mut XPathContext;
4886 if !internal.is_null() {
4887 (*internal).functions.clear();
4888 }
4889 crate::abi::exports_xml2::xpath_cfunc_cleanup((*ctxt).extra);
4890}
4891
4892#[no_mangle]
4898pub unsafe extern "C" fn xmlXPathRegisteredVariablesCleanup(ctxt: *mut _xmlXPathContext) {
4899 if ctxt.is_null() {
4900 return;
4901 }
4902 let internal = (*ctxt).extra as *mut XPathContext;
4903 if !internal.is_null() {
4904 (*internal).variables.clear();
4905 }
4906}
4907
4908#[no_mangle]
4914pub unsafe extern "C" fn xmlXPathRegisteredNsCleanup(ctxt: *mut _xmlXPathContext) {
4915 if ctxt.is_null() {
4916 return;
4917 }
4918 let internal = (*ctxt).extra as *mut XPathContext;
4919 if !internal.is_null() {
4920 (*internal).namespaces.clear();
4921 }
4922 if !(*ctxt).nsHash.is_null() {
4923 drop(Box::from_raw(
4924 (*ctxt).nsHash as *mut HashMap<String, CString>,
4925 ));
4926 (*ctxt).nsHash = ptr::null_mut();
4927 }
4928}
4929
4930#[no_mangle]
4936pub unsafe extern "C" fn xmlXPathSetErrorHandler(
4937 ctxt: *mut _xmlXPathContext,
4938 handler: Option<crate::abi::callbacks::xmlStructuredErrorFunc>,
4939 data: *mut c_void,
4940) {
4941 if ctxt.is_null() {
4942 return;
4943 }
4944 (*ctxt).error = handler;
4945 (*ctxt).userData = data;
4946}
4947
4948extern "C" {
4949 fn fwrite(ptr: *const c_void, size: usize, nmemb: usize, stream: *mut c_void) -> usize;
4950}
4951
4952unsafe fn dump_write(output: *mut c_void, s: &str) {
4953 unsafe {
4954 fwrite(s.as_ptr() as *const c_void, 1, s.len(), output);
4955 }
4956}
4957
4958#[no_mangle]
4964pub unsafe extern "C" fn xmlXPathDebugDumpObject(
4965 output: *mut c_void,
4966 cur: *mut _xmlXPathObject,
4967 depth: c_int,
4968) {
4969 if output.is_null() {
4970 return;
4971 }
4972 let mut s = String::new();
4973 for _ in 0..depth.clamp(0, 25) {
4974 s.push_str(" ");
4975 }
4976 if cur.is_null() {
4977 s.push_str("Object is empty (NULL)\n");
4978 dump_write(output, &s);
4979 return;
4980 }
4981 unsafe {
4982 match (*cur).type_ {
4983 t if t == xmlXPathObjectType::XPATH_BOOLEAN as c_int => {
4984 s.push_str("Object is a Boolean : ");
4985 s.push_str(if (*cur).boolval != 0 {
4986 "true\n"
4987 } else {
4988 "false\n"
4989 });
4990 }
4991 t if t == xmlXPathObjectType::XPATH_NUMBER as c_int => {
4992 let f = (*cur).floatval;
4993 if f.is_nan() {
4994 s.push_str("Object is a number : NaN\n");
4995 } else if f == f64::INFINITY {
4996 s.push_str("Object is a number : Infinity\n");
4997 } else if f == f64::NEG_INFINITY {
4998 s.push_str("Object is a number : -Infinity\n");
4999 } else if f == 0.0 {
5000 s.push_str("Object is a number : 0\n");
5001 } else {
5002 s.push_str("Object is a number : ");
5003 s.push_str(&f.to_string());
5004 s.push('\n');
5005 }
5006 }
5007 t if t == xmlXPathObjectType::XPATH_STRING as c_int => {
5008 s.push_str("Object is a string : ");
5009 if (*cur).stringval.is_null() {
5010 s.push_str("(null)");
5011 } else {
5012 let sv = CStr::from_ptr((*cur).stringval as *const c_char).to_string_lossy();
5013 s.push_str(&sv);
5014 }
5015 s.push('\n');
5016 }
5017 t if t == xmlXPathObjectType::XPATH_NODESET as c_int => {
5018 s.push_str("Object is a Node Set :\n");
5019 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
5020 if !ns.is_null() {
5021 for _ in 0..=depth.min(24) {
5022 s.push_str(" ");
5023 }
5024 s.push_str(&format!("Object contains {} nodes\n", (*ns).nodeNr));
5025 }
5026 }
5027 t if t == xmlXPathObjectType::XPATH_XSLT_TREE as c_int => {
5028 s.push_str("Object is an XSLT value tree :\n");
5029 }
5030 t if t == xmlXPathObjectType::XPATH_USERS as c_int => {
5031 s.push_str("Object is user defined\n");
5032 }
5033 _ => {
5034 s.push_str("Object is uninitialized\n");
5035 }
5036 }
5037 }
5038 dump_write(output, &s);
5039}
5040
5041#[no_mangle]
5051pub unsafe extern "C" fn xmlXPathDebugDumpCompExpr(
5052 output: *mut c_void,
5053 comp: *mut c_void,
5054 depth: c_int,
5055) {
5056 if output.is_null() || comp.is_null() {
5057 return;
5058 }
5059 let registry = crate::abi::exports_xml2::xpath_compiled_registry();
5060 let map = registry.lock();
5061 if let Some(compiled) = map.get(&(comp as u64)) {
5062 let mut s = String::new();
5063 for _ in 0..depth.clamp(0, 25) {
5064 s.push_str(" ");
5065 }
5066 s.push_str("Compiled Expression : ");
5067 s.push_str(&compiled.original);
5068 s.push('\n');
5069 dump_write(output, &s);
5070 }
5071}
5072
5073#[allow(unused)]
5074const fn _unused_xpath_batch(_: *mut _xmlAttr) {}