1use core::ffi::c_void;
37use core::ptr;
38use std::os::raw::{c_char, c_int, c_uint, c_ulong};
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 unsafe fn has_prop(node: *mut _xmlNode, name: *const xmlChar) -> *mut _xmlAttr {
1854 if node.is_null() || name.is_null() {
1855 return ptr::null_mut();
1856 }
1857 let mut cur = unsafe { (*node).properties };
1858 while !cur.is_null() {
1859 let attr = unsafe { &*cur };
1860 if !attr.name.is_null()
1861 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1862 && attr.ns.is_null()
1863 {
1864 return cur;
1865 }
1866 cur = unsafe { (*cur).next };
1867 }
1868 ptr::null_mut()
1869}
1870
1871pub unsafe fn has_ns_prop(
1881 node: *mut _xmlNode,
1882 name: *const xmlChar,
1883 name_space: *const xmlChar,
1884) -> *mut _xmlAttr {
1885 if node.is_null() || name.is_null() {
1886 return ptr::null_mut();
1887 }
1888 let mut cur = unsafe { (*node).properties };
1889 while !cur.is_null() {
1890 let attr = unsafe { &*cur };
1891 if !attr.name.is_null()
1892 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1893 {
1894 if name_space.is_null() {
1895 if attr.ns.is_null() {
1896 return cur;
1897 }
1898 } else if !attr.ns.is_null() && !(*attr.ns).href.is_null() {
1899 if unsafe {
1900 crate::abi::exports_xml2::xmlStrEqual((*attr.ns).href, name_space) != 0
1901 } {
1902 return cur;
1903 }
1904 }
1905 }
1906 cur = unsafe { (*cur).next };
1907 }
1908 ptr::null_mut()
1909}
1910
1911pub unsafe fn unset_prop(node: *mut _xmlNode, name: *const xmlChar) -> c_int {
1920 let attr = unsafe { has_prop(node, name) };
1921 if attr.is_null() {
1922 return -1;
1923 }
1924 unsafe { remove_prop(attr) }
1925}
1926
1927pub unsafe fn unset_ns_prop(
1935 node: *mut _xmlNode,
1936 name: *const xmlChar,
1937 name_space: *const xmlChar,
1938) -> c_int {
1939 let attr = unsafe { has_ns_prop(node, name, name_space) };
1940 if attr.is_null() {
1941 return -1;
1942 }
1943 unsafe { remove_prop(attr) }
1944}
1945
1946pub unsafe fn first_element_child(node: *mut _xmlNode) -> *mut _xmlNode {
1953 if node.is_null() {
1954 return ptr::null_mut();
1955 }
1956 let mut cur = unsafe { (*node).children };
1957 while !cur.is_null() {
1958 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
1959 return cur;
1960 }
1961 cur = unsafe { (*cur).next };
1962 }
1963 ptr::null_mut()
1964}
1965
1966pub unsafe fn last_element_child(node: *mut _xmlNode) -> *mut _xmlNode {
1973 if node.is_null() {
1974 return ptr::null_mut();
1975 }
1976 let mut cur = unsafe { (*node).last };
1977 while !cur.is_null() {
1978 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
1979 return cur;
1980 }
1981 cur = unsafe { (*cur).prev };
1982 }
1983 ptr::null_mut()
1984}
1985
1986pub unsafe fn next_element_sibling(node: *mut _xmlNode) -> *mut _xmlNode {
1993 if node.is_null() {
1994 return ptr::null_mut();
1995 }
1996 let mut cur = unsafe { (*node).next };
1997 while !cur.is_null() {
1998 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
1999 return cur;
2000 }
2001 cur = unsafe { (*cur).next };
2002 }
2003 ptr::null_mut()
2004}
2005
2006pub unsafe fn previous_element_sibling(node: *mut _xmlNode) -> *mut _xmlNode {
2013 if node.is_null() {
2014 return ptr::null_mut();
2015 }
2016 let mut cur = unsafe { (*node).prev };
2017 while !cur.is_null() {
2018 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2019 return cur;
2020 }
2021 cur = unsafe { (*cur).prev };
2022 }
2023 ptr::null_mut()
2024}
2025
2026pub unsafe fn child_element_count(node: *mut _xmlNode) -> c_ulong {
2033 if node.is_null() {
2034 return 0;
2035 }
2036 let mut cur = unsafe { (*node).children };
2037 let mut count: c_ulong = 0;
2038 while !cur.is_null() {
2039 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2040 count += 1;
2041 }
2042 cur = unsafe { (*cur).next };
2043 }
2044 count
2045}
2046
2047pub unsafe fn text_concat(node: *mut _xmlNode, str: *const xmlChar, num: c_int) -> c_int {
2056 if node.is_null() || str.is_null() || num <= 0 {
2057 return -1;
2058 }
2059 let cur = unsafe { &mut *node };
2060 if cur.content.is_null() {
2061 let p = unsafe { allocator::xmlMalloc(num as usize + 1) as *mut xmlChar };
2062 if p.is_null() {
2063 return -1;
2064 }
2065 unsafe {
2066 ptr::copy_nonoverlapping(str, p, num as usize);
2067 *p.add(num as usize) = 0;
2068 }
2069 cur.content = p;
2070 return 0;
2071 }
2072 let old_len = unsafe { crate::xml::string::xml_strlen(cur.content) };
2073 let p = unsafe {
2074 allocator::xmlRealloc(cur.content as *mut c_void, old_len + num as usize + 1)
2075 as *mut xmlChar
2076 };
2077 if p.is_null() {
2078 return -1;
2079 }
2080 unsafe {
2081 ptr::copy_nonoverlapping(str, p.add(old_len), num as usize);
2082 *p.add(old_len + num as usize) = 0;
2083 }
2084 cur.content = p;
2085 0
2086}
2087
2088pub unsafe fn text_merge(text: *mut _xmlNode, ntext: *mut _xmlNode) -> *mut _xmlNode {
2096 if text.is_null() || ntext.is_null() {
2097 return ptr::null_mut();
2098 }
2099 if unsafe { (*ntext).content.is_null() } {
2100 unsafe { free_node(ntext) };
2101 return text;
2102 }
2103 let num = unsafe { crate::xml::string::xml_strlen((*ntext).content) };
2104 if unsafe { text_concat(text, (*ntext).content, num as c_int) } != 0 {
2105 return ptr::null_mut();
2106 }
2107 unsafe { free_node(ntext) };
2108 text
2109}
2110
2111pub fn get_int_subset(doc: *const _xmlDoc) -> *mut _xmlDtd {
2123 if doc.is_null() {
2124 return ptr::null_mut();
2125 }
2126 let d = unsafe { &*doc };
2127 d.intSubset
2128}
2129
2130pub unsafe fn new_dtd(
2147 doc: *mut _xmlDoc,
2148 name: *const xmlChar,
2149 ExternalID: *const xmlChar,
2150 SystemID: *const xmlChar,
2151) -> *mut _xmlDtd {
2152 let dtd = allocator::xmlMallocZero(size_of::<_xmlDtd>() as usize) as *mut _xmlDtd;
2153 if dtd.is_null() {
2154 return ptr::null_mut();
2155 }
2156
2157 unsafe {
2158 (*dtd).type_ = XML_DTD_NODE as c_int;
2159 (*dtd).name = dup_xml_str(name);
2160 (*dtd).ExternalID = dup_xml_str(ExternalID);
2161 (*dtd).SystemID = dup_xml_str(SystemID);
2162 (*dtd).parent = doc;
2163 (*dtd).doc = doc;
2164
2165 (*dtd).notations = crate::xml::hash::hash_create(8) as *mut c_void;
2168 (*dtd).elements = crate::xml::hash::hash_create(16) as *mut c_void;
2169 (*dtd).attributes = crate::xml::hash::hash_create(16) as *mut c_void;
2170 (*dtd).entities = crate::xml::hash::hash_create(8) as *mut c_void;
2171 (*dtd).pentities = crate::xml::hash::hash_create(8) as *mut c_void;
2172
2173 if !doc.is_null() {
2175 if (*doc).intSubset.is_null() {
2176 (*doc).intSubset = dtd;
2177 }
2178 }
2179 }
2180
2181 dtd
2182}
2183
2184unsafe fn free_dtd(dtd: *mut _xmlDtd) {
2190 if dtd.is_null() {
2191 return;
2192 }
2193
2194 let d = unsafe { &mut *dtd };
2195
2196 if !d.name.is_null() {
2198 allocator::xmlFree(d.name as *mut c_void);
2199 }
2200 if !d.ExternalID.is_null() {
2201 allocator::xmlFree(d.ExternalID as *mut c_void);
2202 }
2203 if !d.SystemID.is_null() {
2204 allocator::xmlFree(d.SystemID as *mut c_void);
2205 }
2206
2207 unsafe extern "C" fn free_notation_wrapper(payload: *mut c_void, _name: *mut u8) {
2209 crate::xml::dtd::free_notation(payload as *mut _xmlNotation);
2210 }
2211 unsafe extern "C" fn free_element_wrapper(payload: *mut c_void, _name: *mut u8) {
2212 crate::xml::dtd::free_element(payload as *mut _xmlElement);
2213 }
2214 unsafe extern "C" fn free_attribute_wrapper(payload: *mut c_void, _name: *mut u8) {
2215 crate::xml::dtd::free_attribute(payload as *mut _xmlAttribute);
2216 }
2217 unsafe extern "C" fn free_entity_wrapper(payload: *mut c_void, _name: *mut u8) {
2218 crate::xml::entities::free_entity(payload as *mut _xmlEntity);
2219 }
2220
2221 if !d.notations.is_null() {
2222 crate::xml::hash::hash_free(
2223 d.notations as *mut crate::xml::hash::HashTable,
2224 Some(free_notation_wrapper),
2225 );
2226 d.notations = ptr::null_mut();
2227 }
2228 if !d.elements.is_null() {
2229 crate::xml::hash::hash_free(
2230 d.elements as *mut crate::xml::hash::HashTable,
2231 Some(free_element_wrapper),
2232 );
2233 d.elements = ptr::null_mut();
2234 }
2235 if !d.attributes.is_null() {
2236 crate::xml::hash::hash_free(
2237 d.attributes as *mut crate::xml::hash::HashTable,
2238 Some(free_attribute_wrapper),
2239 );
2240 d.attributes = ptr::null_mut();
2241 }
2242 if !d.entities.is_null() {
2243 crate::xml::hash::hash_free(
2244 d.entities as *mut crate::xml::hash::HashTable,
2245 Some(free_entity_wrapper),
2246 );
2247 d.entities = ptr::null_mut();
2248 }
2249 if !d.pentities.is_null() {
2250 crate::xml::hash::hash_free(
2251 d.pentities as *mut crate::xml::hash::HashTable,
2252 Some(free_entity_wrapper),
2253 );
2254 d.pentities = ptr::null_mut();
2255 }
2256
2257 if !d.children.is_null() {
2259 free_node_list(d.children);
2260 }
2261
2262 allocator::xmlFree(dtd as *mut c_void);
2263}
2264
2265pub unsafe fn new_entity(
2285 _doc: *mut _xmlDoc,
2286 name: *const xmlChar,
2287 etype: c_int,
2288 ExternalID: *const xmlChar,
2289 SystemID: *const xmlChar,
2290 content: *const xmlChar,
2291) -> *mut _xmlEntity {
2292 let entity = allocator::xmlMallocZero(size_of::<_xmlEntity>() as usize) as *mut _xmlEntity;
2293 if entity.is_null() {
2294 return ptr::null_mut();
2295 }
2296
2297 unsafe {
2298 (*entity).type_ = XML_ENTITY_DECL as c_int;
2299 (*entity).name = dup_xml_str(name);
2300 (*entity).etype = etype;
2301 (*entity).ExternalID = dup_xml_str(ExternalID);
2302 (*entity).SystemID = dup_xml_str(SystemID);
2303 (*entity).content = dup_xml_str(content);
2304 (*entity).length = if content.is_null() {
2305 0
2306 } else {
2307 crate::abi::exports_xml2::xmlStrlen(content)
2308 };
2309 (*entity).flags = 0;
2310 (*entity).expandedSize = 0;
2311 }
2312
2313 entity
2314}
2315
2316pub unsafe fn get_doc_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2331 crate::xml::entities::get_entity(doc as *mut _xmlDoc, name)
2332}
2333
2334pub unsafe fn add_doc_entity(
2342 doc: *mut _xmlDoc,
2343 name: *const xmlChar,
2344 etype: c_int,
2345 ExternalID: *const xmlChar,
2346 SystemID: *const xmlChar,
2347 content: *const xmlChar,
2348) -> *mut _xmlEntity {
2349 if doc.is_null() || name.is_null() {
2350 return ptr::null_mut();
2351 }
2352 unsafe {
2353 let mut dtd = (*doc).intSubset;
2354 if dtd.is_null() {
2355 dtd = new_dtd(
2356 doc,
2357 b"internal\0".as_ptr() as *const xmlChar,
2358 ptr::null(),
2359 ptr::null(),
2360 );
2361 if dtd.is_null() {
2362 return ptr::null_mut();
2363 }
2364 }
2365 crate::xml::entities::add_entity(dtd, name, etype, ExternalID, SystemID, content)
2366 }
2367}
2368
2369pub unsafe fn add_dtd_entity(
2377 doc: *mut _xmlDoc,
2378 name: *const xmlChar,
2379 etype: c_int,
2380 ExternalID: *const xmlChar,
2381 SystemID: *const xmlChar,
2382 content: *const xmlChar,
2383) -> *mut _xmlEntity {
2384 if doc.is_null() || name.is_null() {
2385 return ptr::null_mut();
2386 }
2387 unsafe {
2388 let mut dtd = (*doc).extSubset;
2389 if dtd.is_null() {
2390 dtd = new_dtd(
2391 doc,
2392 b"internal\0".as_ptr() as *const xmlChar,
2393 ptr::null(),
2394 ptr::null(),
2395 );
2396 if dtd.is_null() {
2397 return ptr::null_mut();
2398 }
2399 (*doc).extSubset = dtd;
2400 }
2401 crate::xml::entities::add_entity(dtd, name, etype, ExternalID, SystemID, content)
2402 }
2403}
2404
2405pub unsafe fn get_dtd_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2413 if doc.is_null() || name.is_null() {
2414 return ptr::null_mut();
2415 }
2416 unsafe {
2417 if !(*doc).intSubset.is_null() {
2418 let e = crate::xml::entities::get_entity_from_dtd((*doc).intSubset, name);
2419 if !e.is_null() {
2420 return e;
2421 }
2422 }
2423 if !(*doc).extSubset.is_null() {
2424 return crate::xml::entities::get_entity_from_dtd((*doc).extSubset, name);
2425 }
2426 ptr::null_mut()
2427 }
2428}
2429
2430pub unsafe fn get_parameter_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2443 crate::xml::entities::get_parameter_entity(doc as *mut _xmlDoc, name)
2444}
2445
2446const ENTITY_LT: &[xmlChar] = b"<";
2455const ENTITY_GT: &[xmlChar] = b">";
2456const ENTITY_AMP: &[xmlChar] = b"&";
2457const ENTITY_QUOT: &[xmlChar] = b""";
2458const ENTITY_APOS: &[xmlChar] = b"'";
2459
2460const INDENT: &[xmlChar] = b" ";
2462
2463const MAX_INDENT: c_int = 60;
2465
2466pub(crate) unsafe fn serialize_text(buf: *mut _xmlBuffer, content: *const xmlChar, len: c_int) {
2481 if buf.is_null() || content.is_null() || len <= 0 {
2482 return;
2483 }
2484
2485 let mut i: c_int = 0;
2486 while i < len {
2487 let ch = unsafe { *content.add(i as usize) };
2488
2489 if ch == b']'
2491 && i + 2 < len
2492 && unsafe { *content.add(i as usize + 1) == b']' }
2493 && unsafe { *content.add(i as usize + 2) == b'>' }
2494 {
2495 io::buf_add(buf, &ch as *const u8, 2); io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2498 i += 3;
2499 continue;
2500 }
2501
2502 match ch {
2503 b'<' => {
2504 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
2505 }
2506 b'&' => {
2507 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
2508 }
2509 b'>' => {
2510 io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2514 }
2515 b'\r' => {
2516 io::buf_add(buf, b" " as *const u8, 5);
2518 }
2519 0x01..=0x08 | 0x0B | 0x0C | 0x0E..=0x1F => {
2520 let hex = format!("&#x{:X};", ch);
2522 io::buf_add(buf, hex.as_ptr(), hex.len() as c_int);
2523 }
2524 _ => {
2525 io::buf_add(buf, &ch as *const u8, 1);
2526 }
2527 }
2528 i += 1;
2529 }
2530}
2531
2532pub(crate) unsafe fn serialize_attr_value(buf: *mut _xmlBuffer, value: *const xmlChar) {
2545 if buf.is_null() || value.is_null() {
2546 return;
2547 }
2548
2549 let len = xml_strlen(value);
2550 let mut i: c_int = 0;
2551 while i < len {
2552 let ch = unsafe { *value.add(i as usize) };
2553
2554 match ch {
2555 b'\n' => {
2556 io::buf_add(buf, b" " as *const u8, 5);
2557 }
2558 b'\r' => {
2559 io::buf_add(buf, b" " as *const u8, 5);
2560 }
2561 b'\t' => {
2562 io::buf_add(buf, b"	" as *const u8, 4);
2563 }
2564 b'<' => {
2565 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
2566 }
2567 b'&' => {
2568 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
2569 }
2570 b'"' => {
2571 io::buf_add(buf, ENTITY_QUOT.as_ptr(), ENTITY_QUOT.len() as c_int);
2572 }
2573 b'>' => {
2574 io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2575 }
2576 _ => {
2577 io::buf_add(buf, &ch as *const u8, 1);
2578 }
2579 }
2580 i += 1;
2581 }
2582}
2583
2584unsafe fn write_indent(
2596 buf: *mut _xmlBuffer,
2597 level: c_int,
2598 indent: *const xmlChar,
2599 indent_len: c_int,
2600) {
2601 if buf.is_null() || level <= 0 || indent.is_null() || indent_len <= 0 {
2602 return;
2603 }
2604 let indent_nr = MAX_INDENT / indent_len;
2605 let mut lvl = level;
2606 if lvl > indent_nr {
2607 lvl = indent_nr;
2608 }
2609 for _ in 0..lvl {
2610 io::buf_add(buf, indent, indent_len);
2611 }
2612}
2613
2614unsafe fn is_noenc_text(node: *mut _xmlNode) -> bool {
2622 if node.is_null() {
2623 return false;
2624 }
2625 let n = unsafe { &*node };
2626 if n.name.is_null() {
2627 return false;
2628 }
2629 c_str_eq_bytes(n.name, b"textnoenc")
2630}
2631
2632unsafe fn c_str_eq_bytes(s: *const xmlChar, b: &[u8]) -> bool {
2634 let mut i = 0usize;
2635 while i < b.len() {
2636 if unsafe { *s.add(i) } != b[i] {
2637 return false;
2638 }
2639 i += 1;
2640 }
2641 unsafe { *s.add(i) == 0 }
2642}
2643
2644#[derive(Clone, Copy)]
2647struct DumpState {
2648 format: c_int,
2650 saved: c_int,
2653 unformatted: *mut _xmlNode,
2656 indent: *const xmlChar,
2659 indent_len: c_int,
2661 no_decl: c_int,
2663}
2664
2665impl DumpState {
2666 fn new(format: c_int) -> Self {
2667 let f = if format != 0 { 1 } else { 0 };
2668 DumpState {
2669 format: f,
2670 saved: f,
2671 unformatted: ptr::null_mut(),
2672 indent: INDENT.as_ptr(),
2673 indent_len: INDENT.len() as c_int,
2674 no_decl: 0,
2675 }
2676 }
2677
2678 unsafe fn with_indent(format: c_int, indent: *const xmlChar, no_decl: c_int) -> Self {
2686 let f = if format != 0 { 1 } else { 0 };
2687 let (ptr, len) = if indent.is_null() {
2688 (INDENT.as_ptr(), INDENT.len() as c_int)
2689 } else {
2690 let mut n = 0i32;
2691 while unsafe { *indent.add(n as usize) } != 0 {
2692 n += 1;
2693 }
2694 (indent, n)
2695 };
2696 DumpState {
2697 format: f,
2698 saved: f,
2699 unformatted: ptr::null_mut(),
2700 indent: ptr,
2701 indent_len: len,
2702 no_decl,
2703 }
2704 }
2705}
2706
2707unsafe fn write_qname(buf: *mut _xmlBuffer, node: *mut _xmlNode) {
2713 let n = unsafe { &*node };
2714 if !n.ns.is_null() {
2715 let ns = unsafe { &*n.ns };
2716 if !ns.prefix.is_null() {
2717 io::buf_cat(buf, ns.prefix);
2718 io::buf_ccat(buf, b':');
2719 }
2720 }
2721 if !n.name.is_null() {
2722 io::buf_cat(buf, n.name);
2723 }
2724}
2725
2726unsafe fn ns_dump_output(buf: *mut _xmlBuffer, cur: *mut _xmlNs) {
2732 if cur.is_null() || buf.is_null() {
2733 return;
2734 }
2735 let ns = unsafe { &*cur };
2736 if ns.type_ == XML_LOCAL_NAMESPACE as c_int && !ns.href.is_null() {
2737 if !ns.prefix.is_null() && c_str_eq_bytes(ns.prefix, b"xml") {
2739 return;
2740 }
2741 io::buf_ccat(buf, b' ');
2742 if !ns.prefix.is_null() {
2743 io::buf_add(buf, b"xmlns:" as *const u8, 6);
2744 io::buf_cat(buf, ns.prefix);
2745 } else {
2746 io::buf_add(buf, b"xmlns" as *const u8, 5);
2747 }
2748 io::buf_add(buf, b"=\"" as *const u8, 2);
2749 serialize_attr_value(buf, ns.href);
2750 io::buf_ccat(buf, b'"');
2751 }
2752}
2753
2754unsafe fn attr_dump_output(buf: *mut _xmlBuffer, cur: *mut _xmlAttr) {
2760 if cur.is_null() || buf.is_null() {
2761 return;
2762 }
2763 io::buf_ccat(buf, b' ');
2764 let a = unsafe { &*cur };
2765 if !a.ns.is_null() {
2766 let ans = unsafe { &*a.ns };
2767 if !ans.prefix.is_null() {
2768 io::buf_cat(buf, ans.prefix);
2769 io::buf_ccat(buf, b':');
2770 }
2771 }
2772 if !a.name.is_null() {
2773 io::buf_cat(buf, a.name);
2774 }
2775 io::buf_add(buf, b"=\"" as *const u8, 2);
2776 let mut child = a.children;
2779 while !child.is_null() {
2780 let ct = unsafe { (*child).type_ };
2781 if ct == XML_TEXT_NODE as c_int && !unsafe { (*child).content }.is_null() {
2782 serialize_attr_value(buf, unsafe { (*child).content });
2783 } else if ct == XML_ENTITY_REF_NODE as c_int && !unsafe { (*child).name }.is_null() {
2784 io::buf_ccat(buf, b'&');
2785 io::buf_cat(buf, unsafe { (*child).name });
2786 io::buf_ccat(buf, b';');
2787 }
2788 child = unsafe { (*child).next };
2789 }
2790 io::buf_ccat(buf, b'"');
2791}
2792
2793unsafe fn dump_notation_decl(buf: *mut _xmlBuffer, nota: *mut _xmlNotation) {
2799 let n = unsafe { &*nota };
2800 io::buf_add(buf, b"<!NOTATION " as *const u8, 11);
2801 if !n.name.is_null() {
2802 io::buf_cat(buf, n.name);
2803 }
2804 if !n.PublicID.is_null() {
2805 io::buf_add(buf, b" PUBLIC " as *const u8, 8);
2806 write_quoted_string(buf, n.PublicID);
2807 if !n.SystemID.is_null() {
2808 io::buf_ccat(buf, b' ');
2809 write_quoted_string(buf, n.SystemID);
2810 }
2811 } else {
2812 io::buf_add(buf, b" SYSTEM " as *const u8, 8);
2813 write_quoted_string(buf, n.SystemID);
2814 }
2815 io::buf_add(buf, b" >\n" as *const u8, 4);
2816}
2817
2818unsafe fn dump_element_occur(buf: *mut _xmlBuffer, ocur: c_int) {
2820 use crate::abi::types::xmlElementContentOccur::*;
2821 if ocur == XML_ELEMENT_CONTENT_OPT as c_int {
2822 io::buf_ccat(buf, b'?');
2823 } else if ocur == XML_ELEMENT_CONTENT_MULT as c_int {
2824 io::buf_ccat(buf, b'*');
2825 } else if ocur == XML_ELEMENT_CONTENT_PLUS as c_int {
2826 io::buf_ccat(buf, b'+');
2827 }
2828}
2829
2830unsafe fn dump_element_content(buf: *mut _xmlBuffer, content: *mut _xmlElementContent) {
2836 use crate::abi::types::xmlElementContentOccur::*;
2837 use crate::abi::types::xmlElementContentType::*;
2838 if content.is_null() {
2839 return;
2840 }
2841 io::buf_ccat(buf, b'(');
2842 let mut cur = content;
2843 loop {
2844 if cur.is_null() {
2845 return;
2846 }
2847 let c = unsafe { &*cur };
2848 match c.type_ {
2849 t if t == XML_ELEMENT_CONTENT_PCDATA as c_int => {
2850 io::buf_add(buf, b"#PCDATA" as *const u8, 7);
2851 }
2852 t if t == XML_ELEMENT_CONTENT_ELEMENT as c_int => {
2853 if !c.prefix.is_null() {
2854 io::buf_cat(buf, c.prefix);
2855 io::buf_ccat(buf, b':');
2856 }
2857 if !c.name.is_null() {
2858 io::buf_cat(buf, c.name);
2859 }
2860 }
2861 t if t == XML_ELEMENT_CONTENT_SEQ as c_int || t == XML_ELEMENT_CONTENT_OR as c_int => {
2862 if cur != content
2863 && !c.parent.is_null()
2864 && (c.type_ != unsafe { (*c.parent).type_ }
2865 || c.ocur != XML_ELEMENT_CONTENT_ONCE as c_int)
2866 {
2867 io::buf_ccat(buf, b'(');
2868 }
2869 cur = c.c1;
2870 continue;
2871 }
2872 _ => {}
2873 }
2874
2875 while cur != content {
2877 let ccur = unsafe { &*cur };
2878 let parent = ccur.parent;
2879 if parent.is_null() {
2880 return;
2881 }
2882 let p = unsafe { &*parent };
2883 if ((ccur.type_ == XML_ELEMENT_CONTENT_OR as c_int
2884 || ccur.type_ == XML_ELEMENT_CONTENT_SEQ as c_int)
2885 && (ccur.type_ != p.type_ || ccur.ocur != XML_ELEMENT_CONTENT_ONCE as c_int))
2886 {
2887 io::buf_ccat(buf, b')');
2888 }
2889 dump_element_occur(buf, ccur.ocur);
2890
2891 if ccur.type_ == XML_ELEMENT_CONTENT_SEQ as c_int {
2892 io::buf_add(buf, b" , " as *const u8, 3);
2893 } else if ccur.type_ == XML_ELEMENT_CONTENT_OR as c_int {
2894 io::buf_add(buf, b" | " as *const u8, 3);
2895 }
2896
2897 if cur == p.c1 {
2898 cur = p.c2;
2899 break;
2900 }
2901 cur = parent;
2902 }
2903 if cur == content {
2904 break;
2905 }
2906 }
2907 io::buf_ccat(buf, b')');
2908 let cc = unsafe { &*content };
2909 dump_element_occur(buf, cc.ocur);
2910}
2911
2912unsafe fn dump_element_decl(buf: *mut _xmlBuffer, elem: *mut _xmlElement) {
2918 use crate::abi::types::xmlElementTypeVal::*;
2919 let e = unsafe { &*elem };
2920 io::buf_add(buf, b"<!ELEMENT " as *const u8, 10);
2921 if !e.prefix.is_null() {
2922 io::buf_cat(buf, e.prefix);
2923 io::buf_ccat(buf, b':');
2924 }
2925 if !e.name.is_null() {
2926 io::buf_cat(buf, e.name);
2927 }
2928 io::buf_ccat(buf, b' ');
2929 match e.etype {
2930 t if t == XML_ELEMENT_TYPE_EMPTY as c_int => {
2931 io::buf_add(buf, b"EMPTY" as *const u8, 5);
2932 }
2933 t if t == XML_ELEMENT_TYPE_ANY as c_int => {
2934 io::buf_add(buf, b"ANY" as *const u8, 3);
2935 }
2936 t if t == XML_ELEMENT_TYPE_MIXED as c_int || t == XML_ELEMENT_TYPE_ELEMENT as c_int => {
2937 dump_element_content(buf, e.content);
2938 }
2939 _ => {}
2940 }
2941 io::buf_add(buf, b">\n" as *const u8, 2);
2942}
2943
2944unsafe fn dump_enumeration(buf: *mut _xmlBuffer, cur: *mut _xmlEnumeration) {
2950 let mut e = cur;
2951 while !e.is_null() {
2952 let en = unsafe { &*e };
2953 if !en.name.is_null() {
2954 io::buf_cat(buf, en.name);
2955 }
2956 if !en.next.is_null() {
2957 io::buf_add(buf, b" | " as *const u8, 3);
2958 }
2959 e = en.next;
2960 }
2961 io::buf_ccat(buf, b')');
2962}
2963
2964unsafe fn dump_attribute_decl(buf: *mut _xmlBuffer, attr: *mut _xmlAttribute) {
2970 use crate::abi::types::xmlAttributeDefault::*;
2971 use crate::abi::types::xmlAttributeType::*;
2972 let a = unsafe { &*attr };
2973 io::buf_add(buf, b"<!ATTLIST " as *const u8, 10);
2974 if !a.elem.is_null() {
2975 io::buf_cat(buf, a.elem);
2976 }
2977 io::buf_ccat(buf, b' ');
2978 if !a.prefix.is_null() {
2979 io::buf_cat(buf, a.prefix);
2980 io::buf_ccat(buf, b':');
2981 }
2982 if !a.name.is_null() {
2983 io::buf_cat(buf, a.name);
2984 }
2985 match a.atype {
2986 t if t == XML_ATTRIBUTE_CDATA as c_int => {
2987 io::buf_add(buf, b" CDATA" as *const u8, 6);
2988 }
2989 t if t == XML_ATTRIBUTE_ID as c_int => {
2990 io::buf_add(buf, b" ID" as *const u8, 3);
2991 }
2992 t if t == XML_ATTRIBUTE_IDREF as c_int => {
2993 io::buf_add(buf, b" IDREF" as *const u8, 6);
2994 }
2995 t if t == XML_ATTRIBUTE_IDREFS as c_int => {
2996 io::buf_add(buf, b" IDREFS" as *const u8, 7);
2997 }
2998 t if t == XML_ATTRIBUTE_ENTITY as c_int => {
2999 io::buf_add(buf, b" ENTITY" as *const u8, 7);
3000 }
3001 t if t == XML_ATTRIBUTE_ENTITIES as c_int => {
3002 io::buf_add(buf, b" ENTITIES" as *const u8, 9);
3003 }
3004 t if t == XML_ATTRIBUTE_NMTOKEN as c_int => {
3005 io::buf_add(buf, b" NMTOKEN" as *const u8, 8);
3006 }
3007 t if t == XML_ATTRIBUTE_NMTOKENS as c_int => {
3008 io::buf_add(buf, b" NMTOKENS" as *const u8, 9);
3009 }
3010 t if t == XML_ATTRIBUTE_ENUMERATION as c_int => {
3011 io::buf_add(buf, b" (" as *const u8, 2);
3012 dump_enumeration(buf, a.tree);
3013 }
3014 t if t == XML_ATTRIBUTE_NOTATION as c_int => {
3015 io::buf_add(buf, b" NOTATION (" as *const u8, 11);
3016 dump_enumeration(buf, a.tree);
3017 }
3018 _ => {}
3019 }
3020 match a.def {
3021 t if t == XML_ATTRIBUTE_REQUIRED as c_int => {
3022 io::buf_add(buf, b" #REQUIRED" as *const u8, 10);
3023 }
3024 t if t == XML_ATTRIBUTE_IMPLIED as c_int => {
3025 io::buf_add(buf, b" #IMPLIED" as *const u8, 9);
3026 }
3027 t if t == XML_ATTRIBUTE_FIXED as c_int => {
3028 io::buf_add(buf, b" #FIXED" as *const u8, 7);
3029 }
3030 _ => {}
3031 }
3032 if !a.defaultValue.is_null() {
3033 io::buf_add(buf, b" \"" as *const u8, 2);
3034 serialize_attr_value(buf, a.defaultValue);
3035 io::buf_ccat(buf, b'"');
3036 }
3037 io::buf_add(buf, b">\n" as *const u8, 2);
3038}
3039
3040unsafe fn write_quoted_string(buf: *mut _xmlBuffer, str: *const xmlChar) {
3046 if buf.is_null() {
3047 return;
3048 }
3049 io::buf_ccat(buf, b'"');
3050 if !str.is_null() {
3051 let mut i = 0usize;
3052 while unsafe { *str.add(i) != 0 } {
3053 let ch = unsafe { *str.add(i) };
3054 if ch == b'"' {
3055 io::buf_add(buf, b""" as *const u8, 6);
3056 } else {
3057 io::buf_add(buf, &ch as *const u8, 1);
3058 }
3059 i += 1;
3060 }
3061 }
3062 io::buf_ccat(buf, b'"');
3063}
3064
3065unsafe fn dump_entity_decl(buf: *mut _xmlBuffer, ent: *mut _xmlEntity) {
3071 use crate::abi::types::xmlEntityType::*;
3072 let e = unsafe { &*ent };
3073 if e.etype == XML_INTERNAL_PARAMETER_ENTITY as c_int
3074 || e.etype == XML_EXTERNAL_PARAMETER_ENTITY as c_int
3075 {
3076 io::buf_add(buf, b"<!ENTITY % " as *const u8, 11);
3077 } else {
3078 io::buf_add(buf, b"<!ENTITY " as *const u8, 9);
3079 }
3080 if !e.name.is_null() {
3081 io::buf_cat(buf, e.name);
3082 }
3083 io::buf_ccat(buf, b' ');
3084
3085 if e.etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY as c_int
3086 || e.etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int
3087 || e.etype == XML_EXTERNAL_PARAMETER_ENTITY as c_int
3088 {
3089 if !e.ExternalID.is_null() {
3090 io::buf_add(buf, b"PUBLIC " as *const u8, 7);
3091 write_quoted_string(buf, e.ExternalID);
3092 io::buf_ccat(buf, b' ');
3093 } else {
3094 io::buf_add(buf, b"SYSTEM " as *const u8, 7);
3095 }
3096 write_quoted_string(buf, e.SystemID);
3097 }
3098
3099 if e.etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int {
3100 if !e.content.is_null() {
3101 io::buf_add(buf, b" NDATA " as *const u8, 7);
3102 if !e.orig.is_null() {
3103 io::buf_cat(buf, e.orig);
3104 } else if !e.content.is_null() {
3105 io::buf_cat(buf, e.content);
3106 }
3107 }
3108 }
3109
3110 if e.etype == XML_INTERNAL_GENERAL_ENTITY as c_int
3111 || e.etype == XML_INTERNAL_PARAMETER_ENTITY as c_int
3112 {
3113 if !e.orig.is_null() {
3114 write_quoted_string(buf, e.orig);
3115 } else {
3116 io::buf_ccat(buf, b'"');
3118 if !e.content.is_null() {
3119 let mut i = 0usize;
3120 while unsafe { *e.content.add(i) != 0 } {
3121 let ch = unsafe { *e.content.add(i) };
3122 match ch {
3123 b'"' => io::buf_add(buf, b""" as *const u8, 6),
3124 b'%' => io::buf_add(buf, b"%" as *const u8, 6),
3125 _ => io::buf_add(buf, &ch as *const u8, 1),
3126 };
3127 i += 1;
3128 }
3129 }
3130 io::buf_ccat(buf, b'"');
3131 }
3132 }
3133 io::buf_add(buf, b">\n" as *const u8, 2);
3134}
3135
3136unsafe fn dtd_dump_output(
3142 buf: *mut _xmlBuffer,
3143 cur: *mut _xmlNode,
3144 state: &mut DumpState,
3145 level: &mut c_int,
3146) {
3147 let dtd = cur as *mut _xmlDtd;
3148 let d = unsafe { &*dtd };
3149 io::buf_add(buf, b"<!DOCTYPE " as *const u8, 10);
3150 if !d.name.is_null() {
3151 io::buf_cat(buf, d.name);
3152 }
3153 if !d.ExternalID.is_null() {
3154 io::buf_add(buf, b" PUBLIC " as *const u8, 8);
3155 write_quoted_string(buf, d.ExternalID);
3156 io::buf_ccat(buf, b' ');
3157 write_quoted_string(buf, d.SystemID);
3158 } else if !d.SystemID.is_null() {
3159 io::buf_add(buf, b" SYSTEM " as *const u8, 8);
3160 write_quoted_string(buf, d.SystemID);
3161 }
3162 if crate::xml::hash::hash_size(d.entities as *mut crate::xml::hash::HashTable) == 0
3163 && crate::xml::hash::hash_size(d.elements as *mut crate::xml::hash::HashTable) == 0
3164 && crate::xml::hash::hash_size(d.attributes as *mut crate::xml::hash::HashTable) == 0
3165 && crate::xml::hash::hash_size(d.notations as *mut crate::xml::hash::HashTable) == 0
3166 && crate::xml::hash::hash_size(d.pentities as *mut crate::xml::hash::HashTable) == 0
3167 {
3168 io::buf_ccat(buf, b'>');
3169 return;
3170 }
3171 io::buf_add(buf, b" [\n" as *const u8, 3);
3172 let format = state.format;
3178 let lvl = *level;
3179 state.format = 0;
3180 *level = -1;
3181 if !d.notations.is_null() {
3182 crate::xml::hash::hash_scan(
3183 d.notations as *mut crate::xml::hash::HashTable,
3184 Some(dump_notation_decl_cb),
3185 buf as *mut c_void,
3186 );
3187 }
3188 if !d.elements.is_null() {
3189 crate::xml::hash::hash_scan(
3190 d.elements as *mut crate::xml::hash::HashTable,
3191 Some(dump_element_decl_cb),
3192 buf as *mut c_void,
3193 );
3194 }
3195 if !d.attributes.is_null() {
3196 crate::xml::hash::hash_scan(
3197 d.attributes as *mut crate::xml::hash::HashTable,
3198 Some(dump_attribute_decl_cb),
3199 buf as *mut c_void,
3200 );
3201 }
3202 if !d.entities.is_null() {
3203 crate::xml::hash::hash_scan(
3204 d.entities as *mut crate::xml::hash::HashTable,
3205 Some(dump_entity_decl_cb),
3206 buf as *mut c_void,
3207 );
3208 }
3209 if !d.pentities.is_null() {
3210 crate::xml::hash::hash_scan(
3211 d.pentities as *mut crate::xml::hash::HashTable,
3212 Some(dump_entity_decl_cb),
3213 buf as *mut c_void,
3214 );
3215 }
3216 state.format = format;
3217 *level = lvl;
3218 io::buf_add(buf, b"]>" as *const u8, 2);
3219}
3220
3221unsafe extern "C" fn dump_notation_decl_cb(
3223 payload: *mut c_void,
3224 data: *mut c_void,
3225 _name: *const crate::abi::types::xmlChar,
3226) {
3227 if !payload.is_null() && !data.is_null() {
3228 dump_notation_decl(data as *mut _xmlBuffer, payload as *mut _xmlNotation);
3229 }
3230}
3231
3232unsafe extern "C" fn dump_element_decl_cb(
3234 payload: *mut c_void,
3235 data: *mut c_void,
3236 _name: *const crate::abi::types::xmlChar,
3237) {
3238 if !payload.is_null() && !data.is_null() {
3239 dump_element_decl(data as *mut _xmlBuffer, payload as *mut _xmlElement);
3240 }
3241}
3242
3243unsafe extern "C" fn dump_attribute_decl_cb(
3245 payload: *mut c_void,
3246 data: *mut c_void,
3247 _name: *const crate::abi::types::xmlChar,
3248) {
3249 if !payload.is_null() && !data.is_null() {
3250 dump_attribute_decl(data as *mut _xmlBuffer, payload as *mut _xmlAttribute);
3251 }
3252}
3253
3254unsafe extern "C" fn dump_entity_decl_cb(
3256 payload: *mut c_void,
3257 data: *mut c_void,
3258 _name: *const crate::abi::types::xmlChar,
3259) {
3260 if !payload.is_null() && !data.is_null() {
3261 dump_entity_decl(data as *mut _xmlBuffer, payload as *mut _xmlEntity);
3262 }
3263}
3264
3265unsafe fn doc_content_dump_output(
3274 buf: *mut _xmlBuffer,
3275 cur: *mut _xmlNode,
3276 state: &mut DumpState,
3277 level: &mut c_int,
3278) {
3279 let doc = cur as *mut _xmlDoc;
3280 let d = unsafe { &*doc };
3281
3282 if state.no_decl == 0 {
3286 io::buf_add(buf, b"<?xml version=\"" as *const u8, 15);
3287 if !d.version.is_null() {
3288 io::buf_cat(buf, d.version);
3289 } else {
3290 io::buf_add(buf, b"1.0" as *const u8, 3);
3291 }
3292 io::buf_ccat(buf, b'"');
3293 if !d.encoding.is_null() {
3294 io::buf_add(buf, b" encoding=\"" as *const u8, 11);
3295 io::buf_cat(buf, d.encoding);
3296 io::buf_ccat(buf, b'"');
3297 }
3298 match d.standalone {
3299 0 => {
3300 io::buf_add(buf, b" standalone=\"no\"" as *const u8, 16);
3301 }
3302 1 => {
3303 io::buf_add(buf, b" standalone=\"yes\"" as *const u8, 17);
3304 }
3305 _ => {}
3306 }
3307 io::buf_add(buf, b"?>\n" as *const u8, 3);
3308 }
3309
3310 if !d.intSubset.is_null() {
3313 let mut lvl = 0;
3314 dtd_dump_output(buf, d.intSubset as *mut _xmlNode, state, &mut lvl);
3315 io::buf_ccat(buf, b'\n');
3316 }
3317
3318 if !d.children.is_null() {
3319 let mut child = d.children;
3320 while !child.is_null() {
3321 *level = 0;
3322 node_dump_internal(buf, child, child, cur, state, level);
3323 let ct = unsafe { (*child).type_ };
3324 if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
3325 io::buf_ccat(buf, b'\n');
3326 }
3327 child = unsafe { (*child).next };
3328 }
3329 }
3330}
3331
3332unsafe fn node_dump_internal(
3356 buf: *mut _xmlBuffer,
3357 cur: *mut _xmlNode,
3358 root: *mut _xmlNode,
3359 parent: *mut _xmlNode,
3360 state: &mut DumpState,
3361 level: &mut c_int,
3362) {
3363 if cur.is_null() || buf.is_null() {
3364 return;
3365 }
3366 let n = unsafe { &*cur };
3367 match n.type_ {
3368 t if t == XML_ELEMENT_NODE as c_int => {
3369 if cur != root && state.format == 1 {
3370 write_indent(buf, *level, state.indent, state.indent_len);
3371 }
3372 if !n.parent.is_null() && n.parent != parent && !n.children.is_null() {
3375 let mut sub = DumpState::new(state.format);
3376 let mut sub_level = *level;
3377 node_dump_internal(buf, cur, cur, n.parent, &mut sub, &mut sub_level);
3378 return;
3379 }
3380 io::buf_ccat(buf, b'<');
3382 write_qname(buf, cur);
3383 let mut nsdef = n.nsDef;
3384 while !nsdef.is_null() {
3385 ns_dump_output(buf, nsdef);
3386 nsdef = unsafe { (*nsdef).next };
3387 }
3388 let mut attr = n.properties;
3389 while !attr.is_null() {
3390 attr_dump_output(buf, attr);
3391 attr = unsafe { (*attr).next };
3392 }
3393 if n.children.is_null() {
3394 io::buf_add(buf, b"/>" as *const u8, 2);
3395 } else {
3396 if state.format == 1 {
3397 let mut tmp = n.children;
3400 while !tmp.is_null() {
3401 let tt = unsafe { (*tmp).type_ };
3402 if tt == XML_TEXT_NODE as c_int
3403 || tt == XML_CDATA_SECTION_NODE as c_int
3404 || tt == XML_ENTITY_REF_NODE as c_int
3405 {
3406 state.format = 0;
3407 state.unformatted = cur;
3408 break;
3409 }
3410 tmp = unsafe { (*tmp).next };
3411 }
3412 }
3413 io::buf_ccat(buf, b'>');
3414 if state.format == 1 {
3415 io::buf_ccat(buf, b'\n');
3416 }
3417 if *level >= 0 {
3418 *level += 1;
3419 }
3420 let mut child = n.children;
3421 while !child.is_null() {
3422 node_dump_internal(buf, child, root, cur, state, level);
3423 if state.format == 1 {
3424 let ct = unsafe { (*child).type_ };
3425 if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
3426 io::buf_ccat(buf, b'\n');
3427 }
3428 }
3429 child = unsafe { (*child).next };
3430 }
3431 if *level > 0 {
3433 *level -= 1;
3434 }
3435 if state.format == 1 {
3436 write_indent(buf, *level, state.indent, state.indent_len);
3437 }
3438 io::buf_add(buf, b"</" as *const u8, 2);
3439 write_qname(buf, cur);
3440 io::buf_ccat(buf, b'>');
3441 if cur == state.unformatted {
3442 state.format = state.saved;
3443 state.unformatted = ptr::null_mut();
3444 }
3445 }
3446 }
3447 t if t == XML_TEXT_NODE as c_int => {
3448 if !n.content.is_null() {
3449 if is_noenc_text(cur) {
3450 io::buf_cat(buf, n.content);
3451 } else {
3452 serialize_text(buf, n.content, xml_strlen(n.content));
3453 }
3454 } else if !n.children.is_null() {
3455 let c = node_get_content(cur);
3458 if !c.is_null() {
3459 if is_noenc_text(cur) {
3460 io::buf_cat(buf, c);
3461 } else {
3462 serialize_text(buf, c, xml_strlen(c));
3463 }
3464 allocator::xmlFree(c as *mut c_void);
3465 }
3466 }
3467 }
3468 t if t == XML_CDATA_SECTION_NODE as c_int => {
3469 if n.content.is_null() || unsafe { *n.content == 0 } {
3470 io::buf_add(buf, b"<![CDATA[]]>" as *const u8, 12);
3471 } else {
3472 let len = xml_strlen(n.content) as usize;
3473 let bytes = core::slice::from_raw_parts(n.content, len);
3474 let mut i = 0usize;
3475 let mut seg_start = 0usize;
3476 while i < len {
3477 if bytes[i] == b']'
3478 && i + 2 < len
3479 && bytes[i + 1] == b']'
3480 && bytes[i + 2] == b'>'
3481 {
3482 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
3483 io::buf_add(buf, n.content.add(seg_start), (i + 2 - seg_start) as c_int);
3484 io::buf_add(buf, b"]]>" as *const u8, 3);
3485 seg_start = i + 2;
3486 i += 3;
3487 continue;
3488 }
3489 i += 1;
3490 }
3491 if seg_start < len {
3492 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
3493 io::buf_add(buf, n.content.add(seg_start), (len - seg_start) as c_int);
3494 io::buf_add(buf, b"]]>" as *const u8, 3);
3495 }
3496 }
3497 }
3498 t if t == XML_COMMENT_NODE as c_int => {
3499 if cur != root && state.format == 1 {
3500 write_indent(buf, *level, state.indent, state.indent_len);
3501 }
3502 if !n.content.is_null() {
3503 io::buf_add(buf, b"<!--" as *const u8, 4);
3504 io::buf_cat(buf, n.content);
3505 io::buf_add(buf, b"-->" as *const u8, 3);
3506 }
3507 }
3508 t if t == XML_PI_NODE as c_int => {
3509 if cur != root && state.format == 1 {
3510 write_indent(buf, *level, state.indent, state.indent_len);
3511 }
3512 io::buf_add(buf, b"<?" as *const u8, 2);
3513 if !n.name.is_null() {
3514 io::buf_cat(buf, n.name);
3515 }
3516 if !n.content.is_null() && unsafe { *n.content != 0 } {
3517 io::buf_ccat(buf, b' ');
3518 io::buf_cat(buf, n.content);
3519 }
3520 io::buf_add(buf, b"?>" as *const u8, 2);
3521 }
3522 t if t == XML_ENTITY_REF_NODE as c_int => {
3523 io::buf_ccat(buf, b'&');
3524 if !n.name.is_null() {
3525 io::buf_cat(buf, n.name);
3526 }
3527 io::buf_ccat(buf, b';');
3528 }
3529 t if t == XML_DOCUMENT_NODE as c_int => {
3530 doc_content_dump_output(buf, cur, state, level);
3531 }
3532 t if t == XML_HTML_DOCUMENT_NODE as c_int => {
3533 crate::xml::html::serialize_node(cur, buf, state.format, *level);
3535 }
3536 t if t == XML_DTD_NODE as c_int => {
3537 dtd_dump_output(buf, cur, state, level);
3538 }
3539 t if t == XML_ATTRIBUTE_NODE as c_int => {
3540 attr_dump_output(buf, cur as *mut _xmlAttr);
3541 }
3542 t if t == XML_NAMESPACE_DECL as c_int => {
3543 ns_dump_output(buf, cur as *mut _xmlNs);
3544 }
3545 t if t == XML_ELEMENT_DECL as c_int => {
3546 dump_element_decl(buf, cur as *mut _xmlElement);
3547 }
3548 t if t == XML_ATTRIBUTE_DECL as c_int => {
3549 dump_attribute_decl(buf, cur as *mut _xmlAttribute);
3550 }
3551 t if t == XML_ENTITY_DECL as c_int => {
3552 dump_entity_decl(buf, cur as *mut _xmlEntity);
3553 }
3554 _ => {}
3555 }
3556}
3557
3558pub(crate) unsafe fn serialize_node(
3572 node: *mut _xmlNode,
3573 buf: *mut _xmlBuffer,
3574 format: c_int,
3575 level: c_int,
3576) {
3577 unsafe { serialize_node_opt(node, buf, format, level, ptr::null()) };
3578}
3579
3580pub(crate) unsafe fn serialize_node_opt(
3588 node: *mut _xmlNode,
3589 buf: *mut _xmlBuffer,
3590 format: c_int,
3591 level: c_int,
3592 indent: *const xmlChar,
3593) {
3594 unsafe { serialize_node_opts(node, buf, format, level, indent, 0) };
3595}
3596
3597pub(crate) unsafe fn serialize_node_opts(
3604 node: *mut _xmlNode,
3605 buf: *mut _xmlBuffer,
3606 format: c_int,
3607 level: c_int,
3608 indent: *const xmlChar,
3609 no_decl: c_int,
3610) {
3611 if node.is_null() || buf.is_null() {
3612 return;
3613 }
3614 let parent = unsafe { (*node).parent };
3615 let mut state = DumpState::with_indent(format, indent, no_decl);
3616 let mut lvl = level;
3617 node_dump_internal(buf, node, node, parent, &mut state, &mut lvl);
3618}
3619
3620pub(crate) unsafe fn doc_dump(buf: *mut _xmlBuffer, doc: *mut _xmlDoc) -> c_int {
3630 if buf.is_null() || doc.is_null() {
3631 return -1;
3632 }
3633
3634 let before = io::buf_length(buf);
3635 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
3636 let after = io::buf_length(buf);
3637
3638 if after < 0 || before < 0 {
3639 return -1;
3640 }
3641 after - before
3642}
3643
3644pub(crate) unsafe fn node_dump(
3656 buf: *mut _xmlBuffer,
3657 doc: *mut _xmlDoc,
3658 node: *mut _xmlNode,
3659 level: c_int,
3660 format: c_int,
3661) -> c_int {
3662 let _ = doc; if buf.is_null() || node.is_null() {
3664 return -1;
3665 }
3666
3667 let before = io::buf_length(buf);
3668 serialize_node(node, buf, format, level);
3669 let after = io::buf_length(buf);
3670
3671 if after < 0 || before < 0 {
3672 return -1;
3673 }
3674 after - before
3675}
3676
3677pub(crate) unsafe fn save_doc_to_filename(
3684 doc: *mut _xmlDoc,
3685 filename: *const c_char,
3686 compression: c_int,
3687) -> c_int {
3688 if doc.is_null() || filename.is_null() {
3689 return -1;
3690 }
3691
3692 let out = io::output_buffer_create_filename(filename, ptr::null_mut(), compression);
3693 if out.is_null() {
3694 return -1;
3695 }
3696
3697 let buf = io::buf_create(-1);
3698 if buf.is_null() {
3699 io::output_buffer_close(out);
3700 return -1;
3701 }
3702
3703 let ret = doc_dump(buf, doc);
3704 if ret >= 0 {
3705 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
3707 io::output_buffer_flush(out);
3708 }
3709
3710 io::buf_free(buf);
3711 io::output_buffer_close(out);
3712 ret
3713}
3714
3715pub(crate) unsafe fn save_doc_to_fd(doc: *mut _xmlDoc, fd: c_int, compression: c_int) -> c_int {
3722 if doc.is_null() || fd < 0 {
3723 return -1;
3724 }
3725
3726 let out = io::output_buffer_create_fd(fd, ptr::null_mut());
3727 if out.is_null() {
3728 return -1;
3729 }
3730
3731 let buf = io::buf_create(-1);
3732 if buf.is_null() {
3733 io::output_buffer_close(out);
3734 return -1;
3735 }
3736
3737 let ret = doc_dump(buf, doc);
3738 if ret >= 0 {
3739 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
3740 io::output_buffer_flush(out);
3741 }
3742
3743 io::buf_free(buf);
3744 io::output_buffer_close(out);
3745 ret
3746}
3747
3748pub(crate) unsafe fn save_doc_to_buf(
3755 doc: *mut _xmlDoc,
3756 buf: *mut _xmlBuffer,
3757 compression: c_int,
3758) -> c_int {
3759 let _ = compression;
3760 if doc.is_null() || buf.is_null() {
3761 return -1;
3762 }
3763
3764 doc_dump(buf, doc)
3765}
3766
3767pub(crate) unsafe fn save_format_doc_to_buf(
3774 doc: *mut _xmlDoc,
3775 buf: *mut _xmlBuffer,
3776 compression: c_int,
3777) -> c_int {
3778 let _ = compression;
3779 if doc.is_null() || buf.is_null() {
3780 return -1;
3781 }
3782
3783 let before = io::buf_length(buf);
3784 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
3785 let after = io::buf_length(buf);
3786
3787 if after < 0 || before < 0 {
3788 return -1;
3789 }
3790 after - before
3791}
3792
3793pub(crate) unsafe fn dump_node(node: *mut _xmlNode) -> *mut xmlChar {
3802 if node.is_null() {
3803 return ptr::null_mut();
3804 }
3805
3806 let buf = io::buf_create(-1);
3807 if buf.is_null() {
3808 return ptr::null_mut();
3809 }
3810
3811 serialize_node(node, buf, 0, 0);
3812
3813 let content = io::buf_content(buf);
3814 if content.is_null() {
3815 io::buf_free(buf);
3816 return ptr::null_mut();
3817 }
3818
3819 let result = dup_xml_str(content);
3821 io::buf_free(buf);
3822 result
3823}
3824
3825pub unsafe fn dump_doc(doc: *mut _xmlDoc) -> *mut xmlChar {
3834 if doc.is_null() {
3835 return ptr::null_mut();
3836 }
3837
3838 let buf = io::buf_create(-1);
3839 if buf.is_null() {
3840 return ptr::null_mut();
3841 }
3842
3843 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
3844
3845 let content = io::buf_content(buf);
3846 if content.is_null() {
3847 io::buf_free(buf);
3848 return ptr::null_mut();
3849 }
3850
3851 let result = dup_xml_str(content);
3852 io::buf_free(buf);
3853 result
3854}
3855
3856pub(crate) unsafe fn xmlNodeDump(
3872 buf: *mut _xmlBuffer,
3873 doc: *mut _xmlDoc,
3874 node: *mut _xmlNode,
3875 level: c_int,
3876 format: c_int,
3877) -> c_int {
3878 node_dump(buf, doc, node, level, format)
3879}
3880
3881pub(crate) unsafe fn xmlDocDump(fp: *mut c_void, doc: *mut _xmlDoc) -> c_int {
3894 if fp.is_null() || doc.is_null() {
3895 return -1;
3896 }
3897
3898 let buf = io::buf_create(-1);
3899 if buf.is_null() {
3900 return -1;
3901 }
3902
3903 let ret = doc_dump(buf, doc);
3904 if ret < 0 {
3905 io::buf_free(buf);
3906 return -1;
3907 }
3908
3909 let content = io::buf_content(buf);
3910 let len = io::buf_length(buf);
3911 if !content.is_null() && len > 0 {
3912 let written = libc::fwrite(
3913 content as *const c_void,
3914 1,
3915 len as usize,
3916 fp as *mut libc::FILE,
3917 );
3918 io::buf_free(buf);
3919 written as c_int
3920 } else {
3921 io::buf_free(buf);
3922 0
3923 }
3924}
3925
3926pub(crate) unsafe fn xmlDocDumpFormatMemory(
3940 doc: *mut _xmlDoc,
3941 mem: *mut *mut xmlChar,
3942 size: *mut c_int,
3943 format: c_int,
3944) {
3945 if doc.is_null() || mem.is_null() || size.is_null() {
3946 return;
3947 }
3948
3949 let buf = io::buf_create(-1);
3950 if buf.is_null() {
3951 unsafe {
3952 *mem = ptr::null_mut();
3953 *size = 0;
3954 }
3955 return;
3956 }
3957
3958 serialize_node(doc as *mut _xmlNode, buf, format, 0);
3959
3960 let content = io::buf_content(buf);
3961 let len = io::buf_length(buf);
3962
3963 if !content.is_null() && len > 0 {
3964 let result = allocator::xmlMalloc((len + 1) as usize) as *mut xmlChar;
3966 if !result.is_null() {
3967 ptr::copy_nonoverlapping(content, result, len as usize);
3968 *result.add(len as usize) = 0;
3969 unsafe {
3970 *mem = result;
3971 *size = len;
3972 }
3973 } else {
3974 unsafe {
3975 *mem = ptr::null_mut();
3976 *size = 0;
3977 }
3978 }
3979 } else {
3980 unsafe {
3981 *mem = ptr::null_mut();
3982 *size = 0;
3983 }
3984 }
3985
3986 io::buf_free(buf);
3987}
3988
3989pub(crate) unsafe fn xmlDocDumpMemory(doc: *mut _xmlDoc, mem: *mut *mut xmlChar, size: *mut c_int) {
4003 xmlDocDumpFormatMemory(doc, mem, size, 0)
4004}
4005
4006pub(crate) unsafe fn xmlSaveFile(filename: *const c_char, cur: *mut _xmlDoc) -> c_int {
4019 save_doc_to_filename(cur, filename, 0)
4020}
4021
4022pub(crate) unsafe fn xmlSaveFileEnc(
4036 filename: *const c_char,
4037 cur: *mut _xmlDoc,
4038 encoding: *const c_char,
4039) -> c_int {
4040 let _ = encoding; save_doc_to_filename(cur, filename, 0)
4042}
4043
4044pub(crate) unsafe fn xmlSaveFormatFile(
4057 filename: *const c_char,
4058 cur: *mut _xmlDoc,
4059 format: c_int,
4060) -> c_int {
4061 let _ = format;
4062 save_doc_to_filename(cur, filename, 0)
4063}
4064
4065pub(crate) unsafe fn xmlSaveFormatFileEnc(
4079 filename: *const c_char,
4080 cur: *mut _xmlDoc,
4081 encoding: *const c_char,
4082 format: c_int,
4083) -> c_int {
4084 let _ = encoding;
4085 let _ = format;
4086 save_doc_to_filename(cur, filename, 0)
4087}
4088
4089pub(crate) unsafe fn xmlGetDocCompressMode(doc: *mut _xmlDoc) -> c_int {
4101 if doc.is_null() {
4102 return -1;
4103 }
4104 unsafe { (*doc).compression }
4105}
4106
4107pub(crate) unsafe fn xmlSetDocCompressMode(doc: *mut _xmlDoc, mode: c_int) {
4119 if doc.is_null() {
4120 return;
4121 }
4122 unsafe {
4123 (*doc).compression = mode;
4124 }
4125}
4126
4127#[cfg(test)]
4128mod tests {
4129 use super::*;
4130 use core::ffi::c_void;
4131
4132 fn c_str(s: &str) -> *const xmlChar {
4133 let bytes = s.as_bytes();
4134 let buf = unsafe { allocator::xmlMalloc(bytes.len() + 1) as *mut u8 };
4135 if !buf.is_null() {
4136 unsafe {
4137 ptr::copy_nonoverlapping(bytes.as_ptr(), buf, bytes.len());
4138 *buf.add(bytes.len()) = 0;
4139 }
4140 }
4141 buf as *const xmlChar
4142 }
4143
4144 #[test]
4145 fn test_new_free_doc() {
4146 unsafe {
4147 let doc = new_doc(ptr::null());
4148 assert!(!doc.is_null());
4149 assert_eq!((*doc).type_, XML_DOCUMENT_NODE as c_int);
4150 assert_eq!((*doc).standalone, -1);
4151 assert_eq!((*doc).doc, doc);
4152 assert!(!(*doc).version.is_null());
4153 free_doc(doc);
4154 }
4155 }
4156
4157 #[test]
4158 fn test_new_doc_with_version() {
4159 unsafe {
4160 let ver = c_str("2.0");
4161 let doc = new_doc(ver);
4162 assert!(!doc.is_null());
4163 let doc_ver = (*doc).version;
4164 assert!(!doc_ver.is_null());
4165 assert!(crate::abi::exports_xml2::xmlStrEqual(doc_ver, ver,) != 0);
4166 allocator::xmlFree(ver as *mut c_void);
4167 free_doc(doc);
4168 }
4169 }
4170
4171 #[test]
4172 fn test_new_node() {
4173 unsafe {
4174 let doc = new_doc(ptr::null());
4175 let node = new_node(ptr::null_mut(), c_str("root"));
4176 assert!(!node.is_null());
4177 assert_eq!((*node).type_, XML_ELEMENT_NODE as c_int);
4178 assert!(!(*node).name.is_null());
4179 free_node(node);
4180 free_doc(doc);
4181 }
4182 }
4183
4184 #[test]
4185 fn test_node_get_content_recurses_descendants() {
4186 unsafe {
4191 let doc = new_doc(ptr::null());
4192 let root = new_node(ptr::null_mut(), c_str("library"));
4193 doc_set_root_element(doc, root);
4194 let book = new_child(root, ptr::null_mut(), c_str("book"));
4195 let title = new_child(book, ptr::null_mut(), c_str("title"));
4196 let text = new_text(c_str("Rust"));
4197 add_child(title, text);
4198
4199 let content = node_get_content(book);
4200 assert!(!content.is_null());
4201 let s = core::slice::from_raw_parts(
4202 content,
4203 libc::strlen(content as *const libc::c_char) as usize,
4204 );
4205 assert_eq!(s, b"Rust", "descendant text not concatenated");
4206 allocator::xmlFree(content as *mut c_void);
4207
4208 free_doc(doc);
4209 }
4210 }
4211
4212 #[test]
4213 fn test_doc_set_root_element() {
4214 unsafe {
4215 let doc = new_doc(ptr::null());
4216 let root = new_node(ptr::null_mut(), c_str("root"));
4217 let old = doc_set_root_element(doc, root);
4218 assert!(old.is_null());
4219 assert_eq!(doc_get_root_element(doc), root);
4220 assert_eq!((*doc).children, root as *mut _xmlNode);
4221 free_doc(doc);
4222 }
4223 }
4224
4225 #[test]
4226 fn test_add_child_and_sibling() {
4227 unsafe {
4228 let doc = new_doc(ptr::null());
4229 let root = new_node(ptr::null_mut(), c_str("root"));
4230 doc_set_root_element(doc, root);
4231
4232 let child1 = new_child(root, ptr::null_mut(), c_str("child1"));
4233 assert!(!child1.is_null());
4234 assert_eq!((*child1).parent, root);
4235 assert_eq!((*root).children, child1);
4236 assert_eq!((*root).last, child1);
4237
4238 let child2 = new_child(root, ptr::null_mut(), c_str("child2"));
4239 assert!(!child2.is_null());
4240 assert_eq!((*child2).parent, root);
4241 assert_eq!((*child1).next, child2);
4242 assert_eq!((*child2).prev, child1);
4243 assert_eq!((*root).last, child2);
4244
4245 let sibling = new_node(ptr::null_mut(), c_str("sibling"));
4247 add_sibling(child2, sibling);
4248 assert_eq!((*child2).next, sibling);
4249 assert_eq!((*sibling).prev, child2);
4250 assert_eq!((*root).last, sibling);
4251
4252 free_doc(doc);
4253 }
4254 }
4255
4256 #[test]
4257 fn test_unlink_node() {
4258 unsafe {
4259 let doc = new_doc(ptr::null());
4260 let root = new_node(ptr::null_mut(), c_str("root"));
4261 doc_set_root_element(doc, root);
4262
4263 let child1 = new_child(root, ptr::null_mut(), c_str("c1"));
4264 let child2 = new_child(root, ptr::null_mut(), c_str("c2"));
4265
4266 unlink_node(child1);
4267 assert!((*child1).parent.is_null());
4268 assert!((*child1).prev.is_null());
4269 assert!((*child1).next.is_null());
4270 assert_eq!((*root).children, child2);
4271 assert_eq!((*root).last, child2);
4272
4273 free_node(child1);
4274 free_doc(doc);
4275 }
4276 }
4277
4278 #[test]
4279 fn test_text_and_comment_nodes() {
4280 unsafe {
4281 let text = new_text(c_str("hello world"));
4282 assert!(!text.is_null());
4283 assert_eq!((*text).type_, XML_TEXT_NODE as c_int);
4284 assert!(!(*text).content.is_null());
4285 free_node(text);
4286
4287 let comment = new_comment(c_str("my comment"));
4288 assert!(!comment.is_null());
4289 assert_eq!((*comment).type_, XML_COMMENT_NODE as c_int);
4290 free_node(comment);
4291
4292 let pi = new_pi(c_str("xml"), c_str("version='1.0'"));
4293 assert!(!pi.is_null());
4294 assert_eq!((*pi).type_, XML_PI_NODE as c_int);
4295 free_node(pi);
4296 }
4297 }
4298
4299 #[test]
4300 fn test_set_and_get_prop() {
4301 unsafe {
4302 let doc = new_doc(ptr::null());
4303 let root = new_node(ptr::null_mut(), c_str("root"));
4304 doc_set_root_element(doc, root);
4305
4306 let attr = set_prop(root, c_str("id"), c_str("42"));
4307 assert!(!attr.is_null());
4308 assert_eq!((*attr).type_, XML_ATTRIBUTE_NODE as c_int);
4309
4310 let value = get_prop(root, c_str("id"));
4311 assert!(!value.is_null());
4312 assert!(crate::abi::exports_xml2::xmlStrEqual(value, c_str("42")) != 0);
4313 allocator::xmlFree(value as *mut c_void);
4314
4315 free_doc(doc);
4316 }
4317 }
4318
4319 #[test]
4320 fn test_remove_prop() {
4321 unsafe {
4322 let doc = new_doc(ptr::null());
4323 let root = new_node(ptr::null_mut(), c_str("root"));
4324 doc_set_root_element(doc, root);
4325
4326 set_prop(root, c_str("a"), c_str("1"));
4327 set_prop(root, c_str("b"), c_str("2"));
4328
4329 let value = get_prop(root, c_str("a"));
4330 assert!(!value.is_null());
4331 allocator::xmlFree(value as *mut c_void);
4332
4333 let attr = (*root).properties;
4335 assert!(!attr.is_null());
4336 let result = remove_prop(attr);
4337 assert_eq!(result, 0);
4338
4339 let value2 = get_prop(root, c_str("a"));
4341 assert!(value2.is_null());
4342
4343 free_doc(doc);
4344 }
4345 }
4346
4347 #[test]
4348 fn test_namespace_operations() {
4349 unsafe {
4350 let doc = new_doc(ptr::null());
4351 let root = new_node(ptr::null_mut(), c_str("root"));
4352 doc_set_root_element(doc, root);
4353
4354 let ns = new_ns(root, c_str("http://example.com"), c_str("ex"));
4355 assert!(!ns.is_null());
4356 assert!(!(*root).nsDef.is_null());
4357
4358 set_ns(root, ns);
4359 assert_eq!((*root).ns, ns);
4360
4361 let found = search_ns(doc, root, c_str("ex"));
4362 assert_eq!(found, ns);
4363
4364 let found_href = search_ns_by_href(doc, root, c_str("http://example.com"));
4365 assert_eq!(found_href, ns);
4366
4367 free_doc(doc);
4368 }
4369 }
4370
4371 #[test]
4372 fn test_new_dtd() {
4373 unsafe {
4374 let doc = new_doc(ptr::null());
4375 let dtd = new_dtd(doc, c_str("root"), c_str("-//TEST//DTD"), c_str("test.dtd"));
4376 assert!(!dtd.is_null());
4377 assert_eq!((*dtd).type_, XML_DTD_NODE as c_int);
4378 assert_eq!(get_int_subset(doc), dtd);
4379 free_doc(doc);
4380 }
4381 }
4382
4383 #[test]
4384 fn test_copy_node_deep() {
4385 unsafe {
4386 let doc = new_doc(ptr::null());
4387 let root = new_node(ptr::null_mut(), c_str("root"));
4388 doc_set_root_element(doc, root);
4389 let child = new_child(root, ptr::null_mut(), c_str("child"));
4390
4391 let copy = copy_node(root, 1);
4392 assert!(!copy.is_null());
4393 assert_eq!((*copy).type_, XML_ELEMENT_NODE as c_int);
4394 assert!(!(*copy).children.is_null());
4396 assert_eq!((*(*copy).children).type_, XML_ELEMENT_NODE as c_int);
4397
4398 free_node(copy);
4399 free_doc(doc);
4400 }
4401 }
4402
4403 #[test]
4404 fn test_new_cdata_block() {
4405 unsafe {
4406 let doc = new_doc(ptr::null());
4407 let content = c_str("some <cdata> content");
4408 let cdata = new_cdata_block(doc, content, 20);
4409 assert!(!cdata.is_null());
4410 assert_eq!((*cdata).type_, XML_CDATA_SECTION_NODE as c_int);
4411 free_node(cdata);
4412 free_doc(doc);
4413 }
4414 }
4415
4416 #[test]
4417 fn test_null_handling() {
4418 unsafe {
4419 assert!(new_doc(ptr::null()).is_null() == false); let doc = new_doc(ptr::null());
4421 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());
4426 assert!(add_sibling(ptr::null_mut(), ptr::null_mut()).is_null());
4427 free_doc(doc);
4428 }
4429 }
4430
4431 unsafe fn buf_eq_str(buf: *mut _xmlBuffer, expected: &str) -> bool {
4437 let content = io::buf_content(buf);
4438 if content.is_null() {
4439 return expected.is_empty();
4440 }
4441 let len = io::buf_length(buf) as usize;
4442 if len != expected.len() {
4443 return false;
4444 }
4445 let slice = unsafe { core::slice::from_raw_parts(content, len) };
4446 slice == expected.as_bytes()
4447 }
4448
4449 #[test]
4450 fn test_serialize_empty_document() {
4451 unsafe {
4452 let doc = new_doc(ptr::null());
4453 let buf = io::buf_create(-1);
4454 assert!(!buf.is_null());
4455
4456 let ret = doc_dump(buf, doc);
4457 assert!(ret >= 0);
4458
4459 let expected = "<?xml version=\"1.0\"?>\n";
4463 assert!(buf_eq_str(buf, expected));
4464
4465 io::buf_free(buf);
4466 free_doc(doc);
4467 }
4468 }
4469
4470 #[test]
4471 fn test_serialize_element_with_text() {
4472 unsafe {
4473 let doc = new_doc(ptr::null());
4474 let root = new_node(ptr::null_mut(), c_str("root"));
4475 doc_set_root_element(doc, root);
4476
4477 let text = new_text(c_str("hello world"));
4479 add_child(root, text);
4480
4481 let buf = io::buf_create(-1);
4482 assert!(!buf.is_null());
4483
4484 let ret = doc_dump(buf, doc);
4485 assert!(ret >= 0);
4486
4487 let expected = "<?xml version=\"1.0\"?>\n<root>hello world</root>\n";
4488 assert!(buf_eq_str(buf, expected));
4489
4490 io::buf_free(buf);
4491 free_doc(doc);
4492 }
4493 }
4494
4495 #[test]
4496 fn test_serialize_element_with_attributes() {
4497 unsafe {
4498 let doc = new_doc(ptr::null());
4499 let root = new_node(ptr::null_mut(), c_str("root"));
4500 doc_set_root_element(doc, root);
4501
4502 set_prop(root, c_str("id"), c_str("42"));
4503 set_prop(root, c_str("name"), c_str("test"));
4504
4505 let buf = io::buf_create(-1);
4506 assert!(!buf.is_null());
4507
4508 let ret = doc_dump(buf, doc);
4509 assert!(ret >= 0);
4510
4511 let expected = "<?xml version=\"1.0\"?>\n<root id=\"42\" name=\"test\"/>\n";
4512 assert!(buf_eq_str(buf, expected));
4513
4514 io::buf_free(buf);
4515 free_doc(doc);
4516 }
4517 }
4518
4519 #[test]
4520 fn test_serialize_nested_elements() {
4521 unsafe {
4522 let doc = new_doc(ptr::null());
4523 let root = new_node(ptr::null_mut(), c_str("root"));
4524 doc_set_root_element(doc, root);
4525
4526 let child = new_child(root, ptr::null_mut(), c_str("child"));
4527 let grandchild = new_child(child, ptr::null_mut(), c_str("gc"));
4528 let text = new_text(c_str("text"));
4529 add_child(grandchild, text);
4530
4531 let buf = io::buf_create(-1);
4532 assert!(!buf.is_null());
4533
4534 let ret = doc_dump(buf, doc);
4535 assert!(ret >= 0);
4536
4537 let expected = "<?xml version=\"1.0\"?>\n<root><child><gc>text</gc></child></root>\n";
4538 assert!(buf_eq_str(buf, expected));
4539
4540 io::buf_free(buf);
4541 free_doc(doc);
4542 }
4543 }
4544
4545 #[test]
4546 fn test_serialize_with_formatting() {
4547 unsafe {
4548 let doc = new_doc(ptr::null());
4549 let root = new_node(ptr::null_mut(), c_str("root"));
4550 doc_set_root_element(doc, root);
4551
4552 let child = new_child(root, ptr::null_mut(), c_str("child"));
4553 let text = new_text(c_str("text"));
4554 add_child(child, text);
4555
4556 let buf = io::buf_create(-1);
4557 assert!(!buf.is_null());
4558
4559 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
4560
4561 let expected = "<?xml version=\"1.0\"?>\n<root>\n <child>text</child>\n</root>\n";
4562 assert!(buf_eq_str(buf, expected));
4563
4564 io::buf_free(buf);
4565 free_doc(doc);
4566 }
4567 }
4568
4569 #[test]
4570 fn test_serialize_escape_ampersand() {
4571 unsafe {
4572 let doc = new_doc(ptr::null());
4573 let root = new_node(ptr::null_mut(), c_str("root"));
4574 doc_set_root_element(doc, root);
4575
4576 let text = new_text(c_str("a & b"));
4577 add_child(root, text);
4578
4579 let buf = io::buf_create(-1);
4580 assert!(!buf.is_null());
4581
4582 let ret = doc_dump(buf, doc);
4583 assert!(ret >= 0);
4584
4585 let expected = "<?xml version=\"1.0\"?>\n<root>a & b</root>\n";
4586 assert!(buf_eq_str(buf, expected));
4587
4588 io::buf_free(buf);
4589 free_doc(doc);
4590 }
4591 }
4592
4593 #[test]
4594 fn test_serialize_escape_angle_brackets() {
4595 unsafe {
4596 let doc = new_doc(ptr::null());
4597 let root = new_node(ptr::null_mut(), c_str("root"));
4598 doc_set_root_element(doc, root);
4599
4600 let text = new_text(c_str("x < y > z"));
4601 add_child(root, text);
4602
4603 let buf = io::buf_create(-1);
4604 assert!(!buf.is_null());
4605
4606 let ret = doc_dump(buf, doc);
4607 assert!(ret >= 0);
4608
4609 let expected = "<?xml version=\"1.0\"?>\n<root>x < y > z</root>\n";
4610 assert!(buf_eq_str(buf, expected));
4611
4612 io::buf_free(buf);
4613 free_doc(doc);
4614 }
4615 }
4616
4617 #[test]
4618 fn test_serialize_comment() {
4619 unsafe {
4620 let doc = new_doc(ptr::null());
4621 let root = new_node(ptr::null_mut(), c_str("root"));
4622 doc_set_root_element(doc, root);
4623
4624 let comment = new_comment(c_str("my comment"));
4625 add_child(root, comment);
4626
4627 let buf = io::buf_create(-1);
4628 assert!(!buf.is_null());
4629
4630 let ret = doc_dump(buf, doc);
4631 assert!(ret >= 0);
4632
4633 let expected = "<?xml version=\"1.0\"?>\n<root><!--my comment--></root>\n";
4634 assert!(buf_eq_str(buf, expected));
4635
4636 io::buf_free(buf);
4637 free_doc(doc);
4638 }
4639 }
4640
4641 #[test]
4642 fn test_serialize_pi() {
4643 unsafe {
4644 let doc = new_doc(ptr::null());
4645 let root = new_node(ptr::null_mut(), c_str("root"));
4646 doc_set_root_element(doc, root);
4647
4648 let pi = new_pi(
4649 c_str("xml-stylesheet"),
4650 c_str("href=\"style.xsl\" type=\"text/xsl\""),
4651 );
4652 add_child(root, pi);
4653
4654 let buf = io::buf_create(-1);
4655 assert!(!buf.is_null());
4656
4657 let ret = doc_dump(buf, doc);
4658 assert!(ret >= 0);
4659
4660 let expected = "<?xml version=\"1.0\"?>\n<root><?xml-stylesheet href=\"style.xsl\" type=\"text/xsl\"?></root>\n";
4661 assert!(buf_eq_str(buf, expected));
4662
4663 io::buf_free(buf);
4664 free_doc(doc);
4665 }
4666 }
4667
4668 #[test]
4669 fn test_serialize_self_closing() {
4670 unsafe {
4671 let doc = new_doc(ptr::null());
4672 let root = new_node(ptr::null_mut(), c_str("empty"));
4673 doc_set_root_element(doc, root);
4674
4675 let buf = io::buf_create(-1);
4676 assert!(!buf.is_null());
4677
4678 let ret = doc_dump(buf, doc);
4679 assert!(ret >= 0);
4680
4681 let expected = "<?xml version=\"1.0\"?>\n<empty/>\n";
4682 assert!(buf_eq_str(buf, expected));
4683
4684 io::buf_free(buf);
4685 free_doc(doc);
4686 }
4687 }
4688
4689 #[test]
4690 fn test_dump_node_to_string() {
4691 unsafe {
4692 let node = new_node(ptr::null_mut(), c_str("foo"));
4693 let text = new_text(c_str("bar"));
4694 add_child(node, text);
4695
4696 let result = dump_node(node);
4697 assert!(!result.is_null());
4698
4699 let len = xml_strlen(result);
4700 let slice = unsafe { core::slice::from_raw_parts(result, len as usize) };
4701 assert_eq!(slice, b"<foo>bar</foo>");
4702
4703 allocator::xmlFree(result as *mut c_void);
4704 free_node(node);
4705 }
4706 }
4707
4708 #[test]
4709 fn test_dump_doc_to_string() {
4710 unsafe {
4711 let doc = new_doc(ptr::null());
4712 let root = new_node(ptr::null_mut(), c_str("root"));
4713 doc_set_root_element(doc, root);
4714
4715 let result = dump_doc(doc);
4716 assert!(!result.is_null());
4717
4718 let len = xml_strlen(result);
4719 let slice = unsafe { core::slice::from_raw_parts(result, len as usize) };
4720 let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
4721 assert_eq!(slice, expected.as_bytes());
4722
4723 allocator::xmlFree(result as *mut c_void);
4724 free_doc(doc);
4725 }
4726 }
4727
4728 #[test]
4729 fn test_xmlDocDumpFormatMemory() {
4730 unsafe {
4731 let doc = new_doc(ptr::null());
4732 let root = new_node(ptr::null_mut(), c_str("root"));
4733 doc_set_root_element(doc, root);
4734
4735 let mut mem: *mut xmlChar = ptr::null_mut();
4736 let mut size: c_int = 0;
4737
4738 xmlDocDumpFormatMemory(doc, &mut mem, &mut size, 0);
4739
4740 assert!(!mem.is_null());
4741 assert!(size > 0);
4742
4743 let slice = unsafe { core::slice::from_raw_parts(mem, size as usize) };
4744 let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
4747 assert_eq!(slice, expected.as_bytes());
4748
4749 allocator::xmlFree(mem as *mut c_void);
4750 free_doc(doc);
4751 }
4752 }
4753
4754 #[test]
4755 fn test_serialize_escape_attribute() {
4756 unsafe {
4757 let doc = new_doc(ptr::null());
4758 let root = new_node(ptr::null_mut(), c_str("root"));
4759 doc_set_root_element(doc, root);
4760
4761 set_prop(root, c_str("desc"), c_str("a < b & c \"quoted\""));
4763
4764 let buf = io::buf_create(-1);
4765 assert!(!buf.is_null());
4766
4767 let ret = doc_dump(buf, doc);
4768 assert!(ret >= 0);
4769
4770 let expected =
4771 "<?xml version=\"1.0\"?>\n<root desc=\"a < b & c "quoted"\"/>\n";
4772 assert!(buf_eq_str(buf, expected));
4773
4774 io::buf_free(buf);
4775 free_doc(doc);
4776 }
4777 }
4778}