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;
71use core::ptr;
72use std::os::raw::{c_char, c_double, c_int, c_long};
73
74use crate::abi::allocator::{xmlFreeImpl, xmlMallocImpl, xmlMallocZero};
75use crate::abi::structs::{
76 _xmlDoc, _xmlNode, _xmlNodeSet, _xmlNs, _xmlXPathContext, _xmlXPathObject,
77};
78use crate::abi::types::{xmlChar, xmlXPathObjectType};
79use crate::xml::string::xml_strdup;
80use crate::xml::xpath::types::{node_string_value, NodeSet, XPathValue};
81
82fn number_to_xmlstring(val: c_double) -> *mut xmlChar {
84 let s = crate::xml::xpath::types::number_to_string(val);
85 dup_rust_string(&s)
86}
87
88fn dup_rust_string(s: &str) -> *mut xmlChar {
92 let bytes = s.as_bytes();
93 let buf = unsafe { xmlMallocImpl(bytes.len() + 1) } as *mut xmlChar;
94 if buf.is_null() {
95 return ptr::null_mut();
96 }
97 unsafe {
98 ptr::copy_nonoverlapping(bytes.as_ptr(), buf, bytes.len());
99 *buf.add(bytes.len()) = 0;
100 }
101 buf
102}
103
104#[no_mangle]
114pub unsafe extern "C" fn xmlXPathNewString(val: *const xmlChar) -> *mut _xmlXPathObject {
115 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
116 if obj.is_null() {
117 return ptr::null_mut();
118 }
119 (*obj).type_ = xmlXPathObjectType::XPATH_STRING as c_int;
120 (*obj).stringval = if val.is_null() {
121 xml_strdup(c"".as_ptr() as *const xmlChar)
122 } else {
123 xml_strdup(val)
124 };
125 obj
126}
127
128#[no_mangle]
135pub unsafe extern "C" fn xmlXPathNewValueTree(val: *mut _xmlNode) -> *mut _xmlXPathObject {
136 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
137 if obj.is_null() {
138 return ptr::null_mut();
139 }
140 (*obj).type_ = xmlXPathObjectType::XPATH_XSLT_TREE as c_int;
141 let ns = xmlMallocZero(size_of::<_xmlNodeSet>()) as *mut _xmlNodeSet;
142 if ns.is_null() {
143 xmlFreeImpl(obj as *mut c_void);
144 return ptr::null_mut();
145 }
146 (*ns).nodeNr = 0;
147 (*ns).nodeMax = 1;
148 let tab = xmlMallocImpl(size_of::<*mut _xmlNode>()) as *mut *mut _xmlNode;
149 if tab.is_null() {
150 xmlFreeImpl(ns as *mut c_void);
151 xmlFreeImpl(obj as *mut c_void);
152 return ptr::null_mut();
153 }
154 if val.is_null() {
155 (*ns).nodeNr = 0;
156 (*ns).nodeMax = 0;
157 xmlFreeImpl(tab as *mut c_void);
158 (*ns).nodeTab = ptr::null_mut();
159 } else {
160 ptr::write(tab, val);
161 (*ns).nodeTab = tab;
162 (*ns).nodeNr = 1;
163 }
164 (*obj).nodesetval = ns as *mut c_void;
165 obj
166}
167
168#[no_mangle]
175pub unsafe extern "C" fn xmlXPathNewNodeSetList(val: *mut _xmlNodeSet) -> *mut _xmlXPathObject {
176 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
177 if obj.is_null() {
178 return ptr::null_mut();
179 }
180 (*obj).type_ = xmlXPathObjectType::XPATH_NODESET as c_int;
181 if val.is_null() {
182 (*obj).nodesetval = ptr::null_mut();
183 return obj;
184 }
185 let src = &*val;
186 let nr = src.nodeNr;
187 let ns = xmlMallocZero(size_of::<_xmlNodeSet>()) as *mut _xmlNodeSet;
188 if ns.is_null() {
189 xmlFreeImpl(obj as *mut c_void);
190 return ptr::null_mut();
191 }
192 (*ns).nodeNr = nr;
193 (*ns).nodeMax = nr;
194 if nr > 0 && !src.nodeTab.is_null() {
195 let tab = xmlMallocImpl((nr as usize) * size_of::<*mut _xmlNode>()) as *mut *mut _xmlNode;
196 if tab.is_null() {
197 xmlFreeImpl(ns as *mut c_void);
198 xmlFreeImpl(obj as *mut c_void);
199 return ptr::null_mut();
200 }
201 ptr::copy_nonoverlapping(src.nodeTab, tab, nr as usize);
202 (*ns).nodeTab = tab;
203 } else {
204 (*ns).nodeTab = ptr::null_mut();
205 }
206 (*obj).nodesetval = ns as *mut c_void;
207 obj
208}
209
210#[no_mangle]
217pub unsafe extern "C" fn xmlXPathWrapString(val: *mut xmlChar) -> *mut _xmlXPathObject {
218 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
219 if obj.is_null() {
220 if !val.is_null() {
221 xmlFreeImpl(val as *mut c_void);
222 }
223 return ptr::null_mut();
224 }
225 (*obj).type_ = xmlXPathObjectType::XPATH_STRING as c_int;
226 (*obj).stringval = val;
227 obj
228}
229
230#[no_mangle]
236pub unsafe extern "C" fn xmlXPathWrapCString(val: *mut c_char) -> *mut _xmlXPathObject {
237 unsafe { xmlXPathWrapString(val as *mut xmlChar) }
238}
239
240#[no_mangle]
247pub unsafe extern "C" fn xmlXPathWrapNodeSet(val: *mut _xmlNodeSet) -> *mut _xmlXPathObject {
248 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
249 if obj.is_null() {
250 if !val.is_null() {
251 xmlFreeImpl(val as *mut c_void);
252 }
253 return ptr::null_mut();
254 }
255 (*obj).type_ = xmlXPathObjectType::XPATH_NODESET as c_int;
256 (*obj).nodesetval = val as *mut c_void;
257 obj
258}
259
260#[no_mangle]
266pub unsafe extern "C" fn xmlXPathWrapExternal(val: *mut c_void) -> *mut _xmlXPathObject {
267 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
268 if obj.is_null() {
269 return ptr::null_mut();
270 }
271 (*obj).type_ = xmlXPathObjectType::XPATH_USERS as c_int;
272 (*obj).user = val;
273 obj
274}
275
276#[no_mangle]
283pub unsafe extern "C" fn xmlXPathFreeNodeSetList(obj: *mut _xmlXPathObject) {
284 if obj.is_null() {
285 return;
286 }
287 let typ = (*obj).type_;
288 if typ == xmlXPathObjectType::XPATH_NODESET as c_int
289 || typ == xmlXPathObjectType::XPATH_XSLT_TREE as c_int
290 {
291 let ns = (*obj).nodesetval as *mut _xmlNodeSet;
292 if !ns.is_null() {
293 if !(*ns).nodeTab.is_null() {
294 xmlFreeImpl((*ns).nodeTab as *mut c_void);
295 }
296 xmlFreeImpl(ns as *mut c_void);
297 }
298 }
299 xmlFreeImpl(obj as *mut c_void);
300}
301
302#[no_mangle]
313pub unsafe extern "C" fn xmlXPathConvertBoolean(val: *mut _xmlXPathObject) -> *mut _xmlXPathObject {
314 if val.is_null() {
315 return ptr::null_mut();
316 }
317 let typ = (*val).type_;
318 if typ == xmlXPathObjectType::XPATH_BOOLEAN as c_int {
319 return val;
320 }
321 let b = crate::abi::exports_xml2::object_to_xpathvalue_pub(val).as_boolean();
322 crate::abi::exports_xml2::xmlXPathFreeObject(val);
323 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
324 if obj.is_null() {
325 return ptr::null_mut();
326 }
327 (*obj).type_ = xmlXPathObjectType::XPATH_BOOLEAN as c_int;
328 (*obj).boolval = if b { 1 } else { 0 };
329 obj
330}
331
332#[no_mangle]
338pub unsafe extern "C" fn xmlXPathConvertNumber(val: *mut _xmlXPathObject) -> *mut _xmlXPathObject {
339 if val.is_null() {
340 return ptr::null_mut();
341 }
342 let typ = (*val).type_;
343 if typ == xmlXPathObjectType::XPATH_NUMBER as c_int {
344 return val;
345 }
346 let n = crate::abi::exports_xml2::object_to_xpathvalue_pub(val).as_number();
347 crate::abi::exports_xml2::xmlXPathFreeObject(val);
348 let obj = xmlMallocZero(size_of::<_xmlXPathObject>()) as *mut _xmlXPathObject;
349 if obj.is_null() {
350 return ptr::null_mut();
351 }
352 (*obj).type_ = xmlXPathObjectType::XPATH_NUMBER as c_int;
353 (*obj).floatval = n;
354 obj
355}
356
357#[no_mangle]
363pub unsafe extern "C" fn xmlXPathConvertString(val: *mut _xmlXPathObject) -> *mut _xmlXPathObject {
364 if val.is_null() {
365 return unsafe { xmlXPathNewString(ptr::null()) };
366 }
367 let typ = (*val).type_;
368 if typ == xmlXPathObjectType::XPATH_STRING as c_int {
369 return val;
370 }
371 let s = crate::abi::exports_xml2::object_to_xpathvalue_pub(val).as_string();
372 crate::abi::exports_xml2::xmlXPathFreeObject(val);
373 let buf = dup_rust_string(&s);
374 unsafe { xmlXPathWrapString(buf) }
375}
376
377#[no_mangle]
387pub unsafe extern "C" fn xmlXPathCastToBoolean(val: *mut _xmlXPathObject) -> c_int {
388 if val.is_null() {
389 return 0;
390 }
391 crate::abi::exports_xml2::object_to_xpathvalue_pub(val).as_boolean() as c_int
392}
393
394#[no_mangle]
400pub unsafe extern "C" fn xmlXPathCastToNumber(val: *mut _xmlXPathObject) -> c_double {
401 if val.is_null() {
402 return f64::NAN;
403 }
404 crate::abi::exports_xml2::object_to_xpathvalue_pub(val).as_number()
405}
406
407#[no_mangle]
419pub const unsafe extern "C" fn xmlXPathCastBooleanToNumber(val: c_int) -> c_double {
420 if val != 0 {
421 1.0
422 } else {
423 0.0
424 }
425}
426
427#[no_mangle]
439pub unsafe extern "C" fn xmlXPathCastBooleanToString(val: c_int) -> *mut xmlChar {
440 if val != 0 {
441 xml_strdup(c"true".as_ptr() as *const xmlChar)
442 } else {
443 xml_strdup(c"false".as_ptr() as *const xmlChar)
444 }
445}
446
447#[no_mangle]
453pub unsafe extern "C" fn xmlXPathCastNodeSetToBoolean(ns: *mut _xmlNodeSet) -> c_int {
454 if ns.is_null() {
455 return 0;
456 }
457 (unsafe { (*ns).nodeNr > 0 }) as c_int
458}
459
460#[no_mangle]
466pub unsafe extern "C" fn xmlXPathCastNodeSetToNumber(ns: *mut _xmlNodeSet) -> c_double {
467 unsafe {
468 let val = crate::abi::exports_xml2::object_to_xpathvalue_pub(xmlXPathWrapNodeSet(ns));
469 let n = val.as_number();
470 n
472 }
473}
474
475#[no_mangle]
481pub unsafe extern "C" fn xmlXPathCastNodeSetToString(ns: *mut _xmlNodeSet) -> *mut xmlChar {
482 let val = crate::xml::xpath::types::XPathValue::NodeSet(unsafe { node_set_to_internal(ns) });
483 let s = val.as_string();
484 dup_rust_string(&s)
485}
486
487unsafe fn node_set_to_internal(ns: *mut _xmlNodeSet) -> NodeSet {
489 let mut out = NodeSet::new();
490 if ns.is_null() {
491 return out;
492 }
493 let nr = unsafe { (*ns).nodeNr };
494 let tab = unsafe { (*ns).nodeTab };
495 if !tab.is_null() {
496 for i in 0..nr as isize {
497 out.push(unsafe { *tab.add(i as usize) });
498 }
499 }
500 out
501}
502
503#[no_mangle]
509pub unsafe extern "C" fn xmlXPathCastNodeToNumber(node: *mut _xmlNode) -> c_double {
510 let s = node_string_value(node);
511 crate::xml::xpath::types::string_to_number(&s)
512}
513
514#[no_mangle]
520pub unsafe extern "C" fn xmlXPathCastNodeToString(node: *mut _xmlNode) -> *mut xmlChar {
521 let s = node_string_value(node);
522 dup_rust_string(&s)
523}
524
525#[no_mangle]
537pub unsafe extern "C" fn xmlXPathCastNumberToBoolean(val: c_double) -> c_int {
538 (val != 0.0 && !val.is_nan()) as c_int
539}
540
541#[no_mangle]
553pub unsafe extern "C" fn xmlXPathCastNumberToString(val: c_double) -> *mut xmlChar {
554 number_to_xmlstring(val)
555}
556
557#[no_mangle]
563pub const unsafe extern "C" fn xmlXPathCastStringToBoolean(val: *const xmlChar) -> c_int {
564 if val.is_null() || unsafe { *val } == 0 {
565 0
566 } else {
567 1
568 }
569}
570
571#[no_mangle]
583pub const unsafe extern "C" fn xmlXPathIsNaN(val: c_double) -> c_int {
584 val.is_nan() as c_int
585}
586
587#[no_mangle]
599pub unsafe extern "C" fn xmlXPathIsInf(val: c_double) -> c_int {
600 if val.is_infinite() {
601 if val > 0.0 {
602 1
603 } else {
604 -1
605 }
606 } else {
607 0
608 }
609}
610
611#[no_mangle]
617pub unsafe extern "C" fn xmlXPathStringEvalNumber(str_: *const xmlChar) -> c_double {
618 if str_.is_null() {
619 return f64::NAN;
620 }
621 let s = unsafe { crate::xml::string::xmlstr_to_string(str_) };
622 crate::xml::xpath::types::string_to_number(&s)
623}
624
625#[no_mangle]
632pub unsafe extern "C" fn xmlXPathIsNodeType(name: *const xmlChar) -> c_int {
633 if name.is_null() {
634 return 0;
635 }
636 let s = unsafe { crate::xml::string::xmlstr_to_string(name) };
637 match s.as_str() {
638 "comment" | "text" | "processing-instruction" | "node" => 1,
639 _ => 0,
640 }
641}
642
643#[no_mangle]
655pub const unsafe extern "C" fn xmlXPathInit() {}
656
657#[no_mangle]
664pub unsafe extern "C" fn xmlXPathErr(
665 ctxt: *mut crate::xml::xpath::parser_context::XmlXPathParserContext,
666 error: c_int,
667) {
668 if !ctxt.is_null() {
669 unsafe { (*ctxt).error = error };
670 }
671}
672
673#[no_mangle]
680pub unsafe extern "C" fn xmlXPatherror(
681 ctxt: *mut crate::xml::xpath::parser_context::XmlXPathParserContext,
682 _file: *const c_char,
683 _line: c_int,
684 _no: c_int,
685) {
686 if !ctxt.is_null() {
687 unsafe { (*ctxt).error = _no };
688 }
689}
690
691#[allow(unused)]
692const fn _unused_doc(_d: *mut _xmlDoc) {}
693
694unsafe fn node_set_grow(ns: *mut _xmlNodeSet) {
700 if ns.is_null() {
701 return;
702 }
703 unsafe {
704 let nr = (*ns).nodeNr;
705 let max = (*ns).nodeMax;
706 if nr < max {
707 return;
708 }
709 let new_max = if max <= 0 { 8 } else { max * 2 };
710 let new_tab = crate::abi::allocator::xmlReallocImpl(
711 (*ns).nodeTab as *mut c_void,
712 (new_max as usize) * size_of::<*mut _xmlNode>(),
713 ) as *mut *mut _xmlNode;
714 if !new_tab.is_null() {
715 (*ns).nodeTab = new_tab;
716 (*ns).nodeMax = new_max;
717 }
718 }
719}
720
721#[no_mangle]
727pub unsafe extern "C" fn xmlXPathNodeSetContains(
728 cur: *mut _xmlNodeSet,
729 val: *mut _xmlNode,
730) -> c_int {
731 if cur.is_null() || val.is_null() {
732 return 0;
733 }
734 unsafe {
735 let nr = (*cur).nodeNr;
736 let tab = (*cur).nodeTab;
737 if !tab.is_null() {
738 for i in 0..nr as isize {
739 if *tab.add(i as usize) == val {
740 return 1;
741 }
742 }
743 }
744 }
745 0
746}
747
748#[no_mangle]
755pub unsafe extern "C" fn xmlXPathNodeSetAdd(cur: *mut _xmlNodeSet, val: *mut _xmlNode) -> c_int {
756 if cur.is_null() || val.is_null() {
757 return -1;
758 }
759 if xmlXPathNodeSetContains(cur, val) != 0 {
760 return 0;
761 }
762 unsafe {
763 node_set_grow(cur);
764 if (*cur).nodeNr >= (*cur).nodeMax {
765 return -1;
766 }
767 let idx = (*cur).nodeNr as usize;
768 ptr::write((*cur).nodeTab.add(idx), val);
769 (*cur).nodeNr += 1;
770 }
771 0
772}
773
774#[no_mangle]
781pub unsafe extern "C" fn xmlXPathNodeSetAddUnique(
782 cur: *mut _xmlNodeSet,
783 val: *mut _xmlNode,
784) -> c_int {
785 if cur.is_null() || val.is_null() {
786 return -1;
787 }
788 unsafe {
789 node_set_grow(cur);
790 if (*cur).nodeNr >= (*cur).nodeMax {
791 return -1;
792 }
793 let idx = (*cur).nodeNr as usize;
794 ptr::write((*cur).nodeTab.add(idx), val);
795 (*cur).nodeNr += 1;
796 }
797 0
798}
799
800#[no_mangle]
807pub unsafe extern "C" fn xmlXPathNodeSetAddNs(
808 cur: *mut _xmlNodeSet,
809 _node: *mut _xmlNode,
810 ns: *mut _xmlNs,
811) -> c_int {
812 if cur.is_null() || ns.is_null() {
813 return -1;
814 }
815 let ns_node = ns as *mut _xmlNode;
818 if xmlXPathNodeSetContains(cur, ns_node) != 0 {
819 return 0;
820 }
821 xmlXPathNodeSetAddUnique(cur, ns_node)
822}
823
824#[no_mangle]
831pub unsafe extern "C" fn xmlXPathNodeSetDel(cur: *mut _xmlNodeSet, val: *mut _xmlNode) {
832 if cur.is_null() || val.is_null() {
833 return;
834 }
835 unsafe {
836 let nr = (*cur).nodeNr;
837 let tab = (*cur).nodeTab;
838 let mut found = -1;
839 if !tab.is_null() {
840 for i in 0..nr as isize {
841 if *tab.add(i as usize) == val {
842 found = i as c_int;
843 break;
844 }
845 }
846 }
847 if found >= 0 {
848 let fi = found as usize;
849 for i in fi..(nr as usize - 1) {
850 ptr::write(tab.add(i), *tab.add(i + 1));
851 }
852 (*cur).nodeNr -= 1;
853 }
854 }
855}
856
857#[no_mangle]
864pub unsafe extern "C" fn xmlXPathNodeSetRemove(cur: *mut _xmlNodeSet, val: c_int) {
865 if cur.is_null() || val < 0 {
866 return;
867 }
868 unsafe {
869 let nr = (*cur).nodeNr;
870 if val >= nr {
871 return;
872 }
873 let tab = (*cur).nodeTab;
874 let vi = val as usize;
875 for i in vi..(nr as usize - 1) {
876 ptr::write(tab.add(i), *tab.add(i + 1));
877 }
878 (*cur).nodeNr -= 1;
879 }
880}
881
882#[no_mangle]
889pub unsafe extern "C" fn xmlXPathNodeSetSort(set: *mut _xmlNodeSet) {
890 if set.is_null() {
891 return;
892 }
893 unsafe {
894 let nr = (*set).nodeNr;
895 let tab = (*set).nodeTab;
896 if nr <= 1 || tab.is_null() {
897 return;
898 }
899 for i in 1..nr as usize {
902 let key = *tab.add(i);
903 let mut j = i;
904 while j > 0 {
905 let prev = *tab.add(j - 1);
906 if crate::xml::xpath::types::compare_document_order(prev, key)
907 == core::cmp::Ordering::Greater
908 {
909 ptr::write(tab.add(j), prev);
910 j -= 1;
911 } else {
912 break;
913 }
914 }
915 ptr::write(tab.add(j), key);
916 }
917 let mut w = 0usize;
919 for r in 0..nr as usize {
920 if w == 0 || *tab.add(w - 1) != *tab.add(r) {
921 ptr::write(tab.add(w), *tab.add(r));
922 w += 1;
923 }
924 }
925 (*set).nodeNr = w as c_int;
926 }
927}
928
929#[no_mangle]
936pub unsafe extern "C" fn xmlXPathNodeSetMerge(
937 val1: *mut _xmlNodeSet,
938 val2: *mut _xmlNodeSet,
939) -> *mut _xmlNodeSet {
940 if val1.is_null() && val2.is_null() {
941 return ptr::null_mut();
942 }
943 if val1.is_null() {
944 let obj = xmlXPathNewNodeSetList(val2);
946 let ns = unsafe { (*obj).nodesetval as *mut _xmlNodeSet };
947 if obj.is_null() {
948 return ptr::null_mut();
949 }
950 return ns;
951 }
952 if val2.is_null() {
953 return val1;
954 }
955 unsafe {
956 let nr2 = (*val2).nodeNr;
957 let tab2 = (*val2).nodeTab;
958 if !tab2.is_null() {
959 for i in 0..nr2 as isize {
960 let n = *tab2.add(i as usize);
961 if xmlXPathNodeSetContains(val1, n) == 0 {
962 xmlXPathNodeSetAddUnique(val1, n);
963 }
964 }
965 }
966 }
967 val1
968}
969
970#[no_mangle]
977pub unsafe extern "C" fn xmlXPathDifference(
978 nodes1: *mut _xmlNodeSet,
979 nodes2: *mut _xmlNodeSet,
980) -> *mut _xmlNodeSet {
981 if nodes1.is_null() {
982 return ptr::null_mut();
983 }
984 let mut a = unsafe { node_set_to_internal(nodes1) };
985 a.sort();
986 let b = unsafe { node_set_to_internal(nodes2) };
987 let mut out = NodeSet::new();
988 for n in a.iter() {
989 if !b.contains(n) {
990 out.push(n);
991 }
992 }
993 out.sort();
994 out.to_raw()
995}
996
997#[no_mangle]
1003pub unsafe extern "C" fn xmlXPathIntersection(
1004 nodes1: *mut _xmlNodeSet,
1005 nodes2: *mut _xmlNodeSet,
1006) -> *mut _xmlNodeSet {
1007 let a = unsafe { node_set_to_internal(nodes1) };
1008 let b = unsafe { node_set_to_internal(nodes2) };
1009 let mut out = NodeSet::new();
1010 for n in a.iter() {
1011 if b.contains(n) {
1012 out.push(n);
1013 }
1014 }
1015 out.sort();
1016 out.to_raw()
1017}
1018
1019#[no_mangle]
1025pub unsafe extern "C" fn xmlXPathDistinct(nodes: *mut _xmlNodeSet) -> *mut _xmlNodeSet {
1026 if nodes.is_null() {
1027 return ptr::null_mut();
1028 }
1029 unsafe {
1030 xmlXPathNodeSetSort(nodes);
1031 nodes
1032 }
1033}
1034
1035#[no_mangle]
1041pub unsafe extern "C" fn xmlXPathDistinctSorted(nodes: *mut _xmlNodeSet) -> *mut _xmlNodeSet {
1042 if nodes.is_null() {
1043 return ptr::null_mut();
1044 }
1045 unsafe {
1046 let nr = (*nodes).nodeNr;
1047 let tab = (*nodes).nodeTab;
1048 let mut w = 0usize;
1049 if !tab.is_null() {
1050 for r in 0..nr as usize {
1051 if w == 0 || *tab.add(w - 1) != *tab.add(r) {
1052 ptr::write(tab.add(w), *tab.add(r));
1053 w += 1;
1054 }
1055 }
1056 }
1057 (*nodes).nodeNr = w as c_int;
1058 nodes
1059 }
1060}
1061
1062#[no_mangle]
1068pub unsafe extern "C" fn xmlXPathHasSameNodes(
1069 nodes1: *mut _xmlNodeSet,
1070 nodes2: *mut _xmlNodeSet,
1071) -> c_int {
1072 if nodes1.is_null() || nodes2.is_null() {
1073 return 0;
1074 }
1075 unsafe {
1076 let nr1 = (*nodes1).nodeNr;
1077 let nr2 = (*nodes2).nodeNr;
1078 if nr1 != nr2 {
1079 return 0;
1080 }
1081 let tab1 = (*nodes1).nodeTab;
1082 let tab2 = (*nodes2).nodeTab;
1083 for i in 0..nr1 as isize {
1084 let mut found = false;
1085 for j in 0..nr2 as isize {
1086 if *tab1.add(i as usize) == *tab2.add(j as usize) {
1087 found = true;
1088 break;
1089 }
1090 }
1091 if !found {
1092 return 0;
1093 }
1094 }
1095 }
1096 1
1097}
1098
1099unsafe fn leading_nodes(nodes: &NodeSet, node: *mut _xmlNode) -> NodeSet {
1101 let mut out = NodeSet::new();
1102 for n in nodes.iter() {
1103 if n == node {
1104 break;
1105 }
1106 out.push(n);
1107 }
1108 out
1109}
1110
1111unsafe fn trailing_nodes(nodes: &NodeSet, node: *mut _xmlNode) -> NodeSet {
1112 let mut out = NodeSet::new();
1113 let mut seen = false;
1114 for n in nodes.iter() {
1115 if n == node {
1116 seen = true;
1117 continue;
1118 }
1119 if seen {
1120 out.push(n);
1121 }
1122 }
1123 out
1124}
1125
1126#[no_mangle]
1132pub unsafe extern "C" fn xmlXPathLeading(
1133 nodes1: *mut _xmlNodeSet,
1134 nodes2: *mut _xmlNodeSet,
1135) -> *mut _xmlNodeSet {
1136 if nodes1.is_null() {
1137 return ptr::null_mut();
1138 }
1139 let mut a = unsafe { node_set_to_internal(nodes1) };
1140 a.sort();
1141 let b = unsafe { node_set_to_internal(nodes2) };
1142 if b.is_empty() {
1143 let raw = a.to_raw();
1144 return raw;
1145 }
1146 let first = b.first().unwrap();
1147 let out = unsafe { leading_nodes(&a, first) };
1148 out.to_raw()
1149}
1150
1151#[no_mangle]
1157pub unsafe extern "C" fn xmlXPathLeadingSorted(
1158 nodes1: *mut _xmlNodeSet,
1159 nodes2: *mut _xmlNodeSet,
1160) -> *mut _xmlNodeSet {
1161 unsafe { xmlXPathLeading(nodes1, nodes2) }
1162}
1163
1164#[no_mangle]
1170pub unsafe extern "C" fn xmlXPathTrailing(
1171 nodes1: *mut _xmlNodeSet,
1172 nodes2: *mut _xmlNodeSet,
1173) -> *mut _xmlNodeSet {
1174 if nodes1.is_null() {
1175 return ptr::null_mut();
1176 }
1177 let mut a = unsafe { node_set_to_internal(nodes1) };
1178 a.sort();
1179 let b = unsafe { node_set_to_internal(nodes2) };
1180 if b.is_empty() {
1181 return a.to_raw();
1182 }
1183 let last = b.last().unwrap();
1184 let out = unsafe { trailing_nodes(&a, last) };
1185 out.to_raw()
1186}
1187
1188#[no_mangle]
1194pub unsafe extern "C" fn xmlXPathTrailingSorted(
1195 nodes1: *mut _xmlNodeSet,
1196 nodes2: *mut _xmlNodeSet,
1197) -> *mut _xmlNodeSet {
1198 unsafe { xmlXPathTrailing(nodes1, nodes2) }
1199}
1200
1201#[no_mangle]
1207pub unsafe extern "C" fn xmlXPathNodeLeading(
1208 nodes: *mut _xmlNodeSet,
1209 node: *mut _xmlNode,
1210) -> *mut _xmlNodeSet {
1211 if nodes.is_null() {
1212 return ptr::null_mut();
1213 }
1214 let mut a = unsafe { node_set_to_internal(nodes) };
1215 a.sort();
1216 let out = unsafe { leading_nodes(&a, node) };
1217 out.to_raw()
1218}
1219
1220#[no_mangle]
1226pub unsafe extern "C" fn xmlXPathNodeLeadingSorted(
1227 nodes: *mut _xmlNodeSet,
1228 node: *mut _xmlNode,
1229) -> *mut _xmlNodeSet {
1230 unsafe { xmlXPathNodeLeading(nodes, node) }
1231}
1232
1233#[no_mangle]
1239pub unsafe extern "C" fn xmlXPathNodeTrailing(
1240 nodes: *mut _xmlNodeSet,
1241 node: *mut _xmlNode,
1242) -> *mut _xmlNodeSet {
1243 if nodes.is_null() {
1244 return ptr::null_mut();
1245 }
1246 let mut a = unsafe { node_set_to_internal(nodes) };
1247 a.sort();
1248 let out = unsafe { trailing_nodes(&a, node) };
1249 out.to_raw()
1250}
1251
1252#[no_mangle]
1258pub unsafe extern "C" fn xmlXPathNodeTrailingSorted(
1259 nodes: *mut _xmlNodeSet,
1260 node: *mut _xmlNode,
1261) -> *mut _xmlNodeSet {
1262 unsafe { xmlXPathNodeTrailing(nodes, node) }
1263}
1264
1265#[no_mangle]
1278pub unsafe extern "C" fn xmlXPathNodeSetFreeNs(ns: *mut _xmlNs) {
1279 unsafe {
1280 if ns.is_null() {
1281 return;
1282 }
1283 if (*ns).type_ != crate::abi::types::xmlElementType::XML_NAMESPACE_DECL as c_int {
1284 return;
1285 }
1286 if !(*ns).next.is_null()
1288 && (*(*ns).next).type_ != crate::abi::types::xmlElementType::XML_NAMESPACE_DECL as c_int
1289 {
1290 if !(*ns).href.is_null() {
1291 libc::free((*ns).href as *mut libc::c_void);
1292 }
1293 if !(*ns).prefix.is_null() {
1294 libc::free((*ns).prefix as *mut libc::c_void);
1295 }
1296 libc::free(ns as *mut libc::c_void);
1297 }
1298 }
1299}
1300
1301#[no_mangle]
1316pub unsafe extern "C" fn xmlXPathOrderDocElems(doc: *mut _xmlDoc) -> c_long {
1317 if doc.is_null() {
1318 return -1;
1319 }
1320 let mut count: c_long = 0;
1321 unsafe {
1322 let mut cur = (*doc).children;
1323 while !cur.is_null() {
1324 if (*cur).type_ == crate::abi::types::xmlElementType::XML_ELEMENT_NODE as c_int {
1325 count += 1;
1326 (*cur).content = (-count) as *mut xmlChar;
1330 if !(*cur).children.is_null() {
1331 cur = (*cur).children;
1332 continue;
1333 }
1334 }
1335 if !(*cur).next.is_null() {
1336 cur = (*cur).next;
1337 continue;
1338 }
1339 loop {
1340 cur = (*cur).parent;
1341 if cur.is_null() {
1342 break;
1343 }
1344 if cur == doc as *mut _xmlNode {
1345 cur = ptr::null_mut();
1346 break;
1347 }
1348 if !(*cur).next.is_null() {
1349 cur = (*cur).next;
1350 break;
1351 }
1352 }
1353 }
1354 }
1355 count
1356}
1357use std::collections::HashMap;
1358use std::ffi::{CStr, CString};
1359
1360use crate::abi::structs::_xmlAttr;
1361use crate::xml::validation::{get_id, is_xml_name_char, is_xml_name_start};
1362use crate::xml::xpath::context::XPathContext;
1363use crate::xml::xpath::parser_context::{
1364 cast_top_to_number, compare_values_impl, equal_values_impl, free_parser_context, new_bool,
1365 new_number, new_parser_context, pc_set_error, pop_boolean, pop_external, pop_node_set,
1366 pop_number, pop_string, value_pop, value_push, XmlXPathParserContext,
1367};
1368
1369const unsafe fn pc_from(p: *mut c_void) -> *mut XmlXPathParserContext {
1373 p as *mut XmlXPathParserContext
1374}
1375
1376unsafe fn cstr_eq(a: *const xmlChar, b: *const xmlChar) -> bool {
1378 if a.is_null() || b.is_null() {
1379 return a == b;
1380 }
1381 let mut i = 0usize;
1382 loop {
1383 let ca = unsafe { *a.add(i) };
1384 let cb = unsafe { *b.add(i) };
1385 if ca != cb {
1386 return false;
1387 }
1388 if ca == 0 {
1389 return true;
1390 }
1391 i += 1;
1392 }
1393}
1394
1395const unsafe fn is_blank_ch(c: xmlChar) -> bool {
1397 c == b' ' || c == b'\t' || c == b'\n' || c == b'\r'
1398}
1399
1400unsafe fn cast_top_to_string(pc: *mut XmlXPathParserContext) {
1406 unsafe {
1407 let val = (*pc).value;
1408 if val.is_null() {
1409 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
1410 return;
1411 }
1412 if (*val).type_ != xmlXPathObjectType::XPATH_STRING as c_int {
1413 let v = crate::abi::exports_xml2::object_to_xpathvalue_pub(val);
1414 let s = v.as_string();
1415 if !(*val).stringval.is_null() {
1416 xmlFreeImpl((*val).stringval as *mut c_void);
1417 }
1418 (*val).stringval = dup_rust_string(&s);
1419 (*val).type_ = xmlXPathObjectType::XPATH_STRING as c_int;
1420 }
1421 }
1422}
1423
1424unsafe fn cast_top_to_boolean(pc: *mut XmlXPathParserContext) {
1430 unsafe {
1431 let val = (*pc).value;
1432 if val.is_null() {
1433 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
1434 return;
1435 }
1436 if (*val).type_ != xmlXPathObjectType::XPATH_BOOLEAN as c_int {
1437 let v = crate::abi::exports_xml2::object_to_xpathvalue_pub(val);
1438 (*val).boolval = v.as_boolean() as c_int;
1439 (*val).type_ = xmlXPathObjectType::XPATH_BOOLEAN as c_int;
1440 }
1441 }
1442}
1443
1444unsafe fn check_arity(pc: *mut XmlXPathParserContext, n: c_int) -> bool {
1447 if pc.is_null() || (*pc).value_nr < n {
1448 pc_set_error(pc, crate::abi::types::XPATH_INVALID_ARITY as c_int);
1449 return false;
1450 }
1451 true
1452}
1453
1454const unsafe fn scan_c_name(cur: *const xmlChar, nc: bool) -> usize {
1458 if cur.is_null() {
1459 return 0;
1460 }
1461 let mut i = 0usize;
1462 let mut first = true;
1463 loop {
1464 let b = unsafe { *cur.add(i) };
1465 if b == 0 {
1466 break;
1467 }
1468 if nc && b == b':' {
1469 break;
1470 }
1471 let (ch, adv): (char, usize) = if b < 0x80 {
1472 (b as char, 1)
1473 } else if b >= 0xC0 && b <= 0xDF {
1474 (
1475 unsafe {
1476 char::from_u32_unchecked(
1477 ((b as u32 & 0x1F) << 6) | (*cur.add(i + 1) as u32 & 0x3F),
1478 )
1479 },
1480 2,
1481 )
1482 } else if b >= 0xE0 && b <= 0xEF {
1483 (
1484 unsafe {
1485 char::from_u32_unchecked(
1486 ((b as u32 & 0x0F) << 12)
1487 | ((*cur.add(i + 1) as u32 & 0x3F) << 6)
1488 | (*cur.add(i + 2) as u32 & 0x3F),
1489 )
1490 },
1491 3,
1492 )
1493 } else if b >= 0xF0 && b <= 0xF7 {
1494 (
1495 unsafe {
1496 char::from_u32_unchecked(
1497 ((b as u32 & 0x07) << 18)
1498 | ((*cur.add(i + 1) as u32 & 0x3F) << 12)
1499 | ((*cur.add(i + 2) as u32 & 0x3F) << 6)
1500 | (*cur.add(i + 3) as u32 & 0x3F),
1501 )
1502 },
1503 4,
1504 )
1505 } else {
1506 break;
1507 };
1508 let ok = if first {
1509 is_xml_name_start(ch)
1510 } else {
1511 is_xml_name_char(ch)
1512 };
1513 if !ok {
1514 break;
1515 }
1516 first = false;
1517 i += adv;
1518 }
1519 i
1520}
1521
1522unsafe fn cstr_find(hay: *const xmlChar, needle: *const xmlChar) -> *const xmlChar {
1524 if hay.is_null() || needle.is_null() {
1525 return ptr::null();
1526 }
1527 if unsafe { *needle } == 0 {
1528 return hay;
1529 }
1530 let hlen = unsafe { crate::xml::string::xml_strlen(hay) };
1531 let nlen = unsafe { crate::xml::string::xml_strlen(needle) };
1532 if nlen > hlen {
1533 return ptr::null();
1534 }
1535 let hay_b = unsafe { core::slice::from_raw_parts(hay, hlen) };
1536 let needle_b = unsafe { core::slice::from_raw_parts(needle, nlen) };
1537 for off in 0..=hlen - nlen {
1538 if &hay_b[off..off + nlen] == needle_b {
1539 return unsafe { hay.add(off) };
1540 }
1541 }
1542 ptr::null()
1543}
1544
1545const XML_XML_NAMESPACE_BYTES: &[u8] = b"http://www.w3.org/XML/1998/namespace\0";
1547
1548struct XmlXPathXmlNs(_xmlNs);
1552unsafe impl Sync for XmlXPathXmlNs {}
1553static XML_XPATH_XML_NS: XmlXPathXmlNs = XmlXPathXmlNs(crate::abi::structs::_xmlNs {
1554 next: ptr::null_mut(),
1555 type_: crate::abi::types::xmlElementType::XML_NAMESPACE_DECL as c_int,
1556 href: XML_XML_NAMESPACE_BYTES.as_ptr() as *const xmlChar,
1557 prefix: c"xml".as_ptr() as *const xmlChar,
1558 _private: ptr::null_mut(),
1559 context: ptr::null_mut(),
1560});
1561
1562#[no_mangle]
1578pub unsafe extern "C" fn xmlXPathValuePush(
1579 ctxt: *mut c_void,
1580 value: *mut _xmlXPathObject,
1581) -> c_int {
1582 if ctxt.is_null() || value.is_null() {
1583 return -1;
1584 }
1585 let pc = pc_from(ctxt);
1586 let idx = unsafe { (*pc).value_nr };
1589 value_push(pc, value);
1590 idx
1591}
1592
1593#[no_mangle]
1599pub unsafe extern "C" fn xmlXPathValuePop(ctxt: *mut c_void) -> *mut _xmlXPathObject {
1600 value_pop(pc_from(ctxt))
1601}
1602
1603#[no_mangle]
1609pub unsafe extern "C" fn xmlXPathPopBoolean(ctxt: *mut c_void) -> c_int {
1610 pop_boolean(pc_from(ctxt))
1611}
1612
1613#[no_mangle]
1619pub unsafe extern "C" fn xmlXPathPopExternal(ctxt: *mut c_void) -> *mut c_void {
1620 pop_external(pc_from(ctxt))
1621}
1622
1623#[no_mangle]
1629pub unsafe extern "C" fn xmlXPathPopNodeSet(ctxt: *mut c_void) -> *mut _xmlNodeSet {
1630 pop_node_set(pc_from(ctxt))
1631}
1632
1633#[no_mangle]
1639pub unsafe extern "C" fn xmlXPathPopNumber(ctxt: *mut c_void) -> c_double {
1640 pop_number(pc_from(ctxt))
1641}
1642
1643#[no_mangle]
1649pub unsafe extern "C" fn xmlXPathPopString(ctxt: *mut c_void) -> *mut xmlChar {
1650 pop_string(pc_from(ctxt))
1651}
1652
1653unsafe fn binary_inplace(ctxt: *mut c_void, op: impl Fn(&mut f64, f64)) {
1658 let pc = pc_from(ctxt);
1659 if pc.is_null() {
1660 return;
1661 }
1662 let arg = value_pop(pc);
1663 if arg.is_null() {
1664 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
1665 return;
1666 }
1667 let val = crate::abi::exports_xml2::object_to_xpathvalue_pub(arg).as_number();
1668 crate::abi::exports_xml2::xmlXPathFreeObject(arg);
1669 if unsafe { (*pc).value.is_null() } {
1670 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
1671 return;
1672 }
1673 cast_top_to_number(pc);
1674 if (*pc).error != 0 {
1675 return;
1676 }
1677 unsafe {
1681 let float_ref: &mut f64 = &mut (*(*pc).value).floatval;
1682 op(float_ref, val);
1683 }
1684}
1685
1686#[no_mangle]
1703pub unsafe extern "C" fn xmlXPathAddValues(ctxt: *mut c_void) {
1704 binary_inplace(ctxt, |x, v| *x += v);
1705}
1706
1707#[no_mangle]
1724pub unsafe extern "C" fn xmlXPathSubValues(ctxt: *mut c_void) {
1725 binary_inplace(ctxt, |x, v| *x -= v);
1726}
1727
1728#[no_mangle]
1745pub unsafe extern "C" fn xmlXPathMultValues(ctxt: *mut c_void) {
1746 binary_inplace(ctxt, |x, v| *x *= v);
1747}
1748
1749#[no_mangle]
1766pub unsafe extern "C" fn xmlXPathDivValues(ctxt: *mut c_void) {
1767 binary_inplace(ctxt, |x, v| *x /= v);
1768}
1769
1770#[no_mangle]
1787pub unsafe extern "C" fn xmlXPathModValues(ctxt: *mut c_void) {
1788 binary_inplace(ctxt, |x, v| *x %= v);
1789}
1790
1791#[no_mangle]
1808pub unsafe extern "C" fn xmlXPathValueFlipSign(ctxt: *mut c_void) {
1809 let pc = pc_from(ctxt);
1810 if pc.is_null() {
1811 return;
1812 }
1813 cast_top_to_number(pc);
1814 if (*pc).error != 0 {
1815 return;
1816 }
1817 unsafe { (*(*pc).value).floatval = -(*(*pc).value).floatval };
1818}
1819
1820#[no_mangle]
1838pub unsafe extern "C" fn xmlXPathEqualValues(ctxt: *mut c_void) -> c_int {
1839 equal_values_impl(pc_from(ctxt), false)
1840}
1841
1842#[no_mangle]
1859pub unsafe extern "C" fn xmlXPathNotEqualValues(ctxt: *mut c_void) -> c_int {
1860 equal_values_impl(pc_from(ctxt), true)
1861}
1862
1863#[no_mangle]
1884pub unsafe extern "C" fn xmlXPathCompareValues(
1885 ctxt: *mut c_void,
1886 inf: c_int,
1887 strict: c_int,
1888) -> c_int {
1889 compare_values_impl(pc_from(ctxt), inf != 0, strict != 0)
1890}
1891
1892#[no_mangle]
1903pub unsafe extern "C" fn xmlXPathNewParserContext(
1904 str_: *const xmlChar,
1905 ctxt: *mut _xmlXPathContext,
1906) -> *mut c_void {
1907 new_parser_context(str_, ctxt) as *mut c_void
1908}
1909
1910#[no_mangle]
1916pub unsafe extern "C" fn xmlXPathFreeParserContext(ctxt: *mut c_void) {
1917 free_parser_context(pc_from(ctxt));
1918}
1919
1920#[no_mangle]
1927pub unsafe extern "C" fn xmlXPathParseNCName(ctxt: *mut c_void) -> *mut xmlChar {
1928 let pc = pc_from(ctxt);
1929 if pc.is_null() {
1930 return ptr::null_mut();
1931 }
1932 let cur = unsafe { (*pc).cur };
1933 if cur.is_null() {
1934 return ptr::null_mut();
1935 }
1936 let len = scan_c_name(cur, true);
1937 if len == 0 {
1938 return ptr::null_mut();
1939 }
1940 let ret = crate::xml::string::xml_strndup(cur, len);
1941 unsafe { (*pc).cur = cur.add(len) };
1942 ret
1943}
1944
1945#[no_mangle]
1952pub unsafe extern "C" fn xmlXPathParseName(ctxt: *mut c_void) -> *mut xmlChar {
1953 let pc = pc_from(ctxt);
1954 if pc.is_null() {
1955 return ptr::null_mut();
1956 }
1957 let cur = unsafe { (*pc).cur };
1958 if cur.is_null() {
1959 return ptr::null_mut();
1960 }
1961 let len = scan_c_name(cur, false);
1962 if len == 0 {
1963 return ptr::null_mut();
1964 }
1965 let ret = crate::xml::string::xml_strndup(cur, len);
1966 unsafe { (*pc).cur = cur.add(len) };
1967 ret
1968}
1969
1970#[no_mangle]
1977pub unsafe extern "C" fn xmlXPathRoot(ctxt: *mut c_void) {
1978 let pc = pc_from(ctxt);
1979 if pc.is_null() {
1980 return;
1981 }
1982 let ctx = unsafe { (*pc).context };
1983 if ctx.is_null() {
1984 return;
1985 }
1986 let ns = NodeSet::singleton(unsafe { (*ctx).doc } as *mut _xmlNode);
1987 let obj = crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(ns));
1988 value_push(pc, obj);
1989}
1990
1991#[no_mangle]
1999pub unsafe extern "C" fn xmlXPathEvalExpr(ctxt: *mut c_void) {
2000 let pc = pc_from(ctxt);
2001 if pc.is_null() {
2002 return;
2003 }
2004 let ctx = unsafe { (*pc).context };
2005 if ctx.is_null() {
2006 return;
2007 }
2008 let base = unsafe { (*pc).base };
2009 if base.is_null() {
2010 return;
2011 }
2012 let expr_str = match CStr::from_ptr(base as *const c_char).to_str() {
2013 Ok(s) => s,
2014 Err(_) => {
2015 pc_set_error(pc, crate::abi::types::XPATH_EXPR_ERROR as c_int);
2016 return;
2017 }
2018 };
2019 let internal = unsafe { (*ctx).extra } as *mut XPathContext;
2020 if internal.is_null() {
2021 return;
2022 }
2023 let internal = unsafe { &mut *internal };
2024 match crate::xml::xpath::evaluate_str(expr_str, internal) {
2025 Some(val) => {
2026 let obj = crate::abi::exports_xml2::xpath_to_object_pub(val);
2027 value_push(pc, obj);
2028 }
2029 None => {
2030 pc_set_error(pc, crate::abi::types::XPATH_EXPR_ERROR as c_int);
2031 }
2032 }
2033}
2034
2035unsafe fn eval_predicate_result(ctxt: *mut _xmlXPathContext, res: *mut _xmlXPathObject) -> c_int {
2037 if ctxt.is_null() || res.is_null() {
2038 return 0;
2039 }
2040 unsafe {
2041 let t = (*res).type_;
2042 if t == xmlXPathObjectType::XPATH_BOOLEAN as c_int {
2043 (*res).boolval
2044 } else if t == xmlXPathObjectType::XPATH_NUMBER as c_int {
2045 ((*res).floatval == (*ctxt).proximityPosition as f64) as c_int
2046 } else if t == xmlXPathObjectType::XPATH_NODESET as c_int
2047 || t == xmlXPathObjectType::XPATH_XSLT_TREE as c_int
2048 {
2049 let nsp = (*res).nodesetval as *mut _xmlNodeSet;
2050 if nsp.is_null() || (*nsp).nodeNr == 0 {
2051 0
2052 } else {
2053 1
2054 }
2055 } else if t == xmlXPathObjectType::XPATH_STRING as c_int {
2056 if (*res).stringval.is_null() || *(*res).stringval == 0 {
2057 0
2058 } else {
2059 1
2060 }
2061 } else {
2062 0
2063 }
2064 }
2065}
2066
2067#[no_mangle]
2074pub unsafe extern "C" fn xmlXPathEvalPredicate(
2075 ctxt: *mut _xmlXPathContext,
2076 res: *mut _xmlXPathObject,
2077) -> c_int {
2078 eval_predicate_result(ctxt, res)
2079}
2080
2081#[no_mangle]
2087pub unsafe extern "C" fn xmlXPathEvaluatePredicateResult(
2088 ctxt: *mut c_void,
2089 res: *mut _xmlXPathObject,
2090) -> c_int {
2091 let pc = pc_from(ctxt);
2092 if pc.is_null() {
2093 return 0;
2094 }
2095 let ctx = unsafe { (*pc).context };
2096 eval_predicate_result(ctx, res)
2097}
2098
2099#[no_mangle]
2120pub unsafe extern "C" fn xmlXPathNextSelf(ctxt: *mut c_void, cur: *mut _xmlNode) -> *mut _xmlNode {
2121 let pc = pc_from(ctxt);
2122 if pc.is_null() {
2123 return ptr::null_mut();
2124 }
2125 let ctx = unsafe { (*pc).context };
2126 if ctx.is_null() {
2127 return ptr::null_mut();
2128 }
2129 if cur.is_null() {
2130 return unsafe { (*ctx).node };
2131 }
2132 ptr::null_mut()
2133}
2134
2135#[no_mangle]
2152pub unsafe extern "C" fn xmlXPathNextChild(ctxt: *mut c_void, cur: *mut _xmlNode) -> *mut _xmlNode {
2153 let pc = pc_from(ctxt);
2154 if pc.is_null() {
2155 return ptr::null_mut();
2156 }
2157 let ctx = unsafe { (*pc).context };
2158 if ctx.is_null() {
2159 return ptr::null_mut();
2160 }
2161 use crate::abi::types::xmlElementType as ET;
2162 if cur.is_null() {
2163 let node = unsafe { (*ctx).node };
2164 if node.is_null() {
2165 return ptr::null_mut();
2166 }
2167 return match unsafe { (*node).type_ } {
2168 t if t == ET::XML_ELEMENT_NODE as c_int
2169 || t == ET::XML_TEXT_NODE as c_int
2170 || t == ET::XML_CDATA_SECTION_NODE as c_int
2171 || t == ET::XML_ENTITY_REF_NODE as c_int
2172 || t == ET::XML_ENTITY_NODE as c_int
2173 || t == ET::XML_PI_NODE as c_int
2174 || t == ET::XML_COMMENT_NODE as c_int
2175 || t == ET::XML_NOTATION_NODE as c_int
2176 || t == ET::XML_DTD_NODE as c_int =>
2177 unsafe { (*node).children },
2178 t if t == ET::XML_DOCUMENT_NODE as c_int
2179 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2180 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2181 || t == ET::XML_HTML_DOCUMENT_NODE as c_int =>
2182 unsafe { (*(node as *mut _xmlDoc)).children },
2183 _ => ptr::null_mut(),
2184 };
2185 }
2186 let t = unsafe { (*cur).type_ };
2187 if t == ET::XML_DOCUMENT_NODE as c_int || t == ET::XML_HTML_DOCUMENT_NODE as c_int {
2188 return ptr::null_mut();
2189 }
2190 unsafe { (*cur).next }
2191}
2192
2193#[no_mangle]
2210pub unsafe extern "C" fn xmlXPathNextDescendant(
2211 ctxt: *mut c_void,
2212 mut cur: *mut _xmlNode,
2213) -> *mut _xmlNode {
2214 let pc = pc_from(ctxt);
2215 if pc.is_null() {
2216 return ptr::null_mut();
2217 }
2218 let ctx = unsafe { (*pc).context };
2219 if ctx.is_null() {
2220 return ptr::null_mut();
2221 }
2222 use crate::abi::types::xmlElementType as ET;
2223 if cur.is_null() {
2224 let node = unsafe { (*ctx).node };
2225 if node.is_null() {
2226 return ptr::null_mut();
2227 }
2228 let t = unsafe { (*node).type_ };
2229 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
2230 return ptr::null_mut();
2231 }
2232 if node == unsafe { (*ctx).doc } as *mut _xmlNode {
2233 return unsafe { (*(*ctx).doc).children };
2234 }
2235 return unsafe { (*node).children };
2236 }
2237 unsafe {
2238 if (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2239 return ptr::null_mut();
2240 }
2241 if !(*cur).children.is_null() && (*(*cur).children).type_ != ET::XML_ENTITY_DECL as c_int {
2242 cur = (*cur).children;
2243 if (*cur).type_ != ET::XML_DTD_NODE as c_int {
2244 return cur;
2245 }
2246 }
2247 if cur == (*ctx).node {
2248 return ptr::null_mut();
2249 }
2250 while !(*cur).next.is_null() {
2251 cur = (*cur).next;
2252 if (*cur).type_ != ET::XML_ENTITY_DECL as c_int
2253 && (*cur).type_ != ET::XML_DTD_NODE as c_int
2254 {
2255 return cur;
2256 }
2257 }
2258 loop {
2259 cur = (*cur).parent;
2260 if cur.is_null() {
2261 break;
2262 }
2263 if cur == (*ctx).node {
2264 return ptr::null_mut();
2265 }
2266 if !(*cur).next.is_null() {
2267 cur = (*cur).next;
2268 return cur;
2269 }
2270 }
2271 cur
2272 }
2273}
2274
2275#[no_mangle]
2292pub unsafe extern "C" fn xmlXPathNextDescendantOrSelf(
2293 ctxt: *mut c_void,
2294 cur: *mut _xmlNode,
2295) -> *mut _xmlNode {
2296 let pc = pc_from(ctxt);
2297 if pc.is_null() {
2298 return ptr::null_mut();
2299 }
2300 let ctx = unsafe { (*pc).context };
2301 if ctx.is_null() {
2302 return ptr::null_mut();
2303 }
2304 if cur.is_null() {
2305 return unsafe { (*ctx).node };
2306 }
2307 let node = unsafe { (*ctx).node };
2308 if node.is_null() {
2309 return ptr::null_mut();
2310 }
2311 use crate::abi::types::xmlElementType as ET;
2312 let t = unsafe { (*node).type_ };
2313 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
2314 return ptr::null_mut();
2315 }
2316 xmlXPathNextDescendant(ctxt, cur)
2317}
2318
2319#[no_mangle]
2336pub unsafe extern "C" fn xmlXPathNextParent(
2337 ctxt: *mut c_void,
2338 cur: *mut _xmlNode,
2339) -> *mut _xmlNode {
2340 let pc = pc_from(ctxt);
2341 if pc.is_null() {
2342 return ptr::null_mut();
2343 }
2344 let ctx = unsafe { (*pc).context };
2345 if ctx.is_null() {
2346 return ptr::null_mut();
2347 }
2348 if !cur.is_null() {
2349 return ptr::null_mut();
2350 }
2351 next_parent_impl(ctx)
2352}
2353
2354unsafe fn next_parent_impl(ctx: *mut _xmlXPathContext) -> *mut _xmlNode {
2356 use crate::abi::types::xmlElementType as ET;
2357 let node = unsafe { (*ctx).node };
2358 if node.is_null() {
2359 return ptr::null_mut();
2360 }
2361 match unsafe { (*node).type_ } {
2362 t if t == ET::XML_ELEMENT_NODE as c_int
2363 || t == ET::XML_TEXT_NODE as c_int
2364 || t == ET::XML_CDATA_SECTION_NODE as c_int
2365 || t == ET::XML_ENTITY_REF_NODE as c_int
2366 || t == ET::XML_ENTITY_NODE as c_int
2367 || t == ET::XML_PI_NODE as c_int
2368 || t == ET::XML_COMMENT_NODE as c_int
2369 || t == ET::XML_NOTATION_NODE as c_int
2370 || t == ET::XML_DTD_NODE as c_int
2371 || t == ET::XML_ELEMENT_DECL as c_int
2372 || t == ET::XML_ATTRIBUTE_DECL as c_int
2373 || t == ET::XML_ENTITY_DECL as c_int
2374 || t == ET::XML_XINCLUDE_START as c_int
2375 || t == ET::XML_XINCLUDE_END as c_int =>
2376 unsafe {
2377 let parent = (*node).parent;
2378 if parent.is_null() {
2379 return (*ctx).doc as *mut _xmlNode;
2380 }
2381 if (*parent).type_ == ET::XML_ELEMENT_NODE as c_int
2382 && ((*parent).name.is_null() || *(*parent).name == b' ')
2383 {
2384 return ptr::null_mut();
2385 }
2386 parent
2387 },
2388 t if t == ET::XML_ATTRIBUTE_NODE as c_int => unsafe { (*(node as *mut _xmlAttr)).parent },
2389 t if t == ET::XML_DOCUMENT_NODE as c_int
2390 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2391 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2392 || t == ET::XML_HTML_DOCUMENT_NODE as c_int =>
2393 {
2394 ptr::null_mut()
2395 }
2396 t if t == ET::XML_NAMESPACE_DECL as c_int => unsafe {
2397 let ns = node as *mut crate::abi::structs::_xmlNs;
2398 if !(*ns).next.is_null() && (*(*ns).next).type_ != ET::XML_NAMESPACE_DECL as c_int {
2399 (*ns).next as *mut _xmlNode
2400 } else {
2401 ptr::null_mut()
2402 }
2403 },
2404 _ => ptr::null_mut(),
2405 }
2406}
2407
2408#[no_mangle]
2425pub unsafe extern "C" fn xmlXPathNextAncestor(
2426 ctxt: *mut c_void,
2427 cur: *mut _xmlNode,
2428) -> *mut _xmlNode {
2429 let pc = pc_from(ctxt);
2430 if pc.is_null() {
2431 return ptr::null_mut();
2432 }
2433 let ctx = unsafe { (*pc).context };
2434 if ctx.is_null() {
2435 return ptr::null_mut();
2436 }
2437 use crate::abi::types::xmlElementType as ET;
2438 if cur.is_null() {
2439 let node = unsafe { (*ctx).node };
2440 if node.is_null() {
2441 return ptr::null_mut();
2442 }
2443 let t = unsafe { (*node).type_ };
2444 if t == ET::XML_ATTRIBUTE_NODE as c_int {
2445 return unsafe { (*(node as *mut _xmlAttr)).parent };
2446 }
2447 if t == ET::XML_NAMESPACE_DECL as c_int {
2448 let ns = node as *mut crate::abi::structs::_xmlNs;
2449 return unsafe {
2450 if !(*ns).next.is_null() && (*(*ns).next).type_ != ET::XML_NAMESPACE_DECL as c_int {
2451 (*ns).next as *mut _xmlNode
2452 } else {
2453 ptr::null_mut()
2454 }
2455 };
2456 }
2457 if t == ET::XML_DOCUMENT_NODE as c_int
2458 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2459 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2460 || t == ET::XML_HTML_DOCUMENT_NODE as c_int
2461 {
2462 return ptr::null_mut();
2463 }
2464 return next_parent_impl(ctx);
2466 }
2467 if cur == unsafe { (*ctx).doc } as *mut _xmlNode {
2468 return ptr::null_mut();
2469 }
2470 if cur == unsafe { (*(*ctx).doc).children } {
2471 return unsafe { (*ctx).doc } as *mut _xmlNode;
2472 }
2473 let t = unsafe { (*cur).type_ };
2474 if t == ET::XML_ATTRIBUTE_NODE as c_int {
2475 return unsafe { (*(cur as *mut _xmlAttr)).parent };
2476 }
2477 if t == ET::XML_NAMESPACE_DECL as c_int {
2478 let ns = cur as *mut crate::abi::structs::_xmlNs;
2479 return unsafe {
2480 if !(*ns).next.is_null() && (*(*ns).next).type_ != ET::XML_NAMESPACE_DECL as c_int {
2481 (*ns).next as *mut _xmlNode
2482 } else {
2483 ptr::null_mut()
2484 }
2485 };
2486 }
2487 if t == ET::XML_DOCUMENT_NODE as c_int
2488 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2489 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2490 || t == ET::XML_HTML_DOCUMENT_NODE as c_int
2491 {
2492 return ptr::null_mut();
2493 }
2494 unsafe {
2495 let parent = (*cur).parent;
2496 if parent.is_null() {
2497 return ptr::null_mut();
2498 }
2499 if (*parent).type_ == ET::XML_ELEMENT_NODE as c_int
2500 && ((*parent).name.is_null() || *(*parent).name == b' ')
2501 {
2502 return ptr::null_mut();
2503 }
2504 parent
2505 }
2506}
2507
2508#[no_mangle]
2525pub unsafe extern "C" fn xmlXPathNextAncestorOrSelf(
2526 ctxt: *mut c_void,
2527 cur: *mut _xmlNode,
2528) -> *mut _xmlNode {
2529 let pc = pc_from(ctxt);
2530 if pc.is_null() {
2531 return ptr::null_mut();
2532 }
2533 let ctx = unsafe { (*pc).context };
2534 if ctx.is_null() {
2535 return ptr::null_mut();
2536 }
2537 if cur.is_null() {
2538 return unsafe { (*ctx).node };
2539 }
2540 xmlXPathNextAncestor(ctxt, cur)
2541}
2542
2543#[no_mangle]
2560pub unsafe extern "C" fn xmlXPathNextFollowingSibling(
2561 ctxt: *mut c_void,
2562 mut cur: *mut _xmlNode,
2563) -> *mut _xmlNode {
2564 let pc = pc_from(ctxt);
2565 if pc.is_null() {
2566 return ptr::null_mut();
2567 }
2568 let ctx = unsafe { (*pc).context };
2569 if ctx.is_null() {
2570 return ptr::null_mut();
2571 }
2572 use crate::abi::types::xmlElementType as ET;
2573 unsafe {
2574 let cnode = (*ctx).node;
2575 if !cnode.is_null() {
2576 let t = (*cnode).type_;
2577 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
2578 return ptr::null_mut();
2579 }
2580 }
2581 if cur == (*ctx).doc as *mut _xmlNode {
2582 return ptr::null_mut();
2583 }
2584 if cur.is_null() {
2585 cur = cnode;
2586 }
2587 if cur.is_null() {
2588 return ptr::null_mut();
2589 }
2590 if (*cur).type_ == ET::XML_DOCUMENT_NODE as c_int {
2591 return ptr::null_mut();
2592 }
2593 (*cur).next
2594 }
2595}
2596
2597#[no_mangle]
2614pub unsafe extern "C" fn xmlXPathNextPrecedingSibling(
2615 ctxt: *mut c_void,
2616 mut cur: *mut _xmlNode,
2617) -> *mut _xmlNode {
2618 let pc = pc_from(ctxt);
2619 if pc.is_null() {
2620 return ptr::null_mut();
2621 }
2622 let ctx = unsafe { (*pc).context };
2623 if ctx.is_null() {
2624 return ptr::null_mut();
2625 }
2626 use crate::abi::types::xmlElementType as ET;
2627 unsafe {
2628 let cnode = (*ctx).node;
2629 if !cnode.is_null() {
2630 let t = (*cnode).type_;
2631 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
2632 return ptr::null_mut();
2633 }
2634 }
2635 if cur == (*ctx).doc as *mut _xmlNode {
2636 return ptr::null_mut();
2637 }
2638 if cur.is_null() {
2639 cur = cnode;
2640 } else if !(*cur).prev.is_null() && (*(*cur).prev).type_ == ET::XML_DTD_NODE as c_int {
2641 cur = (*cur).prev;
2642 if cur.is_null() {
2643 return ptr::null_mut();
2644 }
2645 }
2646 if cur.is_null() {
2647 return ptr::null_mut();
2648 }
2649 if (*cur).type_ == ET::XML_DOCUMENT_NODE as c_int {
2650 return ptr::null_mut();
2651 }
2652 (*cur).prev
2653 }
2654}
2655
2656#[no_mangle]
2673pub unsafe extern "C" fn xmlXPathNextFollowing(
2674 ctxt: *mut c_void,
2675 mut cur: *mut _xmlNode,
2676) -> *mut _xmlNode {
2677 let pc = pc_from(ctxt);
2678 if pc.is_null() {
2679 return ptr::null_mut();
2680 }
2681 let ctx = unsafe { (*pc).context };
2682 if ctx.is_null() {
2683 return ptr::null_mut();
2684 }
2685 use crate::abi::types::xmlElementType as ET;
2686 unsafe {
2687 if !cur.is_null()
2688 && (*cur).type_ != ET::XML_ATTRIBUTE_NODE as c_int
2689 && (*cur).type_ != ET::XML_NAMESPACE_DECL as c_int
2690 && !(*cur).children.is_null()
2691 {
2692 return (*cur).children;
2693 }
2694 if cur.is_null() {
2695 cur = (*ctx).node;
2696 if cur.is_null() {
2697 return ptr::null_mut();
2698 }
2699 if (*cur).type_ == ET::XML_ATTRIBUTE_NODE as c_int {
2700 cur = (*cur).parent;
2701 } else if (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2702 let ns = cur as *mut crate::abi::structs::_xmlNs;
2703 if (*ns).next.is_null() || (*(*ns).next).type_ == ET::XML_NAMESPACE_DECL as c_int {
2704 return ptr::null_mut();
2705 }
2706 cur = (*ns).next as *mut _xmlNode;
2707 }
2708 }
2709 if cur.is_null() {
2710 return ptr::null_mut();
2711 }
2712 if (*cur).type_ == ET::XML_DOCUMENT_NODE as c_int {
2713 return ptr::null_mut();
2714 }
2715 if !(*cur).next.is_null() {
2716 return (*cur).next;
2717 }
2718 loop {
2719 cur = (*cur).parent;
2720 if cur.is_null() {
2721 break;
2722 }
2723 if cur == (*ctx).doc as *mut _xmlNode {
2724 return ptr::null_mut();
2725 }
2726 if !(*cur).next.is_null() && (*cur).type_ != ET::XML_DOCUMENT_NODE as c_int {
2727 return (*cur).next;
2728 }
2729 }
2730 cur
2731 }
2732}
2733
2734#[no_mangle]
2751pub unsafe extern "C" fn xmlXPathNextPreceding(
2752 ctxt: *mut c_void,
2753 mut cur: *mut _xmlNode,
2754) -> *mut _xmlNode {
2755 let pc = pc_from(ctxt);
2756 if pc.is_null() {
2757 return ptr::null_mut();
2758 }
2759 let ctx = unsafe { (*pc).context };
2760 if ctx.is_null() {
2761 return ptr::null_mut();
2762 }
2763 use crate::abi::types::xmlElementType as ET;
2764 unsafe {
2765 let is_ancestor = |ancestor: *mut _xmlNode, node: *mut _xmlNode| -> bool {
2766 if ancestor.is_null() || node.is_null() {
2767 return false;
2768 }
2769 if (*node).type_ == ET::XML_NAMESPACE_DECL as c_int
2770 || (*ancestor).type_ == ET::XML_NAMESPACE_DECL as c_int
2771 {
2772 return false;
2773 }
2774 if (*ancestor).doc != (*node).doc {
2775 return false;
2776 }
2777 if ancestor == (*node).doc as *mut _xmlNode {
2778 return true;
2779 }
2780 if node == (*ancestor).doc as *mut _xmlNode {
2781 return false;
2782 }
2783 let mut n = node;
2784 while !(*n).parent.is_null() {
2785 if (*n).parent == ancestor {
2786 return true;
2787 }
2788 n = (*n).parent;
2789 }
2790 false
2791 };
2792 if cur.is_null() {
2793 cur = (*ctx).node;
2794 if cur.is_null() {
2795 return ptr::null_mut();
2796 }
2797 if (*cur).type_ == ET::XML_ATTRIBUTE_NODE as c_int {
2798 cur = (*cur).parent;
2799 } else if (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2800 let ns = cur as *mut crate::abi::structs::_xmlNs;
2801 if (*ns).next.is_null() || (*(*ns).next).type_ == ET::XML_NAMESPACE_DECL as c_int {
2802 return ptr::null_mut();
2803 }
2804 cur = (*ns).next as *mut _xmlNode;
2805 }
2806 }
2807 if cur.is_null() || (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2808 return ptr::null_mut();
2809 }
2810 if !(*cur).prev.is_null() && (*(*cur).prev).type_ == ET::XML_DTD_NODE as c_int {
2811 cur = (*cur).prev;
2812 }
2813 loop {
2814 if !(*cur).prev.is_null() {
2815 let mut n = (*cur).prev;
2816 while !(*n).last.is_null() {
2817 n = (*n).last;
2818 }
2819 return n;
2820 }
2821 cur = (*cur).parent;
2822 if cur.is_null() {
2823 return ptr::null_mut();
2824 }
2825 if cur == (*(*ctx).doc).children {
2826 return ptr::null_mut();
2827 }
2828 if !is_ancestor(cur, (*ctx).node) {
2829 return cur;
2830 }
2831 }
2832 }
2833}
2834
2835#[no_mangle]
2852pub unsafe extern "C" fn xmlXPathNextNamespace(
2853 ctxt: *mut c_void,
2854 cur: *mut _xmlNode,
2855) -> *mut _xmlNode {
2856 let pc = pc_from(ctxt);
2857 if pc.is_null() {
2858 return ptr::null_mut();
2859 }
2860 let ctx = unsafe { (*pc).context };
2861 if ctx.is_null() {
2862 return ptr::null_mut();
2863 }
2864 use crate::abi::types::xmlElementType as ET;
2865 unsafe {
2866 let cnode = (*ctx).node;
2867 if cnode.is_null() || (*cnode).type_ != ET::XML_ELEMENT_NODE as c_int {
2868 return ptr::null_mut();
2869 }
2870 if cur.is_null() {
2871 if !(*ctx).tmpNsList.is_null() {
2872 xmlFreeImpl((*ctx).tmpNsList as *mut c_void);
2873 }
2874 (*ctx).tmpNsNr = 0;
2875 (*ctx).tmpNsList = crate::xml::tree::get_ns_list((*ctx).doc, cnode);
2876 if !(*ctx).tmpNsList.is_null() {
2877 while !(*(*ctx).tmpNsList.add((*ctx).tmpNsNr as usize)).is_null() {
2878 (*ctx).tmpNsNr += 1;
2879 }
2880 }
2881 return (&XML_XPATH_XML_NS.0) as *const crate::abi::structs::_xmlNs as *mut _xmlNode;
2882 }
2883 if (*ctx).tmpNsNr > 0 {
2884 (*ctx).tmpNsNr -= 1;
2885 return (*(*ctx).tmpNsList.add((*ctx).tmpNsNr as usize)) as *mut _xmlNode;
2886 }
2887 if !(*ctx).tmpNsList.is_null() {
2888 xmlFreeImpl((*ctx).tmpNsList as *mut c_void);
2889 }
2890 (*ctx).tmpNsList = ptr::null_mut();
2891 ptr::null_mut()
2892 }
2893}
2894
2895#[no_mangle]
2912pub unsafe extern "C" fn xmlXPathNextAttribute(
2913 ctxt: *mut c_void,
2914 cur: *mut _xmlNode,
2915) -> *mut _xmlNode {
2916 let pc = pc_from(ctxt);
2917 if pc.is_null() {
2918 return ptr::null_mut();
2919 }
2920 let ctx = unsafe { (*pc).context };
2921 if ctx.is_null() {
2922 return ptr::null_mut();
2923 }
2924 use crate::abi::types::xmlElementType as ET;
2925 unsafe {
2926 let cnode = (*ctx).node;
2927 if cnode.is_null() || (*cnode).type_ != ET::XML_ELEMENT_NODE as c_int {
2928 return ptr::null_mut();
2929 }
2930 if cur.is_null() {
2931 if cnode == (*ctx).doc as *mut _xmlNode {
2932 return ptr::null_mut();
2933 }
2934 return (*cnode).properties as *mut _xmlNode;
2935 }
2936 (*cur).next
2937 }
2938}
2939
2940#[no_mangle]
2961pub unsafe extern "C" fn xmlXPathBooleanFunction(ctxt: *mut c_void, _nargs: c_int) {
2962 let pc = pc_from(ctxt);
2963 if pc.is_null() {
2964 return;
2965 }
2966 if !check_arity(pc, 1) {
2967 return;
2968 }
2969 let cur = value_pop(pc);
2970 if cur.is_null() {
2971 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
2972 return;
2973 }
2974 let b = crate::abi::exports_xml2::object_to_xpathvalue_pub(cur).as_boolean();
2975 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
2976 value_push(pc, new_bool(b));
2977}
2978
2979#[no_mangle]
2996pub unsafe extern "C" fn xmlXPathNotFunction(ctxt: *mut c_void, _nargs: c_int) {
2997 let pc = pc_from(ctxt);
2998 if pc.is_null() {
2999 return;
3000 }
3001 if !check_arity(pc, 1) {
3002 return;
3003 }
3004 cast_top_to_boolean(pc);
3005 if (*pc).error != 0 {
3006 return;
3007 }
3008 unsafe {
3009 (*(*pc).value).boolval = if (*(*pc).value).boolval == 0 { 1 } else { 0 };
3010 }
3011}
3012
3013#[no_mangle]
3030pub unsafe extern "C" fn xmlXPathTrueFunction(ctxt: *mut c_void, _nargs: c_int) {
3031 let pc = pc_from(ctxt);
3032 if pc.is_null() {
3033 return;
3034 }
3035
3036 value_push(pc, new_bool(true));
3037}
3038
3039#[no_mangle]
3056pub unsafe extern "C" fn xmlXPathFalseFunction(ctxt: *mut c_void, _nargs: c_int) {
3057 let pc = pc_from(ctxt);
3058 if pc.is_null() {
3059 return;
3060 }
3061
3062 value_push(pc, new_bool(false));
3063}
3064
3065const unsafe fn lang_matches(lang: *const xmlChar, the_lang: *const xmlChar) -> bool {
3068 if lang.is_null() || the_lang.is_null() {
3069 return false;
3070 }
3071 let mut i = 0usize;
3072 loop {
3073 let lc = unsafe { *lang.add(i) };
3074 if lc == 0 {
3075 break;
3076 }
3077 let tc = unsafe { *the_lang.add(i) };
3078 if tc == 0 {
3079 return false;
3080 }
3081 if !lc.eq_ignore_ascii_case(&tc) {
3082 return false;
3083 }
3084 i += 1;
3085 }
3086 let c = unsafe { *the_lang.add(i) };
3087 c == 0 || c == b'-'
3088}
3089
3090#[no_mangle]
3107pub unsafe extern "C" fn xmlXPathLangFunction(ctxt: *mut c_void, _nargs: c_int) {
3108 let pc = pc_from(ctxt);
3109 if pc.is_null() {
3110 return;
3111 }
3112 let ctx = unsafe { (*pc).context };
3113 if ctx.is_null() {
3114 return;
3115 }
3116 if !check_arity(pc, 1) {
3117 return;
3118 }
3119 cast_top_to_string(pc);
3120 if (*pc).error != 0 {
3121 return;
3122 }
3123 let val = value_pop(pc);
3124 if val.is_null() {
3125 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3126 return;
3127 }
3128 let lang = unsafe { (*val).stringval };
3129 let mut ret = 0;
3130 unsafe {
3131 let mut n = (*ctx).node;
3132 let mut found: *mut xmlChar = ptr::null_mut();
3133 while !n.is_null() {
3134 let got = crate::xml::tree::get_ns_prop(
3135 n,
3136 c"lang".as_ptr() as *const xmlChar,
3137 XML_XML_NAMESPACE_BYTES.as_ptr() as *const xmlChar,
3138 );
3139 if !got.is_null() {
3140 found = got;
3141 break;
3142 }
3143 n = (*n).parent;
3144 }
3145 if !found.is_null() && lang_matches(lang, found) {
3146 ret = 1;
3147 }
3148 if !found.is_null() {
3149 xmlFreeImpl(found as *mut c_void);
3150 }
3151 }
3152 crate::abi::exports_xml2::xmlXPathFreeObject(val);
3153 value_push(pc, new_bool(ret != 0));
3154}
3155
3156#[no_mangle]
3173pub unsafe extern "C" fn xmlXPathNumberFunction(ctxt: *mut c_void, nargs: c_int) {
3174 let pc = pc_from(ctxt);
3175 if pc.is_null() {
3176 return;
3177 }
3178 let ctx = unsafe { (*pc).context };
3179 if ctx.is_null() {
3180 return;
3181 }
3182 if nargs == 0 {
3183 let node = unsafe { (*ctx).node };
3184 let res = if node.is_null() {
3185 0.0
3186 } else {
3187 let sv = node_string_value(node);
3188 crate::xml::xpath::types::string_to_number(&sv)
3189 };
3190 value_push(pc, new_number(res));
3191 return;
3192 }
3193 if !check_arity(pc, 1) {
3194 return;
3195 }
3196 cast_top_to_number(pc);
3197}
3198
3199#[no_mangle]
3216pub unsafe extern "C" fn xmlXPathSumFunction(ctxt: *mut c_void, _nargs: c_int) {
3217 let pc = pc_from(ctxt);
3218 if pc.is_null() {
3219 return;
3220 }
3221 if !check_arity(pc, 1) {
3222 return;
3223 }
3224 let cur = value_pop(pc);
3225 if cur.is_null() {
3226 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3227 return;
3228 }
3229 let typ = unsafe { (*cur).type_ };
3230 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3231 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3232 {
3233 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3234 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3235 return;
3236 }
3237 let mut res = 0.0;
3238 unsafe {
3239 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3240 if !ns.is_null() {
3241 let nr = (*ns).nodeNr;
3242 let tab = (*ns).nodeTab;
3243 if !tab.is_null() {
3244 for i in 0..nr as isize {
3245 let node = *tab.add(i as usize);
3246 let sv = node_string_value(node);
3247 res += crate::xml::xpath::types::string_to_number(&sv);
3248 }
3249 }
3250 }
3251 }
3252 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3253 value_push(pc, new_number(res));
3254}
3255
3256#[no_mangle]
3273pub unsafe extern "C" fn xmlXPathFloorFunction(ctxt: *mut c_void, _nargs: c_int) {
3274 let pc = pc_from(ctxt);
3275 if pc.is_null() {
3276 return;
3277 }
3278 if !check_arity(pc, 1) {
3279 return;
3280 }
3281 cast_top_to_number(pc);
3282 if (*pc).error != 0 {
3283 return;
3284 }
3285 unsafe {
3286 (*(*pc).value).floatval = (*(*pc).value).floatval.floor();
3287 }
3288}
3289
3290#[no_mangle]
3307pub unsafe extern "C" fn xmlXPathCeilingFunction(ctxt: *mut c_void, _nargs: c_int) {
3308 let pc = pc_from(ctxt);
3309 if pc.is_null() {
3310 return;
3311 }
3312 if !check_arity(pc, 1) {
3313 return;
3314 }
3315 cast_top_to_number(pc);
3316 if (*pc).error != 0 {
3317 return;
3318 }
3319 unsafe {
3320 (*(*pc).value).floatval = (*(*pc).value).floatval.ceil();
3321 }
3322}
3323
3324#[no_mangle]
3341pub unsafe extern "C" fn xmlXPathRoundFunction(ctxt: *mut c_void, _nargs: c_int) {
3342 let pc = pc_from(ctxt);
3343 if pc.is_null() {
3344 return;
3345 }
3346 if !check_arity(pc, 1) {
3347 return;
3348 }
3349 cast_top_to_number(pc);
3350 if (*pc).error != 0 {
3351 return;
3352 }
3353 unsafe {
3354 let f = (*(*pc).value).floatval;
3355 if (-0.5..0.5).contains(&f) {
3356 (*(*pc).value).floatval *= 0.0;
3358 } else {
3359 let mut rounded = f.floor();
3360 if f - rounded >= 0.5 {
3361 rounded += 1.0;
3362 }
3363 (*(*pc).value).floatval = rounded;
3364 }
3365 }
3366}
3367
3368#[no_mangle]
3385pub unsafe extern "C" fn xmlXPathLastFunction(ctxt: *mut c_void, _nargs: c_int) {
3386 let pc = pc_from(ctxt);
3387 if pc.is_null() {
3388 return;
3389 }
3390 let ctx = unsafe { (*pc).context };
3391 if ctx.is_null() {
3392 return;
3393 }
3394
3395 value_push(pc, new_number(unsafe { (*ctx).contextSize } as f64));
3396}
3397
3398#[no_mangle]
3415pub unsafe extern "C" fn xmlXPathPositionFunction(ctxt: *mut c_void, _nargs: c_int) {
3416 let pc = pc_from(ctxt);
3417 if pc.is_null() {
3418 return;
3419 }
3420 let ctx = unsafe { (*pc).context };
3421 if ctx.is_null() {
3422 return;
3423 }
3424
3425 value_push(pc, new_number(unsafe { (*ctx).proximityPosition } as f64));
3426}
3427
3428#[no_mangle]
3445pub unsafe extern "C" fn xmlXPathCountFunction(ctxt: *mut c_void, _nargs: c_int) {
3446 let pc = pc_from(ctxt);
3447 if pc.is_null() {
3448 return;
3449 }
3450 if !check_arity(pc, 1) {
3451 return;
3452 }
3453 let cur = value_pop(pc);
3454 if cur.is_null() {
3455 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3456 return;
3457 }
3458 let typ = unsafe { (*cur).type_ };
3459 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3460 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3461 {
3462 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3463 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3464 return;
3465 }
3466 let count = unsafe {
3467 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3468 if ns.is_null() {
3469 0
3470 } else {
3471 (*ns).nodeNr
3472 }
3473 };
3474 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3475 value_push(pc, new_number(count as f64));
3476}
3477
3478unsafe fn get_elements_by_ids(doc: *mut _xmlDoc, ids: *const xmlChar) -> *mut _xmlNodeSet {
3481 use crate::abi::types::xmlElementType as ET;
3482 if ids.is_null() {
3483 return ptr::null_mut();
3484 }
3485 let mut out = NodeSet::new();
3486 unsafe {
3487 let mut p = ids;
3488 while *p != 0 {
3489 while is_blank_ch(*p) {
3490 p = p.add(1);
3491 }
3492 if *p == 0 {
3493 break;
3494 }
3495 let start = p;
3496 while *p != 0 && !is_blank_ch(*p) {
3497 p = p.add(1);
3498 }
3499 let id_c = crate::xml::string::xml_strndup(start, p.offset_from(start) as usize);
3500 if id_c.is_null() {
3501 break;
3502 }
3503 let attr = get_id(doc, id_c);
3504 xmlFreeImpl(id_c as *mut c_void);
3505 if !attr.is_null() {
3506 let t = (*attr).type_;
3507 let elem = if t == ET::XML_ATTRIBUTE_NODE as c_int {
3508 (*attr).parent
3509 } else if t == ET::XML_ELEMENT_NODE as c_int {
3510 attr as *mut _xmlNode
3511 } else {
3512 ptr::null_mut()
3513 };
3514 if !elem.is_null() {
3515 out.push(elem);
3516 }
3517 }
3518 }
3519 }
3520 out.to_raw()
3521}
3522
3523#[no_mangle]
3540pub unsafe extern "C" fn xmlXPathIdFunction(ctxt: *mut c_void, _nargs: c_int) {
3541 let pc = pc_from(ctxt);
3542 if pc.is_null() {
3543 return;
3544 }
3545 let ctx = unsafe { (*pc).context };
3546 if ctx.is_null() {
3547 return;
3548 }
3549 if !check_arity(pc, 1) {
3550 return;
3551 }
3552 let obj = value_pop(pc);
3553 if obj.is_null() {
3554 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3555 return;
3556 }
3557 let doc = unsafe { (*ctx).doc };
3558 let v = crate::abi::exports_xml2::object_to_xpathvalue_pub(obj);
3559 crate::abi::exports_xml2::xmlXPathFreeObject(obj);
3560 match &v {
3561 XPathValue::NodeSet(ns) => {
3562 let mut merged = NodeSet::new();
3563 for n in ns.iter() {
3564 let sv = node_string_value(n);
3565 let c = dup_rust_string(&sv);
3566 let sub = get_elements_by_ids(doc, c);
3567 xmlFreeImpl(c as *mut c_void);
3568 if !sub.is_null() {
3569 let sub_internal = node_set_to_internal(sub);
3570 for m in sub_internal.iter() {
3571 if !merged.contains(m) {
3572 merged.push(m);
3573 }
3574 }
3575 crate::abi::exports_xml2::xmlXPathFreeNodeSet(sub);
3577 }
3578 }
3579 value_push(
3580 pc,
3581 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(merged)),
3582 );
3583 }
3584 _ => {
3585 let s = v.as_string();
3586 let c = dup_rust_string(&s);
3587 let ret = get_elements_by_ids(doc, c);
3588 xmlFreeImpl(c as *mut c_void);
3589 if ret.is_null() {
3590 value_push(
3591 pc,
3592 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(
3593 NodeSet::new(),
3594 )),
3595 );
3596 } else {
3597 let obj2 = crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(
3598 node_set_to_internal(ret),
3599 ));
3600 crate::abi::exports_xml2::xmlXPathFreeNodeSet(ret);
3601 value_push(pc, obj2);
3602 }
3603 }
3604 }
3605}
3606
3607unsafe fn node_local_name(node: *mut _xmlNode) -> String {
3610 use crate::abi::types::xmlElementType as ET;
3611 if node.is_null() {
3612 return String::new();
3613 }
3614 unsafe {
3615 match (*node).type_ {
3616 t if t == ET::XML_ELEMENT_NODE as c_int
3617 || t == ET::XML_ATTRIBUTE_NODE as c_int
3618 || t == ET::XML_PI_NODE as c_int =>
3619 {
3620 let name = (*node).name;
3621 if name.is_null() || *name == b' ' {
3622 String::new()
3623 } else {
3624 let s = CStr::from_ptr(name as *const c_char)
3625 .to_string_lossy()
3626 .into_owned();
3627 match s.split_once(':') {
3628 Some((_, local)) => local.to_string(),
3629 None => s,
3630 }
3631 }
3632 }
3633 t if t == ET::XML_NAMESPACE_DECL as c_int => {
3634 let ns = node as *mut crate::abi::structs::_xmlNs;
3635 let p = (*ns).prefix;
3636 if p.is_null() {
3637 String::new()
3638 } else {
3639 CStr::from_ptr(p as *const c_char)
3640 .to_string_lossy()
3641 .into_owned()
3642 }
3643 }
3644 _ => String::new(),
3645 }
3646 }
3647}
3648
3649#[no_mangle]
3666pub unsafe extern "C" fn xmlXPathLocalNameFunction(ctxt: *mut c_void, nargs: c_int) {
3667 let pc = pc_from(ctxt);
3668 if pc.is_null() {
3669 return;
3670 }
3671 let ctx = unsafe { (*pc).context };
3672 if ctx.is_null() {
3673 return;
3674 }
3675 if nargs == 0 {
3676 value_push(
3677 pc,
3678 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(NodeSet::singleton(
3679 unsafe { (*ctx).node },
3680 ))),
3681 );
3682 }
3684
3685 if !check_arity(pc, 1) {
3686 return;
3687 }
3688 let cur = value_pop(pc);
3689 if cur.is_null() {
3690 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3691 return;
3692 }
3693 let typ = unsafe { (*cur).type_ };
3694 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3695 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3696 {
3697 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3698 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3699 return;
3700 }
3701 let name = unsafe {
3702 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3703 if ns.is_null() || (*ns).nodeNr == 0 {
3704 String::new()
3705 } else {
3706 node_local_name(*(*ns).nodeTab)
3707 }
3708 };
3709 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3710 let out = dup_rust_string(&name);
3711 value_push(pc, xmlXPathWrapString(out));
3712}
3713
3714unsafe fn node_namespace_uri(node: *mut _xmlNode) -> String {
3716 use crate::abi::types::xmlElementType as ET;
3717 if node.is_null() {
3718 return String::new();
3719 }
3720 unsafe {
3721 match (*node).type_ {
3722 t if t == ET::XML_ELEMENT_NODE as c_int || t == ET::XML_ATTRIBUTE_NODE as c_int => {
3723 let ns = (*node).ns;
3724 if ns.is_null() || (*ns).href.is_null() {
3725 String::new()
3726 } else {
3727 CStr::from_ptr((*ns).href as *const c_char)
3728 .to_string_lossy()
3729 .into_owned()
3730 }
3731 }
3732 t if t == ET::XML_NAMESPACE_DECL as c_int => {
3733 let ns = node as *mut crate::abi::structs::_xmlNs;
3734 if (*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 _ => String::new(),
3743 }
3744 }
3745}
3746
3747#[no_mangle]
3764pub unsafe extern "C" fn xmlXPathNamespaceURIFunction(ctxt: *mut c_void, nargs: c_int) {
3765 let pc = pc_from(ctxt);
3766 if pc.is_null() {
3767 return;
3768 }
3769 let ctx = unsafe { (*pc).context };
3770 if ctx.is_null() {
3771 return;
3772 }
3773 if nargs == 0 {
3774 value_push(
3775 pc,
3776 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(NodeSet::singleton(
3777 unsafe { (*ctx).node },
3778 ))),
3779 );
3780 }
3781
3782 if !check_arity(pc, 1) {
3783 return;
3784 }
3785 let cur = value_pop(pc);
3786 if cur.is_null() {
3787 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3788 return;
3789 }
3790 let typ = unsafe { (*cur).type_ };
3791 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3792 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3793 {
3794 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3795 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3796 return;
3797 }
3798 let uri = unsafe {
3799 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3800 if ns.is_null() || (*ns).nodeNr == 0 {
3801 String::new()
3802 } else {
3803 node_namespace_uri(*(*ns).nodeTab)
3804 }
3805 };
3806 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3807 let out = dup_rust_string(&uri);
3808 value_push(pc, xmlXPathWrapString(out));
3809}
3810
3811#[no_mangle]
3828pub unsafe extern "C" fn xmlXPathStringFunction(ctxt: *mut c_void, nargs: c_int) {
3829 let pc = pc_from(ctxt);
3830 if pc.is_null() {
3831 return;
3832 }
3833 let ctx = unsafe { (*pc).context };
3834 if ctx.is_null() {
3835 return;
3836 }
3837 if nargs == 0 {
3838 let node = unsafe { (*ctx).node };
3839 let sv = if node.is_null() {
3840 String::new()
3841 } else {
3842 node_string_value(node)
3843 };
3844 let out = dup_rust_string(&sv);
3845 value_push(pc, xmlXPathWrapString(out));
3846 return;
3847 }
3848 if !check_arity(pc, 1) {
3849 return;
3850 }
3851 cast_top_to_string(pc);
3852}
3853
3854#[no_mangle]
3871pub unsafe extern "C" fn xmlXPathStringLengthFunction(ctxt: *mut c_void, nargs: c_int) {
3872 let pc = pc_from(ctxt);
3873 if pc.is_null() {
3874 return;
3875 }
3876 let ctx = unsafe { (*pc).context };
3877 if ctx.is_null() {
3878 return;
3879 }
3880 if nargs == 0 {
3881 let node = unsafe { (*ctx).node };
3882 let len = if node.is_null() {
3883 0
3884 } else {
3885 let sv = node_string_value(node);
3886 sv.chars().count()
3887 };
3888 value_push(pc, new_number(len as f64));
3889 return;
3890 }
3891 if !check_arity(pc, 1) {
3892 return;
3893 }
3894 cast_top_to_string(pc);
3895 if (*pc).error != 0 {
3896 return;
3897 }
3898 let len = unsafe {
3899 let s = (*(*pc).value).stringval;
3900 if s.is_null() {
3901 0
3902 } else {
3903 let sv = CStr::from_ptr(s as *const c_char).to_string_lossy();
3904 sv.chars().count()
3905 }
3906 };
3907 let cur = value_pop(pc);
3908 if !cur.is_null() {
3909 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3910 }
3911 value_push(pc, new_number(len as f64));
3912}
3913
3914#[no_mangle]
3931pub unsafe extern "C" fn xmlXPathConcatFunction(ctxt: *mut c_void, nargs: c_int) {
3932 let pc = pc_from(ctxt);
3933 if pc.is_null() {
3934 return;
3935 }
3936 if nargs < 2 && !check_arity(pc, 2) {
3937 return;
3938 }
3939 if !check_arity(pc, nargs) {
3940 return;
3941 }
3942 let mut parts: Vec<String> = Vec::with_capacity(nargs as usize);
3943 for _ in 0..nargs {
3944 cast_top_to_string(pc);
3945 if (*pc).error != 0 {
3946 return;
3947 }
3948 let v = crate::abi::exports_xml2::object_to_xpathvalue_pub(unsafe { (*pc).value });
3949 let s = v.as_string();
3950 let obj = value_pop(pc);
3951 if !obj.is_null() {
3952 crate::abi::exports_xml2::xmlXPathFreeObject(obj);
3953 }
3954 parts.push(s);
3955 }
3956 parts.reverse();
3957 let joined = parts.concat();
3958 let out = dup_rust_string(&joined);
3959 value_push(pc, xmlXPathWrapString(out));
3960}
3961
3962#[no_mangle]
3979pub unsafe extern "C" fn xmlXPathContainsFunction(ctxt: *mut c_void, _nargs: c_int) {
3980 let pc = pc_from(ctxt);
3981 if pc.is_null() {
3982 return;
3983 }
3984 if !check_arity(pc, 2) {
3985 return;
3986 }
3987 cast_top_to_string(pc);
3988 if (*pc).error != 0 {
3989 return;
3990 }
3991 let needle = value_pop(pc);
3992 cast_top_to_string(pc);
3993 if (*pc).error != 0 {
3994 if !needle.is_null() {
3995 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
3996 }
3997 return;
3998 }
3999 let hay = value_pop(pc);
4000 let found = if hay.is_null() || needle.is_null() {
4001 false
4002 } else {
4003 unsafe { !cstr_find((*hay).stringval, (*needle).stringval).is_null() }
4004 };
4005 if !hay.is_null() {
4006 crate::abi::exports_xml2::xmlXPathFreeObject(hay);
4007 }
4008 if !needle.is_null() {
4009 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
4010 }
4011 value_push(pc, new_bool(found));
4012}
4013
4014#[no_mangle]
4031pub unsafe extern "C" fn xmlXPathStartsWithFunction(ctxt: *mut c_void, _nargs: c_int) {
4032 let pc = pc_from(ctxt);
4033 if pc.is_null() {
4034 return;
4035 }
4036 if !check_arity(pc, 2) {
4037 return;
4038 }
4039 cast_top_to_string(pc);
4040 if (*pc).error != 0 {
4041 return;
4042 }
4043 let needle = value_pop(pc);
4044 cast_top_to_string(pc);
4045 if (*pc).error != 0 {
4046 if !needle.is_null() {
4047 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
4048 }
4049 return;
4050 }
4051 let hay = value_pop(pc);
4052 let found = if hay.is_null() || needle.is_null() {
4053 false
4054 } else {
4055 unsafe { crate::xml::string::xml_str_starts_with((*hay).stringval, (*needle).stringval) }
4056 };
4057 if !hay.is_null() {
4058 crate::abi::exports_xml2::xmlXPathFreeObject(hay);
4059 }
4060 if !needle.is_null() {
4061 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
4062 }
4063 value_push(pc, new_bool(found));
4064}
4065
4066#[no_mangle]
4083pub unsafe extern "C" fn xmlXPathSubstringFunction(ctxt: *mut c_void, nargs: c_int) {
4084 let pc = pc_from(ctxt);
4085 if pc.is_null() {
4086 return;
4087 }
4088 if nargs < 2 {
4089 if !check_arity(pc, 2) {
4090 return;
4091 }
4092 } else if nargs > 3 && !check_arity(pc, 3) {
4093 return;
4094 }
4095 let mut le = 0.0;
4096 if nargs == 3 {
4097 cast_top_to_number(pc);
4098 if (*pc).error != 0 {
4099 return;
4100 }
4101 let len_obj = value_pop(pc);
4102 if !len_obj.is_null() {
4103 le = unsafe { (*len_obj).floatval };
4104 crate::abi::exports_xml2::xmlXPathFreeObject(len_obj);
4105 }
4106 }
4107 cast_top_to_number(pc);
4108 if (*pc).error != 0 {
4109 return;
4110 }
4111 let start_obj = value_pop(pc);
4112 let in_ = if start_obj.is_null() {
4113 f64::NAN
4114 } else {
4115 let v = unsafe { (*start_obj).floatval };
4116 crate::abi::exports_xml2::xmlXPathFreeObject(start_obj);
4117 v
4118 };
4119 cast_top_to_string(pc);
4120 if (*pc).error != 0 {
4121 return;
4122 }
4123 let str_obj = value_pop(pc);
4124 let s = if str_obj.is_null() {
4125 String::new()
4126 } else {
4127 let v = unsafe { CStr::from_ptr((*str_obj).stringval as *const c_char) }
4128 .to_string_lossy()
4129 .into_owned();
4130 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
4131 v
4132 };
4133
4134 let int_max = i32::MAX as f64;
4135 let mut i: i64 = 1;
4136 let mut j: i64 = i32::MAX as i64;
4137 #[allow(clippy::neg_cmp_op_on_partial_ord)]
4141 if !(in_ < int_max) {
4142 i = i32::MAX as i64;
4143 } else if in_ >= 1.0 {
4144 i = in_ as i64;
4145 if in_ - in_.floor() >= 0.5 {
4146 i += 1;
4147 }
4148 }
4149 if nargs == 3 {
4150 let mut rin = in_.floor();
4151 if in_ - rin >= 0.5 {
4152 rin += 1.0;
4153 }
4154 let mut rle = le.floor();
4155 if le - rle >= 0.5 {
4156 rle += 1.0;
4157 }
4158 let end = rin + rle;
4159 #[allow(clippy::neg_cmp_op_on_partial_ord)]
4160 if !(end >= 1.0) {
4161 j = 1;
4162 } else if end < int_max {
4163 j = end as i64;
4164 }
4165 }
4166 i -= 1;
4167 j -= 1;
4168 let chars: Vec<char> = s.chars().collect();
4169 let slen = chars.len() as i64;
4170 let out = if i < j && i < slen {
4171 let start_i = i.max(0) as usize;
4172 let end_i = (j.min(slen)).max(start_i as i64) as usize;
4173 chars[start_i..end_i].iter().collect()
4174 } else {
4175 String::new()
4176 };
4177 let c = dup_rust_string(&out);
4178 value_push(pc, xmlXPathWrapString(c));
4179}
4180
4181#[no_mangle]
4198pub unsafe extern "C" fn xmlXPathSubstringBeforeFunction(ctxt: *mut c_void, _nargs: c_int) {
4199 let pc = pc_from(ctxt);
4200 if pc.is_null() {
4201 return;
4202 }
4203 if !check_arity(pc, 2) {
4204 return;
4205 }
4206 cast_top_to_string(pc);
4207 if (*pc).error != 0 {
4208 return;
4209 }
4210 let find = value_pop(pc);
4211 cast_top_to_string(pc);
4212 if (*pc).error != 0 {
4213 if !find.is_null() {
4214 crate::abi::exports_xml2::xmlXPathFreeObject(find);
4215 }
4216 return;
4217 }
4218 let str_obj = value_pop(pc);
4219 let out: String = if str_obj.is_null() || find.is_null() {
4220 String::new()
4221 } else {
4222 unsafe {
4223 let hay = (*str_obj).stringval;
4224 let needle = (*find).stringval;
4225 let point = cstr_find(hay, needle);
4226 if point.is_null() {
4227 String::new()
4228 } else {
4229 let len = point.offset_from(hay) as usize;
4230 let bytes = core::slice::from_raw_parts(hay as *const u8, len);
4231 String::from_utf8_lossy(bytes).into_owned()
4232 }
4233 }
4234 };
4235 if !str_obj.is_null() {
4236 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
4237 }
4238 if !find.is_null() {
4239 crate::abi::exports_xml2::xmlXPathFreeObject(find);
4240 }
4241 let c = dup_rust_string(&out);
4242 value_push(pc, xmlXPathWrapString(c));
4243}
4244
4245#[no_mangle]
4262pub unsafe extern "C" fn xmlXPathSubstringAfterFunction(ctxt: *mut c_void, _nargs: c_int) {
4263 let pc = pc_from(ctxt);
4264 if pc.is_null() {
4265 return;
4266 }
4267 if !check_arity(pc, 2) {
4268 return;
4269 }
4270 cast_top_to_string(pc);
4271 if (*pc).error != 0 {
4272 return;
4273 }
4274 let find = value_pop(pc);
4275 cast_top_to_string(pc);
4276 if (*pc).error != 0 {
4277 if !find.is_null() {
4278 crate::abi::exports_xml2::xmlXPathFreeObject(find);
4279 }
4280 return;
4281 }
4282 let str_obj = value_pop(pc);
4283 let out: String = if str_obj.is_null() || find.is_null() {
4284 String::new()
4285 } else {
4286 unsafe {
4287 let hay = (*str_obj).stringval;
4288 let needle = (*find).stringval;
4289 let point = cstr_find(hay, needle);
4290 if point.is_null() {
4291 String::new()
4292 } else {
4293 let nlen = crate::xml::string::xml_strlen(needle);
4294 let rest = point.add(nlen);
4295 let len = crate::xml::string::xml_strlen(rest);
4296 let bytes = core::slice::from_raw_parts(rest, len);
4297 String::from_utf8_lossy(bytes).into_owned()
4298 }
4299 }
4300 };
4301 if !str_obj.is_null() {
4302 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
4303 }
4304 if !find.is_null() {
4305 crate::abi::exports_xml2::xmlXPathFreeObject(find);
4306 }
4307 let c = dup_rust_string(&out);
4308 value_push(pc, xmlXPathWrapString(c));
4309}
4310
4311#[no_mangle]
4328pub unsafe extern "C" fn xmlXPathNormalizeFunction(ctxt: *mut c_void, nargs: c_int) {
4329 let pc = pc_from(ctxt);
4330 if pc.is_null() {
4331 return;
4332 }
4333 let ctx = unsafe { (*pc).context };
4334 if ctx.is_null() {
4335 return;
4336 }
4337 if nargs == 0 {
4338 let node = unsafe { (*ctx).node };
4339 let sv = if node.is_null() {
4340 String::new()
4341 } else {
4342 node_string_value(node)
4343 };
4344 let c = dup_rust_string(&sv);
4345 value_push(pc, xmlXPathWrapString(c));
4346 }
4348
4349 if !check_arity(pc, 1) {
4350 return;
4351 }
4352 cast_top_to_string(pc);
4353 if (*pc).error != 0 {
4354 return;
4355 }
4356 let s = unsafe {
4357 let p = (*(*pc).value).stringval;
4358 if p.is_null() {
4359 String::new()
4360 } else {
4361 CStr::from_ptr(p as *const c_char)
4362 .to_string_lossy()
4363 .into_owned()
4364 }
4365 };
4366 let mut out = String::with_capacity(s.len());
4368 let mut blank = false;
4369 let mut started = false;
4370 for c in s.chars() {
4371 let is_b = c == ' ' || c == '\t' || c == '\n' || c == '\r';
4372 if is_b {
4373 if started {
4374 blank = true;
4375 }
4376 } else {
4377 if blank {
4378 out.push(' ');
4379 blank = false;
4380 }
4381 out.push(c);
4382 started = true;
4383 }
4384 }
4385 unsafe {
4386 let val = (*pc).value;
4387 if !(*val).stringval.is_null() {
4388 xmlFreeImpl((*val).stringval as *mut c_void);
4389 }
4390 (*val).stringval = dup_rust_string(&out);
4391 }
4392}
4393
4394#[no_mangle]
4411pub unsafe extern "C" fn xmlXPathTranslateFunction(ctxt: *mut c_void, _nargs: c_int) {
4412 let pc = pc_from(ctxt);
4413 if pc.is_null() {
4414 return;
4415 }
4416 if !check_arity(pc, 3) {
4417 return;
4418 }
4419 cast_top_to_string(pc);
4420 if (*pc).error != 0 {
4421 return;
4422 }
4423 let to = value_pop(pc);
4424 cast_top_to_string(pc);
4425 if (*pc).error != 0 {
4426 if !to.is_null() {
4427 crate::abi::exports_xml2::xmlXPathFreeObject(to);
4428 }
4429 return;
4430 }
4431 let from = value_pop(pc);
4432 cast_top_to_string(pc);
4433 if (*pc).error != 0 {
4434 if !to.is_null() {
4435 crate::abi::exports_xml2::xmlXPathFreeObject(to);
4436 }
4437 if !from.is_null() {
4438 crate::abi::exports_xml2::xmlXPathFreeObject(from);
4439 }
4440 return;
4441 }
4442 let str_obj = value_pop(pc);
4443 let (s, f, t) = unsafe {
4444 let s = if str_obj.is_null() || (*str_obj).stringval.is_null() {
4445 String::new()
4446 } else {
4447 CStr::from_ptr((*str_obj).stringval as *const c_char)
4448 .to_string_lossy()
4449 .into_owned()
4450 };
4451 let f = if from.is_null() || (*from).stringval.is_null() {
4452 String::new()
4453 } else {
4454 CStr::from_ptr((*from).stringval as *const c_char)
4455 .to_string_lossy()
4456 .into_owned()
4457 };
4458 let t = if to.is_null() || (*to).stringval.is_null() {
4459 String::new()
4460 } else {
4461 CStr::from_ptr((*to).stringval as *const c_char)
4462 .to_string_lossy()
4463 .into_owned()
4464 };
4465 (s, f, t)
4466 };
4467 if !str_obj.is_null() {
4468 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
4469 }
4470 if !from.is_null() {
4471 crate::abi::exports_xml2::xmlXPathFreeObject(from);
4472 }
4473 if !to.is_null() {
4474 crate::abi::exports_xml2::xmlXPathFreeObject(to);
4475 }
4476 let from_chars: Vec<char> = f.chars().collect();
4477 let to_chars: Vec<char> = t.chars().collect();
4478 let out: String = s
4481 .chars()
4482 .filter_map(|c| match from_chars.iter().position(|&x| x == c) {
4483 Some(i) if i < to_chars.len() => Some(to_chars[i]),
4484 Some(_) => None,
4485 _ => Some(c),
4486 })
4487 .collect();
4488 let c = dup_rust_string(&out);
4489 value_push(pc, xmlXPathWrapString(c));
4490}
4491
4492#[no_mangle]
4510pub const unsafe extern "C" fn xmlXPathRegisterAllFunctions(_ctxt: *mut _xmlXPathContext) {}
4511
4512unsafe fn standard_function_pointer(
4515 name: &str,
4516) -> Option<unsafe extern "C" fn(*mut c_void, c_int)> {
4517 let f: unsafe extern "C" fn(*mut c_void, c_int) = match name {
4518 "boolean" => xmlXPathBooleanFunction,
4519 "not" => xmlXPathNotFunction,
4520 "true" => xmlXPathTrueFunction,
4521 "false" => xmlXPathFalseFunction,
4522 "lang" => xmlXPathLangFunction,
4523 "number" => xmlXPathNumberFunction,
4524 "sum" => xmlXPathSumFunction,
4525 "floor" => xmlXPathFloorFunction,
4526 "ceiling" => xmlXPathCeilingFunction,
4527 "round" => xmlXPathRoundFunction,
4528 "last" => xmlXPathLastFunction,
4529 "position" => xmlXPathPositionFunction,
4530 "count" => xmlXPathCountFunction,
4531 "id" => xmlXPathIdFunction,
4532 "local-name" => xmlXPathLocalNameFunction,
4533 "namespace-uri" => xmlXPathNamespaceURIFunction,
4534 "string" => xmlXPathStringFunction,
4535 "string-length" => xmlXPathStringLengthFunction,
4536 "concat" => xmlXPathConcatFunction,
4537 "contains" => xmlXPathContainsFunction,
4538 "starts-with" => xmlXPathStartsWithFunction,
4539 "substring" => xmlXPathSubstringFunction,
4540 "substring-before" => xmlXPathSubstringBeforeFunction,
4541 "substring-after" => xmlXPathSubstringAfterFunction,
4542 "normalize-space" => xmlXPathNormalizeFunction,
4543 "translate" => xmlXPathTranslateFunction,
4544 _ => return None,
4545 };
4546 Some(f)
4547}
4548
4549#[no_mangle]
4555pub unsafe extern "C" fn xmlXPathFunctionLookup(
4556 ctxt: *mut _xmlXPathContext,
4557 name: *const xmlChar,
4558) -> Option<unsafe extern "C" fn(*mut c_void, c_int)> {
4559 xmlXPathFunctionLookupNS(ctxt, name, ptr::null())
4560}
4561
4562#[no_mangle]
4568pub unsafe extern "C" fn xmlXPathFunctionLookupNS(
4569 ctxt: *mut _xmlXPathContext,
4570 name: *const xmlChar,
4571 ns_uri: *const xmlChar,
4572) -> Option<unsafe extern "C" fn(*mut c_void, c_int)> {
4573 if ctxt.is_null() || name.is_null() {
4574 return None;
4575 }
4576 let name_str = match CStr::from_ptr(name as *const c_char).to_str() {
4577 Ok(s) => s.to_string(),
4578 Err(_) => return None,
4579 };
4580 if ns_uri.is_null() {
4581 if let Some(f) = standard_function_pointer(&name_str) {
4582 return Some(f);
4583 }
4584 }
4585 if let Some(f) = (*ctxt).funcLookupFunc {
4587 let ret = f((*ctxt).funcLookupData, name, ns_uri);
4588 if !ret.is_null() {
4589 let fp =
4591 std::mem::transmute::<*mut c_void, unsafe extern "C" fn(*mut c_void, c_int)>(ret);
4592 return Some(fp);
4593 }
4594 }
4595 let qualified = if ns_uri.is_null() {
4596 name_str
4597 } else {
4598 let ns = match CStr::from_ptr(ns_uri as *const c_char).to_str() {
4599 Ok(s) => s,
4600 Err(_) => return None,
4601 };
4602 format!("{{{}}}{}", ns, name_str)
4603 };
4604 crate::abi::exports_xml2::xpath_cfunc_lookup((*ctxt).extra, &qualified)
4605}
4606
4607#[no_mangle]
4621pub unsafe extern "C" fn xmlXPathCtxtCompile(
4622 _ctxt: *mut _xmlXPathContext,
4623 str_: *const xmlChar,
4624) -> *mut c_void {
4625 crate::abi::exports_xml2::xmlXPathCompile(str_)
4626}
4627
4628#[no_mangle]
4634pub unsafe extern "C" fn xmlXPathCompiledEval(
4635 comp: *mut c_void,
4636 ctx: *mut _xmlXPathContext,
4637) -> *mut _xmlXPathObject {
4638 if comp.is_null() || ctx.is_null() {
4639 return ptr::null_mut();
4640 }
4641 let internal = (*ctx).extra as *mut XPathContext;
4642 if internal.is_null() {
4643 return ptr::null_mut();
4644 }
4645 let internal = &mut *internal;
4646 let registry = crate::abi::exports_xml2::xpath_compiled_registry();
4647 let map = registry.lock();
4648 match map.get(&(comp as u64)) {
4649 Some(compiled) => match crate::xml::xpath::evaluate(compiled, internal) {
4650 Some(val) => crate::abi::exports_xml2::xpath_to_object_pub(val),
4651 None => ptr::null_mut(),
4652 },
4653 None => ptr::null_mut(),
4654 }
4655}
4656
4657#[no_mangle]
4665pub unsafe extern "C" fn xmlXPathCompiledEvalToBoolean(
4666 comp: *mut c_void,
4667 ctxt: *mut _xmlXPathContext,
4668) -> c_int {
4669 let obj = xmlXPathCompiledEval(comp, ctxt);
4670 if obj.is_null() {
4671 return -1;
4672 }
4673 let b = crate::abi::exports_xml2::object_to_xpathvalue_pub(obj).as_boolean();
4674 crate::abi::exports_xml2::xmlXPathFreeObject(obj);
4675 b as c_int
4676}
4677
4678#[no_mangle]
4685pub unsafe extern "C" fn xmlXPathSetContextNode(
4686 node: *mut _xmlNode,
4687 ctx: *mut _xmlXPathContext,
4688) -> c_int {
4689 if node.is_null() || ctx.is_null() {
4690 return -1;
4691 }
4692 if (*node).doc != (*ctx).doc {
4693 return -1;
4694 }
4695 (*ctx).node = node;
4696 let internal = (*ctx).extra as *mut XPathContext;
4697 if !internal.is_null() {
4698 (*internal).context_node = node;
4699 }
4700 0
4701}
4702
4703#[no_mangle]
4709pub unsafe extern "C" fn xmlXPathNodeEval(
4710 node: *mut _xmlNode,
4711 str_: *const xmlChar,
4712 ctx: *mut _xmlXPathContext,
4713) -> *mut _xmlXPathObject {
4714 if str_.is_null() {
4715 return ptr::null_mut();
4716 }
4717 if xmlXPathSetContextNode(node, ctx) < 0 {
4718 return ptr::null_mut();
4719 }
4720 crate::abi::exports_xml2::xmlXPathEvalExpression(str_, ctx)
4721}
4722
4723#[no_mangle]
4732pub unsafe extern "C" fn xmlXPathContextSetCache(
4733 ctxt: *mut _xmlXPathContext,
4734 active: c_int,
4735 _value: c_int,
4736 _options: c_int,
4737) -> c_int {
4738 if ctxt.is_null() {
4739 return -1;
4740 }
4741 (*ctxt).cache = if active != 0 {
4742 (&XML_XPATH_XML_NS.0) as *const crate::abi::structs::_xmlNs as *mut c_void
4743 } else {
4744 ptr::null_mut()
4745 };
4746 0
4747}
4748
4749#[no_mangle]
4755pub unsafe extern "C" fn xmlXPathRegisterFuncLookup(
4756 ctxt: *mut _xmlXPathContext,
4757 f: Option<crate::abi::callbacks::xmlXPathFuncLookupFunc>,
4758 data: *mut c_void,
4759) {
4760 if ctxt.is_null() {
4761 return;
4762 }
4763 (*ctxt).funcLookupFunc = f;
4764 (*ctxt).funcLookupData = data;
4765 let internal = (*ctxt).extra as *mut XPathContext;
4766 if !internal.is_null() {
4767 (*internal).func_lookup_func = f;
4768 (*internal).func_lookup_data = data;
4769 }
4770}
4771
4772#[no_mangle]
4778pub unsafe extern "C" fn xmlXPathRegisterVariableLookup(
4779 ctxt: *mut _xmlXPathContext,
4780 f: Option<crate::abi::callbacks::xmlXPathVariableLookupFunc>,
4781 data: *mut c_void,
4782) {
4783 if ctxt.is_null() {
4784 return;
4785 }
4786 (*ctxt).varLookupFunc = f;
4787 (*ctxt).varLookupData = data;
4788 let internal = (*ctxt).extra as *mut XPathContext;
4789 if !internal.is_null() {
4790 (*internal).var_lookup_func = f;
4791 (*internal).var_lookup_data = data;
4792 }
4793}
4794
4795#[no_mangle]
4801pub unsafe extern "C" fn xmlXPathRegisterVariableNS(
4802 ctxt: *mut _xmlXPathContext,
4803 name: *const xmlChar,
4804 ns_uri: *const xmlChar,
4805 value: *mut _xmlXPathObject,
4806) -> c_int {
4807 if ctxt.is_null() || name.is_null() || value.is_null() {
4808 return -1;
4809 }
4810 let internal = (*ctxt).extra as *mut XPathContext;
4811 if internal.is_null() {
4812 return -1;
4813 }
4814 let internal = &mut *internal;
4815 let name_str = match CStr::from_ptr(name as *const c_char).to_str() {
4816 Ok(s) => s.to_string(),
4817 Err(_) => return -1,
4818 };
4819 let qualified = if ns_uri.is_null() {
4820 name_str
4821 } else {
4822 match CStr::from_ptr(ns_uri as *const c_char).to_str() {
4823 Ok(s) => format!("{{{}}}{}", s, name_str),
4824 Err(_) => return -1,
4825 }
4826 };
4827 let xpath_val = crate::abi::exports_xml2::object_to_xpathvalue_pub(value);
4828 internal.register_variable(&qualified, xpath_val);
4829 0
4830}
4831
4832#[no_mangle]
4838pub unsafe extern "C" fn xmlXPathVariableLookup(
4839 ctxt: *mut _xmlXPathContext,
4840 name: *const xmlChar,
4841) -> *mut _xmlXPathObject {
4842 if ctxt.is_null() {
4843 return ptr::null_mut();
4844 }
4845 if let Some(f) = (*ctxt).varLookupFunc {
4846 let ret = f((*ctxt).varLookupData, name, ptr::null());
4847 return ret;
4848 }
4849 xmlXPathVariableLookupNS(ctxt, name, ptr::null())
4850}
4851
4852#[no_mangle]
4858pub unsafe extern "C" fn xmlXPathVariableLookupNS(
4859 ctxt: *mut _xmlXPathContext,
4860 name: *const xmlChar,
4861 ns_uri: *const xmlChar,
4862) -> *mut _xmlXPathObject {
4863 if ctxt.is_null() || name.is_null() {
4864 return ptr::null_mut();
4865 }
4866 if let Some(f) = (*ctxt).varLookupFunc {
4867 let ret = f((*ctxt).varLookupData, name, ns_uri);
4868 if !ret.is_null() {
4869 return ret;
4870 }
4871 }
4872 let internal = (*ctxt).extra as *mut XPathContext;
4873 if internal.is_null() {
4874 return ptr::null_mut();
4875 }
4876 let internal = &*internal;
4877 let name_str = match CStr::from_ptr(name as *const c_char).to_str() {
4878 Ok(s) => s.to_string(),
4879 Err(_) => return ptr::null_mut(),
4880 };
4881 let qualified = if ns_uri.is_null() {
4882 name_str
4883 } else {
4884 match CStr::from_ptr(ns_uri as *const c_char).to_str() {
4885 Ok(s) => format!("{{{}}}{}", s, name_str),
4886 Err(_) => return ptr::null_mut(),
4887 }
4888 };
4889 match internal.variables.get(&qualified) {
4890 Some(v) => crate::abi::exports_xml2::xpath_to_object_pub(v.clone()),
4891 None => ptr::null_mut(),
4892 }
4893}
4894
4895#[no_mangle]
4901pub unsafe extern "C" fn xmlXPathNsLookup(
4902 ctxt: *mut _xmlXPathContext,
4903 prefix: *const xmlChar,
4904) -> *const xmlChar {
4905 if ctxt.is_null() || prefix.is_null() {
4906 return ptr::null();
4907 }
4908 if cstr_eq(prefix, c"xml".as_ptr() as *const xmlChar) {
4910 return XML_XML_NAMESPACE_BYTES.as_ptr() as *const xmlChar;
4911 }
4912 let namespaces = (*ctxt).namespaces;
4914 if !namespaces.is_null() {
4915 for i in 0..(*ctxt).nsNr as isize {
4916 let ns = *namespaces.add(i as usize);
4917 if !ns.is_null() && !(*ns).prefix.is_null() && cstr_eq((*ns).prefix, prefix) {
4918 return (*ns).href;
4919 }
4920 }
4921 }
4922 if !(*ctxt).nsHash.is_null() {
4925 let map = &*((*ctxt).nsHash as *const HashMap<String, CString>);
4926 let p = CStr::from_ptr(prefix as *const c_char)
4927 .to_string_lossy()
4928 .into_owned();
4929 if let Some(c) = map.get(&p) {
4930 return c.as_ptr() as *const xmlChar;
4931 }
4932 }
4933 ptr::null()
4934}
4935
4936#[no_mangle]
4942pub unsafe extern "C" fn xmlXPathRegisteredFuncsCleanup(ctxt: *mut _xmlXPathContext) {
4943 if ctxt.is_null() {
4944 return;
4945 }
4946 let internal = (*ctxt).extra as *mut XPathContext;
4947 if !internal.is_null() {
4948 (*internal).functions.clear();
4949 }
4950 crate::abi::exports_xml2::xpath_cfunc_cleanup((*ctxt).extra);
4951}
4952
4953#[no_mangle]
4959pub unsafe extern "C" fn xmlXPathRegisteredVariablesCleanup(ctxt: *mut _xmlXPathContext) {
4960 if ctxt.is_null() {
4961 return;
4962 }
4963 let internal = (*ctxt).extra as *mut XPathContext;
4964 if !internal.is_null() {
4965 (*internal).variables.clear();
4966 }
4967}
4968
4969#[no_mangle]
4975pub unsafe extern "C" fn xmlXPathRegisteredNsCleanup(ctxt: *mut _xmlXPathContext) {
4976 if ctxt.is_null() {
4977 return;
4978 }
4979 let internal = (*ctxt).extra as *mut XPathContext;
4980 if !internal.is_null() {
4981 (*internal).namespaces.clear();
4982 }
4983 if !(*ctxt).nsHash.is_null() {
4984 drop(Box::from_raw(
4985 (*ctxt).nsHash as *mut HashMap<String, CString>,
4986 ));
4987 (*ctxt).nsHash = ptr::null_mut();
4988 }
4989}
4990
4991#[no_mangle]
4997pub unsafe extern "C" fn xmlXPathSetErrorHandler(
4998 ctxt: *mut _xmlXPathContext,
4999 handler: Option<crate::abi::callbacks::xmlStructuredErrorFunc>,
5000 data: *mut c_void,
5001) {
5002 if ctxt.is_null() {
5003 return;
5004 }
5005 (*ctxt).error = handler;
5006 (*ctxt).userData = data;
5007}
5008
5009extern "C" {
5010 fn fwrite(ptr: *const c_void, size: usize, nmemb: usize, stream: *mut c_void) -> usize;
5011}
5012
5013unsafe fn dump_write(output: *mut c_void, s: &str) {
5014 unsafe {
5015 fwrite(s.as_ptr() as *const c_void, 1, s.len(), output);
5016 }
5017}
5018
5019#[no_mangle]
5025pub unsafe extern "C" fn xmlXPathDebugDumpObject(
5026 output: *mut c_void,
5027 cur: *mut _xmlXPathObject,
5028 depth: c_int,
5029) {
5030 if output.is_null() {
5031 return;
5032 }
5033 let mut s = String::new();
5034 for _ in 0..depth.clamp(0, 25) {
5035 s.push_str(" ");
5036 }
5037 if cur.is_null() {
5038 s.push_str("Object is empty (NULL)\n");
5039 dump_write(output, &s);
5040 return;
5041 }
5042 unsafe {
5043 match (*cur).type_ {
5044 t if t == xmlXPathObjectType::XPATH_BOOLEAN as c_int => {
5045 s.push_str("Object is a Boolean : ");
5046 s.push_str(if (*cur).boolval != 0 {
5047 "true\n"
5048 } else {
5049 "false\n"
5050 });
5051 }
5052 t if t == xmlXPathObjectType::XPATH_NUMBER as c_int => {
5053 let f = (*cur).floatval;
5054 if f.is_nan() {
5055 s.push_str("Object is a number : NaN\n");
5056 } else if f == f64::INFINITY {
5057 s.push_str("Object is a number : Infinity\n");
5058 } else if f == f64::NEG_INFINITY {
5059 s.push_str("Object is a number : -Infinity\n");
5060 } else if f == 0.0 {
5061 s.push_str("Object is a number : 0\n");
5062 } else {
5063 s.push_str("Object is a number : ");
5064 s.push_str(&f.to_string());
5065 s.push('\n');
5066 }
5067 }
5068 t if t == xmlXPathObjectType::XPATH_STRING as c_int => {
5069 s.push_str("Object is a string : ");
5070 if (*cur).stringval.is_null() {
5071 s.push_str("(null)");
5072 } else {
5073 let sv = CStr::from_ptr((*cur).stringval as *const c_char).to_string_lossy();
5074 s.push_str(&sv);
5075 }
5076 s.push('\n');
5077 }
5078 t if t == xmlXPathObjectType::XPATH_NODESET as c_int => {
5079 s.push_str("Object is a Node Set :\n");
5080 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
5081 if !ns.is_null() {
5082 for _ in 0..=depth.min(24) {
5083 s.push_str(" ");
5084 }
5085 s.push_str(&format!("Object contains {} nodes\n", (*ns).nodeNr));
5086 }
5087 }
5088 t if t == xmlXPathObjectType::XPATH_XSLT_TREE as c_int => {
5089 s.push_str("Object is an XSLT value tree :\n");
5090 }
5091 t if t == xmlXPathObjectType::XPATH_USERS as c_int => {
5092 s.push_str("Object is user defined\n");
5093 }
5094 _ => {
5095 s.push_str("Object is uninitialized\n");
5096 }
5097 }
5098 }
5099 dump_write(output, &s);
5100}
5101
5102#[no_mangle]
5112pub unsafe extern "C" fn xmlXPathDebugDumpCompExpr(
5113 output: *mut c_void,
5114 comp: *mut c_void,
5115 depth: c_int,
5116) {
5117 if output.is_null() || comp.is_null() {
5118 return;
5119 }
5120 let registry = crate::abi::exports_xml2::xpath_compiled_registry();
5121 let map = registry.lock();
5122 if let Some(compiled) = map.get(&(comp as u64)) {
5123 let mut s = String::new();
5124 for _ in 0..depth.clamp(0, 25) {
5125 s.push_str(" ");
5126 }
5127 s.push_str("Compiled Expression : ");
5128 s.push_str(&compiled.original);
5129 s.push('\n');
5130 dump_write(output, &s);
5131 }
5132}
5133
5134#[allow(unused)]
5135const fn _unused_xpath_batch(_: *mut _xmlAttr) {}