1#![allow(
64 missing_docs,
65 non_snake_case,
66 non_camel_case_types,
67 non_upper_case_globals
68)]
69
70use core::ffi::c_void;
81use core::ptr;
82use std::os::raw::{c_char, c_double, c_int, c_long};
83
84use crate::abi::allocator::{xmlFreeImpl, xmlMallocImpl, xmlMallocZero};
85use crate::abi::structs::{
86 _xmlDoc, _xmlNode, _xmlNodeSet, _xmlNs, _xmlXPathContext, _xmlXPathObject,
87};
88use crate::abi::types::{xmlChar, xmlXPathObjectType};
89use crate::xml::string::xml_strdup;
90use crate::xml::xpath::types::{node_string_value, NodeSet, XPathValue};
91
92fn number_to_xmlstring(val: c_double) -> *mut xmlChar {
94 let s = crate::xml::xpath::types::number_to_string(val);
95 dup_rust_string(&s)
96}
97
98fn dup_rust_string(s: &str) -> *mut xmlChar {
102 let bytes = s.as_bytes();
103 let buf = unsafe { xmlMallocImpl(bytes.len() + 1) } as *mut xmlChar;
104 if buf.is_null() {
105 return ptr::null_mut();
106 }
107 unsafe {
108 ptr::copy_nonoverlapping(bytes.as_ptr(), buf, bytes.len());
109 *buf.add(bytes.len()) = 0;
110 }
111 buf
112}
113
114#[no_mangle]
124pub unsafe extern "C" fn xmlXPathNewString(val: *const xmlChar) -> *mut _xmlXPathObject {
125 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
126 if obj.is_null() {
127 return ptr::null_mut();
128 }
129 (*obj).type_ = xmlXPathObjectType::XPATH_STRING as c_int;
130 (*obj).stringval = if val.is_null() {
131 xml_strdup(c"".as_ptr() as *const xmlChar)
132 } else {
133 xml_strdup(val)
134 };
135 obj
136}
137
138#[no_mangle]
145pub unsafe extern "C" fn xmlXPathNewValueTree(val: *mut _xmlNode) -> *mut _xmlXPathObject {
146 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
147 if obj.is_null() {
148 return ptr::null_mut();
149 }
150 (*obj).type_ = xmlXPathObjectType::XPATH_XSLT_TREE as c_int;
151 let ns = xmlMallocZero(size_of::<_xmlNodeSet>()) as *mut _xmlNodeSet;
152 if ns.is_null() {
153 xmlFreeImpl(obj as *mut c_void);
154 return ptr::null_mut();
155 }
156 (*ns).nodeNr = 0;
157 (*ns).nodeMax = 1;
158 let tab = xmlMallocImpl(size_of::<*mut _xmlNode>()) as *mut *mut _xmlNode;
159 if tab.is_null() {
160 xmlFreeImpl(ns as *mut c_void);
161 xmlFreeImpl(obj as *mut c_void);
162 return ptr::null_mut();
163 }
164 if val.is_null() {
165 (*ns).nodeNr = 0;
166 (*ns).nodeMax = 0;
167 xmlFreeImpl(tab as *mut c_void);
168 (*ns).nodeTab = ptr::null_mut();
169 } else {
170 ptr::write(tab, val);
171 (*ns).nodeTab = tab;
172 (*ns).nodeNr = 1;
173 }
174 (*obj).nodesetval = ns as *mut c_void;
175 obj
176}
177
178#[no_mangle]
185pub unsafe extern "C" fn xmlXPathNewNodeSetList(val: *mut _xmlNodeSet) -> *mut _xmlXPathObject {
186 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
187 if obj.is_null() {
188 return ptr::null_mut();
189 }
190 (*obj).type_ = xmlXPathObjectType::XPATH_NODESET as c_int;
191 if val.is_null() {
192 (*obj).nodesetval = ptr::null_mut();
193 return obj;
194 }
195 let src = &*val;
196 let nr = src.nodeNr;
197 let ns = xmlMallocZero(size_of::<_xmlNodeSet>()) as *mut _xmlNodeSet;
198 if ns.is_null() {
199 xmlFreeImpl(obj as *mut c_void);
200 return ptr::null_mut();
201 }
202 (*ns).nodeNr = nr;
203 (*ns).nodeMax = nr;
204 if nr > 0 && !src.nodeTab.is_null() {
205 let tab = xmlMallocImpl((nr as usize) * size_of::<*mut _xmlNode>()) as *mut *mut _xmlNode;
206 if tab.is_null() {
207 xmlFreeImpl(ns as *mut c_void);
208 xmlFreeImpl(obj as *mut c_void);
209 return ptr::null_mut();
210 }
211 ptr::copy_nonoverlapping(src.nodeTab, tab, nr as usize);
212 (*ns).nodeTab = tab;
213 } else {
214 (*ns).nodeTab = ptr::null_mut();
215 }
216 (*obj).nodesetval = ns as *mut c_void;
217 obj
218}
219
220#[no_mangle]
227pub unsafe extern "C" fn xmlXPathWrapString(val: *mut xmlChar) -> *mut _xmlXPathObject {
228 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
229 if obj.is_null() {
230 if !val.is_null() {
231 xmlFreeImpl(val as *mut c_void);
232 }
233 return ptr::null_mut();
234 }
235 (*obj).type_ = xmlXPathObjectType::XPATH_STRING as c_int;
236 (*obj).stringval = val;
237 obj
238}
239
240#[no_mangle]
246pub unsafe extern "C" fn xmlXPathWrapCString(val: *mut c_char) -> *mut _xmlXPathObject {
247 unsafe { xmlXPathWrapString(val as *mut xmlChar) }
248}
249
250#[no_mangle]
257pub unsafe extern "C" fn xmlXPathWrapNodeSet(val: *mut _xmlNodeSet) -> *mut _xmlXPathObject {
258 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
259 if obj.is_null() {
260 if !val.is_null() {
261 xmlFreeImpl(val as *mut c_void);
262 }
263 return ptr::null_mut();
264 }
265 (*obj).type_ = xmlXPathObjectType::XPATH_NODESET as c_int;
266 (*obj).nodesetval = val as *mut c_void;
267 obj
268}
269
270#[no_mangle]
276pub unsafe extern "C" fn xmlXPathWrapExternal(val: *mut c_void) -> *mut _xmlXPathObject {
277 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
278 if obj.is_null() {
279 return ptr::null_mut();
280 }
281 (*obj).type_ = xmlXPathObjectType::XPATH_USERS as c_int;
282 (*obj).user = val;
283 obj
284}
285
286#[no_mangle]
300pub unsafe extern "C" fn xmlXPathFreeNodeSetList(obj: *mut _xmlXPathObject) {
301 xmlFreeImpl(obj as *mut c_void);
302}
303
304#[no_mangle]
315pub unsafe extern "C" fn xmlXPathConvertBoolean(val: *mut _xmlXPathObject) -> *mut _xmlXPathObject {
316 if val.is_null() {
317 return ptr::null_mut();
318 }
319 let typ = (*val).type_;
320 if typ == xmlXPathObjectType::XPATH_BOOLEAN as c_int {
321 return val;
322 }
323 let b = crate::abi::exports_xml2::object_to_xpathvalue_pub(val).as_boolean();
324 crate::abi::exports_xml2::xmlXPathFreeObject(val);
325 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
326 if obj.is_null() {
327 return ptr::null_mut();
328 }
329 (*obj).type_ = xmlXPathObjectType::XPATH_BOOLEAN as c_int;
330 (*obj).boolval = if b { 1 } else { 0 };
331 obj
332}
333
334#[no_mangle]
340pub unsafe extern "C" fn xmlXPathConvertNumber(val: *mut _xmlXPathObject) -> *mut _xmlXPathObject {
341 if val.is_null() {
342 return ptr::null_mut();
343 }
344 let typ = (*val).type_;
345 if typ == xmlXPathObjectType::XPATH_NUMBER as c_int {
346 return val;
347 }
348 let n = crate::abi::exports_xml2::object_to_xpathvalue_pub(val).as_number();
349 crate::abi::exports_xml2::xmlXPathFreeObject(val);
350 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
351 if obj.is_null() {
352 return ptr::null_mut();
353 }
354 (*obj).type_ = xmlXPathObjectType::XPATH_NUMBER as c_int;
355 (*obj).floatval = n;
356 obj
357}
358
359#[no_mangle]
365pub unsafe extern "C" fn xmlXPathConvertString(val: *mut _xmlXPathObject) -> *mut _xmlXPathObject {
366 if val.is_null() {
367 return unsafe { xmlXPathNewString(ptr::null()) };
368 }
369 let typ = (*val).type_;
370 if typ == xmlXPathObjectType::XPATH_STRING as c_int {
371 return val;
372 }
373 let s = crate::abi::exports_xml2::object_to_xpathvalue_pub(val).as_string();
374 crate::abi::exports_xml2::xmlXPathFreeObject(val);
375 let buf = dup_rust_string(&s);
376 unsafe { xmlXPathWrapString(buf) }
377}
378
379#[no_mangle]
389pub unsafe extern "C" fn xmlXPathCastToBoolean(val: *mut _xmlXPathObject) -> c_int {
390 if val.is_null() {
391 return 0;
392 }
393 crate::abi::exports_xml2::object_to_xpathvalue_pub(val).as_boolean() as c_int
394}
395
396#[no_mangle]
402pub unsafe extern "C" fn xmlXPathCastToNumber(val: *mut _xmlXPathObject) -> c_double {
403 if val.is_null() {
404 return f64::NAN;
405 }
406 crate::abi::exports_xml2::object_to_xpathvalue_pub(val).as_number()
407}
408
409#[no_mangle]
421pub const unsafe extern "C" fn xmlXPathCastBooleanToNumber(val: c_int) -> c_double {
422 if val != 0 {
423 1.0
424 } else {
425 0.0
426 }
427}
428
429#[no_mangle]
441pub unsafe extern "C" fn xmlXPathCastBooleanToString(val: c_int) -> *mut xmlChar {
442 if val != 0 {
443 xml_strdup(c"true".as_ptr() as *const xmlChar)
444 } else {
445 xml_strdup(c"false".as_ptr() as *const xmlChar)
446 }
447}
448
449#[no_mangle]
455pub unsafe extern "C" fn xmlXPathCastNodeSetToBoolean(ns: *mut _xmlNodeSet) -> c_int {
456 if ns.is_null() {
457 return 0;
458 }
459 (unsafe { (*ns).nodeNr > 0 }) as c_int
460}
461
462#[no_mangle]
468pub unsafe extern "C" fn xmlXPathCastNodeSetToNumber(ns: *mut _xmlNodeSet) -> c_double {
469 unsafe {
470 let val = crate::abi::exports_xml2::object_to_xpathvalue_pub(xmlXPathWrapNodeSet(ns));
471 let n = val.as_number();
472 n
474 }
475}
476
477#[no_mangle]
483pub unsafe extern "C" fn xmlXPathCastNodeSetToString(ns: *mut _xmlNodeSet) -> *mut xmlChar {
484 let val = crate::xml::xpath::types::XPathValue::NodeSet(unsafe { node_set_to_internal(ns) });
485 let s = val.as_string();
486 dup_rust_string(&s)
487}
488
489unsafe fn node_set_to_internal(ns: *mut _xmlNodeSet) -> NodeSet {
491 let mut out = NodeSet::new();
492 if ns.is_null() {
493 return out;
494 }
495 let nr = unsafe { (*ns).nodeNr };
496 let tab = unsafe { (*ns).nodeTab };
497 if !tab.is_null() {
498 for i in 0..nr as isize {
499 out.push(unsafe { *tab.add(i as usize) });
500 }
501 }
502 out.sort();
503 out
504}
505
506#[no_mangle]
512pub unsafe extern "C" fn xmlXPathCastNodeToNumber(node: *mut _xmlNode) -> c_double {
513 let s = node_string_value(node);
514 crate::xml::xpath::types::string_to_number(&s)
515}
516
517#[no_mangle]
523pub unsafe extern "C" fn xmlXPathCastNodeToString(node: *mut _xmlNode) -> *mut xmlChar {
524 let s = node_string_value(node);
525 dup_rust_string(&s)
526}
527
528#[no_mangle]
540pub unsafe extern "C" fn xmlXPathCastNumberToBoolean(val: c_double) -> c_int {
541 (val != 0.0 && !val.is_nan()) as c_int
542}
543
544#[no_mangle]
556pub unsafe extern "C" fn xmlXPathCastNumberToString(val: c_double) -> *mut xmlChar {
557 number_to_xmlstring(val)
558}
559
560#[no_mangle]
566pub const unsafe extern "C" fn xmlXPathCastStringToBoolean(val: *const xmlChar) -> c_int {
567 if val.is_null() || unsafe { *val } == 0 {
568 0
569 } else {
570 1
571 }
572}
573
574#[no_mangle]
586pub const unsafe extern "C" fn xmlXPathIsNaN(val: c_double) -> c_int {
587 val.is_nan() as c_int
588}
589
590#[no_mangle]
602pub unsafe extern "C" fn xmlXPathIsInf(val: c_double) -> c_int {
603 if val.is_infinite() {
604 if val > 0.0 {
605 1
606 } else {
607 -1
608 }
609 } else {
610 0
611 }
612}
613
614#[no_mangle]
620pub unsafe extern "C" fn xmlXPathStringEvalNumber(str_: *const xmlChar) -> c_double {
621 if str_.is_null() {
622 return f64::NAN;
623 }
624 let s = unsafe { crate::xml::string::xmlstr_to_string(str_) };
625 crate::xml::xpath::types::string_to_number(&s)
626}
627
628#[no_mangle]
635pub unsafe extern "C" fn xmlXPathIsNodeType(name: *const xmlChar) -> c_int {
636 if name.is_null() {
637 return 0;
638 }
639 let s = unsafe { crate::xml::string::xmlstr_to_string(name) };
640 match s.as_str() {
641 "comment" | "text" | "processing-instruction" | "node" => 1,
642 _ => 0,
643 }
644}
645
646#[no_mangle]
658pub const unsafe extern "C" fn xmlXPathInit() {}
659
660#[no_mangle]
667pub unsafe extern "C" fn xmlXPathErr(
668 ctxt: *mut crate::xml::xpath::parser_context::XmlXPathParserContext,
669 error: c_int,
670) {
671 if !ctxt.is_null() {
672 unsafe { (*ctxt).error = error };
673 }
674}
675
676#[no_mangle]
683pub unsafe extern "C" fn xmlXPatherror(
684 ctxt: *mut crate::xml::xpath::parser_context::XmlXPathParserContext,
685 _file: *const c_char,
686 _line: c_int,
687 _no: c_int,
688) {
689 if !ctxt.is_null() {
690 unsafe { (*ctxt).error = _no };
691 }
692}
693
694#[allow(unused)]
695const fn _unused_doc(_d: *mut _xmlDoc) {}
696
697unsafe fn node_set_grow(ns: *mut _xmlNodeSet) {
703 if ns.is_null() {
704 return;
705 }
706 unsafe {
707 let nr = (*ns).nodeNr;
708 let max = (*ns).nodeMax;
709 if nr < max {
710 return;
711 }
712 let new_max = if max <= 0 { 8 } else { max * 2 };
713 let new_tab = crate::abi::allocator::xmlReallocImpl(
714 (*ns).nodeTab as *mut c_void,
715 (new_max as usize) * size_of::<*mut _xmlNode>(),
716 ) as *mut *mut _xmlNode;
717 if !new_tab.is_null() {
718 (*ns).nodeTab = new_tab;
719 (*ns).nodeMax = new_max;
720 }
721 }
722}
723
724#[no_mangle]
730pub unsafe extern "C" fn xmlXPathNodeSetContains(
731 cur: *mut _xmlNodeSet,
732 val: *mut _xmlNode,
733) -> c_int {
734 if cur.is_null() || val.is_null() {
735 return 0;
736 }
737 unsafe {
738 let nr = (*cur).nodeNr;
739 let tab = (*cur).nodeTab;
740 if !tab.is_null() {
741 for i in 0..nr as isize {
742 if *tab.add(i as usize) == val {
743 return 1;
744 }
745 }
746 }
747 }
748 0
749}
750
751#[no_mangle]
758pub unsafe extern "C" fn xmlXPathNodeSetAdd(cur: *mut _xmlNodeSet, val: *mut _xmlNode) -> c_int {
759 if cur.is_null() || val.is_null() {
760 return -1;
761 }
762 if xmlXPathNodeSetContains(cur, val) != 0 {
763 return 0;
764 }
765 unsafe {
766 node_set_grow(cur);
767 if (*cur).nodeNr >= (*cur).nodeMax {
768 return -1;
769 }
770 let idx = (*cur).nodeNr as usize;
771 ptr::write((*cur).nodeTab.add(idx), val);
772 (*cur).nodeNr += 1;
773 }
774 0
775}
776
777#[no_mangle]
784pub unsafe extern "C" fn xmlXPathNodeSetAddUnique(
785 cur: *mut _xmlNodeSet,
786 val: *mut _xmlNode,
787) -> c_int {
788 if cur.is_null() || val.is_null() {
789 return -1;
790 }
791 unsafe {
792 node_set_grow(cur);
793 if (*cur).nodeNr >= (*cur).nodeMax {
794 return -1;
795 }
796 let idx = (*cur).nodeNr as usize;
797 ptr::write((*cur).nodeTab.add(idx), val);
798 (*cur).nodeNr += 1;
799 }
800 0
801}
802
803#[no_mangle]
810pub unsafe extern "C" fn xmlXPathNodeSetAddNs(
811 cur: *mut _xmlNodeSet,
812 _node: *mut _xmlNode,
813 ns: *mut _xmlNs,
814) -> c_int {
815 if cur.is_null() || ns.is_null() {
816 return -1;
817 }
818 let ns_node = ns as *mut _xmlNode;
821 if xmlXPathNodeSetContains(cur, ns_node) != 0 {
822 return 0;
823 }
824 xmlXPathNodeSetAddUnique(cur, ns_node)
825}
826
827#[no_mangle]
834pub unsafe extern "C" fn xmlXPathNodeSetDel(cur: *mut _xmlNodeSet, val: *mut _xmlNode) {
835 if cur.is_null() || val.is_null() {
836 return;
837 }
838 unsafe {
839 let nr = (*cur).nodeNr;
840 let tab = (*cur).nodeTab;
841 let mut found = -1;
842 if !tab.is_null() {
843 for i in 0..nr as isize {
844 if *tab.add(i as usize) == val {
845 found = i as c_int;
846 break;
847 }
848 }
849 }
850 if found >= 0 {
851 let fi = found as usize;
852 for i in fi..(nr as usize - 1) {
853 ptr::write(tab.add(i), *tab.add(i + 1));
854 }
855 (*cur).nodeNr -= 1;
856 }
857 }
858}
859
860#[no_mangle]
867pub unsafe extern "C" fn xmlXPathNodeSetRemove(cur: *mut _xmlNodeSet, val: c_int) {
868 if cur.is_null() || val < 0 {
869 return;
870 }
871 unsafe {
872 let nr = (*cur).nodeNr;
873 if val >= nr {
874 return;
875 }
876 let tab = (*cur).nodeTab;
877 let vi = val as usize;
878 for i in vi..(nr as usize - 1) {
879 ptr::write(tab.add(i), *tab.add(i + 1));
880 }
881 (*cur).nodeNr -= 1;
882 }
883}
884
885#[no_mangle]
892pub unsafe extern "C" fn xmlXPathNodeSetSort(set: *mut _xmlNodeSet) {
893 if set.is_null() {
894 return;
895 }
896 unsafe {
897 let nr = (*set).nodeNr;
898 let tab = (*set).nodeTab;
899 if nr <= 1 || tab.is_null() {
900 return;
901 }
902 for i in 1..nr as usize {
905 let key = *tab.add(i);
906 let mut j = i;
907 while j > 0 {
908 let prev = *tab.add(j - 1);
909 if crate::xml::xpath::types::compare_document_order(prev, key)
910 == core::cmp::Ordering::Greater
911 {
912 ptr::write(tab.add(j), prev);
913 j -= 1;
914 } else {
915 break;
916 }
917 }
918 ptr::write(tab.add(j), key);
919 }
920 let mut w = 0usize;
922 for r in 0..nr as usize {
923 if w == 0 || *tab.add(w - 1) != *tab.add(r) {
924 ptr::write(tab.add(w), *tab.add(r));
925 w += 1;
926 }
927 }
928 (*set).nodeNr = w as c_int;
929 }
930}
931
932#[no_mangle]
939pub unsafe extern "C" fn xmlXPathNodeSetMerge(
940 val1: *mut _xmlNodeSet,
941 val2: *mut _xmlNodeSet,
942) -> *mut _xmlNodeSet {
943 if val1.is_null() && val2.is_null() {
944 return ptr::null_mut();
945 }
946 if val1.is_null() {
947 let obj = xmlXPathNewNodeSetList(val2);
949 let ns = unsafe { (*obj).nodesetval as *mut _xmlNodeSet };
950 if obj.is_null() {
951 return ptr::null_mut();
952 }
953 return ns;
954 }
955 if val2.is_null() {
956 return val1;
957 }
958 unsafe {
959 let nr2 = (*val2).nodeNr;
960 let tab2 = (*val2).nodeTab;
961 if !tab2.is_null() {
962 for i in 0..nr2 as isize {
963 let n = *tab2.add(i as usize);
964 if xmlXPathNodeSetContains(val1, n) == 0 {
965 xmlXPathNodeSetAddUnique(val1, n);
966 }
967 }
968 }
969 }
970 val1
971}
972
973#[no_mangle]
980pub unsafe extern "C" fn xmlXPathDifference(
981 nodes1: *mut _xmlNodeSet,
982 nodes2: *mut _xmlNodeSet,
983) -> *mut _xmlNodeSet {
984 if nodes1.is_null() {
985 return ptr::null_mut();
986 }
987 let mut a = unsafe { node_set_to_internal(nodes1) };
988 a.sort();
989 let b = unsafe { node_set_to_internal(nodes2) };
990 let mut out = NodeSet::new();
991 for n in a.iter() {
992 if !b.contains(n) {
993 out.push(n);
994 }
995 }
996 out.sort();
997 out.to_raw()
998}
999
1000#[no_mangle]
1006pub unsafe extern "C" fn xmlXPathIntersection(
1007 nodes1: *mut _xmlNodeSet,
1008 nodes2: *mut _xmlNodeSet,
1009) -> *mut _xmlNodeSet {
1010 let a = unsafe { node_set_to_internal(nodes1) };
1011 let b = unsafe { node_set_to_internal(nodes2) };
1012 let mut out = NodeSet::new();
1013 for n in a.iter() {
1014 if b.contains(n) {
1015 out.push(n);
1016 }
1017 }
1018 out.sort();
1019 out.to_raw()
1020}
1021
1022#[no_mangle]
1028pub unsafe extern "C" fn xmlXPathDistinct(nodes: *mut _xmlNodeSet) -> *mut _xmlNodeSet {
1029 if nodes.is_null() {
1030 return ptr::null_mut();
1031 }
1032 unsafe {
1033 xmlXPathNodeSetSort(nodes);
1034 nodes
1035 }
1036}
1037
1038#[no_mangle]
1044pub unsafe extern "C" fn xmlXPathDistinctSorted(nodes: *mut _xmlNodeSet) -> *mut _xmlNodeSet {
1045 if nodes.is_null() {
1046 return ptr::null_mut();
1047 }
1048 unsafe {
1049 let nr = (*nodes).nodeNr;
1050 let tab = (*nodes).nodeTab;
1051 let mut w = 0usize;
1052 if !tab.is_null() {
1053 for r in 0..nr as usize {
1054 if w == 0 || *tab.add(w - 1) != *tab.add(r) {
1055 ptr::write(tab.add(w), *tab.add(r));
1056 w += 1;
1057 }
1058 }
1059 }
1060 (*nodes).nodeNr = w as c_int;
1061 nodes
1062 }
1063}
1064
1065#[no_mangle]
1071pub unsafe extern "C" fn xmlXPathHasSameNodes(
1072 nodes1: *mut _xmlNodeSet,
1073 nodes2: *mut _xmlNodeSet,
1074) -> c_int {
1075 if nodes1.is_null() || nodes2.is_null() {
1076 return 0;
1077 }
1078 unsafe {
1079 let nr1 = (*nodes1).nodeNr;
1080 let nr2 = (*nodes2).nodeNr;
1081 if nr1 != nr2 {
1082 return 0;
1083 }
1084 let tab1 = (*nodes1).nodeTab;
1085 let tab2 = (*nodes2).nodeTab;
1086 for i in 0..nr1 as isize {
1087 let mut found = false;
1088 for j in 0..nr2 as isize {
1089 if *tab1.add(i as usize) == *tab2.add(j as usize) {
1090 found = true;
1091 break;
1092 }
1093 }
1094 if !found {
1095 return 0;
1096 }
1097 }
1098 }
1099 1
1100}
1101
1102unsafe fn leading_nodes(nodes: &NodeSet, node: *mut _xmlNode) -> NodeSet {
1104 let mut out = NodeSet::new();
1105 for n in nodes.iter() {
1106 if n == node {
1107 break;
1108 }
1109 out.push(n);
1110 }
1111 out
1112}
1113
1114unsafe fn trailing_nodes(nodes: &NodeSet, node: *mut _xmlNode) -> NodeSet {
1115 let mut out = NodeSet::new();
1116 let mut seen = false;
1117 for n in nodes.iter() {
1118 if n == node {
1119 seen = true;
1120 continue;
1121 }
1122 if seen {
1123 out.push(n);
1124 }
1125 }
1126 out
1127}
1128
1129#[no_mangle]
1135pub unsafe extern "C" fn xmlXPathLeading(
1136 nodes1: *mut _xmlNodeSet,
1137 nodes2: *mut _xmlNodeSet,
1138) -> *mut _xmlNodeSet {
1139 if nodes1.is_null() {
1140 return ptr::null_mut();
1141 }
1142 let mut a = unsafe { node_set_to_internal(nodes1) };
1143 a.sort();
1144 let b = unsafe { node_set_to_internal(nodes2) };
1145 if b.is_empty() {
1146 let raw = a.to_raw();
1147 return raw;
1148 }
1149 let first = b.first().unwrap();
1150 let out = unsafe { leading_nodes(&a, first) };
1151 out.to_raw()
1152}
1153
1154#[no_mangle]
1160pub unsafe extern "C" fn xmlXPathLeadingSorted(
1161 nodes1: *mut _xmlNodeSet,
1162 nodes2: *mut _xmlNodeSet,
1163) -> *mut _xmlNodeSet {
1164 unsafe { xmlXPathLeading(nodes1, nodes2) }
1165}
1166
1167#[no_mangle]
1173pub unsafe extern "C" fn xmlXPathTrailing(
1174 nodes1: *mut _xmlNodeSet,
1175 nodes2: *mut _xmlNodeSet,
1176) -> *mut _xmlNodeSet {
1177 if nodes1.is_null() {
1178 return ptr::null_mut();
1179 }
1180 let mut a = unsafe { node_set_to_internal(nodes1) };
1181 a.sort();
1182 let b = unsafe { node_set_to_internal(nodes2) };
1183 if b.is_empty() {
1184 return a.to_raw();
1185 }
1186 let last = b.last().unwrap();
1187 let out = unsafe { trailing_nodes(&a, last) };
1188 out.to_raw()
1189}
1190
1191#[no_mangle]
1197pub unsafe extern "C" fn xmlXPathTrailingSorted(
1198 nodes1: *mut _xmlNodeSet,
1199 nodes2: *mut _xmlNodeSet,
1200) -> *mut _xmlNodeSet {
1201 unsafe { xmlXPathTrailing(nodes1, nodes2) }
1202}
1203
1204#[no_mangle]
1210pub unsafe extern "C" fn xmlXPathNodeLeading(
1211 nodes: *mut _xmlNodeSet,
1212 node: *mut _xmlNode,
1213) -> *mut _xmlNodeSet {
1214 if nodes.is_null() {
1215 return ptr::null_mut();
1216 }
1217 let mut a = unsafe { node_set_to_internal(nodes) };
1218 a.sort();
1219 let out = unsafe { leading_nodes(&a, node) };
1220 out.to_raw()
1221}
1222
1223#[no_mangle]
1229pub unsafe extern "C" fn xmlXPathNodeLeadingSorted(
1230 nodes: *mut _xmlNodeSet,
1231 node: *mut _xmlNode,
1232) -> *mut _xmlNodeSet {
1233 unsafe { xmlXPathNodeLeading(nodes, node) }
1234}
1235
1236#[no_mangle]
1242pub unsafe extern "C" fn xmlXPathNodeTrailing(
1243 nodes: *mut _xmlNodeSet,
1244 node: *mut _xmlNode,
1245) -> *mut _xmlNodeSet {
1246 if nodes.is_null() {
1247 return ptr::null_mut();
1248 }
1249 let mut a = unsafe { node_set_to_internal(nodes) };
1250 a.sort();
1251 let out = unsafe { trailing_nodes(&a, node) };
1252 out.to_raw()
1253}
1254
1255#[no_mangle]
1261pub unsafe extern "C" fn xmlXPathNodeTrailingSorted(
1262 nodes: *mut _xmlNodeSet,
1263 node: *mut _xmlNode,
1264) -> *mut _xmlNodeSet {
1265 unsafe { xmlXPathNodeTrailing(nodes, node) }
1266}
1267
1268#[no_mangle]
1281pub unsafe extern "C" fn xmlXPathNodeSetFreeNs(ns: *mut _xmlNs) {
1282 unsafe {
1283 if ns.is_null() {
1284 return;
1285 }
1286 if (*ns).type_ != crate::abi::types::xmlElementType::XML_NAMESPACE_DECL as c_int {
1287 return;
1288 }
1289 if !(*ns).next.is_null()
1291 && (*(*ns).next).type_ != crate::abi::types::xmlElementType::XML_NAMESPACE_DECL as c_int
1292 {
1293 if !(*ns).href.is_null() {
1294 libc::free((*ns).href as *mut libc::c_void);
1295 }
1296 if !(*ns).prefix.is_null() {
1297 libc::free((*ns).prefix as *mut libc::c_void);
1298 }
1299 libc::free(ns as *mut libc::c_void);
1300 }
1301 }
1302}
1303
1304#[no_mangle]
1319pub unsafe extern "C" fn xmlXPathOrderDocElems(doc: *mut _xmlDoc) -> c_long {
1320 if doc.is_null() {
1321 return -1;
1322 }
1323 let mut count: c_long = 0;
1324 unsafe {
1325 let mut cur = (*doc).children;
1326 while !cur.is_null() {
1327 if (*cur).type_ == crate::abi::types::xmlElementType::XML_ELEMENT_NODE as c_int {
1328 count += 1;
1329 (*cur).content = (-count) as *mut xmlChar;
1333 if !(*cur).children.is_null() {
1334 cur = (*cur).children;
1335 continue;
1336 }
1337 }
1338 if !(*cur).next.is_null() {
1339 cur = (*cur).next;
1340 continue;
1341 }
1342 loop {
1343 cur = (*cur).parent;
1344 if cur.is_null() {
1345 break;
1346 }
1347 if cur == doc as *mut _xmlNode {
1348 cur = ptr::null_mut();
1349 break;
1350 }
1351 if !(*cur).next.is_null() {
1352 cur = (*cur).next;
1353 break;
1354 }
1355 }
1356 }
1357 }
1358 count
1359}
1360use std::ffi::CStr;
1361
1362use crate::abi::structs::_xmlAttr;
1363use crate::xml::validation::{get_id, is_xml_name_char, is_xml_name_start};
1364use crate::xml::xpath::context::XPathContext;
1365use crate::xml::xpath::parser_context::{
1366 cast_top_to_number, compare_values_impl, equal_values_impl, free_parser_context, new_bool,
1367 new_number, new_parser_context, pc_set_error, pop_boolean, pop_external, pop_node_set,
1368 pop_number, pop_string, value_pop, value_push, XmlXPathParserContext,
1369};
1370
1371const unsafe fn pc_from(p: *mut c_void) -> *mut XmlXPathParserContext {
1375 p as *mut XmlXPathParserContext
1376}
1377
1378unsafe fn cstr_eq(a: *const xmlChar, b: *const xmlChar) -> bool {
1380 if a.is_null() || b.is_null() {
1381 return a == b;
1382 }
1383 let mut i = 0usize;
1384 loop {
1385 let ca = unsafe { *a.add(i) };
1386 let cb = unsafe { *b.add(i) };
1387 if ca != cb {
1388 return false;
1389 }
1390 if ca == 0 {
1391 return true;
1392 }
1393 i += 1;
1394 }
1395}
1396
1397const unsafe fn is_blank_ch(c: xmlChar) -> bool {
1399 c == b' ' || c == b'\t' || c == b'\n' || c == b'\r'
1400}
1401
1402unsafe fn cast_top_to_string(pc: *mut XmlXPathParserContext) {
1408 unsafe {
1409 let val = (*pc).value;
1410 if val.is_null() {
1411 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
1412 return;
1413 }
1414 if (*val).type_ != xmlXPathObjectType::XPATH_STRING as c_int {
1415 let v = crate::abi::exports_xml2::object_to_xpathvalue_pub(val);
1416 let s = v.as_string();
1417 if !(*val).stringval.is_null() {
1418 xmlFreeImpl((*val).stringval as *mut c_void);
1419 }
1420 (*val).stringval = dup_rust_string(&s);
1421 (*val).type_ = xmlXPathObjectType::XPATH_STRING as c_int;
1422 }
1423 }
1424}
1425
1426unsafe fn cast_top_to_boolean(pc: *mut XmlXPathParserContext) {
1432 unsafe {
1433 let val = (*pc).value;
1434 if val.is_null() {
1435 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
1436 return;
1437 }
1438 if (*val).type_ != xmlXPathObjectType::XPATH_BOOLEAN as c_int {
1439 let v = crate::abi::exports_xml2::object_to_xpathvalue_pub(val);
1440 (*val).boolval = v.as_boolean() as c_int;
1441 (*val).type_ = xmlXPathObjectType::XPATH_BOOLEAN as c_int;
1442 }
1443 }
1444}
1445
1446unsafe fn check_arity(pc: *mut XmlXPathParserContext, n: c_int) -> bool {
1449 if pc.is_null() || (*pc).value_nr < n {
1450 pc_set_error(pc, crate::abi::types::XPATH_INVALID_ARITY as c_int);
1451 return false;
1452 }
1453 true
1454}
1455
1456const unsafe fn scan_c_name(cur: *const xmlChar, nc: bool) -> usize {
1460 if cur.is_null() {
1461 return 0;
1462 }
1463 let mut i = 0usize;
1464 let mut first = true;
1465 loop {
1466 let b = unsafe { *cur.add(i) };
1467 if b == 0 {
1468 break;
1469 }
1470 if nc && b == b':' {
1471 break;
1472 }
1473 let (ch, adv): (char, usize) = if b < 0x80 {
1474 (b as char, 1)
1475 } else if b >= 0xC0 && b <= 0xDF {
1476 (
1477 unsafe {
1478 char::from_u32_unchecked(
1479 ((b as u32 & 0x1F) << 6) | (*cur.add(i + 1) as u32 & 0x3F),
1480 )
1481 },
1482 2,
1483 )
1484 } else if b >= 0xE0 && b <= 0xEF {
1485 (
1486 unsafe {
1487 char::from_u32_unchecked(
1488 ((b as u32 & 0x0F) << 12)
1489 | ((*cur.add(i + 1) as u32 & 0x3F) << 6)
1490 | (*cur.add(i + 2) as u32 & 0x3F),
1491 )
1492 },
1493 3,
1494 )
1495 } else if b >= 0xF0 && b <= 0xF7 {
1496 (
1497 unsafe {
1498 char::from_u32_unchecked(
1499 ((b as u32 & 0x07) << 18)
1500 | ((*cur.add(i + 1) as u32 & 0x3F) << 12)
1501 | ((*cur.add(i + 2) as u32 & 0x3F) << 6)
1502 | (*cur.add(i + 3) as u32 & 0x3F),
1503 )
1504 },
1505 4,
1506 )
1507 } else {
1508 break;
1509 };
1510 let ok = if first {
1511 is_xml_name_start(ch)
1512 } else {
1513 is_xml_name_char(ch)
1514 };
1515 if !ok {
1516 break;
1517 }
1518 first = false;
1519 i += adv;
1520 }
1521 i
1522}
1523
1524unsafe fn cstr_find(hay: *const xmlChar, needle: *const xmlChar) -> *const xmlChar {
1526 if hay.is_null() || needle.is_null() {
1527 return ptr::null();
1528 }
1529 if unsafe { *needle } == 0 {
1530 return hay;
1531 }
1532 let hlen = unsafe { crate::xml::string::xml_strlen(hay) };
1533 let nlen = unsafe { crate::xml::string::xml_strlen(needle) };
1534 if nlen > hlen {
1535 return ptr::null();
1536 }
1537 let hay_b = unsafe { core::slice::from_raw_parts(hay, hlen) };
1538 let needle_b = unsafe { core::slice::from_raw_parts(needle, nlen) };
1539 for off in 0..=hlen - nlen {
1540 if &hay_b[off..off + nlen] == needle_b {
1541 return unsafe { hay.add(off) };
1542 }
1543 }
1544 ptr::null()
1545}
1546
1547const XML_XML_NAMESPACE_BYTES: &[u8] = b"http://www.w3.org/XML/1998/namespace\0";
1549
1550struct XmlXPathXmlNs(_xmlNs);
1554unsafe impl Sync for XmlXPathXmlNs {}
1555static XML_XPATH_XML_NS: XmlXPathXmlNs = XmlXPathXmlNs(crate::abi::structs::_xmlNs {
1556 next: ptr::null_mut(),
1557 type_: crate::abi::types::xmlElementType::XML_NAMESPACE_DECL as c_int,
1558 href: XML_XML_NAMESPACE_BYTES.as_ptr() as *const xmlChar,
1559 prefix: c"xml".as_ptr() as *const xmlChar,
1560 _private: ptr::null_mut(),
1561 context: ptr::null_mut(),
1562});
1563
1564#[no_mangle]
1580pub unsafe extern "C" fn xmlXPathValuePush(
1581 ctxt: *mut c_void,
1582 value: *mut _xmlXPathObject,
1583) -> c_int {
1584 if ctxt.is_null() || value.is_null() {
1585 return -1;
1586 }
1587 let pc = pc_from(ctxt);
1588 let idx = unsafe { (*pc).value_nr };
1591 value_push(pc, value);
1592 idx
1593}
1594
1595#[no_mangle]
1601pub unsafe extern "C" fn xmlXPathValuePop(ctxt: *mut c_void) -> *mut _xmlXPathObject {
1602 value_pop(pc_from(ctxt))
1603}
1604
1605#[no_mangle]
1611pub unsafe extern "C" fn xmlXPathPopBoolean(ctxt: *mut c_void) -> c_int {
1612 pop_boolean(pc_from(ctxt))
1613}
1614
1615#[no_mangle]
1621pub unsafe extern "C" fn xmlXPathPopExternal(ctxt: *mut c_void) -> *mut c_void {
1622 pop_external(pc_from(ctxt))
1623}
1624
1625#[no_mangle]
1631pub unsafe extern "C" fn xmlXPathPopNodeSet(ctxt: *mut c_void) -> *mut _xmlNodeSet {
1632 pop_node_set(pc_from(ctxt))
1633}
1634
1635#[no_mangle]
1641pub unsafe extern "C" fn xmlXPathPopNumber(ctxt: *mut c_void) -> c_double {
1642 pop_number(pc_from(ctxt))
1643}
1644
1645#[no_mangle]
1651pub unsafe extern "C" fn xmlXPathPopString(ctxt: *mut c_void) -> *mut xmlChar {
1652 pop_string(pc_from(ctxt))
1653}
1654
1655unsafe fn binary_inplace(ctxt: *mut c_void, op: impl Fn(&mut f64, f64)) {
1660 let pc = pc_from(ctxt);
1661 if pc.is_null() {
1662 return;
1663 }
1664 let arg = value_pop(pc);
1665 if arg.is_null() {
1666 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
1667 return;
1668 }
1669 let val = crate::abi::exports_xml2::object_to_xpathvalue_pub(arg).as_number();
1670 crate::abi::exports_xml2::xmlXPathFreeObject(arg);
1671 if unsafe { (*pc).value.is_null() } {
1672 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
1673 return;
1674 }
1675 cast_top_to_number(pc);
1676 if (*pc).error != 0 {
1677 return;
1678 }
1679 unsafe {
1683 let float_ref: &mut f64 = &mut (*(*pc).value).floatval;
1684 op(float_ref, val);
1685 }
1686}
1687
1688#[no_mangle]
1705pub unsafe extern "C" fn xmlXPathAddValues(ctxt: *mut c_void) {
1706 binary_inplace(ctxt, |x, v| *x += v);
1707}
1708
1709#[no_mangle]
1726pub unsafe extern "C" fn xmlXPathSubValues(ctxt: *mut c_void) {
1727 binary_inplace(ctxt, |x, v| *x -= v);
1728}
1729
1730#[no_mangle]
1747pub unsafe extern "C" fn xmlXPathMultValues(ctxt: *mut c_void) {
1748 binary_inplace(ctxt, |x, v| *x *= v);
1749}
1750
1751#[no_mangle]
1768pub unsafe extern "C" fn xmlXPathDivValues(ctxt: *mut c_void) {
1769 binary_inplace(ctxt, |x, v| *x /= v);
1770}
1771
1772#[no_mangle]
1789pub unsafe extern "C" fn xmlXPathModValues(ctxt: *mut c_void) {
1790 binary_inplace(ctxt, |x, v| *x %= v);
1791}
1792
1793#[no_mangle]
1810pub unsafe extern "C" fn xmlXPathValueFlipSign(ctxt: *mut c_void) {
1811 let pc = pc_from(ctxt);
1812 if pc.is_null() {
1813 return;
1814 }
1815 cast_top_to_number(pc);
1816 if (*pc).error != 0 {
1817 return;
1818 }
1819 unsafe { (*(*pc).value).floatval = -(*(*pc).value).floatval };
1820}
1821
1822#[no_mangle]
1840pub unsafe extern "C" fn xmlXPathEqualValues(ctxt: *mut c_void) -> c_int {
1841 equal_values_impl(pc_from(ctxt), false)
1842}
1843
1844#[no_mangle]
1861pub unsafe extern "C" fn xmlXPathNotEqualValues(ctxt: *mut c_void) -> c_int {
1862 equal_values_impl(pc_from(ctxt), true)
1863}
1864
1865#[no_mangle]
1886pub unsafe extern "C" fn xmlXPathCompareValues(
1887 ctxt: *mut c_void,
1888 inf: c_int,
1889 strict: c_int,
1890) -> c_int {
1891 compare_values_impl(pc_from(ctxt), inf != 0, strict != 0)
1892}
1893
1894#[no_mangle]
1905pub unsafe extern "C" fn xmlXPathNewParserContext(
1906 str_: *const xmlChar,
1907 ctxt: *mut _xmlXPathContext,
1908) -> *mut c_void {
1909 new_parser_context(str_, ctxt) as *mut c_void
1910}
1911
1912#[no_mangle]
1918pub unsafe extern "C" fn xmlXPathFreeParserContext(ctxt: *mut c_void) {
1919 free_parser_context(pc_from(ctxt));
1920}
1921
1922#[no_mangle]
1929pub unsafe extern "C" fn xmlXPathParseNCName(ctxt: *mut c_void) -> *mut xmlChar {
1930 let pc = pc_from(ctxt);
1931 if pc.is_null() {
1932 return ptr::null_mut();
1933 }
1934 let cur = unsafe { (*pc).cur };
1935 if cur.is_null() {
1936 return ptr::null_mut();
1937 }
1938 let len = scan_c_name(cur, true);
1939 if len == 0 {
1940 return ptr::null_mut();
1941 }
1942 let ret = crate::xml::string::xml_strndup(cur, len);
1943 unsafe { (*pc).cur = cur.add(len) };
1944 ret
1945}
1946
1947#[no_mangle]
1954pub unsafe extern "C" fn xmlXPathParseName(ctxt: *mut c_void) -> *mut xmlChar {
1955 let pc = pc_from(ctxt);
1956 if pc.is_null() {
1957 return ptr::null_mut();
1958 }
1959 let cur = unsafe { (*pc).cur };
1960 if cur.is_null() {
1961 return ptr::null_mut();
1962 }
1963 let len = scan_c_name(cur, false);
1964 if len == 0 {
1965 return ptr::null_mut();
1966 }
1967 let ret = crate::xml::string::xml_strndup(cur, len);
1968 unsafe { (*pc).cur = cur.add(len) };
1969 ret
1970}
1971
1972#[no_mangle]
1979pub unsafe extern "C" fn xmlXPathRoot(ctxt: *mut c_void) {
1980 let pc = pc_from(ctxt);
1981 if pc.is_null() {
1982 return;
1983 }
1984 let ctx = unsafe { (*pc).context };
1985 if ctx.is_null() {
1986 return;
1987 }
1988 let ns = NodeSet::singleton(unsafe { (*ctx).doc } as *mut _xmlNode);
1989 let obj = crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(ns));
1990 value_push(pc, obj);
1991}
1992
1993#[no_mangle]
2001pub unsafe extern "C" fn xmlXPathEvalExpr(ctxt: *mut c_void) {
2002 let pc = pc_from(ctxt);
2003 if pc.is_null() {
2004 return;
2005 }
2006 let ctx = unsafe { (*pc).context };
2007 if ctx.is_null() {
2008 return;
2009 }
2010 let base = unsafe { (*pc).base };
2011 if base.is_null() {
2012 return;
2013 }
2014 let expr_str = match CStr::from_ptr(base as *const c_char).to_str() {
2015 Ok(s) => s,
2016 Err(_) => {
2017 pc_set_error(pc, crate::abi::types::XPATH_EXPR_ERROR as c_int);
2018 return;
2019 }
2020 };
2021 let internal = unsafe { (*ctx).extra } as *mut XPathContext;
2022 if internal.is_null() {
2023 return;
2024 }
2025 let internal = unsafe { &mut *internal };
2026 match crate::xml::xpath::evaluate_str(expr_str, internal) {
2027 Some(val) => {
2028 let obj = crate::abi::exports_xml2::xpath_to_object_pub(val);
2029 value_push(pc, obj);
2030 }
2031 None => {
2032 pc_set_error(pc, crate::abi::types::XPATH_EXPR_ERROR as c_int);
2033 }
2034 }
2035}
2036
2037unsafe fn eval_predicate_result(ctxt: *mut _xmlXPathContext, res: *mut _xmlXPathObject) -> c_int {
2039 if ctxt.is_null() || res.is_null() {
2040 return 0;
2041 }
2042 unsafe {
2043 let t = (*res).type_;
2044 if t == xmlXPathObjectType::XPATH_BOOLEAN as c_int {
2045 (*res).boolval
2046 } else if t == xmlXPathObjectType::XPATH_NUMBER as c_int {
2047 ((*res).floatval == (*ctxt).proximityPosition as f64) as c_int
2048 } else if t == xmlXPathObjectType::XPATH_NODESET as c_int
2049 || t == xmlXPathObjectType::XPATH_XSLT_TREE as c_int
2050 {
2051 let nsp = (*res).nodesetval as *mut _xmlNodeSet;
2052 if nsp.is_null() || (*nsp).nodeNr == 0 {
2053 0
2054 } else {
2055 1
2056 }
2057 } else if t == xmlXPathObjectType::XPATH_STRING as c_int {
2058 if (*res).stringval.is_null() || *(*res).stringval == 0 {
2059 0
2060 } else {
2061 1
2062 }
2063 } else {
2064 0
2065 }
2066 }
2067}
2068
2069#[no_mangle]
2076pub unsafe extern "C" fn xmlXPathEvalPredicate(
2077 ctxt: *mut _xmlXPathContext,
2078 res: *mut _xmlXPathObject,
2079) -> c_int {
2080 eval_predicate_result(ctxt, res)
2081}
2082
2083#[no_mangle]
2089pub unsafe extern "C" fn xmlXPathEvaluatePredicateResult(
2090 ctxt: *mut c_void,
2091 res: *mut _xmlXPathObject,
2092) -> c_int {
2093 let pc = pc_from(ctxt);
2094 if pc.is_null() {
2095 return 0;
2096 }
2097 let ctx = unsafe { (*pc).context };
2098 eval_predicate_result(ctx, res)
2099}
2100
2101#[no_mangle]
2122pub unsafe extern "C" fn xmlXPathNextSelf(ctxt: *mut c_void, cur: *mut _xmlNode) -> *mut _xmlNode {
2123 let pc = pc_from(ctxt);
2124 if pc.is_null() {
2125 return ptr::null_mut();
2126 }
2127 let ctx = unsafe { (*pc).context };
2128 if ctx.is_null() {
2129 return ptr::null_mut();
2130 }
2131 if cur.is_null() {
2132 return unsafe { (*ctx).node };
2133 }
2134 ptr::null_mut()
2135}
2136
2137#[no_mangle]
2154pub unsafe extern "C" fn xmlXPathNextChild(ctxt: *mut c_void, cur: *mut _xmlNode) -> *mut _xmlNode {
2155 let pc = pc_from(ctxt);
2156 if pc.is_null() {
2157 return ptr::null_mut();
2158 }
2159 let ctx = unsafe { (*pc).context };
2160 if ctx.is_null() {
2161 return ptr::null_mut();
2162 }
2163 use crate::abi::types::xmlElementType as ET;
2164 if cur.is_null() {
2165 let node = unsafe { (*ctx).node };
2166 if node.is_null() {
2167 return ptr::null_mut();
2168 }
2169 return match unsafe { (*node).type_ } {
2170 t if t == ET::XML_ELEMENT_NODE as c_int
2171 || t == ET::XML_TEXT_NODE as c_int
2172 || t == ET::XML_CDATA_SECTION_NODE as c_int
2173 || t == ET::XML_ENTITY_REF_NODE as c_int
2174 || t == ET::XML_ENTITY_NODE as c_int
2175 || t == ET::XML_PI_NODE as c_int
2176 || t == ET::XML_COMMENT_NODE as c_int
2177 || t == ET::XML_NOTATION_NODE as c_int
2178 || t == ET::XML_DTD_NODE as c_int =>
2179 unsafe { (*node).children },
2180 t if t == ET::XML_DOCUMENT_NODE as c_int
2181 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2182 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2183 || t == ET::XML_HTML_DOCUMENT_NODE as c_int =>
2184 unsafe { (*(node as *mut _xmlDoc)).children },
2185 _ => ptr::null_mut(),
2186 };
2187 }
2188 let t = unsafe { (*cur).type_ };
2189 if t == ET::XML_DOCUMENT_NODE as c_int || t == ET::XML_HTML_DOCUMENT_NODE as c_int {
2190 return ptr::null_mut();
2191 }
2192 unsafe { (*cur).next }
2193}
2194
2195#[no_mangle]
2212pub unsafe extern "C" fn xmlXPathNextDescendant(
2213 ctxt: *mut c_void,
2214 mut cur: *mut _xmlNode,
2215) -> *mut _xmlNode {
2216 let pc = pc_from(ctxt);
2217 if pc.is_null() {
2218 return ptr::null_mut();
2219 }
2220 let ctx = unsafe { (*pc).context };
2221 if ctx.is_null() {
2222 return ptr::null_mut();
2223 }
2224 use crate::abi::types::xmlElementType as ET;
2225 if cur.is_null() {
2226 let node = unsafe { (*ctx).node };
2227 if node.is_null() {
2228 return ptr::null_mut();
2229 }
2230 let t = unsafe { (*node).type_ };
2231 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
2232 return ptr::null_mut();
2233 }
2234 if node == unsafe { (*ctx).doc } as *mut _xmlNode {
2235 return unsafe { (*(*ctx).doc).children };
2236 }
2237 return unsafe { (*node).children };
2238 }
2239 unsafe {
2240 if (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2241 return ptr::null_mut();
2242 }
2243 if !(*cur).children.is_null() && (*(*cur).children).type_ != ET::XML_ENTITY_DECL as c_int {
2244 cur = (*cur).children;
2245 if (*cur).type_ != ET::XML_DTD_NODE as c_int {
2246 return cur;
2247 }
2248 }
2249 if cur == (*ctx).node {
2250 return ptr::null_mut();
2251 }
2252 while !(*cur).next.is_null() {
2253 cur = (*cur).next;
2254 if (*cur).type_ != ET::XML_ENTITY_DECL as c_int
2255 && (*cur).type_ != ET::XML_DTD_NODE as c_int
2256 {
2257 return cur;
2258 }
2259 }
2260 loop {
2261 cur = (*cur).parent;
2262 if cur.is_null() {
2263 break;
2264 }
2265 if cur == (*ctx).node {
2266 return ptr::null_mut();
2267 }
2268 if !(*cur).next.is_null() {
2269 cur = (*cur).next;
2270 return cur;
2271 }
2272 }
2273 cur
2274 }
2275}
2276
2277#[no_mangle]
2294pub unsafe extern "C" fn xmlXPathNextDescendantOrSelf(
2295 ctxt: *mut c_void,
2296 cur: *mut _xmlNode,
2297) -> *mut _xmlNode {
2298 let pc = pc_from(ctxt);
2299 if pc.is_null() {
2300 return ptr::null_mut();
2301 }
2302 let ctx = unsafe { (*pc).context };
2303 if ctx.is_null() {
2304 return ptr::null_mut();
2305 }
2306 if cur.is_null() {
2307 return unsafe { (*ctx).node };
2308 }
2309 let node = unsafe { (*ctx).node };
2310 if node.is_null() {
2311 return ptr::null_mut();
2312 }
2313 use crate::abi::types::xmlElementType as ET;
2314 let t = unsafe { (*node).type_ };
2315 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
2316 return ptr::null_mut();
2317 }
2318 xmlXPathNextDescendant(ctxt, cur)
2319}
2320
2321#[no_mangle]
2338pub unsafe extern "C" fn xmlXPathNextParent(
2339 ctxt: *mut c_void,
2340 cur: *mut _xmlNode,
2341) -> *mut _xmlNode {
2342 let pc = pc_from(ctxt);
2343 if pc.is_null() {
2344 return ptr::null_mut();
2345 }
2346 let ctx = unsafe { (*pc).context };
2347 if ctx.is_null() {
2348 return ptr::null_mut();
2349 }
2350 if !cur.is_null() {
2351 return ptr::null_mut();
2352 }
2353 next_parent_impl(ctx)
2354}
2355
2356unsafe fn next_parent_impl(ctx: *mut _xmlXPathContext) -> *mut _xmlNode {
2358 use crate::abi::types::xmlElementType as ET;
2359 let node = unsafe { (*ctx).node };
2360 if node.is_null() {
2361 return ptr::null_mut();
2362 }
2363 match unsafe { (*node).type_ } {
2364 t if t == ET::XML_ELEMENT_NODE as c_int
2365 || t == ET::XML_TEXT_NODE as c_int
2366 || t == ET::XML_CDATA_SECTION_NODE as c_int
2367 || t == ET::XML_ENTITY_REF_NODE as c_int
2368 || t == ET::XML_ENTITY_NODE as c_int
2369 || t == ET::XML_PI_NODE as c_int
2370 || t == ET::XML_COMMENT_NODE as c_int
2371 || t == ET::XML_NOTATION_NODE as c_int
2372 || t == ET::XML_DTD_NODE as c_int
2373 || t == ET::XML_ELEMENT_DECL as c_int
2374 || t == ET::XML_ATTRIBUTE_DECL as c_int
2375 || t == ET::XML_ENTITY_DECL as c_int
2376 || t == ET::XML_XINCLUDE_START as c_int
2377 || t == ET::XML_XINCLUDE_END as c_int =>
2378 unsafe {
2379 let parent = (*node).parent;
2380 if parent.is_null() {
2381 return (*ctx).doc as *mut _xmlNode;
2382 }
2383 if (*parent).type_ == ET::XML_ELEMENT_NODE as c_int
2384 && ((*parent).name.is_null() || *(*parent).name == b' ')
2385 {
2386 return ptr::null_mut();
2387 }
2388 parent
2389 },
2390 t if t == ET::XML_ATTRIBUTE_NODE as c_int => unsafe { (*(node as *mut _xmlAttr)).parent },
2391 t if t == ET::XML_DOCUMENT_NODE as c_int
2392 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2393 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2394 || t == ET::XML_HTML_DOCUMENT_NODE as c_int =>
2395 {
2396 ptr::null_mut()
2397 }
2398 t if t == ET::XML_NAMESPACE_DECL as c_int => unsafe {
2399 let ns = node as *mut crate::abi::structs::_xmlNs;
2400 if !(*ns).next.is_null() && (*(*ns).next).type_ != ET::XML_NAMESPACE_DECL as c_int {
2401 (*ns).next as *mut _xmlNode
2402 } else {
2403 ptr::null_mut()
2404 }
2405 },
2406 _ => ptr::null_mut(),
2407 }
2408}
2409
2410#[no_mangle]
2427pub unsafe extern "C" fn xmlXPathNextAncestor(
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 if cur.is_null() {
2441 let node = unsafe { (*ctx).node };
2442 if node.is_null() {
2443 return ptr::null_mut();
2444 }
2445 let t = unsafe { (*node).type_ };
2446 if t == ET::XML_ATTRIBUTE_NODE as c_int {
2447 return unsafe { (*(node as *mut _xmlAttr)).parent };
2448 }
2449 if t == ET::XML_NAMESPACE_DECL as c_int {
2450 let ns = node as *mut crate::abi::structs::_xmlNs;
2451 return unsafe {
2452 if !(*ns).next.is_null() && (*(*ns).next).type_ != ET::XML_NAMESPACE_DECL as c_int {
2453 (*ns).next as *mut _xmlNode
2454 } else {
2455 ptr::null_mut()
2456 }
2457 };
2458 }
2459 if t == ET::XML_DOCUMENT_NODE as c_int
2460 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2461 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2462 || t == ET::XML_HTML_DOCUMENT_NODE as c_int
2463 {
2464 return ptr::null_mut();
2465 }
2466 return next_parent_impl(ctx);
2468 }
2469 if cur == unsafe { (*ctx).doc } as *mut _xmlNode {
2470 return ptr::null_mut();
2471 }
2472 if cur == unsafe { (*(*ctx).doc).children } {
2473 return unsafe { (*ctx).doc } as *mut _xmlNode;
2474 }
2475 let t = unsafe { (*cur).type_ };
2476 if t == ET::XML_ATTRIBUTE_NODE as c_int {
2477 return unsafe { (*(cur as *mut _xmlAttr)).parent };
2478 }
2479 if t == ET::XML_NAMESPACE_DECL as c_int {
2480 let ns = cur as *mut crate::abi::structs::_xmlNs;
2481 return unsafe {
2482 if !(*ns).next.is_null() && (*(*ns).next).type_ != ET::XML_NAMESPACE_DECL as c_int {
2483 (*ns).next as *mut _xmlNode
2484 } else {
2485 ptr::null_mut()
2486 }
2487 };
2488 }
2489 if t == ET::XML_DOCUMENT_NODE as c_int
2490 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2491 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2492 || t == ET::XML_HTML_DOCUMENT_NODE as c_int
2493 {
2494 return ptr::null_mut();
2495 }
2496 unsafe {
2497 let parent = (*cur).parent;
2498 if parent.is_null() {
2499 return ptr::null_mut();
2500 }
2501 if (*parent).type_ == ET::XML_ELEMENT_NODE as c_int
2502 && ((*parent).name.is_null() || *(*parent).name == b' ')
2503 {
2504 return ptr::null_mut();
2505 }
2506 parent
2507 }
2508}
2509
2510#[no_mangle]
2527pub unsafe extern "C" fn xmlXPathNextAncestorOrSelf(
2528 ctxt: *mut c_void,
2529 cur: *mut _xmlNode,
2530) -> *mut _xmlNode {
2531 let pc = pc_from(ctxt);
2532 if pc.is_null() {
2533 return ptr::null_mut();
2534 }
2535 let ctx = unsafe { (*pc).context };
2536 if ctx.is_null() {
2537 return ptr::null_mut();
2538 }
2539 if cur.is_null() {
2540 return unsafe { (*ctx).node };
2541 }
2542 xmlXPathNextAncestor(ctxt, cur)
2543}
2544
2545#[no_mangle]
2562pub unsafe extern "C" fn xmlXPathNextFollowingSibling(
2563 ctxt: *mut c_void,
2564 mut cur: *mut _xmlNode,
2565) -> *mut _xmlNode {
2566 let pc = pc_from(ctxt);
2567 if pc.is_null() {
2568 return ptr::null_mut();
2569 }
2570 let ctx = unsafe { (*pc).context };
2571 if ctx.is_null() {
2572 return ptr::null_mut();
2573 }
2574 use crate::abi::types::xmlElementType as ET;
2575 unsafe {
2576 let cnode = (*ctx).node;
2577 if !cnode.is_null() {
2578 let t = (*cnode).type_;
2579 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
2580 return ptr::null_mut();
2581 }
2582 }
2583 if cur == (*ctx).doc as *mut _xmlNode {
2584 return ptr::null_mut();
2585 }
2586 if cur.is_null() {
2587 cur = cnode;
2588 }
2589 if cur.is_null() {
2590 return ptr::null_mut();
2591 }
2592 if (*cur).type_ == ET::XML_DOCUMENT_NODE as c_int {
2593 return ptr::null_mut();
2594 }
2595 (*cur).next
2596 }
2597}
2598
2599#[no_mangle]
2616pub unsafe extern "C" fn xmlXPathNextPrecedingSibling(
2617 ctxt: *mut c_void,
2618 mut cur: *mut _xmlNode,
2619) -> *mut _xmlNode {
2620 let pc = pc_from(ctxt);
2621 if pc.is_null() {
2622 return ptr::null_mut();
2623 }
2624 let ctx = unsafe { (*pc).context };
2625 if ctx.is_null() {
2626 return ptr::null_mut();
2627 }
2628 use crate::abi::types::xmlElementType as ET;
2629 unsafe {
2630 let cnode = (*ctx).node;
2631 if !cnode.is_null() {
2632 let t = (*cnode).type_;
2633 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
2634 return ptr::null_mut();
2635 }
2636 }
2637 if cur == (*ctx).doc as *mut _xmlNode {
2638 return ptr::null_mut();
2639 }
2640 if cur.is_null() {
2641 cur = cnode;
2642 } else if !(*cur).prev.is_null() && (*(*cur).prev).type_ == ET::XML_DTD_NODE as c_int {
2643 cur = (*cur).prev;
2644 if cur.is_null() {
2645 return ptr::null_mut();
2646 }
2647 }
2648 if cur.is_null() {
2649 return ptr::null_mut();
2650 }
2651 if (*cur).type_ == ET::XML_DOCUMENT_NODE as c_int {
2652 return ptr::null_mut();
2653 }
2654 (*cur).prev
2655 }
2656}
2657
2658#[no_mangle]
2675pub unsafe extern "C" fn xmlXPathNextFollowing(
2676 ctxt: *mut c_void,
2677 mut cur: *mut _xmlNode,
2678) -> *mut _xmlNode {
2679 let pc = pc_from(ctxt);
2680 if pc.is_null() {
2681 return ptr::null_mut();
2682 }
2683 let ctx = unsafe { (*pc).context };
2684 if ctx.is_null() {
2685 return ptr::null_mut();
2686 }
2687 use crate::abi::types::xmlElementType as ET;
2688 unsafe {
2689 if !cur.is_null()
2690 && (*cur).type_ != ET::XML_ATTRIBUTE_NODE as c_int
2691 && (*cur).type_ != ET::XML_NAMESPACE_DECL as c_int
2692 && !(*cur).children.is_null()
2693 {
2694 return (*cur).children;
2695 }
2696 if cur.is_null() {
2697 cur = (*ctx).node;
2698 if cur.is_null() {
2699 return ptr::null_mut();
2700 }
2701 if (*cur).type_ == ET::XML_ATTRIBUTE_NODE as c_int {
2702 cur = (*cur).parent;
2703 } else if (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2704 let ns = cur as *mut crate::abi::structs::_xmlNs;
2705 if (*ns).next.is_null() || (*(*ns).next).type_ == ET::XML_NAMESPACE_DECL as c_int {
2706 return ptr::null_mut();
2707 }
2708 cur = (*ns).next as *mut _xmlNode;
2709 }
2710 }
2711 if cur.is_null() {
2712 return ptr::null_mut();
2713 }
2714 if (*cur).type_ == ET::XML_DOCUMENT_NODE as c_int {
2715 return ptr::null_mut();
2716 }
2717 if !(*cur).next.is_null() {
2718 return (*cur).next;
2719 }
2720 loop {
2721 cur = (*cur).parent;
2722 if cur.is_null() {
2723 break;
2724 }
2725 if cur == (*ctx).doc as *mut _xmlNode {
2726 return ptr::null_mut();
2727 }
2728 if !(*cur).next.is_null() && (*cur).type_ != ET::XML_DOCUMENT_NODE as c_int {
2729 return (*cur).next;
2730 }
2731 }
2732 cur
2733 }
2734}
2735
2736#[no_mangle]
2753pub unsafe extern "C" fn xmlXPathNextPreceding(
2754 ctxt: *mut c_void,
2755 mut cur: *mut _xmlNode,
2756) -> *mut _xmlNode {
2757 let pc = pc_from(ctxt);
2758 if pc.is_null() {
2759 return ptr::null_mut();
2760 }
2761 let ctx = unsafe { (*pc).context };
2762 if ctx.is_null() {
2763 return ptr::null_mut();
2764 }
2765 use crate::abi::types::xmlElementType as ET;
2766 unsafe {
2767 let is_ancestor = |ancestor: *mut _xmlNode, node: *mut _xmlNode| -> bool {
2768 if ancestor.is_null() || node.is_null() {
2769 return false;
2770 }
2771 if (*node).type_ == ET::XML_NAMESPACE_DECL as c_int
2772 || (*ancestor).type_ == ET::XML_NAMESPACE_DECL as c_int
2773 {
2774 return false;
2775 }
2776 if (*ancestor).doc != (*node).doc {
2777 return false;
2778 }
2779 if ancestor == (*node).doc as *mut _xmlNode {
2780 return true;
2781 }
2782 if node == (*ancestor).doc as *mut _xmlNode {
2783 return false;
2784 }
2785 let mut n = node;
2786 while !(*n).parent.is_null() {
2787 if (*n).parent == ancestor {
2788 return true;
2789 }
2790 n = (*n).parent;
2791 }
2792 false
2793 };
2794 if cur.is_null() {
2795 cur = (*ctx).node;
2796 if cur.is_null() {
2797 return ptr::null_mut();
2798 }
2799 if (*cur).type_ == ET::XML_ATTRIBUTE_NODE as c_int {
2800 cur = (*cur).parent;
2801 } else if (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2802 let ns = cur as *mut crate::abi::structs::_xmlNs;
2803 if (*ns).next.is_null() || (*(*ns).next).type_ == ET::XML_NAMESPACE_DECL as c_int {
2804 return ptr::null_mut();
2805 }
2806 cur = (*ns).next as *mut _xmlNode;
2807 }
2808 }
2809 if cur.is_null() || (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2810 return ptr::null_mut();
2811 }
2812 if !(*cur).prev.is_null() && (*(*cur).prev).type_ == ET::XML_DTD_NODE as c_int {
2813 cur = (*cur).prev;
2814 }
2815 loop {
2816 if !(*cur).prev.is_null() {
2817 let mut n = (*cur).prev;
2818 while !(*n).last.is_null() {
2819 n = (*n).last;
2820 }
2821 return n;
2822 }
2823 cur = (*cur).parent;
2824 if cur.is_null() {
2825 return ptr::null_mut();
2826 }
2827 if cur == (*(*ctx).doc).children {
2828 return ptr::null_mut();
2829 }
2830 if !is_ancestor(cur, (*ctx).node) {
2831 return cur;
2832 }
2833 }
2834 }
2835}
2836
2837#[no_mangle]
2854pub unsafe extern "C" fn xmlXPathNextNamespace(
2855 ctxt: *mut c_void,
2856 cur: *mut _xmlNode,
2857) -> *mut _xmlNode {
2858 let pc = pc_from(ctxt);
2859 if pc.is_null() {
2860 return ptr::null_mut();
2861 }
2862 let ctx = unsafe { (*pc).context };
2863 if ctx.is_null() {
2864 return ptr::null_mut();
2865 }
2866 use crate::abi::types::xmlElementType as ET;
2867 unsafe {
2868 let cnode = (*ctx).node;
2869 if cnode.is_null() || (*cnode).type_ != ET::XML_ELEMENT_NODE as c_int {
2870 return ptr::null_mut();
2871 }
2872 if cur.is_null() {
2873 if !(*ctx).tmpNsList.is_null() {
2874 xmlFreeImpl((*ctx).tmpNsList as *mut c_void);
2875 }
2876 (*ctx).tmpNsNr = 0;
2877 (*ctx).tmpNsList = crate::xml::tree::get_ns_list((*ctx).doc, cnode);
2878 if !(*ctx).tmpNsList.is_null() {
2879 while !(*(*ctx).tmpNsList.add((*ctx).tmpNsNr as usize)).is_null() {
2880 (*ctx).tmpNsNr += 1;
2881 }
2882 }
2883 return (&XML_XPATH_XML_NS.0) as *const crate::abi::structs::_xmlNs as *mut _xmlNode;
2884 }
2885 if (*ctx).tmpNsNr > 0 {
2886 (*ctx).tmpNsNr -= 1;
2887 return (*(*ctx).tmpNsList.add((*ctx).tmpNsNr as usize)) as *mut _xmlNode;
2888 }
2889 if !(*ctx).tmpNsList.is_null() {
2890 xmlFreeImpl((*ctx).tmpNsList as *mut c_void);
2891 }
2892 (*ctx).tmpNsList = ptr::null_mut();
2893 ptr::null_mut()
2894 }
2895}
2896
2897#[no_mangle]
2914pub unsafe extern "C" fn xmlXPathNextAttribute(
2915 ctxt: *mut c_void,
2916 cur: *mut _xmlNode,
2917) -> *mut _xmlNode {
2918 let pc = pc_from(ctxt);
2919 if pc.is_null() {
2920 return ptr::null_mut();
2921 }
2922 let ctx = unsafe { (*pc).context };
2923 if ctx.is_null() {
2924 return ptr::null_mut();
2925 }
2926 use crate::abi::types::xmlElementType as ET;
2927 unsafe {
2928 let cnode = (*ctx).node;
2929 if cnode.is_null() || (*cnode).type_ != ET::XML_ELEMENT_NODE as c_int {
2930 return ptr::null_mut();
2931 }
2932 if cur.is_null() {
2933 if cnode == (*ctx).doc as *mut _xmlNode {
2934 return ptr::null_mut();
2935 }
2936 return (*cnode).properties as *mut _xmlNode;
2937 }
2938 (*cur).next
2939 }
2940}
2941
2942#[no_mangle]
2963pub unsafe extern "C" fn xmlXPathBooleanFunction(ctxt: *mut c_void, _nargs: c_int) {
2964 let pc = pc_from(ctxt);
2965 if pc.is_null() {
2966 return;
2967 }
2968 if !check_arity(pc, 1) {
2969 return;
2970 }
2971 let cur = value_pop(pc);
2972 if cur.is_null() {
2973 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
2974 return;
2975 }
2976 let b = crate::abi::exports_xml2::object_to_xpathvalue_pub(cur).as_boolean();
2977 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
2978 value_push(pc, new_bool(b));
2979}
2980
2981#[no_mangle]
2998pub unsafe extern "C" fn xmlXPathNotFunction(ctxt: *mut c_void, _nargs: c_int) {
2999 let pc = pc_from(ctxt);
3000 if pc.is_null() {
3001 return;
3002 }
3003 if !check_arity(pc, 1) {
3004 return;
3005 }
3006 cast_top_to_boolean(pc);
3007 if (*pc).error != 0 {
3008 return;
3009 }
3010 unsafe {
3011 (*(*pc).value).boolval = if (*(*pc).value).boolval == 0 { 1 } else { 0 };
3012 }
3013}
3014
3015#[no_mangle]
3032pub unsafe extern "C" fn xmlXPathTrueFunction(ctxt: *mut c_void, _nargs: c_int) {
3033 let pc = pc_from(ctxt);
3034 if pc.is_null() {
3035 return;
3036 }
3037
3038 value_push(pc, new_bool(true));
3039}
3040
3041#[no_mangle]
3058pub unsafe extern "C" fn xmlXPathFalseFunction(ctxt: *mut c_void, _nargs: c_int) {
3059 let pc = pc_from(ctxt);
3060 if pc.is_null() {
3061 return;
3062 }
3063
3064 value_push(pc, new_bool(false));
3065}
3066
3067const unsafe fn lang_matches(lang: *const xmlChar, the_lang: *const xmlChar) -> bool {
3070 if lang.is_null() || the_lang.is_null() {
3071 return false;
3072 }
3073 let mut i = 0usize;
3074 loop {
3075 let lc = unsafe { *lang.add(i) };
3076 if lc == 0 {
3077 break;
3078 }
3079 let tc = unsafe { *the_lang.add(i) };
3080 if tc == 0 {
3081 return false;
3082 }
3083 if !lc.eq_ignore_ascii_case(&tc) {
3084 return false;
3085 }
3086 i += 1;
3087 }
3088 let c = unsafe { *the_lang.add(i) };
3089 c == 0 || c == b'-'
3090}
3091
3092#[no_mangle]
3109pub unsafe extern "C" fn xmlXPathLangFunction(ctxt: *mut c_void, _nargs: c_int) {
3110 let pc = pc_from(ctxt);
3111 if pc.is_null() {
3112 return;
3113 }
3114 let ctx = unsafe { (*pc).context };
3115 if ctx.is_null() {
3116 return;
3117 }
3118 if !check_arity(pc, 1) {
3119 return;
3120 }
3121 cast_top_to_string(pc);
3122 if (*pc).error != 0 {
3123 return;
3124 }
3125 let val = value_pop(pc);
3126 if val.is_null() {
3127 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3128 return;
3129 }
3130 let lang = unsafe { (*val).stringval };
3131 let mut ret = 0;
3132 unsafe {
3133 let mut n = (*ctx).node;
3134 let mut found: *mut xmlChar = ptr::null_mut();
3135 while !n.is_null() {
3136 let got = crate::xml::tree::get_ns_prop(
3137 n,
3138 c"lang".as_ptr() as *const xmlChar,
3139 XML_XML_NAMESPACE_BYTES.as_ptr() as *const xmlChar,
3140 );
3141 if !got.is_null() {
3142 found = got;
3143 break;
3144 }
3145 n = (*n).parent;
3146 }
3147 if !found.is_null() && lang_matches(lang, found) {
3148 ret = 1;
3149 }
3150 if !found.is_null() {
3151 xmlFreeImpl(found as *mut c_void);
3152 }
3153 }
3154 crate::abi::exports_xml2::xmlXPathFreeObject(val);
3155 value_push(pc, new_bool(ret != 0));
3156}
3157
3158#[no_mangle]
3175pub unsafe extern "C" fn xmlXPathNumberFunction(ctxt: *mut c_void, nargs: c_int) {
3176 let pc = pc_from(ctxt);
3177 if pc.is_null() {
3178 return;
3179 }
3180 let ctx = unsafe { (*pc).context };
3181 if ctx.is_null() {
3182 return;
3183 }
3184 if nargs == 0 {
3185 let node = unsafe { (*ctx).node };
3186 let res = if node.is_null() {
3187 0.0
3188 } else {
3189 let sv = node_string_value(node);
3190 crate::xml::xpath::types::string_to_number(&sv)
3191 };
3192 value_push(pc, new_number(res));
3193 return;
3194 }
3195 if !check_arity(pc, 1) {
3196 return;
3197 }
3198 cast_top_to_number(pc);
3199}
3200
3201#[no_mangle]
3218pub unsafe extern "C" fn xmlXPathSumFunction(ctxt: *mut c_void, _nargs: c_int) {
3219 let pc = pc_from(ctxt);
3220 if pc.is_null() {
3221 return;
3222 }
3223 if !check_arity(pc, 1) {
3224 return;
3225 }
3226 let cur = value_pop(pc);
3227 if cur.is_null() {
3228 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3229 return;
3230 }
3231 let typ = unsafe { (*cur).type_ };
3232 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3233 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3234 {
3235 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3236 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3237 return;
3238 }
3239 let mut res = 0.0;
3240 unsafe {
3241 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3242 if !ns.is_null() {
3243 let nr = (*ns).nodeNr;
3244 let tab = (*ns).nodeTab;
3245 if !tab.is_null() {
3246 for i in 0..nr as isize {
3247 let node = *tab.add(i as usize);
3248 let sv = node_string_value(node);
3249 res += crate::xml::xpath::types::string_to_number(&sv);
3250 }
3251 }
3252 }
3253 }
3254 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3255 value_push(pc, new_number(res));
3256}
3257
3258#[no_mangle]
3275pub unsafe extern "C" fn xmlXPathFloorFunction(ctxt: *mut c_void, _nargs: c_int) {
3276 let pc = pc_from(ctxt);
3277 if pc.is_null() {
3278 return;
3279 }
3280 if !check_arity(pc, 1) {
3281 return;
3282 }
3283 cast_top_to_number(pc);
3284 if (*pc).error != 0 {
3285 return;
3286 }
3287 unsafe {
3288 (*(*pc).value).floatval = (*(*pc).value).floatval.floor();
3289 }
3290}
3291
3292#[no_mangle]
3309pub unsafe extern "C" fn xmlXPathCeilingFunction(ctxt: *mut c_void, _nargs: c_int) {
3310 let pc = pc_from(ctxt);
3311 if pc.is_null() {
3312 return;
3313 }
3314 if !check_arity(pc, 1) {
3315 return;
3316 }
3317 cast_top_to_number(pc);
3318 if (*pc).error != 0 {
3319 return;
3320 }
3321 unsafe {
3322 (*(*pc).value).floatval = (*(*pc).value).floatval.ceil();
3323 }
3324}
3325
3326#[no_mangle]
3343pub unsafe extern "C" fn xmlXPathRoundFunction(ctxt: *mut c_void, _nargs: c_int) {
3344 let pc = pc_from(ctxt);
3345 if pc.is_null() {
3346 return;
3347 }
3348 if !check_arity(pc, 1) {
3349 return;
3350 }
3351 cast_top_to_number(pc);
3352 if (*pc).error != 0 {
3353 return;
3354 }
3355 unsafe {
3356 let f = (*(*pc).value).floatval;
3357 if (-0.5..0.5).contains(&f) {
3358 (*(*pc).value).floatval *= 0.0;
3360 } else {
3361 let mut rounded = f.floor();
3362 if f - rounded >= 0.5 {
3363 rounded += 1.0;
3364 }
3365 (*(*pc).value).floatval = rounded;
3366 }
3367 }
3368}
3369
3370#[no_mangle]
3387pub unsafe extern "C" fn xmlXPathLastFunction(ctxt: *mut c_void, _nargs: c_int) {
3388 let pc = pc_from(ctxt);
3389 if pc.is_null() {
3390 return;
3391 }
3392 let ctx = unsafe { (*pc).context };
3393 if ctx.is_null() {
3394 return;
3395 }
3396
3397 value_push(pc, new_number(unsafe { (*ctx).contextSize } as f64));
3398}
3399
3400#[no_mangle]
3417pub unsafe extern "C" fn xmlXPathPositionFunction(ctxt: *mut c_void, _nargs: c_int) {
3418 let pc = pc_from(ctxt);
3419 if pc.is_null() {
3420 return;
3421 }
3422 let ctx = unsafe { (*pc).context };
3423 if ctx.is_null() {
3424 return;
3425 }
3426
3427 value_push(pc, new_number(unsafe { (*ctx).proximityPosition } as f64));
3428}
3429
3430#[no_mangle]
3447pub unsafe extern "C" fn xmlXPathCountFunction(ctxt: *mut c_void, _nargs: c_int) {
3448 let pc = pc_from(ctxt);
3449 if pc.is_null() {
3450 return;
3451 }
3452 if !check_arity(pc, 1) {
3453 return;
3454 }
3455 let cur = value_pop(pc);
3456 if cur.is_null() {
3457 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3458 return;
3459 }
3460 let typ = unsafe { (*cur).type_ };
3461 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3462 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3463 {
3464 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3465 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3466 return;
3467 }
3468 let count = unsafe {
3469 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3470 if ns.is_null() {
3471 0
3472 } else {
3473 (*ns).nodeNr
3474 }
3475 };
3476 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3477 value_push(pc, new_number(count as f64));
3478}
3479
3480unsafe fn get_elements_by_ids(doc: *mut _xmlDoc, ids: *const xmlChar) -> *mut _xmlNodeSet {
3483 use crate::abi::types::xmlElementType as ET;
3484 if ids.is_null() {
3485 return ptr::null_mut();
3486 }
3487 let mut out = NodeSet::new();
3488 unsafe {
3489 let mut p = ids;
3490 while *p != 0 {
3491 while is_blank_ch(*p) {
3492 p = p.add(1);
3493 }
3494 if *p == 0 {
3495 break;
3496 }
3497 let start = p;
3498 while *p != 0 && !is_blank_ch(*p) {
3499 p = p.add(1);
3500 }
3501 let id_c = crate::xml::string::xml_strndup(start, p.offset_from(start) as usize);
3502 if id_c.is_null() {
3503 break;
3504 }
3505 let attr = get_id(doc, id_c);
3506 xmlFreeImpl(id_c as *mut c_void);
3507 if !attr.is_null() {
3508 let t = (*attr).type_;
3509 let elem = if t == ET::XML_ATTRIBUTE_NODE as c_int {
3510 (*attr).parent
3511 } else if t == ET::XML_ELEMENT_NODE as c_int {
3512 attr as *mut _xmlNode
3513 } else {
3514 ptr::null_mut()
3515 };
3516 if !elem.is_null() {
3517 out.push(elem);
3518 }
3519 }
3520 }
3521 }
3522 out.to_raw()
3523}
3524
3525#[no_mangle]
3542pub unsafe extern "C" fn xmlXPathIdFunction(ctxt: *mut c_void, _nargs: c_int) {
3543 let pc = pc_from(ctxt);
3544 if pc.is_null() {
3545 return;
3546 }
3547 let ctx = unsafe { (*pc).context };
3548 if ctx.is_null() {
3549 return;
3550 }
3551 if !check_arity(pc, 1) {
3552 return;
3553 }
3554 let obj = value_pop(pc);
3555 if obj.is_null() {
3556 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3557 return;
3558 }
3559 let doc = unsafe { (*ctx).doc };
3560 let v = crate::abi::exports_xml2::object_to_xpathvalue_pub(obj);
3561 crate::abi::exports_xml2::xmlXPathFreeObject(obj);
3562 match &v {
3563 XPathValue::NodeSet(ns) => {
3564 let mut merged = NodeSet::new();
3565 for n in ns.iter() {
3566 let sv = node_string_value(n);
3567 let c = dup_rust_string(&sv);
3568 let sub = get_elements_by_ids(doc, c);
3569 xmlFreeImpl(c as *mut c_void);
3570 if !sub.is_null() {
3571 let sub_internal = node_set_to_internal(sub);
3572 for m in sub_internal.iter() {
3573 if !merged.contains(m) {
3574 merged.push(m);
3575 }
3576 }
3577 crate::abi::exports_xml2::xmlXPathFreeNodeSet(sub);
3579 }
3580 }
3581 value_push(
3582 pc,
3583 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(merged)),
3584 );
3585 }
3586 _ => {
3587 let s = v.as_string();
3588 let c = dup_rust_string(&s);
3589 let ret = get_elements_by_ids(doc, c);
3590 xmlFreeImpl(c as *mut c_void);
3591 if ret.is_null() {
3592 value_push(
3593 pc,
3594 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(
3595 NodeSet::new(),
3596 )),
3597 );
3598 } else {
3599 let obj2 = crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(
3600 node_set_to_internal(ret),
3601 ));
3602 crate::abi::exports_xml2::xmlXPathFreeNodeSet(ret);
3603 value_push(pc, obj2);
3604 }
3605 }
3606 }
3607}
3608
3609unsafe fn node_local_name(node: *mut _xmlNode) -> String {
3612 use crate::abi::types::xmlElementType as ET;
3613 if node.is_null() {
3614 return String::new();
3615 }
3616 unsafe {
3617 match (*node).type_ {
3618 t if t == ET::XML_ELEMENT_NODE as c_int
3619 || t == ET::XML_ATTRIBUTE_NODE as c_int
3620 || t == ET::XML_PI_NODE as c_int =>
3621 {
3622 let name = (*node).name;
3623 if name.is_null() || *name == b' ' {
3624 String::new()
3625 } else {
3626 let s = CStr::from_ptr(name as *const c_char)
3627 .to_string_lossy()
3628 .into_owned();
3629 match s.split_once(':') {
3630 Some((_, local)) => local.to_string(),
3631 None => s,
3632 }
3633 }
3634 }
3635 t if t == ET::XML_NAMESPACE_DECL as c_int => {
3636 let ns = node as *mut crate::abi::structs::_xmlNs;
3637 let p = (*ns).prefix;
3638 if p.is_null() {
3639 String::new()
3640 } else {
3641 CStr::from_ptr(p as *const c_char)
3642 .to_string_lossy()
3643 .into_owned()
3644 }
3645 }
3646 _ => String::new(),
3647 }
3648 }
3649}
3650
3651unsafe fn node_qname(node: *mut _xmlNode) -> String {
3656 use crate::abi::types::xmlElementType as ET;
3657 if node.is_null() {
3658 return String::new();
3659 }
3660 unsafe {
3661 let t = (*node).type_;
3662 if t == ET::XML_ELEMENT_NODE as c_int || t == ET::XML_ATTRIBUTE_NODE as c_int {
3663 let name = (*node).name;
3664 if name.is_null() || *name == b' ' {
3665 return String::new();
3666 }
3667 let local = CStr::from_ptr(name as *const c_char)
3668 .to_string_lossy()
3669 .into_owned();
3670 let ns = (*node).ns;
3671 if !ns.is_null() && !(*ns).prefix.is_null() {
3672 let prefix = CStr::from_ptr((*ns).prefix as *const c_char)
3673 .to_string_lossy()
3674 .into_owned();
3675 format!("{prefix}:{local}")
3676 } else {
3677 local
3678 }
3679 } else {
3680 node_local_name(node)
3681 }
3682 }
3683}
3684
3685#[no_mangle]
3702pub unsafe extern "C" fn xmlXPathLocalNameFunction(ctxt: *mut c_void, nargs: c_int) {
3703 let pc = pc_from(ctxt);
3704 if pc.is_null() {
3705 return;
3706 }
3707 let ctx = unsafe { (*pc).context };
3708 if ctx.is_null() {
3709 return;
3710 }
3711 if nargs == 0 {
3712 value_push(
3713 pc,
3714 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(NodeSet::singleton(
3715 unsafe { (*ctx).node },
3716 ))),
3717 );
3718 }
3720
3721 if !check_arity(pc, 1) {
3722 return;
3723 }
3724 let cur = value_pop(pc);
3725 if cur.is_null() {
3726 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3727 return;
3728 }
3729 let typ = unsafe { (*cur).type_ };
3730 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3731 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3732 {
3733 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3734 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3735 return;
3736 }
3737 let name = unsafe {
3738 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3739 if ns.is_null() || (*ns).nodeNr == 0 {
3740 String::new()
3741 } else {
3742 node_local_name(*(*ns).nodeTab)
3743 }
3744 };
3745 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3746 let out = dup_rust_string(&name);
3747 value_push(pc, xmlXPathWrapString(out));
3748}
3749
3750#[no_mangle]
3759pub unsafe extern "C" fn xmlXPathNameFunction(ctxt: *mut c_void, nargs: c_int) {
3760 let pc = pc_from(ctxt);
3761 if pc.is_null() {
3762 return;
3763 }
3764 let ctx = unsafe { (*pc).context };
3765 if ctx.is_null() {
3766 return;
3767 }
3768 if nargs == 0 {
3769 value_push(
3770 pc,
3771 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(NodeSet::singleton(
3772 unsafe { (*ctx).node },
3773 ))),
3774 );
3775 }
3777
3778 if !check_arity(pc, 1) {
3779 return;
3780 }
3781 let cur = value_pop(pc);
3782 if cur.is_null() {
3783 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3784 return;
3785 }
3786 let typ = unsafe { (*cur).type_ };
3787 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3788 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3789 {
3790 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3791 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3792 return;
3793 }
3794 let name = unsafe {
3795 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3796 if ns.is_null() || (*ns).nodeNr == 0 {
3797 String::new()
3798 } else {
3799 node_qname(*(*ns).nodeTab)
3800 }
3801 };
3802 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3803 let out = dup_rust_string(&name);
3804 value_push(pc, xmlXPathWrapString(out));
3805}
3806
3807unsafe fn node_namespace_uri(node: *mut _xmlNode) -> String {
3809 use crate::abi::types::xmlElementType as ET;
3810 if node.is_null() {
3811 return String::new();
3812 }
3813 unsafe {
3814 match (*node).type_ {
3815 t if t == ET::XML_ELEMENT_NODE as c_int || t == ET::XML_ATTRIBUTE_NODE as c_int => {
3816 let ns = (*node).ns;
3817 if ns.is_null() || (*ns).href.is_null() {
3818 String::new()
3819 } else {
3820 CStr::from_ptr((*ns).href as *const c_char)
3821 .to_string_lossy()
3822 .into_owned()
3823 }
3824 }
3825 t if t == ET::XML_NAMESPACE_DECL as c_int => {
3826 let ns = node as *mut crate::abi::structs::_xmlNs;
3827 if (*ns).href.is_null() {
3828 String::new()
3829 } else {
3830 CStr::from_ptr((*ns).href as *const c_char)
3831 .to_string_lossy()
3832 .into_owned()
3833 }
3834 }
3835 _ => String::new(),
3836 }
3837 }
3838}
3839
3840#[no_mangle]
3857pub unsafe extern "C" fn xmlXPathNamespaceURIFunction(ctxt: *mut c_void, nargs: c_int) {
3858 let pc = pc_from(ctxt);
3859 if pc.is_null() {
3860 return;
3861 }
3862 let ctx = unsafe { (*pc).context };
3863 if ctx.is_null() {
3864 return;
3865 }
3866 if nargs == 0 {
3867 value_push(
3868 pc,
3869 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(NodeSet::singleton(
3870 unsafe { (*ctx).node },
3871 ))),
3872 );
3873 }
3874
3875 if !check_arity(pc, 1) {
3876 return;
3877 }
3878 let cur = value_pop(pc);
3879 if cur.is_null() {
3880 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3881 return;
3882 }
3883 let typ = unsafe { (*cur).type_ };
3884 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3885 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3886 {
3887 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3888 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3889 return;
3890 }
3891 let uri = unsafe {
3892 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3893 if ns.is_null() || (*ns).nodeNr == 0 {
3894 String::new()
3895 } else {
3896 node_namespace_uri(*(*ns).nodeTab)
3897 }
3898 };
3899 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3900 let out = dup_rust_string(&uri);
3901 value_push(pc, xmlXPathWrapString(out));
3902}
3903
3904#[no_mangle]
3921pub unsafe extern "C" fn xmlXPathStringFunction(ctxt: *mut c_void, nargs: c_int) {
3922 let pc = pc_from(ctxt);
3923 if pc.is_null() {
3924 return;
3925 }
3926 let ctx = unsafe { (*pc).context };
3927 if ctx.is_null() {
3928 return;
3929 }
3930 if nargs == 0 {
3931 let node = unsafe { (*ctx).node };
3932 let sv = if node.is_null() {
3933 String::new()
3934 } else {
3935 node_string_value(node)
3936 };
3937 let out = dup_rust_string(&sv);
3938 value_push(pc, xmlXPathWrapString(out));
3939 return;
3940 }
3941 if !check_arity(pc, 1) {
3942 return;
3943 }
3944 cast_top_to_string(pc);
3945}
3946
3947#[no_mangle]
3964pub unsafe extern "C" fn xmlXPathStringLengthFunction(ctxt: *mut c_void, nargs: c_int) {
3965 let pc = pc_from(ctxt);
3966 if pc.is_null() {
3967 return;
3968 }
3969 let ctx = unsafe { (*pc).context };
3970 if ctx.is_null() {
3971 return;
3972 }
3973 if nargs == 0 {
3974 let node = unsafe { (*ctx).node };
3975 let len = if node.is_null() {
3976 0
3977 } else {
3978 let sv = node_string_value(node);
3979 sv.chars().count()
3980 };
3981 value_push(pc, new_number(len as f64));
3982 return;
3983 }
3984 if !check_arity(pc, 1) {
3985 return;
3986 }
3987 cast_top_to_string(pc);
3988 if (*pc).error != 0 {
3989 return;
3990 }
3991 let len = unsafe {
3992 let s = (*(*pc).value).stringval;
3993 if s.is_null() {
3994 0
3995 } else {
3996 let sv = CStr::from_ptr(s as *const c_char).to_string_lossy();
3997 sv.chars().count()
3998 }
3999 };
4000 let cur = value_pop(pc);
4001 if !cur.is_null() {
4002 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
4003 }
4004 value_push(pc, new_number(len as f64));
4005}
4006
4007#[no_mangle]
4024pub unsafe extern "C" fn xmlXPathConcatFunction(ctxt: *mut c_void, nargs: c_int) {
4025 let pc = pc_from(ctxt);
4026 if pc.is_null() {
4027 return;
4028 }
4029 if nargs < 2 && !check_arity(pc, 2) {
4030 return;
4031 }
4032 if !check_arity(pc, nargs) {
4033 return;
4034 }
4035 let mut parts: Vec<String> = Vec::with_capacity(nargs as usize);
4036 for _ in 0..nargs {
4037 cast_top_to_string(pc);
4038 if (*pc).error != 0 {
4039 return;
4040 }
4041 let v = crate::abi::exports_xml2::object_to_xpathvalue_pub(unsafe { (*pc).value });
4042 let s = v.as_string();
4043 let obj = value_pop(pc);
4044 if !obj.is_null() {
4045 crate::abi::exports_xml2::xmlXPathFreeObject(obj);
4046 }
4047 parts.push(s);
4048 }
4049 parts.reverse();
4050 let joined = parts.concat();
4051 let out = dup_rust_string(&joined);
4052 value_push(pc, xmlXPathWrapString(out));
4053}
4054
4055#[no_mangle]
4072pub unsafe extern "C" fn xmlXPathContainsFunction(ctxt: *mut c_void, _nargs: c_int) {
4073 let pc = pc_from(ctxt);
4074 if pc.is_null() {
4075 return;
4076 }
4077 if !check_arity(pc, 2) {
4078 return;
4079 }
4080 cast_top_to_string(pc);
4081 if (*pc).error != 0 {
4082 return;
4083 }
4084 let needle = value_pop(pc);
4085 cast_top_to_string(pc);
4086 if (*pc).error != 0 {
4087 if !needle.is_null() {
4088 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
4089 }
4090 return;
4091 }
4092 let hay = value_pop(pc);
4093 let found = if hay.is_null() || needle.is_null() {
4094 false
4095 } else {
4096 unsafe { !cstr_find((*hay).stringval, (*needle).stringval).is_null() }
4097 };
4098 if !hay.is_null() {
4099 crate::abi::exports_xml2::xmlXPathFreeObject(hay);
4100 }
4101 if !needle.is_null() {
4102 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
4103 }
4104 value_push(pc, new_bool(found));
4105}
4106
4107#[no_mangle]
4124pub unsafe extern "C" fn xmlXPathStartsWithFunction(ctxt: *mut c_void, _nargs: c_int) {
4125 let pc = pc_from(ctxt);
4126 if pc.is_null() {
4127 return;
4128 }
4129 if !check_arity(pc, 2) {
4130 return;
4131 }
4132 cast_top_to_string(pc);
4133 if (*pc).error != 0 {
4134 return;
4135 }
4136 let needle = value_pop(pc);
4137 cast_top_to_string(pc);
4138 if (*pc).error != 0 {
4139 if !needle.is_null() {
4140 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
4141 }
4142 return;
4143 }
4144 let hay = value_pop(pc);
4145 let found = if hay.is_null() || needle.is_null() {
4146 false
4147 } else {
4148 unsafe { crate::xml::string::xml_str_starts_with((*hay).stringval, (*needle).stringval) }
4149 };
4150 if !hay.is_null() {
4151 crate::abi::exports_xml2::xmlXPathFreeObject(hay);
4152 }
4153 if !needle.is_null() {
4154 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
4155 }
4156 value_push(pc, new_bool(found));
4157}
4158
4159#[no_mangle]
4176pub unsafe extern "C" fn xmlXPathSubstringFunction(ctxt: *mut c_void, nargs: c_int) {
4177 let pc = pc_from(ctxt);
4178 if pc.is_null() {
4179 return;
4180 }
4181 if nargs < 2 {
4182 if !check_arity(pc, 2) {
4183 return;
4184 }
4185 } else if nargs > 3 && !check_arity(pc, 3) {
4186 return;
4187 }
4188 let mut le = 0.0;
4189 if nargs == 3 {
4190 cast_top_to_number(pc);
4191 if (*pc).error != 0 {
4192 return;
4193 }
4194 let len_obj = value_pop(pc);
4195 if !len_obj.is_null() {
4196 le = unsafe { (*len_obj).floatval };
4197 crate::abi::exports_xml2::xmlXPathFreeObject(len_obj);
4198 }
4199 }
4200 cast_top_to_number(pc);
4201 if (*pc).error != 0 {
4202 return;
4203 }
4204 let start_obj = value_pop(pc);
4205 let in_ = if start_obj.is_null() {
4206 f64::NAN
4207 } else {
4208 let v = unsafe { (*start_obj).floatval };
4209 crate::abi::exports_xml2::xmlXPathFreeObject(start_obj);
4210 v
4211 };
4212 cast_top_to_string(pc);
4213 if (*pc).error != 0 {
4214 return;
4215 }
4216 let str_obj = value_pop(pc);
4217 let s = if str_obj.is_null() {
4218 String::new()
4219 } else {
4220 let v = unsafe { CStr::from_ptr((*str_obj).stringval as *const c_char) }
4221 .to_string_lossy()
4222 .into_owned();
4223 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
4224 v
4225 };
4226
4227 let int_max = i32::MAX as f64;
4228 let mut i: i64 = 1;
4229 let mut j: i64 = i32::MAX as i64;
4230 #[allow(clippy::neg_cmp_op_on_partial_ord)]
4234 if !(in_ < int_max) {
4235 i = i32::MAX as i64;
4236 } else if in_ >= 1.0 {
4237 i = in_ as i64;
4238 if in_ - in_.floor() >= 0.5 {
4239 i += 1;
4240 }
4241 }
4242 if nargs == 3 {
4243 let mut rin = in_.floor();
4244 if in_ - rin >= 0.5 {
4245 rin += 1.0;
4246 }
4247 let mut rle = le.floor();
4248 if le - rle >= 0.5 {
4249 rle += 1.0;
4250 }
4251 let end = rin + rle;
4252 #[allow(clippy::neg_cmp_op_on_partial_ord)]
4253 if !(end >= 1.0) {
4254 j = 1;
4255 } else if end < int_max {
4256 j = end as i64;
4257 }
4258 }
4259 i -= 1;
4260 j -= 1;
4261 let chars: Vec<char> = s.chars().collect();
4262 let slen = chars.len() as i64;
4263 let out = if i < j && i < slen {
4264 let start_i = i.max(0) as usize;
4265 let end_i = (j.min(slen)).max(start_i as i64) as usize;
4266 chars[start_i..end_i].iter().collect()
4267 } else {
4268 String::new()
4269 };
4270 let c = dup_rust_string(&out);
4271 value_push(pc, xmlXPathWrapString(c));
4272}
4273
4274#[no_mangle]
4291pub unsafe extern "C" fn xmlXPathSubstringBeforeFunction(ctxt: *mut c_void, _nargs: c_int) {
4292 let pc = pc_from(ctxt);
4293 if pc.is_null() {
4294 return;
4295 }
4296 if !check_arity(pc, 2) {
4297 return;
4298 }
4299 cast_top_to_string(pc);
4300 if (*pc).error != 0 {
4301 return;
4302 }
4303 let find = value_pop(pc);
4304 cast_top_to_string(pc);
4305 if (*pc).error != 0 {
4306 if !find.is_null() {
4307 crate::abi::exports_xml2::xmlXPathFreeObject(find);
4308 }
4309 return;
4310 }
4311 let str_obj = value_pop(pc);
4312 let out: String = if str_obj.is_null() || find.is_null() {
4313 String::new()
4314 } else {
4315 unsafe {
4316 let hay = (*str_obj).stringval;
4317 let needle = (*find).stringval;
4318 let point = cstr_find(hay, needle);
4319 if point.is_null() {
4320 String::new()
4321 } else {
4322 let len = point.offset_from(hay) as usize;
4323 let bytes = core::slice::from_raw_parts(hay as *const u8, len);
4324 String::from_utf8_lossy(bytes).into_owned()
4325 }
4326 }
4327 };
4328 if !str_obj.is_null() {
4329 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
4330 }
4331 if !find.is_null() {
4332 crate::abi::exports_xml2::xmlXPathFreeObject(find);
4333 }
4334 let c = dup_rust_string(&out);
4335 value_push(pc, xmlXPathWrapString(c));
4336}
4337
4338#[no_mangle]
4355pub unsafe extern "C" fn xmlXPathSubstringAfterFunction(ctxt: *mut c_void, _nargs: c_int) {
4356 let pc = pc_from(ctxt);
4357 if pc.is_null() {
4358 return;
4359 }
4360 if !check_arity(pc, 2) {
4361 return;
4362 }
4363 cast_top_to_string(pc);
4364 if (*pc).error != 0 {
4365 return;
4366 }
4367 let find = value_pop(pc);
4368 cast_top_to_string(pc);
4369 if (*pc).error != 0 {
4370 if !find.is_null() {
4371 crate::abi::exports_xml2::xmlXPathFreeObject(find);
4372 }
4373 return;
4374 }
4375 let str_obj = value_pop(pc);
4376 let out: String = if str_obj.is_null() || find.is_null() {
4377 String::new()
4378 } else {
4379 unsafe {
4380 let hay = (*str_obj).stringval;
4381 let needle = (*find).stringval;
4382 let point = cstr_find(hay, needle);
4383 if point.is_null() {
4384 String::new()
4385 } else {
4386 let nlen = crate::xml::string::xml_strlen(needle);
4387 let rest = point.add(nlen);
4388 let len = crate::xml::string::xml_strlen(rest);
4389 let bytes = core::slice::from_raw_parts(rest, len);
4390 String::from_utf8_lossy(bytes).into_owned()
4391 }
4392 }
4393 };
4394 if !str_obj.is_null() {
4395 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
4396 }
4397 if !find.is_null() {
4398 crate::abi::exports_xml2::xmlXPathFreeObject(find);
4399 }
4400 let c = dup_rust_string(&out);
4401 value_push(pc, xmlXPathWrapString(c));
4402}
4403
4404#[no_mangle]
4421pub unsafe extern "C" fn xmlXPathNormalizeFunction(ctxt: *mut c_void, nargs: c_int) {
4422 let pc = pc_from(ctxt);
4423 if pc.is_null() {
4424 return;
4425 }
4426 let ctx = unsafe { (*pc).context };
4427 if ctx.is_null() {
4428 return;
4429 }
4430 if nargs == 0 {
4431 let node = unsafe { (*ctx).node };
4432 let sv = if node.is_null() {
4433 String::new()
4434 } else {
4435 node_string_value(node)
4436 };
4437 let c = dup_rust_string(&sv);
4438 value_push(pc, xmlXPathWrapString(c));
4439 }
4441
4442 if !check_arity(pc, 1) {
4443 return;
4444 }
4445 cast_top_to_string(pc);
4446 if (*pc).error != 0 {
4447 return;
4448 }
4449 let s = unsafe {
4450 let p = (*(*pc).value).stringval;
4451 if p.is_null() {
4452 String::new()
4453 } else {
4454 CStr::from_ptr(p as *const c_char)
4455 .to_string_lossy()
4456 .into_owned()
4457 }
4458 };
4459 let mut out = String::with_capacity(s.len());
4461 let mut blank = false;
4462 let mut started = false;
4463 for c in s.chars() {
4464 let is_b = c == ' ' || c == '\t' || c == '\n' || c == '\r';
4465 if is_b {
4466 if started {
4467 blank = true;
4468 }
4469 } else {
4470 if blank {
4471 out.push(' ');
4472 blank = false;
4473 }
4474 out.push(c);
4475 started = true;
4476 }
4477 }
4478 unsafe {
4479 let val = (*pc).value;
4480 if !(*val).stringval.is_null() {
4481 xmlFreeImpl((*val).stringval as *mut c_void);
4482 }
4483 (*val).stringval = dup_rust_string(&out);
4484 }
4485}
4486
4487#[no_mangle]
4504pub unsafe extern "C" fn xmlXPathTranslateFunction(ctxt: *mut c_void, _nargs: c_int) {
4505 let pc = pc_from(ctxt);
4506 if pc.is_null() {
4507 return;
4508 }
4509 if !check_arity(pc, 3) {
4510 return;
4511 }
4512 cast_top_to_string(pc);
4513 if (*pc).error != 0 {
4514 return;
4515 }
4516 let to = value_pop(pc);
4517 cast_top_to_string(pc);
4518 if (*pc).error != 0 {
4519 if !to.is_null() {
4520 crate::abi::exports_xml2::xmlXPathFreeObject(to);
4521 }
4522 return;
4523 }
4524 let from = value_pop(pc);
4525 cast_top_to_string(pc);
4526 if (*pc).error != 0 {
4527 if !to.is_null() {
4528 crate::abi::exports_xml2::xmlXPathFreeObject(to);
4529 }
4530 if !from.is_null() {
4531 crate::abi::exports_xml2::xmlXPathFreeObject(from);
4532 }
4533 return;
4534 }
4535 let str_obj = value_pop(pc);
4536 let (s, f, t) = unsafe {
4537 let s = if str_obj.is_null() || (*str_obj).stringval.is_null() {
4538 String::new()
4539 } else {
4540 CStr::from_ptr((*str_obj).stringval as *const c_char)
4541 .to_string_lossy()
4542 .into_owned()
4543 };
4544 let f = if from.is_null() || (*from).stringval.is_null() {
4545 String::new()
4546 } else {
4547 CStr::from_ptr((*from).stringval as *const c_char)
4548 .to_string_lossy()
4549 .into_owned()
4550 };
4551 let t = if to.is_null() || (*to).stringval.is_null() {
4552 String::new()
4553 } else {
4554 CStr::from_ptr((*to).stringval as *const c_char)
4555 .to_string_lossy()
4556 .into_owned()
4557 };
4558 (s, f, t)
4559 };
4560 if !str_obj.is_null() {
4561 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
4562 }
4563 if !from.is_null() {
4564 crate::abi::exports_xml2::xmlXPathFreeObject(from);
4565 }
4566 if !to.is_null() {
4567 crate::abi::exports_xml2::xmlXPathFreeObject(to);
4568 }
4569 let from_chars: Vec<char> = f.chars().collect();
4570 let to_chars: Vec<char> = t.chars().collect();
4571 let out: String = s
4574 .chars()
4575 .filter_map(|c| match from_chars.iter().position(|&x| x == c) {
4576 Some(i) if i < to_chars.len() => Some(to_chars[i]),
4577 Some(_) => None,
4578 _ => Some(c),
4579 })
4580 .collect();
4581 let c = dup_rust_string(&out);
4582 value_push(pc, xmlXPathWrapString(c));
4583}
4584
4585#[no_mangle]
4603pub const unsafe extern "C" fn xmlXPathRegisterAllFunctions(_ctxt: *mut _xmlXPathContext) {}
4604
4605unsafe fn standard_function_pointer(
4608 name: &str,
4609) -> Option<unsafe extern "C" fn(*mut c_void, c_int)> {
4610 let f: unsafe extern "C" fn(*mut c_void, c_int) = match name {
4611 "boolean" => xmlXPathBooleanFunction,
4612 "not" => xmlXPathNotFunction,
4613 "true" => xmlXPathTrueFunction,
4614 "false" => xmlXPathFalseFunction,
4615 "lang" => xmlXPathLangFunction,
4616 "number" => xmlXPathNumberFunction,
4617 "sum" => xmlXPathSumFunction,
4618 "floor" => xmlXPathFloorFunction,
4619 "ceiling" => xmlXPathCeilingFunction,
4620 "round" => xmlXPathRoundFunction,
4621 "last" => xmlXPathLastFunction,
4622 "position" => xmlXPathPositionFunction,
4623 "count" => xmlXPathCountFunction,
4624 "id" => xmlXPathIdFunction,
4625 "local-name" => xmlXPathLocalNameFunction,
4626 "name" => xmlXPathNameFunction,
4627 "namespace-uri" => xmlXPathNamespaceURIFunction,
4628 "string" => xmlXPathStringFunction,
4629 "string-length" => xmlXPathStringLengthFunction,
4630 "concat" => xmlXPathConcatFunction,
4631 "contains" => xmlXPathContainsFunction,
4632 "starts-with" => xmlXPathStartsWithFunction,
4633 "substring" => xmlXPathSubstringFunction,
4634 "substring-before" => xmlXPathSubstringBeforeFunction,
4635 "substring-after" => xmlXPathSubstringAfterFunction,
4636 "normalize-space" => xmlXPathNormalizeFunction,
4637 "translate" => xmlXPathTranslateFunction,
4638 _ => return None,
4639 };
4640 Some(f)
4641}
4642
4643#[no_mangle]
4649pub unsafe extern "C" fn xmlXPathFunctionLookup(
4650 ctxt: *mut _xmlXPathContext,
4651 name: *const xmlChar,
4652) -> Option<unsafe extern "C" fn(*mut c_void, c_int)> {
4653 xmlXPathFunctionLookupNS(ctxt, name, ptr::null())
4654}
4655
4656#[no_mangle]
4662pub unsafe extern "C" fn xmlXPathFunctionLookupNS(
4663 ctxt: *mut _xmlXPathContext,
4664 name: *const xmlChar,
4665 ns_uri: *const xmlChar,
4666) -> Option<unsafe extern "C" fn(*mut c_void, c_int)> {
4667 if ctxt.is_null() || name.is_null() {
4668 return None;
4669 }
4670 let name_str = match CStr::from_ptr(name as *const c_char).to_str() {
4671 Ok(s) => s.to_string(),
4672 Err(_) => return None,
4673 };
4674 if ns_uri.is_null() {
4675 if let Some(f) = standard_function_pointer(&name_str) {
4676 return Some(f);
4677 }
4678 }
4679 if let Some(f) = (*ctxt).funcLookupFunc {
4681 let ret = f((*ctxt).funcLookupData, name, ns_uri);
4682 if !ret.is_null() {
4683 let fp =
4685 std::mem::transmute::<*mut c_void, unsafe extern "C" fn(*mut c_void, c_int)>(ret);
4686 return Some(fp);
4687 }
4688 }
4689 let qualified = if ns_uri.is_null() {
4690 name_str
4691 } else {
4692 let ns = match CStr::from_ptr(ns_uri as *const c_char).to_str() {
4693 Ok(s) => s,
4694 Err(_) => return None,
4695 };
4696 format!("{{{}}}{}", ns, name_str)
4697 };
4698 crate::abi::exports_xml2::xpath_cfunc_lookup((*ctxt).extra, &qualified)
4699}
4700
4701#[no_mangle]
4715pub unsafe extern "C" fn xmlXPathCtxtCompile(
4716 ctxt: *mut _xmlXPathContext,
4717 str_: *const xmlChar,
4718) -> *mut c_void {
4719 if str_.is_null() {
4720 return ptr::null_mut();
4721 }
4722 let expr_str = match CStr::from_ptr(str_ as *const c_char).to_str() {
4723 Ok(s) => s,
4724 Err(_) => return ptr::null_mut(),
4725 };
4726 match crate::abi::exports_xml2::xpath_compile_store(expr_str) {
4727 Ok(key) => key,
4728 Err(e) => {
4729 if ctxt.is_null() {
4730 crate::abi::exports_xml2::xmlXPathCompile(str_)
4734 } else {
4735 let recursion = e.message == "Recursion limit exceeded";
4744 let code = if recursion {
4745 crate::abi::types::XPATH_RECURSION_LIMIT_EXCEEDED
4746 } else {
4747 crate::abi::types::XPATH_EXPR_ERROR
4748 };
4749 let msg = if recursion {
4750 "Recursion limit exceeded"
4751 } else {
4752 "Invalid expression"
4753 };
4754 unsafe {
4755 crate::abi::exports_xml2::raise_xpath_error(ctxt, code, msg, expr_str);
4756 }
4757 ptr::null_mut()
4758 }
4759 }
4760 }
4761}
4762
4763#[no_mangle]
4769pub unsafe extern "C" fn xmlXPathCompiledEval(
4770 comp: *mut c_void,
4771 ctx: *mut _xmlXPathContext,
4772) -> *mut _xmlXPathObject {
4773 if comp.is_null() || ctx.is_null() {
4774 return ptr::null_mut();
4775 }
4776 let internal = (*ctx).extra as *mut XPathContext;
4777 if internal.is_null() {
4778 return ptr::null_mut();
4779 }
4780 let internal = &mut *internal;
4781 internal.document = (*ctx).doc;
4787 internal.set_context_node((*ctx).node);
4788 internal.context_position = (*ctx).proximityPosition;
4789 internal.context_size = (*ctx).contextSize;
4790 internal.proximity_position = (*ctx).proximityPosition;
4791 crate::abi::exports_xml2::sync_xpath_context_namespaces(ctx, internal);
4792 internal.clear_error();
4793 let registry = crate::abi::exports_xml2::xpath_compiled_registry();
4794 let map = registry.lock();
4795 match map.get(&(comp as u64)) {
4796 Some(compiled) => match crate::xml::xpath::evaluate(compiled, internal) {
4797 Some(val) => crate::abi::exports_xml2::xpath_to_object_pub(val),
4798 None => {
4799 unsafe {
4803 crate::abi::exports_xml2::raise_internal_xpath_error(
4804 ctx,
4805 internal,
4806 &compiled.original,
4807 );
4808 }
4809 ptr::null_mut()
4810 }
4811 },
4812 None => ptr::null_mut(),
4813 }
4814}
4815
4816#[no_mangle]
4824pub unsafe extern "C" fn xmlXPathCompiledEvalToBoolean(
4825 comp: *mut c_void,
4826 ctxt: *mut _xmlXPathContext,
4827) -> c_int {
4828 let obj = xmlXPathCompiledEval(comp, ctxt);
4829 if obj.is_null() {
4830 return -1;
4831 }
4832 let b = crate::abi::exports_xml2::object_to_xpathvalue_pub(obj).as_boolean();
4833 crate::abi::exports_xml2::xmlXPathFreeObject(obj);
4834 b as c_int
4835}
4836
4837#[no_mangle]
4844pub unsafe extern "C" fn xmlXPathSetContextNode(
4845 node: *mut _xmlNode,
4846 ctx: *mut _xmlXPathContext,
4847) -> c_int {
4848 if node.is_null() || ctx.is_null() {
4849 return -1;
4850 }
4851 if (*node).doc != (*ctx).doc {
4852 return -1;
4853 }
4854 (*ctx).node = node;
4855 let internal = (*ctx).extra as *mut XPathContext;
4856 if !internal.is_null() {
4857 (*internal).context_node = node;
4858 }
4859 0
4860}
4861
4862#[no_mangle]
4868pub unsafe extern "C" fn xmlXPathNodeEval(
4869 node: *mut _xmlNode,
4870 str_: *const xmlChar,
4871 ctx: *mut _xmlXPathContext,
4872) -> *mut _xmlXPathObject {
4873 if str_.is_null() {
4874 return ptr::null_mut();
4875 }
4876 if xmlXPathSetContextNode(node, ctx) < 0 {
4877 return ptr::null_mut();
4878 }
4879 crate::abi::exports_xml2::xmlXPathEvalExpression(str_, ctx)
4880}
4881
4882#[no_mangle]
4891pub unsafe extern "C" fn xmlXPathContextSetCache(
4892 ctxt: *mut _xmlXPathContext,
4893 active: c_int,
4894 _value: c_int,
4895 _options: c_int,
4896) -> c_int {
4897 if ctxt.is_null() {
4898 return -1;
4899 }
4900 (*ctxt).cache = if active != 0 {
4901 (&XML_XPATH_XML_NS.0) as *const crate::abi::structs::_xmlNs as *mut c_void
4902 } else {
4903 ptr::null_mut()
4904 };
4905 0
4906}
4907
4908#[no_mangle]
4914pub unsafe extern "C" fn xmlXPathRegisterFuncLookup(
4915 ctxt: *mut _xmlXPathContext,
4916 f: Option<crate::abi::callbacks::xmlXPathFuncLookupFunc>,
4917 data: *mut c_void,
4918) {
4919 if ctxt.is_null() {
4920 return;
4921 }
4922 (*ctxt).funcLookupFunc = f;
4923 (*ctxt).funcLookupData = data;
4924 let internal = (*ctxt).extra as *mut XPathContext;
4925 if !internal.is_null() {
4926 (*internal).func_lookup_func = f;
4927 (*internal).func_lookup_data = data;
4928 }
4929}
4930
4931#[no_mangle]
4937pub unsafe extern "C" fn xmlXPathRegisterVariableLookup(
4938 ctxt: *mut _xmlXPathContext,
4939 f: Option<crate::abi::callbacks::xmlXPathVariableLookupFunc>,
4940 data: *mut c_void,
4941) {
4942 if ctxt.is_null() {
4943 return;
4944 }
4945 (*ctxt).varLookupFunc = f;
4946 (*ctxt).varLookupData = data;
4947 let internal = (*ctxt).extra as *mut XPathContext;
4948 if !internal.is_null() {
4949 (*internal).var_lookup_func = f;
4950 (*internal).var_lookup_data = data;
4951 }
4952}
4953
4954#[no_mangle]
4960pub unsafe extern "C" fn xmlXPathRegisterVariableNS(
4961 ctxt: *mut _xmlXPathContext,
4962 name: *const xmlChar,
4963 ns_uri: *const xmlChar,
4964 value: *mut _xmlXPathObject,
4965) -> c_int {
4966 if ctxt.is_null() || name.is_null() || value.is_null() {
4967 return -1;
4968 }
4969 let internal = (*ctxt).extra as *mut XPathContext;
4970 if internal.is_null() {
4971 return -1;
4972 }
4973 let internal = &mut *internal;
4974 let name_str = match CStr::from_ptr(name as *const c_char).to_str() {
4975 Ok(s) => s.to_string(),
4976 Err(_) => return -1,
4977 };
4978 let qualified = if ns_uri.is_null() {
4979 name_str
4980 } else {
4981 match CStr::from_ptr(ns_uri as *const c_char).to_str() {
4982 Ok(s) => format!("{{{}}}{}", s, name_str),
4983 Err(_) => return -1,
4984 }
4985 };
4986 let xpath_val = crate::abi::exports_xml2::object_to_xpathvalue_pub(value);
4987 internal.register_variable(&qualified, xpath_val);
4988 0
4989}
4990
4991#[no_mangle]
4997pub unsafe extern "C" fn xmlXPathVariableLookup(
4998 ctxt: *mut _xmlXPathContext,
4999 name: *const xmlChar,
5000) -> *mut _xmlXPathObject {
5001 if ctxt.is_null() {
5002 return ptr::null_mut();
5003 }
5004 if let Some(f) = (*ctxt).varLookupFunc {
5005 let ret = f((*ctxt).varLookupData, name, ptr::null());
5006 return ret;
5007 }
5008 xmlXPathVariableLookupNS(ctxt, name, ptr::null())
5009}
5010
5011#[no_mangle]
5017pub unsafe extern "C" fn xmlXPathVariableLookupNS(
5018 ctxt: *mut _xmlXPathContext,
5019 name: *const xmlChar,
5020 ns_uri: *const xmlChar,
5021) -> *mut _xmlXPathObject {
5022 if ctxt.is_null() || name.is_null() {
5023 return ptr::null_mut();
5024 }
5025 if let Some(f) = (*ctxt).varLookupFunc {
5026 let ret = f((*ctxt).varLookupData, name, ns_uri);
5027 if !ret.is_null() {
5028 return ret;
5029 }
5030 }
5031 let internal = (*ctxt).extra as *mut XPathContext;
5032 if internal.is_null() {
5033 return ptr::null_mut();
5034 }
5035 let internal = &*internal;
5036 let name_str = match CStr::from_ptr(name as *const c_char).to_str() {
5037 Ok(s) => s.to_string(),
5038 Err(_) => return ptr::null_mut(),
5039 };
5040 let qualified = if ns_uri.is_null() {
5041 name_str
5042 } else {
5043 match CStr::from_ptr(ns_uri as *const c_char).to_str() {
5044 Ok(s) => format!("{{{}}}{}", s, name_str),
5045 Err(_) => return ptr::null_mut(),
5046 }
5047 };
5048 match internal.variables.get(&qualified) {
5049 Some(v) => crate::abi::exports_xml2::xpath_to_object_pub(v.clone()),
5050 None => ptr::null_mut(),
5051 }
5052}
5053
5054#[no_mangle]
5060pub unsafe extern "C" fn xmlXPathNsLookup(
5061 ctxt: *mut _xmlXPathContext,
5062 prefix: *const xmlChar,
5063) -> *const xmlChar {
5064 if ctxt.is_null() || prefix.is_null() {
5065 return ptr::null();
5066 }
5067 if cstr_eq(prefix, c"xml".as_ptr() as *const xmlChar) {
5069 return XML_XML_NAMESPACE_BYTES.as_ptr() as *const xmlChar;
5070 }
5071 let namespaces = (*ctxt).namespaces;
5073 if !namespaces.is_null() {
5074 for i in 0..(*ctxt).nsNr as isize {
5075 let ns = *namespaces.add(i as usize);
5076 if !ns.is_null() && !(*ns).prefix.is_null() && cstr_eq((*ns).prefix, prefix) {
5077 return (*ns).href;
5078 }
5079 }
5080 }
5081 if !(*ctxt).nsHash.is_null() {
5084 let uri = crate::abi::exports_xml2::xmlHashLookup((*ctxt).nsHash, prefix);
5085 if !uri.is_null() {
5086 return uri as *const xmlChar;
5087 }
5088 }
5089 ptr::null()
5090}
5091
5092#[no_mangle]
5098pub unsafe extern "C" fn xmlXPathRegisteredFuncsCleanup(ctxt: *mut _xmlXPathContext) {
5099 if ctxt.is_null() {
5100 return;
5101 }
5102 let internal = (*ctxt).extra as *mut XPathContext;
5103 if !internal.is_null() {
5104 (*internal).functions.clear();
5105 }
5106 crate::abi::exports_xml2::xpath_cfunc_cleanup((*ctxt).extra);
5107}
5108
5109#[no_mangle]
5115pub unsafe extern "C" fn xmlXPathRegisteredVariablesCleanup(ctxt: *mut _xmlXPathContext) {
5116 if ctxt.is_null() {
5117 return;
5118 }
5119 let internal = (*ctxt).extra as *mut XPathContext;
5120 if !internal.is_null() {
5121 (*internal).variables.clear();
5122 }
5123}
5124
5125#[no_mangle]
5131pub unsafe extern "C" fn xmlXPathRegisteredNsCleanup(ctxt: *mut _xmlXPathContext) {
5132 if ctxt.is_null() {
5133 return;
5134 }
5135 let internal = (*ctxt).extra as *mut XPathContext;
5136 if !internal.is_null() {
5137 (*internal).namespaces.clear();
5138 }
5139 if !(*ctxt).nsHash.is_null() {
5140 crate::abi::exports_xml2::xmlHashFree(
5143 (*ctxt).nsHash,
5144 Some(crate::abi::exports_xml2::free_ns_uri_payload),
5145 );
5146 (*ctxt).nsHash = ptr::null_mut();
5147 }
5148}
5149
5150#[no_mangle]
5156pub unsafe extern "C" fn xmlXPathSetErrorHandler(
5157 ctxt: *mut _xmlXPathContext,
5158 handler: Option<crate::abi::callbacks::xmlStructuredErrorFunc>,
5159 data: *mut c_void,
5160) {
5161 if ctxt.is_null() {
5162 return;
5163 }
5164 (*ctxt).error = handler;
5165 (*ctxt).userData = data;
5166}
5167
5168extern "C" {
5169 fn fwrite(ptr: *const c_void, size: usize, nmemb: usize, stream: *mut c_void) -> usize;
5170}
5171
5172unsafe fn dump_write(output: *mut c_void, s: &str) {
5173 unsafe {
5174 fwrite(s.as_ptr() as *const c_void, 1, s.len(), output);
5175 }
5176}
5177
5178#[no_mangle]
5184pub unsafe extern "C" fn xmlXPathDebugDumpObject(
5185 output: *mut c_void,
5186 cur: *mut _xmlXPathObject,
5187 depth: c_int,
5188) {
5189 if output.is_null() {
5190 return;
5191 }
5192 let mut s = String::new();
5193 for _ in 0..depth.clamp(0, 25) {
5194 s.push_str(" ");
5195 }
5196 if cur.is_null() {
5197 s.push_str("Object is empty (NULL)\n");
5198 dump_write(output, &s);
5199 return;
5200 }
5201 unsafe {
5202 match (*cur).type_ {
5203 t if t == xmlXPathObjectType::XPATH_BOOLEAN as c_int => {
5204 s.push_str("Object is a Boolean : ");
5205 s.push_str(if (*cur).boolval != 0 {
5206 "true\n"
5207 } else {
5208 "false\n"
5209 });
5210 }
5211 t if t == xmlXPathObjectType::XPATH_NUMBER as c_int => {
5212 let f = (*cur).floatval;
5213 if f.is_nan() {
5214 s.push_str("Object is a number : NaN\n");
5215 } else if f == f64::INFINITY {
5216 s.push_str("Object is a number : Infinity\n");
5217 } else if f == f64::NEG_INFINITY {
5218 s.push_str("Object is a number : -Infinity\n");
5219 } else if f == 0.0 {
5220 s.push_str("Object is a number : 0\n");
5221 } else {
5222 s.push_str("Object is a number : ");
5223 s.push_str(&f.to_string());
5224 s.push('\n');
5225 }
5226 }
5227 t if t == xmlXPathObjectType::XPATH_STRING as c_int => {
5228 s.push_str("Object is a string : ");
5229 if (*cur).stringval.is_null() {
5230 s.push_str("(null)");
5231 } else {
5232 let sv = CStr::from_ptr((*cur).stringval as *const c_char).to_string_lossy();
5233 s.push_str(&sv);
5234 }
5235 s.push('\n');
5236 }
5237 t if t == xmlXPathObjectType::XPATH_NODESET as c_int => {
5238 s.push_str("Object is a Node Set :\n");
5239 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
5240 if !ns.is_null() {
5241 for _ in 0..=depth.min(24) {
5242 s.push_str(" ");
5243 }
5244 s.push_str(&format!("Object contains {} nodes\n", (*ns).nodeNr));
5245 }
5246 }
5247 t if t == xmlXPathObjectType::XPATH_XSLT_TREE as c_int => {
5248 s.push_str("Object is an XSLT value tree :\n");
5249 }
5250 t if t == xmlXPathObjectType::XPATH_USERS as c_int => {
5251 s.push_str("Object is user defined\n");
5252 }
5253 _ => {
5254 s.push_str("Object is uninitialized\n");
5255 }
5256 }
5257 }
5258 dump_write(output, &s);
5259}
5260
5261#[no_mangle]
5271pub unsafe extern "C" fn xmlXPathDebugDumpCompExpr(
5272 output: *mut c_void,
5273 comp: *mut c_void,
5274 depth: c_int,
5275) {
5276 if output.is_null() || comp.is_null() {
5277 return;
5278 }
5279 let registry = crate::abi::exports_xml2::xpath_compiled_registry();
5280 let map = registry.lock();
5281 if let Some(compiled) = map.get(&(comp as u64)) {
5282 let mut s = String::new();
5283 for _ in 0..depth.clamp(0, 25) {
5284 s.push_str(" ");
5285 }
5286 s.push_str("Compiled Expression : ");
5287 s.push_str(&compiled.original);
5288 s.push('\n');
5289 dump_write(output, &s);
5290 }
5291}
5292
5293#[allow(unused)]
5294const fn _unused_xpath_batch(_: *mut _xmlAttr) {}