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