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;
49use crate::xml::io;
50
51unsafe fn dup_xml_str(str: *const xmlChar) -> *mut xmlChar {
61 if str.is_null() {
62 return ptr::null_mut();
63 }
64 let len = unsafe { crate::abi::exports_xml2::xmlStrlen(str) as usize };
65 if len == 0 {
66 let buf = unsafe { allocator::xmlMalloc(1) as *mut xmlChar };
68 if !buf.is_null() {
69 unsafe { *buf = 0 };
70 }
71 return buf;
72 }
73 let buf = unsafe { allocator::xmlMalloc(len + 1) as *mut xmlChar };
74 if !buf.is_null() {
75 unsafe {
76 ptr::copy_nonoverlapping(str, buf, len + 1);
77 }
78 }
79 buf
80}
81
82unsafe fn copy_xml_str_content(dest: *mut xmlChar, src: *const xmlChar, max_len: usize) -> bool {
84 if src.is_null() || dest.is_null() || max_len == 0 {
85 return false;
86 }
87 let len = unsafe { crate::abi::exports_xml2::xmlStrlen(src) as usize };
88 if len >= max_len {
89 return false;
90 }
91 unsafe {
92 ptr::copy_nonoverlapping(src, dest, len);
93 *dest.add(len) = 0;
94 }
95 true
96}
97
98pub unsafe fn xml_strlen(str: *const xmlChar) -> c_int {
100 if str.is_null() {
101 return 0;
102 }
103 let mut len: c_int = 0;
104 while unsafe { *str.add(len as usize) != 0 } {
105 len += 1;
106 }
107 len
108}
109
110pub unsafe fn new_doc(version: *const xmlChar) -> *mut _xmlDoc {
133 let doc = allocator::xmlMallocZero(size_of::<_xmlDoc>() as usize) as *mut _xmlDoc;
135 if doc.is_null() {
136 return ptr::null_mut();
137 }
138
139 unsafe {
140 (*doc).type_ = XML_DOCUMENT_NODE as c_int;
141 (*doc).standalone = -1; (*doc).doc = doc; (*doc).properties = XML_DOC_WELLFORMED as c_int;
144 (*doc).charset = XML_CHAR_ENCODING_UTF8 as c_int;
145
146 let ver = if version.is_null() {
148 XML_DEFAULT_VERSION.as_ptr() as *const xmlChar
149 } else {
150 version
151 };
152 (*doc).version = dup_xml_str(ver);
153 }
154
155 doc
156}
157
158pub unsafe fn free_doc(doc: *mut _xmlDoc) {
172 if doc.is_null() {
173 return;
174 }
175
176 let d = unsafe { &mut *doc };
177
178 if !d.intSubset.is_null() {
180 free_dtd(d.intSubset);
181 }
182
183 if !d.extSubset.is_null() {
185 free_dtd(d.extSubset);
186 }
187
188 if !d.children.is_null() {
190 free_node_list(d.children);
191 }
192
193 if !d.oldNs.is_null() {
195 free_ns_list(d.oldNs);
196 }
197
198 if !d.version.is_null() {
200 allocator::xmlFree(d.version as *mut c_void);
201 }
202 if !d.encoding.is_null() {
203 allocator::xmlFree(d.encoding as *mut c_void);
204 }
205 if !d.URL.is_null() {
206 allocator::xmlFree(d.URL as *mut c_void);
207 }
208
209 allocator::xmlFree(doc as *mut c_void);
211}
212
213pub unsafe fn copy_doc(doc: *const _xmlDoc, recursive: c_int) -> *mut _xmlDoc {
228 if doc.is_null() {
229 return ptr::null_mut();
230 }
231
232 let d = unsafe { &*doc };
233
234 let new_doc = new_doc(d.version);
235 if new_doc.is_null() {
236 return ptr::null_mut();
237 }
238
239 unsafe {
240 (*new_doc).type_ = d.type_;
241 (*new_doc).standalone = d.standalone;
242 (*new_doc).encoding = dup_xml_str(d.encoding);
243 (*new_doc).URL = dup_xml_str(d.URL);
244 (*new_doc).charset = d.charset;
245 (*new_doc).properties = d.properties;
246
247 if !d.intSubset.is_null() {
252 let dtd_copy = crate::xml::dtd::copy_dtd(d.intSubset);
253 if !dtd_copy.is_null() {
254 (*new_doc).intSubset = dtd_copy;
255 }
256 }
257
258 if recursive != 0 && !d.children.is_null() {
259 (*new_doc).children = copy_node_list(d.children, recursive);
260 if !(*new_doc).children.is_null() {
261 (*(*new_doc).children).parent = ptr::null_mut(); (*(*new_doc).children).doc = new_doc;
263 propagate_doc((*new_doc).children, new_doc);
265 }
266 }
267 }
268
269 new_doc
270}
271
272pub unsafe fn doc_set_root_element(doc: *mut _xmlDoc, root: *mut _xmlNode) -> *mut _xmlNode {
288 if doc.is_null() {
289 return ptr::null_mut();
290 }
291
292 let d = unsafe { &mut *doc };
293
294 let old_root = doc_get_root_element(doc);
295
296 if !root.is_null() {
297 unsafe {
298 (*root).parent = ptr::null_mut();
299 (*root).doc = doc;
300 }
301 d.children = root;
302 d.last = root;
303 unsafe {
304 (*root).prev = ptr::null_mut();
305 (*root).next = ptr::null_mut();
306 }
307 } else {
308 d.children = ptr::null_mut();
309 d.last = ptr::null_mut();
310 }
311
312 old_root
313}
314
315pub fn doc_get_root_element(doc: *mut _xmlDoc) -> *mut _xmlNode {
326 if doc.is_null() {
327 return ptr::null_mut();
328 }
329
330 let d = unsafe { &*doc };
331 let mut cur = d.children;
332
333 while !cur.is_null() {
334 let node = unsafe { &*cur };
335 if node.type_ == XML_ELEMENT_NODE as c_int {
336 return cur;
337 }
338 cur = node.next;
339 }
340
341 ptr::null_mut()
342}
343
344pub fn get_line_no(node: *const _xmlNode) -> c_int {
354 if node.is_null() {
355 return 0;
356 }
357 let n = unsafe { &*node };
358 n.line as c_int
359}
360
361pub unsafe fn node_get_content(node: *mut _xmlNode) -> *mut xmlChar {
381 if node.is_null() {
382 return ptr::null_mut();
383 }
384 let typ = (*node).type_;
385 let mut result: Vec<u8> = Vec::new();
386 match typ {
387 t if t == XML_TEXT_NODE as c_int
388 || t == XML_CDATA_SECTION_NODE as c_int
389 || t == XML_COMMENT_NODE as c_int
390 || t == XML_PI_NODE as c_int =>
391 {
392 if !(*node).content.is_null() {
393 let len = crate::abi::exports_xml2::xmlStrlen((*node).content);
394 result
395 .extend_from_slice(core::slice::from_raw_parts((*node).content, len as usize));
396 } else if t == XML_TEXT_NODE as c_int && !(*node).children.is_null() {
397 let mut child = (*node).children;
400 while !child.is_null() {
401 if !(*child).content.is_null() {
402 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
403 result.extend_from_slice(core::slice::from_raw_parts(
404 (*child).content,
405 len as usize,
406 ));
407 }
408 child = (*child).next;
409 }
410 }
411 }
412 t if t == XML_ATTRIBUTE_NODE as c_int => {
413 if !(*node).children.is_null() {
415 let child = (*node).children;
416 if !(*child).content.is_null() {
417 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
418 result.extend_from_slice(core::slice::from_raw_parts(
419 (*child).content,
420 len as usize,
421 ));
422 }
423 }
424 }
425 t if t == XML_ENTITY_REF_NODE as c_int => {
426 let name = (*node).name;
428 if !name.is_null() && !(*node).doc.is_null() {
429 let ent = crate::xml::tree::get_doc_entity((*node).doc, name);
430 if !ent.is_null() && !(*ent).content.is_null() {
431 let len = crate::abi::exports_xml2::xmlStrlen((*ent).content);
432 result.extend_from_slice(core::slice::from_raw_parts(
433 (*ent).content,
434 len as usize,
435 ));
436 }
437 }
438 }
439 t if t == XML_DOCUMENT_NODE as c_int || t == XML_HTML_DOCUMENT_NODE as c_int => {
440 let root = doc_get_root_element(node as *mut _xmlDoc);
441 if !root.is_null() {
442 let sub = node_get_content(root);
443 if !sub.is_null() {
444 let len = crate::abi::exports_xml2::xmlStrlen(sub);
445 result.extend_from_slice(core::slice::from_raw_parts(sub, len as usize));
446 allocator::xmlFree(sub as *mut c_void);
447 }
448 }
449 }
450 _ => {
451 let mut child = (*node).children;
456 while !child.is_null() {
457 let ctype = (*child).type_;
458 if ctype == XML_TEXT_NODE as c_int || ctype == XML_CDATA_SECTION_NODE as c_int {
459 if !(*child).content.is_null() {
460 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
461 result.extend_from_slice(core::slice::from_raw_parts(
462 (*child).content,
463 len as usize,
464 ));
465 }
466 } else if ctype == XML_ENTITY_REF_NODE as c_int
467 || ctype == XML_ELEMENT_NODE as c_int
468 {
469 let sub = node_get_content(child);
470 if !sub.is_null() {
471 let len = crate::abi::exports_xml2::xmlStrlen(sub);
472 result.extend_from_slice(core::slice::from_raw_parts(sub, len as usize));
473 allocator::xmlFree(sub as *mut c_void);
474 }
475 }
476 child = (*child).next;
477 }
478 }
479 }
480 let buf = allocator::xmlMalloc(result.len() + 1) as *mut xmlChar;
482 if buf.is_null() {
483 return ptr::null_mut();
484 }
485 if !result.is_empty() {
486 ptr::copy_nonoverlapping(result.as_ptr(), buf, result.len());
487 }
488 *buf.add(result.len()) = 0;
489 buf
490}
491
492pub unsafe fn new_node(ns: *mut _xmlNs, name: *const xmlChar) -> *mut _xmlNode {
511 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
512 if node.is_null() {
513 return ptr::null_mut();
514 }
515
516 unsafe {
517 (*node).type_ = XML_ELEMENT_NODE as c_int;
518 (*node).name = dup_xml_str(name);
519 (*node).ns = ns;
520 (*node).line = 0;
521 (*node).extra = 0;
522
523 if !ns.is_null() {
524 (*ns).context = node as *mut _xmlDoc;
525 }
526 }
527
528 node
529}
530
531pub unsafe fn free_node(node: *mut _xmlNode) {
546 if node.is_null() {
547 return;
548 }
549
550 let n = unsafe { &mut *node };
551
552 if n.type_ == XML_DTD_NODE as c_int {
555 free_dtd(node as *mut _xmlDtd);
556 return;
557 }
558
559 let is_element = n.type_ == XML_ELEMENT_NODE as c_int;
564 if is_element && !n.properties.is_null() {
565 free_prop_list(n.properties);
566 }
567
568 if is_element && !n.nsDef.is_null() {
569 free_ns_list(n.nsDef);
570 }
571
572 if !n.name.is_null() {
574 allocator::xmlFree(n.name as *mut c_void);
575 }
576
577 if !n.content.is_null() {
581 let node_type = n.type_;
582 if node_type == XML_TEXT_NODE as c_int
583 || node_type == XML_CDATA_SECTION_NODE as c_int
584 || node_type == XML_COMMENT_NODE as c_int
585 || node_type == XML_PI_NODE as c_int
586 {
587 let inline_addr = std::ptr::addr_of_mut!((*node).properties) as *const c_void;
588 if n.content as *const c_void != inline_addr {
589 allocator::xmlFree(n.content as *mut c_void);
590 }
591 }
592 }
593
594 allocator::xmlFree(node as *mut c_void);
595}
596
597pub unsafe fn free_node_list(node: *mut _xmlNode) {
605 let mut cur = node;
606 while !cur.is_null() {
607 let next = unsafe { (*cur).next };
608
609 if !unsafe { (*cur).children }.is_null() {
611 free_node_list(unsafe { (*cur).children });
612 }
613
614 free_node(cur);
615 cur = next;
616 }
617}
618
619unsafe fn free_prop_list(prop: *mut _xmlAttr) {
625 let mut cur = prop;
626 while !cur.is_null() {
627 let next = unsafe { (*cur).next };
628
629 if !unsafe { (*cur).children }.is_null() {
631 free_node_list(unsafe { (*cur).children });
632 }
633
634 if !unsafe { (*cur).name }.is_null() {
636 allocator::xmlFree(unsafe { (*cur).name } as *mut c_void);
637 }
638
639 allocator::xmlFree(cur as *mut c_void);
640 cur = next;
641 }
642}
643
644unsafe fn free_ns_list(ns: *mut _xmlNs) {
650 let mut cur = ns;
651 while !cur.is_null() {
652 let next = unsafe { (*cur).next };
653
654 if !unsafe { (*cur).href }.is_null() {
656 allocator::xmlFree(unsafe { (*cur).href } as *mut c_void);
657 }
658 if !unsafe { (*cur).prefix }.is_null() {
659 allocator::xmlFree(unsafe { (*cur).prefix } as *mut c_void);
660 }
661
662 allocator::xmlFree(cur as *mut c_void);
663 cur = next;
664 }
665}
666
667pub unsafe fn copy_node(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
682 if node.is_null() {
683 return ptr::null_mut();
684 }
685
686 let n = unsafe { &*node };
687
688 let new_node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
689 if new_node.is_null() {
690 return ptr::null_mut();
691 }
692
693 unsafe {
694 (*new_node).type_ = n.type_;
695 (*new_node).name = dup_xml_str(n.name);
696 (*new_node).line = n.line;
697 (*new_node).extra = n.extra;
698 (*new_node).psvi = n.psvi;
699 (*new_node)._private = n._private;
700
701 (*new_node).ns = n.ns;
703
704 let is_element = n.type_ == XML_ELEMENT_NODE as c_int;
707 if is_element && !n.nsDef.is_null() {
708 (*new_node).nsDef = copy_ns_list(n.nsDef);
709 }
710
711 let node_type = n.type_;
713 if (node_type == XML_TEXT_NODE as c_int
714 || node_type == XML_CDATA_SECTION_NODE as c_int
715 || node_type == XML_COMMENT_NODE as c_int
716 || node_type == XML_PI_NODE as c_int)
717 && !n.content.is_null()
718 {
719 (*new_node).content = dup_xml_str(n.content);
720 }
721
722 if is_element && !n.properties.is_null() {
724 (*new_node).properties = copy_prop_list(n.properties);
725 let mut prop = (*new_node).properties;
727 while !prop.is_null() {
728 (*prop).parent = new_node;
729 if !(*prop).children.is_null() {
730 propagate_doc((*prop).children, (*new_node).doc);
731 }
732 prop = (*prop).next;
733 }
734 }
735
736 if recursive != 0 && !n.children.is_null() {
738 (*new_node).children = copy_node_list(n.children, recursive);
739 if !(*new_node).children.is_null() {
740 (*(*new_node).children).parent = new_node;
741 (*(*new_node).children).doc = (*new_node).doc;
742 propagate_doc((*new_node).children, (*new_node).doc);
743 }
744 }
745 }
746
747 new_node
748}
749
750unsafe fn copy_node_list(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
754 if node.is_null() {
755 return ptr::null_mut();
756 }
757
758 let n = unsafe { &*node };
759 let new_node = copy_node(node, recursive);
760 if new_node.is_null() {
761 return ptr::null_mut();
762 }
763
764 let mut prev = new_node;
765 let mut cur = n.next;
766
767 while !cur.is_null() {
768 let new_cur = copy_node(cur, recursive);
769 if new_cur.is_null() {
770 break;
771 }
772 unsafe {
773 (*prev).next = new_cur;
774 (*new_cur).prev = prev;
775 }
776 prev = new_cur;
777 cur = unsafe { (*cur).next };
778 }
779
780 new_node
781}
782
783unsafe fn copy_ns_list(ns: *const _xmlNs) -> *mut _xmlNs {
785 if ns.is_null() {
786 return ptr::null_mut();
787 }
788
789 let n = unsafe { &*ns };
790 let new_ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
791 if new_ns.is_null() {
792 return ptr::null_mut();
793 }
794
795 unsafe {
796 (*new_ns).type_ = n.type_;
797 (*new_ns).href = dup_xml_str(n.href);
798 (*new_ns).prefix = dup_xml_str(n.prefix);
799 (*new_ns)._private = n._private;
800 }
801
802 let mut prev = new_ns;
803 let mut cur = n.next;
804
805 while !cur.is_null() {
806 let c = unsafe { &*cur };
807 let new_cur = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
808 if new_cur.is_null() {
809 break;
810 }
811 unsafe {
812 (*new_cur).type_ = c.type_;
813 (*new_cur).href = dup_xml_str(c.href);
814 (*new_cur).prefix = dup_xml_str(c.prefix);
815 (*new_cur)._private = c._private;
816 (*prev).next = new_cur;
817 }
818 prev = new_cur;
819 cur = c.next;
820 }
821
822 new_ns
823}
824
825unsafe fn copy_prop_list(prop: *const _xmlAttr) -> *mut _xmlAttr {
827 if prop.is_null() {
828 return ptr::null_mut();
829 }
830
831 let p = unsafe { &*prop };
832 let new_prop = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
833 if new_prop.is_null() {
834 return ptr::null_mut();
835 }
836
837 unsafe {
838 (*new_prop).type_ = p.type_;
839 (*new_prop).name = dup_xml_str(p.name);
840 (*new_prop).ns = p.ns;
841 (*new_prop).atype = p.atype;
842
843 if !p.children.is_null() {
845 (*new_prop).children = copy_node_list(p.children, 1);
846 if !(*new_prop).children.is_null() {
847 (*(*new_prop).children).parent = new_prop as *mut _xmlNode;
848 }
849 }
850 }
851
852 let mut prev = new_prop;
853 let mut cur = p.next;
854
855 while !cur.is_null() {
856 let c = unsafe { &*cur };
857 let new_cur = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
858 if new_cur.is_null() {
859 break;
860 }
861 unsafe {
862 (*new_cur).type_ = c.type_;
863 (*new_cur).name = dup_xml_str(c.name);
864 (*new_cur).ns = c.ns;
865 (*new_cur).atype = c.atype;
866
867 if !c.children.is_null() {
868 (*new_cur).children = copy_node_list(c.children, 1);
869 if !(*new_cur).children.is_null() {
870 (*(*new_cur).children).parent = new_cur as *mut _xmlNode;
871 }
872 }
873
874 (*prev).next = new_cur;
875 }
876 prev = new_cur;
877 cur = c.next;
878 }
879
880 new_prop
881}
882
883unsafe fn propagate_doc(node: *mut _xmlNode, doc: *mut _xmlDoc) {
885 let mut cur = node;
886 while !cur.is_null() {
887 unsafe {
888 (*cur).doc = doc;
889
890 if (*cur).type_ == XML_ELEMENT_NODE as c_int {
894 let mut prop = (*cur).properties;
895 while !prop.is_null() {
896 (*prop).doc = doc;
897 if !(*prop).children.is_null() {
898 propagate_doc((*prop).children, doc);
899 }
900 prop = (*prop).next;
901 }
902 }
903
904 if !(*cur).children.is_null() {
906 propagate_doc((*cur).children, doc);
907 }
908 }
909 cur = unsafe { (*cur).next };
910 }
911}
912
913pub unsafe fn unlink_node(node: *mut _xmlNode) {
929 if node.is_null() {
930 return;
931 }
932
933 let n = unsafe { &mut *node };
934
935 let prev = n.prev;
937 let next = n.next;
938
939 if !prev.is_null() {
940 unsafe { (*prev).next = next };
941 }
942 if !next.is_null() {
943 unsafe { (*next).prev = prev };
944 }
945
946 let parent = n.parent;
948 if !parent.is_null() {
949 if unsafe { (*parent).children } == node {
950 unsafe { (*parent).children = next };
951 }
952 if unsafe { (*parent).last } == node {
953 unsafe { (*parent).last = prev };
954 }
955 }
956
957 let doc = n.doc;
959 if !doc.is_null() && !parent.is_null() {
960 }
962 if !doc.is_null() && parent.is_null() {
963 if unsafe { (*doc).children } == node {
965 unsafe { (*doc).children = next };
966 }
967 if unsafe { (*doc).last } == node {
968 unsafe { (*doc).last = prev };
969 }
970 }
971
972 n.parent = ptr::null_mut();
974 n.prev = ptr::null_mut();
975 n.next = ptr::null_mut();
976}
977
978pub unsafe fn add_child(parent: *mut _xmlNode, cur: *mut _xmlNode) -> *mut _xmlNode {
994 if parent.is_null() || cur.is_null() {
995 return ptr::null_mut();
996 }
997
998 let p = unsafe { &mut *parent };
999 let c = unsafe { &mut *cur };
1000
1001 if !c.parent.is_null() || !c.prev.is_null() || !c.next.is_null() {
1003 unlink_node(cur);
1004 }
1005
1006 c.parent = parent;
1008
1009 if p.children.is_null() {
1010 p.children = cur;
1012 p.last = cur;
1013 c.prev = ptr::null_mut();
1014 c.next = ptr::null_mut();
1015 } else {
1016 c.prev = p.last;
1018 c.next = ptr::null_mut();
1019 if !p.last.is_null() {
1020 unsafe { (*p.last).next = cur };
1021 }
1022 p.last = cur;
1023 }
1024
1025 let doc = if !p.doc.is_null() {
1027 p.doc
1028 } else {
1029 ptr::null_mut()
1030 };
1031 if !doc.is_null() && c.doc != doc {
1032 propagate_doc(cur, doc);
1033 }
1034
1035 cur
1036}
1037
1038pub unsafe fn add_sibling(cur: *mut _xmlNode, elem: *mut _xmlNode) -> *mut _xmlNode {
1054 if cur.is_null() || elem.is_null() {
1055 return ptr::null_mut();
1056 }
1057
1058 let c = unsafe { &mut *cur };
1059
1060 let e = unsafe { &mut *elem };
1062 if !e.parent.is_null() || !e.prev.is_null() || !e.next.is_null() {
1063 unlink_node(elem);
1064 }
1065
1066 e.parent = c.parent;
1068
1069 e.prev = cur;
1071 e.next = c.next;
1072
1073 if !c.next.is_null() {
1074 unsafe { (*c.next).prev = elem };
1075 }
1076 c.next = elem;
1077
1078 let parent = c.parent;
1080 if !parent.is_null() && unsafe { (*parent).last } == cur {
1081 unsafe { (*parent).last = elem };
1082 }
1083
1084 if !c.doc.is_null() && e.doc != c.doc {
1086 propagate_doc(elem, c.doc);
1087 }
1088
1089 elem
1090}
1091
1092pub unsafe fn add_sibling_before(cur: *mut _xmlNode, elem: *mut _xmlNode) -> *mut _xmlNode {
1108 if cur.is_null() || elem.is_null() {
1109 return ptr::null_mut();
1110 }
1111
1112 let c = unsafe { &mut *cur };
1113
1114 let e = unsafe { &mut *elem };
1116 if !e.parent.is_null() || !e.prev.is_null() || !e.next.is_null() {
1117 unlink_node(elem);
1118 }
1119
1120 e.parent = c.parent;
1122
1123 e.prev = c.prev;
1125 e.next = cur;
1126
1127 if !c.prev.is_null() {
1128 unsafe { (*c.prev).next = elem };
1129 }
1130 c.prev = elem;
1131
1132 let parent = c.parent;
1134 if !parent.is_null() && unsafe { (*parent).children } == cur {
1135 unsafe { (*parent).children = elem };
1136 }
1137
1138 let doc = c.doc;
1140 if !doc.is_null() && parent.is_null() {
1141 if unsafe { (*doc).children } == cur {
1142 unsafe { (*doc).children = elem };
1143 }
1144 }
1145
1146 if !c.doc.is_null() && e.doc != c.doc {
1148 propagate_doc(elem, c.doc);
1149 }
1150
1151 elem
1152}
1153
1154pub unsafe fn new_child(
1169 parent: *mut _xmlNode,
1170 ns: *mut _xmlNs,
1171 name: *const xmlChar,
1172) -> *mut _xmlNode {
1173 let node = new_node(ns, name);
1174 if node.is_null() {
1175 return ptr::null_mut();
1176 }
1177
1178 if !parent.is_null() {
1179 add_child(parent, node);
1180 }
1181
1182 node
1183}
1184
1185pub unsafe fn new_text(content: *const xmlChar) -> *mut _xmlNode {
1204 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1205 if node.is_null() {
1206 return ptr::null_mut();
1207 }
1208
1209 unsafe {
1210 (*node).type_ = XML_TEXT_NODE as c_int;
1211 (*node).name = dup_xml_str(b"text\0" as *const u8 as *const xmlChar);
1212 (*node).content = if content.is_null() {
1213 let empty = allocator::xmlMalloc(1) as *mut xmlChar;
1214 if !empty.is_null() {
1215 *empty = 0;
1216 }
1217 empty
1218 } else {
1219 dup_xml_str(content)
1220 };
1221 (*node).line = 0;
1222 }
1223
1224 node
1225}
1226
1227pub unsafe fn new_comment(content: *const xmlChar) -> *mut _xmlNode {
1241 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1242 if node.is_null() {
1243 return ptr::null_mut();
1244 }
1245
1246 unsafe {
1247 (*node).type_ = XML_COMMENT_NODE as c_int;
1248 (*node).name = dup_xml_str(b"comment\0" as *const u8 as *const xmlChar);
1249 (*node).content = dup_xml_str(content);
1250 (*node).line = 0;
1251 }
1252
1253 node
1254}
1255
1256pub unsafe fn new_pi(name: *const xmlChar, content: *const xmlChar) -> *mut _xmlNode {
1271 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1272 if node.is_null() {
1273 return ptr::null_mut();
1274 }
1275
1276 unsafe {
1277 (*node).type_ = XML_PI_NODE as c_int;
1278 (*node).name = dup_xml_str(name);
1279 (*node).content = dup_xml_str(content);
1280 (*node).line = 0;
1281 }
1282
1283 node
1284}
1285
1286pub unsafe fn new_cdata_block(
1302 doc: *mut _xmlDoc,
1303 content: *const xmlChar,
1304 len: c_int,
1305) -> *mut _xmlNode {
1306 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1307 if node.is_null() {
1308 return ptr::null_mut();
1309 }
1310
1311 unsafe {
1312 (*node).type_ = XML_CDATA_SECTION_NODE as c_int;
1313 (*node).name = dup_xml_str(b"cdata\0" as *const u8 as *const xmlChar);
1314 (*node).doc = doc;
1315
1316 if !content.is_null() && len > 0 {
1317 (*node).content = allocator::xmlMalloc((len + 1) as usize) as *mut xmlChar;
1318 if !(*node).content.is_null() {
1319 ptr::copy_nonoverlapping(content, (*node).content, len as usize);
1320 *((*node).content.add(len as usize)) = 0;
1321 }
1322 } else {
1323 let empty = allocator::xmlMalloc(1) as *mut xmlChar;
1324 if !empty.is_null() {
1325 *empty = 0;
1326 }
1327 (*node).content = empty;
1328 }
1329
1330 (*node).line = 0;
1331 }
1332
1333 node
1334}
1335
1336pub unsafe fn new_ns(
1360 node: *mut _xmlNode,
1361 href: *const xmlChar,
1362 prefix: *const xmlChar,
1363) -> *mut _xmlNs {
1364 let ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
1365 if ns.is_null() {
1366 return ptr::null_mut();
1367 }
1368
1369 unsafe {
1370 (*ns).type_ = XML_LOCAL_NAMESPACE as c_int;
1371 (*ns).href = dup_xml_str(href);
1372 (*ns).prefix = dup_xml_str(prefix);
1373 (*ns).context = node as *mut _xmlDoc;
1374
1375 if !node.is_null() {
1377 let n = &mut *node;
1378 if n.nsDef.is_null() {
1379 n.nsDef = ns;
1380 } else {
1381 let mut last = n.nsDef;
1383 while !(*last).next.is_null() {
1384 last = (*last).next;
1385 }
1386 (*last).next = ns;
1387 }
1388 }
1389 }
1390
1391 ns
1392}
1393
1394pub unsafe fn set_ns(node: *mut _xmlNode, ns: *mut _xmlNs) {
1407 if node.is_null() {
1408 return;
1409 }
1410 unsafe {
1411 (*node).ns = ns;
1412 }
1413}
1414
1415pub unsafe fn get_ns_list(doc: *mut _xmlDoc, node: *mut _xmlNode) -> *mut *mut _xmlNs {
1431 if node.is_null() {
1435 return ptr::null_mut();
1436 }
1437
1438 let mut ns_ptrs: Vec<*mut _xmlNs> = Vec::new();
1440 let mut cur = node;
1441
1442 while !cur.is_null() {
1443 let n = unsafe { &*cur };
1444 let mut ns_def = n.nsDef;
1445 while !ns_def.is_null() {
1446 let ns = unsafe { &*ns_def };
1448 let mut found = false;
1449 for &existing in &ns_ptrs {
1450 if existing == ns_def {
1451 found = true;
1452 break;
1453 }
1454 let e = unsafe { &*existing };
1455 if !ns.href.is_null() && !e.href.is_null() {
1456 let href_match =
1457 unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, e.href) != 0 };
1458 if href_match {
1459 if ns.prefix.is_null() && e.prefix.is_null() {
1460 found = true;
1461 break;
1462 }
1463 if !ns.prefix.is_null() && !e.prefix.is_null() {
1464 let prefix_match = unsafe {
1465 crate::abi::exports_xml2::xmlStrEqual(ns.prefix, e.prefix) != 0
1466 };
1467 if prefix_match {
1468 found = true;
1469 break;
1470 }
1471 }
1472 }
1473 }
1474 }
1475 if !found {
1476 ns_ptrs.push(ns_def);
1477 }
1478 ns_def = unsafe { (*ns_def).next };
1479 }
1480 cur = n.parent;
1481 }
1482
1483 if ns_ptrs.is_empty() {
1484 return ptr::null_mut();
1485 }
1486
1487 let arr =
1489 allocator::xmlMalloc((ns_ptrs.len() + 1) * size_of::<*mut _xmlNs>()) as *mut *mut _xmlNs;
1490 if arr.is_null() {
1491 return ptr::null_mut();
1492 }
1493
1494 for (i, ns) in ns_ptrs.iter().enumerate() {
1495 unsafe { *arr.add(i) = *ns };
1496 }
1497 unsafe { *arr.add(ns_ptrs.len()) = ptr::null_mut() };
1498
1499 arr
1500}
1501
1502pub unsafe fn search_ns(
1519 doc: *mut _xmlDoc,
1520 node: *mut _xmlNode,
1521 name_space: *const xmlChar,
1522) -> *mut _xmlNs {
1523 if node.is_null() {
1524 return ptr::null_mut();
1525 }
1526
1527 let mut cur = node;
1528 while !cur.is_null() {
1529 let n = unsafe { &*cur };
1530 let mut ns_def = n.nsDef;
1531 while !ns_def.is_null() {
1532 let ns = unsafe { &*ns_def };
1533 let match_prefix = if name_space.is_null() {
1534 ns.prefix.is_null()
1536 } else {
1537 !ns.prefix.is_null()
1538 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.prefix, name_space) != 0 }
1539 };
1540 if match_prefix {
1541 return ns_def;
1542 }
1543 ns_def = unsafe { (*ns_def).next };
1544 }
1545 cur = n.parent;
1546 }
1547
1548 ptr::null_mut()
1549}
1550
1551pub unsafe fn search_ns_by_href(
1567 doc: *mut _xmlDoc,
1568 node: *mut _xmlNode,
1569 href: *const xmlChar,
1570) -> *mut _xmlNs {
1571 if node.is_null() || href.is_null() {
1572 return ptr::null_mut();
1573 }
1574
1575 let mut cur = node;
1576 while !cur.is_null() {
1577 let n = unsafe { &*cur };
1578 let mut ns_def = n.nsDef;
1579 while !ns_def.is_null() {
1580 let ns = unsafe { &*ns_def };
1581 if !ns.href.is_null()
1582 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, href) != 0 }
1583 {
1584 return ns_def;
1585 }
1586 ns_def = unsafe { (*ns_def).next };
1587 }
1588 cur = n.parent;
1589 }
1590
1591 ptr::null_mut()
1592}
1593
1594pub unsafe fn set_prop(
1618 node: *mut _xmlNode,
1619 name: *const xmlChar,
1620 value: *const xmlChar,
1621) -> *mut _xmlAttr {
1622 if node.is_null() || name.is_null() {
1623 return ptr::null_mut();
1624 }
1625
1626 let n = unsafe { &mut *node };
1627
1628 let mut existing = n.properties;
1630 while !existing.is_null() {
1631 let attr = unsafe { &*existing };
1632 if !attr.name.is_null()
1633 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1634 {
1635 if !attr.children.is_null() {
1638 free_node_list(attr.children);
1639 let attr_mut = existing as *mut _xmlAttr;
1641 unsafe { (*attr_mut).children = ptr::null_mut() };
1642 unsafe { (*attr_mut).last = ptr::null_mut() };
1643 }
1644 if !value.is_null() {
1646 let text = new_text(value);
1647 if !text.is_null() {
1648 let attr_mut = existing as *mut _xmlAttr;
1649 unsafe {
1650 (*attr_mut).children = text;
1651 (*attr_mut).last = text;
1652 (*text).parent = existing as *mut _xmlNode;
1653 (*text).doc = n.doc;
1654 }
1655 }
1656 }
1657 return existing;
1658 }
1659 existing = unsafe { (*existing).next };
1660 }
1661
1662 let attr = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
1664 if attr.is_null() {
1665 return ptr::null_mut();
1666 }
1667
1668 unsafe {
1669 (*attr).type_ = XML_ATTRIBUTE_NODE as c_int;
1670 (*attr).name = dup_xml_str(name);
1671 (*attr).parent = node;
1672 (*attr).doc = n.doc;
1673 (*attr).atype = XML_ATTRIBUTE_CDATA as c_int;
1674
1675 if !value.is_null() {
1677 let text = new_text(value);
1678 if !text.is_null() {
1679 (*attr).children = text;
1680 (*attr).last = text;
1681 (*text).parent = attr as *mut _xmlNode;
1682 (*text).doc = n.doc;
1683 }
1684 }
1685
1686 if n.properties.is_null() {
1688 n.properties = attr;
1689 } else {
1690 let mut last = n.properties;
1691 while !(*last).next.is_null() {
1692 last = (*last).next;
1693 }
1694 (*last).next = attr;
1695 (*attr).prev = last;
1696 }
1697 }
1698
1699 attr
1700}
1701
1702pub unsafe fn get_prop(node: *mut _xmlNode, name: *const xmlChar) -> *mut xmlChar {
1718 if node.is_null() || name.is_null() {
1719 return ptr::null_mut();
1720 }
1721
1722 let n = unsafe { &*node };
1723 let mut cur = n.properties;
1724
1725 while !cur.is_null() {
1726 let attr = unsafe { &*cur };
1727 if !attr.name.is_null()
1728 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1729 {
1730 if !attr.children.is_null() {
1732 let text = unsafe { &*attr.children };
1733 if text.type_ == XML_TEXT_NODE as c_int && !text.content.is_null() {
1734 return dup_xml_str(text.content);
1735 }
1736 }
1737 return dup_xml_str(b"\0" as *const u8 as *const xmlChar);
1738 }
1739 cur = unsafe { (*cur).next };
1740 }
1741
1742 ptr::null_mut()
1743}
1744
1745pub unsafe fn get_ns_prop(
1761 node: *mut _xmlNode,
1762 name: *const xmlChar,
1763 _name_space: *const xmlChar,
1764) -> *mut xmlChar {
1765 get_prop(node, name)
1768}
1769
1770pub unsafe fn set_ns_prop(
1785 node: *mut _xmlNode,
1786 _ns: *mut _xmlNs,
1787 name: *const xmlChar,
1788 value: *const xmlChar,
1789) -> *mut _xmlAttr {
1790 set_prop(node, name, value)
1792}
1793
1794pub unsafe fn remove_prop(attr: *mut _xmlAttr) -> c_int {
1809 if attr.is_null() {
1810 return -1;
1811 }
1812
1813 let a = unsafe { &mut *attr };
1814
1815 let parent = a.parent;
1817 if !parent.is_null() {
1818 let p = unsafe { &mut *parent };
1819 if p.properties == attr {
1820 p.properties = a.next;
1821 }
1822 }
1823
1824 if !a.prev.is_null() {
1826 unsafe { (*a.prev).next = a.next };
1827 }
1828 if !a.next.is_null() {
1829 unsafe { (*a.next).prev = a.prev };
1830 }
1831
1832 if !a.children.is_null() {
1834 free_node_list(a.children);
1835 }
1836
1837 if !a.name.is_null() {
1839 allocator::xmlFree(a.name as *mut c_void);
1840 }
1841
1842 allocator::xmlFree(attr as *mut c_void);
1843 0
1844}
1845
1846pub fn get_int_subset(doc: *const _xmlDoc) -> *mut _xmlDtd {
1858 if doc.is_null() {
1859 return ptr::null_mut();
1860 }
1861 let d = unsafe { &*doc };
1862 d.intSubset
1863}
1864
1865pub unsafe fn new_dtd(
1882 doc: *mut _xmlDoc,
1883 name: *const xmlChar,
1884 ExternalID: *const xmlChar,
1885 SystemID: *const xmlChar,
1886) -> *mut _xmlDtd {
1887 let dtd = allocator::xmlMallocZero(size_of::<_xmlDtd>() as usize) as *mut _xmlDtd;
1888 if dtd.is_null() {
1889 return ptr::null_mut();
1890 }
1891
1892 unsafe {
1893 (*dtd).type_ = XML_DTD_NODE as c_int;
1894 (*dtd).name = dup_xml_str(name);
1895 (*dtd).ExternalID = dup_xml_str(ExternalID);
1896 (*dtd).SystemID = dup_xml_str(SystemID);
1897 (*dtd).parent = doc;
1898 (*dtd).doc = doc;
1899
1900 (*dtd).notations = crate::xml::hash::hash_create(8) as *mut c_void;
1903 (*dtd).elements = crate::xml::hash::hash_create(16) as *mut c_void;
1904 (*dtd).attributes = crate::xml::hash::hash_create(16) as *mut c_void;
1905 (*dtd).entities = crate::xml::hash::hash_create(8) as *mut c_void;
1906 (*dtd).pentities = crate::xml::hash::hash_create(8) as *mut c_void;
1907
1908 if !doc.is_null() {
1910 if (*doc).intSubset.is_null() {
1911 (*doc).intSubset = dtd;
1912 }
1913 }
1914 }
1915
1916 dtd
1917}
1918
1919unsafe fn free_dtd(dtd: *mut _xmlDtd) {
1925 if dtd.is_null() {
1926 return;
1927 }
1928
1929 let d = unsafe { &mut *dtd };
1930
1931 if !d.name.is_null() {
1933 allocator::xmlFree(d.name as *mut c_void);
1934 }
1935 if !d.ExternalID.is_null() {
1936 allocator::xmlFree(d.ExternalID as *mut c_void);
1937 }
1938 if !d.SystemID.is_null() {
1939 allocator::xmlFree(d.SystemID as *mut c_void);
1940 }
1941
1942 unsafe extern "C" fn free_notation_wrapper(payload: *mut c_void, _name: *mut u8) {
1944 crate::xml::dtd::free_notation(payload as *mut _xmlNotation);
1945 }
1946 unsafe extern "C" fn free_element_wrapper(payload: *mut c_void, _name: *mut u8) {
1947 crate::xml::dtd::free_element(payload as *mut _xmlElement);
1948 }
1949 unsafe extern "C" fn free_attribute_wrapper(payload: *mut c_void, _name: *mut u8) {
1950 crate::xml::dtd::free_attribute(payload as *mut _xmlAttribute);
1951 }
1952 unsafe extern "C" fn free_entity_wrapper(payload: *mut c_void, _name: *mut u8) {
1953 crate::xml::entities::free_entity(payload as *mut _xmlEntity);
1954 }
1955
1956 if !d.notations.is_null() {
1957 crate::xml::hash::hash_free(
1958 d.notations as *mut crate::xml::hash::HashTable,
1959 Some(free_notation_wrapper),
1960 );
1961 d.notations = ptr::null_mut();
1962 }
1963 if !d.elements.is_null() {
1964 crate::xml::hash::hash_free(
1965 d.elements as *mut crate::xml::hash::HashTable,
1966 Some(free_element_wrapper),
1967 );
1968 d.elements = ptr::null_mut();
1969 }
1970 if !d.attributes.is_null() {
1971 crate::xml::hash::hash_free(
1972 d.attributes as *mut crate::xml::hash::HashTable,
1973 Some(free_attribute_wrapper),
1974 );
1975 d.attributes = ptr::null_mut();
1976 }
1977 if !d.entities.is_null() {
1978 crate::xml::hash::hash_free(
1979 d.entities as *mut crate::xml::hash::HashTable,
1980 Some(free_entity_wrapper),
1981 );
1982 d.entities = ptr::null_mut();
1983 }
1984 if !d.pentities.is_null() {
1985 crate::xml::hash::hash_free(
1986 d.pentities as *mut crate::xml::hash::HashTable,
1987 Some(free_entity_wrapper),
1988 );
1989 d.pentities = ptr::null_mut();
1990 }
1991
1992 if !d.children.is_null() {
1994 free_node_list(d.children);
1995 }
1996
1997 allocator::xmlFree(dtd as *mut c_void);
1998}
1999
2000pub unsafe fn new_entity(
2020 _doc: *mut _xmlDoc,
2021 name: *const xmlChar,
2022 etype: c_int,
2023 ExternalID: *const xmlChar,
2024 SystemID: *const xmlChar,
2025 content: *const xmlChar,
2026) -> *mut _xmlEntity {
2027 let entity = allocator::xmlMallocZero(size_of::<_xmlEntity>() as usize) as *mut _xmlEntity;
2028 if entity.is_null() {
2029 return ptr::null_mut();
2030 }
2031
2032 unsafe {
2033 (*entity).type_ = XML_ENTITY_DECL as c_int;
2034 (*entity).name = dup_xml_str(name);
2035 (*entity).etype = etype;
2036 (*entity).ExternalID = dup_xml_str(ExternalID);
2037 (*entity).SystemID = dup_xml_str(SystemID);
2038 (*entity).content = dup_xml_str(content);
2039 (*entity).length = if content.is_null() {
2040 0
2041 } else {
2042 crate::abi::exports_xml2::xmlStrlen(content)
2043 };
2044 (*entity).flags = 0;
2045 (*entity).expandedSize = 0;
2046 }
2047
2048 entity
2049}
2050
2051pub unsafe fn get_doc_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2066 crate::xml::entities::get_entity(doc as *mut _xmlDoc, name)
2067}
2068
2069pub unsafe fn get_parameter_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2082 crate::xml::entities::get_parameter_entity(doc as *mut _xmlDoc, name)
2083}
2084
2085const ENTITY_LT: &[xmlChar] = b"<";
2094const ENTITY_GT: &[xmlChar] = b">";
2095const ENTITY_AMP: &[xmlChar] = b"&";
2096const ENTITY_QUOT: &[xmlChar] = b""";
2097const ENTITY_APOS: &[xmlChar] = b"'";
2098
2099const INDENT: &[xmlChar] = b" ";
2101
2102const MAX_INDENT: c_int = 60;
2104
2105pub(crate) unsafe fn serialize_text(buf: *mut _xmlBuffer, content: *const xmlChar, len: c_int) {
2120 if buf.is_null() || content.is_null() || len <= 0 {
2121 return;
2122 }
2123
2124 let mut i: c_int = 0;
2125 while i < len {
2126 let ch = unsafe { *content.add(i as usize) };
2127
2128 if ch == b']'
2130 && i + 2 < len
2131 && unsafe { *content.add(i as usize + 1) == b']' }
2132 && unsafe { *content.add(i as usize + 2) == b'>' }
2133 {
2134 io::buf_add(buf, &ch as *const u8, 2); io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2137 i += 3;
2138 continue;
2139 }
2140
2141 match ch {
2142 b'<' => {
2143 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
2144 }
2145 b'&' => {
2146 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
2147 }
2148 b'>' => {
2149 io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2153 }
2154 b'\r' => {
2155 io::buf_add(buf, b" " as *const u8, 5);
2157 }
2158 0x01..=0x08 | 0x0B | 0x0C | 0x0E..=0x1F => {
2159 let hex = format!("&#x{:X};", ch);
2161 io::buf_add(buf, hex.as_ptr(), hex.len() as c_int);
2162 }
2163 _ => {
2164 io::buf_add(buf, &ch as *const u8, 1);
2165 }
2166 }
2167 i += 1;
2168 }
2169}
2170
2171pub(crate) unsafe fn serialize_attr_value(buf: *mut _xmlBuffer, value: *const xmlChar) {
2184 if buf.is_null() || value.is_null() {
2185 return;
2186 }
2187
2188 let len = xml_strlen(value);
2189 let mut i: c_int = 0;
2190 while i < len {
2191 let ch = unsafe { *value.add(i as usize) };
2192
2193 match ch {
2194 b'\n' => {
2195 io::buf_add(buf, b" " as *const u8, 5);
2196 }
2197 b'\r' => {
2198 io::buf_add(buf, b" " as *const u8, 5);
2199 }
2200 b'\t' => {
2201 io::buf_add(buf, b"	" as *const u8, 4);
2202 }
2203 b'<' => {
2204 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
2205 }
2206 b'&' => {
2207 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
2208 }
2209 b'"' => {
2210 io::buf_add(buf, ENTITY_QUOT.as_ptr(), ENTITY_QUOT.len() as c_int);
2211 }
2212 b'>' => {
2213 io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2214 }
2215 _ => {
2216 io::buf_add(buf, &ch as *const u8, 1);
2217 }
2218 }
2219 i += 1;
2220 }
2221}
2222
2223unsafe fn write_indent(buf: *mut _xmlBuffer, level: c_int) {
2235 if buf.is_null() || level <= 0 {
2236 return;
2237 }
2238 let indent_nr = MAX_INDENT / INDENT.len() as c_int;
2239 let mut lvl = level;
2240 if lvl > indent_nr {
2241 lvl = indent_nr;
2242 }
2243 for _ in 0..lvl {
2244 io::buf_add(buf, INDENT.as_ptr(), INDENT.len() as c_int);
2245 }
2246}
2247
2248unsafe fn is_noenc_text(node: *mut _xmlNode) -> bool {
2256 if node.is_null() {
2257 return false;
2258 }
2259 let n = unsafe { &*node };
2260 if n.name.is_null() {
2261 return false;
2262 }
2263 c_str_eq_bytes(n.name, b"textnoenc")
2264}
2265
2266unsafe fn c_str_eq_bytes(s: *const xmlChar, b: &[u8]) -> bool {
2268 let mut i = 0usize;
2269 while i < b.len() {
2270 if unsafe { *s.add(i) } != b[i] {
2271 return false;
2272 }
2273 i += 1;
2274 }
2275 unsafe { *s.add(i) == 0 }
2276}
2277
2278#[derive(Clone, Copy)]
2281struct DumpState {
2282 format: c_int,
2284 saved: c_int,
2287 unformatted: *mut _xmlNode,
2290}
2291
2292impl DumpState {
2293 fn new(format: c_int) -> Self {
2294 let f = if format != 0 { 1 } else { 0 };
2295 DumpState {
2296 format: f,
2297 saved: f,
2298 unformatted: ptr::null_mut(),
2299 }
2300 }
2301}
2302
2303unsafe fn write_qname(buf: *mut _xmlBuffer, node: *mut _xmlNode) {
2309 let n = unsafe { &*node };
2310 if !n.ns.is_null() {
2311 let ns = unsafe { &*n.ns };
2312 if !ns.prefix.is_null() {
2313 io::buf_cat(buf, ns.prefix);
2314 io::buf_ccat(buf, b':');
2315 }
2316 }
2317 if !n.name.is_null() {
2318 io::buf_cat(buf, n.name);
2319 }
2320}
2321
2322unsafe fn ns_dump_output(buf: *mut _xmlBuffer, cur: *mut _xmlNs) {
2328 if cur.is_null() || buf.is_null() {
2329 return;
2330 }
2331 let ns = unsafe { &*cur };
2332 if ns.type_ == XML_LOCAL_NAMESPACE as c_int && !ns.href.is_null() {
2333 if !ns.prefix.is_null() && c_str_eq_bytes(ns.prefix, b"xml") {
2335 return;
2336 }
2337 io::buf_ccat(buf, b' ');
2338 if !ns.prefix.is_null() {
2339 io::buf_add(buf, b"xmlns:" as *const u8, 6);
2340 io::buf_cat(buf, ns.prefix);
2341 } else {
2342 io::buf_add(buf, b"xmlns" as *const u8, 5);
2343 }
2344 io::buf_add(buf, b"=\"" as *const u8, 2);
2345 serialize_attr_value(buf, ns.href);
2346 io::buf_ccat(buf, b'"');
2347 }
2348}
2349
2350unsafe fn attr_dump_output(buf: *mut _xmlBuffer, cur: *mut _xmlAttr) {
2356 if cur.is_null() || buf.is_null() {
2357 return;
2358 }
2359 io::buf_ccat(buf, b' ');
2360 let a = unsafe { &*cur };
2361 if !a.ns.is_null() {
2362 let ans = unsafe { &*a.ns };
2363 if !ans.prefix.is_null() {
2364 io::buf_cat(buf, ans.prefix);
2365 io::buf_ccat(buf, b':');
2366 }
2367 }
2368 if !a.name.is_null() {
2369 io::buf_cat(buf, a.name);
2370 }
2371 io::buf_add(buf, b"=\"" as *const u8, 2);
2372 let mut child = a.children;
2375 while !child.is_null() {
2376 let ct = unsafe { (*child).type_ };
2377 if ct == XML_TEXT_NODE as c_int && !unsafe { (*child).content }.is_null() {
2378 serialize_attr_value(buf, unsafe { (*child).content });
2379 } else if ct == XML_ENTITY_REF_NODE as c_int && !unsafe { (*child).name }.is_null() {
2380 io::buf_ccat(buf, b'&');
2381 io::buf_cat(buf, unsafe { (*child).name });
2382 io::buf_ccat(buf, b';');
2383 }
2384 child = unsafe { (*child).next };
2385 }
2386 io::buf_ccat(buf, b'"');
2387}
2388
2389unsafe fn dump_notation_decl(buf: *mut _xmlBuffer, nota: *mut _xmlNotation) {
2395 let n = unsafe { &*nota };
2396 io::buf_add(buf, b"<!NOTATION " as *const u8, 11);
2397 if !n.name.is_null() {
2398 io::buf_cat(buf, n.name);
2399 }
2400 if !n.PublicID.is_null() {
2401 io::buf_add(buf, b" PUBLIC " as *const u8, 8);
2402 write_quoted_string(buf, n.PublicID);
2403 if !n.SystemID.is_null() {
2404 io::buf_ccat(buf, b' ');
2405 write_quoted_string(buf, n.SystemID);
2406 }
2407 } else {
2408 io::buf_add(buf, b" SYSTEM " as *const u8, 8);
2409 write_quoted_string(buf, n.SystemID);
2410 }
2411 io::buf_add(buf, b" >\n" as *const u8, 4);
2412}
2413
2414unsafe fn dump_element_occur(buf: *mut _xmlBuffer, ocur: c_int) {
2416 use crate::abi::types::xmlElementContentOccur::*;
2417 if ocur == XML_ELEMENT_CONTENT_OPT as c_int {
2418 io::buf_ccat(buf, b'?');
2419 } else if ocur == XML_ELEMENT_CONTENT_MULT as c_int {
2420 io::buf_ccat(buf, b'*');
2421 } else if ocur == XML_ELEMENT_CONTENT_PLUS as c_int {
2422 io::buf_ccat(buf, b'+');
2423 }
2424}
2425
2426unsafe fn dump_element_content(buf: *mut _xmlBuffer, content: *mut _xmlElementContent) {
2432 use crate::abi::types::xmlElementContentOccur::*;
2433 use crate::abi::types::xmlElementContentType::*;
2434 if content.is_null() {
2435 return;
2436 }
2437 io::buf_ccat(buf, b'(');
2438 let mut cur = content;
2439 loop {
2440 if cur.is_null() {
2441 return;
2442 }
2443 let c = unsafe { &*cur };
2444 match c.type_ {
2445 t if t == XML_ELEMENT_CONTENT_PCDATA as c_int => {
2446 io::buf_add(buf, b"#PCDATA" as *const u8, 7);
2447 }
2448 t if t == XML_ELEMENT_CONTENT_ELEMENT as c_int => {
2449 if !c.prefix.is_null() {
2450 io::buf_cat(buf, c.prefix);
2451 io::buf_ccat(buf, b':');
2452 }
2453 if !c.name.is_null() {
2454 io::buf_cat(buf, c.name);
2455 }
2456 }
2457 t if t == XML_ELEMENT_CONTENT_SEQ as c_int || t == XML_ELEMENT_CONTENT_OR as c_int => {
2458 if cur != content
2459 && !c.parent.is_null()
2460 && (c.type_ != unsafe { (*c.parent).type_ }
2461 || c.ocur != XML_ELEMENT_CONTENT_ONCE as c_int)
2462 {
2463 io::buf_ccat(buf, b'(');
2464 }
2465 cur = c.c1;
2466 continue;
2467 }
2468 _ => {}
2469 }
2470
2471 while cur != content {
2473 let ccur = unsafe { &*cur };
2474 let parent = ccur.parent;
2475 if parent.is_null() {
2476 return;
2477 }
2478 let p = unsafe { &*parent };
2479 if ((ccur.type_ == XML_ELEMENT_CONTENT_OR as c_int
2480 || ccur.type_ == XML_ELEMENT_CONTENT_SEQ as c_int)
2481 && (ccur.type_ != p.type_ || ccur.ocur != XML_ELEMENT_CONTENT_ONCE as c_int))
2482 {
2483 io::buf_ccat(buf, b')');
2484 }
2485 dump_element_occur(buf, ccur.ocur);
2486
2487 if ccur.type_ == XML_ELEMENT_CONTENT_SEQ as c_int {
2488 io::buf_add(buf, b" , " as *const u8, 3);
2489 } else if ccur.type_ == XML_ELEMENT_CONTENT_OR as c_int {
2490 io::buf_add(buf, b" | " as *const u8, 3);
2491 }
2492
2493 if cur == p.c1 {
2494 cur = p.c2;
2495 break;
2496 }
2497 cur = parent;
2498 }
2499 if cur == content {
2500 break;
2501 }
2502 }
2503 io::buf_ccat(buf, b')');
2504 let cc = unsafe { &*content };
2505 dump_element_occur(buf, cc.ocur);
2506}
2507
2508unsafe fn dump_element_decl(buf: *mut _xmlBuffer, elem: *mut _xmlElement) {
2514 use crate::abi::types::xmlElementTypeVal::*;
2515 let e = unsafe { &*elem };
2516 io::buf_add(buf, b"<!ELEMENT " as *const u8, 10);
2517 if !e.prefix.is_null() {
2518 io::buf_cat(buf, e.prefix);
2519 io::buf_ccat(buf, b':');
2520 }
2521 if !e.name.is_null() {
2522 io::buf_cat(buf, e.name);
2523 }
2524 io::buf_ccat(buf, b' ');
2525 match e.type_ {
2526 t if t == XML_ELEMENT_TYPE_EMPTY as c_int => {
2527 io::buf_add(buf, b"EMPTY" as *const u8, 5);
2528 }
2529 t if t == XML_ELEMENT_TYPE_ANY as c_int => {
2530 io::buf_add(buf, b"ANY" as *const u8, 3);
2531 }
2532 t if t == XML_ELEMENT_TYPE_MIXED as c_int || t == XML_ELEMENT_TYPE_ELEMENT as c_int => {
2533 dump_element_content(buf, e.content);
2534 }
2535 _ => {}
2536 }
2537 io::buf_add(buf, b">\n" as *const u8, 2);
2538}
2539
2540unsafe fn dump_enumeration(buf: *mut _xmlBuffer, cur: *mut _xmlEnumeration) {
2546 let mut e = cur;
2547 while !e.is_null() {
2548 let en = unsafe { &*e };
2549 if !en.name.is_null() {
2550 io::buf_cat(buf, en.name);
2551 }
2552 if !en.next.is_null() {
2553 io::buf_add(buf, b" | " as *const u8, 3);
2554 }
2555 e = en.next;
2556 }
2557 io::buf_ccat(buf, b')');
2558}
2559
2560unsafe fn dump_attribute_decl(buf: *mut _xmlBuffer, attr: *mut _xmlAttribute) {
2566 use crate::abi::types::xmlAttributeDefault::*;
2567 use crate::abi::types::xmlAttributeType::*;
2568 let a = unsafe { &*attr };
2569 io::buf_add(buf, b"<!ATTLIST " as *const u8, 10);
2570 if !a.elem.is_null() {
2571 io::buf_cat(buf, a.elem);
2572 }
2573 io::buf_ccat(buf, b' ');
2574 if !a.prefix.is_null() {
2575 io::buf_cat(buf, a.prefix);
2576 io::buf_ccat(buf, b':');
2577 }
2578 if !a.name.is_null() {
2579 io::buf_cat(buf, a.name);
2580 }
2581 match a.atype {
2582 t if t == XML_ATTRIBUTE_CDATA as c_int => {
2583 io::buf_add(buf, b" CDATA" as *const u8, 6);
2584 }
2585 t if t == XML_ATTRIBUTE_ID as c_int => {
2586 io::buf_add(buf, b" ID" as *const u8, 3);
2587 }
2588 t if t == XML_ATTRIBUTE_IDREF as c_int => {
2589 io::buf_add(buf, b" IDREF" as *const u8, 6);
2590 }
2591 t if t == XML_ATTRIBUTE_IDREFS as c_int => {
2592 io::buf_add(buf, b" IDREFS" as *const u8, 7);
2593 }
2594 t if t == XML_ATTRIBUTE_ENTITY as c_int => {
2595 io::buf_add(buf, b" ENTITY" as *const u8, 7);
2596 }
2597 t if t == XML_ATTRIBUTE_ENTITIES as c_int => {
2598 io::buf_add(buf, b" ENTITIES" as *const u8, 9);
2599 }
2600 t if t == XML_ATTRIBUTE_NMTOKEN as c_int => {
2601 io::buf_add(buf, b" NMTOKEN" as *const u8, 8);
2602 }
2603 t if t == XML_ATTRIBUTE_NMTOKENS as c_int => {
2604 io::buf_add(buf, b" NMTOKENS" as *const u8, 9);
2605 }
2606 t if t == XML_ATTRIBUTE_ENUMERATION as c_int => {
2607 io::buf_add(buf, b" (" as *const u8, 2);
2608 dump_enumeration(buf, a.tree);
2609 }
2610 t if t == XML_ATTRIBUTE_NOTATION as c_int => {
2611 io::buf_add(buf, b" NOTATION (" as *const u8, 11);
2612 dump_enumeration(buf, a.tree);
2613 }
2614 _ => {}
2615 }
2616 match a.def {
2617 t if t == XML_ATTRIBUTE_REQUIRED as c_int => {
2618 io::buf_add(buf, b" #REQUIRED" as *const u8, 10);
2619 }
2620 t if t == XML_ATTRIBUTE_IMPLIED as c_int => {
2621 io::buf_add(buf, b" #IMPLIED" as *const u8, 9);
2622 }
2623 t if t == XML_ATTRIBUTE_FIXED as c_int => {
2624 io::buf_add(buf, b" #FIXED" as *const u8, 7);
2625 }
2626 _ => {}
2627 }
2628 if !a.defaultValue.is_null() {
2629 io::buf_add(buf, b" \"" as *const u8, 2);
2630 serialize_attr_value(buf, a.defaultValue);
2631 io::buf_ccat(buf, b'"');
2632 }
2633 io::buf_add(buf, b">\n" as *const u8, 2);
2634}
2635
2636unsafe fn write_quoted_string(buf: *mut _xmlBuffer, str: *const xmlChar) {
2642 if buf.is_null() {
2643 return;
2644 }
2645 io::buf_ccat(buf, b'"');
2646 if !str.is_null() {
2647 let mut i = 0usize;
2648 while unsafe { *str.add(i) != 0 } {
2649 let ch = unsafe { *str.add(i) };
2650 if ch == b'"' {
2651 io::buf_add(buf, b""" as *const u8, 6);
2652 } else {
2653 io::buf_add(buf, &ch as *const u8, 1);
2654 }
2655 i += 1;
2656 }
2657 }
2658 io::buf_ccat(buf, b'"');
2659}
2660
2661unsafe fn dump_entity_decl(buf: *mut _xmlBuffer, ent: *mut _xmlEntity) {
2667 use crate::abi::types::xmlEntityType::*;
2668 let e = unsafe { &*ent };
2669 if e.etype == XML_INTERNAL_PARAMETER_ENTITY as c_int
2670 || e.etype == XML_EXTERNAL_PARAMETER_ENTITY as c_int
2671 {
2672 io::buf_add(buf, b"<!ENTITY % " as *const u8, 11);
2673 } else {
2674 io::buf_add(buf, b"<!ENTITY " as *const u8, 9);
2675 }
2676 if !e.name.is_null() {
2677 io::buf_cat(buf, e.name);
2678 }
2679 io::buf_ccat(buf, b' ');
2680
2681 if e.etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY as c_int
2682 || e.etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int
2683 || e.etype == XML_EXTERNAL_PARAMETER_ENTITY as c_int
2684 {
2685 if !e.ExternalID.is_null() {
2686 io::buf_add(buf, b"PUBLIC " as *const u8, 7);
2687 write_quoted_string(buf, e.ExternalID);
2688 io::buf_ccat(buf, b' ');
2689 } else {
2690 io::buf_add(buf, b"SYSTEM " as *const u8, 7);
2691 }
2692 write_quoted_string(buf, e.SystemID);
2693 }
2694
2695 if e.etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int {
2696 if !e.content.is_null() {
2697 io::buf_add(buf, b" NDATA " as *const u8, 7);
2698 if !e.orig.is_null() {
2699 io::buf_cat(buf, e.orig);
2700 } else if !e.content.is_null() {
2701 io::buf_cat(buf, e.content);
2702 }
2703 }
2704 }
2705
2706 if e.etype == XML_INTERNAL_GENERAL_ENTITY as c_int
2707 || e.etype == XML_INTERNAL_PARAMETER_ENTITY as c_int
2708 {
2709 if !e.orig.is_null() {
2710 write_quoted_string(buf, e.orig);
2711 } else {
2712 io::buf_ccat(buf, b'"');
2714 if !e.content.is_null() {
2715 let mut i = 0usize;
2716 while unsafe { *e.content.add(i) != 0 } {
2717 let ch = unsafe { *e.content.add(i) };
2718 match ch {
2719 b'"' => io::buf_add(buf, b""" as *const u8, 6),
2720 b'%' => io::buf_add(buf, b"%" as *const u8, 6),
2721 _ => io::buf_add(buf, &ch as *const u8, 1),
2722 };
2723 i += 1;
2724 }
2725 }
2726 io::buf_ccat(buf, b'"');
2727 }
2728 }
2729 io::buf_add(buf, b">\n" as *const u8, 2);
2730}
2731
2732unsafe fn dtd_dump_output(
2738 buf: *mut _xmlBuffer,
2739 cur: *mut _xmlNode,
2740 state: &mut DumpState,
2741 level: &mut c_int,
2742) {
2743 let dtd = cur as *mut _xmlDtd;
2744 let d = unsafe { &*dtd };
2745 io::buf_add(buf, b"<!DOCTYPE " as *const u8, 10);
2746 if !d.name.is_null() {
2747 io::buf_cat(buf, d.name);
2748 }
2749 if !d.ExternalID.is_null() {
2750 io::buf_add(buf, b" PUBLIC " as *const u8, 8);
2751 write_quoted_string(buf, d.ExternalID);
2752 io::buf_ccat(buf, b' ');
2753 write_quoted_string(buf, d.SystemID);
2754 } else if !d.SystemID.is_null() {
2755 io::buf_add(buf, b" SYSTEM " as *const u8, 8);
2756 write_quoted_string(buf, d.SystemID);
2757 }
2758 if crate::xml::hash::hash_size(d.entities as *mut crate::xml::hash::HashTable) == 0
2759 && crate::xml::hash::hash_size(d.elements as *mut crate::xml::hash::HashTable) == 0
2760 && crate::xml::hash::hash_size(d.attributes as *mut crate::xml::hash::HashTable) == 0
2761 && crate::xml::hash::hash_size(d.notations as *mut crate::xml::hash::HashTable) == 0
2762 && crate::xml::hash::hash_size(d.pentities as *mut crate::xml::hash::HashTable) == 0
2763 {
2764 io::buf_ccat(buf, b'>');
2765 return;
2766 }
2767 io::buf_add(buf, b" [\n" as *const u8, 3);
2768 let format = state.format;
2774 let lvl = *level;
2775 state.format = 0;
2776 *level = -1;
2777 if !d.notations.is_null() {
2778 crate::xml::hash::hash_scan(
2779 d.notations as *mut crate::xml::hash::HashTable,
2780 Some(dump_notation_decl_cb),
2781 buf as *mut c_void,
2782 );
2783 }
2784 if !d.elements.is_null() {
2785 crate::xml::hash::hash_scan(
2786 d.elements as *mut crate::xml::hash::HashTable,
2787 Some(dump_element_decl_cb),
2788 buf as *mut c_void,
2789 );
2790 }
2791 if !d.attributes.is_null() {
2792 crate::xml::hash::hash_scan(
2793 d.attributes as *mut crate::xml::hash::HashTable,
2794 Some(dump_attribute_decl_cb),
2795 buf as *mut c_void,
2796 );
2797 }
2798 if !d.entities.is_null() {
2799 crate::xml::hash::hash_scan(
2800 d.entities as *mut crate::xml::hash::HashTable,
2801 Some(dump_entity_decl_cb),
2802 buf as *mut c_void,
2803 );
2804 }
2805 if !d.pentities.is_null() {
2806 crate::xml::hash::hash_scan(
2807 d.pentities as *mut crate::xml::hash::HashTable,
2808 Some(dump_entity_decl_cb),
2809 buf as *mut c_void,
2810 );
2811 }
2812 state.format = format;
2813 *level = lvl;
2814 io::buf_add(buf, b"]>" as *const u8, 2);
2815}
2816
2817unsafe extern "C" fn dump_notation_decl_cb(
2819 payload: *mut c_void,
2820 data: *mut c_void,
2821 _name: *const crate::abi::types::xmlChar,
2822) {
2823 if !payload.is_null() && !data.is_null() {
2824 dump_notation_decl(data as *mut _xmlBuffer, payload as *mut _xmlNotation);
2825 }
2826}
2827
2828unsafe extern "C" fn dump_element_decl_cb(
2830 payload: *mut c_void,
2831 data: *mut c_void,
2832 _name: *const crate::abi::types::xmlChar,
2833) {
2834 if !payload.is_null() && !data.is_null() {
2835 dump_element_decl(data as *mut _xmlBuffer, payload as *mut _xmlElement);
2836 }
2837}
2838
2839unsafe extern "C" fn dump_attribute_decl_cb(
2841 payload: *mut c_void,
2842 data: *mut c_void,
2843 _name: *const crate::abi::types::xmlChar,
2844) {
2845 if !payload.is_null() && !data.is_null() {
2846 dump_attribute_decl(data as *mut _xmlBuffer, payload as *mut _xmlAttribute);
2847 }
2848}
2849
2850unsafe extern "C" fn dump_entity_decl_cb(
2852 payload: *mut c_void,
2853 data: *mut c_void,
2854 _name: *const crate::abi::types::xmlChar,
2855) {
2856 if !payload.is_null() && !data.is_null() {
2857 dump_entity_decl(data as *mut _xmlBuffer, payload as *mut _xmlEntity);
2858 }
2859}
2860
2861unsafe fn doc_content_dump_output(
2870 buf: *mut _xmlBuffer,
2871 cur: *mut _xmlNode,
2872 state: &mut DumpState,
2873 level: &mut c_int,
2874) {
2875 let doc = cur as *mut _xmlDoc;
2876 let d = unsafe { &*doc };
2877
2878 io::buf_add(buf, b"<?xml version=\"" as *const u8, 15);
2881 if !d.version.is_null() {
2882 io::buf_cat(buf, d.version);
2883 } else {
2884 io::buf_add(buf, b"1.0" as *const u8, 3);
2885 }
2886 io::buf_ccat(buf, b'"');
2887 if !d.encoding.is_null() {
2888 io::buf_add(buf, b" encoding=\"" as *const u8, 11);
2889 io::buf_cat(buf, d.encoding);
2890 io::buf_ccat(buf, b'"');
2891 }
2892 match d.standalone {
2893 0 => {
2894 io::buf_add(buf, b" standalone=\"no\"" as *const u8, 16);
2895 }
2896 1 => {
2897 io::buf_add(buf, b" standalone=\"yes\"" as *const u8, 17);
2898 }
2899 _ => {}
2900 }
2901 io::buf_add(buf, b"?>\n" as *const u8, 3);
2902
2903 if !d.intSubset.is_null() {
2906 let mut lvl = 0;
2907 dtd_dump_output(buf, d.intSubset as *mut _xmlNode, state, &mut lvl);
2908 io::buf_ccat(buf, b'\n');
2909 }
2910
2911 if !d.children.is_null() {
2912 let mut child = d.children;
2913 while !child.is_null() {
2914 *level = 0;
2915 node_dump_internal(buf, child, child, cur, state, level);
2916 let ct = unsafe { (*child).type_ };
2917 if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
2918 io::buf_ccat(buf, b'\n');
2919 }
2920 child = unsafe { (*child).next };
2921 }
2922 }
2923}
2924
2925unsafe fn node_dump_internal(
2949 buf: *mut _xmlBuffer,
2950 cur: *mut _xmlNode,
2951 root: *mut _xmlNode,
2952 parent: *mut _xmlNode,
2953 state: &mut DumpState,
2954 level: &mut c_int,
2955) {
2956 if cur.is_null() || buf.is_null() {
2957 return;
2958 }
2959 let n = unsafe { &*cur };
2960 match n.type_ {
2961 t if t == XML_ELEMENT_NODE as c_int => {
2962 if cur != root && state.format == 1 {
2963 write_indent(buf, *level);
2964 }
2965 if !n.parent.is_null() && n.parent != parent && !n.children.is_null() {
2968 let mut sub = DumpState::new(state.format);
2969 let mut sub_level = *level;
2970 node_dump_internal(buf, cur, cur, n.parent, &mut sub, &mut sub_level);
2971 return;
2972 }
2973 io::buf_ccat(buf, b'<');
2975 write_qname(buf, cur);
2976 let mut nsdef = n.nsDef;
2977 while !nsdef.is_null() {
2978 ns_dump_output(buf, nsdef);
2979 nsdef = unsafe { (*nsdef).next };
2980 }
2981 let mut attr = n.properties;
2982 while !attr.is_null() {
2983 attr_dump_output(buf, attr);
2984 attr = unsafe { (*attr).next };
2985 }
2986 if n.children.is_null() {
2987 io::buf_add(buf, b"/>" as *const u8, 2);
2988 } else {
2989 if state.format == 1 {
2990 let mut tmp = n.children;
2993 while !tmp.is_null() {
2994 let tt = unsafe { (*tmp).type_ };
2995 if tt == XML_TEXT_NODE as c_int
2996 || tt == XML_CDATA_SECTION_NODE as c_int
2997 || tt == XML_ENTITY_REF_NODE as c_int
2998 {
2999 state.format = 0;
3000 state.unformatted = cur;
3001 break;
3002 }
3003 tmp = unsafe { (*tmp).next };
3004 }
3005 }
3006 io::buf_ccat(buf, b'>');
3007 if state.format == 1 {
3008 io::buf_ccat(buf, b'\n');
3009 }
3010 if *level >= 0 {
3011 *level += 1;
3012 }
3013 let mut child = n.children;
3014 while !child.is_null() {
3015 node_dump_internal(buf, child, root, cur, state, level);
3016 if state.format == 1 {
3017 let ct = unsafe { (*child).type_ };
3018 if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
3019 io::buf_ccat(buf, b'\n');
3020 }
3021 }
3022 child = unsafe { (*child).next };
3023 }
3024 if *level > 0 {
3026 *level -= 1;
3027 }
3028 if state.format == 1 {
3029 write_indent(buf, *level);
3030 }
3031 io::buf_add(buf, b"</" as *const u8, 2);
3032 write_qname(buf, cur);
3033 io::buf_ccat(buf, b'>');
3034 if cur == state.unformatted {
3035 state.format = state.saved;
3036 state.unformatted = ptr::null_mut();
3037 }
3038 }
3039 }
3040 t if t == XML_TEXT_NODE as c_int => {
3041 if !n.content.is_null() {
3042 if is_noenc_text(cur) {
3043 io::buf_cat(buf, n.content);
3044 } else {
3045 serialize_text(buf, n.content, xml_strlen(n.content));
3046 }
3047 } else if !n.children.is_null() {
3048 let c = node_get_content(cur);
3051 if !c.is_null() {
3052 if is_noenc_text(cur) {
3053 io::buf_cat(buf, c);
3054 } else {
3055 serialize_text(buf, c, xml_strlen(c));
3056 }
3057 allocator::xmlFree(c as *mut c_void);
3058 }
3059 }
3060 }
3061 t if t == XML_CDATA_SECTION_NODE as c_int => {
3062 if n.content.is_null() || unsafe { *n.content == 0 } {
3063 io::buf_add(buf, b"<![CDATA[]]>" as *const u8, 12);
3064 } else {
3065 let len = xml_strlen(n.content) as usize;
3066 let bytes = core::slice::from_raw_parts(n.content, len);
3067 let mut i = 0usize;
3068 let mut seg_start = 0usize;
3069 while i < len {
3070 if bytes[i] == b']'
3071 && i + 2 < len
3072 && bytes[i + 1] == b']'
3073 && bytes[i + 2] == b'>'
3074 {
3075 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
3076 io::buf_add(buf, n.content.add(seg_start), (i + 2 - seg_start) as c_int);
3077 io::buf_add(buf, b"]]>" as *const u8, 3);
3078 seg_start = i + 2;
3079 i += 3;
3080 continue;
3081 }
3082 i += 1;
3083 }
3084 if seg_start < len {
3085 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
3086 io::buf_add(buf, n.content.add(seg_start), (len - seg_start) as c_int);
3087 io::buf_add(buf, b"]]>" as *const u8, 3);
3088 }
3089 }
3090 }
3091 t if t == XML_COMMENT_NODE as c_int => {
3092 if cur != root && state.format == 1 {
3093 write_indent(buf, *level);
3094 }
3095 if !n.content.is_null() {
3096 io::buf_add(buf, b"<!--" as *const u8, 4);
3097 io::buf_cat(buf, n.content);
3098 io::buf_add(buf, b"-->" as *const u8, 3);
3099 }
3100 }
3101 t if t == XML_PI_NODE as c_int => {
3102 if cur != root && state.format == 1 {
3103 write_indent(buf, *level);
3104 }
3105 io::buf_add(buf, b"<?" as *const u8, 2);
3106 if !n.name.is_null() {
3107 io::buf_cat(buf, n.name);
3108 }
3109 if !n.content.is_null() && unsafe { *n.content != 0 } {
3110 io::buf_ccat(buf, b' ');
3111 io::buf_cat(buf, n.content);
3112 }
3113 io::buf_add(buf, b"?>" as *const u8, 2);
3114 }
3115 t if t == XML_ENTITY_REF_NODE as c_int => {
3116 io::buf_ccat(buf, b'&');
3117 if !n.name.is_null() {
3118 io::buf_cat(buf, n.name);
3119 }
3120 io::buf_ccat(buf, b';');
3121 }
3122 t if t == XML_DOCUMENT_NODE as c_int => {
3123 doc_content_dump_output(buf, cur, state, level);
3124 }
3125 t if t == XML_HTML_DOCUMENT_NODE as c_int => {
3126 crate::xml::html::serialize_node(cur, buf, state.format, *level);
3128 }
3129 t if t == XML_DTD_NODE as c_int => {
3130 dtd_dump_output(buf, cur, state, level);
3131 }
3132 t if t == XML_ATTRIBUTE_NODE as c_int => {
3133 attr_dump_output(buf, cur as *mut _xmlAttr);
3134 }
3135 t if t == XML_NAMESPACE_DECL as c_int => {
3136 ns_dump_output(buf, cur as *mut _xmlNs);
3137 }
3138 t if t == XML_ELEMENT_DECL as c_int => {
3139 dump_element_decl(buf, cur as *mut _xmlElement);
3140 }
3141 t if t == XML_ATTRIBUTE_DECL as c_int => {
3142 dump_attribute_decl(buf, cur as *mut _xmlAttribute);
3143 }
3144 t if t == XML_ENTITY_DECL as c_int => {
3145 dump_entity_decl(buf, cur as *mut _xmlEntity);
3146 }
3147 _ => {}
3148 }
3149}
3150
3151pub(crate) unsafe fn serialize_node(
3165 node: *mut _xmlNode,
3166 buf: *mut _xmlBuffer,
3167 format: c_int,
3168 level: c_int,
3169) {
3170 if node.is_null() || buf.is_null() {
3171 return;
3172 }
3173 let parent = unsafe { (*node).parent };
3174 let mut state = DumpState::new(format);
3175 let mut lvl = level;
3176 node_dump_internal(buf, node, node, parent, &mut state, &mut lvl);
3177}
3178
3179pub(crate) unsafe fn doc_dump(buf: *mut _xmlBuffer, doc: *mut _xmlDoc) -> c_int {
3189 if buf.is_null() || doc.is_null() {
3190 return -1;
3191 }
3192
3193 let before = io::buf_length(buf);
3194 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
3195 let after = io::buf_length(buf);
3196
3197 if after < 0 || before < 0 {
3198 return -1;
3199 }
3200 after - before
3201}
3202
3203pub(crate) unsafe fn node_dump(
3215 buf: *mut _xmlBuffer,
3216 doc: *mut _xmlDoc,
3217 node: *mut _xmlNode,
3218 level: c_int,
3219 format: c_int,
3220) -> c_int {
3221 let _ = doc; if buf.is_null() || node.is_null() {
3223 return -1;
3224 }
3225
3226 let before = io::buf_length(buf);
3227 serialize_node(node, buf, format, level);
3228 let after = io::buf_length(buf);
3229
3230 if after < 0 || before < 0 {
3231 return -1;
3232 }
3233 after - before
3234}
3235
3236pub(crate) unsafe fn save_doc_to_filename(
3243 doc: *mut _xmlDoc,
3244 filename: *const c_char,
3245 compression: c_int,
3246) -> c_int {
3247 if doc.is_null() || filename.is_null() {
3248 return -1;
3249 }
3250
3251 let out = io::output_buffer_create_filename(filename, ptr::null_mut(), compression);
3252 if out.is_null() {
3253 return -1;
3254 }
3255
3256 let buf = io::buf_create(-1);
3257 if buf.is_null() {
3258 io::output_buffer_close(out);
3259 return -1;
3260 }
3261
3262 let ret = doc_dump(buf, doc);
3263 if ret >= 0 {
3264 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
3266 io::output_buffer_flush(out);
3267 }
3268
3269 io::buf_free(buf);
3270 io::output_buffer_close(out);
3271 ret
3272}
3273
3274pub(crate) unsafe fn save_doc_to_fd(doc: *mut _xmlDoc, fd: c_int, compression: c_int) -> c_int {
3281 if doc.is_null() || fd < 0 {
3282 return -1;
3283 }
3284
3285 let out = io::output_buffer_create_fd(fd, ptr::null_mut());
3286 if out.is_null() {
3287 return -1;
3288 }
3289
3290 let buf = io::buf_create(-1);
3291 if buf.is_null() {
3292 io::output_buffer_close(out);
3293 return -1;
3294 }
3295
3296 let ret = doc_dump(buf, doc);
3297 if ret >= 0 {
3298 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
3299 io::output_buffer_flush(out);
3300 }
3301
3302 io::buf_free(buf);
3303 io::output_buffer_close(out);
3304 ret
3305}
3306
3307pub(crate) unsafe fn save_doc_to_buf(
3314 doc: *mut _xmlDoc,
3315 buf: *mut _xmlBuffer,
3316 compression: c_int,
3317) -> c_int {
3318 let _ = compression;
3319 if doc.is_null() || buf.is_null() {
3320 return -1;
3321 }
3322
3323 doc_dump(buf, doc)
3324}
3325
3326pub(crate) unsafe fn save_format_doc_to_buf(
3333 doc: *mut _xmlDoc,
3334 buf: *mut _xmlBuffer,
3335 compression: c_int,
3336) -> c_int {
3337 let _ = compression;
3338 if doc.is_null() || buf.is_null() {
3339 return -1;
3340 }
3341
3342 let before = io::buf_length(buf);
3343 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
3344 let after = io::buf_length(buf);
3345
3346 if after < 0 || before < 0 {
3347 return -1;
3348 }
3349 after - before
3350}
3351
3352pub(crate) unsafe fn dump_node(node: *mut _xmlNode) -> *mut xmlChar {
3361 if node.is_null() {
3362 return ptr::null_mut();
3363 }
3364
3365 let buf = io::buf_create(-1);
3366 if buf.is_null() {
3367 return ptr::null_mut();
3368 }
3369
3370 serialize_node(node, buf, 0, 0);
3371
3372 let content = io::buf_content(buf);
3373 if content.is_null() {
3374 io::buf_free(buf);
3375 return ptr::null_mut();
3376 }
3377
3378 let result = dup_xml_str(content);
3380 io::buf_free(buf);
3381 result
3382}
3383
3384pub unsafe fn dump_doc(doc: *mut _xmlDoc) -> *mut xmlChar {
3393 if doc.is_null() {
3394 return ptr::null_mut();
3395 }
3396
3397 let buf = io::buf_create(-1);
3398 if buf.is_null() {
3399 return ptr::null_mut();
3400 }
3401
3402 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
3403
3404 let content = io::buf_content(buf);
3405 if content.is_null() {
3406 io::buf_free(buf);
3407 return ptr::null_mut();
3408 }
3409
3410 let result = dup_xml_str(content);
3411 io::buf_free(buf);
3412 result
3413}
3414
3415pub(crate) unsafe fn xmlNodeDump(
3431 buf: *mut _xmlBuffer,
3432 doc: *mut _xmlDoc,
3433 node: *mut _xmlNode,
3434 level: c_int,
3435 format: c_int,
3436) -> c_int {
3437 node_dump(buf, doc, node, level, format)
3438}
3439
3440pub(crate) unsafe fn xmlDocDump(fp: *mut c_void, doc: *mut _xmlDoc) -> c_int {
3453 if fp.is_null() || doc.is_null() {
3454 return -1;
3455 }
3456
3457 let buf = io::buf_create(-1);
3458 if buf.is_null() {
3459 return -1;
3460 }
3461
3462 let ret = doc_dump(buf, doc);
3463 if ret < 0 {
3464 io::buf_free(buf);
3465 return -1;
3466 }
3467
3468 let content = io::buf_content(buf);
3469 let len = io::buf_length(buf);
3470 if !content.is_null() && len > 0 {
3471 let written = libc::fwrite(
3472 content as *const c_void,
3473 1,
3474 len as usize,
3475 fp as *mut libc::FILE,
3476 );
3477 io::buf_free(buf);
3478 written as c_int
3479 } else {
3480 io::buf_free(buf);
3481 0
3482 }
3483}
3484
3485pub(crate) unsafe fn xmlDocDumpFormatMemory(
3499 doc: *mut _xmlDoc,
3500 mem: *mut *mut xmlChar,
3501 size: *mut c_int,
3502 format: c_int,
3503) {
3504 if doc.is_null() || mem.is_null() || size.is_null() {
3505 return;
3506 }
3507
3508 let buf = io::buf_create(-1);
3509 if buf.is_null() {
3510 unsafe {
3511 *mem = ptr::null_mut();
3512 *size = 0;
3513 }
3514 return;
3515 }
3516
3517 serialize_node(doc as *mut _xmlNode, buf, format, 0);
3518
3519 let content = io::buf_content(buf);
3520 let len = io::buf_length(buf);
3521
3522 if !content.is_null() && len > 0 {
3523 let result = allocator::xmlMalloc((len + 1) as usize) as *mut xmlChar;
3525 if !result.is_null() {
3526 ptr::copy_nonoverlapping(content, result, len as usize);
3527 *result.add(len as usize) = 0;
3528 unsafe {
3529 *mem = result;
3530 *size = len;
3531 }
3532 } else {
3533 unsafe {
3534 *mem = ptr::null_mut();
3535 *size = 0;
3536 }
3537 }
3538 } else {
3539 unsafe {
3540 *mem = ptr::null_mut();
3541 *size = 0;
3542 }
3543 }
3544
3545 io::buf_free(buf);
3546}
3547
3548pub(crate) unsafe fn xmlDocDumpMemory(doc: *mut _xmlDoc, mem: *mut *mut xmlChar, size: *mut c_int) {
3562 xmlDocDumpFormatMemory(doc, mem, size, 0)
3563}
3564
3565pub(crate) unsafe fn xmlSaveFile(filename: *const c_char, cur: *mut _xmlDoc) -> c_int {
3578 save_doc_to_filename(cur, filename, 0)
3579}
3580
3581pub(crate) unsafe fn xmlSaveFileEnc(
3595 filename: *const c_char,
3596 cur: *mut _xmlDoc,
3597 encoding: *const c_char,
3598) -> c_int {
3599 let _ = encoding; save_doc_to_filename(cur, filename, 0)
3601}
3602
3603pub(crate) unsafe fn xmlSaveFormatFile(
3616 filename: *const c_char,
3617 cur: *mut _xmlDoc,
3618 format: c_int,
3619) -> c_int {
3620 let _ = format;
3621 save_doc_to_filename(cur, filename, 0)
3622}
3623
3624pub(crate) unsafe fn xmlSaveFormatFileEnc(
3638 filename: *const c_char,
3639 cur: *mut _xmlDoc,
3640 encoding: *const c_char,
3641 format: c_int,
3642) -> c_int {
3643 let _ = encoding;
3644 let _ = format;
3645 save_doc_to_filename(cur, filename, 0)
3646}
3647
3648pub(crate) unsafe fn xmlGetDocCompressMode(doc: *mut _xmlDoc) -> c_int {
3660 if doc.is_null() {
3661 return -1;
3662 }
3663 unsafe { (*doc).compression }
3664}
3665
3666pub(crate) unsafe fn xmlSetDocCompressMode(doc: *mut _xmlDoc, mode: c_int) {
3678 if doc.is_null() {
3679 return;
3680 }
3681 unsafe {
3682 (*doc).compression = mode;
3683 }
3684}
3685
3686#[cfg(test)]
3687mod tests {
3688 use super::*;
3689 use core::ffi::c_void;
3690
3691 fn c_str(s: &str) -> *const xmlChar {
3692 let bytes = s.as_bytes();
3693 let buf = unsafe { allocator::xmlMalloc(bytes.len() + 1) as *mut u8 };
3694 if !buf.is_null() {
3695 unsafe {
3696 ptr::copy_nonoverlapping(bytes.as_ptr(), buf, bytes.len());
3697 *buf.add(bytes.len()) = 0;
3698 }
3699 }
3700 buf as *const xmlChar
3701 }
3702
3703 #[test]
3704 fn test_new_free_doc() {
3705 unsafe {
3706 let doc = new_doc(ptr::null());
3707 assert!(!doc.is_null());
3708 assert_eq!((*doc).type_, XML_DOCUMENT_NODE as c_int);
3709 assert_eq!((*doc).standalone, -1);
3710 assert_eq!((*doc).doc, doc);
3711 assert!(!(*doc).version.is_null());
3712 free_doc(doc);
3713 }
3714 }
3715
3716 #[test]
3717 fn test_new_doc_with_version() {
3718 unsafe {
3719 let ver = c_str("2.0");
3720 let doc = new_doc(ver);
3721 assert!(!doc.is_null());
3722 let doc_ver = (*doc).version;
3723 assert!(!doc_ver.is_null());
3724 assert!(crate::abi::exports_xml2::xmlStrEqual(doc_ver, ver,) != 0);
3725 allocator::xmlFree(ver as *mut c_void);
3726 free_doc(doc);
3727 }
3728 }
3729
3730 #[test]
3731 fn test_new_node() {
3732 unsafe {
3733 let doc = new_doc(ptr::null());
3734 let node = new_node(ptr::null_mut(), c_str("root"));
3735 assert!(!node.is_null());
3736 assert_eq!((*node).type_, XML_ELEMENT_NODE as c_int);
3737 assert!(!(*node).name.is_null());
3738 free_node(node);
3739 free_doc(doc);
3740 }
3741 }
3742
3743 #[test]
3744 fn test_node_get_content_recurses_descendants() {
3745 unsafe {
3750 let doc = new_doc(ptr::null());
3751 let root = new_node(ptr::null_mut(), c_str("library"));
3752 doc_set_root_element(doc, root);
3753 let book = new_child(root, ptr::null_mut(), c_str("book"));
3754 let title = new_child(book, ptr::null_mut(), c_str("title"));
3755 let text = new_text(c_str("Rust"));
3756 add_child(title, text);
3757
3758 let content = node_get_content(book);
3759 assert!(!content.is_null());
3760 let s = core::slice::from_raw_parts(
3761 content,
3762 libc::strlen(content as *const libc::c_char) as usize,
3763 );
3764 assert_eq!(s, b"Rust", "descendant text not concatenated");
3765 allocator::xmlFree(content as *mut c_void);
3766
3767 free_doc(doc);
3768 }
3769 }
3770
3771 #[test]
3772 fn test_doc_set_root_element() {
3773 unsafe {
3774 let doc = new_doc(ptr::null());
3775 let root = new_node(ptr::null_mut(), c_str("root"));
3776 let old = doc_set_root_element(doc, root);
3777 assert!(old.is_null());
3778 assert_eq!(doc_get_root_element(doc), root);
3779 assert_eq!((*doc).children, root as *mut _xmlNode);
3780 free_doc(doc);
3781 }
3782 }
3783
3784 #[test]
3785 fn test_add_child_and_sibling() {
3786 unsafe {
3787 let doc = new_doc(ptr::null());
3788 let root = new_node(ptr::null_mut(), c_str("root"));
3789 doc_set_root_element(doc, root);
3790
3791 let child1 = new_child(root, ptr::null_mut(), c_str("child1"));
3792 assert!(!child1.is_null());
3793 assert_eq!((*child1).parent, root);
3794 assert_eq!((*root).children, child1);
3795 assert_eq!((*root).last, child1);
3796
3797 let child2 = new_child(root, ptr::null_mut(), c_str("child2"));
3798 assert!(!child2.is_null());
3799 assert_eq!((*child2).parent, root);
3800 assert_eq!((*child1).next, child2);
3801 assert_eq!((*child2).prev, child1);
3802 assert_eq!((*root).last, child2);
3803
3804 let sibling = new_node(ptr::null_mut(), c_str("sibling"));
3806 add_sibling(child2, sibling);
3807 assert_eq!((*child2).next, sibling);
3808 assert_eq!((*sibling).prev, child2);
3809 assert_eq!((*root).last, sibling);
3810
3811 free_doc(doc);
3812 }
3813 }
3814
3815 #[test]
3816 fn test_unlink_node() {
3817 unsafe {
3818 let doc = new_doc(ptr::null());
3819 let root = new_node(ptr::null_mut(), c_str("root"));
3820 doc_set_root_element(doc, root);
3821
3822 let child1 = new_child(root, ptr::null_mut(), c_str("c1"));
3823 let child2 = new_child(root, ptr::null_mut(), c_str("c2"));
3824
3825 unlink_node(child1);
3826 assert!((*child1).parent.is_null());
3827 assert!((*child1).prev.is_null());
3828 assert!((*child1).next.is_null());
3829 assert_eq!((*root).children, child2);
3830 assert_eq!((*root).last, child2);
3831
3832 free_node(child1);
3833 free_doc(doc);
3834 }
3835 }
3836
3837 #[test]
3838 fn test_text_and_comment_nodes() {
3839 unsafe {
3840 let text = new_text(c_str("hello world"));
3841 assert!(!text.is_null());
3842 assert_eq!((*text).type_, XML_TEXT_NODE as c_int);
3843 assert!(!(*text).content.is_null());
3844 free_node(text);
3845
3846 let comment = new_comment(c_str("my comment"));
3847 assert!(!comment.is_null());
3848 assert_eq!((*comment).type_, XML_COMMENT_NODE as c_int);
3849 free_node(comment);
3850
3851 let pi = new_pi(c_str("xml"), c_str("version='1.0'"));
3852 assert!(!pi.is_null());
3853 assert_eq!((*pi).type_, XML_PI_NODE as c_int);
3854 free_node(pi);
3855 }
3856 }
3857
3858 #[test]
3859 fn test_set_and_get_prop() {
3860 unsafe {
3861 let doc = new_doc(ptr::null());
3862 let root = new_node(ptr::null_mut(), c_str("root"));
3863 doc_set_root_element(doc, root);
3864
3865 let attr = set_prop(root, c_str("id"), c_str("42"));
3866 assert!(!attr.is_null());
3867 assert_eq!((*attr).type_, XML_ATTRIBUTE_NODE as c_int);
3868
3869 let value = get_prop(root, c_str("id"));
3870 assert!(!value.is_null());
3871 assert!(crate::abi::exports_xml2::xmlStrEqual(value, c_str("42")) != 0);
3872 allocator::xmlFree(value as *mut c_void);
3873
3874 free_doc(doc);
3875 }
3876 }
3877
3878 #[test]
3879 fn test_remove_prop() {
3880 unsafe {
3881 let doc = new_doc(ptr::null());
3882 let root = new_node(ptr::null_mut(), c_str("root"));
3883 doc_set_root_element(doc, root);
3884
3885 set_prop(root, c_str("a"), c_str("1"));
3886 set_prop(root, c_str("b"), c_str("2"));
3887
3888 let value = get_prop(root, c_str("a"));
3889 assert!(!value.is_null());
3890 allocator::xmlFree(value as *mut c_void);
3891
3892 let attr = (*root).properties;
3894 assert!(!attr.is_null());
3895 let result = remove_prop(attr);
3896 assert_eq!(result, 0);
3897
3898 let value2 = get_prop(root, c_str("a"));
3900 assert!(value2.is_null());
3901
3902 free_doc(doc);
3903 }
3904 }
3905
3906 #[test]
3907 fn test_namespace_operations() {
3908 unsafe {
3909 let doc = new_doc(ptr::null());
3910 let root = new_node(ptr::null_mut(), c_str("root"));
3911 doc_set_root_element(doc, root);
3912
3913 let ns = new_ns(root, c_str("http://example.com"), c_str("ex"));
3914 assert!(!ns.is_null());
3915 assert!(!(*root).nsDef.is_null());
3916
3917 set_ns(root, ns);
3918 assert_eq!((*root).ns, ns);
3919
3920 let found = search_ns(doc, root, c_str("ex"));
3921 assert_eq!(found, ns);
3922
3923 let found_href = search_ns_by_href(doc, root, c_str("http://example.com"));
3924 assert_eq!(found_href, ns);
3925
3926 free_doc(doc);
3927 }
3928 }
3929
3930 #[test]
3931 fn test_new_dtd() {
3932 unsafe {
3933 let doc = new_doc(ptr::null());
3934 let dtd = new_dtd(doc, c_str("root"), c_str("-//TEST//DTD"), c_str("test.dtd"));
3935 assert!(!dtd.is_null());
3936 assert_eq!((*dtd).type_, XML_DTD_NODE as c_int);
3937 assert_eq!(get_int_subset(doc), dtd);
3938 free_doc(doc);
3939 }
3940 }
3941
3942 #[test]
3943 fn test_copy_node_deep() {
3944 unsafe {
3945 let doc = new_doc(ptr::null());
3946 let root = new_node(ptr::null_mut(), c_str("root"));
3947 doc_set_root_element(doc, root);
3948 let child = new_child(root, ptr::null_mut(), c_str("child"));
3949
3950 let copy = copy_node(root, 1);
3951 assert!(!copy.is_null());
3952 assert_eq!((*copy).type_, XML_ELEMENT_NODE as c_int);
3953 assert!(!(*copy).children.is_null());
3955 assert_eq!((*(*copy).children).type_, XML_ELEMENT_NODE as c_int);
3956
3957 free_node(copy);
3958 free_doc(doc);
3959 }
3960 }
3961
3962 #[test]
3963 fn test_new_cdata_block() {
3964 unsafe {
3965 let doc = new_doc(ptr::null());
3966 let content = c_str("some <cdata> content");
3967 let cdata = new_cdata_block(doc, content, 20);
3968 assert!(!cdata.is_null());
3969 assert_eq!((*cdata).type_, XML_CDATA_SECTION_NODE as c_int);
3970 free_node(cdata);
3971 free_doc(doc);
3972 }
3973 }
3974
3975 #[test]
3976 fn test_null_handling() {
3977 unsafe {
3978 assert!(new_doc(ptr::null()).is_null() == false); let doc = new_doc(ptr::null());
3980 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());
3985 assert!(add_sibling(ptr::null_mut(), ptr::null_mut()).is_null());
3986 free_doc(doc);
3987 }
3988 }
3989
3990 unsafe fn buf_eq_str(buf: *mut _xmlBuffer, expected: &str) -> bool {
3996 let content = io::buf_content(buf);
3997 if content.is_null() {
3998 return expected.is_empty();
3999 }
4000 let len = io::buf_length(buf) as usize;
4001 if len != expected.len() {
4002 return false;
4003 }
4004 let slice = unsafe { core::slice::from_raw_parts(content, len) };
4005 slice == expected.as_bytes()
4006 }
4007
4008 #[test]
4009 fn test_serialize_empty_document() {
4010 unsafe {
4011 let doc = new_doc(ptr::null());
4012 let buf = io::buf_create(-1);
4013 assert!(!buf.is_null());
4014
4015 let ret = doc_dump(buf, doc);
4016 assert!(ret >= 0);
4017
4018 let expected = "<?xml version=\"1.0\"?>\n";
4022 assert!(buf_eq_str(buf, expected));
4023
4024 io::buf_free(buf);
4025 free_doc(doc);
4026 }
4027 }
4028
4029 #[test]
4030 fn test_serialize_element_with_text() {
4031 unsafe {
4032 let doc = new_doc(ptr::null());
4033 let root = new_node(ptr::null_mut(), c_str("root"));
4034 doc_set_root_element(doc, root);
4035
4036 let text = new_text(c_str("hello world"));
4038 add_child(root, text);
4039
4040 let buf = io::buf_create(-1);
4041 assert!(!buf.is_null());
4042
4043 let ret = doc_dump(buf, doc);
4044 assert!(ret >= 0);
4045
4046 let expected = "<?xml version=\"1.0\"?>\n<root>hello world</root>\n";
4047 assert!(buf_eq_str(buf, expected));
4048
4049 io::buf_free(buf);
4050 free_doc(doc);
4051 }
4052 }
4053
4054 #[test]
4055 fn test_serialize_element_with_attributes() {
4056 unsafe {
4057 let doc = new_doc(ptr::null());
4058 let root = new_node(ptr::null_mut(), c_str("root"));
4059 doc_set_root_element(doc, root);
4060
4061 set_prop(root, c_str("id"), c_str("42"));
4062 set_prop(root, c_str("name"), c_str("test"));
4063
4064 let buf = io::buf_create(-1);
4065 assert!(!buf.is_null());
4066
4067 let ret = doc_dump(buf, doc);
4068 assert!(ret >= 0);
4069
4070 let expected = "<?xml version=\"1.0\"?>\n<root id=\"42\" name=\"test\"/>\n";
4071 assert!(buf_eq_str(buf, expected));
4072
4073 io::buf_free(buf);
4074 free_doc(doc);
4075 }
4076 }
4077
4078 #[test]
4079 fn test_serialize_nested_elements() {
4080 unsafe {
4081 let doc = new_doc(ptr::null());
4082 let root = new_node(ptr::null_mut(), c_str("root"));
4083 doc_set_root_element(doc, root);
4084
4085 let child = new_child(root, ptr::null_mut(), c_str("child"));
4086 let grandchild = new_child(child, ptr::null_mut(), c_str("gc"));
4087 let text = new_text(c_str("text"));
4088 add_child(grandchild, text);
4089
4090 let buf = io::buf_create(-1);
4091 assert!(!buf.is_null());
4092
4093 let ret = doc_dump(buf, doc);
4094 assert!(ret >= 0);
4095
4096 let expected = "<?xml version=\"1.0\"?>\n<root><child><gc>text</gc></child></root>\n";
4097 assert!(buf_eq_str(buf, expected));
4098
4099 io::buf_free(buf);
4100 free_doc(doc);
4101 }
4102 }
4103
4104 #[test]
4105 fn test_serialize_with_formatting() {
4106 unsafe {
4107 let doc = new_doc(ptr::null());
4108 let root = new_node(ptr::null_mut(), c_str("root"));
4109 doc_set_root_element(doc, root);
4110
4111 let child = new_child(root, ptr::null_mut(), c_str("child"));
4112 let text = new_text(c_str("text"));
4113 add_child(child, text);
4114
4115 let buf = io::buf_create(-1);
4116 assert!(!buf.is_null());
4117
4118 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
4119
4120 let expected = "<?xml version=\"1.0\"?>\n<root>\n <child>text</child>\n</root>\n";
4121 assert!(buf_eq_str(buf, expected));
4122
4123 io::buf_free(buf);
4124 free_doc(doc);
4125 }
4126 }
4127
4128 #[test]
4129 fn test_serialize_escape_ampersand() {
4130 unsafe {
4131 let doc = new_doc(ptr::null());
4132 let root = new_node(ptr::null_mut(), c_str("root"));
4133 doc_set_root_element(doc, root);
4134
4135 let text = new_text(c_str("a & b"));
4136 add_child(root, text);
4137
4138 let buf = io::buf_create(-1);
4139 assert!(!buf.is_null());
4140
4141 let ret = doc_dump(buf, doc);
4142 assert!(ret >= 0);
4143
4144 let expected = "<?xml version=\"1.0\"?>\n<root>a & b</root>\n";
4145 assert!(buf_eq_str(buf, expected));
4146
4147 io::buf_free(buf);
4148 free_doc(doc);
4149 }
4150 }
4151
4152 #[test]
4153 fn test_serialize_escape_angle_brackets() {
4154 unsafe {
4155 let doc = new_doc(ptr::null());
4156 let root = new_node(ptr::null_mut(), c_str("root"));
4157 doc_set_root_element(doc, root);
4158
4159 let text = new_text(c_str("x < y > z"));
4160 add_child(root, text);
4161
4162 let buf = io::buf_create(-1);
4163 assert!(!buf.is_null());
4164
4165 let ret = doc_dump(buf, doc);
4166 assert!(ret >= 0);
4167
4168 let expected = "<?xml version=\"1.0\"?>\n<root>x < y > z</root>\n";
4169 assert!(buf_eq_str(buf, expected));
4170
4171 io::buf_free(buf);
4172 free_doc(doc);
4173 }
4174 }
4175
4176 #[test]
4177 fn test_serialize_comment() {
4178 unsafe {
4179 let doc = new_doc(ptr::null());
4180 let root = new_node(ptr::null_mut(), c_str("root"));
4181 doc_set_root_element(doc, root);
4182
4183 let comment = new_comment(c_str("my comment"));
4184 add_child(root, comment);
4185
4186 let buf = io::buf_create(-1);
4187 assert!(!buf.is_null());
4188
4189 let ret = doc_dump(buf, doc);
4190 assert!(ret >= 0);
4191
4192 let expected = "<?xml version=\"1.0\"?>\n<root><!--my comment--></root>\n";
4193 assert!(buf_eq_str(buf, expected));
4194
4195 io::buf_free(buf);
4196 free_doc(doc);
4197 }
4198 }
4199
4200 #[test]
4201 fn test_serialize_pi() {
4202 unsafe {
4203 let doc = new_doc(ptr::null());
4204 let root = new_node(ptr::null_mut(), c_str("root"));
4205 doc_set_root_element(doc, root);
4206
4207 let pi = new_pi(
4208 c_str("xml-stylesheet"),
4209 c_str("href=\"style.xsl\" type=\"text/xsl\""),
4210 );
4211 add_child(root, pi);
4212
4213 let buf = io::buf_create(-1);
4214 assert!(!buf.is_null());
4215
4216 let ret = doc_dump(buf, doc);
4217 assert!(ret >= 0);
4218
4219 let expected = "<?xml version=\"1.0\"?>\n<root><?xml-stylesheet href=\"style.xsl\" type=\"text/xsl\"?></root>\n";
4220 assert!(buf_eq_str(buf, expected));
4221
4222 io::buf_free(buf);
4223 free_doc(doc);
4224 }
4225 }
4226
4227 #[test]
4228 fn test_serialize_self_closing() {
4229 unsafe {
4230 let doc = new_doc(ptr::null());
4231 let root = new_node(ptr::null_mut(), c_str("empty"));
4232 doc_set_root_element(doc, root);
4233
4234 let buf = io::buf_create(-1);
4235 assert!(!buf.is_null());
4236
4237 let ret = doc_dump(buf, doc);
4238 assert!(ret >= 0);
4239
4240 let expected = "<?xml version=\"1.0\"?>\n<empty/>\n";
4241 assert!(buf_eq_str(buf, expected));
4242
4243 io::buf_free(buf);
4244 free_doc(doc);
4245 }
4246 }
4247
4248 #[test]
4249 fn test_dump_node_to_string() {
4250 unsafe {
4251 let node = new_node(ptr::null_mut(), c_str("foo"));
4252 let text = new_text(c_str("bar"));
4253 add_child(node, text);
4254
4255 let result = dump_node(node);
4256 assert!(!result.is_null());
4257
4258 let len = xml_strlen(result);
4259 let slice = unsafe { core::slice::from_raw_parts(result, len as usize) };
4260 assert_eq!(slice, b"<foo>bar</foo>");
4261
4262 allocator::xmlFree(result as *mut c_void);
4263 free_node(node);
4264 }
4265 }
4266
4267 #[test]
4268 fn test_dump_doc_to_string() {
4269 unsafe {
4270 let doc = new_doc(ptr::null());
4271 let root = new_node(ptr::null_mut(), c_str("root"));
4272 doc_set_root_element(doc, root);
4273
4274 let result = dump_doc(doc);
4275 assert!(!result.is_null());
4276
4277 let len = xml_strlen(result);
4278 let slice = unsafe { core::slice::from_raw_parts(result, len as usize) };
4279 let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
4280 assert_eq!(slice, expected.as_bytes());
4281
4282 allocator::xmlFree(result as *mut c_void);
4283 free_doc(doc);
4284 }
4285 }
4286
4287 #[test]
4288 fn test_xmlDocDumpFormatMemory() {
4289 unsafe {
4290 let doc = new_doc(ptr::null());
4291 let root = new_node(ptr::null_mut(), c_str("root"));
4292 doc_set_root_element(doc, root);
4293
4294 let mut mem: *mut xmlChar = ptr::null_mut();
4295 let mut size: c_int = 0;
4296
4297 xmlDocDumpFormatMemory(doc, &mut mem, &mut size, 0);
4298
4299 assert!(!mem.is_null());
4300 assert!(size > 0);
4301
4302 let slice = unsafe { core::slice::from_raw_parts(mem, size as usize) };
4303 let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
4306 assert_eq!(slice, expected.as_bytes());
4307
4308 allocator::xmlFree(mem as *mut c_void);
4309 free_doc(doc);
4310 }
4311 }
4312
4313 #[test]
4314 fn test_serialize_escape_attribute() {
4315 unsafe {
4316 let doc = new_doc(ptr::null());
4317 let root = new_node(ptr::null_mut(), c_str("root"));
4318 doc_set_root_element(doc, root);
4319
4320 set_prop(root, c_str("desc"), c_str("a < b & c \"quoted\""));
4322
4323 let buf = io::buf_create(-1);
4324 assert!(!buf.is_null());
4325
4326 let ret = doc_dump(buf, doc);
4327 assert!(ret >= 0);
4328
4329 let expected =
4330 "<?xml version=\"1.0\"?>\n<root desc=\"a < b & c "quoted"\"/>\n";
4331 assert!(buf_eq_str(buf, expected));
4332
4333 io::buf_free(buf);
4334 free_doc(doc);
4335 }
4336 }
4337}