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 recursive != 0 && !d.children.is_null() {
248 (*new_doc).children = copy_node_list(d.children, recursive);
249 if !(*new_doc).children.is_null() {
250 (*(*new_doc).children).parent = ptr::null_mut(); (*(*new_doc).children).doc = new_doc;
252 propagate_doc((*new_doc).children, new_doc);
254 }
255 }
256 }
257
258 new_doc
259}
260
261pub unsafe fn doc_set_root_element(doc: *mut _xmlDoc, root: *mut _xmlNode) -> *mut _xmlNode {
277 if doc.is_null() {
278 return ptr::null_mut();
279 }
280
281 let d = unsafe { &mut *doc };
282
283 let old_root = doc_get_root_element(doc);
284
285 if !root.is_null() {
286 unsafe {
287 (*root).parent = ptr::null_mut();
288 (*root).doc = doc;
289 }
290 d.children = root;
291 d.last = root;
292 unsafe {
293 (*root).prev = ptr::null_mut();
294 (*root).next = ptr::null_mut();
295 }
296 } else {
297 d.children = ptr::null_mut();
298 d.last = ptr::null_mut();
299 }
300
301 old_root
302}
303
304pub fn doc_get_root_element(doc: *mut _xmlDoc) -> *mut _xmlNode {
315 if doc.is_null() {
316 return ptr::null_mut();
317 }
318
319 let d = unsafe { &*doc };
320 let mut cur = d.children;
321
322 while !cur.is_null() {
323 let node = unsafe { &*cur };
324 if node.type_ == XML_ELEMENT_NODE as c_int {
325 return cur;
326 }
327 cur = node.next;
328 }
329
330 ptr::null_mut()
331}
332
333pub fn get_line_no(node: *const _xmlNode) -> c_int {
343 if node.is_null() {
344 return 0;
345 }
346 let n = unsafe { &*node };
347 n.line as c_int
348}
349
350pub unsafe fn node_get_content(node: *mut _xmlNode) -> *mut xmlChar {
370 if node.is_null() {
371 return ptr::null_mut();
372 }
373 let typ = (*node).type_;
374 let mut result: Vec<u8> = Vec::new();
375 match typ {
376 t if t == XML_TEXT_NODE as c_int
377 || t == XML_CDATA_SECTION_NODE as c_int
378 || t == XML_COMMENT_NODE as c_int
379 || t == XML_PI_NODE as c_int =>
380 {
381 if !(*node).content.is_null() {
382 let len = crate::abi::exports_xml2::xmlStrlen((*node).content);
383 result
384 .extend_from_slice(core::slice::from_raw_parts((*node).content, len as usize));
385 }
386 }
387 t if t == XML_ATTRIBUTE_NODE as c_int => {
388 if !(*node).children.is_null() {
390 let child = (*node).children;
391 if !(*child).content.is_null() {
392 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
393 result.extend_from_slice(core::slice::from_raw_parts(
394 (*child).content,
395 len as usize,
396 ));
397 }
398 }
399 }
400 t if t == XML_ENTITY_REF_NODE as c_int => {
401 let name = (*node).name;
403 if !name.is_null() && !(*node).doc.is_null() {
404 let ent = crate::xml::tree::get_doc_entity((*node).doc, name);
405 if !ent.is_null() && !(*ent).content.is_null() {
406 let len = crate::abi::exports_xml2::xmlStrlen((*ent).content);
407 result.extend_from_slice(core::slice::from_raw_parts(
408 (*ent).content,
409 len as usize,
410 ));
411 }
412 }
413 }
414 t if t == XML_DOCUMENT_NODE as c_int || t == XML_HTML_DOCUMENT_NODE as c_int => {
415 let root = doc_get_root_element(node as *mut _xmlDoc);
416 if !root.is_null() {
417 let sub = node_get_content(root);
418 if !sub.is_null() {
419 let len = crate::abi::exports_xml2::xmlStrlen(sub);
420 result.extend_from_slice(core::slice::from_raw_parts(sub, len as usize));
421 allocator::xmlFree(sub as *mut c_void);
422 }
423 }
424 }
425 _ => {
426 let mut child = (*node).children;
431 while !child.is_null() {
432 let ctype = (*child).type_;
433 if ctype == XML_TEXT_NODE as c_int || ctype == XML_CDATA_SECTION_NODE as c_int {
434 if !(*child).content.is_null() {
435 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
436 result.extend_from_slice(core::slice::from_raw_parts(
437 (*child).content,
438 len as usize,
439 ));
440 }
441 } else if ctype == XML_ENTITY_REF_NODE as c_int
442 || ctype == XML_ELEMENT_NODE as c_int
443 {
444 let sub = node_get_content(child);
445 if !sub.is_null() {
446 let len = crate::abi::exports_xml2::xmlStrlen(sub);
447 result.extend_from_slice(core::slice::from_raw_parts(sub, len as usize));
448 allocator::xmlFree(sub as *mut c_void);
449 }
450 }
451 child = (*child).next;
452 }
453 }
454 }
455 let buf = allocator::xmlMalloc(result.len() + 1) as *mut xmlChar;
457 if buf.is_null() {
458 return ptr::null_mut();
459 }
460 if !result.is_empty() {
461 ptr::copy_nonoverlapping(result.as_ptr(), buf, result.len());
462 }
463 *buf.add(result.len()) = 0;
464 buf
465}
466
467pub unsafe fn new_node(ns: *mut _xmlNs, name: *const xmlChar) -> *mut _xmlNode {
486 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
487 if node.is_null() {
488 return ptr::null_mut();
489 }
490
491 unsafe {
492 (*node).type_ = XML_ELEMENT_NODE as c_int;
493 (*node).name = dup_xml_str(name);
494 (*node).ns = ns;
495 (*node).line = 0;
496 (*node).extra = 0;
497
498 if !ns.is_null() {
499 (*ns).context = node as *mut _xmlDoc;
500 }
501 }
502
503 node
504}
505
506pub unsafe fn free_node(node: *mut _xmlNode) {
521 if node.is_null() {
522 return;
523 }
524
525 let n = unsafe { &mut *node };
526
527 if !n.properties.is_null() {
529 free_prop_list(n.properties);
530 }
531
532 if !n.nsDef.is_null() {
534 free_ns_list(n.nsDef);
535 }
536
537 if !n.name.is_null() {
539 allocator::xmlFree(n.name as *mut c_void);
540 }
541
542 if !n.content.is_null() {
544 let node_type = n.type_;
545 if node_type == XML_TEXT_NODE as c_int
546 || node_type == XML_CDATA_SECTION_NODE as c_int
547 || node_type == XML_COMMENT_NODE as c_int
548 || node_type == XML_PI_NODE as c_int
549 {
550 allocator::xmlFree(n.content as *mut c_void);
551 }
552 }
553
554 allocator::xmlFree(node as *mut c_void);
555}
556
557pub unsafe fn free_node_list(node: *mut _xmlNode) {
565 let mut cur = node;
566 while !cur.is_null() {
567 let next = unsafe { (*cur).next };
568
569 if !unsafe { (*cur).children }.is_null() {
571 free_node_list(unsafe { (*cur).children });
572 }
573
574 free_node(cur);
575 cur = next;
576 }
577}
578
579unsafe fn free_prop_list(prop: *mut _xmlAttr) {
585 let mut cur = prop;
586 while !cur.is_null() {
587 let next = unsafe { (*cur).next };
588
589 if !unsafe { (*cur).children }.is_null() {
591 free_node_list(unsafe { (*cur).children });
592 }
593
594 if !unsafe { (*cur).name }.is_null() {
596 allocator::xmlFree(unsafe { (*cur).name } as *mut c_void);
597 }
598
599 allocator::xmlFree(cur as *mut c_void);
600 cur = next;
601 }
602}
603
604unsafe fn free_ns_list(ns: *mut _xmlNs) {
610 let mut cur = ns;
611 while !cur.is_null() {
612 let next = unsafe { (*cur).next };
613
614 if !unsafe { (*cur).href }.is_null() {
616 allocator::xmlFree(unsafe { (*cur).href } as *mut c_void);
617 }
618 if !unsafe { (*cur).prefix }.is_null() {
619 allocator::xmlFree(unsafe { (*cur).prefix } as *mut c_void);
620 }
621
622 allocator::xmlFree(cur as *mut c_void);
623 cur = next;
624 }
625}
626
627pub unsafe fn copy_node(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
642 if node.is_null() {
643 return ptr::null_mut();
644 }
645
646 let n = unsafe { &*node };
647
648 let new_node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
649 if new_node.is_null() {
650 return ptr::null_mut();
651 }
652
653 unsafe {
654 (*new_node).type_ = n.type_;
655 (*new_node).name = dup_xml_str(n.name);
656 (*new_node).line = n.line;
657 (*new_node).extra = n.extra;
658 (*new_node).psvi = n.psvi;
659 (*new_node)._private = n._private;
660
661 (*new_node).ns = n.ns;
663
664 if !n.nsDef.is_null() {
666 (*new_node).nsDef = copy_ns_list(n.nsDef);
667 }
668
669 let node_type = n.type_;
671 if (node_type == XML_TEXT_NODE as c_int
672 || node_type == XML_CDATA_SECTION_NODE as c_int
673 || node_type == XML_COMMENT_NODE as c_int
674 || node_type == XML_PI_NODE as c_int)
675 && !n.content.is_null()
676 {
677 (*new_node).content = dup_xml_str(n.content);
678 }
679
680 if !n.properties.is_null() {
682 (*new_node).properties = copy_prop_list(n.properties);
683 let mut prop = (*new_node).properties;
685 while !prop.is_null() {
686 (*prop).parent = new_node;
687 if !(*prop).children.is_null() {
688 propagate_doc((*prop).children, (*new_node).doc);
689 }
690 prop = (*prop).next;
691 }
692 }
693
694 if recursive != 0 && !n.children.is_null() {
696 (*new_node).children = copy_node_list(n.children, recursive);
697 if !(*new_node).children.is_null() {
698 (*(*new_node).children).parent = new_node;
699 (*(*new_node).children).doc = (*new_node).doc;
700 propagate_doc((*new_node).children, (*new_node).doc);
701 }
702 }
703 }
704
705 new_node
706}
707
708unsafe fn copy_node_list(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
712 if node.is_null() {
713 return ptr::null_mut();
714 }
715
716 let n = unsafe { &*node };
717 let new_node = copy_node(node, recursive);
718 if new_node.is_null() {
719 return ptr::null_mut();
720 }
721
722 let mut prev = new_node;
723 let mut cur = n.next;
724
725 while !cur.is_null() {
726 let new_cur = copy_node(cur, recursive);
727 if new_cur.is_null() {
728 break;
729 }
730 unsafe {
731 (*prev).next = new_cur;
732 (*new_cur).prev = prev;
733 }
734 prev = new_cur;
735 cur = unsafe { (*cur).next };
736 }
737
738 new_node
739}
740
741unsafe fn copy_ns_list(ns: *const _xmlNs) -> *mut _xmlNs {
743 if ns.is_null() {
744 return ptr::null_mut();
745 }
746
747 let n = unsafe { &*ns };
748 let new_ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
749 if new_ns.is_null() {
750 return ptr::null_mut();
751 }
752
753 unsafe {
754 (*new_ns).type_ = n.type_;
755 (*new_ns).href = dup_xml_str(n.href);
756 (*new_ns).prefix = dup_xml_str(n.prefix);
757 (*new_ns)._private = n._private;
758 }
759
760 let mut prev = new_ns;
761 let mut cur = n.next;
762
763 while !cur.is_null() {
764 let c = unsafe { &*cur };
765 let new_cur = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
766 if new_cur.is_null() {
767 break;
768 }
769 unsafe {
770 (*new_cur).type_ = c.type_;
771 (*new_cur).href = dup_xml_str(c.href);
772 (*new_cur).prefix = dup_xml_str(c.prefix);
773 (*new_cur)._private = c._private;
774 (*prev).next = new_cur;
775 }
776 prev = new_cur;
777 cur = c.next;
778 }
779
780 new_ns
781}
782
783unsafe fn copy_prop_list(prop: *const _xmlAttr) -> *mut _xmlAttr {
785 if prop.is_null() {
786 return ptr::null_mut();
787 }
788
789 let p = unsafe { &*prop };
790 let new_prop = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
791 if new_prop.is_null() {
792 return ptr::null_mut();
793 }
794
795 unsafe {
796 (*new_prop).type_ = p.type_;
797 (*new_prop).name = dup_xml_str(p.name);
798 (*new_prop).ns = p.ns;
799 (*new_prop).atype = p.atype;
800
801 if !p.children.is_null() {
803 (*new_prop).children = copy_node_list(p.children, 1);
804 if !(*new_prop).children.is_null() {
805 (*(*new_prop).children).parent = new_prop as *mut _xmlNode;
806 }
807 }
808 }
809
810 let mut prev = new_prop;
811 let mut cur = p.next;
812
813 while !cur.is_null() {
814 let c = unsafe { &*cur };
815 let new_cur = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
816 if new_cur.is_null() {
817 break;
818 }
819 unsafe {
820 (*new_cur).type_ = c.type_;
821 (*new_cur).name = dup_xml_str(c.name);
822 (*new_cur).ns = c.ns;
823 (*new_cur).atype = c.atype;
824
825 if !c.children.is_null() {
826 (*new_cur).children = copy_node_list(c.children, 1);
827 if !(*new_cur).children.is_null() {
828 (*(*new_cur).children).parent = new_cur as *mut _xmlNode;
829 }
830 }
831
832 (*prev).next = new_cur;
833 }
834 prev = new_cur;
835 cur = c.next;
836 }
837
838 new_prop
839}
840
841unsafe fn propagate_doc(node: *mut _xmlNode, doc: *mut _xmlDoc) {
843 let mut cur = node;
844 while !cur.is_null() {
845 unsafe {
846 (*cur).doc = doc;
847
848 let mut prop = (*cur).properties;
850 while !prop.is_null() {
851 (*prop).doc = doc;
852 if !(*prop).children.is_null() {
853 propagate_doc((*prop).children, doc);
854 }
855 prop = (*prop).next;
856 }
857
858 if !(*cur).children.is_null() {
860 propagate_doc((*cur).children, doc);
861 }
862 }
863 cur = unsafe { (*cur).next };
864 }
865}
866
867pub unsafe fn unlink_node(node: *mut _xmlNode) {
883 if node.is_null() {
884 return;
885 }
886
887 let n = unsafe { &mut *node };
888
889 let prev = n.prev;
891 let next = n.next;
892
893 if !prev.is_null() {
894 unsafe { (*prev).next = next };
895 }
896 if !next.is_null() {
897 unsafe { (*next).prev = prev };
898 }
899
900 let parent = n.parent;
902 if !parent.is_null() {
903 if unsafe { (*parent).children } == node {
904 unsafe { (*parent).children = next };
905 }
906 if unsafe { (*parent).last } == node {
907 unsafe { (*parent).last = prev };
908 }
909 }
910
911 let doc = n.doc;
913 if !doc.is_null() && !parent.is_null() {
914 }
916 if !doc.is_null() && parent.is_null() {
917 if unsafe { (*doc).children } == node {
919 unsafe { (*doc).children = next };
920 }
921 if unsafe { (*doc).last } == node {
922 unsafe { (*doc).last = prev };
923 }
924 }
925
926 n.parent = ptr::null_mut();
928 n.prev = ptr::null_mut();
929 n.next = ptr::null_mut();
930}
931
932pub unsafe fn add_child(parent: *mut _xmlNode, cur: *mut _xmlNode) -> *mut _xmlNode {
948 if parent.is_null() || cur.is_null() {
949 return ptr::null_mut();
950 }
951
952 let p = unsafe { &mut *parent };
953 let c = unsafe { &mut *cur };
954
955 if !c.parent.is_null() || !c.prev.is_null() || !c.next.is_null() {
957 unlink_node(cur);
958 }
959
960 c.parent = parent;
962
963 if p.children.is_null() {
964 p.children = cur;
966 p.last = cur;
967 c.prev = ptr::null_mut();
968 c.next = ptr::null_mut();
969 } else {
970 c.prev = p.last;
972 c.next = ptr::null_mut();
973 if !p.last.is_null() {
974 unsafe { (*p.last).next = cur };
975 }
976 p.last = cur;
977 }
978
979 let doc = if !p.doc.is_null() {
981 p.doc
982 } else {
983 ptr::null_mut()
984 };
985 if !doc.is_null() && c.doc != doc {
986 propagate_doc(cur, doc);
987 }
988
989 cur
990}
991
992pub unsafe fn add_sibling(cur: *mut _xmlNode, elem: *mut _xmlNode) -> *mut _xmlNode {
1008 if cur.is_null() || elem.is_null() {
1009 return ptr::null_mut();
1010 }
1011
1012 let c = unsafe { &mut *cur };
1013
1014 let e = unsafe { &mut *elem };
1016 if !e.parent.is_null() || !e.prev.is_null() || !e.next.is_null() {
1017 unlink_node(elem);
1018 }
1019
1020 e.parent = c.parent;
1022
1023 e.prev = cur;
1025 e.next = c.next;
1026
1027 if !c.next.is_null() {
1028 unsafe { (*c.next).prev = elem };
1029 }
1030 c.next = elem;
1031
1032 let parent = c.parent;
1034 if !parent.is_null() && unsafe { (*parent).last } == cur {
1035 unsafe { (*parent).last = elem };
1036 }
1037
1038 if !c.doc.is_null() && e.doc != c.doc {
1040 propagate_doc(elem, c.doc);
1041 }
1042
1043 elem
1044}
1045
1046pub unsafe fn add_sibling_before(cur: *mut _xmlNode, elem: *mut _xmlNode) -> *mut _xmlNode {
1062 if cur.is_null() || elem.is_null() {
1063 return ptr::null_mut();
1064 }
1065
1066 let c = unsafe { &mut *cur };
1067
1068 let e = unsafe { &mut *elem };
1070 if !e.parent.is_null() || !e.prev.is_null() || !e.next.is_null() {
1071 unlink_node(elem);
1072 }
1073
1074 e.parent = c.parent;
1076
1077 e.prev = c.prev;
1079 e.next = cur;
1080
1081 if !c.prev.is_null() {
1082 unsafe { (*c.prev).next = elem };
1083 }
1084 c.prev = elem;
1085
1086 let parent = c.parent;
1088 if !parent.is_null() && unsafe { (*parent).children } == cur {
1089 unsafe { (*parent).children = elem };
1090 }
1091
1092 let doc = c.doc;
1094 if !doc.is_null() && parent.is_null() {
1095 if unsafe { (*doc).children } == cur {
1096 unsafe { (*doc).children = elem };
1097 }
1098 }
1099
1100 if !c.doc.is_null() && e.doc != c.doc {
1102 propagate_doc(elem, c.doc);
1103 }
1104
1105 elem
1106}
1107
1108pub unsafe fn new_child(
1123 parent: *mut _xmlNode,
1124 ns: *mut _xmlNs,
1125 name: *const xmlChar,
1126) -> *mut _xmlNode {
1127 let node = new_node(ns, name);
1128 if node.is_null() {
1129 return ptr::null_mut();
1130 }
1131
1132 if !parent.is_null() {
1133 add_child(parent, node);
1134 }
1135
1136 node
1137}
1138
1139pub unsafe fn new_text(content: *const xmlChar) -> *mut _xmlNode {
1158 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1159 if node.is_null() {
1160 return ptr::null_mut();
1161 }
1162
1163 unsafe {
1164 (*node).type_ = XML_TEXT_NODE as c_int;
1165 (*node).name = dup_xml_str(b"text\0" as *const u8 as *const xmlChar);
1166 (*node).content = if content.is_null() {
1167 let empty = allocator::xmlMalloc(1) as *mut xmlChar;
1168 if !empty.is_null() {
1169 *empty = 0;
1170 }
1171 empty
1172 } else {
1173 dup_xml_str(content)
1174 };
1175 (*node).line = 0;
1176 }
1177
1178 node
1179}
1180
1181pub unsafe fn new_comment(content: *const xmlChar) -> *mut _xmlNode {
1195 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1196 if node.is_null() {
1197 return ptr::null_mut();
1198 }
1199
1200 unsafe {
1201 (*node).type_ = XML_COMMENT_NODE as c_int;
1202 (*node).name = dup_xml_str(b"comment\0" as *const u8 as *const xmlChar);
1203 (*node).content = dup_xml_str(content);
1204 (*node).line = 0;
1205 }
1206
1207 node
1208}
1209
1210pub unsafe fn new_pi(name: *const xmlChar, content: *const xmlChar) -> *mut _xmlNode {
1225 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1226 if node.is_null() {
1227 return ptr::null_mut();
1228 }
1229
1230 unsafe {
1231 (*node).type_ = XML_PI_NODE as c_int;
1232 (*node).name = dup_xml_str(name);
1233 (*node).content = dup_xml_str(content);
1234 (*node).line = 0;
1235 }
1236
1237 node
1238}
1239
1240pub unsafe fn new_cdata_block(
1256 doc: *mut _xmlDoc,
1257 content: *const xmlChar,
1258 len: c_int,
1259) -> *mut _xmlNode {
1260 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1261 if node.is_null() {
1262 return ptr::null_mut();
1263 }
1264
1265 unsafe {
1266 (*node).type_ = XML_CDATA_SECTION_NODE as c_int;
1267 (*node).name = dup_xml_str(b"cdata\0" as *const u8 as *const xmlChar);
1268 (*node).doc = doc;
1269
1270 if !content.is_null() && len > 0 {
1271 (*node).content = allocator::xmlMalloc((len + 1) as usize) as *mut xmlChar;
1272 if !(*node).content.is_null() {
1273 ptr::copy_nonoverlapping(content, (*node).content, len as usize);
1274 *((*node).content.add(len as usize)) = 0;
1275 }
1276 } else {
1277 let empty = allocator::xmlMalloc(1) as *mut xmlChar;
1278 if !empty.is_null() {
1279 *empty = 0;
1280 }
1281 (*node).content = empty;
1282 }
1283
1284 (*node).line = 0;
1285 }
1286
1287 node
1288}
1289
1290pub unsafe fn new_ns(
1314 node: *mut _xmlNode,
1315 href: *const xmlChar,
1316 prefix: *const xmlChar,
1317) -> *mut _xmlNs {
1318 let ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
1319 if ns.is_null() {
1320 return ptr::null_mut();
1321 }
1322
1323 unsafe {
1324 (*ns).type_ = XML_LOCAL_NAMESPACE as c_int;
1325 (*ns).href = dup_xml_str(href);
1326 (*ns).prefix = dup_xml_str(prefix);
1327 (*ns).context = node as *mut _xmlDoc;
1328
1329 if !node.is_null() {
1331 let n = &mut *node;
1332 if n.nsDef.is_null() {
1333 n.nsDef = ns;
1334 } else {
1335 let mut last = n.nsDef;
1337 while !(*last).next.is_null() {
1338 last = (*last).next;
1339 }
1340 (*last).next = ns;
1341 }
1342 }
1343 }
1344
1345 ns
1346}
1347
1348pub unsafe fn set_ns(node: *mut _xmlNode, ns: *mut _xmlNs) {
1361 if node.is_null() {
1362 return;
1363 }
1364 unsafe {
1365 (*node).ns = ns;
1366 }
1367}
1368
1369pub unsafe fn get_ns_list(doc: *mut _xmlDoc, node: *mut _xmlNode) -> *mut *mut _xmlNs {
1385 if node.is_null() {
1389 return ptr::null_mut();
1390 }
1391
1392 let mut ns_ptrs: Vec<*mut _xmlNs> = Vec::new();
1394 let mut cur = node;
1395
1396 while !cur.is_null() {
1397 let n = unsafe { &*cur };
1398 let mut ns_def = n.nsDef;
1399 while !ns_def.is_null() {
1400 let ns = unsafe { &*ns_def };
1402 let mut found = false;
1403 for &existing in &ns_ptrs {
1404 if existing == ns_def {
1405 found = true;
1406 break;
1407 }
1408 let e = unsafe { &*existing };
1409 if !ns.href.is_null() && !e.href.is_null() {
1410 let href_match =
1411 unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, e.href) != 0 };
1412 if href_match {
1413 if ns.prefix.is_null() && e.prefix.is_null() {
1414 found = true;
1415 break;
1416 }
1417 if !ns.prefix.is_null() && !e.prefix.is_null() {
1418 let prefix_match = unsafe {
1419 crate::abi::exports_xml2::xmlStrEqual(ns.prefix, e.prefix) != 0
1420 };
1421 if prefix_match {
1422 found = true;
1423 break;
1424 }
1425 }
1426 }
1427 }
1428 }
1429 if !found {
1430 ns_ptrs.push(ns_def);
1431 }
1432 ns_def = unsafe { (*ns_def).next };
1433 }
1434 cur = n.parent;
1435 }
1436
1437 if ns_ptrs.is_empty() {
1438 return ptr::null_mut();
1439 }
1440
1441 let arr =
1443 allocator::xmlMalloc((ns_ptrs.len() + 1) * size_of::<*mut _xmlNs>()) as *mut *mut _xmlNs;
1444 if arr.is_null() {
1445 return ptr::null_mut();
1446 }
1447
1448 for (i, ns) in ns_ptrs.iter().enumerate() {
1449 unsafe { *arr.add(i) = *ns };
1450 }
1451 unsafe { *arr.add(ns_ptrs.len()) = ptr::null_mut() };
1452
1453 arr
1454}
1455
1456pub unsafe fn search_ns(
1473 doc: *mut _xmlDoc,
1474 node: *mut _xmlNode,
1475 name_space: *const xmlChar,
1476) -> *mut _xmlNs {
1477 if node.is_null() {
1478 return ptr::null_mut();
1479 }
1480
1481 let mut cur = node;
1482 while !cur.is_null() {
1483 let n = unsafe { &*cur };
1484 let mut ns_def = n.nsDef;
1485 while !ns_def.is_null() {
1486 let ns = unsafe { &*ns_def };
1487 let match_prefix = if name_space.is_null() {
1488 ns.prefix.is_null()
1490 } else {
1491 !ns.prefix.is_null()
1492 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.prefix, name_space) != 0 }
1493 };
1494 if match_prefix {
1495 return ns_def;
1496 }
1497 ns_def = unsafe { (*ns_def).next };
1498 }
1499 cur = n.parent;
1500 }
1501
1502 ptr::null_mut()
1503}
1504
1505pub unsafe fn search_ns_by_href(
1521 doc: *mut _xmlDoc,
1522 node: *mut _xmlNode,
1523 href: *const xmlChar,
1524) -> *mut _xmlNs {
1525 if node.is_null() || href.is_null() {
1526 return ptr::null_mut();
1527 }
1528
1529 let mut cur = node;
1530 while !cur.is_null() {
1531 let n = unsafe { &*cur };
1532 let mut ns_def = n.nsDef;
1533 while !ns_def.is_null() {
1534 let ns = unsafe { &*ns_def };
1535 if !ns.href.is_null()
1536 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, href) != 0 }
1537 {
1538 return ns_def;
1539 }
1540 ns_def = unsafe { (*ns_def).next };
1541 }
1542 cur = n.parent;
1543 }
1544
1545 ptr::null_mut()
1546}
1547
1548pub unsafe fn set_prop(
1572 node: *mut _xmlNode,
1573 name: *const xmlChar,
1574 value: *const xmlChar,
1575) -> *mut _xmlAttr {
1576 if node.is_null() || name.is_null() {
1577 return ptr::null_mut();
1578 }
1579
1580 let n = unsafe { &mut *node };
1581
1582 let mut existing = n.properties;
1584 while !existing.is_null() {
1585 let attr = unsafe { &*existing };
1586 if !attr.name.is_null()
1587 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1588 {
1589 if !attr.children.is_null() {
1592 free_node_list(attr.children);
1593 let attr_mut = existing as *mut _xmlAttr;
1595 unsafe { (*attr_mut).children = ptr::null_mut() };
1596 unsafe { (*attr_mut).last = ptr::null_mut() };
1597 }
1598 if !value.is_null() {
1600 let text = new_text(value);
1601 if !text.is_null() {
1602 let attr_mut = existing as *mut _xmlAttr;
1603 unsafe {
1604 (*attr_mut).children = text;
1605 (*attr_mut).last = text;
1606 (*text).parent = existing as *mut _xmlNode;
1607 (*text).doc = n.doc;
1608 }
1609 }
1610 }
1611 return existing;
1612 }
1613 existing = unsafe { (*existing).next };
1614 }
1615
1616 let attr = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
1618 if attr.is_null() {
1619 return ptr::null_mut();
1620 }
1621
1622 unsafe {
1623 (*attr).type_ = XML_ATTRIBUTE_NODE as c_int;
1624 (*attr).name = dup_xml_str(name);
1625 (*attr).parent = node;
1626 (*attr).doc = n.doc;
1627 (*attr).atype = XML_ATTRIBUTE_CDATA as c_int;
1628
1629 if !value.is_null() {
1631 let text = new_text(value);
1632 if !text.is_null() {
1633 (*attr).children = text;
1634 (*attr).last = text;
1635 (*text).parent = attr as *mut _xmlNode;
1636 (*text).doc = n.doc;
1637 }
1638 }
1639
1640 if n.properties.is_null() {
1642 n.properties = attr;
1643 } else {
1644 let mut last = n.properties;
1645 while !(*last).next.is_null() {
1646 last = (*last).next;
1647 }
1648 (*last).next = attr;
1649 (*attr).prev = last;
1650 }
1651 }
1652
1653 attr
1654}
1655
1656pub unsafe fn get_prop(node: *mut _xmlNode, name: *const xmlChar) -> *mut xmlChar {
1672 if node.is_null() || name.is_null() {
1673 return ptr::null_mut();
1674 }
1675
1676 let n = unsafe { &*node };
1677 let mut cur = n.properties;
1678
1679 while !cur.is_null() {
1680 let attr = unsafe { &*cur };
1681 if !attr.name.is_null()
1682 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1683 {
1684 if !attr.children.is_null() {
1686 let text = unsafe { &*attr.children };
1687 if text.type_ == XML_TEXT_NODE as c_int && !text.content.is_null() {
1688 return dup_xml_str(text.content);
1689 }
1690 }
1691 return dup_xml_str(b"\0" as *const u8 as *const xmlChar);
1692 }
1693 cur = unsafe { (*cur).next };
1694 }
1695
1696 ptr::null_mut()
1697}
1698
1699pub unsafe fn get_ns_prop(
1715 node: *mut _xmlNode,
1716 name: *const xmlChar,
1717 _name_space: *const xmlChar,
1718) -> *mut xmlChar {
1719 get_prop(node, name)
1722}
1723
1724pub unsafe fn set_ns_prop(
1739 node: *mut _xmlNode,
1740 _ns: *mut _xmlNs,
1741 name: *const xmlChar,
1742 value: *const xmlChar,
1743) -> *mut _xmlAttr {
1744 set_prop(node, name, value)
1746}
1747
1748pub unsafe fn remove_prop(attr: *mut _xmlAttr) -> c_int {
1763 if attr.is_null() {
1764 return -1;
1765 }
1766
1767 let a = unsafe { &mut *attr };
1768
1769 let parent = a.parent;
1771 if !parent.is_null() {
1772 let p = unsafe { &mut *parent };
1773 if p.properties == attr {
1774 p.properties = a.next;
1775 }
1776 }
1777
1778 if !a.prev.is_null() {
1780 unsafe { (*a.prev).next = a.next };
1781 }
1782 if !a.next.is_null() {
1783 unsafe { (*a.next).prev = a.prev };
1784 }
1785
1786 if !a.children.is_null() {
1788 free_node_list(a.children);
1789 }
1790
1791 if !a.name.is_null() {
1793 allocator::xmlFree(a.name as *mut c_void);
1794 }
1795
1796 allocator::xmlFree(attr as *mut c_void);
1797 0
1798}
1799
1800pub fn get_int_subset(doc: *const _xmlDoc) -> *mut _xmlDtd {
1812 if doc.is_null() {
1813 return ptr::null_mut();
1814 }
1815 let d = unsafe { &*doc };
1816 d.intSubset
1817}
1818
1819pub unsafe fn new_dtd(
1836 doc: *mut _xmlDoc,
1837 name: *const xmlChar,
1838 ExternalID: *const xmlChar,
1839 SystemID: *const xmlChar,
1840) -> *mut _xmlDtd {
1841 let dtd = allocator::xmlMallocZero(size_of::<_xmlDtd>() as usize) as *mut _xmlDtd;
1842 if dtd.is_null() {
1843 return ptr::null_mut();
1844 }
1845
1846 unsafe {
1847 (*dtd).type_ = XML_DTD_NODE as c_int;
1848 (*dtd).name = dup_xml_str(name);
1849 (*dtd).ExternalID = dup_xml_str(ExternalID);
1850 (*dtd).SystemID = dup_xml_str(SystemID);
1851 (*dtd).parent = doc;
1852 (*dtd).doc = doc;
1853
1854 if !doc.is_null() {
1856 if (*doc).intSubset.is_null() {
1857 (*doc).intSubset = dtd;
1858 }
1859 }
1860 }
1861
1862 dtd
1863}
1864
1865unsafe fn free_dtd(dtd: *mut _xmlDtd) {
1871 if dtd.is_null() {
1872 return;
1873 }
1874
1875 let d = unsafe { &mut *dtd };
1876
1877 if !d.name.is_null() {
1879 allocator::xmlFree(d.name as *mut c_void);
1880 }
1881 if !d.ExternalID.is_null() {
1882 allocator::xmlFree(d.ExternalID as *mut c_void);
1883 }
1884 if !d.SystemID.is_null() {
1885 allocator::xmlFree(d.SystemID as *mut c_void);
1886 }
1887
1888 unsafe extern "C" fn free_notation_wrapper(payload: *mut c_void, _name: *mut u8) {
1890 crate::xml::dtd::free_notation(payload as *mut _xmlNotation);
1891 }
1892 unsafe extern "C" fn free_element_wrapper(payload: *mut c_void, _name: *mut u8) {
1893 crate::xml::dtd::free_element(payload as *mut _xmlElement);
1894 }
1895 unsafe extern "C" fn free_attribute_wrapper(payload: *mut c_void, _name: *mut u8) {
1896 crate::xml::dtd::free_attribute(payload as *mut _xmlAttribute);
1897 }
1898 unsafe extern "C" fn free_entity_wrapper(payload: *mut c_void, _name: *mut u8) {
1899 crate::xml::entities::free_entity(payload as *mut _xmlEntity);
1900 }
1901
1902 if !d.notations.is_null() {
1903 crate::xml::hash::hash_free(
1904 d.notations as *mut crate::xml::hash::HashTable,
1905 Some(free_notation_wrapper),
1906 );
1907 d.notations = ptr::null_mut();
1908 }
1909 if !d.elements.is_null() {
1910 crate::xml::hash::hash_free(
1911 d.elements as *mut crate::xml::hash::HashTable,
1912 Some(free_element_wrapper),
1913 );
1914 d.elements = ptr::null_mut();
1915 }
1916 if !d.attributes.is_null() {
1917 crate::xml::hash::hash_free(
1918 d.attributes as *mut crate::xml::hash::HashTable,
1919 Some(free_attribute_wrapper),
1920 );
1921 d.attributes = ptr::null_mut();
1922 }
1923 if !d.entities.is_null() {
1924 crate::xml::hash::hash_free(
1925 d.entities as *mut crate::xml::hash::HashTable,
1926 Some(free_entity_wrapper),
1927 );
1928 d.entities = ptr::null_mut();
1929 }
1930 if !d.pentities.is_null() {
1931 crate::xml::hash::hash_free(
1932 d.pentities as *mut crate::xml::hash::HashTable,
1933 Some(free_entity_wrapper),
1934 );
1935 d.pentities = ptr::null_mut();
1936 }
1937
1938 if !d.children.is_null() {
1940 free_node_list(d.children);
1941 }
1942
1943 allocator::xmlFree(dtd as *mut c_void);
1944}
1945
1946pub unsafe fn new_entity(
1966 _doc: *mut _xmlDoc,
1967 name: *const xmlChar,
1968 etype: c_int,
1969 ExternalID: *const xmlChar,
1970 SystemID: *const xmlChar,
1971 content: *const xmlChar,
1972) -> *mut _xmlEntity {
1973 let entity = allocator::xmlMallocZero(size_of::<_xmlEntity>() as usize) as *mut _xmlEntity;
1974 if entity.is_null() {
1975 return ptr::null_mut();
1976 }
1977
1978 unsafe {
1979 (*entity).type_ = XML_ENTITY_DECL as c_int;
1980 (*entity).name = dup_xml_str(name);
1981 (*entity).etype = etype;
1982 (*entity).ExternalID = dup_xml_str(ExternalID);
1983 (*entity).SystemID = dup_xml_str(SystemID);
1984 (*entity).content = dup_xml_str(content);
1985 (*entity).length = if content.is_null() {
1986 0
1987 } else {
1988 crate::abi::exports_xml2::xmlStrlen(content)
1989 };
1990 (*entity).flags = 0;
1991 (*entity).expandedSize = 0;
1992 }
1993
1994 entity
1995}
1996
1997pub unsafe fn get_doc_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2012 crate::xml::entities::get_entity(doc as *mut _xmlDoc, name)
2013}
2014
2015pub unsafe fn get_parameter_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2028 crate::xml::entities::get_parameter_entity(doc as *mut _xmlDoc, name)
2029}
2030
2031const ENTITY_LT: &[xmlChar] = b"<";
2040const ENTITY_GT: &[xmlChar] = b">";
2041const ENTITY_AMP: &[xmlChar] = b"&";
2042const ENTITY_QUOT: &[xmlChar] = b""";
2043const ENTITY_APOS: &[xmlChar] = b"'";
2044
2045const INDENT: &[xmlChar] = b" ";
2047
2048const MAX_INDENT: c_int = 60;
2050
2051pub(crate) unsafe fn serialize_text(buf: *mut _xmlBuffer, content: *const xmlChar, len: c_int) {
2066 if buf.is_null() || content.is_null() || len <= 0 {
2067 return;
2068 }
2069
2070 let mut i: c_int = 0;
2071 while i < len {
2072 let ch = unsafe { *content.add(i as usize) };
2073
2074 if ch == b']'
2076 && i + 2 < len
2077 && unsafe { *content.add(i as usize + 1) == b']' }
2078 && unsafe { *content.add(i as usize + 2) == b'>' }
2079 {
2080 io::buf_add(buf, &ch as *const u8, 2); io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2083 i += 3;
2084 continue;
2085 }
2086
2087 match ch {
2088 b'<' => {
2089 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
2090 }
2091 b'&' => {
2092 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
2093 }
2094 b'>' => {
2095 io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2099 }
2100 b'\r' => {
2101 io::buf_add(buf, b" " as *const u8, 5);
2103 }
2104 0x01..=0x08 | 0x0B | 0x0C | 0x0E..=0x1F => {
2105 let hex = format!("&#x{:X};", ch);
2107 io::buf_add(buf, hex.as_ptr(), hex.len() as c_int);
2108 }
2109 _ => {
2110 io::buf_add(buf, &ch as *const u8, 1);
2111 }
2112 }
2113 i += 1;
2114 }
2115}
2116
2117pub(crate) unsafe fn serialize_attr_value(buf: *mut _xmlBuffer, value: *const xmlChar) {
2130 if buf.is_null() || value.is_null() {
2131 return;
2132 }
2133
2134 let len = xml_strlen(value);
2135 let mut i: c_int = 0;
2136 while i < len {
2137 let ch = unsafe { *value.add(i as usize) };
2138
2139 match ch {
2140 b'\n' => {
2141 io::buf_add(buf, b" " as *const u8, 5);
2142 }
2143 b'\r' => {
2144 io::buf_add(buf, b" " as *const u8, 5);
2145 }
2146 b'\t' => {
2147 io::buf_add(buf, b"	" as *const u8, 4);
2148 }
2149 b'<' => {
2150 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
2151 }
2152 b'&' => {
2153 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
2154 }
2155 b'"' => {
2156 io::buf_add(buf, ENTITY_QUOT.as_ptr(), ENTITY_QUOT.len() as c_int);
2157 }
2158 b'>' => {
2159 io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2160 }
2161 _ => {
2162 io::buf_add(buf, &ch as *const u8, 1);
2163 }
2164 }
2165 i += 1;
2166 }
2167}
2168
2169unsafe fn write_indent(buf: *mut _xmlBuffer, level: c_int) {
2181 if buf.is_null() || level <= 0 {
2182 return;
2183 }
2184 let indent_nr = MAX_INDENT / INDENT.len() as c_int;
2185 let mut lvl = level;
2186 if lvl > indent_nr {
2187 lvl = indent_nr;
2188 }
2189 for _ in 0..lvl {
2190 io::buf_add(buf, INDENT.as_ptr(), INDENT.len() as c_int);
2191 }
2192}
2193
2194unsafe fn is_noenc_text(node: *mut _xmlNode) -> bool {
2202 if node.is_null() {
2203 return false;
2204 }
2205 let n = unsafe { &*node };
2206 if n.name.is_null() {
2207 return false;
2208 }
2209 c_str_eq_bytes(n.name, b"textnoenc")
2210}
2211
2212unsafe fn c_str_eq_bytes(s: *const xmlChar, b: &[u8]) -> bool {
2214 let mut i = 0usize;
2215 while i < b.len() {
2216 if unsafe { *s.add(i) } != b[i] {
2217 return false;
2218 }
2219 i += 1;
2220 }
2221 unsafe { *s.add(i) == 0 }
2222}
2223
2224#[derive(Clone, Copy)]
2227struct DumpState {
2228 format: c_int,
2230 saved: c_int,
2233 unformatted: *mut _xmlNode,
2236}
2237
2238impl DumpState {
2239 fn new(format: c_int) -> Self {
2240 let f = if format != 0 { 1 } else { 0 };
2241 DumpState {
2242 format: f,
2243 saved: f,
2244 unformatted: ptr::null_mut(),
2245 }
2246 }
2247}
2248
2249unsafe fn write_qname(buf: *mut _xmlBuffer, node: *mut _xmlNode) {
2255 let n = unsafe { &*node };
2256 if !n.ns.is_null() {
2257 let ns = unsafe { &*n.ns };
2258 if !ns.prefix.is_null() {
2259 io::buf_cat(buf, ns.prefix);
2260 io::buf_ccat(buf, b':');
2261 }
2262 }
2263 if !n.name.is_null() {
2264 io::buf_cat(buf, n.name);
2265 }
2266}
2267
2268unsafe fn ns_dump_output(buf: *mut _xmlBuffer, cur: *mut _xmlNs) {
2274 if cur.is_null() || buf.is_null() {
2275 return;
2276 }
2277 let ns = unsafe { &*cur };
2278 if ns.type_ == XML_LOCAL_NAMESPACE as c_int && !ns.href.is_null() {
2279 if !ns.prefix.is_null() && c_str_eq_bytes(ns.prefix, b"xml") {
2281 return;
2282 }
2283 io::buf_ccat(buf, b' ');
2284 if !ns.prefix.is_null() {
2285 io::buf_add(buf, b"xmlns:" as *const u8, 6);
2286 io::buf_cat(buf, ns.prefix);
2287 } else {
2288 io::buf_add(buf, b"xmlns" as *const u8, 5);
2289 }
2290 io::buf_add(buf, b"=\"" as *const u8, 2);
2291 serialize_attr_value(buf, ns.href);
2292 io::buf_ccat(buf, b'"');
2293 }
2294}
2295
2296unsafe fn attr_dump_output(buf: *mut _xmlBuffer, cur: *mut _xmlAttr) {
2302 if cur.is_null() || buf.is_null() {
2303 return;
2304 }
2305 io::buf_ccat(buf, b' ');
2306 let a = unsafe { &*cur };
2307 if !a.ns.is_null() {
2308 let ans = unsafe { &*a.ns };
2309 if !ans.prefix.is_null() {
2310 io::buf_cat(buf, ans.prefix);
2311 io::buf_ccat(buf, b':');
2312 }
2313 }
2314 if !a.name.is_null() {
2315 io::buf_cat(buf, a.name);
2316 }
2317 io::buf_add(buf, b"=\"" as *const u8, 2);
2318 let mut child = a.children;
2321 while !child.is_null() {
2322 let ct = unsafe { (*child).type_ };
2323 if ct == XML_TEXT_NODE as c_int && !unsafe { (*child).content }.is_null() {
2324 serialize_attr_value(buf, unsafe { (*child).content });
2325 } else if ct == XML_ENTITY_REF_NODE as c_int && !unsafe { (*child).name }.is_null() {
2326 io::buf_ccat(buf, b'&');
2327 io::buf_cat(buf, unsafe { (*child).name });
2328 io::buf_ccat(buf, b';');
2329 }
2330 child = unsafe { (*child).next };
2331 }
2332 io::buf_ccat(buf, b'"');
2333}
2334
2335unsafe fn dump_notation_decl(buf: *mut _xmlBuffer, nota: *mut _xmlNotation) {
2341 let n = unsafe { &*nota };
2342 io::buf_add(buf, b"<!NOTATION " as *const u8, 11);
2343 if !n.name.is_null() {
2344 io::buf_cat(buf, n.name);
2345 }
2346 if !n.PublicID.is_null() {
2347 io::buf_add(buf, b" PUBLIC " as *const u8, 8);
2348 write_quoted_string(buf, n.PublicID);
2349 if !n.SystemID.is_null() {
2350 io::buf_ccat(buf, b' ');
2351 write_quoted_string(buf, n.SystemID);
2352 }
2353 } else {
2354 io::buf_add(buf, b" SYSTEM " as *const u8, 8);
2355 write_quoted_string(buf, n.SystemID);
2356 }
2357 io::buf_add(buf, b" >\n" as *const u8, 4);
2358}
2359
2360unsafe fn dump_element_occur(buf: *mut _xmlBuffer, ocur: c_int) {
2362 use crate::abi::types::xmlElementContentOccur::*;
2363 if ocur == XML_ELEMENT_CONTENT_OPT as c_int {
2364 io::buf_ccat(buf, b'?');
2365 } else if ocur == XML_ELEMENT_CONTENT_MULT as c_int {
2366 io::buf_ccat(buf, b'*');
2367 } else if ocur == XML_ELEMENT_CONTENT_PLUS as c_int {
2368 io::buf_ccat(buf, b'+');
2369 }
2370}
2371
2372unsafe fn dump_element_content(buf: *mut _xmlBuffer, content: *mut _xmlElementContent) {
2378 use crate::abi::types::xmlElementContentOccur::*;
2379 use crate::abi::types::xmlElementContentType::*;
2380 if content.is_null() {
2381 return;
2382 }
2383 io::buf_ccat(buf, b'(');
2384 let mut cur = content;
2385 loop {
2386 if cur.is_null() {
2387 return;
2388 }
2389 let c = unsafe { &*cur };
2390 match c.type_ {
2391 t if t == XML_ELEMENT_CONTENT_PCDATA as c_int => {
2392 io::buf_add(buf, b"#PCDATA" as *const u8, 7);
2393 }
2394 t if t == XML_ELEMENT_CONTENT_ELEMENT as c_int => {
2395 if !c.prefix.is_null() {
2396 io::buf_cat(buf, c.prefix);
2397 io::buf_ccat(buf, b':');
2398 }
2399 if !c.name.is_null() {
2400 io::buf_cat(buf, c.name);
2401 }
2402 }
2403 t if t == XML_ELEMENT_CONTENT_SEQ as c_int || t == XML_ELEMENT_CONTENT_OR as c_int => {
2404 if cur != content
2405 && !c.parent.is_null()
2406 && (c.type_ != unsafe { (*c.parent).type_ }
2407 || c.ocur != XML_ELEMENT_CONTENT_ONCE as c_int)
2408 {
2409 io::buf_ccat(buf, b'(');
2410 }
2411 cur = c.c1;
2412 continue;
2413 }
2414 _ => {}
2415 }
2416
2417 while cur != content {
2419 let ccur = unsafe { &*cur };
2420 let parent = ccur.parent;
2421 if parent.is_null() {
2422 return;
2423 }
2424 let p = unsafe { &*parent };
2425 if ((ccur.type_ == XML_ELEMENT_CONTENT_OR as c_int
2426 || ccur.type_ == XML_ELEMENT_CONTENT_SEQ as c_int)
2427 && (ccur.type_ != p.type_ || ccur.ocur != XML_ELEMENT_CONTENT_ONCE as c_int))
2428 {
2429 io::buf_ccat(buf, b')');
2430 }
2431 dump_element_occur(buf, ccur.ocur);
2432
2433 if ccur.type_ == XML_ELEMENT_CONTENT_SEQ as c_int {
2434 io::buf_add(buf, b" , " as *const u8, 3);
2435 } else if ccur.type_ == XML_ELEMENT_CONTENT_OR as c_int {
2436 io::buf_add(buf, b" | " as *const u8, 3);
2437 }
2438
2439 if cur == p.c1 {
2440 cur = p.c2;
2441 break;
2442 }
2443 cur = parent;
2444 }
2445 if cur == content {
2446 break;
2447 }
2448 }
2449 io::buf_ccat(buf, b')');
2450 let cc = unsafe { &*content };
2451 dump_element_occur(buf, cc.ocur);
2452}
2453
2454unsafe fn dump_element_decl(buf: *mut _xmlBuffer, elem: *mut _xmlElement) {
2460 use crate::abi::types::xmlElementTypeVal::*;
2461 let e = unsafe { &*elem };
2462 io::buf_add(buf, b"<!ELEMENT " as *const u8, 10);
2463 if !e.prefix.is_null() {
2464 io::buf_cat(buf, e.prefix);
2465 io::buf_ccat(buf, b':');
2466 }
2467 if !e.name.is_null() {
2468 io::buf_cat(buf, e.name);
2469 }
2470 io::buf_ccat(buf, b' ');
2471 match e.type_ {
2472 t if t == XML_ELEMENT_TYPE_EMPTY as c_int => {
2473 io::buf_add(buf, b"EMPTY" as *const u8, 5);
2474 }
2475 t if t == XML_ELEMENT_TYPE_ANY as c_int => {
2476 io::buf_add(buf, b"ANY" as *const u8, 3);
2477 }
2478 t if t == XML_ELEMENT_TYPE_MIXED as c_int || t == XML_ELEMENT_TYPE_ELEMENT as c_int => {
2479 dump_element_content(buf, e.content);
2480 }
2481 _ => {}
2482 }
2483 io::buf_add(buf, b">\n" as *const u8, 2);
2484}
2485
2486unsafe fn dump_enumeration(buf: *mut _xmlBuffer, cur: *mut _xmlEnumeration) {
2492 let mut e = cur;
2493 while !e.is_null() {
2494 let en = unsafe { &*e };
2495 if !en.name.is_null() {
2496 io::buf_cat(buf, en.name);
2497 }
2498 if !en.next.is_null() {
2499 io::buf_add(buf, b" | " as *const u8, 3);
2500 }
2501 e = en.next;
2502 }
2503 io::buf_ccat(buf, b')');
2504}
2505
2506unsafe fn dump_attribute_decl(buf: *mut _xmlBuffer, attr: *mut _xmlAttribute) {
2512 use crate::abi::types::xmlAttributeDefault::*;
2513 use crate::abi::types::xmlAttributeType::*;
2514 let a = unsafe { &*attr };
2515 io::buf_add(buf, b"<!ATTLIST " as *const u8, 10);
2516 if !a.elem.is_null() {
2517 io::buf_cat(buf, a.elem);
2518 }
2519 io::buf_ccat(buf, b' ');
2520 if !a.prefix.is_null() {
2521 io::buf_cat(buf, a.prefix);
2522 io::buf_ccat(buf, b':');
2523 }
2524 if !a.name.is_null() {
2525 io::buf_cat(buf, a.name);
2526 }
2527 match a.atype {
2528 t if t == XML_ATTRIBUTE_CDATA as c_int => {
2529 io::buf_add(buf, b" CDATA" as *const u8, 6);
2530 }
2531 t if t == XML_ATTRIBUTE_ID as c_int => {
2532 io::buf_add(buf, b" ID" as *const u8, 3);
2533 }
2534 t if t == XML_ATTRIBUTE_IDREF as c_int => {
2535 io::buf_add(buf, b" IDREF" as *const u8, 6);
2536 }
2537 t if t == XML_ATTRIBUTE_IDREFS as c_int => {
2538 io::buf_add(buf, b" IDREFS" as *const u8, 7);
2539 }
2540 t if t == XML_ATTRIBUTE_ENTITY as c_int => {
2541 io::buf_add(buf, b" ENTITY" as *const u8, 7);
2542 }
2543 t if t == XML_ATTRIBUTE_ENTITIES as c_int => {
2544 io::buf_add(buf, b" ENTITIES" as *const u8, 9);
2545 }
2546 t if t == XML_ATTRIBUTE_NMTOKEN as c_int => {
2547 io::buf_add(buf, b" NMTOKEN" as *const u8, 8);
2548 }
2549 t if t == XML_ATTRIBUTE_NMTOKENS as c_int => {
2550 io::buf_add(buf, b" NMTOKENS" as *const u8, 9);
2551 }
2552 t if t == XML_ATTRIBUTE_ENUMERATION as c_int => {
2553 io::buf_add(buf, b" (" as *const u8, 2);
2554 dump_enumeration(buf, a.tree);
2555 }
2556 t if t == XML_ATTRIBUTE_NOTATION as c_int => {
2557 io::buf_add(buf, b" NOTATION (" as *const u8, 11);
2558 dump_enumeration(buf, a.tree);
2559 }
2560 _ => {}
2561 }
2562 match a.def {
2563 t if t == XML_ATTRIBUTE_REQUIRED as c_int => {
2564 io::buf_add(buf, b" #REQUIRED" as *const u8, 10);
2565 }
2566 t if t == XML_ATTRIBUTE_IMPLIED as c_int => {
2567 io::buf_add(buf, b" #IMPLIED" as *const u8, 9);
2568 }
2569 t if t == XML_ATTRIBUTE_FIXED as c_int => {
2570 io::buf_add(buf, b" #FIXED" as *const u8, 7);
2571 }
2572 _ => {}
2573 }
2574 if !a.defaultValue.is_null() {
2575 io::buf_add(buf, b" \"" as *const u8, 2);
2576 serialize_attr_value(buf, a.defaultValue);
2577 io::buf_ccat(buf, b'"');
2578 }
2579 io::buf_add(buf, b">\n" as *const u8, 2);
2580}
2581
2582unsafe fn write_quoted_string(buf: *mut _xmlBuffer, str: *const xmlChar) {
2588 if buf.is_null() {
2589 return;
2590 }
2591 io::buf_ccat(buf, b'"');
2592 if !str.is_null() {
2593 let mut i = 0usize;
2594 while unsafe { *str.add(i) != 0 } {
2595 let ch = unsafe { *str.add(i) };
2596 if ch == b'"' {
2597 io::buf_add(buf, b""" as *const u8, 6);
2598 } else {
2599 io::buf_add(buf, &ch as *const u8, 1);
2600 }
2601 i += 1;
2602 }
2603 }
2604 io::buf_ccat(buf, b'"');
2605}
2606
2607unsafe fn dump_entity_decl(buf: *mut _xmlBuffer, ent: *mut _xmlEntity) {
2613 use crate::abi::types::xmlEntityType::*;
2614 let e = unsafe { &*ent };
2615 if e.etype == XML_INTERNAL_PARAMETER_ENTITY as c_int
2616 || e.etype == XML_EXTERNAL_PARAMETER_ENTITY as c_int
2617 {
2618 io::buf_add(buf, b"<!ENTITY % " as *const u8, 11);
2619 } else {
2620 io::buf_add(buf, b"<!ENTITY " as *const u8, 9);
2621 }
2622 if !e.name.is_null() {
2623 io::buf_cat(buf, e.name);
2624 }
2625 io::buf_ccat(buf, b' ');
2626
2627 if e.etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY as c_int
2628 || e.etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int
2629 || e.etype == XML_EXTERNAL_PARAMETER_ENTITY as c_int
2630 {
2631 if !e.ExternalID.is_null() {
2632 io::buf_add(buf, b"PUBLIC " as *const u8, 7);
2633 write_quoted_string(buf, e.ExternalID);
2634 io::buf_ccat(buf, b' ');
2635 } else {
2636 io::buf_add(buf, b"SYSTEM " as *const u8, 7);
2637 }
2638 write_quoted_string(buf, e.SystemID);
2639 }
2640
2641 if e.etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int {
2642 if !e.content.is_null() {
2643 io::buf_add(buf, b" NDATA " as *const u8, 7);
2644 if !e.orig.is_null() {
2645 io::buf_cat(buf, e.orig);
2646 } else if !e.content.is_null() {
2647 io::buf_cat(buf, e.content);
2648 }
2649 }
2650 }
2651
2652 if e.etype == XML_INTERNAL_GENERAL_ENTITY as c_int
2653 || e.etype == XML_INTERNAL_PARAMETER_ENTITY as c_int
2654 {
2655 if !e.orig.is_null() {
2656 write_quoted_string(buf, e.orig);
2657 } else {
2658 io::buf_ccat(buf, b'"');
2660 if !e.content.is_null() {
2661 let mut i = 0usize;
2662 while unsafe { *e.content.add(i) != 0 } {
2663 let ch = unsafe { *e.content.add(i) };
2664 match ch {
2665 b'"' => io::buf_add(buf, b""" as *const u8, 6),
2666 b'%' => io::buf_add(buf, b"%" as *const u8, 6),
2667 _ => io::buf_add(buf, &ch as *const u8, 1),
2668 };
2669 i += 1;
2670 }
2671 }
2672 io::buf_ccat(buf, b'"');
2673 }
2674 }
2675 io::buf_add(buf, b">\n" as *const u8, 2);
2676}
2677
2678unsafe fn dtd_dump_output(
2684 buf: *mut _xmlBuffer,
2685 cur: *mut _xmlNode,
2686 state: &mut DumpState,
2687 level: &mut c_int,
2688) {
2689 let dtd = cur as *mut _xmlDtd;
2690 let d = unsafe { &*dtd };
2691 io::buf_add(buf, b"<!DOCTYPE " as *const u8, 10);
2692 if !d.name.is_null() {
2693 io::buf_cat(buf, d.name);
2694 }
2695 if !d.ExternalID.is_null() {
2696 io::buf_add(buf, b" PUBLIC " as *const u8, 8);
2697 write_quoted_string(buf, d.ExternalID);
2698 io::buf_ccat(buf, b' ');
2699 write_quoted_string(buf, d.SystemID);
2700 } else if !d.SystemID.is_null() {
2701 io::buf_add(buf, b" SYSTEM " as *const u8, 8);
2702 write_quoted_string(buf, d.SystemID);
2703 }
2704 if d.entities.is_null()
2705 && d.elements.is_null()
2706 && d.attributes.is_null()
2707 && d.notations.is_null()
2708 && d.pentities.is_null()
2709 {
2710 io::buf_ccat(buf, b'>');
2711 return;
2712 }
2713 io::buf_add(buf, b" [\n" as *const u8, 3);
2714 let format = state.format;
2717 let lvl = *level;
2718 state.format = 0;
2719 *level = -1;
2720 let mut child = d.children;
2721 while !child.is_null() {
2722 let ct = unsafe { (*child).type_ };
2723 if ct == XML_ELEMENT_DECL as c_int {
2724 dump_element_decl(buf, child as *mut _xmlElement);
2725 } else if ct == XML_ATTRIBUTE_DECL as c_int {
2726 dump_attribute_decl(buf, child as *mut _xmlAttribute);
2727 } else if ct == XML_ENTITY_DECL as c_int {
2728 dump_entity_decl(buf, child as *mut _xmlEntity);
2729 }
2730 child = unsafe { (*child).next };
2731 }
2732 state.format = format;
2733 *level = lvl;
2734 io::buf_add(buf, b"]>" as *const u8, 2);
2735}
2736
2737unsafe fn doc_content_dump_output(
2746 buf: *mut _xmlBuffer,
2747 cur: *mut _xmlNode,
2748 state: &mut DumpState,
2749 level: &mut c_int,
2750) {
2751 let doc = cur as *mut _xmlDoc;
2752 let d = unsafe { &*doc };
2753
2754 io::buf_add(buf, b"<?xml version=\"" as *const u8, 15);
2757 if !d.version.is_null() {
2758 io::buf_cat(buf, d.version);
2759 } else {
2760 io::buf_add(buf, b"1.0" as *const u8, 3);
2761 }
2762 io::buf_ccat(buf, b'"');
2763 if !d.encoding.is_null() {
2764 io::buf_add(buf, b" encoding=\"" as *const u8, 11);
2765 io::buf_cat(buf, d.encoding);
2766 io::buf_ccat(buf, b'"');
2767 }
2768 match d.standalone {
2769 0 => {
2770 io::buf_add(buf, b" standalone=\"no\"" as *const u8, 16);
2771 }
2772 1 => {
2773 io::buf_add(buf, b" standalone=\"yes\"" as *const u8, 17);
2774 }
2775 _ => {}
2776 }
2777 io::buf_add(buf, b"?>\n" as *const u8, 3);
2778
2779 if !d.children.is_null() {
2780 let mut child = d.children;
2781 while !child.is_null() {
2782 *level = 0;
2783 node_dump_internal(buf, child, child, cur, state, level);
2784 let ct = unsafe { (*child).type_ };
2785 if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
2786 io::buf_ccat(buf, b'\n');
2787 }
2788 child = unsafe { (*child).next };
2789 }
2790 }
2791}
2792
2793unsafe fn node_dump_internal(
2817 buf: *mut _xmlBuffer,
2818 cur: *mut _xmlNode,
2819 root: *mut _xmlNode,
2820 parent: *mut _xmlNode,
2821 state: &mut DumpState,
2822 level: &mut c_int,
2823) {
2824 if cur.is_null() || buf.is_null() {
2825 return;
2826 }
2827 let n = unsafe { &*cur };
2828 match n.type_ {
2829 t if t == XML_ELEMENT_NODE as c_int => {
2830 if cur != root && state.format == 1 {
2831 write_indent(buf, *level);
2832 }
2833 if !n.parent.is_null() && n.parent != parent && !n.children.is_null() {
2836 let mut sub = DumpState::new(state.format);
2837 let mut sub_level = *level;
2838 node_dump_internal(buf, cur, cur, n.parent, &mut sub, &mut sub_level);
2839 return;
2840 }
2841 io::buf_ccat(buf, b'<');
2843 write_qname(buf, cur);
2844 let mut nsdef = n.nsDef;
2845 while !nsdef.is_null() {
2846 ns_dump_output(buf, nsdef);
2847 nsdef = unsafe { (*nsdef).next };
2848 }
2849 let mut attr = n.properties;
2850 while !attr.is_null() {
2851 attr_dump_output(buf, attr);
2852 attr = unsafe { (*attr).next };
2853 }
2854 if n.children.is_null() {
2855 io::buf_add(buf, b"/>" as *const u8, 2);
2856 } else {
2857 if state.format == 1 {
2858 let mut tmp = n.children;
2861 while !tmp.is_null() {
2862 let tt = unsafe { (*tmp).type_ };
2863 if tt == XML_TEXT_NODE as c_int
2864 || tt == XML_CDATA_SECTION_NODE as c_int
2865 || tt == XML_ENTITY_REF_NODE as c_int
2866 {
2867 state.format = 0;
2868 state.unformatted = cur;
2869 break;
2870 }
2871 tmp = unsafe { (*tmp).next };
2872 }
2873 }
2874 io::buf_ccat(buf, b'>');
2875 if state.format == 1 {
2876 io::buf_ccat(buf, b'\n');
2877 }
2878 if *level >= 0 {
2879 *level += 1;
2880 }
2881 let mut child = n.children;
2882 while !child.is_null() {
2883 node_dump_internal(buf, child, root, cur, state, level);
2884 if state.format == 1 {
2885 let ct = unsafe { (*child).type_ };
2886 if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
2887 io::buf_ccat(buf, b'\n');
2888 }
2889 }
2890 child = unsafe { (*child).next };
2891 }
2892 if *level > 0 {
2894 *level -= 1;
2895 }
2896 if state.format == 1 {
2897 write_indent(buf, *level);
2898 }
2899 io::buf_add(buf, b"</" as *const u8, 2);
2900 write_qname(buf, cur);
2901 io::buf_ccat(buf, b'>');
2902 if cur == state.unformatted {
2903 state.format = state.saved;
2904 state.unformatted = ptr::null_mut();
2905 }
2906 }
2907 }
2908 t if t == XML_TEXT_NODE as c_int => {
2909 if !n.content.is_null() {
2910 if is_noenc_text(cur) {
2911 io::buf_cat(buf, n.content);
2912 } else {
2913 serialize_text(buf, n.content, xml_strlen(n.content));
2914 }
2915 }
2916 }
2917 t if t == XML_CDATA_SECTION_NODE as c_int => {
2918 if n.content.is_null() || unsafe { *n.content == 0 } {
2919 io::buf_add(buf, b"<![CDATA[]]>" as *const u8, 12);
2920 } else {
2921 let len = xml_strlen(n.content) as usize;
2922 let bytes = core::slice::from_raw_parts(n.content, len);
2923 let mut i = 0usize;
2924 let mut seg_start = 0usize;
2925 while i < len {
2926 if bytes[i] == b']'
2927 && i + 2 < len
2928 && bytes[i + 1] == b']'
2929 && bytes[i + 2] == b'>'
2930 {
2931 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
2932 io::buf_add(buf, n.content.add(seg_start), (i + 2 - seg_start) as c_int);
2933 io::buf_add(buf, b"]]>" as *const u8, 3);
2934 seg_start = i + 2;
2935 i += 3;
2936 continue;
2937 }
2938 i += 1;
2939 }
2940 if seg_start < len {
2941 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
2942 io::buf_add(buf, n.content.add(seg_start), (len - seg_start) as c_int);
2943 io::buf_add(buf, b"]]>" as *const u8, 3);
2944 }
2945 }
2946 }
2947 t if t == XML_COMMENT_NODE as c_int => {
2948 if cur != root && state.format == 1 {
2949 write_indent(buf, *level);
2950 }
2951 if !n.content.is_null() {
2952 io::buf_add(buf, b"<!--" as *const u8, 4);
2953 io::buf_cat(buf, n.content);
2954 io::buf_add(buf, b"-->" as *const u8, 3);
2955 }
2956 }
2957 t if t == XML_PI_NODE as c_int => {
2958 if cur != root && state.format == 1 {
2959 write_indent(buf, *level);
2960 }
2961 io::buf_add(buf, b"<?" as *const u8, 2);
2962 if !n.name.is_null() {
2963 io::buf_cat(buf, n.name);
2964 }
2965 if !n.content.is_null() && unsafe { *n.content != 0 } {
2966 io::buf_ccat(buf, b' ');
2967 io::buf_cat(buf, n.content);
2968 }
2969 io::buf_add(buf, b"?>" as *const u8, 2);
2970 }
2971 t if t == XML_ENTITY_REF_NODE as c_int => {
2972 io::buf_ccat(buf, b'&');
2973 if !n.name.is_null() {
2974 io::buf_cat(buf, n.name);
2975 }
2976 io::buf_ccat(buf, b';');
2977 }
2978 t if t == XML_DOCUMENT_NODE as c_int => {
2979 doc_content_dump_output(buf, cur, state, level);
2980 }
2981 t if t == XML_HTML_DOCUMENT_NODE as c_int => {
2982 crate::xml::html::serialize_node(cur, buf, state.format, *level);
2984 }
2985 t if t == XML_DTD_NODE as c_int => {
2986 dtd_dump_output(buf, cur, state, level);
2987 }
2988 t if t == XML_ATTRIBUTE_NODE as c_int => {
2989 attr_dump_output(buf, cur as *mut _xmlAttr);
2990 }
2991 t if t == XML_NAMESPACE_DECL as c_int => {
2992 ns_dump_output(buf, cur as *mut _xmlNs);
2993 }
2994 t if t == XML_ELEMENT_DECL as c_int => {
2995 dump_element_decl(buf, cur as *mut _xmlElement);
2996 }
2997 t if t == XML_ATTRIBUTE_DECL as c_int => {
2998 dump_attribute_decl(buf, cur as *mut _xmlAttribute);
2999 }
3000 t if t == XML_ENTITY_DECL as c_int => {
3001 dump_entity_decl(buf, cur as *mut _xmlEntity);
3002 }
3003 _ => {}
3004 }
3005}
3006
3007pub(crate) unsafe fn serialize_node(
3021 node: *mut _xmlNode,
3022 buf: *mut _xmlBuffer,
3023 format: c_int,
3024 level: c_int,
3025) {
3026 if node.is_null() || buf.is_null() {
3027 return;
3028 }
3029 let parent = unsafe { (*node).parent };
3030 let mut state = DumpState::new(format);
3031 let mut lvl = level;
3032 node_dump_internal(buf, node, node, parent, &mut state, &mut lvl);
3033}
3034
3035pub(crate) unsafe fn doc_dump(buf: *mut _xmlBuffer, doc: *mut _xmlDoc) -> c_int {
3045 if buf.is_null() || doc.is_null() {
3046 return -1;
3047 }
3048
3049 let before = io::buf_length(buf);
3050 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
3051 let after = io::buf_length(buf);
3052
3053 if after < 0 || before < 0 {
3054 return -1;
3055 }
3056 after - before
3057}
3058
3059pub(crate) unsafe fn node_dump(
3071 buf: *mut _xmlBuffer,
3072 doc: *mut _xmlDoc,
3073 node: *mut _xmlNode,
3074 level: c_int,
3075 format: c_int,
3076) -> c_int {
3077 let _ = doc; if buf.is_null() || node.is_null() {
3079 return -1;
3080 }
3081
3082 let before = io::buf_length(buf);
3083 serialize_node(node, buf, format, level);
3084 let after = io::buf_length(buf);
3085
3086 if after < 0 || before < 0 {
3087 return -1;
3088 }
3089 after - before
3090}
3091
3092pub(crate) unsafe fn save_doc_to_filename(
3099 doc: *mut _xmlDoc,
3100 filename: *const c_char,
3101 compression: c_int,
3102) -> c_int {
3103 if doc.is_null() || filename.is_null() {
3104 return -1;
3105 }
3106
3107 let out = io::output_buffer_create_filename(filename, ptr::null_mut(), compression);
3108 if out.is_null() {
3109 return -1;
3110 }
3111
3112 let buf = io::buf_create(-1);
3113 if buf.is_null() {
3114 io::output_buffer_close(out);
3115 return -1;
3116 }
3117
3118 let ret = doc_dump(buf, doc);
3119 if ret >= 0 {
3120 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
3122 io::output_buffer_flush(out);
3123 }
3124
3125 io::buf_free(buf);
3126 io::output_buffer_close(out);
3127 ret
3128}
3129
3130pub(crate) unsafe fn save_doc_to_fd(doc: *mut _xmlDoc, fd: c_int, compression: c_int) -> c_int {
3137 if doc.is_null() || fd < 0 {
3138 return -1;
3139 }
3140
3141 let out = io::output_buffer_create_fd(fd, ptr::null_mut());
3142 if out.is_null() {
3143 return -1;
3144 }
3145
3146 let buf = io::buf_create(-1);
3147 if buf.is_null() {
3148 io::output_buffer_close(out);
3149 return -1;
3150 }
3151
3152 let ret = doc_dump(buf, doc);
3153 if ret >= 0 {
3154 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
3155 io::output_buffer_flush(out);
3156 }
3157
3158 io::buf_free(buf);
3159 io::output_buffer_close(out);
3160 ret
3161}
3162
3163pub(crate) unsafe fn save_doc_to_buf(
3170 doc: *mut _xmlDoc,
3171 buf: *mut _xmlBuffer,
3172 compression: c_int,
3173) -> c_int {
3174 let _ = compression;
3175 if doc.is_null() || buf.is_null() {
3176 return -1;
3177 }
3178
3179 doc_dump(buf, doc)
3180}
3181
3182pub(crate) unsafe fn save_format_doc_to_buf(
3189 doc: *mut _xmlDoc,
3190 buf: *mut _xmlBuffer,
3191 compression: c_int,
3192) -> c_int {
3193 let _ = compression;
3194 if doc.is_null() || buf.is_null() {
3195 return -1;
3196 }
3197
3198 let before = io::buf_length(buf);
3199 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
3200 let after = io::buf_length(buf);
3201
3202 if after < 0 || before < 0 {
3203 return -1;
3204 }
3205 after - before
3206}
3207
3208pub(crate) unsafe fn dump_node(node: *mut _xmlNode) -> *mut xmlChar {
3217 if node.is_null() {
3218 return ptr::null_mut();
3219 }
3220
3221 let buf = io::buf_create(-1);
3222 if buf.is_null() {
3223 return ptr::null_mut();
3224 }
3225
3226 serialize_node(node, buf, 0, 0);
3227
3228 let content = io::buf_content(buf);
3229 if content.is_null() {
3230 io::buf_free(buf);
3231 return ptr::null_mut();
3232 }
3233
3234 let result = dup_xml_str(content);
3236 io::buf_free(buf);
3237 result
3238}
3239
3240pub unsafe fn dump_doc(doc: *mut _xmlDoc) -> *mut xmlChar {
3249 if doc.is_null() {
3250 return ptr::null_mut();
3251 }
3252
3253 let buf = io::buf_create(-1);
3254 if buf.is_null() {
3255 return ptr::null_mut();
3256 }
3257
3258 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
3259
3260 let content = io::buf_content(buf);
3261 if content.is_null() {
3262 io::buf_free(buf);
3263 return ptr::null_mut();
3264 }
3265
3266 let result = dup_xml_str(content);
3267 io::buf_free(buf);
3268 result
3269}
3270
3271pub(crate) unsafe fn xmlNodeDump(
3287 buf: *mut _xmlBuffer,
3288 doc: *mut _xmlDoc,
3289 node: *mut _xmlNode,
3290 level: c_int,
3291 format: c_int,
3292) -> c_int {
3293 node_dump(buf, doc, node, level, format)
3294}
3295
3296pub(crate) unsafe fn xmlDocDump(fp: *mut c_void, doc: *mut _xmlDoc) -> c_int {
3309 if fp.is_null() || doc.is_null() {
3310 return -1;
3311 }
3312
3313 let buf = io::buf_create(-1);
3314 if buf.is_null() {
3315 return -1;
3316 }
3317
3318 let ret = doc_dump(buf, doc);
3319 if ret < 0 {
3320 io::buf_free(buf);
3321 return -1;
3322 }
3323
3324 let content = io::buf_content(buf);
3325 let len = io::buf_length(buf);
3326 if !content.is_null() && len > 0 {
3327 let written = libc::fwrite(
3328 content as *const c_void,
3329 1,
3330 len as usize,
3331 fp as *mut libc::FILE,
3332 );
3333 io::buf_free(buf);
3334 written as c_int
3335 } else {
3336 io::buf_free(buf);
3337 0
3338 }
3339}
3340
3341pub(crate) unsafe fn xmlDocDumpFormatMemory(
3355 doc: *mut _xmlDoc,
3356 mem: *mut *mut xmlChar,
3357 size: *mut c_int,
3358 format: c_int,
3359) {
3360 if doc.is_null() || mem.is_null() || size.is_null() {
3361 return;
3362 }
3363
3364 let buf = io::buf_create(-1);
3365 if buf.is_null() {
3366 unsafe {
3367 *mem = ptr::null_mut();
3368 *size = 0;
3369 }
3370 return;
3371 }
3372
3373 serialize_node(doc as *mut _xmlNode, buf, format, 0);
3374
3375 let content = io::buf_content(buf);
3376 let len = io::buf_length(buf);
3377
3378 if !content.is_null() && len > 0 {
3379 let result = allocator::xmlMalloc((len + 1) as usize) as *mut xmlChar;
3381 if !result.is_null() {
3382 ptr::copy_nonoverlapping(content, result, len as usize);
3383 *result.add(len as usize) = 0;
3384 unsafe {
3385 *mem = result;
3386 *size = len;
3387 }
3388 } else {
3389 unsafe {
3390 *mem = ptr::null_mut();
3391 *size = 0;
3392 }
3393 }
3394 } else {
3395 unsafe {
3396 *mem = ptr::null_mut();
3397 *size = 0;
3398 }
3399 }
3400
3401 io::buf_free(buf);
3402}
3403
3404pub(crate) unsafe fn xmlDocDumpMemory(doc: *mut _xmlDoc, mem: *mut *mut xmlChar, size: *mut c_int) {
3418 xmlDocDumpFormatMemory(doc, mem, size, 0)
3419}
3420
3421pub(crate) unsafe fn xmlSaveFile(filename: *const c_char, cur: *mut _xmlDoc) -> c_int {
3434 save_doc_to_filename(cur, filename, 0)
3435}
3436
3437pub(crate) unsafe fn xmlSaveFileEnc(
3451 filename: *const c_char,
3452 cur: *mut _xmlDoc,
3453 encoding: *const c_char,
3454) -> c_int {
3455 let _ = encoding; save_doc_to_filename(cur, filename, 0)
3457}
3458
3459pub(crate) unsafe fn xmlSaveFormatFile(
3472 filename: *const c_char,
3473 cur: *mut _xmlDoc,
3474 format: c_int,
3475) -> c_int {
3476 let _ = format;
3477 save_doc_to_filename(cur, filename, 0)
3478}
3479
3480pub(crate) unsafe fn xmlSaveFormatFileEnc(
3494 filename: *const c_char,
3495 cur: *mut _xmlDoc,
3496 encoding: *const c_char,
3497 format: c_int,
3498) -> c_int {
3499 let _ = encoding;
3500 let _ = format;
3501 save_doc_to_filename(cur, filename, 0)
3502}
3503
3504pub(crate) unsafe fn xmlGetDocCompressMode(doc: *mut _xmlDoc) -> c_int {
3516 if doc.is_null() {
3517 return -1;
3518 }
3519 unsafe { (*doc).compression }
3520}
3521
3522pub(crate) unsafe fn xmlSetDocCompressMode(doc: *mut _xmlDoc, mode: c_int) {
3534 if doc.is_null() {
3535 return;
3536 }
3537 unsafe {
3538 (*doc).compression = mode;
3539 }
3540}
3541
3542#[cfg(test)]
3543mod tests {
3544 use super::*;
3545 use core::ffi::c_void;
3546
3547 fn c_str(s: &str) -> *const xmlChar {
3548 let bytes = s.as_bytes();
3549 let buf = unsafe { allocator::xmlMalloc(bytes.len() + 1) as *mut u8 };
3550 if !buf.is_null() {
3551 unsafe {
3552 ptr::copy_nonoverlapping(bytes.as_ptr(), buf, bytes.len());
3553 *buf.add(bytes.len()) = 0;
3554 }
3555 }
3556 buf as *const xmlChar
3557 }
3558
3559 #[test]
3560 fn test_new_free_doc() {
3561 unsafe {
3562 let doc = new_doc(ptr::null());
3563 assert!(!doc.is_null());
3564 assert_eq!((*doc).type_, XML_DOCUMENT_NODE as c_int);
3565 assert_eq!((*doc).standalone, -1);
3566 assert_eq!((*doc).doc, doc);
3567 assert!(!(*doc).version.is_null());
3568 free_doc(doc);
3569 }
3570 }
3571
3572 #[test]
3573 fn test_new_doc_with_version() {
3574 unsafe {
3575 let ver = c_str("2.0");
3576 let doc = new_doc(ver);
3577 assert!(!doc.is_null());
3578 let doc_ver = (*doc).version;
3579 assert!(!doc_ver.is_null());
3580 assert!(crate::abi::exports_xml2::xmlStrEqual(doc_ver, ver,) != 0);
3581 allocator::xmlFree(ver as *mut c_void);
3582 free_doc(doc);
3583 }
3584 }
3585
3586 #[test]
3587 fn test_new_node() {
3588 unsafe {
3589 let doc = new_doc(ptr::null());
3590 let node = new_node(ptr::null_mut(), c_str("root"));
3591 assert!(!node.is_null());
3592 assert_eq!((*node).type_, XML_ELEMENT_NODE as c_int);
3593 assert!(!(*node).name.is_null());
3594 free_node(node);
3595 free_doc(doc);
3596 }
3597 }
3598
3599 #[test]
3600 fn test_node_get_content_recurses_descendants() {
3601 unsafe {
3606 let doc = new_doc(ptr::null());
3607 let root = new_node(ptr::null_mut(), c_str("library"));
3608 doc_set_root_element(doc, root);
3609 let book = new_child(root, ptr::null_mut(), c_str("book"));
3610 let title = new_child(book, ptr::null_mut(), c_str("title"));
3611 let text = new_text(c_str("Rust"));
3612 add_child(title, text);
3613
3614 let content = node_get_content(book);
3615 assert!(!content.is_null());
3616 let s = core::slice::from_raw_parts(
3617 content,
3618 libc::strlen(content as *const libc::c_char) as usize,
3619 );
3620 assert_eq!(s, b"Rust", "descendant text not concatenated");
3621 allocator::xmlFree(content as *mut c_void);
3622
3623 free_doc(doc);
3624 }
3625 }
3626
3627 #[test]
3628 fn test_doc_set_root_element() {
3629 unsafe {
3630 let doc = new_doc(ptr::null());
3631 let root = new_node(ptr::null_mut(), c_str("root"));
3632 let old = doc_set_root_element(doc, root);
3633 assert!(old.is_null());
3634 assert_eq!(doc_get_root_element(doc), root);
3635 assert_eq!((*doc).children, root as *mut _xmlNode);
3636 free_doc(doc);
3637 }
3638 }
3639
3640 #[test]
3641 fn test_add_child_and_sibling() {
3642 unsafe {
3643 let doc = new_doc(ptr::null());
3644 let root = new_node(ptr::null_mut(), c_str("root"));
3645 doc_set_root_element(doc, root);
3646
3647 let child1 = new_child(root, ptr::null_mut(), c_str("child1"));
3648 assert!(!child1.is_null());
3649 assert_eq!((*child1).parent, root);
3650 assert_eq!((*root).children, child1);
3651 assert_eq!((*root).last, child1);
3652
3653 let child2 = new_child(root, ptr::null_mut(), c_str("child2"));
3654 assert!(!child2.is_null());
3655 assert_eq!((*child2).parent, root);
3656 assert_eq!((*child1).next, child2);
3657 assert_eq!((*child2).prev, child1);
3658 assert_eq!((*root).last, child2);
3659
3660 let sibling = new_node(ptr::null_mut(), c_str("sibling"));
3662 add_sibling(child2, sibling);
3663 assert_eq!((*child2).next, sibling);
3664 assert_eq!((*sibling).prev, child2);
3665 assert_eq!((*root).last, sibling);
3666
3667 free_doc(doc);
3668 }
3669 }
3670
3671 #[test]
3672 fn test_unlink_node() {
3673 unsafe {
3674 let doc = new_doc(ptr::null());
3675 let root = new_node(ptr::null_mut(), c_str("root"));
3676 doc_set_root_element(doc, root);
3677
3678 let child1 = new_child(root, ptr::null_mut(), c_str("c1"));
3679 let child2 = new_child(root, ptr::null_mut(), c_str("c2"));
3680
3681 unlink_node(child1);
3682 assert!((*child1).parent.is_null());
3683 assert!((*child1).prev.is_null());
3684 assert!((*child1).next.is_null());
3685 assert_eq!((*root).children, child2);
3686 assert_eq!((*root).last, child2);
3687
3688 free_node(child1);
3689 free_doc(doc);
3690 }
3691 }
3692
3693 #[test]
3694 fn test_text_and_comment_nodes() {
3695 unsafe {
3696 let text = new_text(c_str("hello world"));
3697 assert!(!text.is_null());
3698 assert_eq!((*text).type_, XML_TEXT_NODE as c_int);
3699 assert!(!(*text).content.is_null());
3700 free_node(text);
3701
3702 let comment = new_comment(c_str("my comment"));
3703 assert!(!comment.is_null());
3704 assert_eq!((*comment).type_, XML_COMMENT_NODE as c_int);
3705 free_node(comment);
3706
3707 let pi = new_pi(c_str("xml"), c_str("version='1.0'"));
3708 assert!(!pi.is_null());
3709 assert_eq!((*pi).type_, XML_PI_NODE as c_int);
3710 free_node(pi);
3711 }
3712 }
3713
3714 #[test]
3715 fn test_set_and_get_prop() {
3716 unsafe {
3717 let doc = new_doc(ptr::null());
3718 let root = new_node(ptr::null_mut(), c_str("root"));
3719 doc_set_root_element(doc, root);
3720
3721 let attr = set_prop(root, c_str("id"), c_str("42"));
3722 assert!(!attr.is_null());
3723 assert_eq!((*attr).type_, XML_ATTRIBUTE_NODE as c_int);
3724
3725 let value = get_prop(root, c_str("id"));
3726 assert!(!value.is_null());
3727 assert!(crate::abi::exports_xml2::xmlStrEqual(value, c_str("42")) != 0);
3728 allocator::xmlFree(value as *mut c_void);
3729
3730 free_doc(doc);
3731 }
3732 }
3733
3734 #[test]
3735 fn test_remove_prop() {
3736 unsafe {
3737 let doc = new_doc(ptr::null());
3738 let root = new_node(ptr::null_mut(), c_str("root"));
3739 doc_set_root_element(doc, root);
3740
3741 set_prop(root, c_str("a"), c_str("1"));
3742 set_prop(root, c_str("b"), c_str("2"));
3743
3744 let value = get_prop(root, c_str("a"));
3745 assert!(!value.is_null());
3746 allocator::xmlFree(value as *mut c_void);
3747
3748 let attr = (*root).properties;
3750 assert!(!attr.is_null());
3751 let result = remove_prop(attr);
3752 assert_eq!(result, 0);
3753
3754 let value2 = get_prop(root, c_str("a"));
3756 assert!(value2.is_null());
3757
3758 free_doc(doc);
3759 }
3760 }
3761
3762 #[test]
3763 fn test_namespace_operations() {
3764 unsafe {
3765 let doc = new_doc(ptr::null());
3766 let root = new_node(ptr::null_mut(), c_str("root"));
3767 doc_set_root_element(doc, root);
3768
3769 let ns = new_ns(root, c_str("http://example.com"), c_str("ex"));
3770 assert!(!ns.is_null());
3771 assert!(!(*root).nsDef.is_null());
3772
3773 set_ns(root, ns);
3774 assert_eq!((*root).ns, ns);
3775
3776 let found = search_ns(doc, root, c_str("ex"));
3777 assert_eq!(found, ns);
3778
3779 let found_href = search_ns_by_href(doc, root, c_str("http://example.com"));
3780 assert_eq!(found_href, ns);
3781
3782 free_doc(doc);
3783 }
3784 }
3785
3786 #[test]
3787 fn test_new_dtd() {
3788 unsafe {
3789 let doc = new_doc(ptr::null());
3790 let dtd = new_dtd(doc, c_str("root"), c_str("-//TEST//DTD"), c_str("test.dtd"));
3791 assert!(!dtd.is_null());
3792 assert_eq!((*dtd).type_, XML_DTD_NODE as c_int);
3793 assert_eq!(get_int_subset(doc), dtd);
3794 free_doc(doc);
3795 }
3796 }
3797
3798 #[test]
3799 fn test_copy_node_deep() {
3800 unsafe {
3801 let doc = new_doc(ptr::null());
3802 let root = new_node(ptr::null_mut(), c_str("root"));
3803 doc_set_root_element(doc, root);
3804 let child = new_child(root, ptr::null_mut(), c_str("child"));
3805
3806 let copy = copy_node(root, 1);
3807 assert!(!copy.is_null());
3808 assert_eq!((*copy).type_, XML_ELEMENT_NODE as c_int);
3809 assert!(!(*copy).children.is_null());
3811 assert_eq!((*(*copy).children).type_, XML_ELEMENT_NODE as c_int);
3812
3813 free_node(copy);
3814 free_doc(doc);
3815 }
3816 }
3817
3818 #[test]
3819 fn test_new_cdata_block() {
3820 unsafe {
3821 let doc = new_doc(ptr::null());
3822 let content = c_str("some <cdata> content");
3823 let cdata = new_cdata_block(doc, content, 20);
3824 assert!(!cdata.is_null());
3825 assert_eq!((*cdata).type_, XML_CDATA_SECTION_NODE as c_int);
3826 free_node(cdata);
3827 free_doc(doc);
3828 }
3829 }
3830
3831 #[test]
3832 fn test_null_handling() {
3833 unsafe {
3834 assert!(new_doc(ptr::null()).is_null() == false); let doc = new_doc(ptr::null());
3836 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());
3841 assert!(add_sibling(ptr::null_mut(), ptr::null_mut()).is_null());
3842 free_doc(doc);
3843 }
3844 }
3845
3846 unsafe fn buf_eq_str(buf: *mut _xmlBuffer, expected: &str) -> bool {
3852 let content = io::buf_content(buf);
3853 if content.is_null() {
3854 return expected.is_empty();
3855 }
3856 let len = io::buf_length(buf) as usize;
3857 if len != expected.len() {
3858 return false;
3859 }
3860 let slice = unsafe { core::slice::from_raw_parts(content, len) };
3861 slice == expected.as_bytes()
3862 }
3863
3864 #[test]
3865 fn test_serialize_empty_document() {
3866 unsafe {
3867 let doc = new_doc(ptr::null());
3868 let buf = io::buf_create(-1);
3869 assert!(!buf.is_null());
3870
3871 let ret = doc_dump(buf, doc);
3872 assert!(ret >= 0);
3873
3874 let expected = "<?xml version=\"1.0\"?>\n";
3878 assert!(buf_eq_str(buf, expected));
3879
3880 io::buf_free(buf);
3881 free_doc(doc);
3882 }
3883 }
3884
3885 #[test]
3886 fn test_serialize_element_with_text() {
3887 unsafe {
3888 let doc = new_doc(ptr::null());
3889 let root = new_node(ptr::null_mut(), c_str("root"));
3890 doc_set_root_element(doc, root);
3891
3892 let text = new_text(c_str("hello world"));
3894 add_child(root, text);
3895
3896 let buf = io::buf_create(-1);
3897 assert!(!buf.is_null());
3898
3899 let ret = doc_dump(buf, doc);
3900 assert!(ret >= 0);
3901
3902 let expected = "<?xml version=\"1.0\"?>\n<root>hello world</root>\n";
3903 assert!(buf_eq_str(buf, expected));
3904
3905 io::buf_free(buf);
3906 free_doc(doc);
3907 }
3908 }
3909
3910 #[test]
3911 fn test_serialize_element_with_attributes() {
3912 unsafe {
3913 let doc = new_doc(ptr::null());
3914 let root = new_node(ptr::null_mut(), c_str("root"));
3915 doc_set_root_element(doc, root);
3916
3917 set_prop(root, c_str("id"), c_str("42"));
3918 set_prop(root, c_str("name"), c_str("test"));
3919
3920 let buf = io::buf_create(-1);
3921 assert!(!buf.is_null());
3922
3923 let ret = doc_dump(buf, doc);
3924 assert!(ret >= 0);
3925
3926 let expected = "<?xml version=\"1.0\"?>\n<root id=\"42\" name=\"test\"/>\n";
3927 assert!(buf_eq_str(buf, expected));
3928
3929 io::buf_free(buf);
3930 free_doc(doc);
3931 }
3932 }
3933
3934 #[test]
3935 fn test_serialize_nested_elements() {
3936 unsafe {
3937 let doc = new_doc(ptr::null());
3938 let root = new_node(ptr::null_mut(), c_str("root"));
3939 doc_set_root_element(doc, root);
3940
3941 let child = new_child(root, ptr::null_mut(), c_str("child"));
3942 let grandchild = new_child(child, ptr::null_mut(), c_str("gc"));
3943 let text = new_text(c_str("text"));
3944 add_child(grandchild, text);
3945
3946 let buf = io::buf_create(-1);
3947 assert!(!buf.is_null());
3948
3949 let ret = doc_dump(buf, doc);
3950 assert!(ret >= 0);
3951
3952 let expected = "<?xml version=\"1.0\"?>\n<root><child><gc>text</gc></child></root>\n";
3953 assert!(buf_eq_str(buf, expected));
3954
3955 io::buf_free(buf);
3956 free_doc(doc);
3957 }
3958 }
3959
3960 #[test]
3961 fn test_serialize_with_formatting() {
3962 unsafe {
3963 let doc = new_doc(ptr::null());
3964 let root = new_node(ptr::null_mut(), c_str("root"));
3965 doc_set_root_element(doc, root);
3966
3967 let child = new_child(root, ptr::null_mut(), c_str("child"));
3968 let text = new_text(c_str("text"));
3969 add_child(child, text);
3970
3971 let buf = io::buf_create(-1);
3972 assert!(!buf.is_null());
3973
3974 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
3975
3976 let expected = "<?xml version=\"1.0\"?>\n<root>\n <child>text</child>\n</root>\n";
3977 assert!(buf_eq_str(buf, expected));
3978
3979 io::buf_free(buf);
3980 free_doc(doc);
3981 }
3982 }
3983
3984 #[test]
3985 fn test_serialize_escape_ampersand() {
3986 unsafe {
3987 let doc = new_doc(ptr::null());
3988 let root = new_node(ptr::null_mut(), c_str("root"));
3989 doc_set_root_element(doc, root);
3990
3991 let text = new_text(c_str("a & b"));
3992 add_child(root, text);
3993
3994 let buf = io::buf_create(-1);
3995 assert!(!buf.is_null());
3996
3997 let ret = doc_dump(buf, doc);
3998 assert!(ret >= 0);
3999
4000 let expected = "<?xml version=\"1.0\"?>\n<root>a & b</root>\n";
4001 assert!(buf_eq_str(buf, expected));
4002
4003 io::buf_free(buf);
4004 free_doc(doc);
4005 }
4006 }
4007
4008 #[test]
4009 fn test_serialize_escape_angle_brackets() {
4010 unsafe {
4011 let doc = new_doc(ptr::null());
4012 let root = new_node(ptr::null_mut(), c_str("root"));
4013 doc_set_root_element(doc, root);
4014
4015 let text = new_text(c_str("x < y > z"));
4016 add_child(root, text);
4017
4018 let buf = io::buf_create(-1);
4019 assert!(!buf.is_null());
4020
4021 let ret = doc_dump(buf, doc);
4022 assert!(ret >= 0);
4023
4024 let expected = "<?xml version=\"1.0\"?>\n<root>x < y > z</root>\n";
4025 assert!(buf_eq_str(buf, expected));
4026
4027 io::buf_free(buf);
4028 free_doc(doc);
4029 }
4030 }
4031
4032 #[test]
4033 fn test_serialize_comment() {
4034 unsafe {
4035 let doc = new_doc(ptr::null());
4036 let root = new_node(ptr::null_mut(), c_str("root"));
4037 doc_set_root_element(doc, root);
4038
4039 let comment = new_comment(c_str("my comment"));
4040 add_child(root, comment);
4041
4042 let buf = io::buf_create(-1);
4043 assert!(!buf.is_null());
4044
4045 let ret = doc_dump(buf, doc);
4046 assert!(ret >= 0);
4047
4048 let expected = "<?xml version=\"1.0\"?>\n<root><!--my comment--></root>\n";
4049 assert!(buf_eq_str(buf, expected));
4050
4051 io::buf_free(buf);
4052 free_doc(doc);
4053 }
4054 }
4055
4056 #[test]
4057 fn test_serialize_pi() {
4058 unsafe {
4059 let doc = new_doc(ptr::null());
4060 let root = new_node(ptr::null_mut(), c_str("root"));
4061 doc_set_root_element(doc, root);
4062
4063 let pi = new_pi(
4064 c_str("xml-stylesheet"),
4065 c_str("href=\"style.xsl\" type=\"text/xsl\""),
4066 );
4067 add_child(root, pi);
4068
4069 let buf = io::buf_create(-1);
4070 assert!(!buf.is_null());
4071
4072 let ret = doc_dump(buf, doc);
4073 assert!(ret >= 0);
4074
4075 let expected = "<?xml version=\"1.0\"?>\n<root><?xml-stylesheet href=\"style.xsl\" type=\"text/xsl\"?></root>\n";
4076 assert!(buf_eq_str(buf, expected));
4077
4078 io::buf_free(buf);
4079 free_doc(doc);
4080 }
4081 }
4082
4083 #[test]
4084 fn test_serialize_self_closing() {
4085 unsafe {
4086 let doc = new_doc(ptr::null());
4087 let root = new_node(ptr::null_mut(), c_str("empty"));
4088 doc_set_root_element(doc, root);
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<empty/>\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_dump_node_to_string() {
4106 unsafe {
4107 let node = new_node(ptr::null_mut(), c_str("foo"));
4108 let text = new_text(c_str("bar"));
4109 add_child(node, text);
4110
4111 let result = dump_node(node);
4112 assert!(!result.is_null());
4113
4114 let len = xml_strlen(result);
4115 let slice = unsafe { core::slice::from_raw_parts(result, len as usize) };
4116 assert_eq!(slice, b"<foo>bar</foo>");
4117
4118 allocator::xmlFree(result as *mut c_void);
4119 free_node(node);
4120 }
4121 }
4122
4123 #[test]
4124 fn test_dump_doc_to_string() {
4125 unsafe {
4126 let doc = new_doc(ptr::null());
4127 let root = new_node(ptr::null_mut(), c_str("root"));
4128 doc_set_root_element(doc, root);
4129
4130 let result = dump_doc(doc);
4131 assert!(!result.is_null());
4132
4133 let len = xml_strlen(result);
4134 let slice = unsafe { core::slice::from_raw_parts(result, len as usize) };
4135 let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
4136 assert_eq!(slice, expected.as_bytes());
4137
4138 allocator::xmlFree(result as *mut c_void);
4139 free_doc(doc);
4140 }
4141 }
4142
4143 #[test]
4144 fn test_xmlDocDumpFormatMemory() {
4145 unsafe {
4146 let doc = new_doc(ptr::null());
4147 let root = new_node(ptr::null_mut(), c_str("root"));
4148 doc_set_root_element(doc, root);
4149
4150 let mut mem: *mut xmlChar = ptr::null_mut();
4151 let mut size: c_int = 0;
4152
4153 xmlDocDumpFormatMemory(doc, &mut mem, &mut size, 0);
4154
4155 assert!(!mem.is_null());
4156 assert!(size > 0);
4157
4158 let slice = unsafe { core::slice::from_raw_parts(mem, size as usize) };
4159 let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
4162 assert_eq!(slice, expected.as_bytes());
4163
4164 allocator::xmlFree(mem as *mut c_void);
4165 free_doc(doc);
4166 }
4167 }
4168
4169 #[test]
4170 fn test_serialize_escape_attribute() {
4171 unsafe {
4172 let doc = new_doc(ptr::null());
4173 let root = new_node(ptr::null_mut(), c_str("root"));
4174 doc_set_root_element(doc, root);
4175
4176 set_prop(root, c_str("desc"), c_str("a < b & c \"quoted\""));
4178
4179 let buf = io::buf_create(-1);
4180 assert!(!buf.is_null());
4181
4182 let ret = doc_dump(buf, doc);
4183 assert!(ret >= 0);
4184
4185 let expected =
4186 "<?xml version=\"1.0\"?>\n<root desc=\"a < b & c "quoted"\"/>\n";
4187 assert!(buf_eq_str(buf, expected));
4188
4189 io::buf_free(buf);
4190 free_doc(doc);
4191 }
4192 }
4193}