1use core::ffi::c_void;
37use core::ptr;
38use std::os::raw::{c_char, c_int, c_uint};
39
40use crate::abi::allocator;
41use crate::abi::constants::*;
42use crate::abi::structs::*;
43use crate::abi::types::xmlAttributeType::XML_ATTRIBUTE_CDATA;
44use crate::abi::types::xmlCharEncoding::XML_CHAR_ENCODING_UTF8;
45use crate::abi::types::xmlDocProperties::XML_DOC_WELLFORMED;
46use crate::abi::types::xmlElementType::*;
47use crate::abi::types::*;
48use crate::xml::globals;
49use crate::xml::io;
50
51unsafe fn dup_xml_str(str: *const xmlChar) -> *mut xmlChar {
61 if str.is_null() {
62 return ptr::null_mut();
63 }
64 let len = unsafe { crate::abi::exports_xml2::xmlStrlen(str) as usize };
65 if len == 0 {
66 let buf = unsafe { allocator::xmlMalloc(1) as *mut xmlChar };
68 if !buf.is_null() {
69 unsafe { *buf = 0 };
70 }
71 return buf;
72 }
73 let buf = unsafe { allocator::xmlMalloc(len + 1) as *mut xmlChar };
74 if !buf.is_null() {
75 unsafe {
76 ptr::copy_nonoverlapping(str, buf, len + 1);
77 }
78 }
79 buf
80}
81
82unsafe fn copy_xml_str_content(dest: *mut xmlChar, src: *const xmlChar, max_len: usize) -> bool {
84 if src.is_null() || dest.is_null() || max_len == 0 {
85 return false;
86 }
87 let len = unsafe { crate::abi::exports_xml2::xmlStrlen(src) as usize };
88 if len >= max_len {
89 return false;
90 }
91 unsafe {
92 ptr::copy_nonoverlapping(src, dest, len);
93 *dest.add(len) = 0;
94 }
95 true
96}
97
98pub unsafe fn xml_strlen(str: *const xmlChar) -> c_int {
100 if str.is_null() {
101 return 0;
102 }
103 let mut len: c_int = 0;
104 while unsafe { *str.add(len as usize) != 0 } {
105 len += 1;
106 }
107 len
108}
109
110pub unsafe fn new_doc(version: *const xmlChar) -> *mut _xmlDoc {
133 let doc = allocator::xmlMallocZero(size_of::<_xmlDoc>() as usize) as *mut _xmlDoc;
135 if doc.is_null() {
136 return ptr::null_mut();
137 }
138
139 unsafe {
140 (*doc).type_ = XML_DOCUMENT_NODE as c_int;
141 (*doc).standalone = -1; (*doc).doc = doc; (*doc).properties = XML_DOC_WELLFORMED as c_int;
144 (*doc).charset = XML_CHAR_ENCODING_UTF8 as c_int;
145
146 let ver = if version.is_null() {
148 XML_DEFAULT_VERSION.as_ptr() as *const xmlChar
149 } else {
150 version
151 };
152 (*doc).version = dup_xml_str(ver);
153 }
154
155 doc
156}
157
158pub unsafe fn free_doc(doc: *mut _xmlDoc) {
172 if doc.is_null() {
173 return;
174 }
175
176 let d = unsafe { &mut *doc };
177
178 if !d.intSubset.is_null() {
180 free_dtd(d.intSubset);
181 }
182
183 if !d.extSubset.is_null() {
185 free_dtd(d.extSubset);
186 }
187
188 if !d.children.is_null() {
190 free_node_list(d.children);
191 }
192
193 if !d.oldNs.is_null() {
195 free_ns_list(d.oldNs);
196 }
197
198 if !d.version.is_null() {
200 allocator::xmlFree(d.version as *mut c_void);
201 }
202 if !d.encoding.is_null() {
203 allocator::xmlFree(d.encoding as *mut c_void);
204 }
205 if !d.URL.is_null() {
206 allocator::xmlFree(d.URL as *mut c_void);
207 }
208
209 allocator::xmlFree(doc as *mut c_void);
211}
212
213pub unsafe fn copy_doc(doc: *const _xmlDoc, recursive: c_int) -> *mut _xmlDoc {
228 if doc.is_null() {
229 return ptr::null_mut();
230 }
231
232 let d = unsafe { &*doc };
233
234 let new_doc = new_doc(d.version);
235 if new_doc.is_null() {
236 return ptr::null_mut();
237 }
238
239 unsafe {
240 (*new_doc).type_ = d.type_;
241 (*new_doc).standalone = d.standalone;
242 (*new_doc).encoding = dup_xml_str(d.encoding);
243 (*new_doc).URL = dup_xml_str(d.URL);
244 (*new_doc).charset = d.charset;
245 (*new_doc).properties = d.properties;
246
247 if recursive != 0 && !d.children.is_null() {
248 (*new_doc).children = copy_node_list(d.children, recursive);
249 if !(*new_doc).children.is_null() {
250 (*(*new_doc).children).parent = ptr::null_mut(); (*(*new_doc).children).doc = new_doc;
252 propagate_doc((*new_doc).children, new_doc);
254 }
255 }
256 }
257
258 new_doc
259}
260
261pub unsafe fn doc_set_root_element(doc: *mut _xmlDoc, root: *mut _xmlNode) -> *mut _xmlNode {
277 if doc.is_null() {
278 return ptr::null_mut();
279 }
280
281 let d = unsafe { &mut *doc };
282
283 let old_root = doc_get_root_element(doc);
284
285 if !root.is_null() {
286 unsafe {
287 (*root).parent = ptr::null_mut();
288 (*root).doc = doc;
289 }
290 d.children = root;
291 d.last = root;
292 unsafe {
293 (*root).prev = ptr::null_mut();
294 (*root).next = ptr::null_mut();
295 }
296 } else {
297 d.children = ptr::null_mut();
298 d.last = ptr::null_mut();
299 }
300
301 old_root
302}
303
304pub fn doc_get_root_element(doc: *mut _xmlDoc) -> *mut _xmlNode {
315 if doc.is_null() {
316 return ptr::null_mut();
317 }
318
319 let d = unsafe { &*doc };
320 let mut cur = d.children;
321
322 while !cur.is_null() {
323 let node = unsafe { &*cur };
324 if node.type_ == XML_ELEMENT_NODE as c_int {
325 return cur;
326 }
327 cur = node.next;
328 }
329
330 ptr::null_mut()
331}
332
333pub fn get_line_no(node: *const _xmlNode) -> c_int {
343 if node.is_null() {
344 return 0;
345 }
346 let n = unsafe { &*node };
347 n.line as c_int
348}
349
350pub unsafe fn new_node(ns: *mut _xmlNs, name: *const xmlChar) -> *mut _xmlNode {
369 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
370 if node.is_null() {
371 return ptr::null_mut();
372 }
373
374 unsafe {
375 (*node).type_ = XML_ELEMENT_NODE as c_int;
376 (*node).name = dup_xml_str(name);
377 (*node).ns = ns;
378 (*node).line = 0;
379 (*node).extra = 0;
380
381 if !ns.is_null() {
382 (*ns).context = node as *mut _xmlDoc;
383 }
384 }
385
386 node
387}
388
389pub unsafe fn free_node(node: *mut _xmlNode) {
404 if node.is_null() {
405 return;
406 }
407
408 let n = unsafe { &mut *node };
409
410 if !n.properties.is_null() {
412 free_prop_list(n.properties);
413 }
414
415 if !n.nsDef.is_null() {
417 free_ns_list(n.nsDef);
418 }
419
420 if !n.name.is_null() {
422 allocator::xmlFree(n.name as *mut c_void);
423 }
424
425 if !n.content.is_null() {
427 let node_type = n.type_;
428 if node_type == XML_TEXT_NODE as c_int
429 || node_type == XML_CDATA_SECTION_NODE as c_int
430 || node_type == XML_COMMENT_NODE as c_int
431 || node_type == XML_PI_NODE as c_int
432 {
433 allocator::xmlFree(n.content as *mut c_void);
434 }
435 }
436
437 allocator::xmlFree(node as *mut c_void);
438}
439
440pub unsafe fn free_node_list(node: *mut _xmlNode) {
448 let mut cur = node;
449 while !cur.is_null() {
450 let next = unsafe { (*cur).next };
451
452 if !unsafe { (*cur).children }.is_null() {
454 free_node_list(unsafe { (*cur).children });
455 }
456
457 free_node(cur);
458 cur = next;
459 }
460}
461
462unsafe fn free_prop_list(prop: *mut _xmlAttr) {
468 let mut cur = prop;
469 while !cur.is_null() {
470 let next = unsafe { (*cur).next };
471
472 if !unsafe { (*cur).children }.is_null() {
474 free_node_list(unsafe { (*cur).children });
475 }
476
477 if !unsafe { (*cur).name }.is_null() {
479 allocator::xmlFree(unsafe { (*cur).name } as *mut c_void);
480 }
481
482 allocator::xmlFree(cur as *mut c_void);
483 cur = next;
484 }
485}
486
487unsafe fn free_ns_list(ns: *mut _xmlNs) {
493 let mut cur = ns;
494 while !cur.is_null() {
495 let next = unsafe { (*cur).next };
496
497 if !unsafe { (*cur).href }.is_null() {
499 allocator::xmlFree(unsafe { (*cur).href } as *mut c_void);
500 }
501 if !unsafe { (*cur).prefix }.is_null() {
502 allocator::xmlFree(unsafe { (*cur).prefix } as *mut c_void);
503 }
504
505 allocator::xmlFree(cur as *mut c_void);
506 cur = next;
507 }
508}
509
510pub unsafe fn copy_node(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
525 if node.is_null() {
526 return ptr::null_mut();
527 }
528
529 let n = unsafe { &*node };
530
531 let new_node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
532 if new_node.is_null() {
533 return ptr::null_mut();
534 }
535
536 unsafe {
537 (*new_node).type_ = n.type_;
538 (*new_node).name = dup_xml_str(n.name);
539 (*new_node).line = n.line;
540 (*new_node).extra = n.extra;
541 (*new_node).psvi = n.psvi;
542 (*new_node)._private = n._private;
543
544 (*new_node).ns = n.ns;
546
547 if !n.nsDef.is_null() {
549 (*new_node).nsDef = copy_ns_list(n.nsDef);
550 }
551
552 let node_type = n.type_;
554 if (node_type == XML_TEXT_NODE as c_int
555 || node_type == XML_CDATA_SECTION_NODE as c_int
556 || node_type == XML_COMMENT_NODE as c_int
557 || node_type == XML_PI_NODE as c_int)
558 && !n.content.is_null()
559 {
560 (*new_node).content = dup_xml_str(n.content);
561 }
562
563 if !n.properties.is_null() {
565 (*new_node).properties = copy_prop_list(n.properties);
566 let mut prop = (*new_node).properties;
568 while !prop.is_null() {
569 (*prop).parent = new_node;
570 if !(*prop).children.is_null() {
571 propagate_doc((*prop).children, (*new_node).doc);
572 }
573 prop = (*prop).next;
574 }
575 }
576
577 if recursive != 0 && !n.children.is_null() {
579 (*new_node).children = copy_node_list(n.children, recursive);
580 if !(*new_node).children.is_null() {
581 (*(*new_node).children).parent = new_node;
582 (*(*new_node).children).doc = (*new_node).doc;
583 propagate_doc((*new_node).children, (*new_node).doc);
584 }
585 }
586 }
587
588 new_node
589}
590
591unsafe fn copy_node_list(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
595 if node.is_null() {
596 return ptr::null_mut();
597 }
598
599 let n = unsafe { &*node };
600 let new_node = copy_node(node, recursive);
601 if new_node.is_null() {
602 return ptr::null_mut();
603 }
604
605 let mut prev = new_node;
606 let mut cur = n.next;
607
608 while !cur.is_null() {
609 let new_cur = copy_node(cur, recursive);
610 if new_cur.is_null() {
611 break;
612 }
613 unsafe {
614 (*prev).next = new_cur;
615 (*new_cur).prev = prev;
616 }
617 prev = new_cur;
618 cur = unsafe { (*cur).next };
619 }
620
621 new_node
622}
623
624unsafe fn copy_ns_list(ns: *const _xmlNs) -> *mut _xmlNs {
626 if ns.is_null() {
627 return ptr::null_mut();
628 }
629
630 let n = unsafe { &*ns };
631 let new_ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
632 if new_ns.is_null() {
633 return ptr::null_mut();
634 }
635
636 unsafe {
637 (*new_ns).type_ = n.type_;
638 (*new_ns).href = dup_xml_str(n.href);
639 (*new_ns).prefix = dup_xml_str(n.prefix);
640 (*new_ns)._private = n._private;
641 }
642
643 let mut prev = new_ns;
644 let mut cur = n.next;
645
646 while !cur.is_null() {
647 let c = unsafe { &*cur };
648 let new_cur = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
649 if new_cur.is_null() {
650 break;
651 }
652 unsafe {
653 (*new_cur).type_ = c.type_;
654 (*new_cur).href = dup_xml_str(c.href);
655 (*new_cur).prefix = dup_xml_str(c.prefix);
656 (*new_cur)._private = c._private;
657 (*prev).next = new_cur;
658 }
659 prev = new_cur;
660 cur = c.next;
661 }
662
663 new_ns
664}
665
666unsafe fn copy_prop_list(prop: *const _xmlAttr) -> *mut _xmlAttr {
668 if prop.is_null() {
669 return ptr::null_mut();
670 }
671
672 let p = unsafe { &*prop };
673 let new_prop = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
674 if new_prop.is_null() {
675 return ptr::null_mut();
676 }
677
678 unsafe {
679 (*new_prop).type_ = p.type_;
680 (*new_prop).name = dup_xml_str(p.name);
681 (*new_prop).ns = p.ns;
682 (*new_prop).atype = p.atype;
683
684 if !p.children.is_null() {
686 (*new_prop).children = copy_node_list(p.children, 1);
687 if !(*new_prop).children.is_null() {
688 (*(*new_prop).children).parent = new_prop as *mut _xmlNode;
689 }
690 }
691 }
692
693 let mut prev = new_prop;
694 let mut cur = p.next;
695
696 while !cur.is_null() {
697 let c = unsafe { &*cur };
698 let new_cur = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
699 if new_cur.is_null() {
700 break;
701 }
702 unsafe {
703 (*new_cur).type_ = c.type_;
704 (*new_cur).name = dup_xml_str(c.name);
705 (*new_cur).ns = c.ns;
706 (*new_cur).atype = c.atype;
707
708 if !c.children.is_null() {
709 (*new_cur).children = copy_node_list(c.children, 1);
710 if !(*new_cur).children.is_null() {
711 (*(*new_cur).children).parent = new_cur as *mut _xmlNode;
712 }
713 }
714
715 (*prev).next = new_cur;
716 }
717 prev = new_cur;
718 cur = c.next;
719 }
720
721 new_prop
722}
723
724unsafe fn propagate_doc(node: *mut _xmlNode, doc: *mut _xmlDoc) {
726 let mut cur = node;
727 while !cur.is_null() {
728 unsafe {
729 (*cur).doc = doc;
730
731 let mut prop = (*cur).properties;
733 while !prop.is_null() {
734 (*prop).doc = doc;
735 if !(*prop).children.is_null() {
736 propagate_doc((*prop).children, doc);
737 }
738 prop = (*prop).next;
739 }
740
741 if !(*cur).children.is_null() {
743 propagate_doc((*cur).children, doc);
744 }
745 }
746 cur = unsafe { (*cur).next };
747 }
748}
749
750pub unsafe fn unlink_node(node: *mut _xmlNode) {
766 if node.is_null() {
767 return;
768 }
769
770 let n = unsafe { &mut *node };
771
772 let prev = n.prev;
774 let next = n.next;
775
776 if !prev.is_null() {
777 unsafe { (*prev).next = next };
778 }
779 if !next.is_null() {
780 unsafe { (*next).prev = prev };
781 }
782
783 let parent = n.parent;
785 if !parent.is_null() {
786 if unsafe { (*parent).children } == node {
787 unsafe { (*parent).children = next };
788 }
789 if unsafe { (*parent).last } == node {
790 unsafe { (*parent).last = prev };
791 }
792 }
793
794 let doc = n.doc;
796 if !doc.is_null() && !parent.is_null() {
797 }
799 if !doc.is_null() && parent.is_null() {
800 if unsafe { (*doc).children } == node {
802 unsafe { (*doc).children = next };
803 }
804 if unsafe { (*doc).last } == node {
805 unsafe { (*doc).last = prev };
806 }
807 }
808
809 n.parent = ptr::null_mut();
811 n.prev = ptr::null_mut();
812 n.next = ptr::null_mut();
813}
814
815pub unsafe fn add_child(parent: *mut _xmlNode, cur: *mut _xmlNode) -> *mut _xmlNode {
831 if parent.is_null() || cur.is_null() {
832 return ptr::null_mut();
833 }
834
835 let p = unsafe { &mut *parent };
836 let c = unsafe { &mut *cur };
837
838 if !c.parent.is_null() || !c.prev.is_null() || !c.next.is_null() {
840 unlink_node(cur);
841 }
842
843 c.parent = parent;
845
846 if p.children.is_null() {
847 p.children = cur;
849 p.last = cur;
850 c.prev = ptr::null_mut();
851 c.next = ptr::null_mut();
852 } else {
853 c.prev = p.last;
855 c.next = ptr::null_mut();
856 if !p.last.is_null() {
857 unsafe { (*p.last).next = cur };
858 }
859 p.last = cur;
860 }
861
862 let doc = if !p.doc.is_null() {
864 p.doc
865 } else {
866 ptr::null_mut()
867 };
868 if !doc.is_null() && c.doc != doc {
869 propagate_doc(cur, doc);
870 }
871
872 cur
873}
874
875pub unsafe fn add_sibling(cur: *mut _xmlNode, elem: *mut _xmlNode) -> *mut _xmlNode {
891 if cur.is_null() || elem.is_null() {
892 return ptr::null_mut();
893 }
894
895 let c = unsafe { &mut *cur };
896
897 let e = unsafe { &mut *elem };
899 if !e.parent.is_null() || !e.prev.is_null() || !e.next.is_null() {
900 unlink_node(elem);
901 }
902
903 e.parent = c.parent;
905
906 e.prev = cur;
908 e.next = c.next;
909
910 if !c.next.is_null() {
911 unsafe { (*c.next).prev = elem };
912 }
913 c.next = elem;
914
915 let parent = c.parent;
917 if !parent.is_null() && unsafe { (*parent).last } == cur {
918 unsafe { (*parent).last = elem };
919 }
920
921 if !c.doc.is_null() && e.doc != c.doc {
923 propagate_doc(elem, c.doc);
924 }
925
926 elem
927}
928
929pub unsafe fn add_sibling_before(cur: *mut _xmlNode, elem: *mut _xmlNode) -> *mut _xmlNode {
945 if cur.is_null() || elem.is_null() {
946 return ptr::null_mut();
947 }
948
949 let c = unsafe { &mut *cur };
950
951 let e = unsafe { &mut *elem };
953 if !e.parent.is_null() || !e.prev.is_null() || !e.next.is_null() {
954 unlink_node(elem);
955 }
956
957 e.parent = c.parent;
959
960 e.prev = c.prev;
962 e.next = cur;
963
964 if !c.prev.is_null() {
965 unsafe { (*c.prev).next = elem };
966 }
967 c.prev = elem;
968
969 let parent = c.parent;
971 if !parent.is_null() && unsafe { (*parent).children } == cur {
972 unsafe { (*parent).children = elem };
973 }
974
975 let doc = c.doc;
977 if !doc.is_null() && parent.is_null() {
978 if unsafe { (*doc).children } == cur {
979 unsafe { (*doc).children = elem };
980 }
981 }
982
983 if !c.doc.is_null() && e.doc != c.doc {
985 propagate_doc(elem, c.doc);
986 }
987
988 elem
989}
990
991pub unsafe fn new_child(
1006 parent: *mut _xmlNode,
1007 ns: *mut _xmlNs,
1008 name: *const xmlChar,
1009) -> *mut _xmlNode {
1010 let node = new_node(ns, name);
1011 if node.is_null() {
1012 return ptr::null_mut();
1013 }
1014
1015 if !parent.is_null() {
1016 add_child(parent, node);
1017 }
1018
1019 node
1020}
1021
1022pub unsafe fn new_text(content: *const xmlChar) -> *mut _xmlNode {
1041 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1042 if node.is_null() {
1043 return ptr::null_mut();
1044 }
1045
1046 unsafe {
1047 (*node).type_ = XML_TEXT_NODE as c_int;
1048 (*node).name = dup_xml_str(b"text\0" as *const u8 as *const xmlChar);
1049 (*node).content = if content.is_null() {
1050 let empty = allocator::xmlMalloc(1) as *mut xmlChar;
1051 if !empty.is_null() {
1052 *empty = 0;
1053 }
1054 empty
1055 } else {
1056 dup_xml_str(content)
1057 };
1058 (*node).line = 0;
1059 }
1060
1061 node
1062}
1063
1064pub unsafe fn new_comment(content: *const xmlChar) -> *mut _xmlNode {
1078 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1079 if node.is_null() {
1080 return ptr::null_mut();
1081 }
1082
1083 unsafe {
1084 (*node).type_ = XML_COMMENT_NODE as c_int;
1085 (*node).name = dup_xml_str(b"comment\0" as *const u8 as *const xmlChar);
1086 (*node).content = dup_xml_str(content);
1087 (*node).line = 0;
1088 }
1089
1090 node
1091}
1092
1093pub unsafe fn new_pi(name: *const xmlChar, content: *const xmlChar) -> *mut _xmlNode {
1108 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1109 if node.is_null() {
1110 return ptr::null_mut();
1111 }
1112
1113 unsafe {
1114 (*node).type_ = XML_PI_NODE as c_int;
1115 (*node).name = dup_xml_str(name);
1116 (*node).content = dup_xml_str(content);
1117 (*node).line = 0;
1118 }
1119
1120 node
1121}
1122
1123pub unsafe fn new_cdata_block(
1139 doc: *mut _xmlDoc,
1140 content: *const xmlChar,
1141 len: c_int,
1142) -> *mut _xmlNode {
1143 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1144 if node.is_null() {
1145 return ptr::null_mut();
1146 }
1147
1148 unsafe {
1149 (*node).type_ = XML_CDATA_SECTION_NODE as c_int;
1150 (*node).name = dup_xml_str(b"cdata\0" as *const u8 as *const xmlChar);
1151 (*node).doc = doc;
1152
1153 if !content.is_null() && len > 0 {
1154 (*node).content = allocator::xmlMalloc((len + 1) as usize) as *mut xmlChar;
1155 if !(*node).content.is_null() {
1156 ptr::copy_nonoverlapping(content, (*node).content, len as usize);
1157 *((*node).content.add(len as usize)) = 0;
1158 }
1159 } else {
1160 let empty = allocator::xmlMalloc(1) as *mut xmlChar;
1161 if !empty.is_null() {
1162 *empty = 0;
1163 }
1164 (*node).content = empty;
1165 }
1166
1167 (*node).line = 0;
1168 }
1169
1170 node
1171}
1172
1173pub unsafe fn new_ns(
1197 node: *mut _xmlNode,
1198 href: *const xmlChar,
1199 prefix: *const xmlChar,
1200) -> *mut _xmlNs {
1201 let ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
1202 if ns.is_null() {
1203 return ptr::null_mut();
1204 }
1205
1206 unsafe {
1207 (*ns).type_ = XML_LOCAL_NAMESPACE as c_int;
1208 (*ns).href = dup_xml_str(href);
1209 (*ns).prefix = dup_xml_str(prefix);
1210 (*ns).context = node as *mut _xmlDoc;
1211
1212 if !node.is_null() {
1214 let n = &mut *node;
1215 if n.nsDef.is_null() {
1216 n.nsDef = ns;
1217 } else {
1218 let mut last = n.nsDef;
1220 while !(*last).next.is_null() {
1221 last = (*last).next;
1222 }
1223 (*last).next = ns;
1224 }
1225 }
1226 }
1227
1228 ns
1229}
1230
1231pub unsafe fn set_ns(node: *mut _xmlNode, ns: *mut _xmlNs) {
1244 if node.is_null() {
1245 return;
1246 }
1247 unsafe {
1248 (*node).ns = ns;
1249 }
1250}
1251
1252pub unsafe fn get_ns_list(doc: *mut _xmlDoc, node: *mut _xmlNode) -> *mut *mut _xmlNs {
1268 if node.is_null() {
1272 return ptr::null_mut();
1273 }
1274
1275 let mut ns_ptrs: Vec<*mut _xmlNs> = Vec::new();
1277 let mut cur = node;
1278
1279 while !cur.is_null() {
1280 let n = unsafe { &*cur };
1281 let mut ns_def = n.nsDef;
1282 while !ns_def.is_null() {
1283 let ns = unsafe { &*ns_def };
1285 let mut found = false;
1286 for &existing in &ns_ptrs {
1287 if existing == ns_def {
1288 found = true;
1289 break;
1290 }
1291 let e = unsafe { &*existing };
1292 if !ns.href.is_null() && !e.href.is_null() {
1293 let href_match =
1294 unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, e.href) != 0 };
1295 if href_match {
1296 if ns.prefix.is_null() && e.prefix.is_null() {
1297 found = true;
1298 break;
1299 }
1300 if !ns.prefix.is_null() && !e.prefix.is_null() {
1301 let prefix_match = unsafe {
1302 crate::abi::exports_xml2::xmlStrEqual(ns.prefix, e.prefix) != 0
1303 };
1304 if prefix_match {
1305 found = true;
1306 break;
1307 }
1308 }
1309 }
1310 }
1311 }
1312 if !found {
1313 ns_ptrs.push(ns_def);
1314 }
1315 ns_def = unsafe { (*ns_def).next };
1316 }
1317 cur = n.parent;
1318 }
1319
1320 if ns_ptrs.is_empty() {
1321 return ptr::null_mut();
1322 }
1323
1324 let arr =
1326 allocator::xmlMalloc((ns_ptrs.len() + 1) * size_of::<*mut _xmlNs>()) as *mut *mut _xmlNs;
1327 if arr.is_null() {
1328 return ptr::null_mut();
1329 }
1330
1331 for (i, ns) in ns_ptrs.iter().enumerate() {
1332 unsafe { *arr.add(i) = *ns };
1333 }
1334 unsafe { *arr.add(ns_ptrs.len()) = ptr::null_mut() };
1335
1336 arr
1337}
1338
1339pub unsafe fn search_ns(
1356 doc: *mut _xmlDoc,
1357 node: *mut _xmlNode,
1358 name_space: *const xmlChar,
1359) -> *mut _xmlNs {
1360 if node.is_null() {
1361 return ptr::null_mut();
1362 }
1363
1364 let mut cur = node;
1365 while !cur.is_null() {
1366 let n = unsafe { &*cur };
1367 let mut ns_def = n.nsDef;
1368 while !ns_def.is_null() {
1369 let ns = unsafe { &*ns_def };
1370 let match_prefix = if name_space.is_null() {
1371 ns.prefix.is_null()
1373 } else {
1374 !ns.prefix.is_null()
1375 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.prefix, name_space) != 0 }
1376 };
1377 if match_prefix {
1378 return ns_def;
1379 }
1380 ns_def = unsafe { (*ns_def).next };
1381 }
1382 cur = n.parent;
1383 }
1384
1385 ptr::null_mut()
1386}
1387
1388pub unsafe fn search_ns_by_href(
1404 doc: *mut _xmlDoc,
1405 node: *mut _xmlNode,
1406 href: *const xmlChar,
1407) -> *mut _xmlNs {
1408 if node.is_null() || href.is_null() {
1409 return ptr::null_mut();
1410 }
1411
1412 let mut cur = node;
1413 while !cur.is_null() {
1414 let n = unsafe { &*cur };
1415 let mut ns_def = n.nsDef;
1416 while !ns_def.is_null() {
1417 let ns = unsafe { &*ns_def };
1418 if !ns.href.is_null()
1419 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, href) != 0 }
1420 {
1421 return ns_def;
1422 }
1423 ns_def = unsafe { (*ns_def).next };
1424 }
1425 cur = n.parent;
1426 }
1427
1428 ptr::null_mut()
1429}
1430
1431pub unsafe fn set_prop(
1455 node: *mut _xmlNode,
1456 name: *const xmlChar,
1457 value: *const xmlChar,
1458) -> *mut _xmlAttr {
1459 if node.is_null() || name.is_null() {
1460 return ptr::null_mut();
1461 }
1462
1463 let n = unsafe { &mut *node };
1464
1465 let mut existing = n.properties;
1467 while !existing.is_null() {
1468 let attr = unsafe { &*existing };
1469 if !attr.name.is_null()
1470 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1471 {
1472 if !attr.children.is_null() {
1475 free_node_list(attr.children);
1476 let attr_mut = existing as *mut _xmlAttr;
1478 unsafe { (*attr_mut).children = ptr::null_mut() };
1479 unsafe { (*attr_mut).last = ptr::null_mut() };
1480 }
1481 if !value.is_null() {
1483 let text = new_text(value);
1484 if !text.is_null() {
1485 let attr_mut = existing as *mut _xmlAttr;
1486 unsafe {
1487 (*attr_mut).children = text;
1488 (*attr_mut).last = text;
1489 (*text).parent = existing as *mut _xmlNode;
1490 (*text).doc = n.doc;
1491 }
1492 }
1493 }
1494 return existing;
1495 }
1496 existing = unsafe { (*existing).next };
1497 }
1498
1499 let attr = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
1501 if attr.is_null() {
1502 return ptr::null_mut();
1503 }
1504
1505 unsafe {
1506 (*attr).type_ = XML_ATTRIBUTE_NODE as c_int;
1507 (*attr).name = dup_xml_str(name);
1508 (*attr).parent = node;
1509 (*attr).doc = n.doc;
1510 (*attr).atype = XML_ATTRIBUTE_CDATA as c_int;
1511
1512 if !value.is_null() {
1514 let text = new_text(value);
1515 if !text.is_null() {
1516 (*attr).children = text;
1517 (*attr).last = text;
1518 (*text).parent = attr as *mut _xmlNode;
1519 (*text).doc = n.doc;
1520 }
1521 }
1522
1523 if n.properties.is_null() {
1525 n.properties = attr;
1526 } else {
1527 let mut last = n.properties;
1528 while !(*last).next.is_null() {
1529 last = (*last).next;
1530 }
1531 (*last).next = attr;
1532 (*attr).prev = last;
1533 }
1534 }
1535
1536 attr
1537}
1538
1539pub unsafe fn get_prop(node: *mut _xmlNode, name: *const xmlChar) -> *mut xmlChar {
1555 if node.is_null() || name.is_null() {
1556 return ptr::null_mut();
1557 }
1558
1559 let n = unsafe { &*node };
1560 let mut cur = n.properties;
1561
1562 while !cur.is_null() {
1563 let attr = unsafe { &*cur };
1564 if !attr.name.is_null()
1565 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1566 {
1567 if !attr.children.is_null() {
1569 let text = unsafe { &*attr.children };
1570 if text.type_ == XML_TEXT_NODE as c_int && !text.content.is_null() {
1571 return dup_xml_str(text.content);
1572 }
1573 }
1574 return dup_xml_str(b"\0" as *const u8 as *const xmlChar);
1575 }
1576 cur = unsafe { (*cur).next };
1577 }
1578
1579 ptr::null_mut()
1580}
1581
1582pub unsafe fn get_ns_prop(
1598 node: *mut _xmlNode,
1599 name: *const xmlChar,
1600 _name_space: *const xmlChar,
1601) -> *mut xmlChar {
1602 get_prop(node, name)
1605}
1606
1607pub unsafe fn set_ns_prop(
1622 node: *mut _xmlNode,
1623 _ns: *mut _xmlNs,
1624 name: *const xmlChar,
1625 value: *const xmlChar,
1626) -> *mut _xmlAttr {
1627 set_prop(node, name, value)
1629}
1630
1631pub unsafe fn remove_prop(attr: *mut _xmlAttr) -> c_int {
1646 if attr.is_null() {
1647 return -1;
1648 }
1649
1650 let a = unsafe { &mut *attr };
1651
1652 let parent = a.parent;
1654 if !parent.is_null() {
1655 let p = unsafe { &mut *parent };
1656 if p.properties == attr {
1657 p.properties = a.next;
1658 }
1659 }
1660
1661 if !a.prev.is_null() {
1663 unsafe { (*a.prev).next = a.next };
1664 }
1665 if !a.next.is_null() {
1666 unsafe { (*a.next).prev = a.prev };
1667 }
1668
1669 if !a.children.is_null() {
1671 free_node_list(a.children);
1672 }
1673
1674 if !a.name.is_null() {
1676 allocator::xmlFree(a.name as *mut c_void);
1677 }
1678
1679 allocator::xmlFree(attr as *mut c_void);
1680 0
1681}
1682
1683pub fn get_int_subset(doc: *const _xmlDoc) -> *mut _xmlDtd {
1695 if doc.is_null() {
1696 return ptr::null_mut();
1697 }
1698 let d = unsafe { &*doc };
1699 d.intSubset
1700}
1701
1702pub unsafe fn new_dtd(
1719 doc: *mut _xmlDoc,
1720 name: *const xmlChar,
1721 ExternalID: *const xmlChar,
1722 SystemID: *const xmlChar,
1723) -> *mut _xmlDtd {
1724 let dtd = allocator::xmlMallocZero(size_of::<_xmlDtd>() as usize) as *mut _xmlDtd;
1725 if dtd.is_null() {
1726 return ptr::null_mut();
1727 }
1728
1729 unsafe {
1730 (*dtd).type_ = XML_DTD_NODE as c_int;
1731 (*dtd).name = dup_xml_str(name);
1732 (*dtd).ExternalID = dup_xml_str(ExternalID);
1733 (*dtd).SystemID = dup_xml_str(SystemID);
1734 (*dtd).parent = doc;
1735 (*dtd).doc = doc;
1736
1737 if !doc.is_null() {
1739 if (*doc).intSubset.is_null() {
1740 (*doc).intSubset = dtd;
1741 }
1742 }
1743 }
1744
1745 dtd
1746}
1747
1748unsafe fn free_dtd(dtd: *mut _xmlDtd) {
1754 if dtd.is_null() {
1755 return;
1756 }
1757
1758 let d = unsafe { &mut *dtd };
1759
1760 if !d.name.is_null() {
1762 allocator::xmlFree(d.name as *mut c_void);
1763 }
1764 if !d.ExternalID.is_null() {
1765 allocator::xmlFree(d.ExternalID as *mut c_void);
1766 }
1767 if !d.SystemID.is_null() {
1768 allocator::xmlFree(d.SystemID as *mut c_void);
1769 }
1770
1771 if !d.children.is_null() {
1773 free_node_list(d.children);
1774 }
1775
1776 allocator::xmlFree(dtd as *mut c_void);
1777}
1778
1779pub unsafe fn new_entity(
1799 _doc: *mut _xmlDoc,
1800 name: *const xmlChar,
1801 etype: c_int,
1802 ExternalID: *const xmlChar,
1803 SystemID: *const xmlChar,
1804 content: *const xmlChar,
1805) -> *mut _xmlEntity {
1806 let entity = allocator::xmlMallocZero(size_of::<_xmlEntity>() as usize) as *mut _xmlEntity;
1807 if entity.is_null() {
1808 return ptr::null_mut();
1809 }
1810
1811 unsafe {
1812 (*entity).type_ = XML_ENTITY_DECL as c_int;
1813 (*entity).name = dup_xml_str(name);
1814 (*entity).etype = etype;
1815 (*entity).ExternalID = dup_xml_str(ExternalID);
1816 (*entity).SystemID = dup_xml_str(SystemID);
1817 (*entity).content = dup_xml_str(content);
1818 (*entity).length = if content.is_null() {
1819 0
1820 } else {
1821 crate::abi::exports_xml2::xmlStrlen(content)
1822 };
1823 (*entity).flags = 0;
1824 (*entity).expandedSize = 0;
1825 }
1826
1827 entity
1828}
1829
1830pub unsafe fn get_doc_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
1845 let _ = doc;
1848 let _ = name;
1849 ptr::null_mut()
1850}
1851
1852pub unsafe fn get_parameter_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
1865 let _ = doc;
1867 let _ = name;
1868 ptr::null_mut()
1869}
1870
1871const ENTITY_LT: &[xmlChar] = b"<";
1880const ENTITY_GT: &[xmlChar] = b">";
1881const ENTITY_AMP: &[xmlChar] = b"&";
1882const ENTITY_QUOT: &[xmlChar] = b""";
1883const ENTITY_APOS: &[xmlChar] = b"'";
1884
1885const INDENT: &[xmlChar] = b" ";
1887
1888const XML_DECL: &[xmlChar] = b"<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1890
1891unsafe fn serialize_text(buf: *mut _xmlBuffer, content: *const xmlChar, len: c_int) {
1900 if buf.is_null() || content.is_null() || len <= 0 {
1901 return;
1902 }
1903
1904 let mut i: c_int = 0;
1905 while i < len {
1906 let ch = unsafe { *content.add(i as usize) };
1907
1908 if ch == b']'
1910 && i + 2 < len
1911 && unsafe { *content.add(i as usize + 1) == b']' }
1912 && unsafe { *content.add(i as usize + 2) == b'>' }
1913 {
1914 io::buf_add(buf, &ch as *const u8, 2); io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
1917 i += 3;
1918 continue;
1919 }
1920
1921 match ch {
1922 b'<' => {
1923 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
1924 }
1925 b'&' => {
1926 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
1927 }
1928 _ => {
1929 io::buf_add(buf, &ch as *const u8, 1);
1930 }
1931 }
1932 i += 1;
1933 }
1934}
1935
1936unsafe fn serialize_attr_value(buf: *mut _xmlBuffer, value: *const xmlChar) {
1945 if buf.is_null() || value.is_null() {
1946 return;
1947 }
1948
1949 let len = xml_strlen(value);
1950 let mut i: c_int = 0;
1951 while i < len {
1952 let ch = unsafe { *value.add(i as usize) };
1953
1954 if ch == b']'
1956 && i + 2 < len
1957 && unsafe { *value.add(i as usize + 1) == b']' }
1958 && unsafe { *value.add(i as usize + 2) == b'>' }
1959 {
1960 io::buf_add(buf, &ch as *const u8, 2); io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
1963 i += 3;
1964 continue;
1965 }
1966
1967 match ch {
1968 b'<' => {
1969 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
1970 }
1971 b'&' => {
1972 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
1973 }
1974 b'"' => {
1975 io::buf_add(buf, ENTITY_QUOT.as_ptr(), ENTITY_QUOT.len() as c_int);
1976 }
1977 _ => {
1978 io::buf_add(buf, &ch as *const u8, 1);
1979 }
1980 }
1981 i += 1;
1982 }
1983}
1984
1985unsafe fn write_indent(buf: *mut _xmlBuffer, level: c_int) {
1991 if buf.is_null() || level <= 0 {
1992 return;
1993 }
1994 for _ in 0..level {
1995 io::buf_add(buf, INDENT.as_ptr(), INDENT.len() as c_int);
1996 }
1997}
1998
1999unsafe fn serialize_start_tag(
2008 node: *mut _xmlNode,
2009 buf: *mut _xmlBuffer,
2010 format: c_int,
2011 level: c_int,
2012) {
2013 if node.is_null() || buf.is_null() {
2014 return;
2015 }
2016
2017 let n = unsafe { &*node };
2018
2019 io::buf_ccat(buf, b'<');
2021
2022 if !n.ns.is_null() {
2024 let ns = unsafe { &*n.ns };
2025 if !ns.prefix.is_null() {
2026 io::buf_cat(buf, ns.prefix);
2027 io::buf_ccat(buf, b':');
2028 }
2029 }
2030 if !n.name.is_null() {
2031 io::buf_cat(buf, n.name);
2032 }
2033
2034 let mut attr = n.properties;
2036 while !attr.is_null() {
2037 let a = unsafe { &*attr };
2038 io::buf_ccat(buf, b' ');
2039
2040 if !a.ns.is_null() {
2042 let ans = unsafe { &*a.ns };
2043 if !ans.prefix.is_null() {
2044 io::buf_cat(buf, ans.prefix);
2045 io::buf_ccat(buf, b':');
2046 }
2047 }
2048 if !a.name.is_null() {
2049 io::buf_cat(buf, a.name);
2050 }
2051
2052 io::buf_add(buf, b"=\"" as *const u8, 2);
2053
2054 if !a.children.is_null() {
2056 let child = unsafe { &*a.children };
2057 if child.type_ == XML_TEXT_NODE as c_int && !child.content.is_null() {
2058 serialize_attr_value(buf, child.content);
2059 }
2060 }
2061
2062 io::buf_ccat(buf, b'"');
2063
2064 attr = a.next;
2065 }
2066
2067 let mut ns_def = n.nsDef;
2069 while !ns_def.is_null() {
2070 let nd = unsafe { &*ns_def };
2071 io::buf_add(buf, b" xmlns" as *const u8, 6);
2072 if !nd.prefix.is_null() {
2073 io::buf_ccat(buf, b':');
2074 io::buf_cat(buf, nd.prefix);
2075 }
2076 io::buf_add(buf, b"=\"" as *const u8, 2);
2077 if !nd.href.is_null() {
2078 serialize_attr_value(buf, nd.href);
2079 }
2080 io::buf_ccat(buf, b'"');
2081 ns_def = nd.next;
2082 }
2083
2084 if n.children.is_null() {
2085 io::buf_add(buf, b"/>" as *const u8, 2);
2087 } else {
2088 io::buf_ccat(buf, b'>');
2089 }
2090}
2091
2092unsafe fn serialize_end_tag(node: *mut _xmlNode, buf: *mut _xmlBuffer) {
2099 if node.is_null() || buf.is_null() {
2100 return;
2101 }
2102
2103 let n = unsafe { &*node };
2104
2105 io::buf_add(buf, b"</" as *const u8, 2);
2106 if !n.ns.is_null() {
2107 let ns = unsafe { &*n.ns };
2108 if !ns.prefix.is_null() {
2109 io::buf_cat(buf, ns.prefix);
2110 io::buf_ccat(buf, b':');
2111 }
2112 }
2113 if !n.name.is_null() {
2114 io::buf_cat(buf, n.name);
2115 }
2116 io::buf_ccat(buf, b'>');
2117}
2118
2119unsafe fn is_text_only_element(node: *mut _xmlNode) -> bool {
2121 if node.is_null() {
2122 return false;
2123 }
2124 let n = unsafe { &*node };
2125 if n.children.is_null() {
2126 return false;
2127 }
2128 if n.children != n.last {
2130 return false;
2131 }
2132 let child = unsafe { &*n.children };
2133 child.type_ == XML_TEXT_NODE as c_int
2134}
2135
2136pub(crate) unsafe fn serialize_node(
2145 node: *mut _xmlNode,
2146 buf: *mut _xmlBuffer,
2147 format: c_int,
2148 level: c_int,
2149) {
2150 if node.is_null() || buf.is_null() {
2151 return;
2152 }
2153
2154 let n = unsafe { &*node };
2155
2156 match n.type_ {
2157 t if t == XML_ELEMENT_NODE as c_int => {
2158 let is_text_only = is_text_only_element(node);
2159
2160 if format != 0 && level > 0 {
2162 io::buf_ccat(buf, b'\n');
2163 write_indent(buf, level);
2164 }
2165
2166 serialize_start_tag(node, buf, format, level);
2167
2168 if !n.children.is_null() {
2169 if !is_text_only && format != 0 {
2170 let mut child = n.children;
2172 while !child.is_null() {
2173 serialize_node(child, buf, format, level + 1);
2174 child = unsafe { (*child).next };
2175 }
2176 io::buf_ccat(buf, b'\n');
2177 write_indent(buf, level);
2178 } else {
2179 let mut child = n.children;
2181 while !child.is_null() {
2182 serialize_node(child, buf, format, level + 1);
2183 child = unsafe { (*child).next };
2184 }
2185 }
2186 serialize_end_tag(node, buf);
2187 }
2188 }
2189 t if t == XML_TEXT_NODE as c_int => {
2190 serialize_text(buf, n.content, xml_strlen(n.content));
2191 }
2192 t if t == XML_CDATA_SECTION_NODE as c_int => {
2193 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
2194 serialize_text(buf, n.content, xml_strlen(n.content));
2195 io::buf_add(buf, b"]]>" as *const u8, 3);
2196 }
2197 t if t == XML_COMMENT_NODE as c_int => {
2198 if format != 0 && level > 0 {
2199 io::buf_ccat(buf, b'\n');
2200 write_indent(buf, level);
2201 }
2202 io::buf_add(buf, b"<!--" as *const u8, 4);
2203 if !n.content.is_null() {
2204 io::buf_cat(buf, n.content);
2205 }
2206 io::buf_add(buf, b"-->" as *const u8, 3);
2207 }
2208 t if t == XML_PI_NODE as c_int => {
2209 if format != 0 && level > 0 {
2210 io::buf_ccat(buf, b'\n');
2211 write_indent(buf, level);
2212 }
2213 io::buf_add(buf, b"<?" as *const u8, 2);
2214 if !n.name.is_null() {
2215 io::buf_cat(buf, n.name);
2216 }
2217 if !n.content.is_null() && unsafe { *n.content != 0 } {
2218 io::buf_ccat(buf, b' ');
2219 io::buf_cat(buf, n.content);
2220 }
2221 io::buf_add(buf, b"?>" as *const u8, 2);
2222 }
2223 t if t == XML_DOCUMENT_NODE as c_int || t == XML_HTML_DOCUMENT_NODE as c_int => {
2224 io::buf_add(buf, XML_DECL.as_ptr(), XML_DECL.len() as c_int);
2226
2227 if format != 0 {
2229 io::buf_ccat(buf, b'\n');
2230 }
2231
2232 let mut child = n.children;
2234 while !child.is_null() {
2235 serialize_node(child, buf, format, 0);
2236 child = unsafe { (*child).next };
2237 }
2238 if format != 0 {
2239 io::buf_ccat(buf, b'\n');
2240 }
2241 }
2242 t if t == XML_DTD_NODE as c_int => {
2243 }
2245 _ => {
2246 if !n.content.is_null() {
2248 serialize_text(buf, n.content, xml_strlen(n.content));
2249 }
2250 }
2251 }
2252}
2253
2254pub(crate) unsafe fn doc_dump(buf: *mut _xmlBuffer, doc: *mut _xmlDoc) -> c_int {
2264 if buf.is_null() || doc.is_null() {
2265 return -1;
2266 }
2267
2268 let before = io::buf_length(buf);
2269 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
2270 let after = io::buf_length(buf);
2271
2272 if after < 0 || before < 0 {
2273 return -1;
2274 }
2275 after - before
2276}
2277
2278pub(crate) unsafe fn node_dump(
2290 buf: *mut _xmlBuffer,
2291 doc: *mut _xmlDoc,
2292 node: *mut _xmlNode,
2293 level: c_int,
2294 format: c_int,
2295) -> c_int {
2296 let _ = doc; if buf.is_null() || node.is_null() {
2298 return -1;
2299 }
2300
2301 let before = io::buf_length(buf);
2302 serialize_node(node, buf, format, level);
2303 let after = io::buf_length(buf);
2304
2305 if after < 0 || before < 0 {
2306 return -1;
2307 }
2308 after - before
2309}
2310
2311pub(crate) unsafe fn save_doc_to_filename(
2318 doc: *mut _xmlDoc,
2319 filename: *const c_char,
2320 compression: c_int,
2321) -> c_int {
2322 if doc.is_null() || filename.is_null() {
2323 return -1;
2324 }
2325
2326 let out = io::output_buffer_create_filename(filename, ptr::null_mut(), compression);
2327 if out.is_null() {
2328 return -1;
2329 }
2330
2331 let buf = io::buf_create(-1);
2332 if buf.is_null() {
2333 io::output_buffer_close(out);
2334 return -1;
2335 }
2336
2337 let ret = doc_dump(buf, doc);
2338 if ret >= 0 {
2339 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
2341 io::output_buffer_flush(out);
2342 }
2343
2344 io::buf_free(buf);
2345 io::output_buffer_close(out);
2346 ret
2347}
2348
2349pub(crate) unsafe fn save_doc_to_fd(doc: *mut _xmlDoc, fd: c_int, compression: c_int) -> c_int {
2356 if doc.is_null() || fd < 0 {
2357 return -1;
2358 }
2359
2360 let out = io::output_buffer_create_fd(fd, ptr::null_mut());
2361 if out.is_null() {
2362 return -1;
2363 }
2364
2365 let buf = io::buf_create(-1);
2366 if buf.is_null() {
2367 io::output_buffer_close(out);
2368 return -1;
2369 }
2370
2371 let ret = doc_dump(buf, doc);
2372 if ret >= 0 {
2373 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
2374 io::output_buffer_flush(out);
2375 }
2376
2377 io::buf_free(buf);
2378 io::output_buffer_close(out);
2379 ret
2380}
2381
2382pub(crate) unsafe fn save_doc_to_buf(
2389 doc: *mut _xmlDoc,
2390 buf: *mut _xmlBuffer,
2391 compression: c_int,
2392) -> c_int {
2393 let _ = compression;
2394 if doc.is_null() || buf.is_null() {
2395 return -1;
2396 }
2397
2398 doc_dump(buf, doc)
2399}
2400
2401pub(crate) unsafe fn save_format_doc_to_buf(
2408 doc: *mut _xmlDoc,
2409 buf: *mut _xmlBuffer,
2410 compression: c_int,
2411) -> c_int {
2412 let _ = compression;
2413 if doc.is_null() || buf.is_null() {
2414 return -1;
2415 }
2416
2417 let before = io::buf_length(buf);
2418 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
2419 let after = io::buf_length(buf);
2420
2421 if after < 0 || before < 0 {
2422 return -1;
2423 }
2424 after - before
2425}
2426
2427pub(crate) unsafe fn dump_node(node: *mut _xmlNode) -> *mut xmlChar {
2436 if node.is_null() {
2437 return ptr::null_mut();
2438 }
2439
2440 let buf = io::buf_create(-1);
2441 if buf.is_null() {
2442 return ptr::null_mut();
2443 }
2444
2445 serialize_node(node, buf, 0, 0);
2446
2447 let content = io::buf_content(buf);
2448 if content.is_null() {
2449 io::buf_free(buf);
2450 return ptr::null_mut();
2451 }
2452
2453 let result = dup_xml_str(content);
2455 io::buf_free(buf);
2456 result
2457}
2458
2459pub(crate) unsafe fn dump_doc(doc: *mut _xmlDoc) -> *mut xmlChar {
2468 if doc.is_null() {
2469 return ptr::null_mut();
2470 }
2471
2472 let buf = io::buf_create(-1);
2473 if buf.is_null() {
2474 return ptr::null_mut();
2475 }
2476
2477 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
2478
2479 let content = io::buf_content(buf);
2480 if content.is_null() {
2481 io::buf_free(buf);
2482 return ptr::null_mut();
2483 }
2484
2485 let result = dup_xml_str(content);
2486 io::buf_free(buf);
2487 result
2488}
2489
2490pub(crate) unsafe fn xmlNodeDump(
2506 buf: *mut _xmlBuffer,
2507 doc: *mut _xmlDoc,
2508 node: *mut _xmlNode,
2509 level: c_int,
2510 format: c_int,
2511) -> c_int {
2512 node_dump(buf, doc, node, level, format)
2513}
2514
2515pub(crate) unsafe fn xmlDocDump(fp: *mut c_void, doc: *mut _xmlDoc) -> c_int {
2528 if fp.is_null() || doc.is_null() {
2529 return -1;
2530 }
2531
2532 let buf = io::buf_create(-1);
2533 if buf.is_null() {
2534 return -1;
2535 }
2536
2537 let ret = doc_dump(buf, doc);
2538 if ret < 0 {
2539 io::buf_free(buf);
2540 return -1;
2541 }
2542
2543 let content = io::buf_content(buf);
2544 let len = io::buf_length(buf);
2545 if !content.is_null() && len > 0 {
2546 let written = libc::fwrite(
2547 content as *const c_void,
2548 1,
2549 len as usize,
2550 fp as *mut libc::FILE,
2551 );
2552 io::buf_free(buf);
2553 written as c_int
2554 } else {
2555 io::buf_free(buf);
2556 0
2557 }
2558}
2559
2560pub(crate) unsafe fn xmlDocDumpFormatMemory(
2574 doc: *mut _xmlDoc,
2575 mem: *mut *mut xmlChar,
2576 size: *mut c_int,
2577 format: c_int,
2578) {
2579 if doc.is_null() || mem.is_null() || size.is_null() {
2580 return;
2581 }
2582
2583 let buf = io::buf_create(-1);
2584 if buf.is_null() {
2585 unsafe {
2586 *mem = ptr::null_mut();
2587 *size = 0;
2588 }
2589 return;
2590 }
2591
2592 serialize_node(doc as *mut _xmlNode, buf, format, 0);
2593
2594 let content = io::buf_content(buf);
2595 let len = io::buf_length(buf);
2596
2597 if !content.is_null() && len > 0 {
2598 let result = allocator::xmlMalloc((len + 1) as usize) as *mut xmlChar;
2600 if !result.is_null() {
2601 ptr::copy_nonoverlapping(content, result, len as usize);
2602 *result.add(len as usize) = 0;
2603 unsafe {
2604 *mem = result;
2605 *size = len;
2606 }
2607 } else {
2608 unsafe {
2609 *mem = ptr::null_mut();
2610 *size = 0;
2611 }
2612 }
2613 } else {
2614 unsafe {
2615 *mem = ptr::null_mut();
2616 *size = 0;
2617 }
2618 }
2619
2620 io::buf_free(buf);
2621}
2622
2623pub(crate) unsafe fn xmlDocDumpMemory(doc: *mut _xmlDoc, mem: *mut *mut xmlChar, size: *mut c_int) {
2637 xmlDocDumpFormatMemory(doc, mem, size, 0)
2638}
2639
2640pub(crate) unsafe fn xmlSaveFile(filename: *const c_char, cur: *mut _xmlDoc) -> c_int {
2653 save_doc_to_filename(cur, filename, 0)
2654}
2655
2656pub(crate) unsafe fn xmlSaveFileEnc(
2670 filename: *const c_char,
2671 cur: *mut _xmlDoc,
2672 encoding: *const c_char,
2673) -> c_int {
2674 let _ = encoding; save_doc_to_filename(cur, filename, 0)
2676}
2677
2678pub(crate) unsafe fn xmlSaveFormatFile(
2691 filename: *const c_char,
2692 cur: *mut _xmlDoc,
2693 format: c_int,
2694) -> c_int {
2695 let _ = format;
2696 save_doc_to_filename(cur, filename, 0)
2697}
2698
2699pub(crate) unsafe fn xmlSaveFormatFileEnc(
2713 filename: *const c_char,
2714 cur: *mut _xmlDoc,
2715 encoding: *const c_char,
2716 format: c_int,
2717) -> c_int {
2718 let _ = encoding;
2719 let _ = format;
2720 save_doc_to_filename(cur, filename, 0)
2721}
2722
2723pub(crate) unsafe fn xmlGetDocCompressMode(doc: *mut _xmlDoc) -> c_int {
2735 if doc.is_null() {
2736 return -1;
2737 }
2738 unsafe { (*doc).compression }
2739}
2740
2741pub(crate) unsafe fn xmlSetDocCompressMode(doc: *mut _xmlDoc, mode: c_int) {
2753 if doc.is_null() {
2754 return;
2755 }
2756 unsafe {
2757 (*doc).compression = mode;
2758 }
2759}
2760
2761#[cfg(test)]
2762mod tests {
2763 use super::*;
2764 use core::ffi::c_void;
2765
2766 fn c_str(s: &str) -> *const xmlChar {
2767 let bytes = s.as_bytes();
2768 let buf = unsafe { allocator::xmlMalloc(bytes.len() + 1) as *mut u8 };
2769 if !buf.is_null() {
2770 unsafe {
2771 ptr::copy_nonoverlapping(bytes.as_ptr(), buf, bytes.len());
2772 *buf.add(bytes.len()) = 0;
2773 }
2774 }
2775 buf as *const xmlChar
2776 }
2777
2778 #[test]
2779 fn test_new_free_doc() {
2780 unsafe {
2781 let doc = new_doc(ptr::null());
2782 assert!(!doc.is_null());
2783 assert_eq!((*doc).type_, XML_DOCUMENT_NODE as c_int);
2784 assert_eq!((*doc).standalone, -1);
2785 assert_eq!((*doc).doc, doc);
2786 assert!(!(*doc).version.is_null());
2787 free_doc(doc);
2788 }
2789 }
2790
2791 #[test]
2792 fn test_new_doc_with_version() {
2793 unsafe {
2794 let ver = c_str("2.0");
2795 let doc = new_doc(ver);
2796 assert!(!doc.is_null());
2797 let doc_ver = (*doc).version;
2798 assert!(!doc_ver.is_null());
2799 assert!(crate::abi::exports_xml2::xmlStrEqual(doc_ver, ver,) != 0);
2800 allocator::xmlFree(ver as *mut c_void);
2801 free_doc(doc);
2802 }
2803 }
2804
2805 #[test]
2806 fn test_new_node() {
2807 unsafe {
2808 let doc = new_doc(ptr::null());
2809 let node = new_node(ptr::null_mut(), c_str("root"));
2810 assert!(!node.is_null());
2811 assert_eq!((*node).type_, XML_ELEMENT_NODE as c_int);
2812 assert!(!(*node).name.is_null());
2813 free_node(node);
2814 free_doc(doc);
2815 }
2816 }
2817
2818 #[test]
2819 fn test_doc_set_root_element() {
2820 unsafe {
2821 let doc = new_doc(ptr::null());
2822 let root = new_node(ptr::null_mut(), c_str("root"));
2823 let old = doc_set_root_element(doc, root);
2824 assert!(old.is_null());
2825 assert_eq!(doc_get_root_element(doc), root);
2826 assert_eq!((*doc).children, root as *mut _xmlNode);
2827 free_doc(doc);
2828 }
2829 }
2830
2831 #[test]
2832 fn test_add_child_and_sibling() {
2833 unsafe {
2834 let doc = new_doc(ptr::null());
2835 let root = new_node(ptr::null_mut(), c_str("root"));
2836 doc_set_root_element(doc, root);
2837
2838 let child1 = new_child(root, ptr::null_mut(), c_str("child1"));
2839 assert!(!child1.is_null());
2840 assert_eq!((*child1).parent, root);
2841 assert_eq!((*root).children, child1);
2842 assert_eq!((*root).last, child1);
2843
2844 let child2 = new_child(root, ptr::null_mut(), c_str("child2"));
2845 assert!(!child2.is_null());
2846 assert_eq!((*child2).parent, root);
2847 assert_eq!((*child1).next, child2);
2848 assert_eq!((*child2).prev, child1);
2849 assert_eq!((*root).last, child2);
2850
2851 let sibling = new_node(ptr::null_mut(), c_str("sibling"));
2853 add_sibling(child2, sibling);
2854 assert_eq!((*child2).next, sibling);
2855 assert_eq!((*sibling).prev, child2);
2856 assert_eq!((*root).last, sibling);
2857
2858 free_doc(doc);
2859 }
2860 }
2861
2862 #[test]
2863 fn test_unlink_node() {
2864 unsafe {
2865 let doc = new_doc(ptr::null());
2866 let root = new_node(ptr::null_mut(), c_str("root"));
2867 doc_set_root_element(doc, root);
2868
2869 let child1 = new_child(root, ptr::null_mut(), c_str("c1"));
2870 let child2 = new_child(root, ptr::null_mut(), c_str("c2"));
2871
2872 unlink_node(child1);
2873 assert!((*child1).parent.is_null());
2874 assert!((*child1).prev.is_null());
2875 assert!((*child1).next.is_null());
2876 assert_eq!((*root).children, child2);
2877 assert_eq!((*root).last, child2);
2878
2879 free_node(child1);
2880 free_doc(doc);
2881 }
2882 }
2883
2884 #[test]
2885 fn test_text_and_comment_nodes() {
2886 unsafe {
2887 let text = new_text(c_str("hello world"));
2888 assert!(!text.is_null());
2889 assert_eq!((*text).type_, XML_TEXT_NODE as c_int);
2890 assert!(!(*text).content.is_null());
2891 free_node(text);
2892
2893 let comment = new_comment(c_str("my comment"));
2894 assert!(!comment.is_null());
2895 assert_eq!((*comment).type_, XML_COMMENT_NODE as c_int);
2896 free_node(comment);
2897
2898 let pi = new_pi(c_str("xml"), c_str("version='1.0'"));
2899 assert!(!pi.is_null());
2900 assert_eq!((*pi).type_, XML_PI_NODE as c_int);
2901 free_node(pi);
2902 }
2903 }
2904
2905 #[test]
2906 fn test_set_and_get_prop() {
2907 unsafe {
2908 let doc = new_doc(ptr::null());
2909 let root = new_node(ptr::null_mut(), c_str("root"));
2910 doc_set_root_element(doc, root);
2911
2912 let attr = set_prop(root, c_str("id"), c_str("42"));
2913 assert!(!attr.is_null());
2914 assert_eq!((*attr).type_, XML_ATTRIBUTE_NODE as c_int);
2915
2916 let value = get_prop(root, c_str("id"));
2917 assert!(!value.is_null());
2918 assert!(crate::abi::exports_xml2::xmlStrEqual(value, c_str("42")) != 0);
2919 allocator::xmlFree(value as *mut c_void);
2920
2921 free_doc(doc);
2922 }
2923 }
2924
2925 #[test]
2926 fn test_remove_prop() {
2927 unsafe {
2928 let doc = new_doc(ptr::null());
2929 let root = new_node(ptr::null_mut(), c_str("root"));
2930 doc_set_root_element(doc, root);
2931
2932 set_prop(root, c_str("a"), c_str("1"));
2933 set_prop(root, c_str("b"), c_str("2"));
2934
2935 let value = get_prop(root, c_str("a"));
2936 assert!(!value.is_null());
2937 allocator::xmlFree(value as *mut c_void);
2938
2939 let attr = (*root).properties;
2941 assert!(!attr.is_null());
2942 let result = remove_prop(attr);
2943 assert_eq!(result, 0);
2944
2945 let value2 = get_prop(root, c_str("a"));
2947 assert!(value2.is_null());
2948
2949 free_doc(doc);
2950 }
2951 }
2952
2953 #[test]
2954 fn test_namespace_operations() {
2955 unsafe {
2956 let doc = new_doc(ptr::null());
2957 let root = new_node(ptr::null_mut(), c_str("root"));
2958 doc_set_root_element(doc, root);
2959
2960 let ns = new_ns(root, c_str("http://example.com"), c_str("ex"));
2961 assert!(!ns.is_null());
2962 assert!(!(*root).nsDef.is_null());
2963
2964 set_ns(root, ns);
2965 assert_eq!((*root).ns, ns);
2966
2967 let found = search_ns(doc, root, c_str("ex"));
2968 assert_eq!(found, ns);
2969
2970 let found_href = search_ns_by_href(doc, root, c_str("http://example.com"));
2971 assert_eq!(found_href, ns);
2972
2973 free_doc(doc);
2974 }
2975 }
2976
2977 #[test]
2978 fn test_new_dtd() {
2979 unsafe {
2980 let doc = new_doc(ptr::null());
2981 let dtd = new_dtd(doc, c_str("root"), c_str("-//TEST//DTD"), c_str("test.dtd"));
2982 assert!(!dtd.is_null());
2983 assert_eq!((*dtd).type_, XML_DTD_NODE as c_int);
2984 assert_eq!(get_int_subset(doc), dtd);
2985 free_doc(doc);
2986 }
2987 }
2988
2989 #[test]
2990 fn test_copy_node_deep() {
2991 unsafe {
2992 let doc = new_doc(ptr::null());
2993 let root = new_node(ptr::null_mut(), c_str("root"));
2994 doc_set_root_element(doc, root);
2995 let child = new_child(root, ptr::null_mut(), c_str("child"));
2996
2997 let copy = copy_node(root, 1);
2998 assert!(!copy.is_null());
2999 assert_eq!((*copy).type_, XML_ELEMENT_NODE as c_int);
3000 assert!(!(*copy).children.is_null());
3002 assert_eq!((*(*copy).children).type_, XML_ELEMENT_NODE as c_int);
3003
3004 free_node(copy);
3005 free_doc(doc);
3006 }
3007 }
3008
3009 #[test]
3010 fn test_new_cdata_block() {
3011 unsafe {
3012 let doc = new_doc(ptr::null());
3013 let content = c_str("some <cdata> content");
3014 let cdata = new_cdata_block(doc, content, 20);
3015 assert!(!cdata.is_null());
3016 assert_eq!((*cdata).type_, XML_CDATA_SECTION_NODE as c_int);
3017 free_node(cdata);
3018 free_doc(doc);
3019 }
3020 }
3021
3022 #[test]
3023 fn test_null_handling() {
3024 unsafe {
3025 assert!(new_doc(ptr::null()).is_null() == false); let doc = new_doc(ptr::null());
3027 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());
3032 assert!(add_sibling(ptr::null_mut(), ptr::null_mut()).is_null());
3033 free_doc(doc);
3034 }
3035 }
3036
3037 unsafe fn buf_eq_str(buf: *mut _xmlBuffer, expected: &str) -> bool {
3043 let content = io::buf_content(buf);
3044 if content.is_null() {
3045 return expected.is_empty();
3046 }
3047 let len = io::buf_length(buf) as usize;
3048 if len != expected.len() {
3049 return false;
3050 }
3051 let slice = unsafe { core::slice::from_raw_parts(content, len) };
3052 slice == expected.as_bytes()
3053 }
3054
3055 #[test]
3056 fn test_serialize_empty_document() {
3057 unsafe {
3058 let doc = new_doc(ptr::null());
3059 let buf = io::buf_create(-1);
3060 assert!(!buf.is_null());
3061
3062 let ret = doc_dump(buf, doc);
3063 assert!(ret >= 0);
3064
3065 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
3067 assert!(buf_eq_str(buf, expected));
3068
3069 io::buf_free(buf);
3070 free_doc(doc);
3071 }
3072 }
3073
3074 #[test]
3075 fn test_serialize_element_with_text() {
3076 unsafe {
3077 let doc = new_doc(ptr::null());
3078 let root = new_node(ptr::null_mut(), c_str("root"));
3079 doc_set_root_element(doc, root);
3080
3081 let text = new_text(c_str("hello world"));
3083 add_child(root, text);
3084
3085 let buf = io::buf_create(-1);
3086 assert!(!buf.is_null());
3087
3088 let ret = doc_dump(buf, doc);
3089 assert!(ret >= 0);
3090
3091 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>hello world</root>";
3092 assert!(buf_eq_str(buf, expected));
3093
3094 io::buf_free(buf);
3095 free_doc(doc);
3096 }
3097 }
3098
3099 #[test]
3100 fn test_serialize_element_with_attributes() {
3101 unsafe {
3102 let doc = new_doc(ptr::null());
3103 let root = new_node(ptr::null_mut(), c_str("root"));
3104 doc_set_root_element(doc, root);
3105
3106 set_prop(root, c_str("id"), c_str("42"));
3107 set_prop(root, c_str("name"), c_str("test"));
3108
3109 let buf = io::buf_create(-1);
3110 assert!(!buf.is_null());
3111
3112 let ret = doc_dump(buf, doc);
3113 assert!(ret >= 0);
3114
3115 let expected =
3116 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root id=\"42\" name=\"test\"/>";
3117 assert!(buf_eq_str(buf, expected));
3118
3119 io::buf_free(buf);
3120 free_doc(doc);
3121 }
3122 }
3123
3124 #[test]
3125 fn test_serialize_nested_elements() {
3126 unsafe {
3127 let doc = new_doc(ptr::null());
3128 let root = new_node(ptr::null_mut(), c_str("root"));
3129 doc_set_root_element(doc, root);
3130
3131 let child = new_child(root, ptr::null_mut(), c_str("child"));
3132 let grandchild = new_child(child, ptr::null_mut(), c_str("gc"));
3133 let text = new_text(c_str("text"));
3134 add_child(grandchild, text);
3135
3136 let buf = io::buf_create(-1);
3137 assert!(!buf.is_null());
3138
3139 let ret = doc_dump(buf, doc);
3140 assert!(ret >= 0);
3141
3142 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root><child><gc>text</gc></child></root>";
3143 assert!(buf_eq_str(buf, expected));
3144
3145 io::buf_free(buf);
3146 free_doc(doc);
3147 }
3148 }
3149
3150 #[test]
3151 fn test_serialize_with_formatting() {
3152 unsafe {
3153 let doc = new_doc(ptr::null());
3154 let root = new_node(ptr::null_mut(), c_str("root"));
3155 doc_set_root_element(doc, root);
3156
3157 let child = new_child(root, ptr::null_mut(), c_str("child"));
3158 let text = new_text(c_str("text"));
3159 add_child(child, text);
3160
3161 let buf = io::buf_create(-1);
3162 assert!(!buf.is_null());
3163
3164 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
3165
3166 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<root>\n <child>text</child>\n</root>\n";
3167 assert!(buf_eq_str(buf, expected));
3168
3169 io::buf_free(buf);
3170 free_doc(doc);
3171 }
3172 }
3173
3174 #[test]
3175 fn test_serialize_escape_ampersand() {
3176 unsafe {
3177 let doc = new_doc(ptr::null());
3178 let root = new_node(ptr::null_mut(), c_str("root"));
3179 doc_set_root_element(doc, root);
3180
3181 let text = new_text(c_str("a & b"));
3182 add_child(root, text);
3183
3184 let buf = io::buf_create(-1);
3185 assert!(!buf.is_null());
3186
3187 let ret = doc_dump(buf, doc);
3188 assert!(ret >= 0);
3189
3190 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>a & b</root>";
3191 assert!(buf_eq_str(buf, expected));
3192
3193 io::buf_free(buf);
3194 free_doc(doc);
3195 }
3196 }
3197
3198 #[test]
3199 fn test_serialize_escape_angle_brackets() {
3200 unsafe {
3201 let doc = new_doc(ptr::null());
3202 let root = new_node(ptr::null_mut(), c_str("root"));
3203 doc_set_root_element(doc, root);
3204
3205 let text = new_text(c_str("x < y > z"));
3206 add_child(root, text);
3207
3208 let buf = io::buf_create(-1);
3209 assert!(!buf.is_null());
3210
3211 let ret = doc_dump(buf, doc);
3212 assert!(ret >= 0);
3213
3214 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>x < y > z</root>";
3215 assert!(buf_eq_str(buf, expected));
3216
3217 io::buf_free(buf);
3218 free_doc(doc);
3219 }
3220 }
3221
3222 #[test]
3223 fn test_serialize_comment() {
3224 unsafe {
3225 let doc = new_doc(ptr::null());
3226 let root = new_node(ptr::null_mut(), c_str("root"));
3227 doc_set_root_element(doc, root);
3228
3229 let comment = new_comment(c_str("my comment"));
3230 add_child(root, comment);
3231
3232 let buf = io::buf_create(-1);
3233 assert!(!buf.is_null());
3234
3235 let ret = doc_dump(buf, doc);
3236 assert!(ret >= 0);
3237
3238 let expected =
3239 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root><!--my comment--></root>";
3240 assert!(buf_eq_str(buf, expected));
3241
3242 io::buf_free(buf);
3243 free_doc(doc);
3244 }
3245 }
3246
3247 #[test]
3248 fn test_serialize_pi() {
3249 unsafe {
3250 let doc = new_doc(ptr::null());
3251 let root = new_node(ptr::null_mut(), c_str("root"));
3252 doc_set_root_element(doc, root);
3253
3254 let pi = new_pi(
3255 c_str("xml-stylesheet"),
3256 c_str("href=\"style.xsl\" type=\"text/xsl\""),
3257 );
3258 add_child(root, pi);
3259
3260 let buf = io::buf_create(-1);
3261 assert!(!buf.is_null());
3262
3263 let ret = doc_dump(buf, doc);
3264 assert!(ret >= 0);
3265
3266 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root><?xml-stylesheet href=\"style.xsl\" type=\"text/xsl\"?></root>";
3267 assert!(buf_eq_str(buf, expected));
3268
3269 io::buf_free(buf);
3270 free_doc(doc);
3271 }
3272 }
3273
3274 #[test]
3275 fn test_serialize_self_closing() {
3276 unsafe {
3277 let doc = new_doc(ptr::null());
3278 let root = new_node(ptr::null_mut(), c_str("empty"));
3279 doc_set_root_element(doc, root);
3280
3281 let buf = io::buf_create(-1);
3282 assert!(!buf.is_null());
3283
3284 let ret = doc_dump(buf, doc);
3285 assert!(ret >= 0);
3286
3287 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><empty/>";
3288 assert!(buf_eq_str(buf, expected));
3289
3290 io::buf_free(buf);
3291 free_doc(doc);
3292 }
3293 }
3294
3295 #[test]
3296 fn test_dump_node_to_string() {
3297 unsafe {
3298 let node = new_node(ptr::null_mut(), c_str("foo"));
3299 let text = new_text(c_str("bar"));
3300 add_child(node, text);
3301
3302 let result = dump_node(node);
3303 assert!(!result.is_null());
3304
3305 let len = xml_strlen(result);
3306 let slice = unsafe { core::slice::from_raw_parts(result, len as usize) };
3307 assert_eq!(slice, b"<foo>bar</foo>");
3308
3309 allocator::xmlFree(result as *mut c_void);
3310 free_node(node);
3311 }
3312 }
3313
3314 #[test]
3315 fn test_dump_doc_to_string() {
3316 unsafe {
3317 let doc = new_doc(ptr::null());
3318 let root = new_node(ptr::null_mut(), c_str("root"));
3319 doc_set_root_element(doc, root);
3320
3321 let result = dump_doc(doc);
3322 assert!(!result.is_null());
3323
3324 let len = xml_strlen(result);
3325 let slice = unsafe { core::slice::from_raw_parts(result, len as usize) };
3326 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root/>";
3327 assert_eq!(slice, expected.as_bytes());
3328
3329 allocator::xmlFree(result as *mut c_void);
3330 free_doc(doc);
3331 }
3332 }
3333
3334 #[test]
3335 fn test_xmlDocDumpFormatMemory() {
3336 unsafe {
3337 let doc = new_doc(ptr::null());
3338 let root = new_node(ptr::null_mut(), c_str("root"));
3339 doc_set_root_element(doc, root);
3340
3341 let mut mem: *mut xmlChar = ptr::null_mut();
3342 let mut size: c_int = 0;
3343
3344 xmlDocDumpFormatMemory(doc, &mut mem, &mut size, 0);
3345
3346 assert!(!mem.is_null());
3347 assert!(size > 0);
3348
3349 let slice = unsafe { core::slice::from_raw_parts(mem, size as usize) };
3350 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root/>";
3351 assert_eq!(slice, expected.as_bytes());
3352
3353 allocator::xmlFree(mem as *mut c_void);
3354 free_doc(doc);
3355 }
3356 }
3357
3358 #[test]
3359 fn test_serialize_escape_attribute() {
3360 unsafe {
3361 let doc = new_doc(ptr::null());
3362 let root = new_node(ptr::null_mut(), c_str("root"));
3363 doc_set_root_element(doc, root);
3364
3365 set_prop(root, c_str("desc"), c_str("a < b & c \"quoted\""));
3367
3368 let buf = io::buf_create(-1);
3369 assert!(!buf.is_null());
3370
3371 let ret = doc_dump(buf, doc);
3372 assert!(ret >= 0);
3373
3374 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root desc=\"a < b & c "quoted"\"/>";
3375 assert!(buf_eq_str(buf, expected));
3376
3377 io::buf_free(buf);
3378 free_doc(doc);
3379 }
3380 }
3381}