1use core::ffi::c_void;
37use core::ptr;
38use std::os::raw::{c_char, c_int, c_uint};
39
40use crate::abi::allocator;
41use crate::abi::constants::*;
42use crate::abi::structs::*;
43use crate::abi::types::xmlAttributeType::XML_ATTRIBUTE_CDATA;
44use crate::abi::types::xmlCharEncoding::XML_CHAR_ENCODING_UTF8;
45use crate::abi::types::xmlDocProperties::XML_DOC_WELLFORMED;
46use crate::abi::types::xmlElementType::*;
47use crate::abi::types::*;
48use crate::xml::globals;
49
50unsafe fn dup_xml_str(str: *const xmlChar) -> *mut xmlChar {
60 if str.is_null() {
61 return ptr::null_mut();
62 }
63 let len = unsafe { crate::abi::exports_xml2::xmlStrlen(str) as usize };
64 if len == 0 {
65 let buf = unsafe { allocator::xmlMalloc(1) as *mut xmlChar };
67 if !buf.is_null() {
68 unsafe { *buf = 0 };
69 }
70 return buf;
71 }
72 let buf = unsafe { allocator::xmlMalloc(len + 1) as *mut xmlChar };
73 if !buf.is_null() {
74 unsafe {
75 ptr::copy_nonoverlapping(str, buf, len + 1);
76 }
77 }
78 buf
79}
80
81unsafe fn copy_xml_str_content(dest: *mut xmlChar, src: *const xmlChar, max_len: usize) -> bool {
83 if src.is_null() || dest.is_null() || max_len == 0 {
84 return false;
85 }
86 let len = unsafe { crate::abi::exports_xml2::xmlStrlen(src) as usize };
87 if len >= max_len {
88 return false;
89 }
90 unsafe {
91 ptr::copy_nonoverlapping(src, dest, len);
92 *dest.add(len) = 0;
93 }
94 true
95}
96
97pub unsafe fn xml_strlen(str: *const xmlChar) -> c_int {
99 if str.is_null() {
100 return 0;
101 }
102 let mut len: c_int = 0;
103 while unsafe { *str.add(len as usize) != 0 } {
104 len += 1;
105 }
106 len
107}
108
109pub unsafe fn new_doc(version: *const xmlChar) -> *mut _xmlDoc {
132 let doc = allocator::xmlMallocZero(size_of::<_xmlDoc>() as usize) as *mut _xmlDoc;
134 if doc.is_null() {
135 return ptr::null_mut();
136 }
137
138 unsafe {
139 (*doc).type_ = XML_DOCUMENT_NODE as c_int;
140 (*doc).standalone = -1; (*doc).doc = doc; (*doc).properties = XML_DOC_WELLFORMED as c_int;
143 (*doc).charset = XML_CHAR_ENCODING_UTF8 as c_int;
144
145 let ver = if version.is_null() {
147 XML_DEFAULT_VERSION.as_ptr() as *const xmlChar
148 } else {
149 version
150 };
151 (*doc).version = dup_xml_str(ver);
152 }
153
154 doc
155}
156
157pub unsafe fn free_doc(doc: *mut _xmlDoc) {
171 if doc.is_null() {
172 return;
173 }
174
175 let d = unsafe { &mut *doc };
176
177 if !d.intSubset.is_null() {
179 free_dtd(d.intSubset);
180 }
181
182 if !d.extSubset.is_null() {
184 free_dtd(d.extSubset);
185 }
186
187 if !d.children.is_null() {
189 free_node_list(d.children);
190 }
191
192 if !d.oldNs.is_null() {
194 free_ns_list(d.oldNs);
195 }
196
197 if !d.version.is_null() {
199 allocator::xmlFree(d.version as *mut c_void);
200 }
201 if !d.encoding.is_null() {
202 allocator::xmlFree(d.encoding as *mut c_void);
203 }
204 if !d.URL.is_null() {
205 allocator::xmlFree(d.URL as *mut c_void);
206 }
207
208 allocator::xmlFree(doc as *mut c_void);
210}
211
212pub unsafe fn copy_doc(doc: *const _xmlDoc, recursive: c_int) -> *mut _xmlDoc {
227 if doc.is_null() {
228 return ptr::null_mut();
229 }
230
231 let d = unsafe { &*doc };
232
233 let new_doc = new_doc(d.version);
234 if new_doc.is_null() {
235 return ptr::null_mut();
236 }
237
238 unsafe {
239 (*new_doc).type_ = d.type_;
240 (*new_doc).standalone = d.standalone;
241 (*new_doc).encoding = dup_xml_str(d.encoding);
242 (*new_doc).URL = dup_xml_str(d.URL);
243 (*new_doc).charset = d.charset;
244 (*new_doc).properties = d.properties;
245
246 if recursive != 0 && !d.children.is_null() {
247 (*new_doc).children = copy_node_list(d.children, recursive);
248 if !(*new_doc).children.is_null() {
249 (*(*new_doc).children).parent = ptr::null_mut(); (*(*new_doc).children).doc = new_doc;
251 propagate_doc((*new_doc).children, new_doc);
253 }
254 }
255 }
256
257 new_doc
258}
259
260pub unsafe fn doc_set_root_element(doc: *mut _xmlDoc, root: *mut _xmlNode) -> *mut _xmlNode {
276 if doc.is_null() {
277 return ptr::null_mut();
278 }
279
280 let d = unsafe { &mut *doc };
281
282 let old_root = doc_get_root_element(doc);
283
284 if !root.is_null() {
285 unsafe {
286 (*root).parent = ptr::null_mut();
287 (*root).doc = doc;
288 }
289 d.children = root;
290 d.last = root;
291 unsafe {
292 (*root).prev = ptr::null_mut();
293 (*root).next = ptr::null_mut();
294 }
295 } else {
296 d.children = ptr::null_mut();
297 d.last = ptr::null_mut();
298 }
299
300 old_root
301}
302
303pub fn doc_get_root_element(doc: *mut _xmlDoc) -> *mut _xmlNode {
314 if doc.is_null() {
315 return ptr::null_mut();
316 }
317
318 let d = unsafe { &*doc };
319 let mut cur = d.children;
320
321 while !cur.is_null() {
322 let node = unsafe { &*cur };
323 if node.type_ == XML_ELEMENT_NODE as c_int {
324 return cur;
325 }
326 cur = node.next;
327 }
328
329 ptr::null_mut()
330}
331
332pub fn get_line_no(node: *const _xmlNode) -> c_int {
342 if node.is_null() {
343 return 0;
344 }
345 let n = unsafe { &*node };
346 n.line as c_int
347}
348
349pub unsafe fn new_node(ns: *mut _xmlNs, name: *const xmlChar) -> *mut _xmlNode {
368 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
369 if node.is_null() {
370 return ptr::null_mut();
371 }
372
373 unsafe {
374 (*node).type_ = XML_ELEMENT_NODE as c_int;
375 (*node).name = dup_xml_str(name);
376 (*node).ns = ns;
377 (*node).line = 0;
378 (*node).extra = 0;
379
380 if !ns.is_null() {
381 (*ns).context = node as *mut _xmlDoc;
382 }
383 }
384
385 node
386}
387
388pub unsafe fn free_node(node: *mut _xmlNode) {
403 if node.is_null() {
404 return;
405 }
406
407 let n = unsafe { &mut *node };
408
409 if !n.properties.is_null() {
411 free_prop_list(n.properties);
412 }
413
414 if !n.nsDef.is_null() {
416 free_ns_list(n.nsDef);
417 }
418
419 if !n.name.is_null() {
421 allocator::xmlFree(n.name as *mut c_void);
422 }
423
424 if !n.content.is_null() {
426 let node_type = n.type_;
427 if node_type == XML_TEXT_NODE as c_int
428 || node_type == XML_CDATA_SECTION_NODE as c_int
429 || node_type == XML_COMMENT_NODE as c_int
430 || node_type == XML_PI_NODE as c_int
431 {
432 allocator::xmlFree(n.content as *mut c_void);
433 }
434 }
435
436 allocator::xmlFree(node as *mut c_void);
437}
438
439pub unsafe fn free_node_list(node: *mut _xmlNode) {
447 let mut cur = node;
448 while !cur.is_null() {
449 let next = unsafe { (*cur).next };
450
451 if !unsafe { (*cur).children }.is_null() {
453 free_node_list(unsafe { (*cur).children });
454 }
455
456 free_node(cur);
457 cur = next;
458 }
459}
460
461unsafe fn free_prop_list(prop: *mut _xmlAttr) {
467 let mut cur = prop;
468 while !cur.is_null() {
469 let next = unsafe { (*cur).next };
470
471 if !unsafe { (*cur).children }.is_null() {
473 free_node_list(unsafe { (*cur).children });
474 }
475
476 if !unsafe { (*cur).name }.is_null() {
478 allocator::xmlFree(unsafe { (*cur).name } as *mut c_void);
479 }
480
481 allocator::xmlFree(cur as *mut c_void);
482 cur = next;
483 }
484}
485
486unsafe fn free_ns_list(ns: *mut _xmlNs) {
492 let mut cur = ns;
493 while !cur.is_null() {
494 let next = unsafe { (*cur).next };
495
496 if !unsafe { (*cur).href }.is_null() {
498 allocator::xmlFree(unsafe { (*cur).href } as *mut c_void);
499 }
500 if !unsafe { (*cur).prefix }.is_null() {
501 allocator::xmlFree(unsafe { (*cur).prefix } as *mut c_void);
502 }
503
504 allocator::xmlFree(cur as *mut c_void);
505 cur = next;
506 }
507}
508
509pub unsafe fn copy_node(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
524 if node.is_null() {
525 return ptr::null_mut();
526 }
527
528 let n = unsafe { &*node };
529
530 let new_node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
531 if new_node.is_null() {
532 return ptr::null_mut();
533 }
534
535 unsafe {
536 (*new_node).type_ = n.type_;
537 (*new_node).name = dup_xml_str(n.name);
538 (*new_node).line = n.line;
539 (*new_node).extra = n.extra;
540 (*new_node).psvi = n.psvi;
541 (*new_node)._private = n._private;
542
543 (*new_node).ns = n.ns;
545
546 if !n.nsDef.is_null() {
548 (*new_node).nsDef = copy_ns_list(n.nsDef);
549 }
550
551 let node_type = n.type_;
553 if (node_type == XML_TEXT_NODE as c_int
554 || node_type == XML_CDATA_SECTION_NODE as c_int
555 || node_type == XML_COMMENT_NODE as c_int
556 || node_type == XML_PI_NODE as c_int)
557 && !n.content.is_null()
558 {
559 (*new_node).content = dup_xml_str(n.content);
560 }
561
562 if !n.properties.is_null() {
564 (*new_node).properties = copy_prop_list(n.properties);
565 let mut prop = (*new_node).properties;
567 while !prop.is_null() {
568 (*prop).parent = new_node;
569 if !(*prop).children.is_null() {
570 propagate_doc((*prop).children, (*new_node).doc);
571 }
572 prop = (*prop).next;
573 }
574 }
575
576 if recursive != 0 && !n.children.is_null() {
578 (*new_node).children = copy_node_list(n.children, recursive);
579 if !(*new_node).children.is_null() {
580 (*(*new_node).children).parent = new_node;
581 (*(*new_node).children).doc = (*new_node).doc;
582 propagate_doc((*new_node).children, (*new_node).doc);
583 }
584 }
585 }
586
587 new_node
588}
589
590unsafe fn copy_node_list(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
594 if node.is_null() {
595 return ptr::null_mut();
596 }
597
598 let n = unsafe { &*node };
599 let new_node = copy_node(node, recursive);
600 if new_node.is_null() {
601 return ptr::null_mut();
602 }
603
604 let mut prev = new_node;
605 let mut cur = n.next;
606
607 while !cur.is_null() {
608 let new_cur = copy_node(cur, recursive);
609 if new_cur.is_null() {
610 break;
611 }
612 unsafe {
613 (*prev).next = new_cur;
614 (*new_cur).prev = prev;
615 }
616 prev = new_cur;
617 cur = unsafe { (*cur).next };
618 }
619
620 new_node
621}
622
623unsafe fn copy_ns_list(ns: *const _xmlNs) -> *mut _xmlNs {
625 if ns.is_null() {
626 return ptr::null_mut();
627 }
628
629 let n = unsafe { &*ns };
630 let new_ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
631 if new_ns.is_null() {
632 return ptr::null_mut();
633 }
634
635 unsafe {
636 (*new_ns).type_ = n.type_;
637 (*new_ns).href = dup_xml_str(n.href);
638 (*new_ns).prefix = dup_xml_str(n.prefix);
639 (*new_ns)._private = n._private;
640 }
641
642 let mut prev = new_ns;
643 let mut cur = n.next;
644
645 while !cur.is_null() {
646 let c = unsafe { &*cur };
647 let new_cur = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
648 if new_cur.is_null() {
649 break;
650 }
651 unsafe {
652 (*new_cur).type_ = c.type_;
653 (*new_cur).href = dup_xml_str(c.href);
654 (*new_cur).prefix = dup_xml_str(c.prefix);
655 (*new_cur)._private = c._private;
656 (*prev).next = new_cur;
657 }
658 prev = new_cur;
659 cur = c.next;
660 }
661
662 new_ns
663}
664
665unsafe fn copy_prop_list(prop: *const _xmlAttr) -> *mut _xmlAttr {
667 if prop.is_null() {
668 return ptr::null_mut();
669 }
670
671 let p = unsafe { &*prop };
672 let new_prop = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
673 if new_prop.is_null() {
674 return ptr::null_mut();
675 }
676
677 unsafe {
678 (*new_prop).type_ = p.type_;
679 (*new_prop).name = dup_xml_str(p.name);
680 (*new_prop).ns = p.ns;
681 (*new_prop).atype = p.atype;
682
683 if !p.children.is_null() {
685 (*new_prop).children = copy_node_list(p.children, 1);
686 if !(*new_prop).children.is_null() {
687 (*(*new_prop).children).parent = new_prop as *mut _xmlNode;
688 }
689 }
690 }
691
692 let mut prev = new_prop;
693 let mut cur = p.next;
694
695 while !cur.is_null() {
696 let c = unsafe { &*cur };
697 let new_cur = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
698 if new_cur.is_null() {
699 break;
700 }
701 unsafe {
702 (*new_cur).type_ = c.type_;
703 (*new_cur).name = dup_xml_str(c.name);
704 (*new_cur).ns = c.ns;
705 (*new_cur).atype = c.atype;
706
707 if !c.children.is_null() {
708 (*new_cur).children = copy_node_list(c.children, 1);
709 if !(*new_cur).children.is_null() {
710 (*(*new_cur).children).parent = new_cur as *mut _xmlNode;
711 }
712 }
713
714 (*prev).next = new_cur;
715 }
716 prev = new_cur;
717 cur = c.next;
718 }
719
720 new_prop
721}
722
723unsafe fn propagate_doc(node: *mut _xmlNode, doc: *mut _xmlDoc) {
725 let mut cur = node;
726 while !cur.is_null() {
727 unsafe {
728 (*cur).doc = doc;
729
730 let mut prop = (*cur).properties;
732 while !prop.is_null() {
733 (*prop).doc = doc;
734 if !(*prop).children.is_null() {
735 propagate_doc((*prop).children, doc);
736 }
737 prop = (*prop).next;
738 }
739
740 if !(*cur).children.is_null() {
742 propagate_doc((*cur).children, doc);
743 }
744 }
745 cur = unsafe { (*cur).next };
746 }
747}
748
749pub unsafe fn unlink_node(node: *mut _xmlNode) {
765 if node.is_null() {
766 return;
767 }
768
769 let n = unsafe { &mut *node };
770
771 let prev = n.prev;
773 let next = n.next;
774
775 if !prev.is_null() {
776 unsafe { (*prev).next = next };
777 }
778 if !next.is_null() {
779 unsafe { (*next).prev = prev };
780 }
781
782 let parent = n.parent;
784 if !parent.is_null() {
785 if unsafe { (*parent).children } == node {
786 unsafe { (*parent).children = next };
787 }
788 if unsafe { (*parent).last } == node {
789 unsafe { (*parent).last = prev };
790 }
791 }
792
793 let doc = n.doc;
795 if !doc.is_null() && !parent.is_null() {
796 }
798 if !doc.is_null() && parent.is_null() {
799 if unsafe { (*doc).children } == node {
801 unsafe { (*doc).children = next };
802 }
803 if unsafe { (*doc).last } == node {
804 unsafe { (*doc).last = prev };
805 }
806 }
807
808 n.parent = ptr::null_mut();
810 n.prev = ptr::null_mut();
811 n.next = ptr::null_mut();
812}
813
814pub unsafe fn add_child(parent: *mut _xmlNode, cur: *mut _xmlNode) -> *mut _xmlNode {
830 if parent.is_null() || cur.is_null() {
831 return ptr::null_mut();
832 }
833
834 let p = unsafe { &mut *parent };
835 let c = unsafe { &mut *cur };
836
837 if !c.parent.is_null() || !c.prev.is_null() || !c.next.is_null() {
839 unlink_node(cur);
840 }
841
842 c.parent = parent;
844
845 if p.children.is_null() {
846 p.children = cur;
848 p.last = cur;
849 c.prev = ptr::null_mut();
850 c.next = ptr::null_mut();
851 } else {
852 c.prev = p.last;
854 c.next = ptr::null_mut();
855 if !p.last.is_null() {
856 unsafe { (*p.last).next = cur };
857 }
858 p.last = cur;
859 }
860
861 let doc = if !p.doc.is_null() {
863 p.doc
864 } else {
865 ptr::null_mut()
866 };
867 if !doc.is_null() && c.doc != doc {
868 propagate_doc(cur, doc);
869 }
870
871 cur
872}
873
874pub unsafe fn add_sibling(cur: *mut _xmlNode, elem: *mut _xmlNode) -> *mut _xmlNode {
890 if cur.is_null() || elem.is_null() {
891 return ptr::null_mut();
892 }
893
894 let c = unsafe { &mut *cur };
895
896 let e = unsafe { &mut *elem };
898 if !e.parent.is_null() || !e.prev.is_null() || !e.next.is_null() {
899 unlink_node(elem);
900 }
901
902 e.parent = c.parent;
904
905 e.prev = cur;
907 e.next = c.next;
908
909 if !c.next.is_null() {
910 unsafe { (*c.next).prev = elem };
911 }
912 c.next = elem;
913
914 let parent = c.parent;
916 if !parent.is_null() && unsafe { (*parent).last } == cur {
917 unsafe { (*parent).last = elem };
918 }
919
920 if !c.doc.is_null() && e.doc != c.doc {
922 propagate_doc(elem, c.doc);
923 }
924
925 elem
926}
927
928pub unsafe fn new_child(
943 parent: *mut _xmlNode,
944 ns: *mut _xmlNs,
945 name: *const xmlChar,
946) -> *mut _xmlNode {
947 let node = new_node(ns, name);
948 if node.is_null() {
949 return ptr::null_mut();
950 }
951
952 if !parent.is_null() {
953 add_child(parent, node);
954 }
955
956 node
957}
958
959pub unsafe fn new_text(content: *const xmlChar) -> *mut _xmlNode {
978 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
979 if node.is_null() {
980 return ptr::null_mut();
981 }
982
983 unsafe {
984 (*node).type_ = XML_TEXT_NODE as c_int;
985 (*node).name = dup_xml_str(b"text\0" as *const u8 as *const xmlChar);
986 (*node).content = if content.is_null() {
987 let empty = allocator::xmlMalloc(1) as *mut xmlChar;
988 if !empty.is_null() {
989 *empty = 0;
990 }
991 empty
992 } else {
993 dup_xml_str(content)
994 };
995 (*node).line = 0;
996 }
997
998 node
999}
1000
1001pub unsafe fn new_comment(content: *const xmlChar) -> *mut _xmlNode {
1015 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1016 if node.is_null() {
1017 return ptr::null_mut();
1018 }
1019
1020 unsafe {
1021 (*node).type_ = XML_COMMENT_NODE as c_int;
1022 (*node).name = dup_xml_str(b"comment\0" as *const u8 as *const xmlChar);
1023 (*node).content = dup_xml_str(content);
1024 (*node).line = 0;
1025 }
1026
1027 node
1028}
1029
1030pub unsafe fn new_pi(name: *const xmlChar, content: *const xmlChar) -> *mut _xmlNode {
1045 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1046 if node.is_null() {
1047 return ptr::null_mut();
1048 }
1049
1050 unsafe {
1051 (*node).type_ = XML_PI_NODE as c_int;
1052 (*node).name = dup_xml_str(name);
1053 (*node).content = dup_xml_str(content);
1054 (*node).line = 0;
1055 }
1056
1057 node
1058}
1059
1060pub unsafe fn new_cdata_block(
1076 doc: *mut _xmlDoc,
1077 content: *const xmlChar,
1078 len: c_int,
1079) -> *mut _xmlNode {
1080 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1081 if node.is_null() {
1082 return ptr::null_mut();
1083 }
1084
1085 unsafe {
1086 (*node).type_ = XML_CDATA_SECTION_NODE as c_int;
1087 (*node).name = dup_xml_str(b"cdata\0" as *const u8 as *const xmlChar);
1088 (*node).doc = doc;
1089
1090 if !content.is_null() && len > 0 {
1091 (*node).content = allocator::xmlMalloc((len + 1) as usize) as *mut xmlChar;
1092 if !(*node).content.is_null() {
1093 ptr::copy_nonoverlapping(content, (*node).content, len as usize);
1094 *((*node).content.add(len as usize)) = 0;
1095 }
1096 } else {
1097 let empty = allocator::xmlMalloc(1) as *mut xmlChar;
1098 if !empty.is_null() {
1099 *empty = 0;
1100 }
1101 (*node).content = empty;
1102 }
1103
1104 (*node).line = 0;
1105 }
1106
1107 node
1108}
1109
1110pub unsafe fn new_ns(
1134 node: *mut _xmlNode,
1135 href: *const xmlChar,
1136 prefix: *const xmlChar,
1137) -> *mut _xmlNs {
1138 let ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
1139 if ns.is_null() {
1140 return ptr::null_mut();
1141 }
1142
1143 unsafe {
1144 (*ns).type_ = XML_LOCAL_NAMESPACE as c_int;
1145 (*ns).href = dup_xml_str(href);
1146 (*ns).prefix = dup_xml_str(prefix);
1147 (*ns).context = node as *mut _xmlDoc;
1148
1149 if !node.is_null() {
1151 let n = &mut *node;
1152 if n.nsDef.is_null() {
1153 n.nsDef = ns;
1154 } else {
1155 let mut last = n.nsDef;
1157 while !(*last).next.is_null() {
1158 last = (*last).next;
1159 }
1160 (*last).next = ns;
1161 }
1162 }
1163 }
1164
1165 ns
1166}
1167
1168pub unsafe fn set_ns(node: *mut _xmlNode, ns: *mut _xmlNs) {
1181 if node.is_null() {
1182 return;
1183 }
1184 unsafe {
1185 (*node).ns = ns;
1186 }
1187}
1188
1189pub unsafe fn get_ns_list(doc: *mut _xmlDoc, node: *mut _xmlNode) -> *mut *mut _xmlNs {
1205 if node.is_null() {
1209 return ptr::null_mut();
1210 }
1211
1212 let mut ns_ptrs: Vec<*mut _xmlNs> = Vec::new();
1214 let mut cur = node;
1215
1216 while !cur.is_null() {
1217 let n = unsafe { &*cur };
1218 let mut ns_def = n.nsDef;
1219 while !ns_def.is_null() {
1220 let ns = unsafe { &*ns_def };
1222 let mut found = false;
1223 for &existing in &ns_ptrs {
1224 if existing == ns_def {
1225 found = true;
1226 break;
1227 }
1228 let e = unsafe { &*existing };
1229 if !ns.href.is_null() && !e.href.is_null() {
1230 let href_match =
1231 unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, e.href) != 0 };
1232 if href_match {
1233 if ns.prefix.is_null() && e.prefix.is_null() {
1234 found = true;
1235 break;
1236 }
1237 if !ns.prefix.is_null() && !e.prefix.is_null() {
1238 let prefix_match = unsafe {
1239 crate::abi::exports_xml2::xmlStrEqual(ns.prefix, e.prefix) != 0
1240 };
1241 if prefix_match {
1242 found = true;
1243 break;
1244 }
1245 }
1246 }
1247 }
1248 }
1249 if !found {
1250 ns_ptrs.push(ns_def);
1251 }
1252 ns_def = unsafe { (*ns_def).next };
1253 }
1254 cur = n.parent;
1255 }
1256
1257 if ns_ptrs.is_empty() {
1258 return ptr::null_mut();
1259 }
1260
1261 let arr =
1263 allocator::xmlMalloc((ns_ptrs.len() + 1) * size_of::<*mut _xmlNs>()) as *mut *mut _xmlNs;
1264 if arr.is_null() {
1265 return ptr::null_mut();
1266 }
1267
1268 for (i, ns) in ns_ptrs.iter().enumerate() {
1269 unsafe { *arr.add(i) = *ns };
1270 }
1271 unsafe { *arr.add(ns_ptrs.len()) = ptr::null_mut() };
1272
1273 arr
1274}
1275
1276pub unsafe fn search_ns(
1293 doc: *mut _xmlDoc,
1294 node: *mut _xmlNode,
1295 name_space: *const xmlChar,
1296) -> *mut _xmlNs {
1297 if node.is_null() {
1298 return ptr::null_mut();
1299 }
1300
1301 let mut cur = node;
1302 while !cur.is_null() {
1303 let n = unsafe { &*cur };
1304 let mut ns_def = n.nsDef;
1305 while !ns_def.is_null() {
1306 let ns = unsafe { &*ns_def };
1307 let match_prefix = if name_space.is_null() {
1308 ns.prefix.is_null()
1310 } else {
1311 !ns.prefix.is_null()
1312 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.prefix, name_space) != 0 }
1313 };
1314 if match_prefix {
1315 return ns_def;
1316 }
1317 ns_def = unsafe { (*ns_def).next };
1318 }
1319 cur = n.parent;
1320 }
1321
1322 ptr::null_mut()
1323}
1324
1325pub unsafe fn search_ns_by_href(
1341 doc: *mut _xmlDoc,
1342 node: *mut _xmlNode,
1343 href: *const xmlChar,
1344) -> *mut _xmlNs {
1345 if node.is_null() || href.is_null() {
1346 return ptr::null_mut();
1347 }
1348
1349 let mut cur = node;
1350 while !cur.is_null() {
1351 let n = unsafe { &*cur };
1352 let mut ns_def = n.nsDef;
1353 while !ns_def.is_null() {
1354 let ns = unsafe { &*ns_def };
1355 if !ns.href.is_null()
1356 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, href) != 0 }
1357 {
1358 return ns_def;
1359 }
1360 ns_def = unsafe { (*ns_def).next };
1361 }
1362 cur = n.parent;
1363 }
1364
1365 ptr::null_mut()
1366}
1367
1368pub unsafe fn set_prop(
1392 node: *mut _xmlNode,
1393 name: *const xmlChar,
1394 value: *const xmlChar,
1395) -> *mut _xmlAttr {
1396 if node.is_null() || name.is_null() {
1397 return ptr::null_mut();
1398 }
1399
1400 let n = unsafe { &mut *node };
1401
1402 let mut existing = n.properties;
1404 while !existing.is_null() {
1405 let attr = unsafe { &*existing };
1406 if !attr.name.is_null()
1407 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1408 {
1409 if !attr.children.is_null() {
1412 free_node_list(attr.children);
1413 let attr_mut = existing as *mut _xmlAttr;
1415 unsafe { (*attr_mut).children = ptr::null_mut() };
1416 unsafe { (*attr_mut).last = ptr::null_mut() };
1417 }
1418 if !value.is_null() {
1420 let text = new_text(value);
1421 if !text.is_null() {
1422 let attr_mut = existing as *mut _xmlAttr;
1423 unsafe {
1424 (*attr_mut).children = text;
1425 (*attr_mut).last = text;
1426 (*text).parent = existing as *mut _xmlNode;
1427 (*text).doc = n.doc;
1428 }
1429 }
1430 }
1431 return existing;
1432 }
1433 existing = unsafe { (*existing).next };
1434 }
1435
1436 let attr = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
1438 if attr.is_null() {
1439 return ptr::null_mut();
1440 }
1441
1442 unsafe {
1443 (*attr).type_ = XML_ATTRIBUTE_NODE as c_int;
1444 (*attr).name = dup_xml_str(name);
1445 (*attr).parent = node;
1446 (*attr).doc = n.doc;
1447 (*attr).atype = XML_ATTRIBUTE_CDATA as c_int;
1448
1449 if !value.is_null() {
1451 let text = new_text(value);
1452 if !text.is_null() {
1453 (*attr).children = text;
1454 (*attr).last = text;
1455 (*text).parent = attr as *mut _xmlNode;
1456 (*text).doc = n.doc;
1457 }
1458 }
1459
1460 if n.properties.is_null() {
1462 n.properties = attr;
1463 } else {
1464 let mut last = n.properties;
1465 while !(*last).next.is_null() {
1466 last = (*last).next;
1467 }
1468 (*last).next = attr;
1469 (*attr).prev = last;
1470 }
1471 }
1472
1473 attr
1474}
1475
1476pub unsafe fn get_prop(node: *mut _xmlNode, name: *const xmlChar) -> *mut xmlChar {
1492 if node.is_null() || name.is_null() {
1493 return ptr::null_mut();
1494 }
1495
1496 let n = unsafe { &*node };
1497 let mut cur = n.properties;
1498
1499 while !cur.is_null() {
1500 let attr = unsafe { &*cur };
1501 if !attr.name.is_null()
1502 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1503 {
1504 if !attr.children.is_null() {
1506 let text = unsafe { &*attr.children };
1507 if text.type_ == XML_TEXT_NODE as c_int && !text.content.is_null() {
1508 return dup_xml_str(text.content);
1509 }
1510 }
1511 return dup_xml_str(b"\0" as *const u8 as *const xmlChar);
1512 }
1513 cur = unsafe { (*cur).next };
1514 }
1515
1516 ptr::null_mut()
1517}
1518
1519pub unsafe fn get_ns_prop(
1535 node: *mut _xmlNode,
1536 name: *const xmlChar,
1537 _name_space: *const xmlChar,
1538) -> *mut xmlChar {
1539 get_prop(node, name)
1542}
1543
1544pub unsafe fn set_ns_prop(
1559 node: *mut _xmlNode,
1560 _ns: *mut _xmlNs,
1561 name: *const xmlChar,
1562 value: *const xmlChar,
1563) -> *mut _xmlAttr {
1564 set_prop(node, name, value)
1566}
1567
1568pub unsafe fn remove_prop(attr: *mut _xmlAttr) -> c_int {
1583 if attr.is_null() {
1584 return -1;
1585 }
1586
1587 let a = unsafe { &mut *attr };
1588
1589 let parent = a.parent;
1591 if !parent.is_null() {
1592 let p = unsafe { &mut *parent };
1593 if p.properties == attr {
1594 p.properties = a.next;
1595 }
1596 }
1597
1598 if !a.prev.is_null() {
1600 unsafe { (*a.prev).next = a.next };
1601 }
1602 if !a.next.is_null() {
1603 unsafe { (*a.next).prev = a.prev };
1604 }
1605
1606 if !a.children.is_null() {
1608 free_node_list(a.children);
1609 }
1610
1611 if !a.name.is_null() {
1613 allocator::xmlFree(a.name as *mut c_void);
1614 }
1615
1616 allocator::xmlFree(attr as *mut c_void);
1617 0
1618}
1619
1620pub fn get_int_subset(doc: *const _xmlDoc) -> *mut _xmlDtd {
1632 if doc.is_null() {
1633 return ptr::null_mut();
1634 }
1635 let d = unsafe { &*doc };
1636 d.intSubset
1637}
1638
1639pub unsafe fn new_dtd(
1656 doc: *mut _xmlDoc,
1657 name: *const xmlChar,
1658 ExternalID: *const xmlChar,
1659 SystemID: *const xmlChar,
1660) -> *mut _xmlDtd {
1661 let dtd = allocator::xmlMallocZero(size_of::<_xmlDtd>() as usize) as *mut _xmlDtd;
1662 if dtd.is_null() {
1663 return ptr::null_mut();
1664 }
1665
1666 unsafe {
1667 (*dtd).type_ = XML_DTD_NODE as c_int;
1668 (*dtd).name = dup_xml_str(name);
1669 (*dtd).ExternalID = dup_xml_str(ExternalID);
1670 (*dtd).SystemID = dup_xml_str(SystemID);
1671 (*dtd).parent = doc;
1672 (*dtd).doc = doc;
1673
1674 if !doc.is_null() {
1676 if (*doc).intSubset.is_null() {
1677 (*doc).intSubset = dtd;
1678 }
1679 }
1680 }
1681
1682 dtd
1683}
1684
1685unsafe fn free_dtd(dtd: *mut _xmlDtd) {
1691 if dtd.is_null() {
1692 return;
1693 }
1694
1695 let d = unsafe { &mut *dtd };
1696
1697 if !d.name.is_null() {
1699 allocator::xmlFree(d.name as *mut c_void);
1700 }
1701 if !d.ExternalID.is_null() {
1702 allocator::xmlFree(d.ExternalID as *mut c_void);
1703 }
1704 if !d.SystemID.is_null() {
1705 allocator::xmlFree(d.SystemID as *mut c_void);
1706 }
1707
1708 if !d.children.is_null() {
1710 free_node_list(d.children);
1711 }
1712
1713 allocator::xmlFree(dtd as *mut c_void);
1714}
1715
1716pub unsafe fn new_entity(
1736 _doc: *mut _xmlDoc,
1737 name: *const xmlChar,
1738 etype: c_int,
1739 ExternalID: *const xmlChar,
1740 SystemID: *const xmlChar,
1741 content: *const xmlChar,
1742) -> *mut _xmlEntity {
1743 let entity = allocator::xmlMallocZero(size_of::<_xmlEntity>() as usize) as *mut _xmlEntity;
1744 if entity.is_null() {
1745 return ptr::null_mut();
1746 }
1747
1748 unsafe {
1749 (*entity).type_ = XML_ENTITY_DECL as c_int;
1750 (*entity).name = dup_xml_str(name);
1751 (*entity).etype = etype;
1752 (*entity).ExternalID = dup_xml_str(ExternalID);
1753 (*entity).SystemID = dup_xml_str(SystemID);
1754 (*entity).content = dup_xml_str(content);
1755 (*entity).length = if content.is_null() {
1756 0
1757 } else {
1758 crate::abi::exports_xml2::xmlStrlen(content)
1759 };
1760 (*entity).flags = 0;
1761 (*entity).expandedSize = 0;
1762 }
1763
1764 entity
1765}
1766
1767pub unsafe fn get_doc_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
1782 let _ = doc;
1785 let _ = name;
1786 ptr::null_mut()
1787}
1788
1789pub unsafe fn get_parameter_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
1802 let _ = doc;
1804 let _ = name;
1805 ptr::null_mut()
1806}
1807
1808#[cfg(test)]
1813mod tests {
1814 use super::*;
1815 use core::ffi::c_void;
1816
1817 fn c_str(s: &str) -> *const xmlChar {
1818 let bytes = s.as_bytes();
1819 let buf = unsafe { allocator::xmlMalloc(bytes.len() + 1) as *mut u8 };
1820 if !buf.is_null() {
1821 unsafe {
1822 ptr::copy_nonoverlapping(bytes.as_ptr(), buf, bytes.len());
1823 *buf.add(bytes.len()) = 0;
1824 }
1825 }
1826 buf as *const xmlChar
1827 }
1828
1829 #[test]
1830 fn test_new_free_doc() {
1831 unsafe {
1832 let doc = new_doc(ptr::null());
1833 assert!(!doc.is_null());
1834 assert_eq!((*doc).type_, XML_DOCUMENT_NODE as c_int);
1835 assert_eq!((*doc).standalone, -1);
1836 assert_eq!((*doc).doc, doc);
1837 assert!(!(*doc).version.is_null());
1838 free_doc(doc);
1839 }
1840 }
1841
1842 #[test]
1843 fn test_new_doc_with_version() {
1844 unsafe {
1845 let ver = c_str("2.0");
1846 let doc = new_doc(ver);
1847 assert!(!doc.is_null());
1848 let doc_ver = (*doc).version;
1849 assert!(!doc_ver.is_null());
1850 assert!(crate::abi::exports_xml2::xmlStrEqual(doc_ver, ver,) != 0);
1851 allocator::xmlFree(ver as *mut c_void);
1852 free_doc(doc);
1853 }
1854 }
1855
1856 #[test]
1857 fn test_new_node() {
1858 unsafe {
1859 let doc = new_doc(ptr::null());
1860 let node = new_node(ptr::null_mut(), c_str("root"));
1861 assert!(!node.is_null());
1862 assert_eq!((*node).type_, XML_ELEMENT_NODE as c_int);
1863 assert!(!(*node).name.is_null());
1864 free_node(node);
1865 free_doc(doc);
1866 }
1867 }
1868
1869 #[test]
1870 fn test_doc_set_root_element() {
1871 unsafe {
1872 let doc = new_doc(ptr::null());
1873 let root = new_node(ptr::null_mut(), c_str("root"));
1874 let old = doc_set_root_element(doc, root);
1875 assert!(old.is_null());
1876 assert_eq!(doc_get_root_element(doc), root);
1877 assert_eq!((*doc).children, root as *mut _xmlNode);
1878 free_doc(doc);
1879 }
1880 }
1881
1882 #[test]
1883 fn test_add_child_and_sibling() {
1884 unsafe {
1885 let doc = new_doc(ptr::null());
1886 let root = new_node(ptr::null_mut(), c_str("root"));
1887 doc_set_root_element(doc, root);
1888
1889 let child1 = new_child(root, ptr::null_mut(), c_str("child1"));
1890 assert!(!child1.is_null());
1891 assert_eq!((*child1).parent, root);
1892 assert_eq!((*root).children, child1);
1893 assert_eq!((*root).last, child1);
1894
1895 let child2 = new_child(root, ptr::null_mut(), c_str("child2"));
1896 assert!(!child2.is_null());
1897 assert_eq!((*child2).parent, root);
1898 assert_eq!((*child1).next, child2);
1899 assert_eq!((*child2).prev, child1);
1900 assert_eq!((*root).last, child2);
1901
1902 let sibling = new_node(ptr::null_mut(), c_str("sibling"));
1904 add_sibling(child2, sibling);
1905 assert_eq!((*child2).next, sibling);
1906 assert_eq!((*sibling).prev, child2);
1907 assert_eq!((*root).last, sibling);
1908
1909 free_doc(doc);
1910 }
1911 }
1912
1913 #[test]
1914 fn test_unlink_node() {
1915 unsafe {
1916 let doc = new_doc(ptr::null());
1917 let root = new_node(ptr::null_mut(), c_str("root"));
1918 doc_set_root_element(doc, root);
1919
1920 let child1 = new_child(root, ptr::null_mut(), c_str("c1"));
1921 let child2 = new_child(root, ptr::null_mut(), c_str("c2"));
1922
1923 unlink_node(child1);
1924 assert!((*child1).parent.is_null());
1925 assert!((*child1).prev.is_null());
1926 assert!((*child1).next.is_null());
1927 assert_eq!((*root).children, child2);
1928 assert_eq!((*root).last, child2);
1929
1930 free_node(child1);
1931 free_doc(doc);
1932 }
1933 }
1934
1935 #[test]
1936 fn test_text_and_comment_nodes() {
1937 unsafe {
1938 let text = new_text(c_str("hello world"));
1939 assert!(!text.is_null());
1940 assert_eq!((*text).type_, XML_TEXT_NODE as c_int);
1941 assert!(!(*text).content.is_null());
1942 free_node(text);
1943
1944 let comment = new_comment(c_str("my comment"));
1945 assert!(!comment.is_null());
1946 assert_eq!((*comment).type_, XML_COMMENT_NODE as c_int);
1947 free_node(comment);
1948
1949 let pi = new_pi(c_str("xml"), c_str("version='1.0'"));
1950 assert!(!pi.is_null());
1951 assert_eq!((*pi).type_, XML_PI_NODE as c_int);
1952 free_node(pi);
1953 }
1954 }
1955
1956 #[test]
1957 fn test_set_and_get_prop() {
1958 unsafe {
1959 let doc = new_doc(ptr::null());
1960 let root = new_node(ptr::null_mut(), c_str("root"));
1961 doc_set_root_element(doc, root);
1962
1963 let attr = set_prop(root, c_str("id"), c_str("42"));
1964 assert!(!attr.is_null());
1965 assert_eq!((*attr).type_, XML_ATTRIBUTE_NODE as c_int);
1966
1967 let value = get_prop(root, c_str("id"));
1968 assert!(!value.is_null());
1969 assert!(crate::abi::exports_xml2::xmlStrEqual(value, c_str("42")) != 0);
1970 allocator::xmlFree(value as *mut c_void);
1971
1972 free_doc(doc);
1973 }
1974 }
1975
1976 #[test]
1977 fn test_remove_prop() {
1978 unsafe {
1979 let doc = new_doc(ptr::null());
1980 let root = new_node(ptr::null_mut(), c_str("root"));
1981 doc_set_root_element(doc, root);
1982
1983 set_prop(root, c_str("a"), c_str("1"));
1984 set_prop(root, c_str("b"), c_str("2"));
1985
1986 let value = get_prop(root, c_str("a"));
1987 assert!(!value.is_null());
1988 allocator::xmlFree(value as *mut c_void);
1989
1990 let attr = (*root).properties;
1992 assert!(!attr.is_null());
1993 let result = remove_prop(attr);
1994 assert_eq!(result, 0);
1995
1996 let value2 = get_prop(root, c_str("a"));
1998 assert!(value2.is_null());
1999
2000 free_doc(doc);
2001 }
2002 }
2003
2004 #[test]
2005 fn test_namespace_operations() {
2006 unsafe {
2007 let doc = new_doc(ptr::null());
2008 let root = new_node(ptr::null_mut(), c_str("root"));
2009 doc_set_root_element(doc, root);
2010
2011 let ns = new_ns(root, c_str("http://example.com"), c_str("ex"));
2012 assert!(!ns.is_null());
2013 assert!(!(*root).nsDef.is_null());
2014
2015 set_ns(root, ns);
2016 assert_eq!((*root).ns, ns);
2017
2018 let found = search_ns(doc, root, c_str("ex"));
2019 assert_eq!(found, ns);
2020
2021 let found_href = search_ns_by_href(doc, root, c_str("http://example.com"));
2022 assert_eq!(found_href, ns);
2023
2024 free_doc(doc);
2025 }
2026 }
2027
2028 #[test]
2029 fn test_new_dtd() {
2030 unsafe {
2031 let doc = new_doc(ptr::null());
2032 let dtd = new_dtd(doc, c_str("root"), c_str("-//TEST//DTD"), c_str("test.dtd"));
2033 assert!(!dtd.is_null());
2034 assert_eq!((*dtd).type_, XML_DTD_NODE as c_int);
2035 assert_eq!(get_int_subset(doc), dtd);
2036 free_doc(doc);
2037 }
2038 }
2039
2040 #[test]
2041 fn test_copy_node_deep() {
2042 unsafe {
2043 let doc = new_doc(ptr::null());
2044 let root = new_node(ptr::null_mut(), c_str("root"));
2045 doc_set_root_element(doc, root);
2046 let child = new_child(root, ptr::null_mut(), c_str("child"));
2047
2048 let copy = copy_node(root, 1);
2049 assert!(!copy.is_null());
2050 assert_eq!((*copy).type_, XML_ELEMENT_NODE as c_int);
2051 assert!(!(*copy).children.is_null());
2053 assert_eq!((*(*copy).children).type_, XML_ELEMENT_NODE as c_int);
2054
2055 free_node(copy);
2056 free_doc(doc);
2057 }
2058 }
2059
2060 #[test]
2061 fn test_new_cdata_block() {
2062 unsafe {
2063 let doc = new_doc(ptr::null());
2064 let content = c_str("some <cdata> content");
2065 let cdata = new_cdata_block(doc, content, 20);
2066 assert!(!cdata.is_null());
2067 assert_eq!((*cdata).type_, XML_CDATA_SECTION_NODE as c_int);
2068 free_node(cdata);
2069 free_doc(doc);
2070 }
2071 }
2072
2073 #[test]
2074 fn test_null_handling() {
2075 unsafe {
2076 assert!(new_doc(ptr::null()).is_null() == false); let doc = new_doc(ptr::null());
2078 assert!(new_node(ptr::null_mut(), ptr::null()).is_null() == false); free_node(ptr::null_mut()); free_doc(ptr::null_mut()); assert!(unlink_node(ptr::null_mut()) == ()); assert!(add_child(ptr::null_mut(), ptr::null_mut()).is_null());
2083 assert!(add_sibling(ptr::null_mut(), ptr::null_mut()).is_null());
2084 free_doc(doc);
2085 }
2086 }
2087}