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