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::xmlMallocImpl(1) as *mut xmlChar };
68 if !buf.is_null() {
69 unsafe { *buf = 0 };
70 }
71 return buf;
72 }
73 let buf = unsafe { allocator::xmlMallocImpl(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 crate::abi::data_globals::register_node_hook(doc as *mut _xmlNode);
157
158 doc
159}
160
161pub unsafe fn free_doc(doc: *mut _xmlDoc) {
175 if doc.is_null() {
176 return;
177 }
178
179 crate::abi::data_globals::deregister_node_hook(doc as *mut _xmlNode);
182
183 let d = unsafe { &mut *doc };
184
185 if !d.intSubset.is_null() {
187 free_dtd(d.intSubset);
188 }
189
190 if !d.extSubset.is_null() {
192 free_dtd(d.extSubset);
193 }
194
195 if !d.children.is_null() {
197 free_node_list(d.children);
198 }
199
200 if !d.oldNs.is_null() {
202 free_ns_list(d.oldNs);
203 }
204
205 if !d.version.is_null() {
207 allocator::xmlFreeImpl(d.version as *mut c_void);
208 }
209 if !d.encoding.is_null() {
210 allocator::xmlFreeImpl(d.encoding as *mut c_void);
211 }
212 if !d.URL.is_null() {
213 allocator::xmlFreeImpl(d.URL as *mut c_void);
214 }
215
216 allocator::xmlFreeImpl(doc as *mut c_void);
218}
219
220pub unsafe fn copy_doc(doc: *const _xmlDoc, recursive: c_int) -> *mut _xmlDoc {
235 if doc.is_null() {
236 return ptr::null_mut();
237 }
238
239 let d = unsafe { &*doc };
240
241 let new_doc = new_doc(d.version);
242 if new_doc.is_null() {
243 return ptr::null_mut();
244 }
245
246 unsafe {
247 (*new_doc).type_ = d.type_;
248 (*new_doc).standalone = d.standalone;
249 (*new_doc).encoding = dup_xml_str(d.encoding);
250 (*new_doc).URL = dup_xml_str(d.URL);
251 (*new_doc).charset = d.charset;
252 (*new_doc).properties = d.properties;
253
254 if !d.intSubset.is_null() {
259 let dtd_copy = crate::xml::dtd::copy_dtd(d.intSubset);
260 if !dtd_copy.is_null() {
261 (*new_doc).intSubset = dtd_copy;
262 }
263 }
264
265 if recursive != 0 && !d.children.is_null() {
266 (*new_doc).children = copy_node_list(d.children, recursive);
267 if !(*new_doc).children.is_null() {
268 (*(*new_doc).children).parent = ptr::null_mut(); (*(*new_doc).children).doc = new_doc;
270 propagate_doc((*new_doc).children, new_doc);
272 }
273 }
274 }
275
276 new_doc
277}
278
279pub unsafe fn doc_set_root_element(doc: *mut _xmlDoc, root: *mut _xmlNode) -> *mut _xmlNode {
295 if doc.is_null() {
296 return ptr::null_mut();
297 }
298
299 let d = unsafe { &mut *doc };
300
301 let old_root = doc_get_root_element(doc);
302
303 if !root.is_null() {
304 unsafe {
305 (*root).parent = ptr::null_mut();
306 (*root).doc = doc;
307 }
308 d.children = root;
309 d.last = root;
310 unsafe {
311 (*root).prev = ptr::null_mut();
312 (*root).next = ptr::null_mut();
313 }
314 } else {
315 d.children = ptr::null_mut();
316 d.last = ptr::null_mut();
317 }
318
319 old_root
320}
321
322pub fn doc_get_root_element(doc: *mut _xmlDoc) -> *mut _xmlNode {
333 if doc.is_null() {
334 return ptr::null_mut();
335 }
336
337 let d = unsafe { &*doc };
338 let mut cur = d.children;
339
340 while !cur.is_null() {
341 let node = unsafe { &*cur };
342 if node.type_ == XML_ELEMENT_NODE as c_int {
343 return cur;
344 }
345 cur = node.next;
346 }
347
348 ptr::null_mut()
349}
350
351pub fn get_line_no(node: *const _xmlNode) -> c_int {
361 if node.is_null() {
362 return 0;
363 }
364 let n = unsafe { &*node };
365 n.line as c_int
366}
367
368pub unsafe fn node_get_content(node: *mut _xmlNode) -> *mut xmlChar {
388 if node.is_null() {
389 return ptr::null_mut();
390 }
391 let typ = (*node).type_;
392 let mut result: Vec<u8> = Vec::new();
393 match typ {
394 t if t == XML_TEXT_NODE as c_int
395 || t == XML_CDATA_SECTION_NODE as c_int
396 || t == XML_COMMENT_NODE as c_int
397 || t == XML_PI_NODE as c_int =>
398 {
399 if !(*node).content.is_null() {
400 let len = crate::abi::exports_xml2::xmlStrlen((*node).content);
401 result
402 .extend_from_slice(core::slice::from_raw_parts((*node).content, len as usize));
403 } else if t == XML_TEXT_NODE as c_int && !(*node).children.is_null() {
404 let mut child = (*node).children;
407 while !child.is_null() {
408 if !(*child).content.is_null() {
409 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
410 result.extend_from_slice(core::slice::from_raw_parts(
411 (*child).content,
412 len as usize,
413 ));
414 }
415 child = (*child).next;
416 }
417 }
418 }
419 t if t == XML_ATTRIBUTE_NODE as c_int => {
420 if !(*node).children.is_null() {
422 let child = (*node).children;
423 if !(*child).content.is_null() {
424 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
425 result.extend_from_slice(core::slice::from_raw_parts(
426 (*child).content,
427 len as usize,
428 ));
429 }
430 }
431 }
432 t if t == XML_ENTITY_REF_NODE as c_int => {
433 let name = (*node).name;
435 if !name.is_null() && !(*node).doc.is_null() {
436 let ent = crate::xml::tree::get_doc_entity((*node).doc, name);
437 if !ent.is_null() && !(*ent).content.is_null() {
438 let len = crate::abi::exports_xml2::xmlStrlen((*ent).content);
439 result.extend_from_slice(core::slice::from_raw_parts(
440 (*ent).content,
441 len as usize,
442 ));
443 }
444 }
445 }
446 t if t == XML_DOCUMENT_NODE as c_int || t == XML_HTML_DOCUMENT_NODE as c_int => {
447 let root = doc_get_root_element(node as *mut _xmlDoc);
448 if !root.is_null() {
449 let sub = node_get_content(root);
450 if !sub.is_null() {
451 let len = crate::abi::exports_xml2::xmlStrlen(sub);
452 result.extend_from_slice(core::slice::from_raw_parts(sub, len as usize));
453 allocator::xmlFreeImpl(sub as *mut c_void);
454 }
455 }
456 }
457 _ => {
458 let mut child = (*node).children;
463 while !child.is_null() {
464 let ctype = (*child).type_;
465 if ctype == XML_TEXT_NODE as c_int || ctype == XML_CDATA_SECTION_NODE as c_int {
466 if !(*child).content.is_null() {
467 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
468 result.extend_from_slice(core::slice::from_raw_parts(
469 (*child).content,
470 len as usize,
471 ));
472 }
473 } else if ctype == XML_ENTITY_REF_NODE as c_int
474 || ctype == XML_ELEMENT_NODE as c_int
475 {
476 let sub = node_get_content(child);
477 if !sub.is_null() {
478 let len = crate::abi::exports_xml2::xmlStrlen(sub);
479 result.extend_from_slice(core::slice::from_raw_parts(sub, len as usize));
480 allocator::xmlFreeImpl(sub as *mut c_void);
481 }
482 }
483 child = (*child).next;
484 }
485 }
486 }
487 let buf = allocator::xmlMallocImpl(result.len() + 1) as *mut xmlChar;
489 if buf.is_null() {
490 return ptr::null_mut();
491 }
492 if !result.is_empty() {
493 ptr::copy_nonoverlapping(result.as_ptr(), buf, result.len());
494 }
495 *buf.add(result.len()) = 0;
496 buf
497}
498
499pub unsafe fn new_node(ns: *mut _xmlNs, name: *const xmlChar) -> *mut _xmlNode {
518 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
519 if node.is_null() {
520 return ptr::null_mut();
521 }
522
523 unsafe {
524 (*node).type_ = XML_ELEMENT_NODE as c_int;
525 (*node).name = dup_xml_str(name);
526 (*node).ns = ns;
527 (*node).line = 0;
528 (*node).extra = 0;
529
530 if !ns.is_null() {
531 (*ns).context = node as *mut _xmlDoc;
532 }
533 }
534
535 crate::abi::data_globals::register_node_hook(node);
538
539 node
540}
541
542pub unsafe fn free_node(node: *mut _xmlNode) {
557 if node.is_null() {
558 return;
559 }
560
561 crate::abi::data_globals::deregister_node_hook(node);
564
565 let n = unsafe { &mut *node };
566
567 if n.type_ == XML_DTD_NODE as c_int {
570 free_dtd(node as *mut _xmlDtd);
571 return;
572 }
573
574 let is_element = n.type_ == XML_ELEMENT_NODE as c_int;
579 if is_element && !n.properties.is_null() {
580 free_prop_list(n.properties);
581 }
582
583 if is_element && !n.nsDef.is_null() {
584 free_ns_list(n.nsDef);
585 }
586
587 if !n.name.is_null() {
589 allocator::xmlFreeImpl(n.name as *mut c_void);
590 }
591
592 if !n.content.is_null() {
596 let node_type = n.type_;
597 if node_type == XML_TEXT_NODE as c_int
598 || node_type == XML_CDATA_SECTION_NODE as c_int
599 || node_type == XML_COMMENT_NODE as c_int
600 || node_type == XML_PI_NODE as c_int
601 {
602 let inline_addr = std::ptr::addr_of_mut!((*node).properties) as *const c_void;
603 if n.content as *const c_void != inline_addr {
604 allocator::xmlFreeImpl(n.content as *mut c_void);
605 }
606 }
607 }
608
609 allocator::xmlFreeImpl(node as *mut c_void);
610}
611
612pub unsafe fn free_node_list(node: *mut _xmlNode) {
620 let mut cur = node;
621 while !cur.is_null() {
622 let next = unsafe { (*cur).next };
623
624 if !unsafe { (*cur).children }.is_null() {
626 free_node_list(unsafe { (*cur).children });
627 }
628
629 free_node(cur);
630 cur = next;
631 }
632}
633
634unsafe fn free_prop_list(prop: *mut _xmlAttr) {
640 let mut cur = prop;
641 while !cur.is_null() {
642 let next = unsafe { (*cur).next };
643
644 if !unsafe { (*cur).children }.is_null() {
646 free_node_list(unsafe { (*cur).children });
647 }
648
649 if !unsafe { (*cur).name }.is_null() {
651 allocator::xmlFreeImpl(unsafe { (*cur).name } as *mut c_void);
652 }
653
654 allocator::xmlFreeImpl(cur as *mut c_void);
655 cur = next;
656 }
657}
658
659unsafe fn free_ns_list(ns: *mut _xmlNs) {
665 let mut cur = ns;
666 while !cur.is_null() {
667 let next = unsafe { (*cur).next };
668
669 if !unsafe { (*cur).href }.is_null() {
671 allocator::xmlFreeImpl(unsafe { (*cur).href } as *mut c_void);
672 }
673 if !unsafe { (*cur).prefix }.is_null() {
674 allocator::xmlFreeImpl(unsafe { (*cur).prefix } as *mut c_void);
675 }
676
677 allocator::xmlFreeImpl(cur as *mut c_void);
678 cur = next;
679 }
680}
681
682pub unsafe fn copy_node(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
697 if node.is_null() {
698 return ptr::null_mut();
699 }
700
701 let n = unsafe { &*node };
702
703 let new_node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
704 if new_node.is_null() {
705 return ptr::null_mut();
706 }
707
708 unsafe {
709 (*new_node).type_ = n.type_;
710 (*new_node).name = dup_xml_str(n.name);
711 (*new_node).line = n.line;
712 (*new_node).extra = n.extra;
713 (*new_node).psvi = n.psvi;
714 (*new_node)._private = n._private;
715
716 (*new_node).ns = n.ns;
718
719 let is_element = n.type_ == XML_ELEMENT_NODE as c_int;
722 if is_element && !n.nsDef.is_null() {
723 (*new_node).nsDef = copy_ns_list(n.nsDef);
724 }
725
726 let node_type = n.type_;
728 if (node_type == XML_TEXT_NODE as c_int
729 || node_type == XML_CDATA_SECTION_NODE as c_int
730 || node_type == XML_COMMENT_NODE as c_int
731 || node_type == XML_PI_NODE as c_int)
732 && !n.content.is_null()
733 {
734 (*new_node).content = dup_xml_str(n.content);
735 }
736
737 if is_element && !n.properties.is_null() {
739 (*new_node).properties = copy_prop_list(n.properties);
740 let mut prop = (*new_node).properties;
742 while !prop.is_null() {
743 (*prop).parent = new_node;
744 if !(*prop).children.is_null() {
745 propagate_doc((*prop).children, (*new_node).doc);
746 }
747 prop = (*prop).next;
748 }
749 }
750
751 if recursive != 0 && !n.children.is_null() {
753 (*new_node).children = copy_node_list(n.children, recursive);
754 if !(*new_node).children.is_null() {
755 (*(*new_node).children).parent = new_node;
756 (*(*new_node).children).doc = (*new_node).doc;
757 propagate_doc((*new_node).children, (*new_node).doc);
758 }
759 }
760 }
761
762 new_node
763}
764
765unsafe fn copy_node_list(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
769 if node.is_null() {
770 return ptr::null_mut();
771 }
772
773 let n = unsafe { &*node };
774 let new_node = copy_node(node, recursive);
775 if new_node.is_null() {
776 return ptr::null_mut();
777 }
778
779 let mut prev = new_node;
780 let mut cur = n.next;
781
782 while !cur.is_null() {
783 let new_cur = copy_node(cur, recursive);
784 if new_cur.is_null() {
785 break;
786 }
787 unsafe {
788 (*prev).next = new_cur;
789 (*new_cur).prev = prev;
790 }
791 prev = new_cur;
792 cur = unsafe { (*cur).next };
793 }
794
795 new_node
796}
797
798unsafe fn copy_ns_list(ns: *const _xmlNs) -> *mut _xmlNs {
800 if ns.is_null() {
801 return ptr::null_mut();
802 }
803
804 let n = unsafe { &*ns };
805 let new_ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
806 if new_ns.is_null() {
807 return ptr::null_mut();
808 }
809
810 unsafe {
811 (*new_ns).type_ = n.type_;
812 (*new_ns).href = dup_xml_str(n.href);
813 (*new_ns).prefix = dup_xml_str(n.prefix);
814 (*new_ns)._private = n._private;
815 }
816
817 let mut prev = new_ns;
818 let mut cur = n.next;
819
820 while !cur.is_null() {
821 let c = unsafe { &*cur };
822 let new_cur = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
823 if new_cur.is_null() {
824 break;
825 }
826 unsafe {
827 (*new_cur).type_ = c.type_;
828 (*new_cur).href = dup_xml_str(c.href);
829 (*new_cur).prefix = dup_xml_str(c.prefix);
830 (*new_cur)._private = c._private;
831 (*prev).next = new_cur;
832 }
833 prev = new_cur;
834 cur = c.next;
835 }
836
837 new_ns
838}
839
840unsafe fn copy_prop_list(prop: *const _xmlAttr) -> *mut _xmlAttr {
842 if prop.is_null() {
843 return ptr::null_mut();
844 }
845
846 let p = unsafe { &*prop };
847 let new_prop = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
848 if new_prop.is_null() {
849 return ptr::null_mut();
850 }
851
852 unsafe {
853 (*new_prop).type_ = p.type_;
854 (*new_prop).name = dup_xml_str(p.name);
855 (*new_prop).ns = p.ns;
856 (*new_prop).atype = p.atype;
857
858 if !p.children.is_null() {
860 (*new_prop).children = copy_node_list(p.children, 1);
861 if !(*new_prop).children.is_null() {
862 (*(*new_prop).children).parent = new_prop as *mut _xmlNode;
863 }
864 }
865 }
866
867 let mut prev = new_prop;
868 let mut cur = p.next;
869
870 while !cur.is_null() {
871 let c = unsafe { &*cur };
872 let new_cur = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
873 if new_cur.is_null() {
874 break;
875 }
876 unsafe {
877 (*new_cur).type_ = c.type_;
878 (*new_cur).name = dup_xml_str(c.name);
879 (*new_cur).ns = c.ns;
880 (*new_cur).atype = c.atype;
881
882 if !c.children.is_null() {
883 (*new_cur).children = copy_node_list(c.children, 1);
884 if !(*new_cur).children.is_null() {
885 (*(*new_cur).children).parent = new_cur as *mut _xmlNode;
886 }
887 }
888
889 (*prev).next = new_cur;
890 }
891 prev = new_cur;
892 cur = c.next;
893 }
894
895 new_prop
896}
897
898unsafe fn propagate_doc(node: *mut _xmlNode, doc: *mut _xmlDoc) {
900 let mut cur = node;
901 while !cur.is_null() {
902 unsafe {
903 (*cur).doc = doc;
904
905 if (*cur).type_ == XML_ELEMENT_NODE as c_int {
909 let mut prop = (*cur).properties;
910 while !prop.is_null() {
911 (*prop).doc = doc;
912 if !(*prop).children.is_null() {
913 propagate_doc((*prop).children, doc);
914 }
915 prop = (*prop).next;
916 }
917 }
918
919 if !(*cur).children.is_null() {
921 propagate_doc((*cur).children, doc);
922 }
923 }
924 cur = unsafe { (*cur).next };
925 }
926}
927
928pub unsafe fn unlink_node(node: *mut _xmlNode) {
944 if node.is_null() {
945 return;
946 }
947
948 let n = unsafe { &mut *node };
949
950 let prev = n.prev;
952 let next = n.next;
953
954 if !prev.is_null() {
955 unsafe { (*prev).next = next };
956 }
957 if !next.is_null() {
958 unsafe { (*next).prev = prev };
959 }
960
961 let parent = n.parent;
963 if !parent.is_null() {
964 if unsafe { (*parent).children } == node {
965 unsafe { (*parent).children = next };
966 }
967 if unsafe { (*parent).last } == node {
968 unsafe { (*parent).last = prev };
969 }
970 }
971
972 let doc = n.doc;
974 if !doc.is_null() && !parent.is_null() {
975 }
977 if !doc.is_null() && parent.is_null() {
978 if unsafe { (*doc).children } == node {
980 unsafe { (*doc).children = next };
981 }
982 if unsafe { (*doc).last } == node {
983 unsafe { (*doc).last = prev };
984 }
985 }
986
987 n.parent = ptr::null_mut();
989 n.prev = ptr::null_mut();
990 n.next = ptr::null_mut();
991}
992
993pub unsafe fn add_child(parent: *mut _xmlNode, cur: *mut _xmlNode) -> *mut _xmlNode {
1009 if parent.is_null() || cur.is_null() {
1010 return ptr::null_mut();
1011 }
1012
1013 let p = unsafe { &mut *parent };
1014 let c = unsafe { &mut *cur };
1015
1016 if !c.parent.is_null() || !c.prev.is_null() || !c.next.is_null() {
1018 unlink_node(cur);
1019 }
1020
1021 c.parent = parent;
1023
1024 if p.children.is_null() {
1025 p.children = cur;
1027 p.last = cur;
1028 c.prev = ptr::null_mut();
1029 c.next = ptr::null_mut();
1030 } else {
1031 c.prev = p.last;
1033 c.next = ptr::null_mut();
1034 if !p.last.is_null() {
1035 unsafe { (*p.last).next = cur };
1036 }
1037 p.last = cur;
1038 }
1039
1040 let doc = if !p.doc.is_null() {
1042 p.doc
1043 } else {
1044 ptr::null_mut()
1045 };
1046 if !doc.is_null() && c.doc != doc {
1047 propagate_doc(cur, doc);
1048 }
1049
1050 cur
1051}
1052
1053pub unsafe fn add_sibling(cur: *mut _xmlNode, elem: *mut _xmlNode) -> *mut _xmlNode {
1069 if cur.is_null() || elem.is_null() {
1070 return ptr::null_mut();
1071 }
1072
1073 let c = unsafe { &mut *cur };
1074
1075 let e = unsafe { &mut *elem };
1077 if !e.parent.is_null() || !e.prev.is_null() || !e.next.is_null() {
1078 unlink_node(elem);
1079 }
1080
1081 e.parent = c.parent;
1083
1084 e.prev = cur;
1086 e.next = c.next;
1087
1088 if !c.next.is_null() {
1089 unsafe { (*c.next).prev = elem };
1090 }
1091 c.next = elem;
1092
1093 let parent = c.parent;
1095 if !parent.is_null() && unsafe { (*parent).last } == cur {
1096 unsafe { (*parent).last = elem };
1097 }
1098
1099 if !c.doc.is_null() && e.doc != c.doc {
1101 propagate_doc(elem, c.doc);
1102 }
1103
1104 elem
1105}
1106
1107pub unsafe fn add_sibling_before(cur: *mut _xmlNode, elem: *mut _xmlNode) -> *mut _xmlNode {
1123 if cur.is_null() || elem.is_null() {
1124 return ptr::null_mut();
1125 }
1126
1127 let c = unsafe { &mut *cur };
1128
1129 let e = unsafe { &mut *elem };
1131 if !e.parent.is_null() || !e.prev.is_null() || !e.next.is_null() {
1132 unlink_node(elem);
1133 }
1134
1135 e.parent = c.parent;
1137
1138 e.prev = c.prev;
1140 e.next = cur;
1141
1142 if !c.prev.is_null() {
1143 unsafe { (*c.prev).next = elem };
1144 }
1145 c.prev = elem;
1146
1147 let parent = c.parent;
1149 if !parent.is_null() && unsafe { (*parent).children } == cur {
1150 unsafe { (*parent).children = elem };
1151 }
1152
1153 let doc = c.doc;
1155 if !doc.is_null() && parent.is_null() {
1156 if unsafe { (*doc).children } == cur {
1157 unsafe { (*doc).children = elem };
1158 }
1159 }
1160
1161 if !c.doc.is_null() && e.doc != c.doc {
1163 propagate_doc(elem, c.doc);
1164 }
1165
1166 elem
1167}
1168
1169pub unsafe fn new_child(
1184 parent: *mut _xmlNode,
1185 ns: *mut _xmlNs,
1186 name: *const xmlChar,
1187) -> *mut _xmlNode {
1188 let node = new_node(ns, name);
1189 if node.is_null() {
1190 return ptr::null_mut();
1191 }
1192
1193 if !parent.is_null() {
1194 add_child(parent, node);
1195 }
1196
1197 node
1198}
1199
1200pub unsafe fn new_text(content: *const xmlChar) -> *mut _xmlNode {
1219 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1220 if node.is_null() {
1221 return ptr::null_mut();
1222 }
1223
1224 unsafe {
1225 (*node).type_ = XML_TEXT_NODE as c_int;
1226 (*node).name = dup_xml_str(b"text\0" as *const u8 as *const xmlChar);
1227 (*node).content = if content.is_null() {
1228 let empty = allocator::xmlMallocImpl(1) as *mut xmlChar;
1229 if !empty.is_null() {
1230 *empty = 0;
1231 }
1232 empty
1233 } else {
1234 dup_xml_str(content)
1235 };
1236 (*node).line = 0;
1237 }
1238
1239 crate::abi::data_globals::register_node_hook(node);
1242
1243 node
1244}
1245
1246pub unsafe fn new_comment(content: *const xmlChar) -> *mut _xmlNode {
1260 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1261 if node.is_null() {
1262 return ptr::null_mut();
1263 }
1264
1265 unsafe {
1266 (*node).type_ = XML_COMMENT_NODE as c_int;
1267 (*node).name = dup_xml_str(b"comment\0" as *const u8 as *const xmlChar);
1268 (*node).content = dup_xml_str(content);
1269 (*node).line = 0;
1270 }
1271
1272 crate::abi::data_globals::register_node_hook(node);
1275
1276 node
1277}
1278
1279pub unsafe fn new_pi(name: *const xmlChar, content: *const xmlChar) -> *mut _xmlNode {
1294 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1295 if node.is_null() {
1296 return ptr::null_mut();
1297 }
1298
1299 unsafe {
1300 (*node).type_ = XML_PI_NODE as c_int;
1301 (*node).name = dup_xml_str(name);
1302 (*node).content = dup_xml_str(content);
1303 (*node).line = 0;
1304 }
1305
1306 crate::abi::data_globals::register_node_hook(node);
1309
1310 node
1311}
1312
1313pub unsafe fn new_cdata_block(
1329 doc: *mut _xmlDoc,
1330 content: *const xmlChar,
1331 len: c_int,
1332) -> *mut _xmlNode {
1333 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1334 if node.is_null() {
1335 return ptr::null_mut();
1336 }
1337
1338 unsafe {
1339 (*node).type_ = XML_CDATA_SECTION_NODE as c_int;
1340 (*node).name = dup_xml_str(b"cdata\0" as *const u8 as *const xmlChar);
1341 (*node).doc = doc;
1342
1343 if !content.is_null() && len > 0 {
1344 (*node).content = allocator::xmlMallocImpl((len + 1) as usize) as *mut xmlChar;
1345 if !(*node).content.is_null() {
1346 ptr::copy_nonoverlapping(content, (*node).content, len as usize);
1347 *((*node).content.add(len as usize)) = 0;
1348 }
1349 } else {
1350 let empty = allocator::xmlMallocImpl(1) as *mut xmlChar;
1351 if !empty.is_null() {
1352 *empty = 0;
1353 }
1354 (*node).content = empty;
1355 }
1356
1357 (*node).line = 0;
1358 }
1359
1360 node
1361}
1362
1363pub unsafe fn new_ns(
1387 node: *mut _xmlNode,
1388 href: *const xmlChar,
1389 prefix: *const xmlChar,
1390) -> *mut _xmlNs {
1391 let ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
1392 if ns.is_null() {
1393 return ptr::null_mut();
1394 }
1395
1396 unsafe {
1397 (*ns).type_ = XML_LOCAL_NAMESPACE as c_int;
1398 (*ns).href = dup_xml_str(href);
1399 (*ns).prefix = dup_xml_str(prefix);
1400 (*ns).context = node as *mut _xmlDoc;
1401
1402 if !node.is_null() {
1404 let n = &mut *node;
1405 if n.nsDef.is_null() {
1406 n.nsDef = ns;
1407 } else {
1408 let mut last = n.nsDef;
1410 while !(*last).next.is_null() {
1411 last = (*last).next;
1412 }
1413 (*last).next = ns;
1414 }
1415 }
1416 }
1417
1418 ns
1419}
1420
1421pub unsafe fn set_ns(node: *mut _xmlNode, ns: *mut _xmlNs) {
1434 if node.is_null() {
1435 return;
1436 }
1437 unsafe {
1438 (*node).ns = ns;
1439 }
1440}
1441
1442pub unsafe fn get_ns_list(doc: *mut _xmlDoc, node: *mut _xmlNode) -> *mut *mut _xmlNs {
1458 if node.is_null() {
1462 return ptr::null_mut();
1463 }
1464
1465 let mut ns_ptrs: Vec<*mut _xmlNs> = Vec::new();
1467 let mut cur = node;
1468
1469 while !cur.is_null() {
1470 let n = unsafe { &*cur };
1471 let mut ns_def = n.nsDef;
1472 while !ns_def.is_null() {
1473 let ns = unsafe { &*ns_def };
1475 let mut found = false;
1476 for &existing in &ns_ptrs {
1477 if existing == ns_def {
1478 found = true;
1479 break;
1480 }
1481 let e = unsafe { &*existing };
1482 if !ns.href.is_null() && !e.href.is_null() {
1483 let href_match =
1484 unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, e.href) != 0 };
1485 if href_match {
1486 if ns.prefix.is_null() && e.prefix.is_null() {
1487 found = true;
1488 break;
1489 }
1490 if !ns.prefix.is_null() && !e.prefix.is_null() {
1491 let prefix_match = unsafe {
1492 crate::abi::exports_xml2::xmlStrEqual(ns.prefix, e.prefix) != 0
1493 };
1494 if prefix_match {
1495 found = true;
1496 break;
1497 }
1498 }
1499 }
1500 }
1501 }
1502 if !found {
1503 ns_ptrs.push(ns_def);
1504 }
1505 ns_def = unsafe { (*ns_def).next };
1506 }
1507 cur = n.parent;
1508 }
1509
1510 if ns_ptrs.is_empty() {
1511 return ptr::null_mut();
1512 }
1513
1514 let arr = allocator::xmlMallocImpl((ns_ptrs.len() + 1) * size_of::<*mut _xmlNs>())
1516 as *mut *mut _xmlNs;
1517 if arr.is_null() {
1518 return ptr::null_mut();
1519 }
1520
1521 for (i, ns) in ns_ptrs.iter().enumerate() {
1522 unsafe { *arr.add(i) = *ns };
1523 }
1524 unsafe { *arr.add(ns_ptrs.len()) = ptr::null_mut() };
1525
1526 arr
1527}
1528
1529pub unsafe fn search_ns(
1546 doc: *mut _xmlDoc,
1547 node: *mut _xmlNode,
1548 name_space: *const xmlChar,
1549) -> *mut _xmlNs {
1550 if node.is_null() {
1551 return ptr::null_mut();
1552 }
1553
1554 let mut cur = node;
1555 while !cur.is_null() {
1556 let n = unsafe { &*cur };
1557 let mut ns_def = n.nsDef;
1558 while !ns_def.is_null() {
1559 let ns = unsafe { &*ns_def };
1560 let match_prefix = if name_space.is_null() {
1561 ns.prefix.is_null()
1563 } else {
1564 !ns.prefix.is_null()
1565 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.prefix, name_space) != 0 }
1566 };
1567 if match_prefix {
1568 return ns_def;
1569 }
1570 ns_def = unsafe { (*ns_def).next };
1571 }
1572 cur = n.parent;
1573 }
1574
1575 ptr::null_mut()
1576}
1577
1578pub unsafe fn search_ns_by_href(
1594 doc: *mut _xmlDoc,
1595 node: *mut _xmlNode,
1596 href: *const xmlChar,
1597) -> *mut _xmlNs {
1598 if node.is_null() || href.is_null() {
1599 return ptr::null_mut();
1600 }
1601
1602 let mut cur = node;
1603 while !cur.is_null() {
1604 let n = unsafe { &*cur };
1605 let mut ns_def = n.nsDef;
1606 while !ns_def.is_null() {
1607 let ns = unsafe { &*ns_def };
1608 if !ns.href.is_null()
1609 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, href) != 0 }
1610 {
1611 return ns_def;
1612 }
1613 ns_def = unsafe { (*ns_def).next };
1614 }
1615 cur = n.parent;
1616 }
1617
1618 ptr::null_mut()
1619}
1620
1621pub unsafe fn set_prop(
1645 node: *mut _xmlNode,
1646 name: *const xmlChar,
1647 value: *const xmlChar,
1648) -> *mut _xmlAttr {
1649 if node.is_null() || name.is_null() {
1650 return ptr::null_mut();
1651 }
1652
1653 let n = unsafe { &mut *node };
1654
1655 let mut existing = n.properties;
1657 while !existing.is_null() {
1658 let attr = unsafe { &*existing };
1659 if !attr.name.is_null()
1660 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1661 {
1662 if !attr.children.is_null() {
1665 free_node_list(attr.children);
1666 let attr_mut = existing as *mut _xmlAttr;
1668 unsafe { (*attr_mut).children = ptr::null_mut() };
1669 unsafe { (*attr_mut).last = ptr::null_mut() };
1670 }
1671 if !value.is_null() {
1673 let text = new_text(value);
1674 if !text.is_null() {
1675 let attr_mut = existing as *mut _xmlAttr;
1676 unsafe {
1677 (*attr_mut).children = text;
1678 (*attr_mut).last = text;
1679 (*text).parent = existing as *mut _xmlNode;
1680 (*text).doc = n.doc;
1681 }
1682 }
1683 }
1684 return existing;
1685 }
1686 existing = unsafe { (*existing).next };
1687 }
1688
1689 let attr = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
1691 if attr.is_null() {
1692 return ptr::null_mut();
1693 }
1694
1695 unsafe {
1696 (*attr).type_ = XML_ATTRIBUTE_NODE as c_int;
1697 (*attr).name = dup_xml_str(name);
1698 (*attr).parent = node;
1699 (*attr).doc = n.doc;
1700 (*attr).atype = XML_ATTRIBUTE_CDATA as c_int;
1701
1702 if !value.is_null() {
1704 let text = new_text(value);
1705 if !text.is_null() {
1706 (*attr).children = text;
1707 (*attr).last = text;
1708 (*text).parent = attr as *mut _xmlNode;
1709 (*text).doc = n.doc;
1710 }
1711 }
1712
1713 if n.properties.is_null() {
1715 n.properties = attr;
1716 } else {
1717 let mut last = n.properties;
1718 while !(*last).next.is_null() {
1719 last = (*last).next;
1720 }
1721 (*last).next = attr;
1722 (*attr).prev = last;
1723 }
1724 }
1725
1726 attr
1727}
1728
1729pub unsafe fn get_prop(node: *mut _xmlNode, name: *const xmlChar) -> *mut xmlChar {
1745 if node.is_null() || name.is_null() {
1746 return ptr::null_mut();
1747 }
1748
1749 let n = unsafe { &*node };
1750 let mut cur = n.properties;
1751
1752 while !cur.is_null() {
1753 let attr = unsafe { &*cur };
1754 if !attr.name.is_null()
1755 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1756 {
1757 if !attr.children.is_null() {
1759 let text = unsafe { &*attr.children };
1760 if text.type_ == XML_TEXT_NODE as c_int && !text.content.is_null() {
1761 return dup_xml_str(text.content);
1762 }
1763 }
1764 return dup_xml_str(b"\0" as *const u8 as *const xmlChar);
1765 }
1766 cur = unsafe { (*cur).next };
1767 }
1768
1769 ptr::null_mut()
1770}
1771
1772pub unsafe fn get_ns_prop(
1788 node: *mut _xmlNode,
1789 name: *const xmlChar,
1790 _name_space: *const xmlChar,
1791) -> *mut xmlChar {
1792 get_prop(node, name)
1795}
1796
1797pub unsafe fn set_ns_prop(
1812 node: *mut _xmlNode,
1813 _ns: *mut _xmlNs,
1814 name: *const xmlChar,
1815 value: *const xmlChar,
1816) -> *mut _xmlAttr {
1817 set_prop(node, name, value)
1819}
1820
1821pub unsafe fn remove_prop(attr: *mut _xmlAttr) -> c_int {
1836 if attr.is_null() {
1837 return -1;
1838 }
1839
1840 let a = unsafe { &mut *attr };
1841
1842 let parent = a.parent;
1844 if !parent.is_null() {
1845 let p = unsafe { &mut *parent };
1846 if p.properties == attr {
1847 p.properties = a.next;
1848 }
1849 }
1850
1851 if !a.prev.is_null() {
1853 unsafe { (*a.prev).next = a.next };
1854 }
1855 if !a.next.is_null() {
1856 unsafe { (*a.next).prev = a.prev };
1857 }
1858
1859 if !a.children.is_null() {
1861 free_node_list(a.children);
1862 }
1863
1864 if !a.name.is_null() {
1866 allocator::xmlFreeImpl(a.name as *mut c_void);
1867 }
1868
1869 allocator::xmlFreeImpl(attr as *mut c_void);
1870 0
1871}
1872
1873pub unsafe fn has_prop(node: *mut _xmlNode, name: *const xmlChar) -> *mut _xmlAttr {
1881 if node.is_null() || name.is_null() {
1882 return ptr::null_mut();
1883 }
1884 let mut cur = unsafe { (*node).properties };
1885 while !cur.is_null() {
1886 let attr = unsafe { &*cur };
1887 if !attr.name.is_null()
1888 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1889 && attr.ns.is_null()
1890 {
1891 return cur;
1892 }
1893 cur = unsafe { (*cur).next };
1894 }
1895 ptr::null_mut()
1896}
1897
1898pub unsafe fn has_ns_prop(
1908 node: *mut _xmlNode,
1909 name: *const xmlChar,
1910 name_space: *const xmlChar,
1911) -> *mut _xmlAttr {
1912 if node.is_null() || name.is_null() {
1913 return ptr::null_mut();
1914 }
1915 let mut cur = unsafe { (*node).properties };
1916 while !cur.is_null() {
1917 let attr = unsafe { &*cur };
1918 if !attr.name.is_null()
1919 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1920 {
1921 if name_space.is_null() {
1922 if attr.ns.is_null() {
1923 return cur;
1924 }
1925 } else if !attr.ns.is_null() && !(*attr.ns).href.is_null() {
1926 if unsafe {
1927 crate::abi::exports_xml2::xmlStrEqual((*attr.ns).href, name_space) != 0
1928 } {
1929 return cur;
1930 }
1931 }
1932 }
1933 cur = unsafe { (*cur).next };
1934 }
1935 ptr::null_mut()
1936}
1937
1938pub unsafe fn unset_prop(node: *mut _xmlNode, name: *const xmlChar) -> c_int {
1947 let attr = unsafe { has_prop(node, name) };
1948 if attr.is_null() {
1949 return -1;
1950 }
1951 unsafe { remove_prop(attr) }
1952}
1953
1954pub unsafe fn unset_ns_prop(
1962 node: *mut _xmlNode,
1963 name: *const xmlChar,
1964 name_space: *const xmlChar,
1965) -> c_int {
1966 let attr = unsafe { has_ns_prop(node, name, name_space) };
1967 if attr.is_null() {
1968 return -1;
1969 }
1970 unsafe { remove_prop(attr) }
1971}
1972
1973pub unsafe fn first_element_child(node: *mut _xmlNode) -> *mut _xmlNode {
1980 if node.is_null() {
1981 return ptr::null_mut();
1982 }
1983 let mut cur = unsafe { (*node).children };
1984 while !cur.is_null() {
1985 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
1986 return cur;
1987 }
1988 cur = unsafe { (*cur).next };
1989 }
1990 ptr::null_mut()
1991}
1992
1993pub unsafe fn last_element_child(node: *mut _xmlNode) -> *mut _xmlNode {
2000 if node.is_null() {
2001 return ptr::null_mut();
2002 }
2003 let mut cur = unsafe { (*node).last };
2004 while !cur.is_null() {
2005 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2006 return cur;
2007 }
2008 cur = unsafe { (*cur).prev };
2009 }
2010 ptr::null_mut()
2011}
2012
2013pub unsafe fn next_element_sibling(node: *mut _xmlNode) -> *mut _xmlNode {
2020 if node.is_null() {
2021 return ptr::null_mut();
2022 }
2023 let mut cur = unsafe { (*node).next };
2024 while !cur.is_null() {
2025 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2026 return cur;
2027 }
2028 cur = unsafe { (*cur).next };
2029 }
2030 ptr::null_mut()
2031}
2032
2033pub unsafe fn previous_element_sibling(node: *mut _xmlNode) -> *mut _xmlNode {
2040 if node.is_null() {
2041 return ptr::null_mut();
2042 }
2043 let mut cur = unsafe { (*node).prev };
2044 while !cur.is_null() {
2045 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2046 return cur;
2047 }
2048 cur = unsafe { (*cur).prev };
2049 }
2050 ptr::null_mut()
2051}
2052
2053pub unsafe fn child_element_count(node: *mut _xmlNode) -> c_ulong {
2060 if node.is_null() {
2061 return 0;
2062 }
2063 let mut cur = unsafe { (*node).children };
2064 let mut count: c_ulong = 0;
2065 while !cur.is_null() {
2066 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2067 count += 1;
2068 }
2069 cur = unsafe { (*cur).next };
2070 }
2071 count
2072}
2073
2074pub unsafe fn text_concat(node: *mut _xmlNode, str: *const xmlChar, num: c_int) -> c_int {
2083 if node.is_null() || str.is_null() || num <= 0 {
2084 return -1;
2085 }
2086 let cur = unsafe { &mut *node };
2087 if cur.content.is_null() {
2088 let p = unsafe { allocator::xmlMallocImpl(num as usize + 1) as *mut xmlChar };
2089 if p.is_null() {
2090 return -1;
2091 }
2092 unsafe {
2093 ptr::copy_nonoverlapping(str, p, num as usize);
2094 *p.add(num as usize) = 0;
2095 }
2096 cur.content = p;
2097 return 0;
2098 }
2099 let old_len = unsafe { crate::xml::string::xml_strlen(cur.content) };
2100 let p = unsafe {
2101 allocator::xmlReallocImpl(cur.content as *mut c_void, old_len + num as usize + 1)
2102 as *mut xmlChar
2103 };
2104 if p.is_null() {
2105 return -1;
2106 }
2107 unsafe {
2108 ptr::copy_nonoverlapping(str, p.add(old_len), num as usize);
2109 *p.add(old_len + num as usize) = 0;
2110 }
2111 cur.content = p;
2112 0
2113}
2114
2115pub unsafe fn text_merge(text: *mut _xmlNode, ntext: *mut _xmlNode) -> *mut _xmlNode {
2123 if text.is_null() || ntext.is_null() {
2124 return ptr::null_mut();
2125 }
2126 if unsafe { (*ntext).content.is_null() } {
2127 unsafe { free_node(ntext) };
2128 return text;
2129 }
2130 let num = unsafe { crate::xml::string::xml_strlen((*ntext).content) };
2131 if unsafe { text_concat(text, (*ntext).content, num as c_int) } != 0 {
2132 return ptr::null_mut();
2133 }
2134 unsafe { free_node(ntext) };
2135 text
2136}
2137
2138pub fn get_int_subset(doc: *const _xmlDoc) -> *mut _xmlDtd {
2150 if doc.is_null() {
2151 return ptr::null_mut();
2152 }
2153 let d = unsafe { &*doc };
2154 d.intSubset
2155}
2156
2157pub unsafe fn new_dtd(
2174 doc: *mut _xmlDoc,
2175 name: *const xmlChar,
2176 ExternalID: *const xmlChar,
2177 SystemID: *const xmlChar,
2178) -> *mut _xmlDtd {
2179 let dtd = allocator::xmlMallocZero(size_of::<_xmlDtd>() as usize) as *mut _xmlDtd;
2180 if dtd.is_null() {
2181 return ptr::null_mut();
2182 }
2183
2184 unsafe {
2185 (*dtd).type_ = XML_DTD_NODE as c_int;
2186 (*dtd).name = dup_xml_str(name);
2187 (*dtd).ExternalID = dup_xml_str(ExternalID);
2188 (*dtd).SystemID = dup_xml_str(SystemID);
2189 (*dtd).parent = doc;
2190 (*dtd).doc = doc;
2191
2192 (*dtd).notations = crate::xml::hash::hash_create(8) as *mut c_void;
2195 (*dtd).elements = crate::xml::hash::hash_create(16) as *mut c_void;
2196 (*dtd).attributes = crate::xml::hash::hash_create(16) as *mut c_void;
2197 (*dtd).entities = crate::xml::hash::hash_create(8) as *mut c_void;
2198 (*dtd).pentities = crate::xml::hash::hash_create(8) as *mut c_void;
2199
2200 if !doc.is_null() {
2202 if (*doc).intSubset.is_null() {
2203 (*doc).intSubset = dtd;
2204 }
2205 }
2206 }
2207
2208 dtd
2209}
2210
2211unsafe fn free_dtd(dtd: *mut _xmlDtd) {
2217 if dtd.is_null() {
2218 return;
2219 }
2220
2221 let d = unsafe { &mut *dtd };
2222
2223 if !d.name.is_null() {
2225 allocator::xmlFreeImpl(d.name as *mut c_void);
2226 }
2227 if !d.ExternalID.is_null() {
2228 allocator::xmlFreeImpl(d.ExternalID as *mut c_void);
2229 }
2230 if !d.SystemID.is_null() {
2231 allocator::xmlFreeImpl(d.SystemID as *mut c_void);
2232 }
2233
2234 unsafe extern "C" fn free_notation_wrapper(payload: *mut c_void, _name: *mut u8) {
2236 crate::xml::dtd::free_notation(payload as *mut _xmlNotation);
2237 }
2238 unsafe extern "C" fn free_element_wrapper(payload: *mut c_void, _name: *mut u8) {
2239 crate::xml::dtd::free_element(payload as *mut _xmlElement);
2240 }
2241 unsafe extern "C" fn free_attribute_wrapper(payload: *mut c_void, _name: *mut u8) {
2242 crate::xml::dtd::free_attribute(payload as *mut _xmlAttribute);
2243 }
2244 unsafe extern "C" fn free_entity_wrapper(payload: *mut c_void, _name: *mut u8) {
2245 crate::xml::entities::free_entity(payload as *mut _xmlEntity);
2246 }
2247
2248 if !d.notations.is_null() {
2249 crate::xml::hash::hash_free(
2250 d.notations as *mut crate::xml::hash::HashTable,
2251 Some(free_notation_wrapper),
2252 );
2253 d.notations = ptr::null_mut();
2254 }
2255 if !d.elements.is_null() {
2256 crate::xml::hash::hash_free(
2257 d.elements as *mut crate::xml::hash::HashTable,
2258 Some(free_element_wrapper),
2259 );
2260 d.elements = ptr::null_mut();
2261 }
2262 if !d.attributes.is_null() {
2263 crate::xml::hash::hash_free(
2264 d.attributes as *mut crate::xml::hash::HashTable,
2265 Some(free_attribute_wrapper),
2266 );
2267 d.attributes = ptr::null_mut();
2268 }
2269 if !d.entities.is_null() {
2270 crate::xml::hash::hash_free(
2271 d.entities as *mut crate::xml::hash::HashTable,
2272 Some(free_entity_wrapper),
2273 );
2274 d.entities = ptr::null_mut();
2275 }
2276 if !d.pentities.is_null() {
2277 crate::xml::hash::hash_free(
2278 d.pentities as *mut crate::xml::hash::HashTable,
2279 Some(free_entity_wrapper),
2280 );
2281 d.pentities = ptr::null_mut();
2282 }
2283
2284 if !d.children.is_null() {
2286 free_node_list(d.children);
2287 }
2288
2289 allocator::xmlFreeImpl(dtd as *mut c_void);
2290}
2291
2292pub unsafe fn new_entity(
2312 _doc: *mut _xmlDoc,
2313 name: *const xmlChar,
2314 etype: c_int,
2315 ExternalID: *const xmlChar,
2316 SystemID: *const xmlChar,
2317 content: *const xmlChar,
2318) -> *mut _xmlEntity {
2319 let entity = allocator::xmlMallocZero(size_of::<_xmlEntity>() as usize) as *mut _xmlEntity;
2320 if entity.is_null() {
2321 return ptr::null_mut();
2322 }
2323
2324 unsafe {
2325 (*entity).type_ = XML_ENTITY_DECL as c_int;
2326 (*entity).name = dup_xml_str(name);
2327 (*entity).etype = etype;
2328 (*entity).ExternalID = dup_xml_str(ExternalID);
2329 (*entity).SystemID = dup_xml_str(SystemID);
2330 (*entity).content = dup_xml_str(content);
2331 (*entity).length = if content.is_null() {
2332 0
2333 } else {
2334 crate::abi::exports_xml2::xmlStrlen(content)
2335 };
2336 (*entity).flags = 0;
2337 (*entity).expandedSize = 0;
2338 }
2339
2340 entity
2341}
2342
2343pub unsafe fn get_doc_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2358 crate::xml::entities::get_entity(doc as *mut _xmlDoc, name)
2359}
2360
2361pub unsafe fn add_doc_entity(
2369 doc: *mut _xmlDoc,
2370 name: *const xmlChar,
2371 etype: c_int,
2372 ExternalID: *const xmlChar,
2373 SystemID: *const xmlChar,
2374 content: *const xmlChar,
2375) -> *mut _xmlEntity {
2376 if doc.is_null() || name.is_null() {
2377 return ptr::null_mut();
2378 }
2379 unsafe {
2380 let mut dtd = (*doc).intSubset;
2381 if dtd.is_null() {
2382 dtd = new_dtd(
2383 doc,
2384 b"internal\0".as_ptr() as *const xmlChar,
2385 ptr::null(),
2386 ptr::null(),
2387 );
2388 if dtd.is_null() {
2389 return ptr::null_mut();
2390 }
2391 }
2392 crate::xml::entities::add_entity(dtd, name, etype, ExternalID, SystemID, content)
2393 }
2394}
2395
2396pub unsafe fn add_dtd_entity(
2404 doc: *mut _xmlDoc,
2405 name: *const xmlChar,
2406 etype: c_int,
2407 ExternalID: *const xmlChar,
2408 SystemID: *const xmlChar,
2409 content: *const xmlChar,
2410) -> *mut _xmlEntity {
2411 if doc.is_null() || name.is_null() {
2412 return ptr::null_mut();
2413 }
2414 unsafe {
2415 let mut dtd = (*doc).extSubset;
2416 if dtd.is_null() {
2417 dtd = new_dtd(
2418 doc,
2419 b"internal\0".as_ptr() as *const xmlChar,
2420 ptr::null(),
2421 ptr::null(),
2422 );
2423 if dtd.is_null() {
2424 return ptr::null_mut();
2425 }
2426 (*doc).extSubset = dtd;
2427 }
2428 crate::xml::entities::add_entity(dtd, name, etype, ExternalID, SystemID, content)
2429 }
2430}
2431
2432pub unsafe fn get_dtd_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2440 if doc.is_null() || name.is_null() {
2441 return ptr::null_mut();
2442 }
2443 unsafe {
2444 if !(*doc).intSubset.is_null() {
2445 let e = crate::xml::entities::get_entity_from_dtd((*doc).intSubset, name);
2446 if !e.is_null() {
2447 return e;
2448 }
2449 }
2450 if !(*doc).extSubset.is_null() {
2451 return crate::xml::entities::get_entity_from_dtd((*doc).extSubset, name);
2452 }
2453 ptr::null_mut()
2454 }
2455}
2456
2457pub unsafe fn get_parameter_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2470 crate::xml::entities::get_parameter_entity(doc as *mut _xmlDoc, name)
2471}
2472
2473const ENTITY_LT: &[xmlChar] = b"<";
2482const ENTITY_GT: &[xmlChar] = b">";
2483const ENTITY_AMP: &[xmlChar] = b"&";
2484const ENTITY_QUOT: &[xmlChar] = b""";
2485const ENTITY_APOS: &[xmlChar] = b"'";
2486
2487const INDENT: &[xmlChar] = b" ";
2489
2490const MAX_INDENT: c_int = 60;
2492
2493pub(crate) unsafe fn serialize_text(buf: *mut _xmlBuffer, content: *const xmlChar, len: c_int) {
2508 if buf.is_null() || content.is_null() || len <= 0 {
2509 return;
2510 }
2511
2512 let mut i: c_int = 0;
2513 while i < len {
2514 let ch = unsafe { *content.add(i as usize) };
2515
2516 if ch == b']'
2518 && i + 2 < len
2519 && unsafe { *content.add(i as usize + 1) == b']' }
2520 && unsafe { *content.add(i as usize + 2) == b'>' }
2521 {
2522 io::buf_add(buf, &ch as *const u8, 2); io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2525 i += 3;
2526 continue;
2527 }
2528
2529 match ch {
2530 b'<' => {
2531 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
2532 }
2533 b'&' => {
2534 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
2535 }
2536 b'>' => {
2537 io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2541 }
2542 b'\r' => {
2543 io::buf_add(buf, b" " as *const u8, 5);
2545 }
2546 0x01..=0x08 | 0x0B | 0x0C | 0x0E..=0x1F => {
2547 let hex = format!("&#x{:X};", ch);
2549 io::buf_add(buf, hex.as_ptr(), hex.len() as c_int);
2550 }
2551 _ => {
2552 io::buf_add(buf, &ch as *const u8, 1);
2553 }
2554 }
2555 i += 1;
2556 }
2557}
2558
2559pub(crate) unsafe fn serialize_attr_value(buf: *mut _xmlBuffer, value: *const xmlChar) {
2572 if buf.is_null() || value.is_null() {
2573 return;
2574 }
2575
2576 let len = xml_strlen(value);
2577 let mut i: c_int = 0;
2578 while i < len {
2579 let ch = unsafe { *value.add(i as usize) };
2580
2581 match ch {
2582 b'\n' => {
2583 io::buf_add(buf, b" " as *const u8, 5);
2584 }
2585 b'\r' => {
2586 io::buf_add(buf, b" " as *const u8, 5);
2587 }
2588 b'\t' => {
2589 io::buf_add(buf, b"	" as *const u8, 4);
2590 }
2591 b'<' => {
2592 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
2593 }
2594 b'&' => {
2595 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
2596 }
2597 b'"' => {
2598 io::buf_add(buf, ENTITY_QUOT.as_ptr(), ENTITY_QUOT.len() as c_int);
2599 }
2600 b'>' => {
2601 io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2602 }
2603 _ => {
2604 io::buf_add(buf, &ch as *const u8, 1);
2605 }
2606 }
2607 i += 1;
2608 }
2609}
2610
2611unsafe fn write_indent(
2623 buf: *mut _xmlBuffer,
2624 level: c_int,
2625 indent: *const xmlChar,
2626 indent_len: c_int,
2627) {
2628 if buf.is_null() || level <= 0 || indent.is_null() || indent_len <= 0 {
2629 return;
2630 }
2631 let indent_nr = MAX_INDENT / indent_len;
2632 let mut lvl = level;
2633 if lvl > indent_nr {
2634 lvl = indent_nr;
2635 }
2636 for _ in 0..lvl {
2637 io::buf_add(buf, indent, indent_len);
2638 }
2639}
2640
2641unsafe fn is_noenc_text(node: *mut _xmlNode) -> bool {
2649 if node.is_null() {
2650 return false;
2651 }
2652 let n = unsafe { &*node };
2653 if n.name.is_null() {
2654 return false;
2655 }
2656 c_str_eq_bytes(n.name, b"textnoenc")
2657}
2658
2659unsafe fn c_str_eq_bytes(s: *const xmlChar, b: &[u8]) -> bool {
2661 let mut i = 0usize;
2662 while i < b.len() {
2663 if unsafe { *s.add(i) } != b[i] {
2664 return false;
2665 }
2666 i += 1;
2667 }
2668 unsafe { *s.add(i) == 0 }
2669}
2670
2671#[derive(Clone, Copy)]
2674struct DumpState {
2675 format: c_int,
2677 saved: c_int,
2680 unformatted: *mut _xmlNode,
2683 indent: *const xmlChar,
2686 indent_len: c_int,
2688 no_decl: c_int,
2690}
2691
2692impl DumpState {
2693 fn new(format: c_int) -> Self {
2694 let f = if format != 0 { 1 } else { 0 };
2695 DumpState {
2696 format: f,
2697 saved: f,
2698 unformatted: ptr::null_mut(),
2699 indent: INDENT.as_ptr(),
2700 indent_len: INDENT.len() as c_int,
2701 no_decl: 0,
2702 }
2703 }
2704
2705 unsafe fn with_indent(format: c_int, indent: *const xmlChar, no_decl: c_int) -> Self {
2713 let f = if format != 0 { 1 } else { 0 };
2714 let (ptr, len) = if indent.is_null() {
2715 (INDENT.as_ptr(), INDENT.len() as c_int)
2716 } else {
2717 let mut n = 0i32;
2718 while unsafe { *indent.add(n as usize) } != 0 {
2719 n += 1;
2720 }
2721 (indent, n)
2722 };
2723 DumpState {
2724 format: f,
2725 saved: f,
2726 unformatted: ptr::null_mut(),
2727 indent: ptr,
2728 indent_len: len,
2729 no_decl,
2730 }
2731 }
2732}
2733
2734unsafe fn write_qname(buf: *mut _xmlBuffer, node: *mut _xmlNode) {
2740 let n = unsafe { &*node };
2741 if !n.ns.is_null() {
2742 let ns = unsafe { &*n.ns };
2743 if !ns.prefix.is_null() {
2744 io::buf_cat(buf, ns.prefix);
2745 io::buf_ccat(buf, b':');
2746 }
2747 }
2748 if !n.name.is_null() {
2749 io::buf_cat(buf, n.name);
2750 }
2751}
2752
2753unsafe fn ns_dump_output(buf: *mut _xmlBuffer, cur: *mut _xmlNs) {
2759 if cur.is_null() || buf.is_null() {
2760 return;
2761 }
2762 let ns = unsafe { &*cur };
2763 if ns.type_ == XML_LOCAL_NAMESPACE as c_int && !ns.href.is_null() {
2764 if !ns.prefix.is_null() && c_str_eq_bytes(ns.prefix, b"xml") {
2766 return;
2767 }
2768 io::buf_ccat(buf, b' ');
2769 if !ns.prefix.is_null() {
2770 io::buf_add(buf, b"xmlns:" as *const u8, 6);
2771 io::buf_cat(buf, ns.prefix);
2772 } else {
2773 io::buf_add(buf, b"xmlns" as *const u8, 5);
2774 }
2775 io::buf_add(buf, b"=\"" as *const u8, 2);
2776 serialize_attr_value(buf, ns.href);
2777 io::buf_ccat(buf, b'"');
2778 }
2779}
2780
2781unsafe fn attr_dump_output(buf: *mut _xmlBuffer, cur: *mut _xmlAttr) {
2787 if cur.is_null() || buf.is_null() {
2788 return;
2789 }
2790 io::buf_ccat(buf, b' ');
2791 let a = unsafe { &*cur };
2792 if !a.ns.is_null() {
2793 let ans = unsafe { &*a.ns };
2794 if !ans.prefix.is_null() {
2795 io::buf_cat(buf, ans.prefix);
2796 io::buf_ccat(buf, b':');
2797 }
2798 }
2799 if !a.name.is_null() {
2800 io::buf_cat(buf, a.name);
2801 }
2802 io::buf_add(buf, b"=\"" as *const u8, 2);
2803 let mut child = a.children;
2806 while !child.is_null() {
2807 let ct = unsafe { (*child).type_ };
2808 if ct == XML_TEXT_NODE as c_int && !unsafe { (*child).content }.is_null() {
2809 serialize_attr_value(buf, unsafe { (*child).content });
2810 } else if ct == XML_ENTITY_REF_NODE as c_int && !unsafe { (*child).name }.is_null() {
2811 io::buf_ccat(buf, b'&');
2812 io::buf_cat(buf, unsafe { (*child).name });
2813 io::buf_ccat(buf, b';');
2814 }
2815 child = unsafe { (*child).next };
2816 }
2817 io::buf_ccat(buf, b'"');
2818}
2819
2820unsafe fn dump_notation_decl(buf: *mut _xmlBuffer, nota: *mut _xmlNotation) {
2826 let n = unsafe { &*nota };
2827 io::buf_add(buf, b"<!NOTATION " as *const u8, 11);
2828 if !n.name.is_null() {
2829 io::buf_cat(buf, n.name);
2830 }
2831 if !n.PublicID.is_null() {
2832 io::buf_add(buf, b" PUBLIC " as *const u8, 8);
2833 write_quoted_string(buf, n.PublicID);
2834 if !n.SystemID.is_null() {
2835 io::buf_ccat(buf, b' ');
2836 write_quoted_string(buf, n.SystemID);
2837 }
2838 } else {
2839 io::buf_add(buf, b" SYSTEM " as *const u8, 8);
2840 write_quoted_string(buf, n.SystemID);
2841 }
2842 io::buf_add(buf, b" >\n" as *const u8, 4);
2843}
2844
2845unsafe fn dump_element_occur(buf: *mut _xmlBuffer, ocur: c_int) {
2847 use crate::abi::types::xmlElementContentOccur::*;
2848 if ocur == XML_ELEMENT_CONTENT_OPT as c_int {
2849 io::buf_ccat(buf, b'?');
2850 } else if ocur == XML_ELEMENT_CONTENT_MULT as c_int {
2851 io::buf_ccat(buf, b'*');
2852 } else if ocur == XML_ELEMENT_CONTENT_PLUS as c_int {
2853 io::buf_ccat(buf, b'+');
2854 }
2855}
2856
2857unsafe fn dump_element_content(buf: *mut _xmlBuffer, content: *mut _xmlElementContent) {
2863 use crate::abi::types::xmlElementContentOccur::*;
2864 use crate::abi::types::xmlElementContentType::*;
2865 if content.is_null() {
2866 return;
2867 }
2868 io::buf_ccat(buf, b'(');
2869 let mut cur = content;
2870 loop {
2871 if cur.is_null() {
2872 return;
2873 }
2874 let c = unsafe { &*cur };
2875 match c.type_ {
2876 t if t == XML_ELEMENT_CONTENT_PCDATA as c_int => {
2877 io::buf_add(buf, b"#PCDATA" as *const u8, 7);
2878 }
2879 t if t == XML_ELEMENT_CONTENT_ELEMENT as c_int => {
2880 if !c.prefix.is_null() {
2881 io::buf_cat(buf, c.prefix);
2882 io::buf_ccat(buf, b':');
2883 }
2884 if !c.name.is_null() {
2885 io::buf_cat(buf, c.name);
2886 }
2887 }
2888 t if t == XML_ELEMENT_CONTENT_SEQ as c_int || t == XML_ELEMENT_CONTENT_OR as c_int => {
2889 if cur != content
2890 && !c.parent.is_null()
2891 && (c.type_ != unsafe { (*c.parent).type_ }
2892 || c.ocur != XML_ELEMENT_CONTENT_ONCE as c_int)
2893 {
2894 io::buf_ccat(buf, b'(');
2895 }
2896 cur = c.c1;
2897 continue;
2898 }
2899 _ => {}
2900 }
2901
2902 while cur != content {
2904 let ccur = unsafe { &*cur };
2905 let parent = ccur.parent;
2906 if parent.is_null() {
2907 return;
2908 }
2909 let p = unsafe { &*parent };
2910 if ((ccur.type_ == XML_ELEMENT_CONTENT_OR as c_int
2911 || ccur.type_ == XML_ELEMENT_CONTENT_SEQ as c_int)
2912 && (ccur.type_ != p.type_ || ccur.ocur != XML_ELEMENT_CONTENT_ONCE as c_int))
2913 {
2914 io::buf_ccat(buf, b')');
2915 }
2916 dump_element_occur(buf, ccur.ocur);
2917
2918 if ccur.type_ == XML_ELEMENT_CONTENT_SEQ as c_int {
2919 io::buf_add(buf, b" , " as *const u8, 3);
2920 } else if ccur.type_ == XML_ELEMENT_CONTENT_OR as c_int {
2921 io::buf_add(buf, b" | " as *const u8, 3);
2922 }
2923
2924 if cur == p.c1 {
2925 cur = p.c2;
2926 break;
2927 }
2928 cur = parent;
2929 }
2930 if cur == content {
2931 break;
2932 }
2933 }
2934 io::buf_ccat(buf, b')');
2935 let cc = unsafe { &*content };
2936 dump_element_occur(buf, cc.ocur);
2937}
2938
2939unsafe fn dump_element_decl(buf: *mut _xmlBuffer, elem: *mut _xmlElement) {
2945 use crate::abi::types::xmlElementTypeVal::*;
2946 let e = unsafe { &*elem };
2947 io::buf_add(buf, b"<!ELEMENT " as *const u8, 10);
2948 if !e.prefix.is_null() {
2949 io::buf_cat(buf, e.prefix);
2950 io::buf_ccat(buf, b':');
2951 }
2952 if !e.name.is_null() {
2953 io::buf_cat(buf, e.name);
2954 }
2955 io::buf_ccat(buf, b' ');
2956 match e.etype {
2957 t if t == XML_ELEMENT_TYPE_EMPTY as c_int => {
2958 io::buf_add(buf, b"EMPTY" as *const u8, 5);
2959 }
2960 t if t == XML_ELEMENT_TYPE_ANY as c_int => {
2961 io::buf_add(buf, b"ANY" as *const u8, 3);
2962 }
2963 t if t == XML_ELEMENT_TYPE_MIXED as c_int || t == XML_ELEMENT_TYPE_ELEMENT as c_int => {
2964 dump_element_content(buf, e.content);
2965 }
2966 _ => {}
2967 }
2968 io::buf_add(buf, b">\n" as *const u8, 2);
2969}
2970
2971unsafe fn dump_enumeration(buf: *mut _xmlBuffer, cur: *mut _xmlEnumeration) {
2977 let mut e = cur;
2978 while !e.is_null() {
2979 let en = unsafe { &*e };
2980 if !en.name.is_null() {
2981 io::buf_cat(buf, en.name);
2982 }
2983 if !en.next.is_null() {
2984 io::buf_add(buf, b" | " as *const u8, 3);
2985 }
2986 e = en.next;
2987 }
2988 io::buf_ccat(buf, b')');
2989}
2990
2991unsafe fn dump_attribute_decl(buf: *mut _xmlBuffer, attr: *mut _xmlAttribute) {
2997 use crate::abi::types::xmlAttributeDefault::*;
2998 use crate::abi::types::xmlAttributeType::*;
2999 let a = unsafe { &*attr };
3000 io::buf_add(buf, b"<!ATTLIST " as *const u8, 10);
3001 if !a.elem.is_null() {
3002 io::buf_cat(buf, a.elem);
3003 }
3004 io::buf_ccat(buf, b' ');
3005 if !a.prefix.is_null() {
3006 io::buf_cat(buf, a.prefix);
3007 io::buf_ccat(buf, b':');
3008 }
3009 if !a.name.is_null() {
3010 io::buf_cat(buf, a.name);
3011 }
3012 match a.atype {
3013 t if t == XML_ATTRIBUTE_CDATA as c_int => {
3014 io::buf_add(buf, b" CDATA" as *const u8, 6);
3015 }
3016 t if t == XML_ATTRIBUTE_ID as c_int => {
3017 io::buf_add(buf, b" ID" as *const u8, 3);
3018 }
3019 t if t == XML_ATTRIBUTE_IDREF as c_int => {
3020 io::buf_add(buf, b" IDREF" as *const u8, 6);
3021 }
3022 t if t == XML_ATTRIBUTE_IDREFS as c_int => {
3023 io::buf_add(buf, b" IDREFS" as *const u8, 7);
3024 }
3025 t if t == XML_ATTRIBUTE_ENTITY as c_int => {
3026 io::buf_add(buf, b" ENTITY" as *const u8, 7);
3027 }
3028 t if t == XML_ATTRIBUTE_ENTITIES as c_int => {
3029 io::buf_add(buf, b" ENTITIES" as *const u8, 9);
3030 }
3031 t if t == XML_ATTRIBUTE_NMTOKEN as c_int => {
3032 io::buf_add(buf, b" NMTOKEN" as *const u8, 8);
3033 }
3034 t if t == XML_ATTRIBUTE_NMTOKENS as c_int => {
3035 io::buf_add(buf, b" NMTOKENS" as *const u8, 9);
3036 }
3037 t if t == XML_ATTRIBUTE_ENUMERATION as c_int => {
3038 io::buf_add(buf, b" (" as *const u8, 2);
3039 dump_enumeration(buf, a.tree);
3040 }
3041 t if t == XML_ATTRIBUTE_NOTATION as c_int => {
3042 io::buf_add(buf, b" NOTATION (" as *const u8, 11);
3043 dump_enumeration(buf, a.tree);
3044 }
3045 _ => {}
3046 }
3047 match a.def {
3048 t if t == XML_ATTRIBUTE_REQUIRED as c_int => {
3049 io::buf_add(buf, b" #REQUIRED" as *const u8, 10);
3050 }
3051 t if t == XML_ATTRIBUTE_IMPLIED as c_int => {
3052 io::buf_add(buf, b" #IMPLIED" as *const u8, 9);
3053 }
3054 t if t == XML_ATTRIBUTE_FIXED as c_int => {
3055 io::buf_add(buf, b" #FIXED" as *const u8, 7);
3056 }
3057 _ => {}
3058 }
3059 if !a.defaultValue.is_null() {
3060 io::buf_add(buf, b" \"" as *const u8, 2);
3061 serialize_attr_value(buf, a.defaultValue);
3062 io::buf_ccat(buf, b'"');
3063 }
3064 io::buf_add(buf, b">\n" as *const u8, 2);
3065}
3066
3067unsafe fn write_quoted_string(buf: *mut _xmlBuffer, str: *const xmlChar) {
3073 if buf.is_null() {
3074 return;
3075 }
3076 io::buf_ccat(buf, b'"');
3077 if !str.is_null() {
3078 let mut i = 0usize;
3079 while unsafe { *str.add(i) != 0 } {
3080 let ch = unsafe { *str.add(i) };
3081 if ch == b'"' {
3082 io::buf_add(buf, b""" as *const u8, 6);
3083 } else {
3084 io::buf_add(buf, &ch as *const u8, 1);
3085 }
3086 i += 1;
3087 }
3088 }
3089 io::buf_ccat(buf, b'"');
3090}
3091
3092unsafe fn dump_entity_decl(buf: *mut _xmlBuffer, ent: *mut _xmlEntity) {
3098 use crate::abi::types::xmlEntityType::*;
3099 let e = unsafe { &*ent };
3100 if e.etype == XML_INTERNAL_PARAMETER_ENTITY as c_int
3101 || e.etype == XML_EXTERNAL_PARAMETER_ENTITY as c_int
3102 {
3103 io::buf_add(buf, b"<!ENTITY % " as *const u8, 11);
3104 } else {
3105 io::buf_add(buf, b"<!ENTITY " as *const u8, 9);
3106 }
3107 if !e.name.is_null() {
3108 io::buf_cat(buf, e.name);
3109 }
3110 io::buf_ccat(buf, b' ');
3111
3112 if e.etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY as c_int
3113 || e.etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int
3114 || e.etype == XML_EXTERNAL_PARAMETER_ENTITY as c_int
3115 {
3116 if !e.ExternalID.is_null() {
3117 io::buf_add(buf, b"PUBLIC " as *const u8, 7);
3118 write_quoted_string(buf, e.ExternalID);
3119 io::buf_ccat(buf, b' ');
3120 } else {
3121 io::buf_add(buf, b"SYSTEM " as *const u8, 7);
3122 }
3123 write_quoted_string(buf, e.SystemID);
3124 }
3125
3126 if e.etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int {
3127 if !e.content.is_null() {
3128 io::buf_add(buf, b" NDATA " as *const u8, 7);
3129 if !e.orig.is_null() {
3130 io::buf_cat(buf, e.orig);
3131 } else if !e.content.is_null() {
3132 io::buf_cat(buf, e.content);
3133 }
3134 }
3135 }
3136
3137 if e.etype == XML_INTERNAL_GENERAL_ENTITY as c_int
3138 || e.etype == XML_INTERNAL_PARAMETER_ENTITY as c_int
3139 {
3140 if !e.orig.is_null() {
3141 write_quoted_string(buf, e.orig);
3142 } else {
3143 io::buf_ccat(buf, b'"');
3145 if !e.content.is_null() {
3146 let mut i = 0usize;
3147 while unsafe { *e.content.add(i) != 0 } {
3148 let ch = unsafe { *e.content.add(i) };
3149 match ch {
3150 b'"' => io::buf_add(buf, b""" as *const u8, 6),
3151 b'%' => io::buf_add(buf, b"%" as *const u8, 6),
3152 _ => io::buf_add(buf, &ch as *const u8, 1),
3153 };
3154 i += 1;
3155 }
3156 }
3157 io::buf_ccat(buf, b'"');
3158 }
3159 }
3160 io::buf_add(buf, b">\n" as *const u8, 2);
3161}
3162
3163unsafe fn dtd_dump_output(
3169 buf: *mut _xmlBuffer,
3170 cur: *mut _xmlNode,
3171 state: &mut DumpState,
3172 level: &mut c_int,
3173) {
3174 let dtd = cur as *mut _xmlDtd;
3175 let d = unsafe { &*dtd };
3176 io::buf_add(buf, b"<!DOCTYPE " as *const u8, 10);
3177 if !d.name.is_null() {
3178 io::buf_cat(buf, d.name);
3179 }
3180 if !d.ExternalID.is_null() {
3181 io::buf_add(buf, b" PUBLIC " as *const u8, 8);
3182 write_quoted_string(buf, d.ExternalID);
3183 io::buf_ccat(buf, b' ');
3184 write_quoted_string(buf, d.SystemID);
3185 } else if !d.SystemID.is_null() {
3186 io::buf_add(buf, b" SYSTEM " as *const u8, 8);
3187 write_quoted_string(buf, d.SystemID);
3188 }
3189 if crate::xml::hash::hash_size(d.entities as *mut crate::xml::hash::HashTable) == 0
3190 && crate::xml::hash::hash_size(d.elements as *mut crate::xml::hash::HashTable) == 0
3191 && crate::xml::hash::hash_size(d.attributes as *mut crate::xml::hash::HashTable) == 0
3192 && crate::xml::hash::hash_size(d.notations as *mut crate::xml::hash::HashTable) == 0
3193 && crate::xml::hash::hash_size(d.pentities as *mut crate::xml::hash::HashTable) == 0
3194 {
3195 io::buf_ccat(buf, b'>');
3196 return;
3197 }
3198 io::buf_add(buf, b" [\n" as *const u8, 3);
3199 let format = state.format;
3205 let lvl = *level;
3206 state.format = 0;
3207 *level = -1;
3208 if !d.notations.is_null() {
3209 crate::xml::hash::hash_scan(
3210 d.notations as *mut crate::xml::hash::HashTable,
3211 Some(dump_notation_decl_cb),
3212 buf as *mut c_void,
3213 );
3214 }
3215 if !d.elements.is_null() {
3216 crate::xml::hash::hash_scan(
3217 d.elements as *mut crate::xml::hash::HashTable,
3218 Some(dump_element_decl_cb),
3219 buf as *mut c_void,
3220 );
3221 }
3222 if !d.attributes.is_null() {
3223 crate::xml::hash::hash_scan(
3224 d.attributes as *mut crate::xml::hash::HashTable,
3225 Some(dump_attribute_decl_cb),
3226 buf as *mut c_void,
3227 );
3228 }
3229 if !d.entities.is_null() {
3230 crate::xml::hash::hash_scan(
3231 d.entities as *mut crate::xml::hash::HashTable,
3232 Some(dump_entity_decl_cb),
3233 buf as *mut c_void,
3234 );
3235 }
3236 if !d.pentities.is_null() {
3237 crate::xml::hash::hash_scan(
3238 d.pentities as *mut crate::xml::hash::HashTable,
3239 Some(dump_entity_decl_cb),
3240 buf as *mut c_void,
3241 );
3242 }
3243 state.format = format;
3244 *level = lvl;
3245 io::buf_add(buf, b"]>" as *const u8, 2);
3246}
3247
3248unsafe extern "C" fn dump_notation_decl_cb(
3250 payload: *mut c_void,
3251 data: *mut c_void,
3252 _name: *const crate::abi::types::xmlChar,
3253) {
3254 if !payload.is_null() && !data.is_null() {
3255 dump_notation_decl(data as *mut _xmlBuffer, payload as *mut _xmlNotation);
3256 }
3257}
3258
3259unsafe extern "C" fn dump_element_decl_cb(
3261 payload: *mut c_void,
3262 data: *mut c_void,
3263 _name: *const crate::abi::types::xmlChar,
3264) {
3265 if !payload.is_null() && !data.is_null() {
3266 dump_element_decl(data as *mut _xmlBuffer, payload as *mut _xmlElement);
3267 }
3268}
3269
3270unsafe extern "C" fn dump_attribute_decl_cb(
3272 payload: *mut c_void,
3273 data: *mut c_void,
3274 _name: *const crate::abi::types::xmlChar,
3275) {
3276 if !payload.is_null() && !data.is_null() {
3277 dump_attribute_decl(data as *mut _xmlBuffer, payload as *mut _xmlAttribute);
3278 }
3279}
3280
3281unsafe extern "C" fn dump_entity_decl_cb(
3283 payload: *mut c_void,
3284 data: *mut c_void,
3285 _name: *const crate::abi::types::xmlChar,
3286) {
3287 if !payload.is_null() && !data.is_null() {
3288 dump_entity_decl(data as *mut _xmlBuffer, payload as *mut _xmlEntity);
3289 }
3290}
3291
3292unsafe fn doc_content_dump_output(
3301 buf: *mut _xmlBuffer,
3302 cur: *mut _xmlNode,
3303 state: &mut DumpState,
3304 level: &mut c_int,
3305) {
3306 let doc = cur as *mut _xmlDoc;
3307 let d = unsafe { &*doc };
3308
3309 if state.no_decl == 0 {
3313 io::buf_add(buf, b"<?xml version=\"" as *const u8, 15);
3314 if !d.version.is_null() {
3315 io::buf_cat(buf, d.version);
3316 } else {
3317 io::buf_add(buf, b"1.0" as *const u8, 3);
3318 }
3319 io::buf_ccat(buf, b'"');
3320 if !d.encoding.is_null() {
3321 io::buf_add(buf, b" encoding=\"" as *const u8, 11);
3322 io::buf_cat(buf, d.encoding);
3323 io::buf_ccat(buf, b'"');
3324 }
3325 match d.standalone {
3326 0 => {
3327 io::buf_add(buf, b" standalone=\"no\"" as *const u8, 16);
3328 }
3329 1 => {
3330 io::buf_add(buf, b" standalone=\"yes\"" as *const u8, 17);
3331 }
3332 _ => {}
3333 }
3334 io::buf_add(buf, b"?>\n" as *const u8, 3);
3335 }
3336
3337 if !d.intSubset.is_null() {
3340 let mut lvl = 0;
3341 dtd_dump_output(buf, d.intSubset as *mut _xmlNode, state, &mut lvl);
3342 io::buf_ccat(buf, b'\n');
3343 }
3344
3345 if !d.children.is_null() {
3346 let mut child = d.children;
3347 while !child.is_null() {
3348 *level = 0;
3349 node_dump_internal(buf, child, child, cur, state, level);
3350 let ct = unsafe { (*child).type_ };
3351 if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
3352 io::buf_ccat(buf, b'\n');
3353 }
3354 child = unsafe { (*child).next };
3355 }
3356 }
3357}
3358
3359unsafe fn node_dump_internal(
3383 buf: *mut _xmlBuffer,
3384 cur: *mut _xmlNode,
3385 root: *mut _xmlNode,
3386 parent: *mut _xmlNode,
3387 state: &mut DumpState,
3388 level: &mut c_int,
3389) {
3390 if cur.is_null() || buf.is_null() {
3391 return;
3392 }
3393 let n = unsafe { &*cur };
3394 match n.type_ {
3395 t if t == XML_ELEMENT_NODE as c_int => {
3396 if cur != root && state.format == 1 {
3397 write_indent(buf, *level, state.indent, state.indent_len);
3398 }
3399 if !n.parent.is_null() && n.parent != parent && !n.children.is_null() {
3402 let mut sub = DumpState::new(state.format);
3403 let mut sub_level = *level;
3404 node_dump_internal(buf, cur, cur, n.parent, &mut sub, &mut sub_level);
3405 return;
3406 }
3407 io::buf_ccat(buf, b'<');
3409 write_qname(buf, cur);
3410 let mut nsdef = n.nsDef;
3411 while !nsdef.is_null() {
3412 ns_dump_output(buf, nsdef);
3413 nsdef = unsafe { (*nsdef).next };
3414 }
3415 let mut attr = n.properties;
3416 while !attr.is_null() {
3417 attr_dump_output(buf, attr);
3418 attr = unsafe { (*attr).next };
3419 }
3420 if n.children.is_null() {
3421 io::buf_add(buf, b"/>" as *const u8, 2);
3422 } else {
3423 if state.format == 1 {
3424 let mut tmp = n.children;
3427 while !tmp.is_null() {
3428 let tt = unsafe { (*tmp).type_ };
3429 if tt == XML_TEXT_NODE as c_int
3430 || tt == XML_CDATA_SECTION_NODE as c_int
3431 || tt == XML_ENTITY_REF_NODE as c_int
3432 {
3433 state.format = 0;
3434 state.unformatted = cur;
3435 break;
3436 }
3437 tmp = unsafe { (*tmp).next };
3438 }
3439 }
3440 io::buf_ccat(buf, b'>');
3441 if state.format == 1 {
3442 io::buf_ccat(buf, b'\n');
3443 }
3444 if *level >= 0 {
3445 *level += 1;
3446 }
3447 let mut child = n.children;
3448 while !child.is_null() {
3449 node_dump_internal(buf, child, root, cur, state, level);
3450 if state.format == 1 {
3451 let ct = unsafe { (*child).type_ };
3452 if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
3453 io::buf_ccat(buf, b'\n');
3454 }
3455 }
3456 child = unsafe { (*child).next };
3457 }
3458 if *level > 0 {
3460 *level -= 1;
3461 }
3462 if state.format == 1 {
3463 write_indent(buf, *level, state.indent, state.indent_len);
3464 }
3465 io::buf_add(buf, b"</" as *const u8, 2);
3466 write_qname(buf, cur);
3467 io::buf_ccat(buf, b'>');
3468 if cur == state.unformatted {
3469 state.format = state.saved;
3470 state.unformatted = ptr::null_mut();
3471 }
3472 }
3473 }
3474 t if t == XML_TEXT_NODE as c_int => {
3475 if !n.content.is_null() {
3476 if is_noenc_text(cur) {
3477 io::buf_cat(buf, n.content);
3478 } else {
3479 serialize_text(buf, n.content, xml_strlen(n.content));
3480 }
3481 } else if !n.children.is_null() {
3482 let c = node_get_content(cur);
3485 if !c.is_null() {
3486 if is_noenc_text(cur) {
3487 io::buf_cat(buf, c);
3488 } else {
3489 serialize_text(buf, c, xml_strlen(c));
3490 }
3491 allocator::xmlFreeImpl(c as *mut c_void);
3492 }
3493 }
3494 }
3495 t if t == XML_CDATA_SECTION_NODE as c_int => {
3496 if n.content.is_null() || unsafe { *n.content == 0 } {
3497 io::buf_add(buf, b"<![CDATA[]]>" as *const u8, 12);
3498 } else {
3499 let len = xml_strlen(n.content) as usize;
3500 let bytes = core::slice::from_raw_parts(n.content, len);
3501 let mut i = 0usize;
3502 let mut seg_start = 0usize;
3503 while i < len {
3504 if bytes[i] == b']'
3505 && i + 2 < len
3506 && bytes[i + 1] == b']'
3507 && bytes[i + 2] == b'>'
3508 {
3509 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
3510 io::buf_add(buf, n.content.add(seg_start), (i + 2 - seg_start) as c_int);
3511 io::buf_add(buf, b"]]>" as *const u8, 3);
3512 seg_start = i + 2;
3513 i += 3;
3514 continue;
3515 }
3516 i += 1;
3517 }
3518 if seg_start < len {
3519 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
3520 io::buf_add(buf, n.content.add(seg_start), (len - seg_start) as c_int);
3521 io::buf_add(buf, b"]]>" as *const u8, 3);
3522 }
3523 }
3524 }
3525 t if t == XML_COMMENT_NODE as c_int => {
3526 if cur != root && state.format == 1 {
3527 write_indent(buf, *level, state.indent, state.indent_len);
3528 }
3529 if !n.content.is_null() {
3530 io::buf_add(buf, b"<!--" as *const u8, 4);
3531 io::buf_cat(buf, n.content);
3532 io::buf_add(buf, b"-->" as *const u8, 3);
3533 }
3534 }
3535 t if t == XML_PI_NODE as c_int => {
3536 if cur != root && state.format == 1 {
3537 write_indent(buf, *level, state.indent, state.indent_len);
3538 }
3539 io::buf_add(buf, b"<?" as *const u8, 2);
3540 if !n.name.is_null() {
3541 io::buf_cat(buf, n.name);
3542 }
3543 if !n.content.is_null() && unsafe { *n.content != 0 } {
3544 io::buf_ccat(buf, b' ');
3545 io::buf_cat(buf, n.content);
3546 }
3547 io::buf_add(buf, b"?>" as *const u8, 2);
3548 }
3549 t if t == XML_ENTITY_REF_NODE as c_int => {
3550 io::buf_ccat(buf, b'&');
3551 if !n.name.is_null() {
3552 io::buf_cat(buf, n.name);
3553 }
3554 io::buf_ccat(buf, b';');
3555 }
3556 t if t == XML_DOCUMENT_NODE as c_int => {
3557 doc_content_dump_output(buf, cur, state, level);
3558 }
3559 t if t == XML_HTML_DOCUMENT_NODE as c_int => {
3560 crate::xml::html::serialize_node(cur, buf, state.format, *level);
3562 }
3563 t if t == XML_DTD_NODE as c_int => {
3564 dtd_dump_output(buf, cur, state, level);
3565 }
3566 t if t == XML_ATTRIBUTE_NODE as c_int => {
3567 attr_dump_output(buf, cur as *mut _xmlAttr);
3568 }
3569 t if t == XML_NAMESPACE_DECL as c_int => {
3570 ns_dump_output(buf, cur as *mut _xmlNs);
3571 }
3572 t if t == XML_ELEMENT_DECL as c_int => {
3573 dump_element_decl(buf, cur as *mut _xmlElement);
3574 }
3575 t if t == XML_ATTRIBUTE_DECL as c_int => {
3576 dump_attribute_decl(buf, cur as *mut _xmlAttribute);
3577 }
3578 t if t == XML_ENTITY_DECL as c_int => {
3579 dump_entity_decl(buf, cur as *mut _xmlEntity);
3580 }
3581 _ => {}
3582 }
3583}
3584
3585pub(crate) unsafe fn serialize_node(
3599 node: *mut _xmlNode,
3600 buf: *mut _xmlBuffer,
3601 format: c_int,
3602 level: c_int,
3603) {
3604 unsafe { serialize_node_opt(node, buf, format, level, ptr::null()) };
3605}
3606
3607pub(crate) unsafe fn serialize_node_opt(
3615 node: *mut _xmlNode,
3616 buf: *mut _xmlBuffer,
3617 format: c_int,
3618 level: c_int,
3619 indent: *const xmlChar,
3620) {
3621 unsafe { serialize_node_opts(node, buf, format, level, indent, 0) };
3622}
3623
3624pub(crate) unsafe fn serialize_node_opts(
3631 node: *mut _xmlNode,
3632 buf: *mut _xmlBuffer,
3633 format: c_int,
3634 level: c_int,
3635 indent: *const xmlChar,
3636 no_decl: c_int,
3637) {
3638 if node.is_null() || buf.is_null() {
3639 return;
3640 }
3641 let parent = unsafe { (*node).parent };
3642 let mut state = DumpState::with_indent(format, indent, no_decl);
3643 let mut lvl = level;
3644 node_dump_internal(buf, node, node, parent, &mut state, &mut lvl);
3645}
3646
3647pub(crate) unsafe fn doc_dump(buf: *mut _xmlBuffer, doc: *mut _xmlDoc) -> c_int {
3657 if buf.is_null() || doc.is_null() {
3658 return -1;
3659 }
3660
3661 let before = io::buf_length(buf);
3662 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
3663 let after = io::buf_length(buf);
3664
3665 if after < 0 || before < 0 {
3666 return -1;
3667 }
3668 after - before
3669}
3670
3671pub(crate) unsafe fn node_dump(
3683 buf: *mut _xmlBuffer,
3684 doc: *mut _xmlDoc,
3685 node: *mut _xmlNode,
3686 level: c_int,
3687 format: c_int,
3688) -> c_int {
3689 let _ = doc; if buf.is_null() || node.is_null() {
3691 return -1;
3692 }
3693
3694 let before = io::buf_length(buf);
3695 serialize_node(node, buf, format, level);
3696 let after = io::buf_length(buf);
3697
3698 if after < 0 || before < 0 {
3699 return -1;
3700 }
3701 after - before
3702}
3703
3704pub(crate) unsafe fn save_doc_to_filename(
3711 doc: *mut _xmlDoc,
3712 filename: *const c_char,
3713 compression: c_int,
3714) -> c_int {
3715 if doc.is_null() || filename.is_null() {
3716 return -1;
3717 }
3718
3719 let out = io::output_buffer_create_filename(filename, ptr::null_mut(), compression);
3720 if out.is_null() {
3721 return -1;
3722 }
3723
3724 let buf = io::buf_create(-1);
3725 if buf.is_null() {
3726 io::output_buffer_close(out);
3727 return -1;
3728 }
3729
3730 let ret = doc_dump(buf, doc);
3731 if ret >= 0 {
3732 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
3734 io::output_buffer_flush(out);
3735 }
3736
3737 io::buf_free(buf);
3738 io::output_buffer_close(out);
3739 ret
3740}
3741
3742pub(crate) unsafe fn save_doc_to_fd(doc: *mut _xmlDoc, fd: c_int, compression: c_int) -> c_int {
3749 if doc.is_null() || fd < 0 {
3750 return -1;
3751 }
3752
3753 let out = io::output_buffer_create_fd(fd, ptr::null_mut());
3754 if out.is_null() {
3755 return -1;
3756 }
3757
3758 let buf = io::buf_create(-1);
3759 if buf.is_null() {
3760 io::output_buffer_close(out);
3761 return -1;
3762 }
3763
3764 let ret = doc_dump(buf, doc);
3765 if ret >= 0 {
3766 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
3767 io::output_buffer_flush(out);
3768 }
3769
3770 io::buf_free(buf);
3771 io::output_buffer_close(out);
3772 ret
3773}
3774
3775pub(crate) unsafe fn save_doc_to_buf(
3782 doc: *mut _xmlDoc,
3783 buf: *mut _xmlBuffer,
3784 compression: c_int,
3785) -> c_int {
3786 let _ = compression;
3787 if doc.is_null() || buf.is_null() {
3788 return -1;
3789 }
3790
3791 doc_dump(buf, doc)
3792}
3793
3794pub(crate) unsafe fn save_format_doc_to_buf(
3801 doc: *mut _xmlDoc,
3802 buf: *mut _xmlBuffer,
3803 compression: c_int,
3804) -> c_int {
3805 let _ = compression;
3806 if doc.is_null() || buf.is_null() {
3807 return -1;
3808 }
3809
3810 let before = io::buf_length(buf);
3811 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
3812 let after = io::buf_length(buf);
3813
3814 if after < 0 || before < 0 {
3815 return -1;
3816 }
3817 after - before
3818}
3819
3820pub(crate) unsafe fn dump_node(node: *mut _xmlNode) -> *mut xmlChar {
3829 if node.is_null() {
3830 return ptr::null_mut();
3831 }
3832
3833 let buf = io::buf_create(-1);
3834 if buf.is_null() {
3835 return ptr::null_mut();
3836 }
3837
3838 serialize_node(node, buf, 0, 0);
3839
3840 let content = io::buf_content(buf);
3841 if content.is_null() {
3842 io::buf_free(buf);
3843 return ptr::null_mut();
3844 }
3845
3846 let result = dup_xml_str(content);
3848 io::buf_free(buf);
3849 result
3850}
3851
3852pub unsafe fn dump_doc(doc: *mut _xmlDoc) -> *mut xmlChar {
3861 if doc.is_null() {
3862 return ptr::null_mut();
3863 }
3864
3865 let buf = io::buf_create(-1);
3866 if buf.is_null() {
3867 return ptr::null_mut();
3868 }
3869
3870 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
3871
3872 let content = io::buf_content(buf);
3873 if content.is_null() {
3874 io::buf_free(buf);
3875 return ptr::null_mut();
3876 }
3877
3878 let result = dup_xml_str(content);
3879 io::buf_free(buf);
3880 result
3881}
3882
3883pub(crate) unsafe fn xmlNodeDump(
3899 buf: *mut _xmlBuffer,
3900 doc: *mut _xmlDoc,
3901 node: *mut _xmlNode,
3902 level: c_int,
3903 format: c_int,
3904) -> c_int {
3905 node_dump(buf, doc, node, level, format)
3906}
3907
3908pub(crate) unsafe fn xmlDocDump(fp: *mut c_void, doc: *mut _xmlDoc) -> c_int {
3921 if fp.is_null() || doc.is_null() {
3922 return -1;
3923 }
3924
3925 let buf = io::buf_create(-1);
3926 if buf.is_null() {
3927 return -1;
3928 }
3929
3930 let ret = doc_dump(buf, doc);
3931 if ret < 0 {
3932 io::buf_free(buf);
3933 return -1;
3934 }
3935
3936 let content = io::buf_content(buf);
3937 let len = io::buf_length(buf);
3938 if !content.is_null() && len > 0 {
3939 let written = libc::fwrite(
3940 content as *const c_void,
3941 1,
3942 len as usize,
3943 fp as *mut libc::FILE,
3944 );
3945 io::buf_free(buf);
3946 written as c_int
3947 } else {
3948 io::buf_free(buf);
3949 0
3950 }
3951}
3952
3953pub(crate) unsafe fn xmlDocDumpFormatMemory(
3967 doc: *mut _xmlDoc,
3968 mem: *mut *mut xmlChar,
3969 size: *mut c_int,
3970 format: c_int,
3971) {
3972 if doc.is_null() || mem.is_null() || size.is_null() {
3973 return;
3974 }
3975
3976 let buf = io::buf_create(-1);
3977 if buf.is_null() {
3978 unsafe {
3979 *mem = ptr::null_mut();
3980 *size = 0;
3981 }
3982 return;
3983 }
3984
3985 serialize_node(doc as *mut _xmlNode, buf, format, 0);
3986
3987 let content = io::buf_content(buf);
3988 let len = io::buf_length(buf);
3989
3990 if !content.is_null() && len > 0 {
3991 let result = allocator::xmlMallocImpl((len + 1) as usize) as *mut xmlChar;
3993 if !result.is_null() {
3994 ptr::copy_nonoverlapping(content, result, len as usize);
3995 *result.add(len as usize) = 0;
3996 unsafe {
3997 *mem = result;
3998 *size = len;
3999 }
4000 } else {
4001 unsafe {
4002 *mem = ptr::null_mut();
4003 *size = 0;
4004 }
4005 }
4006 } else {
4007 unsafe {
4008 *mem = ptr::null_mut();
4009 *size = 0;
4010 }
4011 }
4012
4013 io::buf_free(buf);
4014}
4015
4016pub(crate) unsafe fn xmlDocDumpMemory(doc: *mut _xmlDoc, mem: *mut *mut xmlChar, size: *mut c_int) {
4030 xmlDocDumpFormatMemory(doc, mem, size, 0)
4031}
4032
4033pub(crate) unsafe fn xmlSaveFile(filename: *const c_char, cur: *mut _xmlDoc) -> c_int {
4046 save_doc_to_filename(cur, filename, 0)
4047}
4048
4049pub(crate) unsafe fn xmlSaveFileEnc(
4063 filename: *const c_char,
4064 cur: *mut _xmlDoc,
4065 encoding: *const c_char,
4066) -> c_int {
4067 let _ = encoding; save_doc_to_filename(cur, filename, 0)
4069}
4070
4071pub(crate) unsafe fn xmlSaveFormatFile(
4084 filename: *const c_char,
4085 cur: *mut _xmlDoc,
4086 format: c_int,
4087) -> c_int {
4088 let _ = format;
4089 save_doc_to_filename(cur, filename, 0)
4090}
4091
4092pub(crate) unsafe fn xmlSaveFormatFileEnc(
4106 filename: *const c_char,
4107 cur: *mut _xmlDoc,
4108 encoding: *const c_char,
4109 format: c_int,
4110) -> c_int {
4111 let _ = encoding;
4112 let _ = format;
4113 save_doc_to_filename(cur, filename, 0)
4114}
4115
4116pub(crate) unsafe fn xmlGetDocCompressMode(doc: *mut _xmlDoc) -> c_int {
4128 if doc.is_null() {
4129 return -1;
4130 }
4131 unsafe { (*doc).compression }
4132}
4133
4134pub(crate) unsafe fn xmlSetDocCompressMode(doc: *mut _xmlDoc, mode: c_int) {
4146 if doc.is_null() {
4147 return;
4148 }
4149 unsafe {
4150 (*doc).compression = mode;
4151 }
4152}
4153
4154#[cfg(test)]
4155mod tests {
4156 use super::*;
4157 use core::ffi::c_void;
4158
4159 fn c_str(s: &str) -> *const xmlChar {
4160 let bytes = s.as_bytes();
4161 let buf = unsafe { allocator::xmlMallocImpl(bytes.len() + 1) as *mut u8 };
4162 if !buf.is_null() {
4163 unsafe {
4164 ptr::copy_nonoverlapping(bytes.as_ptr(), buf, bytes.len());
4165 *buf.add(bytes.len()) = 0;
4166 }
4167 }
4168 buf as *const xmlChar
4169 }
4170
4171 #[test]
4172 fn test_new_free_doc() {
4173 unsafe {
4174 let doc = new_doc(ptr::null());
4175 assert!(!doc.is_null());
4176 assert_eq!((*doc).type_, XML_DOCUMENT_NODE as c_int);
4177 assert_eq!((*doc).standalone, -1);
4178 assert_eq!((*doc).doc, doc);
4179 assert!(!(*doc).version.is_null());
4180 free_doc(doc);
4181 }
4182 }
4183
4184 #[test]
4185 fn test_new_doc_with_version() {
4186 unsafe {
4187 let ver = c_str("2.0");
4188 let doc = new_doc(ver);
4189 assert!(!doc.is_null());
4190 let doc_ver = (*doc).version;
4191 assert!(!doc_ver.is_null());
4192 assert!(crate::abi::exports_xml2::xmlStrEqual(doc_ver, ver,) != 0);
4193 allocator::xmlFreeImpl(ver as *mut c_void);
4194 free_doc(doc);
4195 }
4196 }
4197
4198 #[test]
4199 fn test_new_node() {
4200 unsafe {
4201 let doc = new_doc(ptr::null());
4202 let node = new_node(ptr::null_mut(), c_str("root"));
4203 assert!(!node.is_null());
4204 assert_eq!((*node).type_, XML_ELEMENT_NODE as c_int);
4205 assert!(!(*node).name.is_null());
4206 free_node(node);
4207 free_doc(doc);
4208 }
4209 }
4210
4211 #[test]
4212 fn test_node_get_content_recurses_descendants() {
4213 unsafe {
4218 let doc = new_doc(ptr::null());
4219 let root = new_node(ptr::null_mut(), c_str("library"));
4220 doc_set_root_element(doc, root);
4221 let book = new_child(root, ptr::null_mut(), c_str("book"));
4222 let title = new_child(book, ptr::null_mut(), c_str("title"));
4223 let text = new_text(c_str("Rust"));
4224 add_child(title, text);
4225
4226 let content = node_get_content(book);
4227 assert!(!content.is_null());
4228 let s = core::slice::from_raw_parts(
4229 content,
4230 libc::strlen(content as *const libc::c_char) as usize,
4231 );
4232 assert_eq!(s, b"Rust", "descendant text not concatenated");
4233 allocator::xmlFreeImpl(content as *mut c_void);
4234
4235 free_doc(doc);
4236 }
4237 }
4238
4239 #[test]
4240 fn test_doc_set_root_element() {
4241 unsafe {
4242 let doc = new_doc(ptr::null());
4243 let root = new_node(ptr::null_mut(), c_str("root"));
4244 let old = doc_set_root_element(doc, root);
4245 assert!(old.is_null());
4246 assert_eq!(doc_get_root_element(doc), root);
4247 assert_eq!((*doc).children, root as *mut _xmlNode);
4248 free_doc(doc);
4249 }
4250 }
4251
4252 #[test]
4253 fn test_add_child_and_sibling() {
4254 unsafe {
4255 let doc = new_doc(ptr::null());
4256 let root = new_node(ptr::null_mut(), c_str("root"));
4257 doc_set_root_element(doc, root);
4258
4259 let child1 = new_child(root, ptr::null_mut(), c_str("child1"));
4260 assert!(!child1.is_null());
4261 assert_eq!((*child1).parent, root);
4262 assert_eq!((*root).children, child1);
4263 assert_eq!((*root).last, child1);
4264
4265 let child2 = new_child(root, ptr::null_mut(), c_str("child2"));
4266 assert!(!child2.is_null());
4267 assert_eq!((*child2).parent, root);
4268 assert_eq!((*child1).next, child2);
4269 assert_eq!((*child2).prev, child1);
4270 assert_eq!((*root).last, child2);
4271
4272 let sibling = new_node(ptr::null_mut(), c_str("sibling"));
4274 add_sibling(child2, sibling);
4275 assert_eq!((*child2).next, sibling);
4276 assert_eq!((*sibling).prev, child2);
4277 assert_eq!((*root).last, sibling);
4278
4279 free_doc(doc);
4280 }
4281 }
4282
4283 #[test]
4284 fn test_unlink_node() {
4285 unsafe {
4286 let doc = new_doc(ptr::null());
4287 let root = new_node(ptr::null_mut(), c_str("root"));
4288 doc_set_root_element(doc, root);
4289
4290 let child1 = new_child(root, ptr::null_mut(), c_str("c1"));
4291 let child2 = new_child(root, ptr::null_mut(), c_str("c2"));
4292
4293 unlink_node(child1);
4294 assert!((*child1).parent.is_null());
4295 assert!((*child1).prev.is_null());
4296 assert!((*child1).next.is_null());
4297 assert_eq!((*root).children, child2);
4298 assert_eq!((*root).last, child2);
4299
4300 free_node(child1);
4301 free_doc(doc);
4302 }
4303 }
4304
4305 #[test]
4306 fn test_text_and_comment_nodes() {
4307 unsafe {
4308 let text = new_text(c_str("hello world"));
4309 assert!(!text.is_null());
4310 assert_eq!((*text).type_, XML_TEXT_NODE as c_int);
4311 assert!(!(*text).content.is_null());
4312 free_node(text);
4313
4314 let comment = new_comment(c_str("my comment"));
4315 assert!(!comment.is_null());
4316 assert_eq!((*comment).type_, XML_COMMENT_NODE as c_int);
4317 free_node(comment);
4318
4319 let pi = new_pi(c_str("xml"), c_str("version='1.0'"));
4320 assert!(!pi.is_null());
4321 assert_eq!((*pi).type_, XML_PI_NODE as c_int);
4322 free_node(pi);
4323 }
4324 }
4325
4326 #[test]
4327 fn test_set_and_get_prop() {
4328 unsafe {
4329 let doc = new_doc(ptr::null());
4330 let root = new_node(ptr::null_mut(), c_str("root"));
4331 doc_set_root_element(doc, root);
4332
4333 let attr = set_prop(root, c_str("id"), c_str("42"));
4334 assert!(!attr.is_null());
4335 assert_eq!((*attr).type_, XML_ATTRIBUTE_NODE as c_int);
4336
4337 let value = get_prop(root, c_str("id"));
4338 assert!(!value.is_null());
4339 assert!(crate::abi::exports_xml2::xmlStrEqual(value, c_str("42")) != 0);
4340 allocator::xmlFreeImpl(value as *mut c_void);
4341
4342 free_doc(doc);
4343 }
4344 }
4345
4346 #[test]
4347 fn test_remove_prop() {
4348 unsafe {
4349 let doc = new_doc(ptr::null());
4350 let root = new_node(ptr::null_mut(), c_str("root"));
4351 doc_set_root_element(doc, root);
4352
4353 set_prop(root, c_str("a"), c_str("1"));
4354 set_prop(root, c_str("b"), c_str("2"));
4355
4356 let value = get_prop(root, c_str("a"));
4357 assert!(!value.is_null());
4358 allocator::xmlFreeImpl(value as *mut c_void);
4359
4360 let attr = (*root).properties;
4362 assert!(!attr.is_null());
4363 let result = remove_prop(attr);
4364 assert_eq!(result, 0);
4365
4366 let value2 = get_prop(root, c_str("a"));
4368 assert!(value2.is_null());
4369
4370 free_doc(doc);
4371 }
4372 }
4373
4374 #[test]
4375 fn test_namespace_operations() {
4376 unsafe {
4377 let doc = new_doc(ptr::null());
4378 let root = new_node(ptr::null_mut(), c_str("root"));
4379 doc_set_root_element(doc, root);
4380
4381 let ns = new_ns(root, c_str("http://example.com"), c_str("ex"));
4382 assert!(!ns.is_null());
4383 assert!(!(*root).nsDef.is_null());
4384
4385 set_ns(root, ns);
4386 assert_eq!((*root).ns, ns);
4387
4388 let found = search_ns(doc, root, c_str("ex"));
4389 assert_eq!(found, ns);
4390
4391 let found_href = search_ns_by_href(doc, root, c_str("http://example.com"));
4392 assert_eq!(found_href, ns);
4393
4394 free_doc(doc);
4395 }
4396 }
4397
4398 #[test]
4399 fn test_new_dtd() {
4400 unsafe {
4401 let doc = new_doc(ptr::null());
4402 let dtd = new_dtd(doc, c_str("root"), c_str("-//TEST//DTD"), c_str("test.dtd"));
4403 assert!(!dtd.is_null());
4404 assert_eq!((*dtd).type_, XML_DTD_NODE as c_int);
4405 assert_eq!(get_int_subset(doc), dtd);
4406 free_doc(doc);
4407 }
4408 }
4409
4410 #[test]
4411 fn test_copy_node_deep() {
4412 unsafe {
4413 let doc = new_doc(ptr::null());
4414 let root = new_node(ptr::null_mut(), c_str("root"));
4415 doc_set_root_element(doc, root);
4416 let child = new_child(root, ptr::null_mut(), c_str("child"));
4417
4418 let copy = copy_node(root, 1);
4419 assert!(!copy.is_null());
4420 assert_eq!((*copy).type_, XML_ELEMENT_NODE as c_int);
4421 assert!(!(*copy).children.is_null());
4423 assert_eq!((*(*copy).children).type_, XML_ELEMENT_NODE as c_int);
4424
4425 free_node(copy);
4426 free_doc(doc);
4427 }
4428 }
4429
4430 #[test]
4431 fn test_new_cdata_block() {
4432 unsafe {
4433 let doc = new_doc(ptr::null());
4434 let content = c_str("some <cdata> content");
4435 let cdata = new_cdata_block(doc, content, 20);
4436 assert!(!cdata.is_null());
4437 assert_eq!((*cdata).type_, XML_CDATA_SECTION_NODE as c_int);
4438 free_node(cdata);
4439 free_doc(doc);
4440 }
4441 }
4442
4443 #[test]
4444 fn test_null_handling() {
4445 unsafe {
4446 assert!(new_doc(ptr::null()).is_null() == false); let doc = new_doc(ptr::null());
4448 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());
4453 assert!(add_sibling(ptr::null_mut(), ptr::null_mut()).is_null());
4454 free_doc(doc);
4455 }
4456 }
4457
4458 unsafe fn buf_eq_str(buf: *mut _xmlBuffer, expected: &str) -> bool {
4464 let content = io::buf_content(buf);
4465 if content.is_null() {
4466 return expected.is_empty();
4467 }
4468 let len = io::buf_length(buf) as usize;
4469 if len != expected.len() {
4470 return false;
4471 }
4472 let slice = unsafe { core::slice::from_raw_parts(content, len) };
4473 slice == expected.as_bytes()
4474 }
4475
4476 #[test]
4477 fn test_serialize_empty_document() {
4478 unsafe {
4479 let doc = new_doc(ptr::null());
4480 let buf = io::buf_create(-1);
4481 assert!(!buf.is_null());
4482
4483 let ret = doc_dump(buf, doc);
4484 assert!(ret >= 0);
4485
4486 let expected = "<?xml version=\"1.0\"?>\n";
4490 assert!(buf_eq_str(buf, expected));
4491
4492 io::buf_free(buf);
4493 free_doc(doc);
4494 }
4495 }
4496
4497 #[test]
4498 fn test_serialize_element_with_text() {
4499 unsafe {
4500 let doc = new_doc(ptr::null());
4501 let root = new_node(ptr::null_mut(), c_str("root"));
4502 doc_set_root_element(doc, root);
4503
4504 let text = new_text(c_str("hello world"));
4506 add_child(root, text);
4507
4508 let buf = io::buf_create(-1);
4509 assert!(!buf.is_null());
4510
4511 let ret = doc_dump(buf, doc);
4512 assert!(ret >= 0);
4513
4514 let expected = "<?xml version=\"1.0\"?>\n<root>hello world</root>\n";
4515 assert!(buf_eq_str(buf, expected));
4516
4517 io::buf_free(buf);
4518 free_doc(doc);
4519 }
4520 }
4521
4522 #[test]
4523 fn test_serialize_element_with_attributes() {
4524 unsafe {
4525 let doc = new_doc(ptr::null());
4526 let root = new_node(ptr::null_mut(), c_str("root"));
4527 doc_set_root_element(doc, root);
4528
4529 set_prop(root, c_str("id"), c_str("42"));
4530 set_prop(root, c_str("name"), c_str("test"));
4531
4532 let buf = io::buf_create(-1);
4533 assert!(!buf.is_null());
4534
4535 let ret = doc_dump(buf, doc);
4536 assert!(ret >= 0);
4537
4538 let expected = "<?xml version=\"1.0\"?>\n<root id=\"42\" name=\"test\"/>\n";
4539 assert!(buf_eq_str(buf, expected));
4540
4541 io::buf_free(buf);
4542 free_doc(doc);
4543 }
4544 }
4545
4546 #[test]
4547 fn test_serialize_nested_elements() {
4548 unsafe {
4549 let doc = new_doc(ptr::null());
4550 let root = new_node(ptr::null_mut(), c_str("root"));
4551 doc_set_root_element(doc, root);
4552
4553 let child = new_child(root, ptr::null_mut(), c_str("child"));
4554 let grandchild = new_child(child, ptr::null_mut(), c_str("gc"));
4555 let text = new_text(c_str("text"));
4556 add_child(grandchild, text);
4557
4558 let buf = io::buf_create(-1);
4559 assert!(!buf.is_null());
4560
4561 let ret = doc_dump(buf, doc);
4562 assert!(ret >= 0);
4563
4564 let expected = "<?xml version=\"1.0\"?>\n<root><child><gc>text</gc></child></root>\n";
4565 assert!(buf_eq_str(buf, expected));
4566
4567 io::buf_free(buf);
4568 free_doc(doc);
4569 }
4570 }
4571
4572 #[test]
4573 fn test_serialize_with_formatting() {
4574 unsafe {
4575 let doc = new_doc(ptr::null());
4576 let root = new_node(ptr::null_mut(), c_str("root"));
4577 doc_set_root_element(doc, root);
4578
4579 let child = new_child(root, ptr::null_mut(), c_str("child"));
4580 let text = new_text(c_str("text"));
4581 add_child(child, text);
4582
4583 let buf = io::buf_create(-1);
4584 assert!(!buf.is_null());
4585
4586 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
4587
4588 let expected = "<?xml version=\"1.0\"?>\n<root>\n <child>text</child>\n</root>\n";
4589 assert!(buf_eq_str(buf, expected));
4590
4591 io::buf_free(buf);
4592 free_doc(doc);
4593 }
4594 }
4595
4596 #[test]
4597 fn test_serialize_escape_ampersand() {
4598 unsafe {
4599 let doc = new_doc(ptr::null());
4600 let root = new_node(ptr::null_mut(), c_str("root"));
4601 doc_set_root_element(doc, root);
4602
4603 let text = new_text(c_str("a & b"));
4604 add_child(root, text);
4605
4606 let buf = io::buf_create(-1);
4607 assert!(!buf.is_null());
4608
4609 let ret = doc_dump(buf, doc);
4610 assert!(ret >= 0);
4611
4612 let expected = "<?xml version=\"1.0\"?>\n<root>a & b</root>\n";
4613 assert!(buf_eq_str(buf, expected));
4614
4615 io::buf_free(buf);
4616 free_doc(doc);
4617 }
4618 }
4619
4620 #[test]
4621 fn test_serialize_escape_angle_brackets() {
4622 unsafe {
4623 let doc = new_doc(ptr::null());
4624 let root = new_node(ptr::null_mut(), c_str("root"));
4625 doc_set_root_element(doc, root);
4626
4627 let text = new_text(c_str("x < y > z"));
4628 add_child(root, text);
4629
4630 let buf = io::buf_create(-1);
4631 assert!(!buf.is_null());
4632
4633 let ret = doc_dump(buf, doc);
4634 assert!(ret >= 0);
4635
4636 let expected = "<?xml version=\"1.0\"?>\n<root>x < y > z</root>\n";
4637 assert!(buf_eq_str(buf, expected));
4638
4639 io::buf_free(buf);
4640 free_doc(doc);
4641 }
4642 }
4643
4644 #[test]
4645 fn test_serialize_comment() {
4646 unsafe {
4647 let doc = new_doc(ptr::null());
4648 let root = new_node(ptr::null_mut(), c_str("root"));
4649 doc_set_root_element(doc, root);
4650
4651 let comment = new_comment(c_str("my comment"));
4652 add_child(root, comment);
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><!--my comment--></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_pi() {
4670 unsafe {
4671 let doc = new_doc(ptr::null());
4672 let root = new_node(ptr::null_mut(), c_str("root"));
4673 doc_set_root_element(doc, root);
4674
4675 let pi = new_pi(
4676 c_str("xml-stylesheet"),
4677 c_str("href=\"style.xsl\" type=\"text/xsl\""),
4678 );
4679 add_child(root, pi);
4680
4681 let buf = io::buf_create(-1);
4682 assert!(!buf.is_null());
4683
4684 let ret = doc_dump(buf, doc);
4685 assert!(ret >= 0);
4686
4687 let expected = "<?xml version=\"1.0\"?>\n<root><?xml-stylesheet href=\"style.xsl\" type=\"text/xsl\"?></root>\n";
4688 assert!(buf_eq_str(buf, expected));
4689
4690 io::buf_free(buf);
4691 free_doc(doc);
4692 }
4693 }
4694
4695 #[test]
4696 fn test_serialize_self_closing() {
4697 unsafe {
4698 let doc = new_doc(ptr::null());
4699 let root = new_node(ptr::null_mut(), c_str("empty"));
4700 doc_set_root_element(doc, root);
4701
4702 let buf = io::buf_create(-1);
4703 assert!(!buf.is_null());
4704
4705 let ret = doc_dump(buf, doc);
4706 assert!(ret >= 0);
4707
4708 let expected = "<?xml version=\"1.0\"?>\n<empty/>\n";
4709 assert!(buf_eq_str(buf, expected));
4710
4711 io::buf_free(buf);
4712 free_doc(doc);
4713 }
4714 }
4715
4716 #[test]
4717 fn test_dump_node_to_string() {
4718 unsafe {
4719 let node = new_node(ptr::null_mut(), c_str("foo"));
4720 let text = new_text(c_str("bar"));
4721 add_child(node, text);
4722
4723 let result = dump_node(node);
4724 assert!(!result.is_null());
4725
4726 let len = xml_strlen(result);
4727 let slice = unsafe { core::slice::from_raw_parts(result, len as usize) };
4728 assert_eq!(slice, b"<foo>bar</foo>");
4729
4730 allocator::xmlFreeImpl(result as *mut c_void);
4731 free_node(node);
4732 }
4733 }
4734
4735 #[test]
4736 fn test_dump_doc_to_string() {
4737 unsafe {
4738 let doc = new_doc(ptr::null());
4739 let root = new_node(ptr::null_mut(), c_str("root"));
4740 doc_set_root_element(doc, root);
4741
4742 let result = dump_doc(doc);
4743 assert!(!result.is_null());
4744
4745 let len = xml_strlen(result);
4746 let slice = unsafe { core::slice::from_raw_parts(result, len as usize) };
4747 let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
4748 assert_eq!(slice, expected.as_bytes());
4749
4750 allocator::xmlFreeImpl(result as *mut c_void);
4751 free_doc(doc);
4752 }
4753 }
4754
4755 #[test]
4756 fn test_xmlDocDumpFormatMemory() {
4757 unsafe {
4758 let doc = new_doc(ptr::null());
4759 let root = new_node(ptr::null_mut(), c_str("root"));
4760 doc_set_root_element(doc, root);
4761
4762 let mut mem: *mut xmlChar = ptr::null_mut();
4763 let mut size: c_int = 0;
4764
4765 xmlDocDumpFormatMemory(doc, &mut mem, &mut size, 0);
4766
4767 assert!(!mem.is_null());
4768 assert!(size > 0);
4769
4770 let slice = unsafe { core::slice::from_raw_parts(mem, size as usize) };
4771 let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
4774 assert_eq!(slice, expected.as_bytes());
4775
4776 allocator::xmlFreeImpl(mem as *mut c_void);
4777 free_doc(doc);
4778 }
4779 }
4780
4781 #[test]
4782 fn test_serialize_escape_attribute() {
4783 unsafe {
4784 let doc = new_doc(ptr::null());
4785 let root = new_node(ptr::null_mut(), c_str("root"));
4786 doc_set_root_element(doc, root);
4787
4788 set_prop(root, c_str("desc"), c_str("a < b & c \"quoted\""));
4790
4791 let buf = io::buf_create(-1);
4792 assert!(!buf.is_null());
4793
4794 let ret = doc_dump(buf, doc);
4795 assert!(ret >= 0);
4796
4797 let expected =
4798 "<?xml version=\"1.0\"?>\n<root desc=\"a < b & c "quoted"\"/>\n";
4799 assert!(buf_eq_str(buf, expected));
4800
4801 io::buf_free(buf);
4802 free_doc(doc);
4803 }
4804 }
4805}