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]
293pub unsafe extern "C" fn xmlXPathFreeNodeSetList(obj: *mut _xmlXPathObject) {
294 if obj.is_null() {
295 return;
296 }
297 let typ = (*obj).type_;
298 if typ == xmlXPathObjectType::XPATH_NODESET as c_int
299 || typ == xmlXPathObjectType::XPATH_XSLT_TREE as c_int
300 {
301 let ns = (*obj).nodesetval as *mut _xmlNodeSet;
302 if !ns.is_null() {
303 if !(*ns).nodeTab.is_null() {
304 xmlFreeImpl((*ns).nodeTab as *mut c_void);
305 }
306 xmlFreeImpl(ns as *mut c_void);
307 }
308 }
309 xmlFreeImpl(obj as *mut c_void);
310}
311
312#[no_mangle]
323pub unsafe extern "C" fn xmlXPathConvertBoolean(val: *mut _xmlXPathObject) -> *mut _xmlXPathObject {
324 if val.is_null() {
325 return ptr::null_mut();
326 }
327 let typ = (*val).type_;
328 if typ == xmlXPathObjectType::XPATH_BOOLEAN as c_int {
329 return val;
330 }
331 let b = crate::abi::exports_xml2::object_to_xpathvalue_pub(val).as_boolean();
332 crate::abi::exports_xml2::xmlXPathFreeObject(val);
333 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
334 if obj.is_null() {
335 return ptr::null_mut();
336 }
337 (*obj).type_ = xmlXPathObjectType::XPATH_BOOLEAN as c_int;
338 (*obj).boolval = if b { 1 } else { 0 };
339 obj
340}
341
342#[no_mangle]
348pub unsafe extern "C" fn xmlXPathConvertNumber(val: *mut _xmlXPathObject) -> *mut _xmlXPathObject {
349 if val.is_null() {
350 return ptr::null_mut();
351 }
352 let typ = (*val).type_;
353 if typ == xmlXPathObjectType::XPATH_NUMBER as c_int {
354 return val;
355 }
356 let n = crate::abi::exports_xml2::object_to_xpathvalue_pub(val).as_number();
357 crate::abi::exports_xml2::xmlXPathFreeObject(val);
358 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
359 if obj.is_null() {
360 return ptr::null_mut();
361 }
362 (*obj).type_ = xmlXPathObjectType::XPATH_NUMBER as c_int;
363 (*obj).floatval = n;
364 obj
365}
366
367#[no_mangle]
373pub unsafe extern "C" fn xmlXPathConvertString(val: *mut _xmlXPathObject) -> *mut _xmlXPathObject {
374 if val.is_null() {
375 return unsafe { xmlXPathNewString(ptr::null()) };
376 }
377 let typ = (*val).type_;
378 if typ == xmlXPathObjectType::XPATH_STRING as c_int {
379 return val;
380 }
381 let s = crate::abi::exports_xml2::object_to_xpathvalue_pub(val).as_string();
382 crate::abi::exports_xml2::xmlXPathFreeObject(val);
383 let buf = dup_rust_string(&s);
384 unsafe { xmlXPathWrapString(buf) }
385}
386
387#[no_mangle]
397pub unsafe extern "C" fn xmlXPathCastToBoolean(val: *mut _xmlXPathObject) -> c_int {
398 if val.is_null() {
399 return 0;
400 }
401 crate::abi::exports_xml2::object_to_xpathvalue_pub(val).as_boolean() as c_int
402}
403
404#[no_mangle]
410pub unsafe extern "C" fn xmlXPathCastToNumber(val: *mut _xmlXPathObject) -> c_double {
411 if val.is_null() {
412 return f64::NAN;
413 }
414 crate::abi::exports_xml2::object_to_xpathvalue_pub(val).as_number()
415}
416
417#[no_mangle]
429pub const unsafe extern "C" fn xmlXPathCastBooleanToNumber(val: c_int) -> c_double {
430 if val != 0 {
431 1.0
432 } else {
433 0.0
434 }
435}
436
437#[no_mangle]
449pub unsafe extern "C" fn xmlXPathCastBooleanToString(val: c_int) -> *mut xmlChar {
450 if val != 0 {
451 xml_strdup(c"true".as_ptr() as *const xmlChar)
452 } else {
453 xml_strdup(c"false".as_ptr() as *const xmlChar)
454 }
455}
456
457#[no_mangle]
463pub unsafe extern "C" fn xmlXPathCastNodeSetToBoolean(ns: *mut _xmlNodeSet) -> c_int {
464 if ns.is_null() {
465 return 0;
466 }
467 (unsafe { (*ns).nodeNr > 0 }) as c_int
468}
469
470#[no_mangle]
476pub unsafe extern "C" fn xmlXPathCastNodeSetToNumber(ns: *mut _xmlNodeSet) -> c_double {
477 unsafe {
478 let val = crate::abi::exports_xml2::object_to_xpathvalue_pub(xmlXPathWrapNodeSet(ns));
479 let n = val.as_number();
480 n
482 }
483}
484
485#[no_mangle]
491pub unsafe extern "C" fn xmlXPathCastNodeSetToString(ns: *mut _xmlNodeSet) -> *mut xmlChar {
492 let val = crate::xml::xpath::types::XPathValue::NodeSet(unsafe { node_set_to_internal(ns) });
493 let s = val.as_string();
494 dup_rust_string(&s)
495}
496
497unsafe fn node_set_to_internal(ns: *mut _xmlNodeSet) -> NodeSet {
499 let mut out = NodeSet::new();
500 if ns.is_null() {
501 return out;
502 }
503 let nr = unsafe { (*ns).nodeNr };
504 let tab = unsafe { (*ns).nodeTab };
505 if !tab.is_null() {
506 for i in 0..nr as isize {
507 out.push(unsafe { *tab.add(i as usize) });
508 }
509 }
510 out
511}
512
513#[no_mangle]
519pub unsafe extern "C" fn xmlXPathCastNodeToNumber(node: *mut _xmlNode) -> c_double {
520 let s = node_string_value(node);
521 crate::xml::xpath::types::string_to_number(&s)
522}
523
524#[no_mangle]
530pub unsafe extern "C" fn xmlXPathCastNodeToString(node: *mut _xmlNode) -> *mut xmlChar {
531 let s = node_string_value(node);
532 dup_rust_string(&s)
533}
534
535#[no_mangle]
547pub unsafe extern "C" fn xmlXPathCastNumberToBoolean(val: c_double) -> c_int {
548 (val != 0.0 && !val.is_nan()) as c_int
549}
550
551#[no_mangle]
563pub unsafe extern "C" fn xmlXPathCastNumberToString(val: c_double) -> *mut xmlChar {
564 number_to_xmlstring(val)
565}
566
567#[no_mangle]
573pub const unsafe extern "C" fn xmlXPathCastStringToBoolean(val: *const xmlChar) -> c_int {
574 if val.is_null() || unsafe { *val } == 0 {
575 0
576 } else {
577 1
578 }
579}
580
581#[no_mangle]
593pub const unsafe extern "C" fn xmlXPathIsNaN(val: c_double) -> c_int {
594 val.is_nan() as c_int
595}
596
597#[no_mangle]
609pub unsafe extern "C" fn xmlXPathIsInf(val: c_double) -> c_int {
610 if val.is_infinite() {
611 if val > 0.0 {
612 1
613 } else {
614 -1
615 }
616 } else {
617 0
618 }
619}
620
621#[no_mangle]
627pub unsafe extern "C" fn xmlXPathStringEvalNumber(str_: *const xmlChar) -> c_double {
628 if str_.is_null() {
629 return f64::NAN;
630 }
631 let s = unsafe { crate::xml::string::xmlstr_to_string(str_) };
632 crate::xml::xpath::types::string_to_number(&s)
633}
634
635#[no_mangle]
642pub unsafe extern "C" fn xmlXPathIsNodeType(name: *const xmlChar) -> c_int {
643 if name.is_null() {
644 return 0;
645 }
646 let s = unsafe { crate::xml::string::xmlstr_to_string(name) };
647 match s.as_str() {
648 "comment" | "text" | "processing-instruction" | "node" => 1,
649 _ => 0,
650 }
651}
652
653#[no_mangle]
665pub const unsafe extern "C" fn xmlXPathInit() {}
666
667#[no_mangle]
674pub unsafe extern "C" fn xmlXPathErr(
675 ctxt: *mut crate::xml::xpath::parser_context::XmlXPathParserContext,
676 error: c_int,
677) {
678 if !ctxt.is_null() {
679 unsafe { (*ctxt).error = error };
680 }
681}
682
683#[no_mangle]
690pub unsafe extern "C" fn xmlXPatherror(
691 ctxt: *mut crate::xml::xpath::parser_context::XmlXPathParserContext,
692 _file: *const c_char,
693 _line: c_int,
694 _no: c_int,
695) {
696 if !ctxt.is_null() {
697 unsafe { (*ctxt).error = _no };
698 }
699}
700
701#[allow(unused)]
702const fn _unused_doc(_d: *mut _xmlDoc) {}
703
704unsafe fn node_set_grow(ns: *mut _xmlNodeSet) {
710 if ns.is_null() {
711 return;
712 }
713 unsafe {
714 let nr = (*ns).nodeNr;
715 let max = (*ns).nodeMax;
716 if nr < max {
717 return;
718 }
719 let new_max = if max <= 0 { 8 } else { max * 2 };
720 let new_tab = crate::abi::allocator::xmlReallocImpl(
721 (*ns).nodeTab as *mut c_void,
722 (new_max as usize) * size_of::<*mut _xmlNode>(),
723 ) as *mut *mut _xmlNode;
724 if !new_tab.is_null() {
725 (*ns).nodeTab = new_tab;
726 (*ns).nodeMax = new_max;
727 }
728 }
729}
730
731#[no_mangle]
737pub unsafe extern "C" fn xmlXPathNodeSetContains(
738 cur: *mut _xmlNodeSet,
739 val: *mut _xmlNode,
740) -> c_int {
741 if cur.is_null() || val.is_null() {
742 return 0;
743 }
744 unsafe {
745 let nr = (*cur).nodeNr;
746 let tab = (*cur).nodeTab;
747 if !tab.is_null() {
748 for i in 0..nr as isize {
749 if *tab.add(i as usize) == val {
750 return 1;
751 }
752 }
753 }
754 }
755 0
756}
757
758#[no_mangle]
765pub unsafe extern "C" fn xmlXPathNodeSetAdd(cur: *mut _xmlNodeSet, val: *mut _xmlNode) -> c_int {
766 if cur.is_null() || val.is_null() {
767 return -1;
768 }
769 if xmlXPathNodeSetContains(cur, val) != 0 {
770 return 0;
771 }
772 unsafe {
773 node_set_grow(cur);
774 if (*cur).nodeNr >= (*cur).nodeMax {
775 return -1;
776 }
777 let idx = (*cur).nodeNr as usize;
778 ptr::write((*cur).nodeTab.add(idx), val);
779 (*cur).nodeNr += 1;
780 }
781 0
782}
783
784#[no_mangle]
791pub unsafe extern "C" fn xmlXPathNodeSetAddUnique(
792 cur: *mut _xmlNodeSet,
793 val: *mut _xmlNode,
794) -> c_int {
795 if cur.is_null() || val.is_null() {
796 return -1;
797 }
798 unsafe {
799 node_set_grow(cur);
800 if (*cur).nodeNr >= (*cur).nodeMax {
801 return -1;
802 }
803 let idx = (*cur).nodeNr as usize;
804 ptr::write((*cur).nodeTab.add(idx), val);
805 (*cur).nodeNr += 1;
806 }
807 0
808}
809
810#[no_mangle]
817pub unsafe extern "C" fn xmlXPathNodeSetAddNs(
818 cur: *mut _xmlNodeSet,
819 _node: *mut _xmlNode,
820 ns: *mut _xmlNs,
821) -> c_int {
822 if cur.is_null() || ns.is_null() {
823 return -1;
824 }
825 let ns_node = ns as *mut _xmlNode;
828 if xmlXPathNodeSetContains(cur, ns_node) != 0 {
829 return 0;
830 }
831 xmlXPathNodeSetAddUnique(cur, ns_node)
832}
833
834#[no_mangle]
841pub unsafe extern "C" fn xmlXPathNodeSetDel(cur: *mut _xmlNodeSet, val: *mut _xmlNode) {
842 if cur.is_null() || val.is_null() {
843 return;
844 }
845 unsafe {
846 let nr = (*cur).nodeNr;
847 let tab = (*cur).nodeTab;
848 let mut found = -1;
849 if !tab.is_null() {
850 for i in 0..nr as isize {
851 if *tab.add(i as usize) == val {
852 found = i as c_int;
853 break;
854 }
855 }
856 }
857 if found >= 0 {
858 let fi = found as usize;
859 for i in fi..(nr as usize - 1) {
860 ptr::write(tab.add(i), *tab.add(i + 1));
861 }
862 (*cur).nodeNr -= 1;
863 }
864 }
865}
866
867#[no_mangle]
874pub unsafe extern "C" fn xmlXPathNodeSetRemove(cur: *mut _xmlNodeSet, val: c_int) {
875 if cur.is_null() || val < 0 {
876 return;
877 }
878 unsafe {
879 let nr = (*cur).nodeNr;
880 if val >= nr {
881 return;
882 }
883 let tab = (*cur).nodeTab;
884 let vi = val as usize;
885 for i in vi..(nr as usize - 1) {
886 ptr::write(tab.add(i), *tab.add(i + 1));
887 }
888 (*cur).nodeNr -= 1;
889 }
890}
891
892#[no_mangle]
899pub unsafe extern "C" fn xmlXPathNodeSetSort(set: *mut _xmlNodeSet) {
900 if set.is_null() {
901 return;
902 }
903 unsafe {
904 let nr = (*set).nodeNr;
905 let tab = (*set).nodeTab;
906 if nr <= 1 || tab.is_null() {
907 return;
908 }
909 for i in 1..nr as usize {
912 let key = *tab.add(i);
913 let mut j = i;
914 while j > 0 {
915 let prev = *tab.add(j - 1);
916 if crate::xml::xpath::types::compare_document_order(prev, key)
917 == core::cmp::Ordering::Greater
918 {
919 ptr::write(tab.add(j), prev);
920 j -= 1;
921 } else {
922 break;
923 }
924 }
925 ptr::write(tab.add(j), key);
926 }
927 let mut w = 0usize;
929 for r in 0..nr as usize {
930 if w == 0 || *tab.add(w - 1) != *tab.add(r) {
931 ptr::write(tab.add(w), *tab.add(r));
932 w += 1;
933 }
934 }
935 (*set).nodeNr = w as c_int;
936 }
937}
938
939#[no_mangle]
946pub unsafe extern "C" fn xmlXPathNodeSetMerge(
947 val1: *mut _xmlNodeSet,
948 val2: *mut _xmlNodeSet,
949) -> *mut _xmlNodeSet {
950 if val1.is_null() && val2.is_null() {
951 return ptr::null_mut();
952 }
953 if val1.is_null() {
954 let obj = xmlXPathNewNodeSetList(val2);
956 let ns = unsafe { (*obj).nodesetval as *mut _xmlNodeSet };
957 if obj.is_null() {
958 return ptr::null_mut();
959 }
960 return ns;
961 }
962 if val2.is_null() {
963 return val1;
964 }
965 unsafe {
966 let nr2 = (*val2).nodeNr;
967 let tab2 = (*val2).nodeTab;
968 if !tab2.is_null() {
969 for i in 0..nr2 as isize {
970 let n = *tab2.add(i as usize);
971 if xmlXPathNodeSetContains(val1, n) == 0 {
972 xmlXPathNodeSetAddUnique(val1, n);
973 }
974 }
975 }
976 }
977 val1
978}
979
980#[no_mangle]
987pub unsafe extern "C" fn xmlXPathDifference(
988 nodes1: *mut _xmlNodeSet,
989 nodes2: *mut _xmlNodeSet,
990) -> *mut _xmlNodeSet {
991 if nodes1.is_null() {
992 return ptr::null_mut();
993 }
994 let mut a = unsafe { node_set_to_internal(nodes1) };
995 a.sort();
996 let b = unsafe { node_set_to_internal(nodes2) };
997 let mut out = NodeSet::new();
998 for n in a.iter() {
999 if !b.contains(n) {
1000 out.push(n);
1001 }
1002 }
1003 out.sort();
1004 out.to_raw()
1005}
1006
1007#[no_mangle]
1013pub unsafe extern "C" fn xmlXPathIntersection(
1014 nodes1: *mut _xmlNodeSet,
1015 nodes2: *mut _xmlNodeSet,
1016) -> *mut _xmlNodeSet {
1017 let a = unsafe { node_set_to_internal(nodes1) };
1018 let b = unsafe { node_set_to_internal(nodes2) };
1019 let mut out = NodeSet::new();
1020 for n in a.iter() {
1021 if b.contains(n) {
1022 out.push(n);
1023 }
1024 }
1025 out.sort();
1026 out.to_raw()
1027}
1028
1029#[no_mangle]
1035pub unsafe extern "C" fn xmlXPathDistinct(nodes: *mut _xmlNodeSet) -> *mut _xmlNodeSet {
1036 if nodes.is_null() {
1037 return ptr::null_mut();
1038 }
1039 unsafe {
1040 xmlXPathNodeSetSort(nodes);
1041 nodes
1042 }
1043}
1044
1045#[no_mangle]
1051pub unsafe extern "C" fn xmlXPathDistinctSorted(nodes: *mut _xmlNodeSet) -> *mut _xmlNodeSet {
1052 if nodes.is_null() {
1053 return ptr::null_mut();
1054 }
1055 unsafe {
1056 let nr = (*nodes).nodeNr;
1057 let tab = (*nodes).nodeTab;
1058 let mut w = 0usize;
1059 if !tab.is_null() {
1060 for r in 0..nr as usize {
1061 if w == 0 || *tab.add(w - 1) != *tab.add(r) {
1062 ptr::write(tab.add(w), *tab.add(r));
1063 w += 1;
1064 }
1065 }
1066 }
1067 (*nodes).nodeNr = w as c_int;
1068 nodes
1069 }
1070}
1071
1072#[no_mangle]
1078pub unsafe extern "C" fn xmlXPathHasSameNodes(
1079 nodes1: *mut _xmlNodeSet,
1080 nodes2: *mut _xmlNodeSet,
1081) -> c_int {
1082 if nodes1.is_null() || nodes2.is_null() {
1083 return 0;
1084 }
1085 unsafe {
1086 let nr1 = (*nodes1).nodeNr;
1087 let nr2 = (*nodes2).nodeNr;
1088 if nr1 != nr2 {
1089 return 0;
1090 }
1091 let tab1 = (*nodes1).nodeTab;
1092 let tab2 = (*nodes2).nodeTab;
1093 for i in 0..nr1 as isize {
1094 let mut found = false;
1095 for j in 0..nr2 as isize {
1096 if *tab1.add(i as usize) == *tab2.add(j as usize) {
1097 found = true;
1098 break;
1099 }
1100 }
1101 if !found {
1102 return 0;
1103 }
1104 }
1105 }
1106 1
1107}
1108
1109unsafe fn leading_nodes(nodes: &NodeSet, node: *mut _xmlNode) -> NodeSet {
1111 let mut out = NodeSet::new();
1112 for n in nodes.iter() {
1113 if n == node {
1114 break;
1115 }
1116 out.push(n);
1117 }
1118 out
1119}
1120
1121unsafe fn trailing_nodes(nodes: &NodeSet, node: *mut _xmlNode) -> NodeSet {
1122 let mut out = NodeSet::new();
1123 let mut seen = false;
1124 for n in nodes.iter() {
1125 if n == node {
1126 seen = true;
1127 continue;
1128 }
1129 if seen {
1130 out.push(n);
1131 }
1132 }
1133 out
1134}
1135
1136#[no_mangle]
1142pub unsafe extern "C" fn xmlXPathLeading(
1143 nodes1: *mut _xmlNodeSet,
1144 nodes2: *mut _xmlNodeSet,
1145) -> *mut _xmlNodeSet {
1146 if nodes1.is_null() {
1147 return ptr::null_mut();
1148 }
1149 let mut a = unsafe { node_set_to_internal(nodes1) };
1150 a.sort();
1151 let b = unsafe { node_set_to_internal(nodes2) };
1152 if b.is_empty() {
1153 let raw = a.to_raw();
1154 return raw;
1155 }
1156 let first = b.first().unwrap();
1157 let out = unsafe { leading_nodes(&a, first) };
1158 out.to_raw()
1159}
1160
1161#[no_mangle]
1167pub unsafe extern "C" fn xmlXPathLeadingSorted(
1168 nodes1: *mut _xmlNodeSet,
1169 nodes2: *mut _xmlNodeSet,
1170) -> *mut _xmlNodeSet {
1171 unsafe { xmlXPathLeading(nodes1, nodes2) }
1172}
1173
1174#[no_mangle]
1180pub unsafe extern "C" fn xmlXPathTrailing(
1181 nodes1: *mut _xmlNodeSet,
1182 nodes2: *mut _xmlNodeSet,
1183) -> *mut _xmlNodeSet {
1184 if nodes1.is_null() {
1185 return ptr::null_mut();
1186 }
1187 let mut a = unsafe { node_set_to_internal(nodes1) };
1188 a.sort();
1189 let b = unsafe { node_set_to_internal(nodes2) };
1190 if b.is_empty() {
1191 return a.to_raw();
1192 }
1193 let last = b.last().unwrap();
1194 let out = unsafe { trailing_nodes(&a, last) };
1195 out.to_raw()
1196}
1197
1198#[no_mangle]
1204pub unsafe extern "C" fn xmlXPathTrailingSorted(
1205 nodes1: *mut _xmlNodeSet,
1206 nodes2: *mut _xmlNodeSet,
1207) -> *mut _xmlNodeSet {
1208 unsafe { xmlXPathTrailing(nodes1, nodes2) }
1209}
1210
1211#[no_mangle]
1217pub unsafe extern "C" fn xmlXPathNodeLeading(
1218 nodes: *mut _xmlNodeSet,
1219 node: *mut _xmlNode,
1220) -> *mut _xmlNodeSet {
1221 if nodes.is_null() {
1222 return ptr::null_mut();
1223 }
1224 let mut a = unsafe { node_set_to_internal(nodes) };
1225 a.sort();
1226 let out = unsafe { leading_nodes(&a, node) };
1227 out.to_raw()
1228}
1229
1230#[no_mangle]
1236pub unsafe extern "C" fn xmlXPathNodeLeadingSorted(
1237 nodes: *mut _xmlNodeSet,
1238 node: *mut _xmlNode,
1239) -> *mut _xmlNodeSet {
1240 unsafe { xmlXPathNodeLeading(nodes, node) }
1241}
1242
1243#[no_mangle]
1249pub unsafe extern "C" fn xmlXPathNodeTrailing(
1250 nodes: *mut _xmlNodeSet,
1251 node: *mut _xmlNode,
1252) -> *mut _xmlNodeSet {
1253 if nodes.is_null() {
1254 return ptr::null_mut();
1255 }
1256 let mut a = unsafe { node_set_to_internal(nodes) };
1257 a.sort();
1258 let out = unsafe { trailing_nodes(&a, node) };
1259 out.to_raw()
1260}
1261
1262#[no_mangle]
1268pub unsafe extern "C" fn xmlXPathNodeTrailingSorted(
1269 nodes: *mut _xmlNodeSet,
1270 node: *mut _xmlNode,
1271) -> *mut _xmlNodeSet {
1272 unsafe { xmlXPathNodeTrailing(nodes, node) }
1273}
1274
1275#[no_mangle]
1288pub unsafe extern "C" fn xmlXPathNodeSetFreeNs(ns: *mut _xmlNs) {
1289 unsafe {
1290 if ns.is_null() {
1291 return;
1292 }
1293 if (*ns).type_ != crate::abi::types::xmlElementType::XML_NAMESPACE_DECL as c_int {
1294 return;
1295 }
1296 if !(*ns).next.is_null()
1298 && (*(*ns).next).type_ != crate::abi::types::xmlElementType::XML_NAMESPACE_DECL as c_int
1299 {
1300 if !(*ns).href.is_null() {
1301 libc::free((*ns).href as *mut libc::c_void);
1302 }
1303 if !(*ns).prefix.is_null() {
1304 libc::free((*ns).prefix as *mut libc::c_void);
1305 }
1306 libc::free(ns as *mut libc::c_void);
1307 }
1308 }
1309}
1310
1311#[no_mangle]
1326pub unsafe extern "C" fn xmlXPathOrderDocElems(doc: *mut _xmlDoc) -> c_long {
1327 if doc.is_null() {
1328 return -1;
1329 }
1330 let mut count: c_long = 0;
1331 unsafe {
1332 let mut cur = (*doc).children;
1333 while !cur.is_null() {
1334 if (*cur).type_ == crate::abi::types::xmlElementType::XML_ELEMENT_NODE as c_int {
1335 count += 1;
1336 (*cur).content = (-count) as *mut xmlChar;
1340 if !(*cur).children.is_null() {
1341 cur = (*cur).children;
1342 continue;
1343 }
1344 }
1345 if !(*cur).next.is_null() {
1346 cur = (*cur).next;
1347 continue;
1348 }
1349 loop {
1350 cur = (*cur).parent;
1351 if cur.is_null() {
1352 break;
1353 }
1354 if cur == doc as *mut _xmlNode {
1355 cur = ptr::null_mut();
1356 break;
1357 }
1358 if !(*cur).next.is_null() {
1359 cur = (*cur).next;
1360 break;
1361 }
1362 }
1363 }
1364 }
1365 count
1366}
1367use std::collections::HashMap;
1368use std::ffi::{CStr, CString};
1369
1370use crate::abi::structs::_xmlAttr;
1371use crate::xml::validation::{get_id, is_xml_name_char, is_xml_name_start};
1372use crate::xml::xpath::context::XPathContext;
1373use crate::xml::xpath::parser_context::{
1374 cast_top_to_number, compare_values_impl, equal_values_impl, free_parser_context, new_bool,
1375 new_number, new_parser_context, pc_set_error, pop_boolean, pop_external, pop_node_set,
1376 pop_number, pop_string, value_pop, value_push, XmlXPathParserContext,
1377};
1378
1379const unsafe fn pc_from(p: *mut c_void) -> *mut XmlXPathParserContext {
1383 p as *mut XmlXPathParserContext
1384}
1385
1386unsafe fn cstr_eq(a: *const xmlChar, b: *const xmlChar) -> bool {
1388 if a.is_null() || b.is_null() {
1389 return a == b;
1390 }
1391 let mut i = 0usize;
1392 loop {
1393 let ca = unsafe { *a.add(i) };
1394 let cb = unsafe { *b.add(i) };
1395 if ca != cb {
1396 return false;
1397 }
1398 if ca == 0 {
1399 return true;
1400 }
1401 i += 1;
1402 }
1403}
1404
1405const unsafe fn is_blank_ch(c: xmlChar) -> bool {
1407 c == b' ' || c == b'\t' || c == b'\n' || c == b'\r'
1408}
1409
1410unsafe fn cast_top_to_string(pc: *mut XmlXPathParserContext) {
1416 unsafe {
1417 let val = (*pc).value;
1418 if val.is_null() {
1419 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
1420 return;
1421 }
1422 if (*val).type_ != xmlXPathObjectType::XPATH_STRING as c_int {
1423 let v = crate::abi::exports_xml2::object_to_xpathvalue_pub(val);
1424 let s = v.as_string();
1425 if !(*val).stringval.is_null() {
1426 xmlFreeImpl((*val).stringval as *mut c_void);
1427 }
1428 (*val).stringval = dup_rust_string(&s);
1429 (*val).type_ = xmlXPathObjectType::XPATH_STRING as c_int;
1430 }
1431 }
1432}
1433
1434unsafe fn cast_top_to_boolean(pc: *mut XmlXPathParserContext) {
1440 unsafe {
1441 let val = (*pc).value;
1442 if val.is_null() {
1443 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
1444 return;
1445 }
1446 if (*val).type_ != xmlXPathObjectType::XPATH_BOOLEAN as c_int {
1447 let v = crate::abi::exports_xml2::object_to_xpathvalue_pub(val);
1448 (*val).boolval = v.as_boolean() as c_int;
1449 (*val).type_ = xmlXPathObjectType::XPATH_BOOLEAN as c_int;
1450 }
1451 }
1452}
1453
1454unsafe fn check_arity(pc: *mut XmlXPathParserContext, n: c_int) -> bool {
1457 if pc.is_null() || (*pc).value_nr < n {
1458 pc_set_error(pc, crate::abi::types::XPATH_INVALID_ARITY as c_int);
1459 return false;
1460 }
1461 true
1462}
1463
1464const unsafe fn scan_c_name(cur: *const xmlChar, nc: bool) -> usize {
1468 if cur.is_null() {
1469 return 0;
1470 }
1471 let mut i = 0usize;
1472 let mut first = true;
1473 loop {
1474 let b = unsafe { *cur.add(i) };
1475 if b == 0 {
1476 break;
1477 }
1478 if nc && b == b':' {
1479 break;
1480 }
1481 let (ch, adv): (char, usize) = if b < 0x80 {
1482 (b as char, 1)
1483 } else if b >= 0xC0 && b <= 0xDF {
1484 (
1485 unsafe {
1486 char::from_u32_unchecked(
1487 ((b as u32 & 0x1F) << 6) | (*cur.add(i + 1) as u32 & 0x3F),
1488 )
1489 },
1490 2,
1491 )
1492 } else if b >= 0xE0 && b <= 0xEF {
1493 (
1494 unsafe {
1495 char::from_u32_unchecked(
1496 ((b as u32 & 0x0F) << 12)
1497 | ((*cur.add(i + 1) as u32 & 0x3F) << 6)
1498 | (*cur.add(i + 2) as u32 & 0x3F),
1499 )
1500 },
1501 3,
1502 )
1503 } else if b >= 0xF0 && b <= 0xF7 {
1504 (
1505 unsafe {
1506 char::from_u32_unchecked(
1507 ((b as u32 & 0x07) << 18)
1508 | ((*cur.add(i + 1) as u32 & 0x3F) << 12)
1509 | ((*cur.add(i + 2) as u32 & 0x3F) << 6)
1510 | (*cur.add(i + 3) as u32 & 0x3F),
1511 )
1512 },
1513 4,
1514 )
1515 } else {
1516 break;
1517 };
1518 let ok = if first {
1519 is_xml_name_start(ch)
1520 } else {
1521 is_xml_name_char(ch)
1522 };
1523 if !ok {
1524 break;
1525 }
1526 first = false;
1527 i += adv;
1528 }
1529 i
1530}
1531
1532unsafe fn cstr_find(hay: *const xmlChar, needle: *const xmlChar) -> *const xmlChar {
1534 if hay.is_null() || needle.is_null() {
1535 return ptr::null();
1536 }
1537 if unsafe { *needle } == 0 {
1538 return hay;
1539 }
1540 let hlen = unsafe { crate::xml::string::xml_strlen(hay) };
1541 let nlen = unsafe { crate::xml::string::xml_strlen(needle) };
1542 if nlen > hlen {
1543 return ptr::null();
1544 }
1545 let hay_b = unsafe { core::slice::from_raw_parts(hay, hlen) };
1546 let needle_b = unsafe { core::slice::from_raw_parts(needle, nlen) };
1547 for off in 0..=hlen - nlen {
1548 if &hay_b[off..off + nlen] == needle_b {
1549 return unsafe { hay.add(off) };
1550 }
1551 }
1552 ptr::null()
1553}
1554
1555const XML_XML_NAMESPACE_BYTES: &[u8] = b"http://www.w3.org/XML/1998/namespace\0";
1557
1558struct XmlXPathXmlNs(_xmlNs);
1562unsafe impl Sync for XmlXPathXmlNs {}
1563static XML_XPATH_XML_NS: XmlXPathXmlNs = XmlXPathXmlNs(crate::abi::structs::_xmlNs {
1564 next: ptr::null_mut(),
1565 type_: crate::abi::types::xmlElementType::XML_NAMESPACE_DECL as c_int,
1566 href: XML_XML_NAMESPACE_BYTES.as_ptr() as *const xmlChar,
1567 prefix: c"xml".as_ptr() as *const xmlChar,
1568 _private: ptr::null_mut(),
1569 context: ptr::null_mut(),
1570});
1571
1572#[no_mangle]
1588pub unsafe extern "C" fn xmlXPathValuePush(
1589 ctxt: *mut c_void,
1590 value: *mut _xmlXPathObject,
1591) -> c_int {
1592 if ctxt.is_null() || value.is_null() {
1593 return -1;
1594 }
1595 let pc = pc_from(ctxt);
1596 let idx = unsafe { (*pc).value_nr };
1599 value_push(pc, value);
1600 idx
1601}
1602
1603#[no_mangle]
1609pub unsafe extern "C" fn xmlXPathValuePop(ctxt: *mut c_void) -> *mut _xmlXPathObject {
1610 value_pop(pc_from(ctxt))
1611}
1612
1613#[no_mangle]
1619pub unsafe extern "C" fn xmlXPathPopBoolean(ctxt: *mut c_void) -> c_int {
1620 pop_boolean(pc_from(ctxt))
1621}
1622
1623#[no_mangle]
1629pub unsafe extern "C" fn xmlXPathPopExternal(ctxt: *mut c_void) -> *mut c_void {
1630 pop_external(pc_from(ctxt))
1631}
1632
1633#[no_mangle]
1639pub unsafe extern "C" fn xmlXPathPopNodeSet(ctxt: *mut c_void) -> *mut _xmlNodeSet {
1640 pop_node_set(pc_from(ctxt))
1641}
1642
1643#[no_mangle]
1649pub unsafe extern "C" fn xmlXPathPopNumber(ctxt: *mut c_void) -> c_double {
1650 pop_number(pc_from(ctxt))
1651}
1652
1653#[no_mangle]
1659pub unsafe extern "C" fn xmlXPathPopString(ctxt: *mut c_void) -> *mut xmlChar {
1660 pop_string(pc_from(ctxt))
1661}
1662
1663unsafe fn binary_inplace(ctxt: *mut c_void, op: impl Fn(&mut f64, f64)) {
1668 let pc = pc_from(ctxt);
1669 if pc.is_null() {
1670 return;
1671 }
1672 let arg = value_pop(pc);
1673 if arg.is_null() {
1674 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
1675 return;
1676 }
1677 let val = crate::abi::exports_xml2::object_to_xpathvalue_pub(arg).as_number();
1678 crate::abi::exports_xml2::xmlXPathFreeObject(arg);
1679 if unsafe { (*pc).value.is_null() } {
1680 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
1681 return;
1682 }
1683 cast_top_to_number(pc);
1684 if (*pc).error != 0 {
1685 return;
1686 }
1687 unsafe {
1691 let float_ref: &mut f64 = &mut (*(*pc).value).floatval;
1692 op(float_ref, val);
1693 }
1694}
1695
1696#[no_mangle]
1713pub unsafe extern "C" fn xmlXPathAddValues(ctxt: *mut c_void) {
1714 binary_inplace(ctxt, |x, v| *x += v);
1715}
1716
1717#[no_mangle]
1734pub unsafe extern "C" fn xmlXPathSubValues(ctxt: *mut c_void) {
1735 binary_inplace(ctxt, |x, v| *x -= v);
1736}
1737
1738#[no_mangle]
1755pub unsafe extern "C" fn xmlXPathMultValues(ctxt: *mut c_void) {
1756 binary_inplace(ctxt, |x, v| *x *= v);
1757}
1758
1759#[no_mangle]
1776pub unsafe extern "C" fn xmlXPathDivValues(ctxt: *mut c_void) {
1777 binary_inplace(ctxt, |x, v| *x /= v);
1778}
1779
1780#[no_mangle]
1797pub unsafe extern "C" fn xmlXPathModValues(ctxt: *mut c_void) {
1798 binary_inplace(ctxt, |x, v| *x %= v);
1799}
1800
1801#[no_mangle]
1818pub unsafe extern "C" fn xmlXPathValueFlipSign(ctxt: *mut c_void) {
1819 let pc = pc_from(ctxt);
1820 if pc.is_null() {
1821 return;
1822 }
1823 cast_top_to_number(pc);
1824 if (*pc).error != 0 {
1825 return;
1826 }
1827 unsafe { (*(*pc).value).floatval = -(*(*pc).value).floatval };
1828}
1829
1830#[no_mangle]
1848pub unsafe extern "C" fn xmlXPathEqualValues(ctxt: *mut c_void) -> c_int {
1849 equal_values_impl(pc_from(ctxt), false)
1850}
1851
1852#[no_mangle]
1869pub unsafe extern "C" fn xmlXPathNotEqualValues(ctxt: *mut c_void) -> c_int {
1870 equal_values_impl(pc_from(ctxt), true)
1871}
1872
1873#[no_mangle]
1894pub unsafe extern "C" fn xmlXPathCompareValues(
1895 ctxt: *mut c_void,
1896 inf: c_int,
1897 strict: c_int,
1898) -> c_int {
1899 compare_values_impl(pc_from(ctxt), inf != 0, strict != 0)
1900}
1901
1902#[no_mangle]
1913pub unsafe extern "C" fn xmlXPathNewParserContext(
1914 str_: *const xmlChar,
1915 ctxt: *mut _xmlXPathContext,
1916) -> *mut c_void {
1917 new_parser_context(str_, ctxt) as *mut c_void
1918}
1919
1920#[no_mangle]
1926pub unsafe extern "C" fn xmlXPathFreeParserContext(ctxt: *mut c_void) {
1927 free_parser_context(pc_from(ctxt));
1928}
1929
1930#[no_mangle]
1937pub unsafe extern "C" fn xmlXPathParseNCName(ctxt: *mut c_void) -> *mut xmlChar {
1938 let pc = pc_from(ctxt);
1939 if pc.is_null() {
1940 return ptr::null_mut();
1941 }
1942 let cur = unsafe { (*pc).cur };
1943 if cur.is_null() {
1944 return ptr::null_mut();
1945 }
1946 let len = scan_c_name(cur, true);
1947 if len == 0 {
1948 return ptr::null_mut();
1949 }
1950 let ret = crate::xml::string::xml_strndup(cur, len);
1951 unsafe { (*pc).cur = cur.add(len) };
1952 ret
1953}
1954
1955#[no_mangle]
1962pub unsafe extern "C" fn xmlXPathParseName(ctxt: *mut c_void) -> *mut xmlChar {
1963 let pc = pc_from(ctxt);
1964 if pc.is_null() {
1965 return ptr::null_mut();
1966 }
1967 let cur = unsafe { (*pc).cur };
1968 if cur.is_null() {
1969 return ptr::null_mut();
1970 }
1971 let len = scan_c_name(cur, false);
1972 if len == 0 {
1973 return ptr::null_mut();
1974 }
1975 let ret = crate::xml::string::xml_strndup(cur, len);
1976 unsafe { (*pc).cur = cur.add(len) };
1977 ret
1978}
1979
1980#[no_mangle]
1987pub unsafe extern "C" fn xmlXPathRoot(ctxt: *mut c_void) {
1988 let pc = pc_from(ctxt);
1989 if pc.is_null() {
1990 return;
1991 }
1992 let ctx = unsafe { (*pc).context };
1993 if ctx.is_null() {
1994 return;
1995 }
1996 let ns = NodeSet::singleton(unsafe { (*ctx).doc } as *mut _xmlNode);
1997 let obj = crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(ns));
1998 value_push(pc, obj);
1999}
2000
2001#[no_mangle]
2009pub unsafe extern "C" fn xmlXPathEvalExpr(ctxt: *mut c_void) {
2010 let pc = pc_from(ctxt);
2011 if pc.is_null() {
2012 return;
2013 }
2014 let ctx = unsafe { (*pc).context };
2015 if ctx.is_null() {
2016 return;
2017 }
2018 let base = unsafe { (*pc).base };
2019 if base.is_null() {
2020 return;
2021 }
2022 let expr_str = match CStr::from_ptr(base as *const c_char).to_str() {
2023 Ok(s) => s,
2024 Err(_) => {
2025 pc_set_error(pc, crate::abi::types::XPATH_EXPR_ERROR as c_int);
2026 return;
2027 }
2028 };
2029 let internal = unsafe { (*ctx).extra } as *mut XPathContext;
2030 if internal.is_null() {
2031 return;
2032 }
2033 let internal = unsafe { &mut *internal };
2034 match crate::xml::xpath::evaluate_str(expr_str, internal) {
2035 Some(val) => {
2036 let obj = crate::abi::exports_xml2::xpath_to_object_pub(val);
2037 value_push(pc, obj);
2038 }
2039 None => {
2040 pc_set_error(pc, crate::abi::types::XPATH_EXPR_ERROR as c_int);
2041 }
2042 }
2043}
2044
2045unsafe fn eval_predicate_result(ctxt: *mut _xmlXPathContext, res: *mut _xmlXPathObject) -> c_int {
2047 if ctxt.is_null() || res.is_null() {
2048 return 0;
2049 }
2050 unsafe {
2051 let t = (*res).type_;
2052 if t == xmlXPathObjectType::XPATH_BOOLEAN as c_int {
2053 (*res).boolval
2054 } else if t == xmlXPathObjectType::XPATH_NUMBER as c_int {
2055 ((*res).floatval == (*ctxt).proximityPosition as f64) as c_int
2056 } else if t == xmlXPathObjectType::XPATH_NODESET as c_int
2057 || t == xmlXPathObjectType::XPATH_XSLT_TREE as c_int
2058 {
2059 let nsp = (*res).nodesetval as *mut _xmlNodeSet;
2060 if nsp.is_null() || (*nsp).nodeNr == 0 {
2061 0
2062 } else {
2063 1
2064 }
2065 } else if t == xmlXPathObjectType::XPATH_STRING as c_int {
2066 if (*res).stringval.is_null() || *(*res).stringval == 0 {
2067 0
2068 } else {
2069 1
2070 }
2071 } else {
2072 0
2073 }
2074 }
2075}
2076
2077#[no_mangle]
2084pub unsafe extern "C" fn xmlXPathEvalPredicate(
2085 ctxt: *mut _xmlXPathContext,
2086 res: *mut _xmlXPathObject,
2087) -> c_int {
2088 eval_predicate_result(ctxt, res)
2089}
2090
2091#[no_mangle]
2097pub unsafe extern "C" fn xmlXPathEvaluatePredicateResult(
2098 ctxt: *mut c_void,
2099 res: *mut _xmlXPathObject,
2100) -> c_int {
2101 let pc = pc_from(ctxt);
2102 if pc.is_null() {
2103 return 0;
2104 }
2105 let ctx = unsafe { (*pc).context };
2106 eval_predicate_result(ctx, res)
2107}
2108
2109#[no_mangle]
2130pub unsafe extern "C" fn xmlXPathNextSelf(ctxt: *mut c_void, cur: *mut _xmlNode) -> *mut _xmlNode {
2131 let pc = pc_from(ctxt);
2132 if pc.is_null() {
2133 return ptr::null_mut();
2134 }
2135 let ctx = unsafe { (*pc).context };
2136 if ctx.is_null() {
2137 return ptr::null_mut();
2138 }
2139 if cur.is_null() {
2140 return unsafe { (*ctx).node };
2141 }
2142 ptr::null_mut()
2143}
2144
2145#[no_mangle]
2162pub unsafe extern "C" fn xmlXPathNextChild(ctxt: *mut c_void, cur: *mut _xmlNode) -> *mut _xmlNode {
2163 let pc = pc_from(ctxt);
2164 if pc.is_null() {
2165 return ptr::null_mut();
2166 }
2167 let ctx = unsafe { (*pc).context };
2168 if ctx.is_null() {
2169 return ptr::null_mut();
2170 }
2171 use crate::abi::types::xmlElementType as ET;
2172 if cur.is_null() {
2173 let node = unsafe { (*ctx).node };
2174 if node.is_null() {
2175 return ptr::null_mut();
2176 }
2177 return match unsafe { (*node).type_ } {
2178 t if t == ET::XML_ELEMENT_NODE as c_int
2179 || t == ET::XML_TEXT_NODE as c_int
2180 || t == ET::XML_CDATA_SECTION_NODE as c_int
2181 || t == ET::XML_ENTITY_REF_NODE as c_int
2182 || t == ET::XML_ENTITY_NODE as c_int
2183 || t == ET::XML_PI_NODE as c_int
2184 || t == ET::XML_COMMENT_NODE as c_int
2185 || t == ET::XML_NOTATION_NODE as c_int
2186 || t == ET::XML_DTD_NODE as c_int =>
2187 unsafe { (*node).children },
2188 t if t == ET::XML_DOCUMENT_NODE as c_int
2189 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2190 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2191 || t == ET::XML_HTML_DOCUMENT_NODE as c_int =>
2192 unsafe { (*(node as *mut _xmlDoc)).children },
2193 _ => ptr::null_mut(),
2194 };
2195 }
2196 let t = unsafe { (*cur).type_ };
2197 if t == ET::XML_DOCUMENT_NODE as c_int || t == ET::XML_HTML_DOCUMENT_NODE as c_int {
2198 return ptr::null_mut();
2199 }
2200 unsafe { (*cur).next }
2201}
2202
2203#[no_mangle]
2220pub unsafe extern "C" fn xmlXPathNextDescendant(
2221 ctxt: *mut c_void,
2222 mut cur: *mut _xmlNode,
2223) -> *mut _xmlNode {
2224 let pc = pc_from(ctxt);
2225 if pc.is_null() {
2226 return ptr::null_mut();
2227 }
2228 let ctx = unsafe { (*pc).context };
2229 if ctx.is_null() {
2230 return ptr::null_mut();
2231 }
2232 use crate::abi::types::xmlElementType as ET;
2233 if cur.is_null() {
2234 let node = unsafe { (*ctx).node };
2235 if node.is_null() {
2236 return ptr::null_mut();
2237 }
2238 let t = unsafe { (*node).type_ };
2239 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
2240 return ptr::null_mut();
2241 }
2242 if node == unsafe { (*ctx).doc } as *mut _xmlNode {
2243 return unsafe { (*(*ctx).doc).children };
2244 }
2245 return unsafe { (*node).children };
2246 }
2247 unsafe {
2248 if (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2249 return ptr::null_mut();
2250 }
2251 if !(*cur).children.is_null() && (*(*cur).children).type_ != ET::XML_ENTITY_DECL as c_int {
2252 cur = (*cur).children;
2253 if (*cur).type_ != ET::XML_DTD_NODE as c_int {
2254 return cur;
2255 }
2256 }
2257 if cur == (*ctx).node {
2258 return ptr::null_mut();
2259 }
2260 while !(*cur).next.is_null() {
2261 cur = (*cur).next;
2262 if (*cur).type_ != ET::XML_ENTITY_DECL as c_int
2263 && (*cur).type_ != ET::XML_DTD_NODE as c_int
2264 {
2265 return cur;
2266 }
2267 }
2268 loop {
2269 cur = (*cur).parent;
2270 if cur.is_null() {
2271 break;
2272 }
2273 if cur == (*ctx).node {
2274 return ptr::null_mut();
2275 }
2276 if !(*cur).next.is_null() {
2277 cur = (*cur).next;
2278 return cur;
2279 }
2280 }
2281 cur
2282 }
2283}
2284
2285#[no_mangle]
2302pub unsafe extern "C" fn xmlXPathNextDescendantOrSelf(
2303 ctxt: *mut c_void,
2304 cur: *mut _xmlNode,
2305) -> *mut _xmlNode {
2306 let pc = pc_from(ctxt);
2307 if pc.is_null() {
2308 return ptr::null_mut();
2309 }
2310 let ctx = unsafe { (*pc).context };
2311 if ctx.is_null() {
2312 return ptr::null_mut();
2313 }
2314 if cur.is_null() {
2315 return unsafe { (*ctx).node };
2316 }
2317 let node = unsafe { (*ctx).node };
2318 if node.is_null() {
2319 return ptr::null_mut();
2320 }
2321 use crate::abi::types::xmlElementType as ET;
2322 let t = unsafe { (*node).type_ };
2323 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
2324 return ptr::null_mut();
2325 }
2326 xmlXPathNextDescendant(ctxt, cur)
2327}
2328
2329#[no_mangle]
2346pub unsafe extern "C" fn xmlXPathNextParent(
2347 ctxt: *mut c_void,
2348 cur: *mut _xmlNode,
2349) -> *mut _xmlNode {
2350 let pc = pc_from(ctxt);
2351 if pc.is_null() {
2352 return ptr::null_mut();
2353 }
2354 let ctx = unsafe { (*pc).context };
2355 if ctx.is_null() {
2356 return ptr::null_mut();
2357 }
2358 if !cur.is_null() {
2359 return ptr::null_mut();
2360 }
2361 next_parent_impl(ctx)
2362}
2363
2364unsafe fn next_parent_impl(ctx: *mut _xmlXPathContext) -> *mut _xmlNode {
2366 use crate::abi::types::xmlElementType as ET;
2367 let node = unsafe { (*ctx).node };
2368 if node.is_null() {
2369 return ptr::null_mut();
2370 }
2371 match unsafe { (*node).type_ } {
2372 t if t == ET::XML_ELEMENT_NODE as c_int
2373 || t == ET::XML_TEXT_NODE as c_int
2374 || t == ET::XML_CDATA_SECTION_NODE as c_int
2375 || t == ET::XML_ENTITY_REF_NODE as c_int
2376 || t == ET::XML_ENTITY_NODE as c_int
2377 || t == ET::XML_PI_NODE as c_int
2378 || t == ET::XML_COMMENT_NODE as c_int
2379 || t == ET::XML_NOTATION_NODE as c_int
2380 || t == ET::XML_DTD_NODE as c_int
2381 || t == ET::XML_ELEMENT_DECL as c_int
2382 || t == ET::XML_ATTRIBUTE_DECL as c_int
2383 || t == ET::XML_ENTITY_DECL as c_int
2384 || t == ET::XML_XINCLUDE_START as c_int
2385 || t == ET::XML_XINCLUDE_END as c_int =>
2386 unsafe {
2387 let parent = (*node).parent;
2388 if parent.is_null() {
2389 return (*ctx).doc as *mut _xmlNode;
2390 }
2391 if (*parent).type_ == ET::XML_ELEMENT_NODE as c_int
2392 && ((*parent).name.is_null() || *(*parent).name == b' ')
2393 {
2394 return ptr::null_mut();
2395 }
2396 parent
2397 },
2398 t if t == ET::XML_ATTRIBUTE_NODE as c_int => unsafe { (*(node as *mut _xmlAttr)).parent },
2399 t if t == ET::XML_DOCUMENT_NODE as c_int
2400 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2401 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2402 || t == ET::XML_HTML_DOCUMENT_NODE as c_int =>
2403 {
2404 ptr::null_mut()
2405 }
2406 t if t == ET::XML_NAMESPACE_DECL as c_int => unsafe {
2407 let ns = node as *mut crate::abi::structs::_xmlNs;
2408 if !(*ns).next.is_null() && (*(*ns).next).type_ != ET::XML_NAMESPACE_DECL as c_int {
2409 (*ns).next as *mut _xmlNode
2410 } else {
2411 ptr::null_mut()
2412 }
2413 },
2414 _ => ptr::null_mut(),
2415 }
2416}
2417
2418#[no_mangle]
2435pub unsafe extern "C" fn xmlXPathNextAncestor(
2436 ctxt: *mut c_void,
2437 cur: *mut _xmlNode,
2438) -> *mut _xmlNode {
2439 let pc = pc_from(ctxt);
2440 if pc.is_null() {
2441 return ptr::null_mut();
2442 }
2443 let ctx = unsafe { (*pc).context };
2444 if ctx.is_null() {
2445 return ptr::null_mut();
2446 }
2447 use crate::abi::types::xmlElementType as ET;
2448 if cur.is_null() {
2449 let node = unsafe { (*ctx).node };
2450 if node.is_null() {
2451 return ptr::null_mut();
2452 }
2453 let t = unsafe { (*node).type_ };
2454 if t == ET::XML_ATTRIBUTE_NODE as c_int {
2455 return unsafe { (*(node as *mut _xmlAttr)).parent };
2456 }
2457 if t == ET::XML_NAMESPACE_DECL as c_int {
2458 let ns = node as *mut crate::abi::structs::_xmlNs;
2459 return unsafe {
2460 if !(*ns).next.is_null() && (*(*ns).next).type_ != ET::XML_NAMESPACE_DECL as c_int {
2461 (*ns).next as *mut _xmlNode
2462 } else {
2463 ptr::null_mut()
2464 }
2465 };
2466 }
2467 if t == ET::XML_DOCUMENT_NODE as c_int
2468 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2469 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2470 || t == ET::XML_HTML_DOCUMENT_NODE as c_int
2471 {
2472 return ptr::null_mut();
2473 }
2474 return next_parent_impl(ctx);
2476 }
2477 if cur == unsafe { (*ctx).doc } as *mut _xmlNode {
2478 return ptr::null_mut();
2479 }
2480 if cur == unsafe { (*(*ctx).doc).children } {
2481 return unsafe { (*ctx).doc } as *mut _xmlNode;
2482 }
2483 let t = unsafe { (*cur).type_ };
2484 if t == ET::XML_ATTRIBUTE_NODE as c_int {
2485 return unsafe { (*(cur as *mut _xmlAttr)).parent };
2486 }
2487 if t == ET::XML_NAMESPACE_DECL as c_int {
2488 let ns = cur as *mut crate::abi::structs::_xmlNs;
2489 return unsafe {
2490 if !(*ns).next.is_null() && (*(*ns).next).type_ != ET::XML_NAMESPACE_DECL as c_int {
2491 (*ns).next as *mut _xmlNode
2492 } else {
2493 ptr::null_mut()
2494 }
2495 };
2496 }
2497 if t == ET::XML_DOCUMENT_NODE as c_int
2498 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2499 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2500 || t == ET::XML_HTML_DOCUMENT_NODE as c_int
2501 {
2502 return ptr::null_mut();
2503 }
2504 unsafe {
2505 let parent = (*cur).parent;
2506 if parent.is_null() {
2507 return ptr::null_mut();
2508 }
2509 if (*parent).type_ == ET::XML_ELEMENT_NODE as c_int
2510 && ((*parent).name.is_null() || *(*parent).name == b' ')
2511 {
2512 return ptr::null_mut();
2513 }
2514 parent
2515 }
2516}
2517
2518#[no_mangle]
2535pub unsafe extern "C" fn xmlXPathNextAncestorOrSelf(
2536 ctxt: *mut c_void,
2537 cur: *mut _xmlNode,
2538) -> *mut _xmlNode {
2539 let pc = pc_from(ctxt);
2540 if pc.is_null() {
2541 return ptr::null_mut();
2542 }
2543 let ctx = unsafe { (*pc).context };
2544 if ctx.is_null() {
2545 return ptr::null_mut();
2546 }
2547 if cur.is_null() {
2548 return unsafe { (*ctx).node };
2549 }
2550 xmlXPathNextAncestor(ctxt, cur)
2551}
2552
2553#[no_mangle]
2570pub unsafe extern "C" fn xmlXPathNextFollowingSibling(
2571 ctxt: *mut c_void,
2572 mut cur: *mut _xmlNode,
2573) -> *mut _xmlNode {
2574 let pc = pc_from(ctxt);
2575 if pc.is_null() {
2576 return ptr::null_mut();
2577 }
2578 let ctx = unsafe { (*pc).context };
2579 if ctx.is_null() {
2580 return ptr::null_mut();
2581 }
2582 use crate::abi::types::xmlElementType as ET;
2583 unsafe {
2584 let cnode = (*ctx).node;
2585 if !cnode.is_null() {
2586 let t = (*cnode).type_;
2587 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
2588 return ptr::null_mut();
2589 }
2590 }
2591 if cur == (*ctx).doc as *mut _xmlNode {
2592 return ptr::null_mut();
2593 }
2594 if cur.is_null() {
2595 cur = cnode;
2596 }
2597 if cur.is_null() {
2598 return ptr::null_mut();
2599 }
2600 if (*cur).type_ == ET::XML_DOCUMENT_NODE as c_int {
2601 return ptr::null_mut();
2602 }
2603 (*cur).next
2604 }
2605}
2606
2607#[no_mangle]
2624pub unsafe extern "C" fn xmlXPathNextPrecedingSibling(
2625 ctxt: *mut c_void,
2626 mut cur: *mut _xmlNode,
2627) -> *mut _xmlNode {
2628 let pc = pc_from(ctxt);
2629 if pc.is_null() {
2630 return ptr::null_mut();
2631 }
2632 let ctx = unsafe { (*pc).context };
2633 if ctx.is_null() {
2634 return ptr::null_mut();
2635 }
2636 use crate::abi::types::xmlElementType as ET;
2637 unsafe {
2638 let cnode = (*ctx).node;
2639 if !cnode.is_null() {
2640 let t = (*cnode).type_;
2641 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
2642 return ptr::null_mut();
2643 }
2644 }
2645 if cur == (*ctx).doc as *mut _xmlNode {
2646 return ptr::null_mut();
2647 }
2648 if cur.is_null() {
2649 cur = cnode;
2650 } else if !(*cur).prev.is_null() && (*(*cur).prev).type_ == ET::XML_DTD_NODE as c_int {
2651 cur = (*cur).prev;
2652 if cur.is_null() {
2653 return ptr::null_mut();
2654 }
2655 }
2656 if cur.is_null() {
2657 return ptr::null_mut();
2658 }
2659 if (*cur).type_ == ET::XML_DOCUMENT_NODE as c_int {
2660 return ptr::null_mut();
2661 }
2662 (*cur).prev
2663 }
2664}
2665
2666#[no_mangle]
2683pub unsafe extern "C" fn xmlXPathNextFollowing(
2684 ctxt: *mut c_void,
2685 mut cur: *mut _xmlNode,
2686) -> *mut _xmlNode {
2687 let pc = pc_from(ctxt);
2688 if pc.is_null() {
2689 return ptr::null_mut();
2690 }
2691 let ctx = unsafe { (*pc).context };
2692 if ctx.is_null() {
2693 return ptr::null_mut();
2694 }
2695 use crate::abi::types::xmlElementType as ET;
2696 unsafe {
2697 if !cur.is_null()
2698 && (*cur).type_ != ET::XML_ATTRIBUTE_NODE as c_int
2699 && (*cur).type_ != ET::XML_NAMESPACE_DECL as c_int
2700 && !(*cur).children.is_null()
2701 {
2702 return (*cur).children;
2703 }
2704 if cur.is_null() {
2705 cur = (*ctx).node;
2706 if cur.is_null() {
2707 return ptr::null_mut();
2708 }
2709 if (*cur).type_ == ET::XML_ATTRIBUTE_NODE as c_int {
2710 cur = (*cur).parent;
2711 } else if (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2712 let ns = cur as *mut crate::abi::structs::_xmlNs;
2713 if (*ns).next.is_null() || (*(*ns).next).type_ == ET::XML_NAMESPACE_DECL as c_int {
2714 return ptr::null_mut();
2715 }
2716 cur = (*ns).next as *mut _xmlNode;
2717 }
2718 }
2719 if cur.is_null() {
2720 return ptr::null_mut();
2721 }
2722 if (*cur).type_ == ET::XML_DOCUMENT_NODE as c_int {
2723 return ptr::null_mut();
2724 }
2725 if !(*cur).next.is_null() {
2726 return (*cur).next;
2727 }
2728 loop {
2729 cur = (*cur).parent;
2730 if cur.is_null() {
2731 break;
2732 }
2733 if cur == (*ctx).doc as *mut _xmlNode {
2734 return ptr::null_mut();
2735 }
2736 if !(*cur).next.is_null() && (*cur).type_ != ET::XML_DOCUMENT_NODE as c_int {
2737 return (*cur).next;
2738 }
2739 }
2740 cur
2741 }
2742}
2743
2744#[no_mangle]
2761pub unsafe extern "C" fn xmlXPathNextPreceding(
2762 ctxt: *mut c_void,
2763 mut cur: *mut _xmlNode,
2764) -> *mut _xmlNode {
2765 let pc = pc_from(ctxt);
2766 if pc.is_null() {
2767 return ptr::null_mut();
2768 }
2769 let ctx = unsafe { (*pc).context };
2770 if ctx.is_null() {
2771 return ptr::null_mut();
2772 }
2773 use crate::abi::types::xmlElementType as ET;
2774 unsafe {
2775 let is_ancestor = |ancestor: *mut _xmlNode, node: *mut _xmlNode| -> bool {
2776 if ancestor.is_null() || node.is_null() {
2777 return false;
2778 }
2779 if (*node).type_ == ET::XML_NAMESPACE_DECL as c_int
2780 || (*ancestor).type_ == ET::XML_NAMESPACE_DECL as c_int
2781 {
2782 return false;
2783 }
2784 if (*ancestor).doc != (*node).doc {
2785 return false;
2786 }
2787 if ancestor == (*node).doc as *mut _xmlNode {
2788 return true;
2789 }
2790 if node == (*ancestor).doc as *mut _xmlNode {
2791 return false;
2792 }
2793 let mut n = node;
2794 while !(*n).parent.is_null() {
2795 if (*n).parent == ancestor {
2796 return true;
2797 }
2798 n = (*n).parent;
2799 }
2800 false
2801 };
2802 if cur.is_null() {
2803 cur = (*ctx).node;
2804 if cur.is_null() {
2805 return ptr::null_mut();
2806 }
2807 if (*cur).type_ == ET::XML_ATTRIBUTE_NODE as c_int {
2808 cur = (*cur).parent;
2809 } else if (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2810 let ns = cur as *mut crate::abi::structs::_xmlNs;
2811 if (*ns).next.is_null() || (*(*ns).next).type_ == ET::XML_NAMESPACE_DECL as c_int {
2812 return ptr::null_mut();
2813 }
2814 cur = (*ns).next as *mut _xmlNode;
2815 }
2816 }
2817 if cur.is_null() || (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2818 return ptr::null_mut();
2819 }
2820 if !(*cur).prev.is_null() && (*(*cur).prev).type_ == ET::XML_DTD_NODE as c_int {
2821 cur = (*cur).prev;
2822 }
2823 loop {
2824 if !(*cur).prev.is_null() {
2825 let mut n = (*cur).prev;
2826 while !(*n).last.is_null() {
2827 n = (*n).last;
2828 }
2829 return n;
2830 }
2831 cur = (*cur).parent;
2832 if cur.is_null() {
2833 return ptr::null_mut();
2834 }
2835 if cur == (*(*ctx).doc).children {
2836 return ptr::null_mut();
2837 }
2838 if !is_ancestor(cur, (*ctx).node) {
2839 return cur;
2840 }
2841 }
2842 }
2843}
2844
2845#[no_mangle]
2862pub unsafe extern "C" fn xmlXPathNextNamespace(
2863 ctxt: *mut c_void,
2864 cur: *mut _xmlNode,
2865) -> *mut _xmlNode {
2866 let pc = pc_from(ctxt);
2867 if pc.is_null() {
2868 return ptr::null_mut();
2869 }
2870 let ctx = unsafe { (*pc).context };
2871 if ctx.is_null() {
2872 return ptr::null_mut();
2873 }
2874 use crate::abi::types::xmlElementType as ET;
2875 unsafe {
2876 let cnode = (*ctx).node;
2877 if cnode.is_null() || (*cnode).type_ != ET::XML_ELEMENT_NODE as c_int {
2878 return ptr::null_mut();
2879 }
2880 if cur.is_null() {
2881 if !(*ctx).tmpNsList.is_null() {
2882 xmlFreeImpl((*ctx).tmpNsList as *mut c_void);
2883 }
2884 (*ctx).tmpNsNr = 0;
2885 (*ctx).tmpNsList = crate::xml::tree::get_ns_list((*ctx).doc, cnode);
2886 if !(*ctx).tmpNsList.is_null() {
2887 while !(*(*ctx).tmpNsList.add((*ctx).tmpNsNr as usize)).is_null() {
2888 (*ctx).tmpNsNr += 1;
2889 }
2890 }
2891 return (&XML_XPATH_XML_NS.0) as *const crate::abi::structs::_xmlNs as *mut _xmlNode;
2892 }
2893 if (*ctx).tmpNsNr > 0 {
2894 (*ctx).tmpNsNr -= 1;
2895 return (*(*ctx).tmpNsList.add((*ctx).tmpNsNr as usize)) as *mut _xmlNode;
2896 }
2897 if !(*ctx).tmpNsList.is_null() {
2898 xmlFreeImpl((*ctx).tmpNsList as *mut c_void);
2899 }
2900 (*ctx).tmpNsList = ptr::null_mut();
2901 ptr::null_mut()
2902 }
2903}
2904
2905#[no_mangle]
2922pub unsafe extern "C" fn xmlXPathNextAttribute(
2923 ctxt: *mut c_void,
2924 cur: *mut _xmlNode,
2925) -> *mut _xmlNode {
2926 let pc = pc_from(ctxt);
2927 if pc.is_null() {
2928 return ptr::null_mut();
2929 }
2930 let ctx = unsafe { (*pc).context };
2931 if ctx.is_null() {
2932 return ptr::null_mut();
2933 }
2934 use crate::abi::types::xmlElementType as ET;
2935 unsafe {
2936 let cnode = (*ctx).node;
2937 if cnode.is_null() || (*cnode).type_ != ET::XML_ELEMENT_NODE as c_int {
2938 return ptr::null_mut();
2939 }
2940 if cur.is_null() {
2941 if cnode == (*ctx).doc as *mut _xmlNode {
2942 return ptr::null_mut();
2943 }
2944 return (*cnode).properties as *mut _xmlNode;
2945 }
2946 (*cur).next
2947 }
2948}
2949
2950#[no_mangle]
2971pub unsafe extern "C" fn xmlXPathBooleanFunction(ctxt: *mut c_void, _nargs: c_int) {
2972 let pc = pc_from(ctxt);
2973 if pc.is_null() {
2974 return;
2975 }
2976 if !check_arity(pc, 1) {
2977 return;
2978 }
2979 let cur = value_pop(pc);
2980 if cur.is_null() {
2981 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
2982 return;
2983 }
2984 let b = crate::abi::exports_xml2::object_to_xpathvalue_pub(cur).as_boolean();
2985 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
2986 value_push(pc, new_bool(b));
2987}
2988
2989#[no_mangle]
3006pub unsafe extern "C" fn xmlXPathNotFunction(ctxt: *mut c_void, _nargs: c_int) {
3007 let pc = pc_from(ctxt);
3008 if pc.is_null() {
3009 return;
3010 }
3011 if !check_arity(pc, 1) {
3012 return;
3013 }
3014 cast_top_to_boolean(pc);
3015 if (*pc).error != 0 {
3016 return;
3017 }
3018 unsafe {
3019 (*(*pc).value).boolval = if (*(*pc).value).boolval == 0 { 1 } else { 0 };
3020 }
3021}
3022
3023#[no_mangle]
3040pub unsafe extern "C" fn xmlXPathTrueFunction(ctxt: *mut c_void, _nargs: c_int) {
3041 let pc = pc_from(ctxt);
3042 if pc.is_null() {
3043 return;
3044 }
3045
3046 value_push(pc, new_bool(true));
3047}
3048
3049#[no_mangle]
3066pub unsafe extern "C" fn xmlXPathFalseFunction(ctxt: *mut c_void, _nargs: c_int) {
3067 let pc = pc_from(ctxt);
3068 if pc.is_null() {
3069 return;
3070 }
3071
3072 value_push(pc, new_bool(false));
3073}
3074
3075const unsafe fn lang_matches(lang: *const xmlChar, the_lang: *const xmlChar) -> bool {
3078 if lang.is_null() || the_lang.is_null() {
3079 return false;
3080 }
3081 let mut i = 0usize;
3082 loop {
3083 let lc = unsafe { *lang.add(i) };
3084 if lc == 0 {
3085 break;
3086 }
3087 let tc = unsafe { *the_lang.add(i) };
3088 if tc == 0 {
3089 return false;
3090 }
3091 if !lc.eq_ignore_ascii_case(&tc) {
3092 return false;
3093 }
3094 i += 1;
3095 }
3096 let c = unsafe { *the_lang.add(i) };
3097 c == 0 || c == b'-'
3098}
3099
3100#[no_mangle]
3117pub unsafe extern "C" fn xmlXPathLangFunction(ctxt: *mut c_void, _nargs: c_int) {
3118 let pc = pc_from(ctxt);
3119 if pc.is_null() {
3120 return;
3121 }
3122 let ctx = unsafe { (*pc).context };
3123 if ctx.is_null() {
3124 return;
3125 }
3126 if !check_arity(pc, 1) {
3127 return;
3128 }
3129 cast_top_to_string(pc);
3130 if (*pc).error != 0 {
3131 return;
3132 }
3133 let val = value_pop(pc);
3134 if val.is_null() {
3135 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3136 return;
3137 }
3138 let lang = unsafe { (*val).stringval };
3139 let mut ret = 0;
3140 unsafe {
3141 let mut n = (*ctx).node;
3142 let mut found: *mut xmlChar = ptr::null_mut();
3143 while !n.is_null() {
3144 let got = crate::xml::tree::get_ns_prop(
3145 n,
3146 c"lang".as_ptr() as *const xmlChar,
3147 XML_XML_NAMESPACE_BYTES.as_ptr() as *const xmlChar,
3148 );
3149 if !got.is_null() {
3150 found = got;
3151 break;
3152 }
3153 n = (*n).parent;
3154 }
3155 if !found.is_null() && lang_matches(lang, found) {
3156 ret = 1;
3157 }
3158 if !found.is_null() {
3159 xmlFreeImpl(found as *mut c_void);
3160 }
3161 }
3162 crate::abi::exports_xml2::xmlXPathFreeObject(val);
3163 value_push(pc, new_bool(ret != 0));
3164}
3165
3166#[no_mangle]
3183pub unsafe extern "C" fn xmlXPathNumberFunction(ctxt: *mut c_void, nargs: c_int) {
3184 let pc = pc_from(ctxt);
3185 if pc.is_null() {
3186 return;
3187 }
3188 let ctx = unsafe { (*pc).context };
3189 if ctx.is_null() {
3190 return;
3191 }
3192 if nargs == 0 {
3193 let node = unsafe { (*ctx).node };
3194 let res = if node.is_null() {
3195 0.0
3196 } else {
3197 let sv = node_string_value(node);
3198 crate::xml::xpath::types::string_to_number(&sv)
3199 };
3200 value_push(pc, new_number(res));
3201 return;
3202 }
3203 if !check_arity(pc, 1) {
3204 return;
3205 }
3206 cast_top_to_number(pc);
3207}
3208
3209#[no_mangle]
3226pub unsafe extern "C" fn xmlXPathSumFunction(ctxt: *mut c_void, _nargs: c_int) {
3227 let pc = pc_from(ctxt);
3228 if pc.is_null() {
3229 return;
3230 }
3231 if !check_arity(pc, 1) {
3232 return;
3233 }
3234 let cur = value_pop(pc);
3235 if cur.is_null() {
3236 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3237 return;
3238 }
3239 let typ = unsafe { (*cur).type_ };
3240 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3241 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3242 {
3243 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3244 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3245 return;
3246 }
3247 let mut res = 0.0;
3248 unsafe {
3249 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3250 if !ns.is_null() {
3251 let nr = (*ns).nodeNr;
3252 let tab = (*ns).nodeTab;
3253 if !tab.is_null() {
3254 for i in 0..nr as isize {
3255 let node = *tab.add(i as usize);
3256 let sv = node_string_value(node);
3257 res += crate::xml::xpath::types::string_to_number(&sv);
3258 }
3259 }
3260 }
3261 }
3262 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3263 value_push(pc, new_number(res));
3264}
3265
3266#[no_mangle]
3283pub unsafe extern "C" fn xmlXPathFloorFunction(ctxt: *mut c_void, _nargs: c_int) {
3284 let pc = pc_from(ctxt);
3285 if pc.is_null() {
3286 return;
3287 }
3288 if !check_arity(pc, 1) {
3289 return;
3290 }
3291 cast_top_to_number(pc);
3292 if (*pc).error != 0 {
3293 return;
3294 }
3295 unsafe {
3296 (*(*pc).value).floatval = (*(*pc).value).floatval.floor();
3297 }
3298}
3299
3300#[no_mangle]
3317pub unsafe extern "C" fn xmlXPathCeilingFunction(ctxt: *mut c_void, _nargs: c_int) {
3318 let pc = pc_from(ctxt);
3319 if pc.is_null() {
3320 return;
3321 }
3322 if !check_arity(pc, 1) {
3323 return;
3324 }
3325 cast_top_to_number(pc);
3326 if (*pc).error != 0 {
3327 return;
3328 }
3329 unsafe {
3330 (*(*pc).value).floatval = (*(*pc).value).floatval.ceil();
3331 }
3332}
3333
3334#[no_mangle]
3351pub unsafe extern "C" fn xmlXPathRoundFunction(ctxt: *mut c_void, _nargs: c_int) {
3352 let pc = pc_from(ctxt);
3353 if pc.is_null() {
3354 return;
3355 }
3356 if !check_arity(pc, 1) {
3357 return;
3358 }
3359 cast_top_to_number(pc);
3360 if (*pc).error != 0 {
3361 return;
3362 }
3363 unsafe {
3364 let f = (*(*pc).value).floatval;
3365 if (-0.5..0.5).contains(&f) {
3366 (*(*pc).value).floatval *= 0.0;
3368 } else {
3369 let mut rounded = f.floor();
3370 if f - rounded >= 0.5 {
3371 rounded += 1.0;
3372 }
3373 (*(*pc).value).floatval = rounded;
3374 }
3375 }
3376}
3377
3378#[no_mangle]
3395pub unsafe extern "C" fn xmlXPathLastFunction(ctxt: *mut c_void, _nargs: c_int) {
3396 let pc = pc_from(ctxt);
3397 if pc.is_null() {
3398 return;
3399 }
3400 let ctx = unsafe { (*pc).context };
3401 if ctx.is_null() {
3402 return;
3403 }
3404
3405 value_push(pc, new_number(unsafe { (*ctx).contextSize } as f64));
3406}
3407
3408#[no_mangle]
3425pub unsafe extern "C" fn xmlXPathPositionFunction(ctxt: *mut c_void, _nargs: c_int) {
3426 let pc = pc_from(ctxt);
3427 if pc.is_null() {
3428 return;
3429 }
3430 let ctx = unsafe { (*pc).context };
3431 if ctx.is_null() {
3432 return;
3433 }
3434
3435 value_push(pc, new_number(unsafe { (*ctx).proximityPosition } as f64));
3436}
3437
3438#[no_mangle]
3455pub unsafe extern "C" fn xmlXPathCountFunction(ctxt: *mut c_void, _nargs: c_int) {
3456 let pc = pc_from(ctxt);
3457 if pc.is_null() {
3458 return;
3459 }
3460 if !check_arity(pc, 1) {
3461 return;
3462 }
3463 let cur = value_pop(pc);
3464 if cur.is_null() {
3465 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3466 return;
3467 }
3468 let typ = unsafe { (*cur).type_ };
3469 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3470 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3471 {
3472 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3473 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3474 return;
3475 }
3476 let count = unsafe {
3477 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3478 if ns.is_null() {
3479 0
3480 } else {
3481 (*ns).nodeNr
3482 }
3483 };
3484 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3485 value_push(pc, new_number(count as f64));
3486}
3487
3488unsafe fn get_elements_by_ids(doc: *mut _xmlDoc, ids: *const xmlChar) -> *mut _xmlNodeSet {
3491 use crate::abi::types::xmlElementType as ET;
3492 if ids.is_null() {
3493 return ptr::null_mut();
3494 }
3495 let mut out = NodeSet::new();
3496 unsafe {
3497 let mut p = ids;
3498 while *p != 0 {
3499 while is_blank_ch(*p) {
3500 p = p.add(1);
3501 }
3502 if *p == 0 {
3503 break;
3504 }
3505 let start = p;
3506 while *p != 0 && !is_blank_ch(*p) {
3507 p = p.add(1);
3508 }
3509 let id_c = crate::xml::string::xml_strndup(start, p.offset_from(start) as usize);
3510 if id_c.is_null() {
3511 break;
3512 }
3513 let attr = get_id(doc, id_c);
3514 xmlFreeImpl(id_c as *mut c_void);
3515 if !attr.is_null() {
3516 let t = (*attr).type_;
3517 let elem = if t == ET::XML_ATTRIBUTE_NODE as c_int {
3518 (*attr).parent
3519 } else if t == ET::XML_ELEMENT_NODE as c_int {
3520 attr as *mut _xmlNode
3521 } else {
3522 ptr::null_mut()
3523 };
3524 if !elem.is_null() {
3525 out.push(elem);
3526 }
3527 }
3528 }
3529 }
3530 out.to_raw()
3531}
3532
3533#[no_mangle]
3550pub unsafe extern "C" fn xmlXPathIdFunction(ctxt: *mut c_void, _nargs: c_int) {
3551 let pc = pc_from(ctxt);
3552 if pc.is_null() {
3553 return;
3554 }
3555 let ctx = unsafe { (*pc).context };
3556 if ctx.is_null() {
3557 return;
3558 }
3559 if !check_arity(pc, 1) {
3560 return;
3561 }
3562 let obj = value_pop(pc);
3563 if obj.is_null() {
3564 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3565 return;
3566 }
3567 let doc = unsafe { (*ctx).doc };
3568 let v = crate::abi::exports_xml2::object_to_xpathvalue_pub(obj);
3569 crate::abi::exports_xml2::xmlXPathFreeObject(obj);
3570 match &v {
3571 XPathValue::NodeSet(ns) => {
3572 let mut merged = NodeSet::new();
3573 for n in ns.iter() {
3574 let sv = node_string_value(n);
3575 let c = dup_rust_string(&sv);
3576 let sub = get_elements_by_ids(doc, c);
3577 xmlFreeImpl(c as *mut c_void);
3578 if !sub.is_null() {
3579 let sub_internal = node_set_to_internal(sub);
3580 for m in sub_internal.iter() {
3581 if !merged.contains(m) {
3582 merged.push(m);
3583 }
3584 }
3585 crate::abi::exports_xml2::xmlXPathFreeNodeSet(sub);
3587 }
3588 }
3589 value_push(
3590 pc,
3591 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(merged)),
3592 );
3593 }
3594 _ => {
3595 let s = v.as_string();
3596 let c = dup_rust_string(&s);
3597 let ret = get_elements_by_ids(doc, c);
3598 xmlFreeImpl(c as *mut c_void);
3599 if ret.is_null() {
3600 value_push(
3601 pc,
3602 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(
3603 NodeSet::new(),
3604 )),
3605 );
3606 } else {
3607 let obj2 = crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(
3608 node_set_to_internal(ret),
3609 ));
3610 crate::abi::exports_xml2::xmlXPathFreeNodeSet(ret);
3611 value_push(pc, obj2);
3612 }
3613 }
3614 }
3615}
3616
3617unsafe fn node_local_name(node: *mut _xmlNode) -> String {
3620 use crate::abi::types::xmlElementType as ET;
3621 if node.is_null() {
3622 return String::new();
3623 }
3624 unsafe {
3625 match (*node).type_ {
3626 t if t == ET::XML_ELEMENT_NODE as c_int
3627 || t == ET::XML_ATTRIBUTE_NODE as c_int
3628 || t == ET::XML_PI_NODE as c_int =>
3629 {
3630 let name = (*node).name;
3631 if name.is_null() || *name == b' ' {
3632 String::new()
3633 } else {
3634 let s = CStr::from_ptr(name as *const c_char)
3635 .to_string_lossy()
3636 .into_owned();
3637 match s.split_once(':') {
3638 Some((_, local)) => local.to_string(),
3639 None => s,
3640 }
3641 }
3642 }
3643 t if t == ET::XML_NAMESPACE_DECL as c_int => {
3644 let ns = node as *mut crate::abi::structs::_xmlNs;
3645 let p = (*ns).prefix;
3646 if p.is_null() {
3647 String::new()
3648 } else {
3649 CStr::from_ptr(p as *const c_char)
3650 .to_string_lossy()
3651 .into_owned()
3652 }
3653 }
3654 _ => String::new(),
3655 }
3656 }
3657}
3658
3659#[no_mangle]
3676pub unsafe extern "C" fn xmlXPathLocalNameFunction(ctxt: *mut c_void, nargs: c_int) {
3677 let pc = pc_from(ctxt);
3678 if pc.is_null() {
3679 return;
3680 }
3681 let ctx = unsafe { (*pc).context };
3682 if ctx.is_null() {
3683 return;
3684 }
3685 if nargs == 0 {
3686 value_push(
3687 pc,
3688 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(NodeSet::singleton(
3689 unsafe { (*ctx).node },
3690 ))),
3691 );
3692 }
3694
3695 if !check_arity(pc, 1) {
3696 return;
3697 }
3698 let cur = value_pop(pc);
3699 if cur.is_null() {
3700 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3701 return;
3702 }
3703 let typ = unsafe { (*cur).type_ };
3704 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3705 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3706 {
3707 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3708 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3709 return;
3710 }
3711 let name = unsafe {
3712 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3713 if ns.is_null() || (*ns).nodeNr == 0 {
3714 String::new()
3715 } else {
3716 node_local_name(*(*ns).nodeTab)
3717 }
3718 };
3719 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3720 let out = dup_rust_string(&name);
3721 value_push(pc, xmlXPathWrapString(out));
3722}
3723
3724unsafe fn node_namespace_uri(node: *mut _xmlNode) -> String {
3726 use crate::abi::types::xmlElementType as ET;
3727 if node.is_null() {
3728 return String::new();
3729 }
3730 unsafe {
3731 match (*node).type_ {
3732 t if t == ET::XML_ELEMENT_NODE as c_int || t == ET::XML_ATTRIBUTE_NODE as c_int => {
3733 let ns = (*node).ns;
3734 if ns.is_null() || (*ns).href.is_null() {
3735 String::new()
3736 } else {
3737 CStr::from_ptr((*ns).href as *const c_char)
3738 .to_string_lossy()
3739 .into_owned()
3740 }
3741 }
3742 t if t == ET::XML_NAMESPACE_DECL as c_int => {
3743 let ns = node as *mut crate::abi::structs::_xmlNs;
3744 if (*ns).href.is_null() {
3745 String::new()
3746 } else {
3747 CStr::from_ptr((*ns).href as *const c_char)
3748 .to_string_lossy()
3749 .into_owned()
3750 }
3751 }
3752 _ => String::new(),
3753 }
3754 }
3755}
3756
3757#[no_mangle]
3774pub unsafe extern "C" fn xmlXPathNamespaceURIFunction(ctxt: *mut c_void, nargs: c_int) {
3775 let pc = pc_from(ctxt);
3776 if pc.is_null() {
3777 return;
3778 }
3779 let ctx = unsafe { (*pc).context };
3780 if ctx.is_null() {
3781 return;
3782 }
3783 if nargs == 0 {
3784 value_push(
3785 pc,
3786 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(NodeSet::singleton(
3787 unsafe { (*ctx).node },
3788 ))),
3789 );
3790 }
3791
3792 if !check_arity(pc, 1) {
3793 return;
3794 }
3795 let cur = value_pop(pc);
3796 if cur.is_null() {
3797 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3798 return;
3799 }
3800 let typ = unsafe { (*cur).type_ };
3801 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3802 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3803 {
3804 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3805 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3806 return;
3807 }
3808 let uri = unsafe {
3809 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3810 if ns.is_null() || (*ns).nodeNr == 0 {
3811 String::new()
3812 } else {
3813 node_namespace_uri(*(*ns).nodeTab)
3814 }
3815 };
3816 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3817 let out = dup_rust_string(&uri);
3818 value_push(pc, xmlXPathWrapString(out));
3819}
3820
3821#[no_mangle]
3838pub unsafe extern "C" fn xmlXPathStringFunction(ctxt: *mut c_void, nargs: c_int) {
3839 let pc = pc_from(ctxt);
3840 if pc.is_null() {
3841 return;
3842 }
3843 let ctx = unsafe { (*pc).context };
3844 if ctx.is_null() {
3845 return;
3846 }
3847 if nargs == 0 {
3848 let node = unsafe { (*ctx).node };
3849 let sv = if node.is_null() {
3850 String::new()
3851 } else {
3852 node_string_value(node)
3853 };
3854 let out = dup_rust_string(&sv);
3855 value_push(pc, xmlXPathWrapString(out));
3856 return;
3857 }
3858 if !check_arity(pc, 1) {
3859 return;
3860 }
3861 cast_top_to_string(pc);
3862}
3863
3864#[no_mangle]
3881pub unsafe extern "C" fn xmlXPathStringLengthFunction(ctxt: *mut c_void, nargs: c_int) {
3882 let pc = pc_from(ctxt);
3883 if pc.is_null() {
3884 return;
3885 }
3886 let ctx = unsafe { (*pc).context };
3887 if ctx.is_null() {
3888 return;
3889 }
3890 if nargs == 0 {
3891 let node = unsafe { (*ctx).node };
3892 let len = if node.is_null() {
3893 0
3894 } else {
3895 let sv = node_string_value(node);
3896 sv.chars().count()
3897 };
3898 value_push(pc, new_number(len as f64));
3899 return;
3900 }
3901 if !check_arity(pc, 1) {
3902 return;
3903 }
3904 cast_top_to_string(pc);
3905 if (*pc).error != 0 {
3906 return;
3907 }
3908 let len = unsafe {
3909 let s = (*(*pc).value).stringval;
3910 if s.is_null() {
3911 0
3912 } else {
3913 let sv = CStr::from_ptr(s as *const c_char).to_string_lossy();
3914 sv.chars().count()
3915 }
3916 };
3917 let cur = value_pop(pc);
3918 if !cur.is_null() {
3919 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3920 }
3921 value_push(pc, new_number(len as f64));
3922}
3923
3924#[no_mangle]
3941pub unsafe extern "C" fn xmlXPathConcatFunction(ctxt: *mut c_void, nargs: c_int) {
3942 let pc = pc_from(ctxt);
3943 if pc.is_null() {
3944 return;
3945 }
3946 if nargs < 2 && !check_arity(pc, 2) {
3947 return;
3948 }
3949 if !check_arity(pc, nargs) {
3950 return;
3951 }
3952 let mut parts: Vec<String> = Vec::with_capacity(nargs as usize);
3953 for _ in 0..nargs {
3954 cast_top_to_string(pc);
3955 if (*pc).error != 0 {
3956 return;
3957 }
3958 let v = crate::abi::exports_xml2::object_to_xpathvalue_pub(unsafe { (*pc).value });
3959 let s = v.as_string();
3960 let obj = value_pop(pc);
3961 if !obj.is_null() {
3962 crate::abi::exports_xml2::xmlXPathFreeObject(obj);
3963 }
3964 parts.push(s);
3965 }
3966 parts.reverse();
3967 let joined = parts.concat();
3968 let out = dup_rust_string(&joined);
3969 value_push(pc, xmlXPathWrapString(out));
3970}
3971
3972#[no_mangle]
3989pub unsafe extern "C" fn xmlXPathContainsFunction(ctxt: *mut c_void, _nargs: c_int) {
3990 let pc = pc_from(ctxt);
3991 if pc.is_null() {
3992 return;
3993 }
3994 if !check_arity(pc, 2) {
3995 return;
3996 }
3997 cast_top_to_string(pc);
3998 if (*pc).error != 0 {
3999 return;
4000 }
4001 let needle = value_pop(pc);
4002 cast_top_to_string(pc);
4003 if (*pc).error != 0 {
4004 if !needle.is_null() {
4005 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
4006 }
4007 return;
4008 }
4009 let hay = value_pop(pc);
4010 let found = if hay.is_null() || needle.is_null() {
4011 false
4012 } else {
4013 unsafe { !cstr_find((*hay).stringval, (*needle).stringval).is_null() }
4014 };
4015 if !hay.is_null() {
4016 crate::abi::exports_xml2::xmlXPathFreeObject(hay);
4017 }
4018 if !needle.is_null() {
4019 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
4020 }
4021 value_push(pc, new_bool(found));
4022}
4023
4024#[no_mangle]
4041pub unsafe extern "C" fn xmlXPathStartsWithFunction(ctxt: *mut c_void, _nargs: c_int) {
4042 let pc = pc_from(ctxt);
4043 if pc.is_null() {
4044 return;
4045 }
4046 if !check_arity(pc, 2) {
4047 return;
4048 }
4049 cast_top_to_string(pc);
4050 if (*pc).error != 0 {
4051 return;
4052 }
4053 let needle = value_pop(pc);
4054 cast_top_to_string(pc);
4055 if (*pc).error != 0 {
4056 if !needle.is_null() {
4057 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
4058 }
4059 return;
4060 }
4061 let hay = value_pop(pc);
4062 let found = if hay.is_null() || needle.is_null() {
4063 false
4064 } else {
4065 unsafe { crate::xml::string::xml_str_starts_with((*hay).stringval, (*needle).stringval) }
4066 };
4067 if !hay.is_null() {
4068 crate::abi::exports_xml2::xmlXPathFreeObject(hay);
4069 }
4070 if !needle.is_null() {
4071 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
4072 }
4073 value_push(pc, new_bool(found));
4074}
4075
4076#[no_mangle]
4093pub unsafe extern "C" fn xmlXPathSubstringFunction(ctxt: *mut c_void, nargs: c_int) {
4094 let pc = pc_from(ctxt);
4095 if pc.is_null() {
4096 return;
4097 }
4098 if nargs < 2 {
4099 if !check_arity(pc, 2) {
4100 return;
4101 }
4102 } else if nargs > 3 && !check_arity(pc, 3) {
4103 return;
4104 }
4105 let mut le = 0.0;
4106 if nargs == 3 {
4107 cast_top_to_number(pc);
4108 if (*pc).error != 0 {
4109 return;
4110 }
4111 let len_obj = value_pop(pc);
4112 if !len_obj.is_null() {
4113 le = unsafe { (*len_obj).floatval };
4114 crate::abi::exports_xml2::xmlXPathFreeObject(len_obj);
4115 }
4116 }
4117 cast_top_to_number(pc);
4118 if (*pc).error != 0 {
4119 return;
4120 }
4121 let start_obj = value_pop(pc);
4122 let in_ = if start_obj.is_null() {
4123 f64::NAN
4124 } else {
4125 let v = unsafe { (*start_obj).floatval };
4126 crate::abi::exports_xml2::xmlXPathFreeObject(start_obj);
4127 v
4128 };
4129 cast_top_to_string(pc);
4130 if (*pc).error != 0 {
4131 return;
4132 }
4133 let str_obj = value_pop(pc);
4134 let s = if str_obj.is_null() {
4135 String::new()
4136 } else {
4137 let v = unsafe { CStr::from_ptr((*str_obj).stringval as *const c_char) }
4138 .to_string_lossy()
4139 .into_owned();
4140 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
4141 v
4142 };
4143
4144 let int_max = i32::MAX as f64;
4145 let mut i: i64 = 1;
4146 let mut j: i64 = i32::MAX as i64;
4147 #[allow(clippy::neg_cmp_op_on_partial_ord)]
4151 if !(in_ < int_max) {
4152 i = i32::MAX as i64;
4153 } else if in_ >= 1.0 {
4154 i = in_ as i64;
4155 if in_ - in_.floor() >= 0.5 {
4156 i += 1;
4157 }
4158 }
4159 if nargs == 3 {
4160 let mut rin = in_.floor();
4161 if in_ - rin >= 0.5 {
4162 rin += 1.0;
4163 }
4164 let mut rle = le.floor();
4165 if le - rle >= 0.5 {
4166 rle += 1.0;
4167 }
4168 let end = rin + rle;
4169 #[allow(clippy::neg_cmp_op_on_partial_ord)]
4170 if !(end >= 1.0) {
4171 j = 1;
4172 } else if end < int_max {
4173 j = end as i64;
4174 }
4175 }
4176 i -= 1;
4177 j -= 1;
4178 let chars: Vec<char> = s.chars().collect();
4179 let slen = chars.len() as i64;
4180 let out = if i < j && i < slen {
4181 let start_i = i.max(0) as usize;
4182 let end_i = (j.min(slen)).max(start_i as i64) as usize;
4183 chars[start_i..end_i].iter().collect()
4184 } else {
4185 String::new()
4186 };
4187 let c = dup_rust_string(&out);
4188 value_push(pc, xmlXPathWrapString(c));
4189}
4190
4191#[no_mangle]
4208pub unsafe extern "C" fn xmlXPathSubstringBeforeFunction(ctxt: *mut c_void, _nargs: c_int) {
4209 let pc = pc_from(ctxt);
4210 if pc.is_null() {
4211 return;
4212 }
4213 if !check_arity(pc, 2) {
4214 return;
4215 }
4216 cast_top_to_string(pc);
4217 if (*pc).error != 0 {
4218 return;
4219 }
4220 let find = value_pop(pc);
4221 cast_top_to_string(pc);
4222 if (*pc).error != 0 {
4223 if !find.is_null() {
4224 crate::abi::exports_xml2::xmlXPathFreeObject(find);
4225 }
4226 return;
4227 }
4228 let str_obj = value_pop(pc);
4229 let out: String = if str_obj.is_null() || find.is_null() {
4230 String::new()
4231 } else {
4232 unsafe {
4233 let hay = (*str_obj).stringval;
4234 let needle = (*find).stringval;
4235 let point = cstr_find(hay, needle);
4236 if point.is_null() {
4237 String::new()
4238 } else {
4239 let len = point.offset_from(hay) as usize;
4240 let bytes = core::slice::from_raw_parts(hay as *const u8, len);
4241 String::from_utf8_lossy(bytes).into_owned()
4242 }
4243 }
4244 };
4245 if !str_obj.is_null() {
4246 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
4247 }
4248 if !find.is_null() {
4249 crate::abi::exports_xml2::xmlXPathFreeObject(find);
4250 }
4251 let c = dup_rust_string(&out);
4252 value_push(pc, xmlXPathWrapString(c));
4253}
4254
4255#[no_mangle]
4272pub unsafe extern "C" fn xmlXPathSubstringAfterFunction(ctxt: *mut c_void, _nargs: c_int) {
4273 let pc = pc_from(ctxt);
4274 if pc.is_null() {
4275 return;
4276 }
4277 if !check_arity(pc, 2) {
4278 return;
4279 }
4280 cast_top_to_string(pc);
4281 if (*pc).error != 0 {
4282 return;
4283 }
4284 let find = value_pop(pc);
4285 cast_top_to_string(pc);
4286 if (*pc).error != 0 {
4287 if !find.is_null() {
4288 crate::abi::exports_xml2::xmlXPathFreeObject(find);
4289 }
4290 return;
4291 }
4292 let str_obj = value_pop(pc);
4293 let out: String = if str_obj.is_null() || find.is_null() {
4294 String::new()
4295 } else {
4296 unsafe {
4297 let hay = (*str_obj).stringval;
4298 let needle = (*find).stringval;
4299 let point = cstr_find(hay, needle);
4300 if point.is_null() {
4301 String::new()
4302 } else {
4303 let nlen = crate::xml::string::xml_strlen(needle);
4304 let rest = point.add(nlen);
4305 let len = crate::xml::string::xml_strlen(rest);
4306 let bytes = core::slice::from_raw_parts(rest, len);
4307 String::from_utf8_lossy(bytes).into_owned()
4308 }
4309 }
4310 };
4311 if !str_obj.is_null() {
4312 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
4313 }
4314 if !find.is_null() {
4315 crate::abi::exports_xml2::xmlXPathFreeObject(find);
4316 }
4317 let c = dup_rust_string(&out);
4318 value_push(pc, xmlXPathWrapString(c));
4319}
4320
4321#[no_mangle]
4338pub unsafe extern "C" fn xmlXPathNormalizeFunction(ctxt: *mut c_void, nargs: c_int) {
4339 let pc = pc_from(ctxt);
4340 if pc.is_null() {
4341 return;
4342 }
4343 let ctx = unsafe { (*pc).context };
4344 if ctx.is_null() {
4345 return;
4346 }
4347 if nargs == 0 {
4348 let node = unsafe { (*ctx).node };
4349 let sv = if node.is_null() {
4350 String::new()
4351 } else {
4352 node_string_value(node)
4353 };
4354 let c = dup_rust_string(&sv);
4355 value_push(pc, xmlXPathWrapString(c));
4356 }
4358
4359 if !check_arity(pc, 1) {
4360 return;
4361 }
4362 cast_top_to_string(pc);
4363 if (*pc).error != 0 {
4364 return;
4365 }
4366 let s = unsafe {
4367 let p = (*(*pc).value).stringval;
4368 if p.is_null() {
4369 String::new()
4370 } else {
4371 CStr::from_ptr(p as *const c_char)
4372 .to_string_lossy()
4373 .into_owned()
4374 }
4375 };
4376 let mut out = String::with_capacity(s.len());
4378 let mut blank = false;
4379 let mut started = false;
4380 for c in s.chars() {
4381 let is_b = c == ' ' || c == '\t' || c == '\n' || c == '\r';
4382 if is_b {
4383 if started {
4384 blank = true;
4385 }
4386 } else {
4387 if blank {
4388 out.push(' ');
4389 blank = false;
4390 }
4391 out.push(c);
4392 started = true;
4393 }
4394 }
4395 unsafe {
4396 let val = (*pc).value;
4397 if !(*val).stringval.is_null() {
4398 xmlFreeImpl((*val).stringval as *mut c_void);
4399 }
4400 (*val).stringval = dup_rust_string(&out);
4401 }
4402}
4403
4404#[no_mangle]
4421pub unsafe extern "C" fn xmlXPathTranslateFunction(ctxt: *mut c_void, _nargs: c_int) {
4422 let pc = pc_from(ctxt);
4423 if pc.is_null() {
4424 return;
4425 }
4426 if !check_arity(pc, 3) {
4427 return;
4428 }
4429 cast_top_to_string(pc);
4430 if (*pc).error != 0 {
4431 return;
4432 }
4433 let to = value_pop(pc);
4434 cast_top_to_string(pc);
4435 if (*pc).error != 0 {
4436 if !to.is_null() {
4437 crate::abi::exports_xml2::xmlXPathFreeObject(to);
4438 }
4439 return;
4440 }
4441 let from = value_pop(pc);
4442 cast_top_to_string(pc);
4443 if (*pc).error != 0 {
4444 if !to.is_null() {
4445 crate::abi::exports_xml2::xmlXPathFreeObject(to);
4446 }
4447 if !from.is_null() {
4448 crate::abi::exports_xml2::xmlXPathFreeObject(from);
4449 }
4450 return;
4451 }
4452 let str_obj = value_pop(pc);
4453 let (s, f, t) = unsafe {
4454 let s = if str_obj.is_null() || (*str_obj).stringval.is_null() {
4455 String::new()
4456 } else {
4457 CStr::from_ptr((*str_obj).stringval as *const c_char)
4458 .to_string_lossy()
4459 .into_owned()
4460 };
4461 let f = if from.is_null() || (*from).stringval.is_null() {
4462 String::new()
4463 } else {
4464 CStr::from_ptr((*from).stringval as *const c_char)
4465 .to_string_lossy()
4466 .into_owned()
4467 };
4468 let t = if to.is_null() || (*to).stringval.is_null() {
4469 String::new()
4470 } else {
4471 CStr::from_ptr((*to).stringval as *const c_char)
4472 .to_string_lossy()
4473 .into_owned()
4474 };
4475 (s, f, t)
4476 };
4477 if !str_obj.is_null() {
4478 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
4479 }
4480 if !from.is_null() {
4481 crate::abi::exports_xml2::xmlXPathFreeObject(from);
4482 }
4483 if !to.is_null() {
4484 crate::abi::exports_xml2::xmlXPathFreeObject(to);
4485 }
4486 let from_chars: Vec<char> = f.chars().collect();
4487 let to_chars: Vec<char> = t.chars().collect();
4488 let out: String = s
4491 .chars()
4492 .filter_map(|c| match from_chars.iter().position(|&x| x == c) {
4493 Some(i) if i < to_chars.len() => Some(to_chars[i]),
4494 Some(_) => None,
4495 _ => Some(c),
4496 })
4497 .collect();
4498 let c = dup_rust_string(&out);
4499 value_push(pc, xmlXPathWrapString(c));
4500}
4501
4502#[no_mangle]
4520pub const unsafe extern "C" fn xmlXPathRegisterAllFunctions(_ctxt: *mut _xmlXPathContext) {}
4521
4522unsafe fn standard_function_pointer(
4525 name: &str,
4526) -> Option<unsafe extern "C" fn(*mut c_void, c_int)> {
4527 let f: unsafe extern "C" fn(*mut c_void, c_int) = match name {
4528 "boolean" => xmlXPathBooleanFunction,
4529 "not" => xmlXPathNotFunction,
4530 "true" => xmlXPathTrueFunction,
4531 "false" => xmlXPathFalseFunction,
4532 "lang" => xmlXPathLangFunction,
4533 "number" => xmlXPathNumberFunction,
4534 "sum" => xmlXPathSumFunction,
4535 "floor" => xmlXPathFloorFunction,
4536 "ceiling" => xmlXPathCeilingFunction,
4537 "round" => xmlXPathRoundFunction,
4538 "last" => xmlXPathLastFunction,
4539 "position" => xmlXPathPositionFunction,
4540 "count" => xmlXPathCountFunction,
4541 "id" => xmlXPathIdFunction,
4542 "local-name" => xmlXPathLocalNameFunction,
4543 "namespace-uri" => xmlXPathNamespaceURIFunction,
4544 "string" => xmlXPathStringFunction,
4545 "string-length" => xmlXPathStringLengthFunction,
4546 "concat" => xmlXPathConcatFunction,
4547 "contains" => xmlXPathContainsFunction,
4548 "starts-with" => xmlXPathStartsWithFunction,
4549 "substring" => xmlXPathSubstringFunction,
4550 "substring-before" => xmlXPathSubstringBeforeFunction,
4551 "substring-after" => xmlXPathSubstringAfterFunction,
4552 "normalize-space" => xmlXPathNormalizeFunction,
4553 "translate" => xmlXPathTranslateFunction,
4554 _ => return None,
4555 };
4556 Some(f)
4557}
4558
4559#[no_mangle]
4565pub unsafe extern "C" fn xmlXPathFunctionLookup(
4566 ctxt: *mut _xmlXPathContext,
4567 name: *const xmlChar,
4568) -> Option<unsafe extern "C" fn(*mut c_void, c_int)> {
4569 xmlXPathFunctionLookupNS(ctxt, name, ptr::null())
4570}
4571
4572#[no_mangle]
4578pub unsafe extern "C" fn xmlXPathFunctionLookupNS(
4579 ctxt: *mut _xmlXPathContext,
4580 name: *const xmlChar,
4581 ns_uri: *const xmlChar,
4582) -> Option<unsafe extern "C" fn(*mut c_void, c_int)> {
4583 if ctxt.is_null() || name.is_null() {
4584 return None;
4585 }
4586 let name_str = match CStr::from_ptr(name as *const c_char).to_str() {
4587 Ok(s) => s.to_string(),
4588 Err(_) => return None,
4589 };
4590 if ns_uri.is_null() {
4591 if let Some(f) = standard_function_pointer(&name_str) {
4592 return Some(f);
4593 }
4594 }
4595 if let Some(f) = (*ctxt).funcLookupFunc {
4597 let ret = f((*ctxt).funcLookupData, name, ns_uri);
4598 if !ret.is_null() {
4599 let fp =
4601 std::mem::transmute::<*mut c_void, unsafe extern "C" fn(*mut c_void, c_int)>(ret);
4602 return Some(fp);
4603 }
4604 }
4605 let qualified = if ns_uri.is_null() {
4606 name_str
4607 } else {
4608 let ns = match CStr::from_ptr(ns_uri as *const c_char).to_str() {
4609 Ok(s) => s,
4610 Err(_) => return None,
4611 };
4612 format!("{{{}}}{}", ns, name_str)
4613 };
4614 crate::abi::exports_xml2::xpath_cfunc_lookup((*ctxt).extra, &qualified)
4615}
4616
4617#[no_mangle]
4631pub unsafe extern "C" fn xmlXPathCtxtCompile(
4632 _ctxt: *mut _xmlXPathContext,
4633 str_: *const xmlChar,
4634) -> *mut c_void {
4635 crate::abi::exports_xml2::xmlXPathCompile(str_)
4636}
4637
4638#[no_mangle]
4644pub unsafe extern "C" fn xmlXPathCompiledEval(
4645 comp: *mut c_void,
4646 ctx: *mut _xmlXPathContext,
4647) -> *mut _xmlXPathObject {
4648 if comp.is_null() || ctx.is_null() {
4649 return ptr::null_mut();
4650 }
4651 let internal = (*ctx).extra as *mut XPathContext;
4652 if internal.is_null() {
4653 return ptr::null_mut();
4654 }
4655 let internal = &mut *internal;
4656 let registry = crate::abi::exports_xml2::xpath_compiled_registry();
4657 let map = registry.lock();
4658 match map.get(&(comp as u64)) {
4659 Some(compiled) => match crate::xml::xpath::evaluate(compiled, internal) {
4660 Some(val) => crate::abi::exports_xml2::xpath_to_object_pub(val),
4661 None => ptr::null_mut(),
4662 },
4663 None => ptr::null_mut(),
4664 }
4665}
4666
4667#[no_mangle]
4675pub unsafe extern "C" fn xmlXPathCompiledEvalToBoolean(
4676 comp: *mut c_void,
4677 ctxt: *mut _xmlXPathContext,
4678) -> c_int {
4679 let obj = xmlXPathCompiledEval(comp, ctxt);
4680 if obj.is_null() {
4681 return -1;
4682 }
4683 let b = crate::abi::exports_xml2::object_to_xpathvalue_pub(obj).as_boolean();
4684 crate::abi::exports_xml2::xmlXPathFreeObject(obj);
4685 b as c_int
4686}
4687
4688#[no_mangle]
4695pub unsafe extern "C" fn xmlXPathSetContextNode(
4696 node: *mut _xmlNode,
4697 ctx: *mut _xmlXPathContext,
4698) -> c_int {
4699 if node.is_null() || ctx.is_null() {
4700 return -1;
4701 }
4702 if (*node).doc != (*ctx).doc {
4703 return -1;
4704 }
4705 (*ctx).node = node;
4706 let internal = (*ctx).extra as *mut XPathContext;
4707 if !internal.is_null() {
4708 (*internal).context_node = node;
4709 }
4710 0
4711}
4712
4713#[no_mangle]
4719pub unsafe extern "C" fn xmlXPathNodeEval(
4720 node: *mut _xmlNode,
4721 str_: *const xmlChar,
4722 ctx: *mut _xmlXPathContext,
4723) -> *mut _xmlXPathObject {
4724 if str_.is_null() {
4725 return ptr::null_mut();
4726 }
4727 if xmlXPathSetContextNode(node, ctx) < 0 {
4728 return ptr::null_mut();
4729 }
4730 crate::abi::exports_xml2::xmlXPathEvalExpression(str_, ctx)
4731}
4732
4733#[no_mangle]
4742pub unsafe extern "C" fn xmlXPathContextSetCache(
4743 ctxt: *mut _xmlXPathContext,
4744 active: c_int,
4745 _value: c_int,
4746 _options: c_int,
4747) -> c_int {
4748 if ctxt.is_null() {
4749 return -1;
4750 }
4751 (*ctxt).cache = if active != 0 {
4752 (&XML_XPATH_XML_NS.0) as *const crate::abi::structs::_xmlNs as *mut c_void
4753 } else {
4754 ptr::null_mut()
4755 };
4756 0
4757}
4758
4759#[no_mangle]
4765pub unsafe extern "C" fn xmlXPathRegisterFuncLookup(
4766 ctxt: *mut _xmlXPathContext,
4767 f: Option<crate::abi::callbacks::xmlXPathFuncLookupFunc>,
4768 data: *mut c_void,
4769) {
4770 if ctxt.is_null() {
4771 return;
4772 }
4773 (*ctxt).funcLookupFunc = f;
4774 (*ctxt).funcLookupData = data;
4775 let internal = (*ctxt).extra as *mut XPathContext;
4776 if !internal.is_null() {
4777 (*internal).func_lookup_func = f;
4778 (*internal).func_lookup_data = data;
4779 }
4780}
4781
4782#[no_mangle]
4788pub unsafe extern "C" fn xmlXPathRegisterVariableLookup(
4789 ctxt: *mut _xmlXPathContext,
4790 f: Option<crate::abi::callbacks::xmlXPathVariableLookupFunc>,
4791 data: *mut c_void,
4792) {
4793 if ctxt.is_null() {
4794 return;
4795 }
4796 (*ctxt).varLookupFunc = f;
4797 (*ctxt).varLookupData = data;
4798 let internal = (*ctxt).extra as *mut XPathContext;
4799 if !internal.is_null() {
4800 (*internal).var_lookup_func = f;
4801 (*internal).var_lookup_data = data;
4802 }
4803}
4804
4805#[no_mangle]
4811pub unsafe extern "C" fn xmlXPathRegisterVariableNS(
4812 ctxt: *mut _xmlXPathContext,
4813 name: *const xmlChar,
4814 ns_uri: *const xmlChar,
4815 value: *mut _xmlXPathObject,
4816) -> c_int {
4817 if ctxt.is_null() || name.is_null() || value.is_null() {
4818 return -1;
4819 }
4820 let internal = (*ctxt).extra as *mut XPathContext;
4821 if internal.is_null() {
4822 return -1;
4823 }
4824 let internal = &mut *internal;
4825 let name_str = match CStr::from_ptr(name as *const c_char).to_str() {
4826 Ok(s) => s.to_string(),
4827 Err(_) => return -1,
4828 };
4829 let qualified = if ns_uri.is_null() {
4830 name_str
4831 } else {
4832 match CStr::from_ptr(ns_uri as *const c_char).to_str() {
4833 Ok(s) => format!("{{{}}}{}", s, name_str),
4834 Err(_) => return -1,
4835 }
4836 };
4837 let xpath_val = crate::abi::exports_xml2::object_to_xpathvalue_pub(value);
4838 internal.register_variable(&qualified, xpath_val);
4839 0
4840}
4841
4842#[no_mangle]
4848pub unsafe extern "C" fn xmlXPathVariableLookup(
4849 ctxt: *mut _xmlXPathContext,
4850 name: *const xmlChar,
4851) -> *mut _xmlXPathObject {
4852 if ctxt.is_null() {
4853 return ptr::null_mut();
4854 }
4855 if let Some(f) = (*ctxt).varLookupFunc {
4856 let ret = f((*ctxt).varLookupData, name, ptr::null());
4857 return ret;
4858 }
4859 xmlXPathVariableLookupNS(ctxt, name, ptr::null())
4860}
4861
4862#[no_mangle]
4868pub unsafe extern "C" fn xmlXPathVariableLookupNS(
4869 ctxt: *mut _xmlXPathContext,
4870 name: *const xmlChar,
4871 ns_uri: *const xmlChar,
4872) -> *mut _xmlXPathObject {
4873 if ctxt.is_null() || name.is_null() {
4874 return ptr::null_mut();
4875 }
4876 if let Some(f) = (*ctxt).varLookupFunc {
4877 let ret = f((*ctxt).varLookupData, name, ns_uri);
4878 if !ret.is_null() {
4879 return ret;
4880 }
4881 }
4882 let internal = (*ctxt).extra as *mut XPathContext;
4883 if internal.is_null() {
4884 return ptr::null_mut();
4885 }
4886 let internal = &*internal;
4887 let name_str = match CStr::from_ptr(name as *const c_char).to_str() {
4888 Ok(s) => s.to_string(),
4889 Err(_) => return ptr::null_mut(),
4890 };
4891 let qualified = if ns_uri.is_null() {
4892 name_str
4893 } else {
4894 match CStr::from_ptr(ns_uri as *const c_char).to_str() {
4895 Ok(s) => format!("{{{}}}{}", s, name_str),
4896 Err(_) => return ptr::null_mut(),
4897 }
4898 };
4899 match internal.variables.get(&qualified) {
4900 Some(v) => crate::abi::exports_xml2::xpath_to_object_pub(v.clone()),
4901 None => ptr::null_mut(),
4902 }
4903}
4904
4905#[no_mangle]
4911pub unsafe extern "C" fn xmlXPathNsLookup(
4912 ctxt: *mut _xmlXPathContext,
4913 prefix: *const xmlChar,
4914) -> *const xmlChar {
4915 if ctxt.is_null() || prefix.is_null() {
4916 return ptr::null();
4917 }
4918 if cstr_eq(prefix, c"xml".as_ptr() as *const xmlChar) {
4920 return XML_XML_NAMESPACE_BYTES.as_ptr() as *const xmlChar;
4921 }
4922 let namespaces = (*ctxt).namespaces;
4924 if !namespaces.is_null() {
4925 for i in 0..(*ctxt).nsNr as isize {
4926 let ns = *namespaces.add(i as usize);
4927 if !ns.is_null() && !(*ns).prefix.is_null() && cstr_eq((*ns).prefix, prefix) {
4928 return (*ns).href;
4929 }
4930 }
4931 }
4932 if !(*ctxt).nsHash.is_null() {
4935 let map = &*((*ctxt).nsHash as *const HashMap<String, CString>);
4936 let p = CStr::from_ptr(prefix as *const c_char)
4937 .to_string_lossy()
4938 .into_owned();
4939 if let Some(c) = map.get(&p) {
4940 return c.as_ptr() as *const xmlChar;
4941 }
4942 }
4943 ptr::null()
4944}
4945
4946#[no_mangle]
4952pub unsafe extern "C" fn xmlXPathRegisteredFuncsCleanup(ctxt: *mut _xmlXPathContext) {
4953 if ctxt.is_null() {
4954 return;
4955 }
4956 let internal = (*ctxt).extra as *mut XPathContext;
4957 if !internal.is_null() {
4958 (*internal).functions.clear();
4959 }
4960 crate::abi::exports_xml2::xpath_cfunc_cleanup((*ctxt).extra);
4961}
4962
4963#[no_mangle]
4969pub unsafe extern "C" fn xmlXPathRegisteredVariablesCleanup(ctxt: *mut _xmlXPathContext) {
4970 if ctxt.is_null() {
4971 return;
4972 }
4973 let internal = (*ctxt).extra as *mut XPathContext;
4974 if !internal.is_null() {
4975 (*internal).variables.clear();
4976 }
4977}
4978
4979#[no_mangle]
4985pub unsafe extern "C" fn xmlXPathRegisteredNsCleanup(ctxt: *mut _xmlXPathContext) {
4986 if ctxt.is_null() {
4987 return;
4988 }
4989 let internal = (*ctxt).extra as *mut XPathContext;
4990 if !internal.is_null() {
4991 (*internal).namespaces.clear();
4992 }
4993 if !(*ctxt).nsHash.is_null() {
4994 drop(Box::from_raw(
4995 (*ctxt).nsHash as *mut HashMap<String, CString>,
4996 ));
4997 (*ctxt).nsHash = ptr::null_mut();
4998 }
4999}
5000
5001#[no_mangle]
5007pub unsafe extern "C" fn xmlXPathSetErrorHandler(
5008 ctxt: *mut _xmlXPathContext,
5009 handler: Option<crate::abi::callbacks::xmlStructuredErrorFunc>,
5010 data: *mut c_void,
5011) {
5012 if ctxt.is_null() {
5013 return;
5014 }
5015 (*ctxt).error = handler;
5016 (*ctxt).userData = data;
5017}
5018
5019extern "C" {
5020 fn fwrite(ptr: *const c_void, size: usize, nmemb: usize, stream: *mut c_void) -> usize;
5021}
5022
5023unsafe fn dump_write(output: *mut c_void, s: &str) {
5024 unsafe {
5025 fwrite(s.as_ptr() as *const c_void, 1, s.len(), output);
5026 }
5027}
5028
5029#[no_mangle]
5035pub unsafe extern "C" fn xmlXPathDebugDumpObject(
5036 output: *mut c_void,
5037 cur: *mut _xmlXPathObject,
5038 depth: c_int,
5039) {
5040 if output.is_null() {
5041 return;
5042 }
5043 let mut s = String::new();
5044 for _ in 0..depth.clamp(0, 25) {
5045 s.push_str(" ");
5046 }
5047 if cur.is_null() {
5048 s.push_str("Object is empty (NULL)\n");
5049 dump_write(output, &s);
5050 return;
5051 }
5052 unsafe {
5053 match (*cur).type_ {
5054 t if t == xmlXPathObjectType::XPATH_BOOLEAN as c_int => {
5055 s.push_str("Object is a Boolean : ");
5056 s.push_str(if (*cur).boolval != 0 {
5057 "true\n"
5058 } else {
5059 "false\n"
5060 });
5061 }
5062 t if t == xmlXPathObjectType::XPATH_NUMBER as c_int => {
5063 let f = (*cur).floatval;
5064 if f.is_nan() {
5065 s.push_str("Object is a number : NaN\n");
5066 } else if f == f64::INFINITY {
5067 s.push_str("Object is a number : Infinity\n");
5068 } else if f == f64::NEG_INFINITY {
5069 s.push_str("Object is a number : -Infinity\n");
5070 } else if f == 0.0 {
5071 s.push_str("Object is a number : 0\n");
5072 } else {
5073 s.push_str("Object is a number : ");
5074 s.push_str(&f.to_string());
5075 s.push('\n');
5076 }
5077 }
5078 t if t == xmlXPathObjectType::XPATH_STRING as c_int => {
5079 s.push_str("Object is a string : ");
5080 if (*cur).stringval.is_null() {
5081 s.push_str("(null)");
5082 } else {
5083 let sv = CStr::from_ptr((*cur).stringval as *const c_char).to_string_lossy();
5084 s.push_str(&sv);
5085 }
5086 s.push('\n');
5087 }
5088 t if t == xmlXPathObjectType::XPATH_NODESET as c_int => {
5089 s.push_str("Object is a Node Set :\n");
5090 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
5091 if !ns.is_null() {
5092 for _ in 0..=depth.min(24) {
5093 s.push_str(" ");
5094 }
5095 s.push_str(&format!("Object contains {} nodes\n", (*ns).nodeNr));
5096 }
5097 }
5098 t if t == xmlXPathObjectType::XPATH_XSLT_TREE as c_int => {
5099 s.push_str("Object is an XSLT value tree :\n");
5100 }
5101 t if t == xmlXPathObjectType::XPATH_USERS as c_int => {
5102 s.push_str("Object is user defined\n");
5103 }
5104 _ => {
5105 s.push_str("Object is uninitialized\n");
5106 }
5107 }
5108 }
5109 dump_write(output, &s);
5110}
5111
5112#[no_mangle]
5122pub unsafe extern "C" fn xmlXPathDebugDumpCompExpr(
5123 output: *mut c_void,
5124 comp: *mut c_void,
5125 depth: c_int,
5126) {
5127 if output.is_null() || comp.is_null() {
5128 return;
5129 }
5130 let registry = crate::abi::exports_xml2::xpath_compiled_registry();
5131 let map = registry.lock();
5132 if let Some(compiled) = map.get(&(comp as u64)) {
5133 let mut s = String::new();
5134 for _ in 0..depth.clamp(0, 25) {
5135 s.push_str(" ");
5136 }
5137 s.push_str("Compiled Expression : ");
5138 s.push_str(&compiled.original);
5139 s.push('\n');
5140 dump_write(output, &s);
5141 }
5142}
5143
5144#[allow(unused)]
5145const fn _unused_xpath_batch(_: *mut _xmlAttr) {}