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 unsafe extern "C" fn free_notation_wrapper(payload: *mut c_void, _name: *mut u8) {
1773 crate::xml::dtd::free_notation(payload as *mut _xmlNotation);
1774 }
1775 unsafe extern "C" fn free_element_wrapper(payload: *mut c_void, _name: *mut u8) {
1776 crate::xml::dtd::free_element(payload as *mut _xmlElement);
1777 }
1778 unsafe extern "C" fn free_attribute_wrapper(payload: *mut c_void, _name: *mut u8) {
1779 crate::xml::dtd::free_attribute(payload as *mut _xmlAttribute);
1780 }
1781 unsafe extern "C" fn free_entity_wrapper(payload: *mut c_void, _name: *mut u8) {
1782 crate::xml::entities::free_entity(payload as *mut _xmlEntity);
1783 }
1784
1785 if !d.notations.is_null() {
1786 crate::xml::hash::hash_free(
1787 d.notations as *mut crate::xml::hash::HashTable,
1788 Some(free_notation_wrapper),
1789 );
1790 d.notations = ptr::null_mut();
1791 }
1792 if !d.elements.is_null() {
1793 crate::xml::hash::hash_free(
1794 d.elements as *mut crate::xml::hash::HashTable,
1795 Some(free_element_wrapper),
1796 );
1797 d.elements = ptr::null_mut();
1798 }
1799 if !d.attributes.is_null() {
1800 crate::xml::hash::hash_free(
1801 d.attributes as *mut crate::xml::hash::HashTable,
1802 Some(free_attribute_wrapper),
1803 );
1804 d.attributes = ptr::null_mut();
1805 }
1806 if !d.entities.is_null() {
1807 crate::xml::hash::hash_free(
1808 d.entities as *mut crate::xml::hash::HashTable,
1809 Some(free_entity_wrapper),
1810 );
1811 d.entities = ptr::null_mut();
1812 }
1813 if !d.pentities.is_null() {
1814 crate::xml::hash::hash_free(
1815 d.pentities as *mut crate::xml::hash::HashTable,
1816 Some(free_entity_wrapper),
1817 );
1818 d.pentities = ptr::null_mut();
1819 }
1820
1821 if !d.children.is_null() {
1823 free_node_list(d.children);
1824 }
1825
1826 allocator::xmlFree(dtd as *mut c_void);
1827}
1828
1829pub unsafe fn new_entity(
1849 _doc: *mut _xmlDoc,
1850 name: *const xmlChar,
1851 etype: c_int,
1852 ExternalID: *const xmlChar,
1853 SystemID: *const xmlChar,
1854 content: *const xmlChar,
1855) -> *mut _xmlEntity {
1856 let entity = allocator::xmlMallocZero(size_of::<_xmlEntity>() as usize) as *mut _xmlEntity;
1857 if entity.is_null() {
1858 return ptr::null_mut();
1859 }
1860
1861 unsafe {
1862 (*entity).type_ = XML_ENTITY_DECL as c_int;
1863 (*entity).name = dup_xml_str(name);
1864 (*entity).etype = etype;
1865 (*entity).ExternalID = dup_xml_str(ExternalID);
1866 (*entity).SystemID = dup_xml_str(SystemID);
1867 (*entity).content = dup_xml_str(content);
1868 (*entity).length = if content.is_null() {
1869 0
1870 } else {
1871 crate::abi::exports_xml2::xmlStrlen(content)
1872 };
1873 (*entity).flags = 0;
1874 (*entity).expandedSize = 0;
1875 }
1876
1877 entity
1878}
1879
1880pub unsafe fn get_doc_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
1895 crate::xml::entities::get_entity(doc as *mut _xmlDoc, name)
1896}
1897
1898pub unsafe fn get_parameter_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
1911 crate::xml::entities::get_parameter_entity(doc as *mut _xmlDoc, name)
1912}
1913
1914const ENTITY_LT: &[xmlChar] = b"<";
1923const ENTITY_GT: &[xmlChar] = b">";
1924const ENTITY_AMP: &[xmlChar] = b"&";
1925const ENTITY_QUOT: &[xmlChar] = b""";
1926const ENTITY_APOS: &[xmlChar] = b"'";
1927
1928const INDENT: &[xmlChar] = b" ";
1930
1931const XML_DECL: &[xmlChar] = b"<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
1933
1934unsafe fn serialize_text(buf: *mut _xmlBuffer, content: *const xmlChar, len: c_int) {
1943 if buf.is_null() || content.is_null() || len <= 0 {
1944 return;
1945 }
1946
1947 let mut i: c_int = 0;
1948 while i < len {
1949 let ch = unsafe { *content.add(i as usize) };
1950
1951 if ch == b']'
1953 && i + 2 < len
1954 && unsafe { *content.add(i as usize + 1) == b']' }
1955 && unsafe { *content.add(i as usize + 2) == b'>' }
1956 {
1957 io::buf_add(buf, &ch as *const u8, 2); io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
1960 i += 3;
1961 continue;
1962 }
1963
1964 match ch {
1965 b'<' => {
1966 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
1967 }
1968 b'&' => {
1969 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
1970 }
1971 _ => {
1972 io::buf_add(buf, &ch as *const u8, 1);
1973 }
1974 }
1975 i += 1;
1976 }
1977}
1978
1979unsafe fn serialize_attr_value(buf: *mut _xmlBuffer, value: *const xmlChar) {
1988 if buf.is_null() || value.is_null() {
1989 return;
1990 }
1991
1992 let len = xml_strlen(value);
1993 let mut i: c_int = 0;
1994 while i < len {
1995 let ch = unsafe { *value.add(i as usize) };
1996
1997 if ch == b']'
1999 && i + 2 < len
2000 && unsafe { *value.add(i as usize + 1) == b']' }
2001 && unsafe { *value.add(i as usize + 2) == b'>' }
2002 {
2003 io::buf_add(buf, &ch as *const u8, 2); io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2006 i += 3;
2007 continue;
2008 }
2009
2010 match ch {
2011 b'<' => {
2012 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
2013 }
2014 b'&' => {
2015 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
2016 }
2017 b'"' => {
2018 io::buf_add(buf, ENTITY_QUOT.as_ptr(), ENTITY_QUOT.len() as c_int);
2019 }
2020 _ => {
2021 io::buf_add(buf, &ch as *const u8, 1);
2022 }
2023 }
2024 i += 1;
2025 }
2026}
2027
2028unsafe fn write_indent(buf: *mut _xmlBuffer, level: c_int) {
2034 if buf.is_null() || level <= 0 {
2035 return;
2036 }
2037 for _ in 0..level {
2038 io::buf_add(buf, INDENT.as_ptr(), INDENT.len() as c_int);
2039 }
2040}
2041
2042unsafe fn serialize_start_tag(
2051 node: *mut _xmlNode,
2052 buf: *mut _xmlBuffer,
2053 format: c_int,
2054 level: c_int,
2055) {
2056 if node.is_null() || buf.is_null() {
2057 return;
2058 }
2059
2060 let n = unsafe { &*node };
2061
2062 io::buf_ccat(buf, b'<');
2064
2065 if !n.ns.is_null() {
2067 let ns = unsafe { &*n.ns };
2068 if !ns.prefix.is_null() {
2069 io::buf_cat(buf, ns.prefix);
2070 io::buf_ccat(buf, b':');
2071 }
2072 }
2073 if !n.name.is_null() {
2074 io::buf_cat(buf, n.name);
2075 }
2076
2077 let mut attr = n.properties;
2079 while !attr.is_null() {
2080 let a = unsafe { &*attr };
2081 io::buf_ccat(buf, b' ');
2082
2083 if !a.ns.is_null() {
2085 let ans = unsafe { &*a.ns };
2086 if !ans.prefix.is_null() {
2087 io::buf_cat(buf, ans.prefix);
2088 io::buf_ccat(buf, b':');
2089 }
2090 }
2091 if !a.name.is_null() {
2092 io::buf_cat(buf, a.name);
2093 }
2094
2095 io::buf_add(buf, b"=\"" as *const u8, 2);
2096
2097 if !a.children.is_null() {
2099 let child = unsafe { &*a.children };
2100 if child.type_ == XML_TEXT_NODE as c_int && !child.content.is_null() {
2101 serialize_attr_value(buf, child.content);
2102 }
2103 }
2104
2105 io::buf_ccat(buf, b'"');
2106
2107 attr = a.next;
2108 }
2109
2110 let mut ns_def = n.nsDef;
2112 while !ns_def.is_null() {
2113 let nd = unsafe { &*ns_def };
2114 io::buf_add(buf, b" xmlns" as *const u8, 6);
2115 if !nd.prefix.is_null() {
2116 io::buf_ccat(buf, b':');
2117 io::buf_cat(buf, nd.prefix);
2118 }
2119 io::buf_add(buf, b"=\"" as *const u8, 2);
2120 if !nd.href.is_null() {
2121 serialize_attr_value(buf, nd.href);
2122 }
2123 io::buf_ccat(buf, b'"');
2124 ns_def = nd.next;
2125 }
2126
2127 if n.children.is_null() {
2128 io::buf_add(buf, b"/>" as *const u8, 2);
2130 } else {
2131 io::buf_ccat(buf, b'>');
2132 }
2133}
2134
2135unsafe fn serialize_end_tag(node: *mut _xmlNode, buf: *mut _xmlBuffer) {
2142 if node.is_null() || buf.is_null() {
2143 return;
2144 }
2145
2146 let n = unsafe { &*node };
2147
2148 io::buf_add(buf, b"</" as *const u8, 2);
2149 if !n.ns.is_null() {
2150 let ns = unsafe { &*n.ns };
2151 if !ns.prefix.is_null() {
2152 io::buf_cat(buf, ns.prefix);
2153 io::buf_ccat(buf, b':');
2154 }
2155 }
2156 if !n.name.is_null() {
2157 io::buf_cat(buf, n.name);
2158 }
2159 io::buf_ccat(buf, b'>');
2160}
2161
2162unsafe fn is_text_only_element(node: *mut _xmlNode) -> bool {
2164 if node.is_null() {
2165 return false;
2166 }
2167 let n = unsafe { &*node };
2168 if n.children.is_null() {
2169 return false;
2170 }
2171 if n.children != n.last {
2173 return false;
2174 }
2175 let child = unsafe { &*n.children };
2176 child.type_ == XML_TEXT_NODE as c_int
2177}
2178
2179pub(crate) unsafe fn serialize_node(
2188 node: *mut _xmlNode,
2189 buf: *mut _xmlBuffer,
2190 format: c_int,
2191 level: c_int,
2192) {
2193 if node.is_null() || buf.is_null() {
2194 return;
2195 }
2196
2197 let n = unsafe { &*node };
2198
2199 match n.type_ {
2200 t if t == XML_ELEMENT_NODE as c_int => {
2201 let is_text_only = is_text_only_element(node);
2202
2203 if format != 0 && level > 0 {
2205 io::buf_ccat(buf, b'\n');
2206 write_indent(buf, level);
2207 }
2208
2209 serialize_start_tag(node, buf, format, level);
2210
2211 if !n.children.is_null() {
2212 if !is_text_only && format != 0 {
2213 let mut child = n.children;
2215 while !child.is_null() {
2216 serialize_node(child, buf, format, level + 1);
2217 child = unsafe { (*child).next };
2218 }
2219 io::buf_ccat(buf, b'\n');
2220 write_indent(buf, level);
2221 } else {
2222 let mut child = n.children;
2224 while !child.is_null() {
2225 serialize_node(child, buf, format, level + 1);
2226 child = unsafe { (*child).next };
2227 }
2228 }
2229 serialize_end_tag(node, buf);
2230 }
2231 }
2232 t if t == XML_TEXT_NODE as c_int => {
2233 serialize_text(buf, n.content, xml_strlen(n.content));
2234 }
2235 t if t == XML_CDATA_SECTION_NODE as c_int => {
2236 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
2237 serialize_text(buf, n.content, xml_strlen(n.content));
2238 io::buf_add(buf, b"]]>" as *const u8, 3);
2239 }
2240 t if t == XML_COMMENT_NODE as c_int => {
2241 if format != 0 && level > 0 {
2242 io::buf_ccat(buf, b'\n');
2243 write_indent(buf, level);
2244 }
2245 io::buf_add(buf, b"<!--" as *const u8, 4);
2246 if !n.content.is_null() {
2247 io::buf_cat(buf, n.content);
2248 }
2249 io::buf_add(buf, b"-->" as *const u8, 3);
2250 }
2251 t if t == XML_PI_NODE as c_int => {
2252 if format != 0 && level > 0 {
2253 io::buf_ccat(buf, b'\n');
2254 write_indent(buf, level);
2255 }
2256 io::buf_add(buf, b"<?" as *const u8, 2);
2257 if !n.name.is_null() {
2258 io::buf_cat(buf, n.name);
2259 }
2260 if !n.content.is_null() && unsafe { *n.content != 0 } {
2261 io::buf_ccat(buf, b' ');
2262 io::buf_cat(buf, n.content);
2263 }
2264 io::buf_add(buf, b"?>" as *const u8, 2);
2265 }
2266 t if t == XML_DOCUMENT_NODE as c_int || t == XML_HTML_DOCUMENT_NODE as c_int => {
2267 io::buf_add(buf, XML_DECL.as_ptr(), XML_DECL.len() as c_int);
2269
2270 if format != 0 {
2272 io::buf_ccat(buf, b'\n');
2273 }
2274
2275 let mut child = n.children;
2277 while !child.is_null() {
2278 serialize_node(child, buf, format, 0);
2279 child = unsafe { (*child).next };
2280 }
2281 if format != 0 {
2282 io::buf_ccat(buf, b'\n');
2283 }
2284 }
2285 t if t == XML_DTD_NODE as c_int => {
2286 }
2288 _ => {
2289 if !n.content.is_null() {
2291 serialize_text(buf, n.content, xml_strlen(n.content));
2292 }
2293 }
2294 }
2295}
2296
2297pub(crate) unsafe fn doc_dump(buf: *mut _xmlBuffer, doc: *mut _xmlDoc) -> c_int {
2307 if buf.is_null() || doc.is_null() {
2308 return -1;
2309 }
2310
2311 let before = io::buf_length(buf);
2312 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
2313 let after = io::buf_length(buf);
2314
2315 if after < 0 || before < 0 {
2316 return -1;
2317 }
2318 after - before
2319}
2320
2321pub(crate) unsafe fn node_dump(
2333 buf: *mut _xmlBuffer,
2334 doc: *mut _xmlDoc,
2335 node: *mut _xmlNode,
2336 level: c_int,
2337 format: c_int,
2338) -> c_int {
2339 let _ = doc; if buf.is_null() || node.is_null() {
2341 return -1;
2342 }
2343
2344 let before = io::buf_length(buf);
2345 serialize_node(node, buf, format, level);
2346 let after = io::buf_length(buf);
2347
2348 if after < 0 || before < 0 {
2349 return -1;
2350 }
2351 after - before
2352}
2353
2354pub(crate) unsafe fn save_doc_to_filename(
2361 doc: *mut _xmlDoc,
2362 filename: *const c_char,
2363 compression: c_int,
2364) -> c_int {
2365 if doc.is_null() || filename.is_null() {
2366 return -1;
2367 }
2368
2369 let out = io::output_buffer_create_filename(filename, ptr::null_mut(), compression);
2370 if out.is_null() {
2371 return -1;
2372 }
2373
2374 let buf = io::buf_create(-1);
2375 if buf.is_null() {
2376 io::output_buffer_close(out);
2377 return -1;
2378 }
2379
2380 let ret = doc_dump(buf, doc);
2381 if ret >= 0 {
2382 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
2384 io::output_buffer_flush(out);
2385 }
2386
2387 io::buf_free(buf);
2388 io::output_buffer_close(out);
2389 ret
2390}
2391
2392pub(crate) unsafe fn save_doc_to_fd(doc: *mut _xmlDoc, fd: c_int, compression: c_int) -> c_int {
2399 if doc.is_null() || fd < 0 {
2400 return -1;
2401 }
2402
2403 let out = io::output_buffer_create_fd(fd, ptr::null_mut());
2404 if out.is_null() {
2405 return -1;
2406 }
2407
2408 let buf = io::buf_create(-1);
2409 if buf.is_null() {
2410 io::output_buffer_close(out);
2411 return -1;
2412 }
2413
2414 let ret = doc_dump(buf, doc);
2415 if ret >= 0 {
2416 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
2417 io::output_buffer_flush(out);
2418 }
2419
2420 io::buf_free(buf);
2421 io::output_buffer_close(out);
2422 ret
2423}
2424
2425pub(crate) unsafe fn save_doc_to_buf(
2432 doc: *mut _xmlDoc,
2433 buf: *mut _xmlBuffer,
2434 compression: c_int,
2435) -> c_int {
2436 let _ = compression;
2437 if doc.is_null() || buf.is_null() {
2438 return -1;
2439 }
2440
2441 doc_dump(buf, doc)
2442}
2443
2444pub(crate) unsafe fn save_format_doc_to_buf(
2451 doc: *mut _xmlDoc,
2452 buf: *mut _xmlBuffer,
2453 compression: c_int,
2454) -> c_int {
2455 let _ = compression;
2456 if doc.is_null() || buf.is_null() {
2457 return -1;
2458 }
2459
2460 let before = io::buf_length(buf);
2461 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
2462 let after = io::buf_length(buf);
2463
2464 if after < 0 || before < 0 {
2465 return -1;
2466 }
2467 after - before
2468}
2469
2470pub(crate) unsafe fn dump_node(node: *mut _xmlNode) -> *mut xmlChar {
2479 if node.is_null() {
2480 return ptr::null_mut();
2481 }
2482
2483 let buf = io::buf_create(-1);
2484 if buf.is_null() {
2485 return ptr::null_mut();
2486 }
2487
2488 serialize_node(node, buf, 0, 0);
2489
2490 let content = io::buf_content(buf);
2491 if content.is_null() {
2492 io::buf_free(buf);
2493 return ptr::null_mut();
2494 }
2495
2496 let result = dup_xml_str(content);
2498 io::buf_free(buf);
2499 result
2500}
2501
2502pub(crate) unsafe fn dump_doc(doc: *mut _xmlDoc) -> *mut xmlChar {
2511 if doc.is_null() {
2512 return ptr::null_mut();
2513 }
2514
2515 let buf = io::buf_create(-1);
2516 if buf.is_null() {
2517 return ptr::null_mut();
2518 }
2519
2520 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
2521
2522 let content = io::buf_content(buf);
2523 if content.is_null() {
2524 io::buf_free(buf);
2525 return ptr::null_mut();
2526 }
2527
2528 let result = dup_xml_str(content);
2529 io::buf_free(buf);
2530 result
2531}
2532
2533pub(crate) unsafe fn xmlNodeDump(
2549 buf: *mut _xmlBuffer,
2550 doc: *mut _xmlDoc,
2551 node: *mut _xmlNode,
2552 level: c_int,
2553 format: c_int,
2554) -> c_int {
2555 node_dump(buf, doc, node, level, format)
2556}
2557
2558pub(crate) unsafe fn xmlDocDump(fp: *mut c_void, doc: *mut _xmlDoc) -> c_int {
2571 if fp.is_null() || doc.is_null() {
2572 return -1;
2573 }
2574
2575 let buf = io::buf_create(-1);
2576 if buf.is_null() {
2577 return -1;
2578 }
2579
2580 let ret = doc_dump(buf, doc);
2581 if ret < 0 {
2582 io::buf_free(buf);
2583 return -1;
2584 }
2585
2586 let content = io::buf_content(buf);
2587 let len = io::buf_length(buf);
2588 if !content.is_null() && len > 0 {
2589 let written = libc::fwrite(
2590 content as *const c_void,
2591 1,
2592 len as usize,
2593 fp as *mut libc::FILE,
2594 );
2595 io::buf_free(buf);
2596 written as c_int
2597 } else {
2598 io::buf_free(buf);
2599 0
2600 }
2601}
2602
2603pub(crate) unsafe fn xmlDocDumpFormatMemory(
2617 doc: *mut _xmlDoc,
2618 mem: *mut *mut xmlChar,
2619 size: *mut c_int,
2620 format: c_int,
2621) {
2622 if doc.is_null() || mem.is_null() || size.is_null() {
2623 return;
2624 }
2625
2626 let buf = io::buf_create(-1);
2627 if buf.is_null() {
2628 unsafe {
2629 *mem = ptr::null_mut();
2630 *size = 0;
2631 }
2632 return;
2633 }
2634
2635 serialize_node(doc as *mut _xmlNode, buf, format, 0);
2636
2637 let content = io::buf_content(buf);
2638 let len = io::buf_length(buf);
2639
2640 if !content.is_null() && len > 0 {
2641 let result = allocator::xmlMalloc((len + 1) as usize) as *mut xmlChar;
2643 if !result.is_null() {
2644 ptr::copy_nonoverlapping(content, result, len as usize);
2645 *result.add(len as usize) = 0;
2646 unsafe {
2647 *mem = result;
2648 *size = len;
2649 }
2650 } else {
2651 unsafe {
2652 *mem = ptr::null_mut();
2653 *size = 0;
2654 }
2655 }
2656 } else {
2657 unsafe {
2658 *mem = ptr::null_mut();
2659 *size = 0;
2660 }
2661 }
2662
2663 io::buf_free(buf);
2664}
2665
2666pub(crate) unsafe fn xmlDocDumpMemory(doc: *mut _xmlDoc, mem: *mut *mut xmlChar, size: *mut c_int) {
2680 xmlDocDumpFormatMemory(doc, mem, size, 0)
2681}
2682
2683pub(crate) unsafe fn xmlSaveFile(filename: *const c_char, cur: *mut _xmlDoc) -> c_int {
2696 save_doc_to_filename(cur, filename, 0)
2697}
2698
2699pub(crate) unsafe fn xmlSaveFileEnc(
2713 filename: *const c_char,
2714 cur: *mut _xmlDoc,
2715 encoding: *const c_char,
2716) -> c_int {
2717 let _ = encoding; save_doc_to_filename(cur, filename, 0)
2719}
2720
2721pub(crate) unsafe fn xmlSaveFormatFile(
2734 filename: *const c_char,
2735 cur: *mut _xmlDoc,
2736 format: c_int,
2737) -> c_int {
2738 let _ = format;
2739 save_doc_to_filename(cur, filename, 0)
2740}
2741
2742pub(crate) unsafe fn xmlSaveFormatFileEnc(
2756 filename: *const c_char,
2757 cur: *mut _xmlDoc,
2758 encoding: *const c_char,
2759 format: c_int,
2760) -> c_int {
2761 let _ = encoding;
2762 let _ = format;
2763 save_doc_to_filename(cur, filename, 0)
2764}
2765
2766pub(crate) unsafe fn xmlGetDocCompressMode(doc: *mut _xmlDoc) -> c_int {
2778 if doc.is_null() {
2779 return -1;
2780 }
2781 unsafe { (*doc).compression }
2782}
2783
2784pub(crate) unsafe fn xmlSetDocCompressMode(doc: *mut _xmlDoc, mode: c_int) {
2796 if doc.is_null() {
2797 return;
2798 }
2799 unsafe {
2800 (*doc).compression = mode;
2801 }
2802}
2803
2804#[cfg(test)]
2805mod tests {
2806 use super::*;
2807 use core::ffi::c_void;
2808
2809 fn c_str(s: &str) -> *const xmlChar {
2810 let bytes = s.as_bytes();
2811 let buf = unsafe { allocator::xmlMalloc(bytes.len() + 1) as *mut u8 };
2812 if !buf.is_null() {
2813 unsafe {
2814 ptr::copy_nonoverlapping(bytes.as_ptr(), buf, bytes.len());
2815 *buf.add(bytes.len()) = 0;
2816 }
2817 }
2818 buf as *const xmlChar
2819 }
2820
2821 #[test]
2822 fn test_new_free_doc() {
2823 unsafe {
2824 let doc = new_doc(ptr::null());
2825 assert!(!doc.is_null());
2826 assert_eq!((*doc).type_, XML_DOCUMENT_NODE as c_int);
2827 assert_eq!((*doc).standalone, -1);
2828 assert_eq!((*doc).doc, doc);
2829 assert!(!(*doc).version.is_null());
2830 free_doc(doc);
2831 }
2832 }
2833
2834 #[test]
2835 fn test_new_doc_with_version() {
2836 unsafe {
2837 let ver = c_str("2.0");
2838 let doc = new_doc(ver);
2839 assert!(!doc.is_null());
2840 let doc_ver = (*doc).version;
2841 assert!(!doc_ver.is_null());
2842 assert!(crate::abi::exports_xml2::xmlStrEqual(doc_ver, ver,) != 0);
2843 allocator::xmlFree(ver as *mut c_void);
2844 free_doc(doc);
2845 }
2846 }
2847
2848 #[test]
2849 fn test_new_node() {
2850 unsafe {
2851 let doc = new_doc(ptr::null());
2852 let node = new_node(ptr::null_mut(), c_str("root"));
2853 assert!(!node.is_null());
2854 assert_eq!((*node).type_, XML_ELEMENT_NODE as c_int);
2855 assert!(!(*node).name.is_null());
2856 free_node(node);
2857 free_doc(doc);
2858 }
2859 }
2860
2861 #[test]
2862 fn test_doc_set_root_element() {
2863 unsafe {
2864 let doc = new_doc(ptr::null());
2865 let root = new_node(ptr::null_mut(), c_str("root"));
2866 let old = doc_set_root_element(doc, root);
2867 assert!(old.is_null());
2868 assert_eq!(doc_get_root_element(doc), root);
2869 assert_eq!((*doc).children, root as *mut _xmlNode);
2870 free_doc(doc);
2871 }
2872 }
2873
2874 #[test]
2875 fn test_add_child_and_sibling() {
2876 unsafe {
2877 let doc = new_doc(ptr::null());
2878 let root = new_node(ptr::null_mut(), c_str("root"));
2879 doc_set_root_element(doc, root);
2880
2881 let child1 = new_child(root, ptr::null_mut(), c_str("child1"));
2882 assert!(!child1.is_null());
2883 assert_eq!((*child1).parent, root);
2884 assert_eq!((*root).children, child1);
2885 assert_eq!((*root).last, child1);
2886
2887 let child2 = new_child(root, ptr::null_mut(), c_str("child2"));
2888 assert!(!child2.is_null());
2889 assert_eq!((*child2).parent, root);
2890 assert_eq!((*child1).next, child2);
2891 assert_eq!((*child2).prev, child1);
2892 assert_eq!((*root).last, child2);
2893
2894 let sibling = new_node(ptr::null_mut(), c_str("sibling"));
2896 add_sibling(child2, sibling);
2897 assert_eq!((*child2).next, sibling);
2898 assert_eq!((*sibling).prev, child2);
2899 assert_eq!((*root).last, sibling);
2900
2901 free_doc(doc);
2902 }
2903 }
2904
2905 #[test]
2906 fn test_unlink_node() {
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 child1 = new_child(root, ptr::null_mut(), c_str("c1"));
2913 let child2 = new_child(root, ptr::null_mut(), c_str("c2"));
2914
2915 unlink_node(child1);
2916 assert!((*child1).parent.is_null());
2917 assert!((*child1).prev.is_null());
2918 assert!((*child1).next.is_null());
2919 assert_eq!((*root).children, child2);
2920 assert_eq!((*root).last, child2);
2921
2922 free_node(child1);
2923 free_doc(doc);
2924 }
2925 }
2926
2927 #[test]
2928 fn test_text_and_comment_nodes() {
2929 unsafe {
2930 let text = new_text(c_str("hello world"));
2931 assert!(!text.is_null());
2932 assert_eq!((*text).type_, XML_TEXT_NODE as c_int);
2933 assert!(!(*text).content.is_null());
2934 free_node(text);
2935
2936 let comment = new_comment(c_str("my comment"));
2937 assert!(!comment.is_null());
2938 assert_eq!((*comment).type_, XML_COMMENT_NODE as c_int);
2939 free_node(comment);
2940
2941 let pi = new_pi(c_str("xml"), c_str("version='1.0'"));
2942 assert!(!pi.is_null());
2943 assert_eq!((*pi).type_, XML_PI_NODE as c_int);
2944 free_node(pi);
2945 }
2946 }
2947
2948 #[test]
2949 fn test_set_and_get_prop() {
2950 unsafe {
2951 let doc = new_doc(ptr::null());
2952 let root = new_node(ptr::null_mut(), c_str("root"));
2953 doc_set_root_element(doc, root);
2954
2955 let attr = set_prop(root, c_str("id"), c_str("42"));
2956 assert!(!attr.is_null());
2957 assert_eq!((*attr).type_, XML_ATTRIBUTE_NODE as c_int);
2958
2959 let value = get_prop(root, c_str("id"));
2960 assert!(!value.is_null());
2961 assert!(crate::abi::exports_xml2::xmlStrEqual(value, c_str("42")) != 0);
2962 allocator::xmlFree(value as *mut c_void);
2963
2964 free_doc(doc);
2965 }
2966 }
2967
2968 #[test]
2969 fn test_remove_prop() {
2970 unsafe {
2971 let doc = new_doc(ptr::null());
2972 let root = new_node(ptr::null_mut(), c_str("root"));
2973 doc_set_root_element(doc, root);
2974
2975 set_prop(root, c_str("a"), c_str("1"));
2976 set_prop(root, c_str("b"), c_str("2"));
2977
2978 let value = get_prop(root, c_str("a"));
2979 assert!(!value.is_null());
2980 allocator::xmlFree(value as *mut c_void);
2981
2982 let attr = (*root).properties;
2984 assert!(!attr.is_null());
2985 let result = remove_prop(attr);
2986 assert_eq!(result, 0);
2987
2988 let value2 = get_prop(root, c_str("a"));
2990 assert!(value2.is_null());
2991
2992 free_doc(doc);
2993 }
2994 }
2995
2996 #[test]
2997 fn test_namespace_operations() {
2998 unsafe {
2999 let doc = new_doc(ptr::null());
3000 let root = new_node(ptr::null_mut(), c_str("root"));
3001 doc_set_root_element(doc, root);
3002
3003 let ns = new_ns(root, c_str("http://example.com"), c_str("ex"));
3004 assert!(!ns.is_null());
3005 assert!(!(*root).nsDef.is_null());
3006
3007 set_ns(root, ns);
3008 assert_eq!((*root).ns, ns);
3009
3010 let found = search_ns(doc, root, c_str("ex"));
3011 assert_eq!(found, ns);
3012
3013 let found_href = search_ns_by_href(doc, root, c_str("http://example.com"));
3014 assert_eq!(found_href, ns);
3015
3016 free_doc(doc);
3017 }
3018 }
3019
3020 #[test]
3021 fn test_new_dtd() {
3022 unsafe {
3023 let doc = new_doc(ptr::null());
3024 let dtd = new_dtd(doc, c_str("root"), c_str("-//TEST//DTD"), c_str("test.dtd"));
3025 assert!(!dtd.is_null());
3026 assert_eq!((*dtd).type_, XML_DTD_NODE as c_int);
3027 assert_eq!(get_int_subset(doc), dtd);
3028 free_doc(doc);
3029 }
3030 }
3031
3032 #[test]
3033 fn test_copy_node_deep() {
3034 unsafe {
3035 let doc = new_doc(ptr::null());
3036 let root = new_node(ptr::null_mut(), c_str("root"));
3037 doc_set_root_element(doc, root);
3038 let child = new_child(root, ptr::null_mut(), c_str("child"));
3039
3040 let copy = copy_node(root, 1);
3041 assert!(!copy.is_null());
3042 assert_eq!((*copy).type_, XML_ELEMENT_NODE as c_int);
3043 assert!(!(*copy).children.is_null());
3045 assert_eq!((*(*copy).children).type_, XML_ELEMENT_NODE as c_int);
3046
3047 free_node(copy);
3048 free_doc(doc);
3049 }
3050 }
3051
3052 #[test]
3053 fn test_new_cdata_block() {
3054 unsafe {
3055 let doc = new_doc(ptr::null());
3056 let content = c_str("some <cdata> content");
3057 let cdata = new_cdata_block(doc, content, 20);
3058 assert!(!cdata.is_null());
3059 assert_eq!((*cdata).type_, XML_CDATA_SECTION_NODE as c_int);
3060 free_node(cdata);
3061 free_doc(doc);
3062 }
3063 }
3064
3065 #[test]
3066 fn test_null_handling() {
3067 unsafe {
3068 assert!(new_doc(ptr::null()).is_null() == false); let doc = new_doc(ptr::null());
3070 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());
3075 assert!(add_sibling(ptr::null_mut(), ptr::null_mut()).is_null());
3076 free_doc(doc);
3077 }
3078 }
3079
3080 unsafe fn buf_eq_str(buf: *mut _xmlBuffer, expected: &str) -> bool {
3086 let content = io::buf_content(buf);
3087 if content.is_null() {
3088 return expected.is_empty();
3089 }
3090 let len = io::buf_length(buf) as usize;
3091 if len != expected.len() {
3092 return false;
3093 }
3094 let slice = unsafe { core::slice::from_raw_parts(content, len) };
3095 slice == expected.as_bytes()
3096 }
3097
3098 #[test]
3099 fn test_serialize_empty_document() {
3100 unsafe {
3101 let doc = new_doc(ptr::null());
3102 let buf = io::buf_create(-1);
3103 assert!(!buf.is_null());
3104
3105 let ret = doc_dump(buf, doc);
3106 assert!(ret >= 0);
3107
3108 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
3110 assert!(buf_eq_str(buf, expected));
3111
3112 io::buf_free(buf);
3113 free_doc(doc);
3114 }
3115 }
3116
3117 #[test]
3118 fn test_serialize_element_with_text() {
3119 unsafe {
3120 let doc = new_doc(ptr::null());
3121 let root = new_node(ptr::null_mut(), c_str("root"));
3122 doc_set_root_element(doc, root);
3123
3124 let text = new_text(c_str("hello world"));
3126 add_child(root, text);
3127
3128 let buf = io::buf_create(-1);
3129 assert!(!buf.is_null());
3130
3131 let ret = doc_dump(buf, doc);
3132 assert!(ret >= 0);
3133
3134 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>hello world</root>";
3135 assert!(buf_eq_str(buf, expected));
3136
3137 io::buf_free(buf);
3138 free_doc(doc);
3139 }
3140 }
3141
3142 #[test]
3143 fn test_serialize_element_with_attributes() {
3144 unsafe {
3145 let doc = new_doc(ptr::null());
3146 let root = new_node(ptr::null_mut(), c_str("root"));
3147 doc_set_root_element(doc, root);
3148
3149 set_prop(root, c_str("id"), c_str("42"));
3150 set_prop(root, c_str("name"), c_str("test"));
3151
3152 let buf = io::buf_create(-1);
3153 assert!(!buf.is_null());
3154
3155 let ret = doc_dump(buf, doc);
3156 assert!(ret >= 0);
3157
3158 let expected =
3159 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root id=\"42\" name=\"test\"/>";
3160 assert!(buf_eq_str(buf, expected));
3161
3162 io::buf_free(buf);
3163 free_doc(doc);
3164 }
3165 }
3166
3167 #[test]
3168 fn test_serialize_nested_elements() {
3169 unsafe {
3170 let doc = new_doc(ptr::null());
3171 let root = new_node(ptr::null_mut(), c_str("root"));
3172 doc_set_root_element(doc, root);
3173
3174 let child = new_child(root, ptr::null_mut(), c_str("child"));
3175 let grandchild = new_child(child, ptr::null_mut(), c_str("gc"));
3176 let text = new_text(c_str("text"));
3177 add_child(grandchild, text);
3178
3179 let buf = io::buf_create(-1);
3180 assert!(!buf.is_null());
3181
3182 let ret = doc_dump(buf, doc);
3183 assert!(ret >= 0);
3184
3185 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root><child><gc>text</gc></child></root>";
3186 assert!(buf_eq_str(buf, expected));
3187
3188 io::buf_free(buf);
3189 free_doc(doc);
3190 }
3191 }
3192
3193 #[test]
3194 fn test_serialize_with_formatting() {
3195 unsafe {
3196 let doc = new_doc(ptr::null());
3197 let root = new_node(ptr::null_mut(), c_str("root"));
3198 doc_set_root_element(doc, root);
3199
3200 let child = new_child(root, ptr::null_mut(), c_str("child"));
3201 let text = new_text(c_str("text"));
3202 add_child(child, text);
3203
3204 let buf = io::buf_create(-1);
3205 assert!(!buf.is_null());
3206
3207 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
3208
3209 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<root>\n <child>text</child>\n</root>\n";
3210 assert!(buf_eq_str(buf, expected));
3211
3212 io::buf_free(buf);
3213 free_doc(doc);
3214 }
3215 }
3216
3217 #[test]
3218 fn test_serialize_escape_ampersand() {
3219 unsafe {
3220 let doc = new_doc(ptr::null());
3221 let root = new_node(ptr::null_mut(), c_str("root"));
3222 doc_set_root_element(doc, root);
3223
3224 let text = new_text(c_str("a & b"));
3225 add_child(root, text);
3226
3227 let buf = io::buf_create(-1);
3228 assert!(!buf.is_null());
3229
3230 let ret = doc_dump(buf, doc);
3231 assert!(ret >= 0);
3232
3233 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>a & b</root>";
3234 assert!(buf_eq_str(buf, expected));
3235
3236 io::buf_free(buf);
3237 free_doc(doc);
3238 }
3239 }
3240
3241 #[test]
3242 fn test_serialize_escape_angle_brackets() {
3243 unsafe {
3244 let doc = new_doc(ptr::null());
3245 let root = new_node(ptr::null_mut(), c_str("root"));
3246 doc_set_root_element(doc, root);
3247
3248 let text = new_text(c_str("x < y > z"));
3249 add_child(root, text);
3250
3251 let buf = io::buf_create(-1);
3252 assert!(!buf.is_null());
3253
3254 let ret = doc_dump(buf, doc);
3255 assert!(ret >= 0);
3256
3257 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>x < y > z</root>";
3258 assert!(buf_eq_str(buf, expected));
3259
3260 io::buf_free(buf);
3261 free_doc(doc);
3262 }
3263 }
3264
3265 #[test]
3266 fn test_serialize_comment() {
3267 unsafe {
3268 let doc = new_doc(ptr::null());
3269 let root = new_node(ptr::null_mut(), c_str("root"));
3270 doc_set_root_element(doc, root);
3271
3272 let comment = new_comment(c_str("my comment"));
3273 add_child(root, comment);
3274
3275 let buf = io::buf_create(-1);
3276 assert!(!buf.is_null());
3277
3278 let ret = doc_dump(buf, doc);
3279 assert!(ret >= 0);
3280
3281 let expected =
3282 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root><!--my comment--></root>";
3283 assert!(buf_eq_str(buf, expected));
3284
3285 io::buf_free(buf);
3286 free_doc(doc);
3287 }
3288 }
3289
3290 #[test]
3291 fn test_serialize_pi() {
3292 unsafe {
3293 let doc = new_doc(ptr::null());
3294 let root = new_node(ptr::null_mut(), c_str("root"));
3295 doc_set_root_element(doc, root);
3296
3297 let pi = new_pi(
3298 c_str("xml-stylesheet"),
3299 c_str("href=\"style.xsl\" type=\"text/xsl\""),
3300 );
3301 add_child(root, pi);
3302
3303 let buf = io::buf_create(-1);
3304 assert!(!buf.is_null());
3305
3306 let ret = doc_dump(buf, doc);
3307 assert!(ret >= 0);
3308
3309 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root><?xml-stylesheet href=\"style.xsl\" type=\"text/xsl\"?></root>";
3310 assert!(buf_eq_str(buf, expected));
3311
3312 io::buf_free(buf);
3313 free_doc(doc);
3314 }
3315 }
3316
3317 #[test]
3318 fn test_serialize_self_closing() {
3319 unsafe {
3320 let doc = new_doc(ptr::null());
3321 let root = new_node(ptr::null_mut(), c_str("empty"));
3322 doc_set_root_element(doc, root);
3323
3324 let buf = io::buf_create(-1);
3325 assert!(!buf.is_null());
3326
3327 let ret = doc_dump(buf, doc);
3328 assert!(ret >= 0);
3329
3330 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><empty/>";
3331 assert!(buf_eq_str(buf, expected));
3332
3333 io::buf_free(buf);
3334 free_doc(doc);
3335 }
3336 }
3337
3338 #[test]
3339 fn test_dump_node_to_string() {
3340 unsafe {
3341 let node = new_node(ptr::null_mut(), c_str("foo"));
3342 let text = new_text(c_str("bar"));
3343 add_child(node, text);
3344
3345 let result = dump_node(node);
3346 assert!(!result.is_null());
3347
3348 let len = xml_strlen(result);
3349 let slice = unsafe { core::slice::from_raw_parts(result, len as usize) };
3350 assert_eq!(slice, b"<foo>bar</foo>");
3351
3352 allocator::xmlFree(result as *mut c_void);
3353 free_node(node);
3354 }
3355 }
3356
3357 #[test]
3358 fn test_dump_doc_to_string() {
3359 unsafe {
3360 let doc = new_doc(ptr::null());
3361 let root = new_node(ptr::null_mut(), c_str("root"));
3362 doc_set_root_element(doc, root);
3363
3364 let result = dump_doc(doc);
3365 assert!(!result.is_null());
3366
3367 let len = xml_strlen(result);
3368 let slice = unsafe { core::slice::from_raw_parts(result, len as usize) };
3369 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root/>";
3370 assert_eq!(slice, expected.as_bytes());
3371
3372 allocator::xmlFree(result as *mut c_void);
3373 free_doc(doc);
3374 }
3375 }
3376
3377 #[test]
3378 fn test_xmlDocDumpFormatMemory() {
3379 unsafe {
3380 let doc = new_doc(ptr::null());
3381 let root = new_node(ptr::null_mut(), c_str("root"));
3382 doc_set_root_element(doc, root);
3383
3384 let mut mem: *mut xmlChar = ptr::null_mut();
3385 let mut size: c_int = 0;
3386
3387 xmlDocDumpFormatMemory(doc, &mut mem, &mut size, 0);
3388
3389 assert!(!mem.is_null());
3390 assert!(size > 0);
3391
3392 let slice = unsafe { core::slice::from_raw_parts(mem, size as usize) };
3393 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root/>";
3394 assert_eq!(slice, expected.as_bytes());
3395
3396 allocator::xmlFree(mem as *mut c_void);
3397 free_doc(doc);
3398 }
3399 }
3400
3401 #[test]
3402 fn test_serialize_escape_attribute() {
3403 unsafe {
3404 let doc = new_doc(ptr::null());
3405 let root = new_node(ptr::null_mut(), c_str("root"));
3406 doc_set_root_element(doc, root);
3407
3408 set_prop(root, c_str("desc"), c_str("a < b & c \"quoted\""));
3410
3411 let buf = io::buf_create(-1);
3412 assert!(!buf.is_null());
3413
3414 let ret = doc_dump(buf, doc);
3415 assert!(ret >= 0);
3416
3417 let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root desc=\"a < b & c "quoted"\"/>";
3418 assert!(buf_eq_str(buf, expected));
3419
3420 io::buf_free(buf);
3421 free_doc(doc);
3422 }
3423 }
3424}