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 new_child(
944 parent: *mut _xmlNode,
945 ns: *mut _xmlNs,
946 name: *const xmlChar,
947) -> *mut _xmlNode {
948 let node = new_node(ns, name);
949 if node.is_null() {
950 return ptr::null_mut();
951 }
952
953 if !parent.is_null() {
954 add_child(parent, node);
955 }
956
957 node
958}
959
960pub unsafe fn new_text(content: *const xmlChar) -> *mut _xmlNode {
979 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
980 if node.is_null() {
981 return ptr::null_mut();
982 }
983
984 unsafe {
985 (*node).type_ = XML_TEXT_NODE as c_int;
986 (*node).name = dup_xml_str(b"text\0" as *const u8 as *const xmlChar);
987 (*node).content = if content.is_null() {
988 let empty = allocator::xmlMalloc(1) as *mut xmlChar;
989 if !empty.is_null() {
990 *empty = 0;
991 }
992 empty
993 } else {
994 dup_xml_str(content)
995 };
996 (*node).line = 0;
997 }
998
999 node
1000}
1001
1002pub unsafe fn new_comment(content: *const xmlChar) -> *mut _xmlNode {
1016 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1017 if node.is_null() {
1018 return ptr::null_mut();
1019 }
1020
1021 unsafe {
1022 (*node).type_ = XML_COMMENT_NODE as c_int;
1023 (*node).name = dup_xml_str(b"comment\0" as *const u8 as *const xmlChar);
1024 (*node).content = dup_xml_str(content);
1025 (*node).line = 0;
1026 }
1027
1028 node
1029}
1030
1031pub unsafe fn new_pi(name: *const xmlChar, content: *const xmlChar) -> *mut _xmlNode {
1046 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1047 if node.is_null() {
1048 return ptr::null_mut();
1049 }
1050
1051 unsafe {
1052 (*node).type_ = XML_PI_NODE as c_int;
1053 (*node).name = dup_xml_str(name);
1054 (*node).content = dup_xml_str(content);
1055 (*node).line = 0;
1056 }
1057
1058 node
1059}
1060
1061pub unsafe fn new_cdata_block(
1077 doc: *mut _xmlDoc,
1078 content: *const xmlChar,
1079 len: c_int,
1080) -> *mut _xmlNode {
1081 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1082 if node.is_null() {
1083 return ptr::null_mut();
1084 }
1085
1086 unsafe {
1087 (*node).type_ = XML_CDATA_SECTION_NODE as c_int;
1088 (*node).name = dup_xml_str(b"cdata\0" as *const u8 as *const xmlChar);
1089 (*node).doc = doc;
1090
1091 if !content.is_null() && len > 0 {
1092 (*node).content = allocator::xmlMalloc((len + 1) as usize) as *mut xmlChar;
1093 if !(*node).content.is_null() {
1094 ptr::copy_nonoverlapping(content, (*node).content, len as usize);
1095 *((*node).content.add(len as usize)) = 0;
1096 }
1097 } else {
1098 let empty = allocator::xmlMalloc(1) as *mut xmlChar;
1099 if !empty.is_null() {
1100 *empty = 0;
1101 }
1102 (*node).content = empty;
1103 }
1104
1105 (*node).line = 0;
1106 }
1107
1108 node
1109}
1110
1111pub unsafe fn new_ns(
1135 node: *mut _xmlNode,
1136 href: *const xmlChar,
1137 prefix: *const xmlChar,
1138) -> *mut _xmlNs {
1139 let ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
1140 if ns.is_null() {
1141 return ptr::null_mut();
1142 }
1143
1144 unsafe {
1145 (*ns).type_ = XML_LOCAL_NAMESPACE as c_int;
1146 (*ns).href = dup_xml_str(href);
1147 (*ns).prefix = dup_xml_str(prefix);
1148 (*ns).context = node as *mut _xmlDoc;
1149
1150 if !node.is_null() {
1152 let n = &mut *node;
1153 if n.nsDef.is_null() {
1154 n.nsDef = ns;
1155 } else {
1156 let mut last = n.nsDef;
1158 while !(*last).next.is_null() {
1159 last = (*last).next;
1160 }
1161 (*last).next = ns;
1162 }
1163 }
1164 }
1165
1166 ns
1167}
1168
1169pub unsafe fn set_ns(node: *mut _xmlNode, ns: *mut _xmlNs) {
1182 if node.is_null() {
1183 return;
1184 }
1185 unsafe {
1186 (*node).ns = ns;
1187 }
1188}
1189
1190pub unsafe fn get_ns_list(doc: *mut _xmlDoc, node: *mut _xmlNode) -> *mut *mut _xmlNs {
1206 if node.is_null() {
1210 return ptr::null_mut();
1211 }
1212
1213 let mut ns_ptrs: Vec<*mut _xmlNs> = Vec::new();
1215 let mut cur = node;
1216
1217 while !cur.is_null() {
1218 let n = unsafe { &*cur };
1219 let mut ns_def = n.nsDef;
1220 while !ns_def.is_null() {
1221 let ns = unsafe { &*ns_def };
1223 let mut found = false;
1224 for &existing in &ns_ptrs {
1225 if existing == ns_def {
1226 found = true;
1227 break;
1228 }
1229 let e = unsafe { &*existing };
1230 if !ns.href.is_null() && !e.href.is_null() {
1231 let href_match =
1232 unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, e.href) != 0 };
1233 if href_match {
1234 if ns.prefix.is_null() && e.prefix.is_null() {
1235 found = true;
1236 break;
1237 }
1238 if !ns.prefix.is_null() && !e.prefix.is_null() {
1239 let prefix_match = unsafe {
1240 crate::abi::exports_xml2::xmlStrEqual(ns.prefix, e.prefix) != 0
1241 };
1242 if prefix_match {
1243 found = true;
1244 break;
1245 }
1246 }
1247 }
1248 }
1249 }
1250 if !found {
1251 ns_ptrs.push(ns_def);
1252 }
1253 ns_def = unsafe { (*ns_def).next };
1254 }
1255 cur = n.parent;
1256 }
1257
1258 if ns_ptrs.is_empty() {
1259 return ptr::null_mut();
1260 }
1261
1262 let arr =
1264 allocator::xmlMalloc((ns_ptrs.len() + 1) * size_of::<*mut _xmlNs>()) as *mut *mut _xmlNs;
1265 if arr.is_null() {
1266 return ptr::null_mut();
1267 }
1268
1269 for (i, ns) in ns_ptrs.iter().enumerate() {
1270 unsafe { *arr.add(i) = *ns };
1271 }
1272 unsafe { *arr.add(ns_ptrs.len()) = ptr::null_mut() };
1273
1274 arr
1275}
1276
1277pub unsafe fn search_ns(
1294 doc: *mut _xmlDoc,
1295 node: *mut _xmlNode,
1296 name_space: *const xmlChar,
1297) -> *mut _xmlNs {
1298 if node.is_null() {
1299 return ptr::null_mut();
1300 }
1301
1302 let mut cur = node;
1303 while !cur.is_null() {
1304 let n = unsafe { &*cur };
1305 let mut ns_def = n.nsDef;
1306 while !ns_def.is_null() {
1307 let ns = unsafe { &*ns_def };
1308 let match_prefix = if name_space.is_null() {
1309 ns.prefix.is_null()
1311 } else {
1312 !ns.prefix.is_null()
1313 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.prefix, name_space) != 0 }
1314 };
1315 if match_prefix {
1316 return ns_def;
1317 }
1318 ns_def = unsafe { (*ns_def).next };
1319 }
1320 cur = n.parent;
1321 }
1322
1323 ptr::null_mut()
1324}
1325
1326pub unsafe fn search_ns_by_href(
1342 doc: *mut _xmlDoc,
1343 node: *mut _xmlNode,
1344 href: *const xmlChar,
1345) -> *mut _xmlNs {
1346 if node.is_null() || href.is_null() {
1347 return ptr::null_mut();
1348 }
1349
1350 let mut cur = node;
1351 while !cur.is_null() {
1352 let n = unsafe { &*cur };
1353 let mut ns_def = n.nsDef;
1354 while !ns_def.is_null() {
1355 let ns = unsafe { &*ns_def };
1356 if !ns.href.is_null()
1357 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, href) != 0 }
1358 {
1359 return ns_def;
1360 }
1361 ns_def = unsafe { (*ns_def).next };
1362 }
1363 cur = n.parent;
1364 }
1365
1366 ptr::null_mut()
1367}
1368
1369pub unsafe fn set_prop(
1393 node: *mut _xmlNode,
1394 name: *const xmlChar,
1395 value: *const xmlChar,
1396) -> *mut _xmlAttr {
1397 if node.is_null() || name.is_null() {
1398 return ptr::null_mut();
1399 }
1400
1401 let n = unsafe { &mut *node };
1402
1403 let mut existing = n.properties;
1405 while !existing.is_null() {
1406 let attr = unsafe { &*existing };
1407 if !attr.name.is_null()
1408 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1409 {
1410 if !attr.children.is_null() {
1413 free_node_list(attr.children);
1414 let attr_mut = existing as *mut _xmlAttr;
1416 unsafe { (*attr_mut).children = ptr::null_mut() };
1417 unsafe { (*attr_mut).last = ptr::null_mut() };
1418 }
1419 if !value.is_null() {
1421 let text = new_text(value);
1422 if !text.is_null() {
1423 let attr_mut = existing as *mut _xmlAttr;
1424 unsafe {
1425 (*attr_mut).children = text;
1426 (*attr_mut).last = text;
1427 (*text).parent = existing as *mut _xmlNode;
1428 (*text).doc = n.doc;
1429 }
1430 }
1431 }
1432 return existing;
1433 }
1434 existing = unsafe { (*existing).next };
1435 }
1436
1437 let attr = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
1439 if attr.is_null() {
1440 return ptr::null_mut();
1441 }
1442
1443 unsafe {
1444 (*attr).type_ = XML_ATTRIBUTE_NODE as c_int;
1445 (*attr).name = dup_xml_str(name);
1446 (*attr).parent = node;
1447 (*attr).doc = n.doc;
1448 (*attr).atype = XML_ATTRIBUTE_CDATA as c_int;
1449
1450 if !value.is_null() {
1452 let text = new_text(value);
1453 if !text.is_null() {
1454 (*attr).children = text;
1455 (*attr).last = text;
1456 (*text).parent = attr as *mut _xmlNode;
1457 (*text).doc = n.doc;
1458 }
1459 }
1460
1461 if n.properties.is_null() {
1463 n.properties = attr;
1464 } else {
1465 let mut last = n.properties;
1466 while !(*last).next.is_null() {
1467 last = (*last).next;
1468 }
1469 (*last).next = attr;
1470 (*attr).prev = last;
1471 }
1472 }
1473
1474 attr
1475}
1476
1477pub unsafe fn get_prop(node: *mut _xmlNode, name: *const xmlChar) -> *mut xmlChar {
1493 if node.is_null() || name.is_null() {
1494 return ptr::null_mut();
1495 }
1496
1497 let n = unsafe { &*node };
1498 let mut cur = n.properties;
1499
1500 while !cur.is_null() {
1501 let attr = unsafe { &*cur };
1502 if !attr.name.is_null()
1503 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1504 {
1505 if !attr.children.is_null() {
1507 let text = unsafe { &*attr.children };
1508 if text.type_ == XML_TEXT_NODE as c_int && !text.content.is_null() {
1509 return dup_xml_str(text.content);
1510 }
1511 }
1512 return dup_xml_str(b"\0" as *const u8 as *const xmlChar);
1513 }
1514 cur = unsafe { (*cur).next };
1515 }
1516
1517 ptr::null_mut()
1518}
1519
1520pub unsafe fn get_ns_prop(
1536 node: *mut _xmlNode,
1537 name: *const xmlChar,
1538 _name_space: *const xmlChar,
1539) -> *mut xmlChar {
1540 get_prop(node, name)
1543}
1544
1545pub unsafe fn set_ns_prop(
1560 node: *mut _xmlNode,
1561 _ns: *mut _xmlNs,
1562 name: *const xmlChar,
1563 value: *const xmlChar,
1564) -> *mut _xmlAttr {
1565 set_prop(node, name, value)
1567}
1568
1569pub unsafe fn remove_prop(attr: *mut _xmlAttr) -> c_int {
1584 if attr.is_null() {
1585 return -1;
1586 }
1587
1588 let a = unsafe { &mut *attr };
1589
1590 let parent = a.parent;
1592 if !parent.is_null() {
1593 let p = unsafe { &mut *parent };
1594 if p.properties == attr {
1595 p.properties = a.next;
1596 }
1597 }
1598
1599 if !a.prev.is_null() {
1601 unsafe { (*a.prev).next = a.next };
1602 }
1603 if !a.next.is_null() {
1604 unsafe { (*a.next).prev = a.prev };
1605 }
1606
1607 if !a.children.is_null() {
1609 free_node_list(a.children);
1610 }
1611
1612 if !a.name.is_null() {
1614 allocator::xmlFree(a.name as *mut c_void);
1615 }
1616
1617 allocator::xmlFree(attr as *mut c_void);
1618 0
1619}
1620
1621pub fn get_int_subset(doc: *const _xmlDoc) -> *mut _xmlDtd {
1633 if doc.is_null() {
1634 return ptr::null_mut();
1635 }
1636 let d = unsafe { &*doc };
1637 d.intSubset
1638}
1639
1640pub unsafe fn new_dtd(
1657 doc: *mut _xmlDoc,
1658 name: *const xmlChar,
1659 ExternalID: *const xmlChar,
1660 SystemID: *const xmlChar,
1661) -> *mut _xmlDtd {
1662 let dtd = allocator::xmlMallocZero(size_of::<_xmlDtd>() as usize) as *mut _xmlDtd;
1663 if dtd.is_null() {
1664 return ptr::null_mut();
1665 }
1666
1667 unsafe {
1668 (*dtd).type_ = XML_DTD_NODE as c_int;
1669 (*dtd).name = dup_xml_str(name);
1670 (*dtd).ExternalID = dup_xml_str(ExternalID);
1671 (*dtd).SystemID = dup_xml_str(SystemID);
1672 (*dtd).parent = doc;
1673 (*dtd).doc = doc;
1674
1675 if !doc.is_null() {
1677 if (*doc).intSubset.is_null() {
1678 (*doc).intSubset = dtd;
1679 }
1680 }
1681 }
1682
1683 dtd
1684}
1685
1686unsafe fn free_dtd(dtd: *mut _xmlDtd) {
1692 if dtd.is_null() {
1693 return;
1694 }
1695
1696 let d = unsafe { &mut *dtd };
1697
1698 if !d.name.is_null() {
1700 allocator::xmlFree(d.name as *mut c_void);
1701 }
1702 if !d.ExternalID.is_null() {
1703 allocator::xmlFree(d.ExternalID as *mut c_void);
1704 }
1705 if !d.SystemID.is_null() {
1706 allocator::xmlFree(d.SystemID as *mut c_void);
1707 }
1708
1709 if !d.children.is_null() {
1711 free_node_list(d.children);
1712 }
1713
1714 allocator::xmlFree(dtd as *mut c_void);
1715}
1716
1717pub unsafe fn new_entity(
1737 _doc: *mut _xmlDoc,
1738 name: *const xmlChar,
1739 etype: c_int,
1740 ExternalID: *const xmlChar,
1741 SystemID: *const xmlChar,
1742 content: *const xmlChar,
1743) -> *mut _xmlEntity {
1744 let entity = allocator::xmlMallocZero(size_of::<_xmlEntity>() as usize) as *mut _xmlEntity;
1745 if entity.is_null() {
1746 return ptr::null_mut();
1747 }
1748
1749 unsafe {
1750 (*entity).type_ = XML_ENTITY_DECL as c_int;
1751 (*entity).name = dup_xml_str(name);
1752 (*entity).etype = etype;
1753 (*entity).ExternalID = dup_xml_str(ExternalID);
1754 (*entity).SystemID = dup_xml_str(SystemID);
1755 (*entity).content = dup_xml_str(content);
1756 (*entity).length = if content.is_null() {
1757 0
1758 } else {
1759 crate::abi::exports_xml2::xmlStrlen(content)
1760 };
1761 (*entity).flags = 0;
1762 (*entity).expandedSize = 0;
1763 }
1764
1765 entity
1766}
1767
1768pub unsafe fn get_doc_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
1783 let _ = doc;
1786 let _ = name;
1787 ptr::null_mut()
1788}
1789
1790pub unsafe fn get_parameter_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
1803 let _ = doc;
1805 let _ = name;
1806 ptr::null_mut()
1807}
1808
1809const ENTITY_LT: &[xmlChar] = b"<";
1818const ENTITY_GT: &[xmlChar] = b">";
1819const ENTITY_AMP: &[xmlChar] = b"&";
1820const ENTITY_QUOT: &[xmlChar] = b""";
1821const ENTITY_APOS: &[xmlChar] = b"'";
1822
1823const INDENT: &[xmlChar] = b" ";
1825
1826const XML_DECL: &[xmlChar] = b"<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1828
1829unsafe fn serialize_text(buf: *mut _xmlBuffer, content: *const xmlChar, len: c_int) {
1838 if buf.is_null() || content.is_null() || len <= 0 {
1839 return;
1840 }
1841
1842 let mut i: c_int = 0;
1843 while i < len {
1844 let ch = unsafe { *content.add(i as usize) };
1845
1846 if ch == b']'
1848 && i + 2 < len
1849 && unsafe { *content.add(i as usize + 1) == b']' }
1850 && unsafe { *content.add(i as usize + 2) == b'>' }
1851 {
1852 io::buf_add(buf, &ch as *const u8, 2); io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
1855 i += 3;
1856 continue;
1857 }
1858
1859 match ch {
1860 b'<' => {
1861 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
1862 }
1863 b'&' => {
1864 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
1865 }
1866 _ => {
1867 io::buf_add(buf, &ch as *const u8, 1);
1868 }
1869 }
1870 i += 1;
1871 }
1872}
1873
1874unsafe fn serialize_attr_value(buf: *mut _xmlBuffer, value: *const xmlChar) {
1883 if buf.is_null() || value.is_null() {
1884 return;
1885 }
1886
1887 let len = xml_strlen(value);
1888 let mut i: c_int = 0;
1889 while i < len {
1890 let ch = unsafe { *value.add(i as usize) };
1891
1892 if ch == b']'
1894 && i + 2 < len
1895 && unsafe { *value.add(i as usize + 1) == b']' }
1896 && unsafe { *value.add(i as usize + 2) == b'>' }
1897 {
1898 io::buf_add(buf, &ch as *const u8, 2); io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
1901 i += 3;
1902 continue;
1903 }
1904
1905 match ch {
1906 b'<' => {
1907 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
1908 }
1909 b'&' => {
1910 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
1911 }
1912 b'"' => {
1913 io::buf_add(buf, ENTITY_QUOT.as_ptr(), ENTITY_QUOT.len() as c_int);
1914 }
1915 _ => {
1916 io::buf_add(buf, &ch as *const u8, 1);
1917 }
1918 }
1919 i += 1;
1920 }
1921}
1922
1923unsafe fn write_indent(buf: *mut _xmlBuffer, level: c_int) {
1929 if buf.is_null() || level <= 0 {
1930 return;
1931 }
1932 for _ in 0..level {
1933 io::buf_add(buf, INDENT.as_ptr(), INDENT.len() as c_int);
1934 }
1935}
1936
1937unsafe fn serialize_start_tag(
1946 node: *mut _xmlNode,
1947 buf: *mut _xmlBuffer,
1948 format: c_int,
1949 level: c_int,
1950) {
1951 if node.is_null() || buf.is_null() {
1952 return;
1953 }
1954
1955 let n = unsafe { &*node };
1956
1957 io::buf_ccat(buf, b'<');
1959
1960 if !n.ns.is_null() {
1962 let ns = unsafe { &*n.ns };
1963 if !ns.prefix.is_null() {
1964 io::buf_cat(buf, ns.prefix);
1965 io::buf_ccat(buf, b':');
1966 }
1967 }
1968 if !n.name.is_null() {
1969 io::buf_cat(buf, n.name);
1970 }
1971
1972 let mut attr = n.properties;
1974 while !attr.is_null() {
1975 let a = unsafe { &*attr };
1976 io::buf_ccat(buf, b' ');
1977
1978 if !a.ns.is_null() {
1980 let ans = unsafe { &*a.ns };
1981 if !ans.prefix.is_null() {
1982 io::buf_cat(buf, ans.prefix);
1983 io::buf_ccat(buf, b':');
1984 }
1985 }
1986 if !a.name.is_null() {
1987 io::buf_cat(buf, a.name);
1988 }
1989
1990 io::buf_add(buf, b"=\"" as *const u8, 2);
1991
1992 if !a.children.is_null() {
1994 let child = unsafe { &*a.children };
1995 if child.type_ == XML_TEXT_NODE as c_int && !child.content.is_null() {
1996 serialize_attr_value(buf, child.content);
1997 }
1998 }
1999
2000 io::buf_ccat(buf, b'"');
2001
2002 attr = a.next;
2003 }
2004
2005 let mut ns_def = n.nsDef;
2007 while !ns_def.is_null() {
2008 let nd = unsafe { &*ns_def };
2009 io::buf_add(buf, b" xmlns" as *const u8, 6);
2010 if !nd.prefix.is_null() {
2011 io::buf_ccat(buf, b':');
2012 io::buf_cat(buf, nd.prefix);
2013 }
2014 io::buf_add(buf, b"=\"" as *const u8, 2);
2015 if !nd.href.is_null() {
2016 serialize_attr_value(buf, nd.href);
2017 }
2018 io::buf_ccat(buf, b'"');
2019 ns_def = nd.next;
2020 }
2021
2022 if n.children.is_null() {
2023 io::buf_add(buf, b"/>" as *const u8, 2);
2025 } else {
2026 io::buf_ccat(buf, b'>');
2027 }
2028}
2029
2030unsafe fn serialize_end_tag(node: *mut _xmlNode, buf: *mut _xmlBuffer) {
2037 if node.is_null() || buf.is_null() {
2038 return;
2039 }
2040
2041 let n = unsafe { &*node };
2042
2043 io::buf_add(buf, b"</" as *const u8, 2);
2044 if !n.ns.is_null() {
2045 let ns = unsafe { &*n.ns };
2046 if !ns.prefix.is_null() {
2047 io::buf_cat(buf, ns.prefix);
2048 io::buf_ccat(buf, b':');
2049 }
2050 }
2051 if !n.name.is_null() {
2052 io::buf_cat(buf, n.name);
2053 }
2054 io::buf_ccat(buf, b'>');
2055}
2056
2057unsafe fn is_text_only_element(node: *mut _xmlNode) -> bool {
2059 if node.is_null() {
2060 return false;
2061 }
2062 let n = unsafe { &*node };
2063 if n.children.is_null() {
2064 return false;
2065 }
2066 if n.children != n.last {
2068 return false;
2069 }
2070 let child = unsafe { &*n.children };
2071 child.type_ == XML_TEXT_NODE as c_int
2072}
2073
2074pub(crate) unsafe fn serialize_node(
2083 node: *mut _xmlNode,
2084 buf: *mut _xmlBuffer,
2085 format: c_int,
2086 level: c_int,
2087) {
2088 if node.is_null() || buf.is_null() {
2089 return;
2090 }
2091
2092 let n = unsafe { &*node };
2093
2094 match n.type_ {
2095 t if t == XML_ELEMENT_NODE as c_int => {
2096 let is_text_only = is_text_only_element(node);
2097
2098 if format != 0 && level > 0 {
2100 io::buf_ccat(buf, b'\n');
2101 write_indent(buf, level);
2102 }
2103
2104 serialize_start_tag(node, buf, format, level);
2105
2106 if !n.children.is_null() {
2107 if !is_text_only && format != 0 {
2108 let mut child = n.children;
2110 while !child.is_null() {
2111 serialize_node(child, buf, format, level + 1);
2112 child = unsafe { (*child).next };
2113 }
2114 io::buf_ccat(buf, b'\n');
2115 write_indent(buf, level);
2116 } else {
2117 let mut child = n.children;
2119 while !child.is_null() {
2120 serialize_node(child, buf, format, level + 1);
2121 child = unsafe { (*child).next };
2122 }
2123 }
2124 serialize_end_tag(node, buf);
2125 }
2126 }
2127 t if t == XML_TEXT_NODE as c_int => {
2128 serialize_text(buf, n.content, xml_strlen(n.content));
2129 }
2130 t if t == XML_CDATA_SECTION_NODE as c_int => {
2131 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
2132 serialize_text(buf, n.content, xml_strlen(n.content));
2133 io::buf_add(buf, b"]]>" as *const u8, 3);
2134 }
2135 t if t == XML_COMMENT_NODE as c_int => {
2136 if format != 0 && level > 0 {
2137 io::buf_ccat(buf, b'\n');
2138 write_indent(buf, level);
2139 }
2140 io::buf_add(buf, b"<!--" as *const u8, 4);
2141 if !n.content.is_null() {
2142 io::buf_cat(buf, n.content);
2143 }
2144 io::buf_add(buf, b"-->" as *const u8, 3);
2145 }
2146 t if t == XML_PI_NODE as c_int => {
2147 if format != 0 && level > 0 {
2148 io::buf_ccat(buf, b'\n');
2149 write_indent(buf, level);
2150 }
2151 io::buf_add(buf, b"<?" as *const u8, 2);
2152 if !n.name.is_null() {
2153 io::buf_cat(buf, n.name);
2154 }
2155 if !n.content.is_null() && unsafe { *n.content != 0 } {
2156 io::buf_ccat(buf, b' ');
2157 io::buf_cat(buf, n.content);
2158 }
2159 io::buf_add(buf, b"?>" as *const u8, 2);
2160 }
2161 t if t == XML_DOCUMENT_NODE as c_int || t == XML_HTML_DOCUMENT_NODE as c_int => {
2162 io::buf_add(buf, XML_DECL.as_ptr(), XML_DECL.len() as c_int);
2164
2165 if format != 0 {
2167 io::buf_ccat(buf, b'\n');
2168 }
2169
2170 let mut child = n.children;
2172 while !child.is_null() {
2173 serialize_node(child, buf, format, 0);
2174 child = unsafe { (*child).next };
2175 }
2176 if format != 0 {
2177 io::buf_ccat(buf, b'\n');
2178 }
2179 }
2180 t if t == XML_DTD_NODE as c_int => {
2181 }
2183 _ => {
2184 if !n.content.is_null() {
2186 serialize_text(buf, n.content, xml_strlen(n.content));
2187 }
2188 }
2189 }
2190}
2191
2192pub(crate) unsafe fn doc_dump(buf: *mut _xmlBuffer, doc: *mut _xmlDoc) -> c_int {
2202 if buf.is_null() || doc.is_null() {
2203 return -1;
2204 }
2205
2206 let before = io::buf_length(buf);
2207 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
2208 let after = io::buf_length(buf);
2209
2210 if after < 0 || before < 0 {
2211 return -1;
2212 }
2213 after - before
2214}
2215
2216pub(crate) unsafe fn node_dump(
2228 buf: *mut _xmlBuffer,
2229 doc: *mut _xmlDoc,
2230 node: *mut _xmlNode,
2231 level: c_int,
2232 format: c_int,
2233) -> c_int {
2234 let _ = doc; if buf.is_null() || node.is_null() {
2236 return -1;
2237 }
2238
2239 let before = io::buf_length(buf);
2240 serialize_node(node, buf, format, level);
2241 let after = io::buf_length(buf);
2242
2243 if after < 0 || before < 0 {
2244 return -1;
2245 }
2246 after - before
2247}
2248
2249pub(crate) unsafe fn save_doc_to_filename(
2256 doc: *mut _xmlDoc,
2257 filename: *const c_char,
2258 compression: c_int,
2259) -> c_int {
2260 if doc.is_null() || filename.is_null() {
2261 return -1;
2262 }
2263
2264 let out = io::output_buffer_create_filename(filename, ptr::null_mut(), compression);
2265 if out.is_null() {
2266 return -1;
2267 }
2268
2269 let buf = io::buf_create(-1);
2270 if buf.is_null() {
2271 io::output_buffer_close(out);
2272 return -1;
2273 }
2274
2275 let ret = doc_dump(buf, doc);
2276 if ret >= 0 {
2277 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
2279 io::output_buffer_flush(out);
2280 }
2281
2282 io::buf_free(buf);
2283 io::output_buffer_close(out);
2284 ret
2285}
2286
2287pub(crate) unsafe fn save_doc_to_fd(doc: *mut _xmlDoc, fd: c_int, compression: c_int) -> c_int {
2294 if doc.is_null() || fd < 0 {
2295 return -1;
2296 }
2297
2298 let out = io::output_buffer_create_fd(fd, ptr::null_mut());
2299 if out.is_null() {
2300 return -1;
2301 }
2302
2303 let buf = io::buf_create(-1);
2304 if buf.is_null() {
2305 io::output_buffer_close(out);
2306 return -1;
2307 }
2308
2309 let ret = doc_dump(buf, doc);
2310 if ret >= 0 {
2311 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
2312 io::output_buffer_flush(out);
2313 }
2314
2315 io::buf_free(buf);
2316 io::output_buffer_close(out);
2317 ret
2318}
2319
2320pub(crate) unsafe fn save_doc_to_buf(
2327 doc: *mut _xmlDoc,
2328 buf: *mut _xmlBuffer,
2329 compression: c_int,
2330) -> c_int {
2331 let _ = compression;
2332 if doc.is_null() || buf.is_null() {
2333 return -1;
2334 }
2335
2336 doc_dump(buf, doc)
2337}
2338
2339pub(crate) unsafe fn save_format_doc_to_buf(
2346 doc: *mut _xmlDoc,
2347 buf: *mut _xmlBuffer,
2348 compression: c_int,
2349) -> c_int {
2350 let _ = compression;
2351 if doc.is_null() || buf.is_null() {
2352 return -1;
2353 }
2354
2355 let before = io::buf_length(buf);
2356 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
2357 let after = io::buf_length(buf);
2358
2359 if after < 0 || before < 0 {
2360 return -1;
2361 }
2362 after - before
2363}
2364
2365pub(crate) unsafe fn dump_node(node: *mut _xmlNode) -> *mut xmlChar {
2374 if node.is_null() {
2375 return ptr::null_mut();
2376 }
2377
2378 let buf = io::buf_create(-1);
2379 if buf.is_null() {
2380 return ptr::null_mut();
2381 }
2382
2383 serialize_node(node, buf, 0, 0);
2384
2385 let content = io::buf_content(buf);
2386 if content.is_null() {
2387 io::buf_free(buf);
2388 return ptr::null_mut();
2389 }
2390
2391 let result = dup_xml_str(content);
2393 io::buf_free(buf);
2394 result
2395}
2396
2397pub(crate) unsafe fn dump_doc(doc: *mut _xmlDoc) -> *mut xmlChar {
2406 if doc.is_null() {
2407 return ptr::null_mut();
2408 }
2409
2410 let buf = io::buf_create(-1);
2411 if buf.is_null() {
2412 return ptr::null_mut();
2413 }
2414
2415 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
2416
2417 let content = io::buf_content(buf);
2418 if content.is_null() {
2419 io::buf_free(buf);
2420 return ptr::null_mut();
2421 }
2422
2423 let result = dup_xml_str(content);
2424 io::buf_free(buf);
2425 result
2426}
2427
2428pub(crate) unsafe fn xmlNodeDump(
2444 buf: *mut _xmlBuffer,
2445 doc: *mut _xmlDoc,
2446 node: *mut _xmlNode,
2447 level: c_int,
2448 format: c_int,
2449) -> c_int {
2450 node_dump(buf, doc, node, level, format)
2451}
2452
2453pub(crate) unsafe fn xmlDocDump(fp: *mut c_void, doc: *mut _xmlDoc) -> c_int {
2466 if fp.is_null() || doc.is_null() {
2467 return -1;
2468 }
2469
2470 let buf = io::buf_create(-1);
2471 if buf.is_null() {
2472 return -1;
2473 }
2474
2475 let ret = doc_dump(buf, doc);
2476 if ret < 0 {
2477 io::buf_free(buf);
2478 return -1;
2479 }
2480
2481 let content = io::buf_content(buf);
2482 let len = io::buf_length(buf);
2483 if !content.is_null() && len > 0 {
2484 let written = libc::fwrite(
2485 content as *const c_void,
2486 1,
2487 len as usize,
2488 fp as *mut libc::FILE,
2489 );
2490 io::buf_free(buf);
2491 written as c_int
2492 } else {
2493 io::buf_free(buf);
2494 0
2495 }
2496}
2497
2498pub(crate) unsafe fn xmlDocDumpFormatMemory(
2512 doc: *mut _xmlDoc,
2513 mem: *mut *mut xmlChar,
2514 size: *mut c_int,
2515 format: c_int,
2516) {
2517 if doc.is_null() || mem.is_null() || size.is_null() {
2518 return;
2519 }
2520
2521 let buf = io::buf_create(-1);
2522 if buf.is_null() {
2523 unsafe {
2524 *mem = ptr::null_mut();
2525 *size = 0;
2526 }
2527 return;
2528 }
2529
2530 serialize_node(doc as *mut _xmlNode, buf, format, 0);
2531
2532 let content = io::buf_content(buf);
2533 let len = io::buf_length(buf);
2534
2535 if !content.is_null() && len > 0 {
2536 let result = allocator::xmlMalloc((len + 1) as usize) as *mut xmlChar;
2538 if !result.is_null() {
2539 ptr::copy_nonoverlapping(content, result, len as usize);
2540 *result.add(len as usize) = 0;
2541 unsafe {
2542 *mem = result;
2543 *size = len;
2544 }
2545 } else {
2546 unsafe {
2547 *mem = ptr::null_mut();
2548 *size = 0;
2549 }
2550 }
2551 } else {
2552 unsafe {
2553 *mem = ptr::null_mut();
2554 *size = 0;
2555 }
2556 }
2557
2558 io::buf_free(buf);
2559}
2560
2561pub(crate) unsafe fn xmlDocDumpMemory(doc: *mut _xmlDoc, mem: *mut *mut xmlChar, size: *mut c_int) {
2575 xmlDocDumpFormatMemory(doc, mem, size, 0)
2576}
2577
2578pub(crate) unsafe fn xmlSaveFile(filename: *const c_char, cur: *mut _xmlDoc) -> c_int {
2591 save_doc_to_filename(cur, filename, 0)
2592}
2593
2594pub(crate) unsafe fn xmlSaveFileEnc(
2608 filename: *const c_char,
2609 cur: *mut _xmlDoc,
2610 encoding: *const c_char,
2611) -> c_int {
2612 let _ = encoding; save_doc_to_filename(cur, filename, 0)
2614}
2615
2616pub(crate) unsafe fn xmlSaveFormatFile(
2629 filename: *const c_char,
2630 cur: *mut _xmlDoc,
2631 format: c_int,
2632) -> c_int {
2633 let _ = format;
2634 save_doc_to_filename(cur, filename, 0)
2635}
2636
2637pub(crate) unsafe fn xmlSaveFormatFileEnc(
2651 filename: *const c_char,
2652 cur: *mut _xmlDoc,
2653 encoding: *const c_char,
2654 format: c_int,
2655) -> c_int {
2656 let _ = encoding;
2657 let _ = format;
2658 save_doc_to_filename(cur, filename, 0)
2659}
2660
2661pub(crate) unsafe fn xmlGetDocCompressMode(doc: *mut _xmlDoc) -> c_int {
2673 if doc.is_null() {
2674 return -1;
2675 }
2676 unsafe { (*doc).compression }
2677}
2678
2679pub(crate) unsafe fn xmlSetDocCompressMode(doc: *mut _xmlDoc, mode: c_int) {
2691 if doc.is_null() {
2692 return;
2693 }
2694 unsafe {
2695 (*doc).compression = mode;
2696 }
2697}
2698
2699#[cfg(test)]
2700mod tests {
2701 use super::*;
2702 use core::ffi::c_void;
2703
2704 fn c_str(s: &str) -> *const xmlChar {
2705 let bytes = s.as_bytes();
2706 let buf = unsafe { allocator::xmlMalloc(bytes.len() + 1) as *mut u8 };
2707 if !buf.is_null() {
2708 unsafe {
2709 ptr::copy_nonoverlapping(bytes.as_ptr(), buf, bytes.len());
2710 *buf.add(bytes.len()) = 0;
2711 }
2712 }
2713 buf as *const xmlChar
2714 }
2715
2716 #[test]
2717 fn test_new_free_doc() {
2718 unsafe {
2719 let doc = new_doc(ptr::null());
2720 assert!(!doc.is_null());
2721 assert_eq!((*doc).type_, XML_DOCUMENT_NODE as c_int);
2722 assert_eq!((*doc).standalone, -1);
2723 assert_eq!((*doc).doc, doc);
2724 assert!(!(*doc).version.is_null());
2725 free_doc(doc);
2726 }
2727 }
2728
2729 #[test]
2730 fn test_new_doc_with_version() {
2731 unsafe {
2732 let ver = c_str("2.0");
2733 let doc = new_doc(ver);
2734 assert!(!doc.is_null());
2735 let doc_ver = (*doc).version;
2736 assert!(!doc_ver.is_null());
2737 assert!(crate::abi::exports_xml2::xmlStrEqual(doc_ver, ver,) != 0);
2738 allocator::xmlFree(ver as *mut c_void);
2739 free_doc(doc);
2740 }
2741 }
2742
2743 #[test]
2744 fn test_new_node() {
2745 unsafe {
2746 let doc = new_doc(ptr::null());
2747 let node = new_node(ptr::null_mut(), c_str("root"));
2748 assert!(!node.is_null());
2749 assert_eq!((*node).type_, XML_ELEMENT_NODE as c_int);
2750 assert!(!(*node).name.is_null());
2751 free_node(node);
2752 free_doc(doc);
2753 }
2754 }
2755
2756 #[test]
2757 fn test_doc_set_root_element() {
2758 unsafe {
2759 let doc = new_doc(ptr::null());
2760 let root = new_node(ptr::null_mut(), c_str("root"));
2761 let old = doc_set_root_element(doc, root);
2762 assert!(old.is_null());
2763 assert_eq!(doc_get_root_element(doc), root);
2764 assert_eq!((*doc).children, root as *mut _xmlNode);
2765 free_doc(doc);
2766 }
2767 }
2768
2769 #[test]
2770 fn test_add_child_and_sibling() {
2771 unsafe {
2772 let doc = new_doc(ptr::null());
2773 let root = new_node(ptr::null_mut(), c_str("root"));
2774 doc_set_root_element(doc, root);
2775
2776 let child1 = new_child(root, ptr::null_mut(), c_str("child1"));
2777 assert!(!child1.is_null());
2778 assert_eq!((*child1).parent, root);
2779 assert_eq!((*root).children, child1);
2780 assert_eq!((*root).last, child1);
2781
2782 let child2 = new_child(root, ptr::null_mut(), c_str("child2"));
2783 assert!(!child2.is_null());
2784 assert_eq!((*child2).parent, root);
2785 assert_eq!((*child1).next, child2);
2786 assert_eq!((*child2).prev, child1);
2787 assert_eq!((*root).last, child2);
2788
2789 let sibling = new_node(ptr::null_mut(), c_str("sibling"));
2791 add_sibling(child2, sibling);
2792 assert_eq!((*child2).next, sibling);
2793 assert_eq!((*sibling).prev, child2);
2794 assert_eq!((*root).last, sibling);
2795
2796 free_doc(doc);
2797 }
2798 }
2799
2800 #[test]
2801 fn test_unlink_node() {
2802 unsafe {
2803 let doc = new_doc(ptr::null());
2804 let root = new_node(ptr::null_mut(), c_str("root"));
2805 doc_set_root_element(doc, root);
2806
2807 let child1 = new_child(root, ptr::null_mut(), c_str("c1"));
2808 let child2 = new_child(root, ptr::null_mut(), c_str("c2"));
2809
2810 unlink_node(child1);
2811 assert!((*child1).parent.is_null());
2812 assert!((*child1).prev.is_null());
2813 assert!((*child1).next.is_null());
2814 assert_eq!((*root).children, child2);
2815 assert_eq!((*root).last, child2);
2816
2817 free_node(child1);
2818 free_doc(doc);
2819 }
2820 }
2821
2822 #[test]
2823 fn test_text_and_comment_nodes() {
2824 unsafe {
2825 let text = new_text(c_str("hello world"));
2826 assert!(!text.is_null());
2827 assert_eq!((*text).type_, XML_TEXT_NODE as c_int);
2828 assert!(!(*text).content.is_null());
2829 free_node(text);
2830
2831 let comment = new_comment(c_str("my comment"));
2832 assert!(!comment.is_null());
2833 assert_eq!((*comment).type_, XML_COMMENT_NODE as c_int);
2834 free_node(comment);
2835
2836 let pi = new_pi(c_str("xml"), c_str("version='1.0'"));
2837 assert!(!pi.is_null());
2838 assert_eq!((*pi).type_, XML_PI_NODE as c_int);
2839 free_node(pi);
2840 }
2841 }
2842
2843 #[test]
2844 fn test_set_and_get_prop() {
2845 unsafe {
2846 let doc = new_doc(ptr::null());
2847 let root = new_node(ptr::null_mut(), c_str("root"));
2848 doc_set_root_element(doc, root);
2849
2850 let attr = set_prop(root, c_str("id"), c_str("42"));
2851 assert!(!attr.is_null());
2852 assert_eq!((*attr).type_, XML_ATTRIBUTE_NODE as c_int);
2853
2854 let value = get_prop(root, c_str("id"));
2855 assert!(!value.is_null());
2856 assert!(crate::abi::exports_xml2::xmlStrEqual(value, c_str("42")) != 0);
2857 allocator::xmlFree(value as *mut c_void);
2858
2859 free_doc(doc);
2860 }
2861 }
2862
2863 #[test]
2864 fn test_remove_prop() {
2865 unsafe {
2866 let doc = new_doc(ptr::null());
2867 let root = new_node(ptr::null_mut(), c_str("root"));
2868 doc_set_root_element(doc, root);
2869
2870 set_prop(root, c_str("a"), c_str("1"));
2871 set_prop(root, c_str("b"), c_str("2"));
2872
2873 let value = get_prop(root, c_str("a"));
2874 assert!(!value.is_null());
2875 allocator::xmlFree(value as *mut c_void);
2876
2877 let attr = (*root).properties;
2879 assert!(!attr.is_null());
2880 let result = remove_prop(attr);
2881 assert_eq!(result, 0);
2882
2883 let value2 = get_prop(root, c_str("a"));
2885 assert!(value2.is_null());
2886
2887 free_doc(doc);
2888 }
2889 }
2890
2891 #[test]
2892 fn test_namespace_operations() {
2893 unsafe {
2894 let doc = new_doc(ptr::null());
2895 let root = new_node(ptr::null_mut(), c_str("root"));
2896 doc_set_root_element(doc, root);
2897
2898 let ns = new_ns(root, c_str("http://example.com"), c_str("ex"));
2899 assert!(!ns.is_null());
2900 assert!(!(*root).nsDef.is_null());
2901
2902 set_ns(root, ns);
2903 assert_eq!((*root).ns, ns);
2904
2905 let found = search_ns(doc, root, c_str("ex"));
2906 assert_eq!(found, ns);
2907
2908 let found_href = search_ns_by_href(doc, root, c_str("http://example.com"));
2909 assert_eq!(found_href, ns);
2910
2911 free_doc(doc);
2912 }
2913 }
2914
2915 #[test]
2916 fn test_new_dtd() {
2917 unsafe {
2918 let doc = new_doc(ptr::null());
2919 let dtd = new_dtd(doc, c_str("root"), c_str("-//TEST//DTD"), c_str("test.dtd"));
2920 assert!(!dtd.is_null());
2921 assert_eq!((*dtd).type_, XML_DTD_NODE as c_int);
2922 assert_eq!(get_int_subset(doc), dtd);
2923 free_doc(doc);
2924 }
2925 }
2926
2927 #[test]
2928 fn test_copy_node_deep() {
2929 unsafe {
2930 let doc = new_doc(ptr::null());
2931 let root = new_node(ptr::null_mut(), c_str("root"));
2932 doc_set_root_element(doc, root);
2933 let child = new_child(root, ptr::null_mut(), c_str("child"));
2934
2935 let copy = copy_node(root, 1);
2936 assert!(!copy.is_null());
2937 assert_eq!((*copy).type_, XML_ELEMENT_NODE as c_int);
2938 assert!(!(*copy).children.is_null());
2940 assert_eq!((*(*copy).children).type_, XML_ELEMENT_NODE as c_int);
2941
2942 free_node(copy);
2943 free_doc(doc);
2944 }
2945 }
2946
2947 #[test]
2948 fn test_new_cdata_block() {
2949 unsafe {
2950 let doc = new_doc(ptr::null());
2951 let content = c_str("some <cdata> content");
2952 let cdata = new_cdata_block(doc, content, 20);
2953 assert!(!cdata.is_null());
2954 assert_eq!((*cdata).type_, XML_CDATA_SECTION_NODE as c_int);
2955 free_node(cdata);
2956 free_doc(doc);
2957 }
2958 }
2959
2960 #[test]
2961 fn test_null_handling() {
2962 unsafe {
2963 assert!(new_doc(ptr::null()).is_null() == false); let doc = new_doc(ptr::null());
2965 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());
2970 assert!(add_sibling(ptr::null_mut(), ptr::null_mut()).is_null());
2971 free_doc(doc);
2972 }
2973 }
2974
2975 unsafe fn buf_eq_str(buf: *mut _xmlBuffer, expected: &str) -> bool {
2981 let content = io::buf_content(buf);
2982 if content.is_null() {
2983 return expected.is_empty();
2984 }
2985 let len = io::buf_length(buf) as usize;
2986 if len != expected.len() {
2987 return false;
2988 }
2989 let slice = unsafe { core::slice::from_raw_parts(content, len) };
2990 slice == expected.as_bytes()
2991 }
2992
2993 #[test]
2994 fn test_serialize_empty_document() {
2995 unsafe {
2996 let doc = new_doc(ptr::null());
2997 let buf = io::buf_create(-1);
2998 assert!(!buf.is_null());
2999
3000 let ret = doc_dump(buf, doc);
3001 assert!(ret >= 0);
3002
3003 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
3005 assert!(buf_eq_str(buf, expected));
3006
3007 io::buf_free(buf);
3008 free_doc(doc);
3009 }
3010 }
3011
3012 #[test]
3013 fn test_serialize_element_with_text() {
3014 unsafe {
3015 let doc = new_doc(ptr::null());
3016 let root = new_node(ptr::null_mut(), c_str("root"));
3017 doc_set_root_element(doc, root);
3018
3019 let text = new_text(c_str("hello world"));
3021 add_child(root, text);
3022
3023 let buf = io::buf_create(-1);
3024 assert!(!buf.is_null());
3025
3026 let ret = doc_dump(buf, doc);
3027 assert!(ret >= 0);
3028
3029 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>hello world</root>";
3030 assert!(buf_eq_str(buf, expected));
3031
3032 io::buf_free(buf);
3033 free_doc(doc);
3034 }
3035 }
3036
3037 #[test]
3038 fn test_serialize_element_with_attributes() {
3039 unsafe {
3040 let doc = new_doc(ptr::null());
3041 let root = new_node(ptr::null_mut(), c_str("root"));
3042 doc_set_root_element(doc, root);
3043
3044 set_prop(root, c_str("id"), c_str("42"));
3045 set_prop(root, c_str("name"), c_str("test"));
3046
3047 let buf = io::buf_create(-1);
3048 assert!(!buf.is_null());
3049
3050 let ret = doc_dump(buf, doc);
3051 assert!(ret >= 0);
3052
3053 let expected =
3054 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root id=\"42\" name=\"test\"/>";
3055 assert!(buf_eq_str(buf, expected));
3056
3057 io::buf_free(buf);
3058 free_doc(doc);
3059 }
3060 }
3061
3062 #[test]
3063 fn test_serialize_nested_elements() {
3064 unsafe {
3065 let doc = new_doc(ptr::null());
3066 let root = new_node(ptr::null_mut(), c_str("root"));
3067 doc_set_root_element(doc, root);
3068
3069 let child = new_child(root, ptr::null_mut(), c_str("child"));
3070 let grandchild = new_child(child, ptr::null_mut(), c_str("gc"));
3071 let text = new_text(c_str("text"));
3072 add_child(grandchild, text);
3073
3074 let buf = io::buf_create(-1);
3075 assert!(!buf.is_null());
3076
3077 let ret = doc_dump(buf, doc);
3078 assert!(ret >= 0);
3079
3080 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root><child><gc>text</gc></child></root>";
3081 assert!(buf_eq_str(buf, expected));
3082
3083 io::buf_free(buf);
3084 free_doc(doc);
3085 }
3086 }
3087
3088 #[test]
3089 fn test_serialize_with_formatting() {
3090 unsafe {
3091 let doc = new_doc(ptr::null());
3092 let root = new_node(ptr::null_mut(), c_str("root"));
3093 doc_set_root_element(doc, root);
3094
3095 let child = new_child(root, ptr::null_mut(), c_str("child"));
3096 let text = new_text(c_str("text"));
3097 add_child(child, text);
3098
3099 let buf = io::buf_create(-1);
3100 assert!(!buf.is_null());
3101
3102 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
3103
3104 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<root>\n <child>text</child>\n</root>\n";
3105 assert!(buf_eq_str(buf, expected));
3106
3107 io::buf_free(buf);
3108 free_doc(doc);
3109 }
3110 }
3111
3112 #[test]
3113 fn test_serialize_escape_ampersand() {
3114 unsafe {
3115 let doc = new_doc(ptr::null());
3116 let root = new_node(ptr::null_mut(), c_str("root"));
3117 doc_set_root_element(doc, root);
3118
3119 let text = new_text(c_str("a & b"));
3120 add_child(root, text);
3121
3122 let buf = io::buf_create(-1);
3123 assert!(!buf.is_null());
3124
3125 let ret = doc_dump(buf, doc);
3126 assert!(ret >= 0);
3127
3128 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>a & b</root>";
3129 assert!(buf_eq_str(buf, expected));
3130
3131 io::buf_free(buf);
3132 free_doc(doc);
3133 }
3134 }
3135
3136 #[test]
3137 fn test_serialize_escape_angle_brackets() {
3138 unsafe {
3139 let doc = new_doc(ptr::null());
3140 let root = new_node(ptr::null_mut(), c_str("root"));
3141 doc_set_root_element(doc, root);
3142
3143 let text = new_text(c_str("x < y > z"));
3144 add_child(root, text);
3145
3146 let buf = io::buf_create(-1);
3147 assert!(!buf.is_null());
3148
3149 let ret = doc_dump(buf, doc);
3150 assert!(ret >= 0);
3151
3152 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>x < y > z</root>";
3153 assert!(buf_eq_str(buf, expected));
3154
3155 io::buf_free(buf);
3156 free_doc(doc);
3157 }
3158 }
3159
3160 #[test]
3161 fn test_serialize_comment() {
3162 unsafe {
3163 let doc = new_doc(ptr::null());
3164 let root = new_node(ptr::null_mut(), c_str("root"));
3165 doc_set_root_element(doc, root);
3166
3167 let comment = new_comment(c_str("my comment"));
3168 add_child(root, comment);
3169
3170 let buf = io::buf_create(-1);
3171 assert!(!buf.is_null());
3172
3173 let ret = doc_dump(buf, doc);
3174 assert!(ret >= 0);
3175
3176 let expected =
3177 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root><!--my comment--></root>";
3178 assert!(buf_eq_str(buf, expected));
3179
3180 io::buf_free(buf);
3181 free_doc(doc);
3182 }
3183 }
3184
3185 #[test]
3186 fn test_serialize_pi() {
3187 unsafe {
3188 let doc = new_doc(ptr::null());
3189 let root = new_node(ptr::null_mut(), c_str("root"));
3190 doc_set_root_element(doc, root);
3191
3192 let pi = new_pi(
3193 c_str("xml-stylesheet"),
3194 c_str("href=\"style.xsl\" type=\"text/xsl\""),
3195 );
3196 add_child(root, pi);
3197
3198 let buf = io::buf_create(-1);
3199 assert!(!buf.is_null());
3200
3201 let ret = doc_dump(buf, doc);
3202 assert!(ret >= 0);
3203
3204 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root><?xml-stylesheet href=\"style.xsl\" type=\"text/xsl\"?></root>";
3205 assert!(buf_eq_str(buf, expected));
3206
3207 io::buf_free(buf);
3208 free_doc(doc);
3209 }
3210 }
3211
3212 #[test]
3213 fn test_serialize_self_closing() {
3214 unsafe {
3215 let doc = new_doc(ptr::null());
3216 let root = new_node(ptr::null_mut(), c_str("empty"));
3217 doc_set_root_element(doc, root);
3218
3219 let buf = io::buf_create(-1);
3220 assert!(!buf.is_null());
3221
3222 let ret = doc_dump(buf, doc);
3223 assert!(ret >= 0);
3224
3225 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><empty/>";
3226 assert!(buf_eq_str(buf, expected));
3227
3228 io::buf_free(buf);
3229 free_doc(doc);
3230 }
3231 }
3232
3233 #[test]
3234 fn test_dump_node_to_string() {
3235 unsafe {
3236 let node = new_node(ptr::null_mut(), c_str("foo"));
3237 let text = new_text(c_str("bar"));
3238 add_child(node, text);
3239
3240 let result = dump_node(node);
3241 assert!(!result.is_null());
3242
3243 let len = xml_strlen(result);
3244 let slice = unsafe { core::slice::from_raw_parts(result, len as usize) };
3245 assert_eq!(slice, b"<foo>bar</foo>");
3246
3247 allocator::xmlFree(result as *mut c_void);
3248 free_node(node);
3249 }
3250 }
3251
3252 #[test]
3253 fn test_dump_doc_to_string() {
3254 unsafe {
3255 let doc = new_doc(ptr::null());
3256 let root = new_node(ptr::null_mut(), c_str("root"));
3257 doc_set_root_element(doc, root);
3258
3259 let result = dump_doc(doc);
3260 assert!(!result.is_null());
3261
3262 let len = xml_strlen(result);
3263 let slice = unsafe { core::slice::from_raw_parts(result, len as usize) };
3264 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root/>";
3265 assert_eq!(slice, expected.as_bytes());
3266
3267 allocator::xmlFree(result as *mut c_void);
3268 free_doc(doc);
3269 }
3270 }
3271
3272 #[test]
3273 fn test_xmlDocDumpFormatMemory() {
3274 unsafe {
3275 let doc = new_doc(ptr::null());
3276 let root = new_node(ptr::null_mut(), c_str("root"));
3277 doc_set_root_element(doc, root);
3278
3279 let mut mem: *mut xmlChar = ptr::null_mut();
3280 let mut size: c_int = 0;
3281
3282 xmlDocDumpFormatMemory(doc, &mut mem, &mut size, 0);
3283
3284 assert!(!mem.is_null());
3285 assert!(size > 0);
3286
3287 let slice = unsafe { core::slice::from_raw_parts(mem, size as usize) };
3288 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root/>";
3289 assert_eq!(slice, expected.as_bytes());
3290
3291 allocator::xmlFree(mem as *mut c_void);
3292 free_doc(doc);
3293 }
3294 }
3295
3296 #[test]
3297 fn test_serialize_escape_attribute() {
3298 unsafe {
3299 let doc = new_doc(ptr::null());
3300 let root = new_node(ptr::null_mut(), c_str("root"));
3301 doc_set_root_element(doc, root);
3302
3303 set_prop(root, c_str("desc"), c_str("a < b & c \"quoted\""));
3305
3306 let buf = io::buf_create(-1);
3307 assert!(!buf.is_null());
3308
3309 let ret = doc_dump(buf, doc);
3310 assert!(ret >= 0);
3311
3312 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root desc=\"a < b & c "quoted"\"/>";
3313 assert!(buf_eq_str(buf, expected));
3314
3315 io::buf_free(buf);
3316 free_doc(doc);
3317 }
3318 }
3319}