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]
830pub unsafe extern "C" fn xmlXPathNodeSetDel(cur: *mut _xmlNodeSet, val: *mut _xmlNode) -> c_int {
831 if cur.is_null() || val.is_null() {
832 return -1;
833 }
834 unsafe {
835 let nr = (*cur).nodeNr;
836 let tab = (*cur).nodeTab;
837 let mut found = -1;
838 if !tab.is_null() {
839 for i in 0..nr as isize {
840 if *tab.add(i as usize) == val {
841 found = i as c_int;
842 break;
843 }
844 }
845 }
846 if found >= 0 {
847 let fi = found as usize;
848 for i in fi..(nr as usize - 1) {
849 ptr::write(tab.add(i), *tab.add(i + 1));
850 }
851 (*cur).nodeNr -= 1;
852 }
853 }
854 0
855}
856
857#[no_mangle]
863pub unsafe extern "C" fn xmlXPathNodeSetRemove(cur: *mut _xmlNodeSet, val: c_int) -> c_int {
864 if cur.is_null() || val < 0 {
865 return -1;
866 }
867 unsafe {
868 let nr = (*cur).nodeNr;
869 if val >= nr {
870 return -1;
871 }
872 let tab = (*cur).nodeTab;
873 let vi = val as usize;
874 for i in vi..(nr as usize - 1) {
875 ptr::write(tab.add(i), *tab.add(i + 1));
876 }
877 (*cur).nodeNr -= 1;
878 }
879 0
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]
1575pub unsafe extern "C" fn xmlXPathValuePush(
1576 ctxt: *mut c_void,
1577 value: *mut _xmlXPathObject,
1578) -> *mut _xmlXPathObject {
1579 value_push(pc_from(ctxt), value)
1580}
1581
1582#[no_mangle]
1588pub unsafe extern "C" fn xmlXPathValuePop(ctxt: *mut c_void) -> *mut _xmlXPathObject {
1589 value_pop(pc_from(ctxt))
1590}
1591
1592#[no_mangle]
1598pub unsafe extern "C" fn xmlXPathPopBoolean(ctxt: *mut c_void) -> c_int {
1599 pop_boolean(pc_from(ctxt))
1600}
1601
1602#[no_mangle]
1608pub unsafe extern "C" fn xmlXPathPopExternal(ctxt: *mut c_void) -> *mut c_void {
1609 pop_external(pc_from(ctxt))
1610}
1611
1612#[no_mangle]
1618pub unsafe extern "C" fn xmlXPathPopNodeSet(ctxt: *mut c_void) -> *mut _xmlNodeSet {
1619 pop_node_set(pc_from(ctxt))
1620}
1621
1622#[no_mangle]
1628pub unsafe extern "C" fn xmlXPathPopNumber(ctxt: *mut c_void) -> c_double {
1629 pop_number(pc_from(ctxt))
1630}
1631
1632#[no_mangle]
1638pub unsafe extern "C" fn xmlXPathPopString(ctxt: *mut c_void) -> *mut xmlChar {
1639 pop_string(pc_from(ctxt))
1640}
1641
1642unsafe fn binary_inplace(ctxt: *mut c_void, op: impl Fn(&mut f64, f64)) {
1647 let pc = pc_from(ctxt);
1648 if pc.is_null() {
1649 return;
1650 }
1651 let arg = value_pop(pc);
1652 if arg.is_null() {
1653 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
1654 return;
1655 }
1656 let val = crate::abi::exports_xml2::object_to_xpathvalue_pub(arg).as_number();
1657 crate::abi::exports_xml2::xmlXPathFreeObject(arg);
1658 if unsafe { (*pc).value.is_null() } {
1659 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
1660 return;
1661 }
1662 cast_top_to_number(pc);
1663 if (*pc).error != 0 {
1664 return;
1665 }
1666 unsafe {
1670 let float_ref: &mut f64 = &mut (*(*pc).value).floatval;
1671 op(float_ref, val);
1672 }
1673}
1674
1675#[no_mangle]
1692pub unsafe extern "C" fn xmlXPathAddValues(ctxt: *mut c_void) {
1693 binary_inplace(ctxt, |x, v| *x += v);
1694}
1695
1696#[no_mangle]
1713pub unsafe extern "C" fn xmlXPathSubValues(ctxt: *mut c_void) {
1714 binary_inplace(ctxt, |x, v| *x -= v);
1715}
1716
1717#[no_mangle]
1734pub unsafe extern "C" fn xmlXPathMultValues(ctxt: *mut c_void) {
1735 binary_inplace(ctxt, |x, v| *x *= v);
1736}
1737
1738#[no_mangle]
1755pub unsafe extern "C" fn xmlXPathDivValues(ctxt: *mut c_void) {
1756 binary_inplace(ctxt, |x, v| *x /= v);
1757}
1758
1759#[no_mangle]
1776pub unsafe extern "C" fn xmlXPathModValues(ctxt: *mut c_void) {
1777 binary_inplace(ctxt, |x, v| *x %= v);
1778}
1779
1780#[no_mangle]
1797pub unsafe extern "C" fn xmlXPathValueFlipSign(ctxt: *mut c_void) {
1798 let pc = pc_from(ctxt);
1799 if pc.is_null() {
1800 return;
1801 }
1802 cast_top_to_number(pc);
1803 if (*pc).error != 0 {
1804 return;
1805 }
1806 unsafe { (*(*pc).value).floatval = -(*(*pc).value).floatval };
1807}
1808
1809#[no_mangle]
1827pub unsafe extern "C" fn xmlXPathEqualValues(ctxt: *mut c_void) -> c_int {
1828 equal_values_impl(pc_from(ctxt), false)
1829}
1830
1831#[no_mangle]
1848pub unsafe extern "C" fn xmlXPathNotEqualValues(ctxt: *mut c_void) -> c_int {
1849 equal_values_impl(pc_from(ctxt), true)
1850}
1851
1852#[no_mangle]
1873pub unsafe extern "C" fn xmlXPathCompareValues(
1874 ctxt: *mut c_void,
1875 inf: c_int,
1876 strict: c_int,
1877) -> c_int {
1878 compare_values_impl(pc_from(ctxt), inf != 0, strict != 0)
1879}
1880
1881#[no_mangle]
1892pub unsafe extern "C" fn xmlXPathNewParserContext(
1893 str_: *const xmlChar,
1894 ctxt: *mut _xmlXPathContext,
1895) -> *mut c_void {
1896 new_parser_context(str_, ctxt) as *mut c_void
1897}
1898
1899#[no_mangle]
1905pub unsafe extern "C" fn xmlXPathFreeParserContext(ctxt: *mut c_void) {
1906 free_parser_context(pc_from(ctxt));
1907}
1908
1909#[no_mangle]
1916pub unsafe extern "C" fn xmlXPathParseNCName(ctxt: *mut c_void) -> *mut xmlChar {
1917 let pc = pc_from(ctxt);
1918 if pc.is_null() {
1919 return ptr::null_mut();
1920 }
1921 let cur = unsafe { (*pc).cur };
1922 if cur.is_null() {
1923 return ptr::null_mut();
1924 }
1925 let len = scan_c_name(cur, true);
1926 if len == 0 {
1927 return ptr::null_mut();
1928 }
1929 let ret = crate::xml::string::xml_strndup(cur, len);
1930 unsafe { (*pc).cur = cur.add(len) };
1931 ret
1932}
1933
1934#[no_mangle]
1941pub unsafe extern "C" fn xmlXPathParseName(ctxt: *mut c_void) -> *mut xmlChar {
1942 let pc = pc_from(ctxt);
1943 if pc.is_null() {
1944 return ptr::null_mut();
1945 }
1946 let cur = unsafe { (*pc).cur };
1947 if cur.is_null() {
1948 return ptr::null_mut();
1949 }
1950 let len = scan_c_name(cur, false);
1951 if len == 0 {
1952 return ptr::null_mut();
1953 }
1954 let ret = crate::xml::string::xml_strndup(cur, len);
1955 unsafe { (*pc).cur = cur.add(len) };
1956 ret
1957}
1958
1959#[no_mangle]
1966pub unsafe extern "C" fn xmlXPathRoot(ctxt: *mut c_void) {
1967 let pc = pc_from(ctxt);
1968 if pc.is_null() {
1969 return;
1970 }
1971 let ctx = unsafe { (*pc).context };
1972 if ctx.is_null() {
1973 return;
1974 }
1975 let ns = NodeSet::singleton(unsafe { (*ctx).doc } as *mut _xmlNode);
1976 let obj = crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(ns));
1977 value_push(pc, obj);
1978}
1979
1980#[no_mangle]
1988pub unsafe extern "C" fn xmlXPathEvalExpr(ctxt: *mut c_void) {
1989 let pc = pc_from(ctxt);
1990 if pc.is_null() {
1991 return;
1992 }
1993 let ctx = unsafe { (*pc).context };
1994 if ctx.is_null() {
1995 return;
1996 }
1997 let base = unsafe { (*pc).base };
1998 if base.is_null() {
1999 return;
2000 }
2001 let expr_str = match CStr::from_ptr(base as *const c_char).to_str() {
2002 Ok(s) => s,
2003 Err(_) => {
2004 pc_set_error(pc, crate::abi::types::XPATH_EXPR_ERROR as c_int);
2005 return;
2006 }
2007 };
2008 let internal = unsafe { (*ctx).extra } as *mut XPathContext;
2009 if internal.is_null() {
2010 return;
2011 }
2012 let internal = unsafe { &mut *internal };
2013 match crate::xml::xpath::evaluate_str(expr_str, internal) {
2014 Some(val) => {
2015 let obj = crate::abi::exports_xml2::xpath_to_object_pub(val);
2016 value_push(pc, obj);
2017 }
2018 None => {
2019 pc_set_error(pc, crate::abi::types::XPATH_EXPR_ERROR as c_int);
2020 }
2021 }
2022}
2023
2024unsafe fn eval_predicate_result(ctxt: *mut _xmlXPathContext, res: *mut _xmlXPathObject) -> c_int {
2026 if ctxt.is_null() || res.is_null() {
2027 return 0;
2028 }
2029 unsafe {
2030 let t = (*res).type_;
2031 if t == xmlXPathObjectType::XPATH_BOOLEAN as c_int {
2032 (*res).boolval
2033 } else if t == xmlXPathObjectType::XPATH_NUMBER as c_int {
2034 ((*res).floatval == (*ctxt).proximityPosition as f64) as c_int
2035 } else if t == xmlXPathObjectType::XPATH_NODESET as c_int
2036 || t == xmlXPathObjectType::XPATH_XSLT_TREE as c_int
2037 {
2038 let nsp = (*res).nodesetval as *mut _xmlNodeSet;
2039 if nsp.is_null() || (*nsp).nodeNr == 0 {
2040 0
2041 } else {
2042 1
2043 }
2044 } else if t == xmlXPathObjectType::XPATH_STRING as c_int {
2045 if (*res).stringval.is_null() || *(*res).stringval == 0 {
2046 0
2047 } else {
2048 1
2049 }
2050 } else {
2051 0
2052 }
2053 }
2054}
2055
2056#[no_mangle]
2063pub unsafe extern "C" fn xmlXPathEvalPredicate(
2064 ctxt: *mut _xmlXPathContext,
2065 res: *mut _xmlXPathObject,
2066) -> c_int {
2067 eval_predicate_result(ctxt, res)
2068}
2069
2070#[no_mangle]
2076pub unsafe extern "C" fn xmlXPathEvaluatePredicateResult(
2077 ctxt: *mut c_void,
2078 res: *mut _xmlXPathObject,
2079) -> c_int {
2080 let pc = pc_from(ctxt);
2081 if pc.is_null() {
2082 return 0;
2083 }
2084 let ctx = unsafe { (*pc).context };
2085 eval_predicate_result(ctx, res)
2086}
2087
2088#[no_mangle]
2109pub unsafe extern "C" fn xmlXPathNextSelf(ctxt: *mut c_void, cur: *mut _xmlNode) -> *mut _xmlNode {
2110 let pc = pc_from(ctxt);
2111 if pc.is_null() {
2112 return ptr::null_mut();
2113 }
2114 let ctx = unsafe { (*pc).context };
2115 if ctx.is_null() {
2116 return ptr::null_mut();
2117 }
2118 if cur.is_null() {
2119 return unsafe { (*ctx).node };
2120 }
2121 ptr::null_mut()
2122}
2123
2124#[no_mangle]
2141pub unsafe extern "C" fn xmlXPathNextChild(ctxt: *mut c_void, cur: *mut _xmlNode) -> *mut _xmlNode {
2142 let pc = pc_from(ctxt);
2143 if pc.is_null() {
2144 return ptr::null_mut();
2145 }
2146 let ctx = unsafe { (*pc).context };
2147 if ctx.is_null() {
2148 return ptr::null_mut();
2149 }
2150 use crate::abi::types::xmlElementType as ET;
2151 if cur.is_null() {
2152 let node = unsafe { (*ctx).node };
2153 if node.is_null() {
2154 return ptr::null_mut();
2155 }
2156 return match unsafe { (*node).type_ } {
2157 t if t == ET::XML_ELEMENT_NODE as c_int
2158 || t == ET::XML_TEXT_NODE as c_int
2159 || t == ET::XML_CDATA_SECTION_NODE as c_int
2160 || t == ET::XML_ENTITY_REF_NODE as c_int
2161 || t == ET::XML_ENTITY_NODE as c_int
2162 || t == ET::XML_PI_NODE as c_int
2163 || t == ET::XML_COMMENT_NODE as c_int
2164 || t == ET::XML_NOTATION_NODE as c_int
2165 || t == ET::XML_DTD_NODE as c_int =>
2166 unsafe { (*node).children },
2167 t if t == ET::XML_DOCUMENT_NODE as c_int
2168 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2169 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2170 || t == ET::XML_HTML_DOCUMENT_NODE as c_int =>
2171 unsafe { (*(node as *mut _xmlDoc)).children },
2172 _ => ptr::null_mut(),
2173 };
2174 }
2175 let t = unsafe { (*cur).type_ };
2176 if t == ET::XML_DOCUMENT_NODE as c_int || t == ET::XML_HTML_DOCUMENT_NODE as c_int {
2177 return ptr::null_mut();
2178 }
2179 unsafe { (*cur).next }
2180}
2181
2182#[no_mangle]
2199pub unsafe extern "C" fn xmlXPathNextDescendant(
2200 ctxt: *mut c_void,
2201 mut cur: *mut _xmlNode,
2202) -> *mut _xmlNode {
2203 let pc = pc_from(ctxt);
2204 if pc.is_null() {
2205 return ptr::null_mut();
2206 }
2207 let ctx = unsafe { (*pc).context };
2208 if ctx.is_null() {
2209 return ptr::null_mut();
2210 }
2211 use crate::abi::types::xmlElementType as ET;
2212 if cur.is_null() {
2213 let node = unsafe { (*ctx).node };
2214 if node.is_null() {
2215 return ptr::null_mut();
2216 }
2217 let t = unsafe { (*node).type_ };
2218 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
2219 return ptr::null_mut();
2220 }
2221 if node == unsafe { (*ctx).doc } as *mut _xmlNode {
2222 return unsafe { (*(*ctx).doc).children };
2223 }
2224 return unsafe { (*node).children };
2225 }
2226 unsafe {
2227 if (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2228 return ptr::null_mut();
2229 }
2230 if !(*cur).children.is_null() && (*(*cur).children).type_ != ET::XML_ENTITY_DECL as c_int {
2231 cur = (*cur).children;
2232 if (*cur).type_ != ET::XML_DTD_NODE as c_int {
2233 return cur;
2234 }
2235 }
2236 if cur == (*ctx).node {
2237 return ptr::null_mut();
2238 }
2239 while !(*cur).next.is_null() {
2240 cur = (*cur).next;
2241 if (*cur).type_ != ET::XML_ENTITY_DECL as c_int
2242 && (*cur).type_ != ET::XML_DTD_NODE as c_int
2243 {
2244 return cur;
2245 }
2246 }
2247 loop {
2248 cur = (*cur).parent;
2249 if cur.is_null() {
2250 break;
2251 }
2252 if cur == (*ctx).node {
2253 return ptr::null_mut();
2254 }
2255 if !(*cur).next.is_null() {
2256 cur = (*cur).next;
2257 return cur;
2258 }
2259 }
2260 cur
2261 }
2262}
2263
2264#[no_mangle]
2281pub unsafe extern "C" fn xmlXPathNextDescendantOrSelf(
2282 ctxt: *mut c_void,
2283 cur: *mut _xmlNode,
2284) -> *mut _xmlNode {
2285 let pc = pc_from(ctxt);
2286 if pc.is_null() {
2287 return ptr::null_mut();
2288 }
2289 let ctx = unsafe { (*pc).context };
2290 if ctx.is_null() {
2291 return ptr::null_mut();
2292 }
2293 if cur.is_null() {
2294 return unsafe { (*ctx).node };
2295 }
2296 let node = unsafe { (*ctx).node };
2297 if node.is_null() {
2298 return ptr::null_mut();
2299 }
2300 use crate::abi::types::xmlElementType as ET;
2301 let t = unsafe { (*node).type_ };
2302 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
2303 return ptr::null_mut();
2304 }
2305 xmlXPathNextDescendant(ctxt, cur)
2306}
2307
2308#[no_mangle]
2325pub unsafe extern "C" fn xmlXPathNextParent(
2326 ctxt: *mut c_void,
2327 cur: *mut _xmlNode,
2328) -> *mut _xmlNode {
2329 let pc = pc_from(ctxt);
2330 if pc.is_null() {
2331 return ptr::null_mut();
2332 }
2333 let ctx = unsafe { (*pc).context };
2334 if ctx.is_null() {
2335 return ptr::null_mut();
2336 }
2337 if !cur.is_null() {
2338 return ptr::null_mut();
2339 }
2340 next_parent_impl(ctx)
2341}
2342
2343unsafe fn next_parent_impl(ctx: *mut _xmlXPathContext) -> *mut _xmlNode {
2345 use crate::abi::types::xmlElementType as ET;
2346 let node = unsafe { (*ctx).node };
2347 if node.is_null() {
2348 return ptr::null_mut();
2349 }
2350 match unsafe { (*node).type_ } {
2351 t if t == ET::XML_ELEMENT_NODE as c_int
2352 || t == ET::XML_TEXT_NODE as c_int
2353 || t == ET::XML_CDATA_SECTION_NODE as c_int
2354 || t == ET::XML_ENTITY_REF_NODE as c_int
2355 || t == ET::XML_ENTITY_NODE as c_int
2356 || t == ET::XML_PI_NODE as c_int
2357 || t == ET::XML_COMMENT_NODE as c_int
2358 || t == ET::XML_NOTATION_NODE as c_int
2359 || t == ET::XML_DTD_NODE as c_int
2360 || t == ET::XML_ELEMENT_DECL as c_int
2361 || t == ET::XML_ATTRIBUTE_DECL as c_int
2362 || t == ET::XML_ENTITY_DECL as c_int
2363 || t == ET::XML_XINCLUDE_START as c_int
2364 || t == ET::XML_XINCLUDE_END as c_int =>
2365 unsafe {
2366 let parent = (*node).parent;
2367 if parent.is_null() {
2368 return (*ctx).doc as *mut _xmlNode;
2369 }
2370 if (*parent).type_ == ET::XML_ELEMENT_NODE as c_int
2371 && ((*parent).name.is_null() || *(*parent).name == b' ')
2372 {
2373 return ptr::null_mut();
2374 }
2375 parent
2376 },
2377 t if t == ET::XML_ATTRIBUTE_NODE as c_int => unsafe { (*(node as *mut _xmlAttr)).parent },
2378 t if t == ET::XML_DOCUMENT_NODE as c_int
2379 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2380 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2381 || t == ET::XML_HTML_DOCUMENT_NODE as c_int =>
2382 {
2383 ptr::null_mut()
2384 }
2385 t if t == ET::XML_NAMESPACE_DECL as c_int => unsafe {
2386 let ns = node as *mut crate::abi::structs::_xmlNs;
2387 if !(*ns).next.is_null() && (*(*ns).next).type_ != ET::XML_NAMESPACE_DECL as c_int {
2388 (*ns).next as *mut _xmlNode
2389 } else {
2390 ptr::null_mut()
2391 }
2392 },
2393 _ => ptr::null_mut(),
2394 }
2395}
2396
2397#[no_mangle]
2414pub unsafe extern "C" fn xmlXPathNextAncestor(
2415 ctxt: *mut c_void,
2416 cur: *mut _xmlNode,
2417) -> *mut _xmlNode {
2418 let pc = pc_from(ctxt);
2419 if pc.is_null() {
2420 return ptr::null_mut();
2421 }
2422 let ctx = unsafe { (*pc).context };
2423 if ctx.is_null() {
2424 return ptr::null_mut();
2425 }
2426 use crate::abi::types::xmlElementType as ET;
2427 if cur.is_null() {
2428 let node = unsafe { (*ctx).node };
2429 if node.is_null() {
2430 return ptr::null_mut();
2431 }
2432 let t = unsafe { (*node).type_ };
2433 if t == ET::XML_ATTRIBUTE_NODE as c_int {
2434 return unsafe { (*(node as *mut _xmlAttr)).parent };
2435 }
2436 if t == ET::XML_NAMESPACE_DECL as c_int {
2437 let ns = node as *mut crate::abi::structs::_xmlNs;
2438 return unsafe {
2439 if !(*ns).next.is_null() && (*(*ns).next).type_ != ET::XML_NAMESPACE_DECL as c_int {
2440 (*ns).next as *mut _xmlNode
2441 } else {
2442 ptr::null_mut()
2443 }
2444 };
2445 }
2446 if t == ET::XML_DOCUMENT_NODE as c_int
2447 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2448 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2449 || t == ET::XML_HTML_DOCUMENT_NODE as c_int
2450 {
2451 return ptr::null_mut();
2452 }
2453 return next_parent_impl(ctx);
2455 }
2456 if cur == unsafe { (*ctx).doc } as *mut _xmlNode {
2457 return ptr::null_mut();
2458 }
2459 if cur == unsafe { (*(*ctx).doc).children } {
2460 return unsafe { (*ctx).doc } as *mut _xmlNode;
2461 }
2462 let t = unsafe { (*cur).type_ };
2463 if t == ET::XML_ATTRIBUTE_NODE as c_int {
2464 return unsafe { (*(cur as *mut _xmlAttr)).parent };
2465 }
2466 if t == ET::XML_NAMESPACE_DECL as c_int {
2467 let ns = cur as *mut crate::abi::structs::_xmlNs;
2468 return unsafe {
2469 if !(*ns).next.is_null() && (*(*ns).next).type_ != ET::XML_NAMESPACE_DECL as c_int {
2470 (*ns).next as *mut _xmlNode
2471 } else {
2472 ptr::null_mut()
2473 }
2474 };
2475 }
2476 if t == ET::XML_DOCUMENT_NODE as c_int
2477 || t == ET::XML_DOCUMENT_TYPE_NODE as c_int
2478 || t == ET::XML_DOCUMENT_FRAG_NODE as c_int
2479 || t == ET::XML_HTML_DOCUMENT_NODE as c_int
2480 {
2481 return ptr::null_mut();
2482 }
2483 unsafe {
2484 let parent = (*cur).parent;
2485 if parent.is_null() {
2486 return ptr::null_mut();
2487 }
2488 if (*parent).type_ == ET::XML_ELEMENT_NODE as c_int
2489 && ((*parent).name.is_null() || *(*parent).name == b' ')
2490 {
2491 return ptr::null_mut();
2492 }
2493 parent
2494 }
2495}
2496
2497#[no_mangle]
2514pub unsafe extern "C" fn xmlXPathNextAncestorOrSelf(
2515 ctxt: *mut c_void,
2516 cur: *mut _xmlNode,
2517) -> *mut _xmlNode {
2518 let pc = pc_from(ctxt);
2519 if pc.is_null() {
2520 return ptr::null_mut();
2521 }
2522 let ctx = unsafe { (*pc).context };
2523 if ctx.is_null() {
2524 return ptr::null_mut();
2525 }
2526 if cur.is_null() {
2527 return unsafe { (*ctx).node };
2528 }
2529 xmlXPathNextAncestor(ctxt, cur)
2530}
2531
2532#[no_mangle]
2549pub unsafe extern "C" fn xmlXPathNextFollowingSibling(
2550 ctxt: *mut c_void,
2551 mut cur: *mut _xmlNode,
2552) -> *mut _xmlNode {
2553 let pc = pc_from(ctxt);
2554 if pc.is_null() {
2555 return ptr::null_mut();
2556 }
2557 let ctx = unsafe { (*pc).context };
2558 if ctx.is_null() {
2559 return ptr::null_mut();
2560 }
2561 use crate::abi::types::xmlElementType as ET;
2562 unsafe {
2563 let cnode = (*ctx).node;
2564 if !cnode.is_null() {
2565 let t = (*cnode).type_;
2566 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
2567 return ptr::null_mut();
2568 }
2569 }
2570 if cur == (*ctx).doc as *mut _xmlNode {
2571 return ptr::null_mut();
2572 }
2573 if cur.is_null() {
2574 cur = cnode;
2575 }
2576 if cur.is_null() {
2577 return ptr::null_mut();
2578 }
2579 if (*cur).type_ == ET::XML_DOCUMENT_NODE as c_int {
2580 return ptr::null_mut();
2581 }
2582 (*cur).next
2583 }
2584}
2585
2586#[no_mangle]
2603pub unsafe extern "C" fn xmlXPathNextPrecedingSibling(
2604 ctxt: *mut c_void,
2605 mut cur: *mut _xmlNode,
2606) -> *mut _xmlNode {
2607 let pc = pc_from(ctxt);
2608 if pc.is_null() {
2609 return ptr::null_mut();
2610 }
2611 let ctx = unsafe { (*pc).context };
2612 if ctx.is_null() {
2613 return ptr::null_mut();
2614 }
2615 use crate::abi::types::xmlElementType as ET;
2616 unsafe {
2617 let cnode = (*ctx).node;
2618 if !cnode.is_null() {
2619 let t = (*cnode).type_;
2620 if t == ET::XML_ATTRIBUTE_NODE as c_int || t == ET::XML_NAMESPACE_DECL as c_int {
2621 return ptr::null_mut();
2622 }
2623 }
2624 if cur == (*ctx).doc as *mut _xmlNode {
2625 return ptr::null_mut();
2626 }
2627 if cur.is_null() {
2628 cur = cnode;
2629 } else if !(*cur).prev.is_null() && (*(*cur).prev).type_ == ET::XML_DTD_NODE as c_int {
2630 cur = (*cur).prev;
2631 if cur.is_null() {
2632 return ptr::null_mut();
2633 }
2634 }
2635 if cur.is_null() {
2636 return ptr::null_mut();
2637 }
2638 if (*cur).type_ == ET::XML_DOCUMENT_NODE as c_int {
2639 return ptr::null_mut();
2640 }
2641 (*cur).prev
2642 }
2643}
2644
2645#[no_mangle]
2662pub unsafe extern "C" fn xmlXPathNextFollowing(
2663 ctxt: *mut c_void,
2664 mut cur: *mut _xmlNode,
2665) -> *mut _xmlNode {
2666 let pc = pc_from(ctxt);
2667 if pc.is_null() {
2668 return ptr::null_mut();
2669 }
2670 let ctx = unsafe { (*pc).context };
2671 if ctx.is_null() {
2672 return ptr::null_mut();
2673 }
2674 use crate::abi::types::xmlElementType as ET;
2675 unsafe {
2676 if !cur.is_null()
2677 && (*cur).type_ != ET::XML_ATTRIBUTE_NODE as c_int
2678 && (*cur).type_ != ET::XML_NAMESPACE_DECL as c_int
2679 && !(*cur).children.is_null()
2680 {
2681 return (*cur).children;
2682 }
2683 if cur.is_null() {
2684 cur = (*ctx).node;
2685 if cur.is_null() {
2686 return ptr::null_mut();
2687 }
2688 if (*cur).type_ == ET::XML_ATTRIBUTE_NODE as c_int {
2689 cur = (*cur).parent;
2690 } else if (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2691 let ns = cur as *mut crate::abi::structs::_xmlNs;
2692 if (*ns).next.is_null() || (*(*ns).next).type_ == ET::XML_NAMESPACE_DECL as c_int {
2693 return ptr::null_mut();
2694 }
2695 cur = (*ns).next as *mut _xmlNode;
2696 }
2697 }
2698 if cur.is_null() {
2699 return ptr::null_mut();
2700 }
2701 if (*cur).type_ == ET::XML_DOCUMENT_NODE as c_int {
2702 return ptr::null_mut();
2703 }
2704 if !(*cur).next.is_null() {
2705 return (*cur).next;
2706 }
2707 loop {
2708 cur = (*cur).parent;
2709 if cur.is_null() {
2710 break;
2711 }
2712 if cur == (*ctx).doc as *mut _xmlNode {
2713 return ptr::null_mut();
2714 }
2715 if !(*cur).next.is_null() && (*cur).type_ != ET::XML_DOCUMENT_NODE as c_int {
2716 return (*cur).next;
2717 }
2718 }
2719 cur
2720 }
2721}
2722
2723#[no_mangle]
2740pub unsafe extern "C" fn xmlXPathNextPreceding(
2741 ctxt: *mut c_void,
2742 mut cur: *mut _xmlNode,
2743) -> *mut _xmlNode {
2744 let pc = pc_from(ctxt);
2745 if pc.is_null() {
2746 return ptr::null_mut();
2747 }
2748 let ctx = unsafe { (*pc).context };
2749 if ctx.is_null() {
2750 return ptr::null_mut();
2751 }
2752 use crate::abi::types::xmlElementType as ET;
2753 unsafe {
2754 let is_ancestor = |ancestor: *mut _xmlNode, node: *mut _xmlNode| -> bool {
2755 if ancestor.is_null() || node.is_null() {
2756 return false;
2757 }
2758 if (*node).type_ == ET::XML_NAMESPACE_DECL as c_int
2759 || (*ancestor).type_ == ET::XML_NAMESPACE_DECL as c_int
2760 {
2761 return false;
2762 }
2763 if (*ancestor).doc != (*node).doc {
2764 return false;
2765 }
2766 if ancestor == (*node).doc as *mut _xmlNode {
2767 return true;
2768 }
2769 if node == (*ancestor).doc as *mut _xmlNode {
2770 return false;
2771 }
2772 let mut n = node;
2773 while !(*n).parent.is_null() {
2774 if (*n).parent == ancestor {
2775 return true;
2776 }
2777 n = (*n).parent;
2778 }
2779 false
2780 };
2781 if cur.is_null() {
2782 cur = (*ctx).node;
2783 if cur.is_null() {
2784 return ptr::null_mut();
2785 }
2786 if (*cur).type_ == ET::XML_ATTRIBUTE_NODE as c_int {
2787 cur = (*cur).parent;
2788 } else if (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2789 let ns = cur as *mut crate::abi::structs::_xmlNs;
2790 if (*ns).next.is_null() || (*(*ns).next).type_ == ET::XML_NAMESPACE_DECL as c_int {
2791 return ptr::null_mut();
2792 }
2793 cur = (*ns).next as *mut _xmlNode;
2794 }
2795 }
2796 if cur.is_null() || (*cur).type_ == ET::XML_NAMESPACE_DECL as c_int {
2797 return ptr::null_mut();
2798 }
2799 if !(*cur).prev.is_null() && (*(*cur).prev).type_ == ET::XML_DTD_NODE as c_int {
2800 cur = (*cur).prev;
2801 }
2802 loop {
2803 if !(*cur).prev.is_null() {
2804 let mut n = (*cur).prev;
2805 while !(*n).last.is_null() {
2806 n = (*n).last;
2807 }
2808 return n;
2809 }
2810 cur = (*cur).parent;
2811 if cur.is_null() {
2812 return ptr::null_mut();
2813 }
2814 if cur == (*(*ctx).doc).children {
2815 return ptr::null_mut();
2816 }
2817 if !is_ancestor(cur, (*ctx).node) {
2818 return cur;
2819 }
2820 }
2821 }
2822}
2823
2824#[no_mangle]
2841pub unsafe extern "C" fn xmlXPathNextNamespace(
2842 ctxt: *mut c_void,
2843 cur: *mut _xmlNode,
2844) -> *mut _xmlNode {
2845 let pc = pc_from(ctxt);
2846 if pc.is_null() {
2847 return ptr::null_mut();
2848 }
2849 let ctx = unsafe { (*pc).context };
2850 if ctx.is_null() {
2851 return ptr::null_mut();
2852 }
2853 use crate::abi::types::xmlElementType as ET;
2854 unsafe {
2855 let cnode = (*ctx).node;
2856 if cnode.is_null() || (*cnode).type_ != ET::XML_ELEMENT_NODE as c_int {
2857 return ptr::null_mut();
2858 }
2859 if cur.is_null() {
2860 if !(*ctx).tmpNsList.is_null() {
2861 xmlFreeImpl((*ctx).tmpNsList as *mut c_void);
2862 }
2863 (*ctx).tmpNsNr = 0;
2864 (*ctx).tmpNsList = crate::xml::tree::get_ns_list((*ctx).doc, cnode);
2865 if !(*ctx).tmpNsList.is_null() {
2866 while !(*(*ctx).tmpNsList.add((*ctx).tmpNsNr as usize)).is_null() {
2867 (*ctx).tmpNsNr += 1;
2868 }
2869 }
2870 return (&XML_XPATH_XML_NS.0) as *const crate::abi::structs::_xmlNs as *mut _xmlNode;
2871 }
2872 if (*ctx).tmpNsNr > 0 {
2873 (*ctx).tmpNsNr -= 1;
2874 return (*(*ctx).tmpNsList.add((*ctx).tmpNsNr as usize)) as *mut _xmlNode;
2875 }
2876 if !(*ctx).tmpNsList.is_null() {
2877 xmlFreeImpl((*ctx).tmpNsList as *mut c_void);
2878 }
2879 (*ctx).tmpNsList = ptr::null_mut();
2880 ptr::null_mut()
2881 }
2882}
2883
2884#[no_mangle]
2901pub unsafe extern "C" fn xmlXPathNextAttribute(
2902 ctxt: *mut c_void,
2903 cur: *mut _xmlNode,
2904) -> *mut _xmlNode {
2905 let pc = pc_from(ctxt);
2906 if pc.is_null() {
2907 return ptr::null_mut();
2908 }
2909 let ctx = unsafe { (*pc).context };
2910 if ctx.is_null() {
2911 return ptr::null_mut();
2912 }
2913 use crate::abi::types::xmlElementType as ET;
2914 unsafe {
2915 let cnode = (*ctx).node;
2916 if cnode.is_null() || (*cnode).type_ != ET::XML_ELEMENT_NODE as c_int {
2917 return ptr::null_mut();
2918 }
2919 if cur.is_null() {
2920 if cnode == (*ctx).doc as *mut _xmlNode {
2921 return ptr::null_mut();
2922 }
2923 return (*cnode).properties as *mut _xmlNode;
2924 }
2925 (*cur).next
2926 }
2927}
2928
2929#[no_mangle]
2950pub unsafe extern "C" fn xmlXPathBooleanFunction(ctxt: *mut c_void, _nargs: c_int) {
2951 let pc = pc_from(ctxt);
2952 if pc.is_null() {
2953 return;
2954 }
2955 if !check_arity(pc, 1) {
2956 return;
2957 }
2958 let cur = value_pop(pc);
2959 if cur.is_null() {
2960 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
2961 return;
2962 }
2963 let b = crate::abi::exports_xml2::object_to_xpathvalue_pub(cur).as_boolean();
2964 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
2965 value_push(pc, new_bool(b));
2966}
2967
2968#[no_mangle]
2985pub unsafe extern "C" fn xmlXPathNotFunction(ctxt: *mut c_void, _nargs: c_int) {
2986 let pc = pc_from(ctxt);
2987 if pc.is_null() {
2988 return;
2989 }
2990 if !check_arity(pc, 1) {
2991 return;
2992 }
2993 cast_top_to_boolean(pc);
2994 if (*pc).error != 0 {
2995 return;
2996 }
2997 unsafe {
2998 (*(*pc).value).boolval = if (*(*pc).value).boolval == 0 { 1 } else { 0 };
2999 }
3000}
3001
3002#[no_mangle]
3019pub unsafe extern "C" fn xmlXPathTrueFunction(ctxt: *mut c_void, _nargs: c_int) {
3020 let pc = pc_from(ctxt);
3021 if pc.is_null() {
3022 return;
3023 }
3024
3025 value_push(pc, new_bool(true));
3026}
3027
3028#[no_mangle]
3045pub unsafe extern "C" fn xmlXPathFalseFunction(ctxt: *mut c_void, _nargs: c_int) {
3046 let pc = pc_from(ctxt);
3047 if pc.is_null() {
3048 return;
3049 }
3050
3051 value_push(pc, new_bool(false));
3052}
3053
3054const unsafe fn lang_matches(lang: *const xmlChar, the_lang: *const xmlChar) -> bool {
3057 if lang.is_null() || the_lang.is_null() {
3058 return false;
3059 }
3060 let mut i = 0usize;
3061 loop {
3062 let lc = unsafe { *lang.add(i) };
3063 if lc == 0 {
3064 break;
3065 }
3066 let tc = unsafe { *the_lang.add(i) };
3067 if tc == 0 {
3068 return false;
3069 }
3070 if !lc.eq_ignore_ascii_case(&tc) {
3071 return false;
3072 }
3073 i += 1;
3074 }
3075 let c = unsafe { *the_lang.add(i) };
3076 c == 0 || c == b'-'
3077}
3078
3079#[no_mangle]
3096pub unsafe extern "C" fn xmlXPathLangFunction(ctxt: *mut c_void, _nargs: c_int) {
3097 let pc = pc_from(ctxt);
3098 if pc.is_null() {
3099 return;
3100 }
3101 let ctx = unsafe { (*pc).context };
3102 if ctx.is_null() {
3103 return;
3104 }
3105 if !check_arity(pc, 1) {
3106 return;
3107 }
3108 cast_top_to_string(pc);
3109 if (*pc).error != 0 {
3110 return;
3111 }
3112 let val = value_pop(pc);
3113 if val.is_null() {
3114 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3115 return;
3116 }
3117 let lang = unsafe { (*val).stringval };
3118 let mut ret = 0;
3119 unsafe {
3120 let mut n = (*ctx).node;
3121 let mut found: *mut xmlChar = ptr::null_mut();
3122 while !n.is_null() {
3123 let got = crate::xml::tree::get_ns_prop(
3124 n,
3125 c"lang".as_ptr() as *const xmlChar,
3126 XML_XML_NAMESPACE_BYTES.as_ptr() as *const xmlChar,
3127 );
3128 if !got.is_null() {
3129 found = got;
3130 break;
3131 }
3132 n = (*n).parent;
3133 }
3134 if !found.is_null() && lang_matches(lang, found) {
3135 ret = 1;
3136 }
3137 if !found.is_null() {
3138 xmlFreeImpl(found as *mut c_void);
3139 }
3140 }
3141 crate::abi::exports_xml2::xmlXPathFreeObject(val);
3142 value_push(pc, new_bool(ret != 0));
3143}
3144
3145#[no_mangle]
3162pub unsafe extern "C" fn xmlXPathNumberFunction(ctxt: *mut c_void, nargs: c_int) {
3163 let pc = pc_from(ctxt);
3164 if pc.is_null() {
3165 return;
3166 }
3167 let ctx = unsafe { (*pc).context };
3168 if ctx.is_null() {
3169 return;
3170 }
3171 if nargs == 0 {
3172 let node = unsafe { (*ctx).node };
3173 let res = if node.is_null() {
3174 0.0
3175 } else {
3176 let sv = node_string_value(node);
3177 crate::xml::xpath::types::string_to_number(&sv)
3178 };
3179 value_push(pc, new_number(res));
3180 return;
3181 }
3182 if !check_arity(pc, 1) {
3183 return;
3184 }
3185 cast_top_to_number(pc);
3186}
3187
3188#[no_mangle]
3205pub unsafe extern "C" fn xmlXPathSumFunction(ctxt: *mut c_void, _nargs: c_int) {
3206 let pc = pc_from(ctxt);
3207 if pc.is_null() {
3208 return;
3209 }
3210 if !check_arity(pc, 1) {
3211 return;
3212 }
3213 let cur = value_pop(pc);
3214 if cur.is_null() {
3215 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3216 return;
3217 }
3218 let typ = unsafe { (*cur).type_ };
3219 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3220 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3221 {
3222 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3223 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3224 return;
3225 }
3226 let mut res = 0.0;
3227 unsafe {
3228 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3229 if !ns.is_null() {
3230 let nr = (*ns).nodeNr;
3231 let tab = (*ns).nodeTab;
3232 if !tab.is_null() {
3233 for i in 0..nr as isize {
3234 let node = *tab.add(i as usize);
3235 let sv = node_string_value(node);
3236 res += crate::xml::xpath::types::string_to_number(&sv);
3237 }
3238 }
3239 }
3240 }
3241 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3242 value_push(pc, new_number(res));
3243}
3244
3245#[no_mangle]
3262pub unsafe extern "C" fn xmlXPathFloorFunction(ctxt: *mut c_void, _nargs: c_int) {
3263 let pc = pc_from(ctxt);
3264 if pc.is_null() {
3265 return;
3266 }
3267 if !check_arity(pc, 1) {
3268 return;
3269 }
3270 cast_top_to_number(pc);
3271 if (*pc).error != 0 {
3272 return;
3273 }
3274 unsafe {
3275 (*(*pc).value).floatval = (*(*pc).value).floatval.floor();
3276 }
3277}
3278
3279#[no_mangle]
3296pub unsafe extern "C" fn xmlXPathCeilingFunction(ctxt: *mut c_void, _nargs: c_int) {
3297 let pc = pc_from(ctxt);
3298 if pc.is_null() {
3299 return;
3300 }
3301 if !check_arity(pc, 1) {
3302 return;
3303 }
3304 cast_top_to_number(pc);
3305 if (*pc).error != 0 {
3306 return;
3307 }
3308 unsafe {
3309 (*(*pc).value).floatval = (*(*pc).value).floatval.ceil();
3310 }
3311}
3312
3313#[no_mangle]
3330pub unsafe extern "C" fn xmlXPathRoundFunction(ctxt: *mut c_void, _nargs: c_int) {
3331 let pc = pc_from(ctxt);
3332 if pc.is_null() {
3333 return;
3334 }
3335 if !check_arity(pc, 1) {
3336 return;
3337 }
3338 cast_top_to_number(pc);
3339 if (*pc).error != 0 {
3340 return;
3341 }
3342 unsafe {
3343 let f = (*(*pc).value).floatval;
3344 if (-0.5..0.5).contains(&f) {
3345 (*(*pc).value).floatval *= 0.0;
3347 } else {
3348 let mut rounded = f.floor();
3349 if f - rounded >= 0.5 {
3350 rounded += 1.0;
3351 }
3352 (*(*pc).value).floatval = rounded;
3353 }
3354 }
3355}
3356
3357#[no_mangle]
3374pub unsafe extern "C" fn xmlXPathLastFunction(ctxt: *mut c_void, _nargs: c_int) {
3375 let pc = pc_from(ctxt);
3376 if pc.is_null() {
3377 return;
3378 }
3379 let ctx = unsafe { (*pc).context };
3380 if ctx.is_null() {
3381 return;
3382 }
3383
3384 value_push(pc, new_number(unsafe { (*ctx).contextSize } as f64));
3385}
3386
3387#[no_mangle]
3404pub unsafe extern "C" fn xmlXPathPositionFunction(ctxt: *mut c_void, _nargs: c_int) {
3405 let pc = pc_from(ctxt);
3406 if pc.is_null() {
3407 return;
3408 }
3409 let ctx = unsafe { (*pc).context };
3410 if ctx.is_null() {
3411 return;
3412 }
3413
3414 value_push(pc, new_number(unsafe { (*ctx).proximityPosition } as f64));
3415}
3416
3417#[no_mangle]
3434pub unsafe extern "C" fn xmlXPathCountFunction(ctxt: *mut c_void, _nargs: c_int) {
3435 let pc = pc_from(ctxt);
3436 if pc.is_null() {
3437 return;
3438 }
3439 if !check_arity(pc, 1) {
3440 return;
3441 }
3442 let cur = value_pop(pc);
3443 if cur.is_null() {
3444 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3445 return;
3446 }
3447 let typ = unsafe { (*cur).type_ };
3448 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3449 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3450 {
3451 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3452 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3453 return;
3454 }
3455 let count = unsafe {
3456 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3457 if ns.is_null() {
3458 0
3459 } else {
3460 (*ns).nodeNr
3461 }
3462 };
3463 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3464 value_push(pc, new_number(count as f64));
3465}
3466
3467unsafe fn get_elements_by_ids(doc: *mut _xmlDoc, ids: *const xmlChar) -> *mut _xmlNodeSet {
3470 use crate::abi::types::xmlElementType as ET;
3471 if ids.is_null() {
3472 return ptr::null_mut();
3473 }
3474 let mut out = NodeSet::new();
3475 unsafe {
3476 let mut p = ids;
3477 while *p != 0 {
3478 while is_blank_ch(*p) {
3479 p = p.add(1);
3480 }
3481 if *p == 0 {
3482 break;
3483 }
3484 let start = p;
3485 while *p != 0 && !is_blank_ch(*p) {
3486 p = p.add(1);
3487 }
3488 let id_c = crate::xml::string::xml_strndup(start, p.offset_from(start) as usize);
3489 if id_c.is_null() {
3490 break;
3491 }
3492 let attr = get_id(doc, id_c);
3493 xmlFreeImpl(id_c as *mut c_void);
3494 if !attr.is_null() {
3495 let t = (*attr).type_;
3496 let elem = if t == ET::XML_ATTRIBUTE_NODE as c_int {
3497 (*attr).parent
3498 } else if t == ET::XML_ELEMENT_NODE as c_int {
3499 attr as *mut _xmlNode
3500 } else {
3501 ptr::null_mut()
3502 };
3503 if !elem.is_null() {
3504 out.push(elem);
3505 }
3506 }
3507 }
3508 }
3509 out.to_raw()
3510}
3511
3512#[no_mangle]
3529pub unsafe extern "C" fn xmlXPathIdFunction(ctxt: *mut c_void, _nargs: c_int) {
3530 let pc = pc_from(ctxt);
3531 if pc.is_null() {
3532 return;
3533 }
3534 let ctx = unsafe { (*pc).context };
3535 if ctx.is_null() {
3536 return;
3537 }
3538 if !check_arity(pc, 1) {
3539 return;
3540 }
3541 let obj = value_pop(pc);
3542 if obj.is_null() {
3543 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3544 return;
3545 }
3546 let doc = unsafe { (*ctx).doc };
3547 let v = crate::abi::exports_xml2::object_to_xpathvalue_pub(obj);
3548 crate::abi::exports_xml2::xmlXPathFreeObject(obj);
3549 match &v {
3550 XPathValue::NodeSet(ns) => {
3551 let mut merged = NodeSet::new();
3552 for n in ns.iter() {
3553 let sv = node_string_value(n);
3554 let c = dup_rust_string(&sv);
3555 let sub = get_elements_by_ids(doc, c);
3556 xmlFreeImpl(c as *mut c_void);
3557 if !sub.is_null() {
3558 let sub_internal = node_set_to_internal(sub);
3559 for m in sub_internal.iter() {
3560 if !merged.contains(m) {
3561 merged.push(m);
3562 }
3563 }
3564 crate::abi::exports_xml2::xmlXPathFreeNodeSet(sub);
3566 }
3567 }
3568 value_push(
3569 pc,
3570 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(merged)),
3571 );
3572 }
3573 _ => {
3574 let s = v.as_string();
3575 let c = dup_rust_string(&s);
3576 let ret = get_elements_by_ids(doc, c);
3577 xmlFreeImpl(c as *mut c_void);
3578 if ret.is_null() {
3579 value_push(
3580 pc,
3581 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(
3582 NodeSet::new(),
3583 )),
3584 );
3585 } else {
3586 let obj2 = crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(
3587 node_set_to_internal(ret),
3588 ));
3589 crate::abi::exports_xml2::xmlXPathFreeNodeSet(ret);
3590 value_push(pc, obj2);
3591 }
3592 }
3593 }
3594}
3595
3596unsafe fn node_local_name(node: *mut _xmlNode) -> String {
3599 use crate::abi::types::xmlElementType as ET;
3600 if node.is_null() {
3601 return String::new();
3602 }
3603 unsafe {
3604 match (*node).type_ {
3605 t if t == ET::XML_ELEMENT_NODE as c_int
3606 || t == ET::XML_ATTRIBUTE_NODE as c_int
3607 || t == ET::XML_PI_NODE as c_int =>
3608 {
3609 let name = (*node).name;
3610 if name.is_null() || *name == b' ' {
3611 String::new()
3612 } else {
3613 let s = CStr::from_ptr(name as *const c_char)
3614 .to_string_lossy()
3615 .into_owned();
3616 match s.split_once(':') {
3617 Some((_, local)) => local.to_string(),
3618 None => s,
3619 }
3620 }
3621 }
3622 t if t == ET::XML_NAMESPACE_DECL as c_int => {
3623 let ns = node as *mut crate::abi::structs::_xmlNs;
3624 let p = (*ns).prefix;
3625 if p.is_null() {
3626 String::new()
3627 } else {
3628 CStr::from_ptr(p as *const c_char)
3629 .to_string_lossy()
3630 .into_owned()
3631 }
3632 }
3633 _ => String::new(),
3634 }
3635 }
3636}
3637
3638#[no_mangle]
3655pub unsafe extern "C" fn xmlXPathLocalNameFunction(ctxt: *mut c_void, nargs: c_int) {
3656 let pc = pc_from(ctxt);
3657 if pc.is_null() {
3658 return;
3659 }
3660 let ctx = unsafe { (*pc).context };
3661 if ctx.is_null() {
3662 return;
3663 }
3664 if nargs == 0 {
3665 value_push(
3666 pc,
3667 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(NodeSet::singleton(
3668 unsafe { (*ctx).node },
3669 ))),
3670 );
3671 }
3673
3674 if !check_arity(pc, 1) {
3675 return;
3676 }
3677 let cur = value_pop(pc);
3678 if cur.is_null() {
3679 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3680 return;
3681 }
3682 let typ = unsafe { (*cur).type_ };
3683 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3684 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3685 {
3686 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3687 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3688 return;
3689 }
3690 let name = unsafe {
3691 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3692 if ns.is_null() || (*ns).nodeNr == 0 {
3693 String::new()
3694 } else {
3695 node_local_name(*(*ns).nodeTab)
3696 }
3697 };
3698 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3699 let out = dup_rust_string(&name);
3700 value_push(pc, xmlXPathWrapString(out));
3701}
3702
3703unsafe fn node_namespace_uri(node: *mut _xmlNode) -> String {
3705 use crate::abi::types::xmlElementType as ET;
3706 if node.is_null() {
3707 return String::new();
3708 }
3709 unsafe {
3710 match (*node).type_ {
3711 t if t == ET::XML_ELEMENT_NODE as c_int || t == ET::XML_ATTRIBUTE_NODE as c_int => {
3712 let ns = (*node).ns;
3713 if ns.is_null() || (*ns).href.is_null() {
3714 String::new()
3715 } else {
3716 CStr::from_ptr((*ns).href as *const c_char)
3717 .to_string_lossy()
3718 .into_owned()
3719 }
3720 }
3721 t if t == ET::XML_NAMESPACE_DECL as c_int => {
3722 let ns = node as *mut crate::abi::structs::_xmlNs;
3723 if (*ns).href.is_null() {
3724 String::new()
3725 } else {
3726 CStr::from_ptr((*ns).href as *const c_char)
3727 .to_string_lossy()
3728 .into_owned()
3729 }
3730 }
3731 _ => String::new(),
3732 }
3733 }
3734}
3735
3736#[no_mangle]
3753pub unsafe extern "C" fn xmlXPathNamespaceURIFunction(ctxt: *mut c_void, nargs: c_int) {
3754 let pc = pc_from(ctxt);
3755 if pc.is_null() {
3756 return;
3757 }
3758 let ctx = unsafe { (*pc).context };
3759 if ctx.is_null() {
3760 return;
3761 }
3762 if nargs == 0 {
3763 value_push(
3764 pc,
3765 crate::abi::exports_xml2::xpath_to_object_pub(XPathValue::NodeSet(NodeSet::singleton(
3766 unsafe { (*ctx).node },
3767 ))),
3768 );
3769 }
3770
3771 if !check_arity(pc, 1) {
3772 return;
3773 }
3774 let cur = value_pop(pc);
3775 if cur.is_null() {
3776 pc_set_error(pc, crate::abi::types::XPATH_INVALID_OPERAND as c_int);
3777 return;
3778 }
3779 let typ = unsafe { (*cur).type_ };
3780 if typ != xmlXPathObjectType::XPATH_NODESET as c_int
3781 && typ != xmlXPathObjectType::XPATH_XSLT_TREE as c_int
3782 {
3783 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3784 pc_set_error(pc, crate::abi::types::XPATH_INVALID_TYPE as c_int);
3785 return;
3786 }
3787 let uri = unsafe {
3788 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
3789 if ns.is_null() || (*ns).nodeNr == 0 {
3790 String::new()
3791 } else {
3792 node_namespace_uri(*(*ns).nodeTab)
3793 }
3794 };
3795 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3796 let out = dup_rust_string(&uri);
3797 value_push(pc, xmlXPathWrapString(out));
3798}
3799
3800#[no_mangle]
3817pub unsafe extern "C" fn xmlXPathStringFunction(ctxt: *mut c_void, nargs: c_int) {
3818 let pc = pc_from(ctxt);
3819 if pc.is_null() {
3820 return;
3821 }
3822 let ctx = unsafe { (*pc).context };
3823 if ctx.is_null() {
3824 return;
3825 }
3826 if nargs == 0 {
3827 let node = unsafe { (*ctx).node };
3828 let sv = if node.is_null() {
3829 String::new()
3830 } else {
3831 node_string_value(node)
3832 };
3833 let out = dup_rust_string(&sv);
3834 value_push(pc, xmlXPathWrapString(out));
3835 return;
3836 }
3837 if !check_arity(pc, 1) {
3838 return;
3839 }
3840 cast_top_to_string(pc);
3841}
3842
3843#[no_mangle]
3860pub unsafe extern "C" fn xmlXPathStringLengthFunction(ctxt: *mut c_void, nargs: c_int) {
3861 let pc = pc_from(ctxt);
3862 if pc.is_null() {
3863 return;
3864 }
3865 let ctx = unsafe { (*pc).context };
3866 if ctx.is_null() {
3867 return;
3868 }
3869 if nargs == 0 {
3870 let node = unsafe { (*ctx).node };
3871 let len = if node.is_null() {
3872 0
3873 } else {
3874 let sv = node_string_value(node);
3875 sv.chars().count()
3876 };
3877 value_push(pc, new_number(len as f64));
3878 return;
3879 }
3880 if !check_arity(pc, 1) {
3881 return;
3882 }
3883 cast_top_to_string(pc);
3884 if (*pc).error != 0 {
3885 return;
3886 }
3887 let len = unsafe {
3888 let s = (*(*pc).value).stringval;
3889 if s.is_null() {
3890 0
3891 } else {
3892 let sv = CStr::from_ptr(s as *const c_char).to_string_lossy();
3893 sv.chars().count()
3894 }
3895 };
3896 let cur = value_pop(pc);
3897 if !cur.is_null() {
3898 crate::abi::exports_xml2::xmlXPathFreeObject(cur);
3899 }
3900 value_push(pc, new_number(len as f64));
3901}
3902
3903#[no_mangle]
3920pub unsafe extern "C" fn xmlXPathConcatFunction(ctxt: *mut c_void, nargs: c_int) {
3921 let pc = pc_from(ctxt);
3922 if pc.is_null() {
3923 return;
3924 }
3925 if nargs < 2 && !check_arity(pc, 2) {
3926 return;
3927 }
3928 if !check_arity(pc, nargs) {
3929 return;
3930 }
3931 let mut parts: Vec<String> = Vec::with_capacity(nargs as usize);
3932 for _ in 0..nargs {
3933 cast_top_to_string(pc);
3934 if (*pc).error != 0 {
3935 return;
3936 }
3937 let v = crate::abi::exports_xml2::object_to_xpathvalue_pub(unsafe { (*pc).value });
3938 let s = v.as_string();
3939 let obj = value_pop(pc);
3940 if !obj.is_null() {
3941 crate::abi::exports_xml2::xmlXPathFreeObject(obj);
3942 }
3943 parts.push(s);
3944 }
3945 parts.reverse();
3946 let joined = parts.concat();
3947 let out = dup_rust_string(&joined);
3948 value_push(pc, xmlXPathWrapString(out));
3949}
3950
3951#[no_mangle]
3968pub unsafe extern "C" fn xmlXPathContainsFunction(ctxt: *mut c_void, _nargs: c_int) {
3969 let pc = pc_from(ctxt);
3970 if pc.is_null() {
3971 return;
3972 }
3973 if !check_arity(pc, 2) {
3974 return;
3975 }
3976 cast_top_to_string(pc);
3977 if (*pc).error != 0 {
3978 return;
3979 }
3980 let needle = value_pop(pc);
3981 cast_top_to_string(pc);
3982 if (*pc).error != 0 {
3983 if !needle.is_null() {
3984 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
3985 }
3986 return;
3987 }
3988 let hay = value_pop(pc);
3989 let found = if hay.is_null() || needle.is_null() {
3990 false
3991 } else {
3992 unsafe { !cstr_find((*hay).stringval, (*needle).stringval).is_null() }
3993 };
3994 if !hay.is_null() {
3995 crate::abi::exports_xml2::xmlXPathFreeObject(hay);
3996 }
3997 if !needle.is_null() {
3998 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
3999 }
4000 value_push(pc, new_bool(found));
4001}
4002
4003#[no_mangle]
4020pub unsafe extern "C" fn xmlXPathStartsWithFunction(ctxt: *mut c_void, _nargs: c_int) {
4021 let pc = pc_from(ctxt);
4022 if pc.is_null() {
4023 return;
4024 }
4025 if !check_arity(pc, 2) {
4026 return;
4027 }
4028 cast_top_to_string(pc);
4029 if (*pc).error != 0 {
4030 return;
4031 }
4032 let needle = value_pop(pc);
4033 cast_top_to_string(pc);
4034 if (*pc).error != 0 {
4035 if !needle.is_null() {
4036 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
4037 }
4038 return;
4039 }
4040 let hay = value_pop(pc);
4041 let found = if hay.is_null() || needle.is_null() {
4042 false
4043 } else {
4044 unsafe { crate::xml::string::xml_str_starts_with((*hay).stringval, (*needle).stringval) }
4045 };
4046 if !hay.is_null() {
4047 crate::abi::exports_xml2::xmlXPathFreeObject(hay);
4048 }
4049 if !needle.is_null() {
4050 crate::abi::exports_xml2::xmlXPathFreeObject(needle);
4051 }
4052 value_push(pc, new_bool(found));
4053}
4054
4055#[no_mangle]
4072pub unsafe extern "C" fn xmlXPathSubstringFunction(ctxt: *mut c_void, nargs: c_int) {
4073 let pc = pc_from(ctxt);
4074 if pc.is_null() {
4075 return;
4076 }
4077 if nargs < 2 {
4078 if !check_arity(pc, 2) {
4079 return;
4080 }
4081 } else if nargs > 3 && !check_arity(pc, 3) {
4082 return;
4083 }
4084 let mut le = 0.0;
4085 if nargs == 3 {
4086 cast_top_to_number(pc);
4087 if (*pc).error != 0 {
4088 return;
4089 }
4090 let len_obj = value_pop(pc);
4091 if !len_obj.is_null() {
4092 le = unsafe { (*len_obj).floatval };
4093 crate::abi::exports_xml2::xmlXPathFreeObject(len_obj);
4094 }
4095 }
4096 cast_top_to_number(pc);
4097 if (*pc).error != 0 {
4098 return;
4099 }
4100 let start_obj = value_pop(pc);
4101 let in_ = if start_obj.is_null() {
4102 f64::NAN
4103 } else {
4104 let v = unsafe { (*start_obj).floatval };
4105 crate::abi::exports_xml2::xmlXPathFreeObject(start_obj);
4106 v
4107 };
4108 cast_top_to_string(pc);
4109 if (*pc).error != 0 {
4110 return;
4111 }
4112 let str_obj = value_pop(pc);
4113 let s = if str_obj.is_null() {
4114 String::new()
4115 } else {
4116 let v = unsafe { CStr::from_ptr((*str_obj).stringval as *const c_char) }
4117 .to_string_lossy()
4118 .into_owned();
4119 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
4120 v
4121 };
4122
4123 let int_max = i32::MAX as f64;
4124 let mut i: i64 = 1;
4125 let mut j: i64 = i32::MAX as i64;
4126 #[allow(clippy::neg_cmp_op_on_partial_ord)]
4130 if !(in_ < int_max) {
4131 i = i32::MAX as i64;
4132 } else if in_ >= 1.0 {
4133 i = in_ as i64;
4134 if in_ - in_.floor() >= 0.5 {
4135 i += 1;
4136 }
4137 }
4138 if nargs == 3 {
4139 let mut rin = in_.floor();
4140 if in_ - rin >= 0.5 {
4141 rin += 1.0;
4142 }
4143 let mut rle = le.floor();
4144 if le - rle >= 0.5 {
4145 rle += 1.0;
4146 }
4147 let end = rin + rle;
4148 #[allow(clippy::neg_cmp_op_on_partial_ord)]
4149 if !(end >= 1.0) {
4150 j = 1;
4151 } else if end < int_max {
4152 j = end as i64;
4153 }
4154 }
4155 i -= 1;
4156 j -= 1;
4157 let chars: Vec<char> = s.chars().collect();
4158 let slen = chars.len() as i64;
4159 let out = if i < j && i < slen {
4160 let start_i = i.max(0) as usize;
4161 let end_i = (j.min(slen)).max(start_i as i64) as usize;
4162 chars[start_i..end_i].iter().collect()
4163 } else {
4164 String::new()
4165 };
4166 let c = dup_rust_string(&out);
4167 value_push(pc, xmlXPathWrapString(c));
4168}
4169
4170#[no_mangle]
4187pub unsafe extern "C" fn xmlXPathSubstringBeforeFunction(ctxt: *mut c_void, _nargs: c_int) {
4188 let pc = pc_from(ctxt);
4189 if pc.is_null() {
4190 return;
4191 }
4192 if !check_arity(pc, 2) {
4193 return;
4194 }
4195 cast_top_to_string(pc);
4196 if (*pc).error != 0 {
4197 return;
4198 }
4199 let find = value_pop(pc);
4200 cast_top_to_string(pc);
4201 if (*pc).error != 0 {
4202 if !find.is_null() {
4203 crate::abi::exports_xml2::xmlXPathFreeObject(find);
4204 }
4205 return;
4206 }
4207 let str_obj = value_pop(pc);
4208 let out: String = if str_obj.is_null() || find.is_null() {
4209 String::new()
4210 } else {
4211 unsafe {
4212 let hay = (*str_obj).stringval;
4213 let needle = (*find).stringval;
4214 let point = cstr_find(hay, needle);
4215 if point.is_null() {
4216 String::new()
4217 } else {
4218 let len = point.offset_from(hay) as usize;
4219 let bytes = core::slice::from_raw_parts(hay as *const u8, len);
4220 String::from_utf8_lossy(bytes).into_owned()
4221 }
4222 }
4223 };
4224 if !str_obj.is_null() {
4225 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
4226 }
4227 if !find.is_null() {
4228 crate::abi::exports_xml2::xmlXPathFreeObject(find);
4229 }
4230 let c = dup_rust_string(&out);
4231 value_push(pc, xmlXPathWrapString(c));
4232}
4233
4234#[no_mangle]
4251pub unsafe extern "C" fn xmlXPathSubstringAfterFunction(ctxt: *mut c_void, _nargs: c_int) {
4252 let pc = pc_from(ctxt);
4253 if pc.is_null() {
4254 return;
4255 }
4256 if !check_arity(pc, 2) {
4257 return;
4258 }
4259 cast_top_to_string(pc);
4260 if (*pc).error != 0 {
4261 return;
4262 }
4263 let find = value_pop(pc);
4264 cast_top_to_string(pc);
4265 if (*pc).error != 0 {
4266 if !find.is_null() {
4267 crate::abi::exports_xml2::xmlXPathFreeObject(find);
4268 }
4269 return;
4270 }
4271 let str_obj = value_pop(pc);
4272 let out: String = if str_obj.is_null() || find.is_null() {
4273 String::new()
4274 } else {
4275 unsafe {
4276 let hay = (*str_obj).stringval;
4277 let needle = (*find).stringval;
4278 let point = cstr_find(hay, needle);
4279 if point.is_null() {
4280 String::new()
4281 } else {
4282 let nlen = crate::xml::string::xml_strlen(needle);
4283 let rest = point.add(nlen);
4284 let len = crate::xml::string::xml_strlen(rest);
4285 let bytes = core::slice::from_raw_parts(rest, len);
4286 String::from_utf8_lossy(bytes).into_owned()
4287 }
4288 }
4289 };
4290 if !str_obj.is_null() {
4291 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
4292 }
4293 if !find.is_null() {
4294 crate::abi::exports_xml2::xmlXPathFreeObject(find);
4295 }
4296 let c = dup_rust_string(&out);
4297 value_push(pc, xmlXPathWrapString(c));
4298}
4299
4300#[no_mangle]
4317pub unsafe extern "C" fn xmlXPathNormalizeFunction(ctxt: *mut c_void, nargs: c_int) {
4318 let pc = pc_from(ctxt);
4319 if pc.is_null() {
4320 return;
4321 }
4322 let ctx = unsafe { (*pc).context };
4323 if ctx.is_null() {
4324 return;
4325 }
4326 if nargs == 0 {
4327 let node = unsafe { (*ctx).node };
4328 let sv = if node.is_null() {
4329 String::new()
4330 } else {
4331 node_string_value(node)
4332 };
4333 let c = dup_rust_string(&sv);
4334 value_push(pc, xmlXPathWrapString(c));
4335 }
4337
4338 if !check_arity(pc, 1) {
4339 return;
4340 }
4341 cast_top_to_string(pc);
4342 if (*pc).error != 0 {
4343 return;
4344 }
4345 let s = unsafe {
4346 let p = (*(*pc).value).stringval;
4347 if p.is_null() {
4348 String::new()
4349 } else {
4350 CStr::from_ptr(p as *const c_char)
4351 .to_string_lossy()
4352 .into_owned()
4353 }
4354 };
4355 let mut out = String::with_capacity(s.len());
4357 let mut blank = false;
4358 let mut started = false;
4359 for c in s.chars() {
4360 let is_b = c == ' ' || c == '\t' || c == '\n' || c == '\r';
4361 if is_b {
4362 if started {
4363 blank = true;
4364 }
4365 } else {
4366 if blank {
4367 out.push(' ');
4368 blank = false;
4369 }
4370 out.push(c);
4371 started = true;
4372 }
4373 }
4374 unsafe {
4375 let val = (*pc).value;
4376 if !(*val).stringval.is_null() {
4377 xmlFreeImpl((*val).stringval as *mut c_void);
4378 }
4379 (*val).stringval = dup_rust_string(&out);
4380 }
4381}
4382
4383#[no_mangle]
4400pub unsafe extern "C" fn xmlXPathTranslateFunction(ctxt: *mut c_void, _nargs: c_int) {
4401 let pc = pc_from(ctxt);
4402 if pc.is_null() {
4403 return;
4404 }
4405 if !check_arity(pc, 3) {
4406 return;
4407 }
4408 cast_top_to_string(pc);
4409 if (*pc).error != 0 {
4410 return;
4411 }
4412 let to = value_pop(pc);
4413 cast_top_to_string(pc);
4414 if (*pc).error != 0 {
4415 if !to.is_null() {
4416 crate::abi::exports_xml2::xmlXPathFreeObject(to);
4417 }
4418 return;
4419 }
4420 let from = value_pop(pc);
4421 cast_top_to_string(pc);
4422 if (*pc).error != 0 {
4423 if !to.is_null() {
4424 crate::abi::exports_xml2::xmlXPathFreeObject(to);
4425 }
4426 if !from.is_null() {
4427 crate::abi::exports_xml2::xmlXPathFreeObject(from);
4428 }
4429 return;
4430 }
4431 let str_obj = value_pop(pc);
4432 let (s, f, t) = unsafe {
4433 let s = if str_obj.is_null() || (*str_obj).stringval.is_null() {
4434 String::new()
4435 } else {
4436 CStr::from_ptr((*str_obj).stringval as *const c_char)
4437 .to_string_lossy()
4438 .into_owned()
4439 };
4440 let f = if from.is_null() || (*from).stringval.is_null() {
4441 String::new()
4442 } else {
4443 CStr::from_ptr((*from).stringval as *const c_char)
4444 .to_string_lossy()
4445 .into_owned()
4446 };
4447 let t = if to.is_null() || (*to).stringval.is_null() {
4448 String::new()
4449 } else {
4450 CStr::from_ptr((*to).stringval as *const c_char)
4451 .to_string_lossy()
4452 .into_owned()
4453 };
4454 (s, f, t)
4455 };
4456 if !str_obj.is_null() {
4457 crate::abi::exports_xml2::xmlXPathFreeObject(str_obj);
4458 }
4459 if !from.is_null() {
4460 crate::abi::exports_xml2::xmlXPathFreeObject(from);
4461 }
4462 if !to.is_null() {
4463 crate::abi::exports_xml2::xmlXPathFreeObject(to);
4464 }
4465 let from_chars: Vec<char> = f.chars().collect();
4466 let to_chars: Vec<char> = t.chars().collect();
4467 let out: String = s
4470 .chars()
4471 .filter_map(|c| match from_chars.iter().position(|&x| x == c) {
4472 Some(i) if i < to_chars.len() => Some(to_chars[i]),
4473 Some(_) => None,
4474 _ => Some(c),
4475 })
4476 .collect();
4477 let c = dup_rust_string(&out);
4478 value_push(pc, xmlXPathWrapString(c));
4479}
4480
4481#[no_mangle]
4499pub const unsafe extern "C" fn xmlXPathRegisterAllFunctions(_ctxt: *mut _xmlXPathContext) {}
4500
4501unsafe fn standard_function_pointer(
4504 name: &str,
4505) -> Option<unsafe extern "C" fn(*mut c_void, c_int)> {
4506 let f: unsafe extern "C" fn(*mut c_void, c_int) = match name {
4507 "boolean" => xmlXPathBooleanFunction,
4508 "not" => xmlXPathNotFunction,
4509 "true" => xmlXPathTrueFunction,
4510 "false" => xmlXPathFalseFunction,
4511 "lang" => xmlXPathLangFunction,
4512 "number" => xmlXPathNumberFunction,
4513 "sum" => xmlXPathSumFunction,
4514 "floor" => xmlXPathFloorFunction,
4515 "ceiling" => xmlXPathCeilingFunction,
4516 "round" => xmlXPathRoundFunction,
4517 "last" => xmlXPathLastFunction,
4518 "position" => xmlXPathPositionFunction,
4519 "count" => xmlXPathCountFunction,
4520 "id" => xmlXPathIdFunction,
4521 "local-name" => xmlXPathLocalNameFunction,
4522 "namespace-uri" => xmlXPathNamespaceURIFunction,
4523 "string" => xmlXPathStringFunction,
4524 "string-length" => xmlXPathStringLengthFunction,
4525 "concat" => xmlXPathConcatFunction,
4526 "contains" => xmlXPathContainsFunction,
4527 "starts-with" => xmlXPathStartsWithFunction,
4528 "substring" => xmlXPathSubstringFunction,
4529 "substring-before" => xmlXPathSubstringBeforeFunction,
4530 "substring-after" => xmlXPathSubstringAfterFunction,
4531 "normalize-space" => xmlXPathNormalizeFunction,
4532 "translate" => xmlXPathTranslateFunction,
4533 _ => return None,
4534 };
4535 Some(f)
4536}
4537
4538#[no_mangle]
4544pub unsafe extern "C" fn xmlXPathFunctionLookup(
4545 ctxt: *mut _xmlXPathContext,
4546 name: *const xmlChar,
4547) -> Option<unsafe extern "C" fn(*mut c_void, c_int)> {
4548 xmlXPathFunctionLookupNS(ctxt, name, ptr::null())
4549}
4550
4551#[no_mangle]
4557pub unsafe extern "C" fn xmlXPathFunctionLookupNS(
4558 ctxt: *mut _xmlXPathContext,
4559 name: *const xmlChar,
4560 ns_uri: *const xmlChar,
4561) -> Option<unsafe extern "C" fn(*mut c_void, c_int)> {
4562 if ctxt.is_null() || name.is_null() {
4563 return None;
4564 }
4565 let name_str = match CStr::from_ptr(name as *const c_char).to_str() {
4566 Ok(s) => s.to_string(),
4567 Err(_) => return None,
4568 };
4569 if ns_uri.is_null() {
4570 if let Some(f) = standard_function_pointer(&name_str) {
4571 return Some(f);
4572 }
4573 }
4574 if let Some(f) = (*ctxt).funcLookupFunc {
4576 let ret = f((*ctxt).funcLookupData, name, ns_uri);
4577 if !ret.is_null() {
4578 let fp =
4580 std::mem::transmute::<*mut c_void, unsafe extern "C" fn(*mut c_void, c_int)>(ret);
4581 return Some(fp);
4582 }
4583 }
4584 let qualified = if ns_uri.is_null() {
4585 name_str
4586 } else {
4587 let ns = match CStr::from_ptr(ns_uri as *const c_char).to_str() {
4588 Ok(s) => s,
4589 Err(_) => return None,
4590 };
4591 format!("{{{}}}{}", ns, name_str)
4592 };
4593 crate::abi::exports_xml2::xpath_cfunc_lookup((*ctxt).extra, &qualified)
4594}
4595
4596#[no_mangle]
4610pub unsafe extern "C" fn xmlXPathCtxtCompile(
4611 _ctxt: *mut _xmlXPathContext,
4612 str_: *const xmlChar,
4613) -> *mut c_void {
4614 crate::abi::exports_xml2::xmlXPathCompile(str_)
4615}
4616
4617#[no_mangle]
4623pub unsafe extern "C" fn xmlXPathCompiledEval(
4624 comp: *mut c_void,
4625 ctx: *mut _xmlXPathContext,
4626) -> *mut _xmlXPathObject {
4627 if comp.is_null() || ctx.is_null() {
4628 return ptr::null_mut();
4629 }
4630 let internal = (*ctx).extra as *mut XPathContext;
4631 if internal.is_null() {
4632 return ptr::null_mut();
4633 }
4634 let internal = &mut *internal;
4635 let registry = crate::abi::exports_xml2::xpath_compiled_registry();
4636 let map = registry.lock();
4637 match map.get(&(comp as u64)) {
4638 Some(compiled) => match crate::xml::xpath::evaluate(compiled, internal) {
4639 Some(val) => crate::abi::exports_xml2::xpath_to_object_pub(val),
4640 None => ptr::null_mut(),
4641 },
4642 None => ptr::null_mut(),
4643 }
4644}
4645
4646#[no_mangle]
4654pub unsafe extern "C" fn xmlXPathCompiledEvalToBoolean(
4655 comp: *mut c_void,
4656 ctxt: *mut _xmlXPathContext,
4657) -> c_int {
4658 let obj = xmlXPathCompiledEval(comp, ctxt);
4659 if obj.is_null() {
4660 return -1;
4661 }
4662 let b = crate::abi::exports_xml2::object_to_xpathvalue_pub(obj).as_boolean();
4663 crate::abi::exports_xml2::xmlXPathFreeObject(obj);
4664 b as c_int
4665}
4666
4667#[no_mangle]
4674pub unsafe extern "C" fn xmlXPathSetContextNode(
4675 node: *mut _xmlNode,
4676 ctx: *mut _xmlXPathContext,
4677) -> c_int {
4678 if node.is_null() || ctx.is_null() {
4679 return -1;
4680 }
4681 if (*node).doc != (*ctx).doc {
4682 return -1;
4683 }
4684 (*ctx).node = node;
4685 let internal = (*ctx).extra as *mut XPathContext;
4686 if !internal.is_null() {
4687 (*internal).context_node = node;
4688 }
4689 0
4690}
4691
4692#[no_mangle]
4698pub unsafe extern "C" fn xmlXPathNodeEval(
4699 node: *mut _xmlNode,
4700 str_: *const xmlChar,
4701 ctx: *mut _xmlXPathContext,
4702) -> *mut _xmlXPathObject {
4703 if str_.is_null() {
4704 return ptr::null_mut();
4705 }
4706 if xmlXPathSetContextNode(node, ctx) < 0 {
4707 return ptr::null_mut();
4708 }
4709 crate::abi::exports_xml2::xmlXPathEvalExpression(str_, ctx)
4710}
4711
4712#[no_mangle]
4721pub unsafe extern "C" fn xmlXPathContextSetCache(
4722 ctxt: *mut _xmlXPathContext,
4723 active: c_int,
4724 _value: c_int,
4725 _options: c_int,
4726) -> c_int {
4727 if ctxt.is_null() {
4728 return -1;
4729 }
4730 (*ctxt).cache = if active != 0 {
4731 (&XML_XPATH_XML_NS.0) as *const crate::abi::structs::_xmlNs as *mut c_void
4732 } else {
4733 ptr::null_mut()
4734 };
4735 0
4736}
4737
4738#[no_mangle]
4744pub unsafe extern "C" fn xmlXPathRegisterFuncLookup(
4745 ctxt: *mut _xmlXPathContext,
4746 f: Option<crate::abi::callbacks::xmlXPathFuncLookupFunc>,
4747 data: *mut c_void,
4748) {
4749 if ctxt.is_null() {
4750 return;
4751 }
4752 (*ctxt).funcLookupFunc = f;
4753 (*ctxt).funcLookupData = data;
4754 let internal = (*ctxt).extra as *mut XPathContext;
4755 if !internal.is_null() {
4756 (*internal).func_lookup_func = f;
4757 (*internal).func_lookup_data = data;
4758 }
4759}
4760
4761#[no_mangle]
4767pub unsafe extern "C" fn xmlXPathRegisterVariableLookup(
4768 ctxt: *mut _xmlXPathContext,
4769 f: Option<crate::abi::callbacks::xmlXPathVariableLookupFunc>,
4770 data: *mut c_void,
4771) {
4772 if ctxt.is_null() {
4773 return;
4774 }
4775 (*ctxt).varLookupFunc = f;
4776 (*ctxt).varLookupData = data;
4777 let internal = (*ctxt).extra as *mut XPathContext;
4778 if !internal.is_null() {
4779 (*internal).var_lookup_func = f;
4780 (*internal).var_lookup_data = data;
4781 }
4782}
4783
4784#[no_mangle]
4790pub unsafe extern "C" fn xmlXPathRegisterVariableNS(
4791 ctxt: *mut _xmlXPathContext,
4792 name: *const xmlChar,
4793 ns_uri: *const xmlChar,
4794 value: *mut _xmlXPathObject,
4795) -> c_int {
4796 if ctxt.is_null() || name.is_null() || value.is_null() {
4797 return -1;
4798 }
4799 let internal = (*ctxt).extra as *mut XPathContext;
4800 if internal.is_null() {
4801 return -1;
4802 }
4803 let internal = &mut *internal;
4804 let name_str = match CStr::from_ptr(name as *const c_char).to_str() {
4805 Ok(s) => s.to_string(),
4806 Err(_) => return -1,
4807 };
4808 let qualified = if ns_uri.is_null() {
4809 name_str
4810 } else {
4811 match CStr::from_ptr(ns_uri as *const c_char).to_str() {
4812 Ok(s) => format!("{{{}}}{}", s, name_str),
4813 Err(_) => return -1,
4814 }
4815 };
4816 let xpath_val = crate::abi::exports_xml2::object_to_xpathvalue_pub(value);
4817 internal.register_variable(&qualified, xpath_val);
4818 0
4819}
4820
4821#[no_mangle]
4827pub unsafe extern "C" fn xmlXPathVariableLookup(
4828 ctxt: *mut _xmlXPathContext,
4829 name: *const xmlChar,
4830) -> *mut _xmlXPathObject {
4831 if ctxt.is_null() {
4832 return ptr::null_mut();
4833 }
4834 if let Some(f) = (*ctxt).varLookupFunc {
4835 let ret = f((*ctxt).varLookupData, name, ptr::null());
4836 return ret;
4837 }
4838 xmlXPathVariableLookupNS(ctxt, name, ptr::null())
4839}
4840
4841#[no_mangle]
4847pub unsafe extern "C" fn xmlXPathVariableLookupNS(
4848 ctxt: *mut _xmlXPathContext,
4849 name: *const xmlChar,
4850 ns_uri: *const xmlChar,
4851) -> *mut _xmlXPathObject {
4852 if ctxt.is_null() || name.is_null() {
4853 return ptr::null_mut();
4854 }
4855 if let Some(f) = (*ctxt).varLookupFunc {
4856 let ret = f((*ctxt).varLookupData, name, ns_uri);
4857 if !ret.is_null() {
4858 return ret;
4859 }
4860 }
4861 let internal = (*ctxt).extra as *mut XPathContext;
4862 if internal.is_null() {
4863 return ptr::null_mut();
4864 }
4865 let internal = &*internal;
4866 let name_str = match CStr::from_ptr(name as *const c_char).to_str() {
4867 Ok(s) => s.to_string(),
4868 Err(_) => return ptr::null_mut(),
4869 };
4870 let qualified = if ns_uri.is_null() {
4871 name_str
4872 } else {
4873 match CStr::from_ptr(ns_uri as *const c_char).to_str() {
4874 Ok(s) => format!("{{{}}}{}", s, name_str),
4875 Err(_) => return ptr::null_mut(),
4876 }
4877 };
4878 match internal.variables.get(&qualified) {
4879 Some(v) => crate::abi::exports_xml2::xpath_to_object_pub(v.clone()),
4880 None => ptr::null_mut(),
4881 }
4882}
4883
4884#[no_mangle]
4890pub unsafe extern "C" fn xmlXPathNsLookup(
4891 ctxt: *mut _xmlXPathContext,
4892 prefix: *const xmlChar,
4893) -> *const xmlChar {
4894 if ctxt.is_null() || prefix.is_null() {
4895 return ptr::null();
4896 }
4897 if cstr_eq(prefix, c"xml".as_ptr() as *const xmlChar) {
4899 return XML_XML_NAMESPACE_BYTES.as_ptr() as *const xmlChar;
4900 }
4901 let namespaces = (*ctxt).namespaces;
4903 if !namespaces.is_null() {
4904 for i in 0..(*ctxt).nsNr as isize {
4905 let ns = *namespaces.add(i as usize);
4906 if !ns.is_null() && !(*ns).prefix.is_null() && cstr_eq((*ns).prefix, prefix) {
4907 return (*ns).href;
4908 }
4909 }
4910 }
4911 if !(*ctxt).nsHash.is_null() {
4914 let map = &*((*ctxt).nsHash as *const HashMap<String, CString>);
4915 let p = CStr::from_ptr(prefix as *const c_char)
4916 .to_string_lossy()
4917 .into_owned();
4918 if let Some(c) = map.get(&p) {
4919 return c.as_ptr() as *const xmlChar;
4920 }
4921 }
4922 ptr::null()
4923}
4924
4925#[no_mangle]
4931pub unsafe extern "C" fn xmlXPathRegisteredFuncsCleanup(ctxt: *mut _xmlXPathContext) {
4932 if ctxt.is_null() {
4933 return;
4934 }
4935 let internal = (*ctxt).extra as *mut XPathContext;
4936 if !internal.is_null() {
4937 (*internal).functions.clear();
4938 }
4939 crate::abi::exports_xml2::xpath_cfunc_cleanup((*ctxt).extra);
4940}
4941
4942#[no_mangle]
4948pub unsafe extern "C" fn xmlXPathRegisteredVariablesCleanup(ctxt: *mut _xmlXPathContext) {
4949 if ctxt.is_null() {
4950 return;
4951 }
4952 let internal = (*ctxt).extra as *mut XPathContext;
4953 if !internal.is_null() {
4954 (*internal).variables.clear();
4955 }
4956}
4957
4958#[no_mangle]
4964pub unsafe extern "C" fn xmlXPathRegisteredNsCleanup(ctxt: *mut _xmlXPathContext) {
4965 if ctxt.is_null() {
4966 return;
4967 }
4968 let internal = (*ctxt).extra as *mut XPathContext;
4969 if !internal.is_null() {
4970 (*internal).namespaces.clear();
4971 }
4972 if !(*ctxt).nsHash.is_null() {
4973 drop(Box::from_raw(
4974 (*ctxt).nsHash as *mut HashMap<String, CString>,
4975 ));
4976 (*ctxt).nsHash = ptr::null_mut();
4977 }
4978}
4979
4980#[no_mangle]
4986pub unsafe extern "C" fn xmlXPathSetErrorHandler(
4987 ctxt: *mut _xmlXPathContext,
4988 handler: Option<crate::abi::callbacks::xmlStructuredErrorFunc>,
4989 data: *mut c_void,
4990) {
4991 if ctxt.is_null() {
4992 return;
4993 }
4994 (*ctxt).error = handler;
4995 (*ctxt).userData = data;
4996}
4997
4998extern "C" {
4999 fn fwrite(ptr: *const c_void, size: usize, nmemb: usize, stream: *mut c_void) -> usize;
5000}
5001
5002unsafe fn dump_write(output: *mut c_void, s: &str) {
5003 unsafe {
5004 fwrite(s.as_ptr() as *const c_void, 1, s.len(), output);
5005 }
5006}
5007
5008#[no_mangle]
5014pub unsafe extern "C" fn xmlXPathDebugDumpObject(
5015 output: *mut c_void,
5016 cur: *mut _xmlXPathObject,
5017 depth: c_int,
5018) {
5019 if output.is_null() {
5020 return;
5021 }
5022 let mut s = String::new();
5023 for _ in 0..depth.clamp(0, 25) {
5024 s.push_str(" ");
5025 }
5026 if cur.is_null() {
5027 s.push_str("Object is empty (NULL)\n");
5028 dump_write(output, &s);
5029 return;
5030 }
5031 unsafe {
5032 match (*cur).type_ {
5033 t if t == xmlXPathObjectType::XPATH_BOOLEAN as c_int => {
5034 s.push_str("Object is a Boolean : ");
5035 s.push_str(if (*cur).boolval != 0 {
5036 "true\n"
5037 } else {
5038 "false\n"
5039 });
5040 }
5041 t if t == xmlXPathObjectType::XPATH_NUMBER as c_int => {
5042 let f = (*cur).floatval;
5043 if f.is_nan() {
5044 s.push_str("Object is a number : NaN\n");
5045 } else if f == f64::INFINITY {
5046 s.push_str("Object is a number : Infinity\n");
5047 } else if f == f64::NEG_INFINITY {
5048 s.push_str("Object is a number : -Infinity\n");
5049 } else if f == 0.0 {
5050 s.push_str("Object is a number : 0\n");
5051 } else {
5052 s.push_str("Object is a number : ");
5053 s.push_str(&f.to_string());
5054 s.push('\n');
5055 }
5056 }
5057 t if t == xmlXPathObjectType::XPATH_STRING as c_int => {
5058 s.push_str("Object is a string : ");
5059 if (*cur).stringval.is_null() {
5060 s.push_str("(null)");
5061 } else {
5062 let sv = CStr::from_ptr((*cur).stringval as *const c_char).to_string_lossy();
5063 s.push_str(&sv);
5064 }
5065 s.push('\n');
5066 }
5067 t if t == xmlXPathObjectType::XPATH_NODESET as c_int => {
5068 s.push_str("Object is a Node Set :\n");
5069 let ns = (*cur).nodesetval as *mut _xmlNodeSet;
5070 if !ns.is_null() {
5071 for _ in 0..=depth.min(24) {
5072 s.push_str(" ");
5073 }
5074 s.push_str(&format!("Object contains {} nodes\n", (*ns).nodeNr));
5075 }
5076 }
5077 t if t == xmlXPathObjectType::XPATH_XSLT_TREE as c_int => {
5078 s.push_str("Object is an XSLT value tree :\n");
5079 }
5080 t if t == xmlXPathObjectType::XPATH_USERS as c_int => {
5081 s.push_str("Object is user defined\n");
5082 }
5083 _ => {
5084 s.push_str("Object is uninitialized\n");
5085 }
5086 }
5087 }
5088 dump_write(output, &s);
5089}
5090
5091#[no_mangle]
5101pub unsafe extern "C" fn xmlXPathDebugDumpCompExpr(
5102 output: *mut c_void,
5103 comp: *mut c_void,
5104 depth: c_int,
5105) {
5106 if output.is_null() || comp.is_null() {
5107 return;
5108 }
5109 let registry = crate::abi::exports_xml2::xpath_compiled_registry();
5110 let map = registry.lock();
5111 if let Some(compiled) = map.get(&(comp as u64)) {
5112 let mut s = String::new();
5113 for _ in 0..depth.clamp(0, 25) {
5114 s.push_str(" ");
5115 }
5116 s.push_str("Compiled Expression : ");
5117 s.push_str(&compiled.original);
5118 s.push('\n');
5119 dump_write(output, &s);
5120 }
5121}
5122
5123#[allow(unused)]
5124const fn _unused_xpath_batch(_: *mut _xmlAttr) {}