1use core::ffi::c_void;
106use core::ptr;
107use std::os::raw::{c_char, c_int, c_long, c_ulong};
108
109use crate::abi::allocator;
110use crate::abi::constants::*;
111use crate::abi::structs::*;
112use crate::abi::types::xmlCharEncoding::XML_CHAR_ENCODING_UTF8;
113use crate::abi::types::xmlDocProperties::XML_DOC_USERBUILT;
114use crate::abi::types::xmlElementType::*;
115use crate::abi::types::*;
116use crate::xml::io;
117
118unsafe fn dup_xml_str(str: *const xmlChar) -> *mut xmlChar {
128 if str.is_null() {
129 return ptr::null_mut();
130 }
131 let len = unsafe { crate::abi::exports_xml2::xmlStrlen(str) as usize };
132 if len == 0 {
133 let buf = unsafe { allocator::xmlMallocImpl(1) as *mut xmlChar };
135 if !buf.is_null() {
136 unsafe { *buf = 0 };
137 }
138 return buf;
139 }
140 let buf = unsafe { allocator::xmlMallocImpl(len + 1) as *mut xmlChar };
141 if !buf.is_null() {
142 unsafe {
143 ptr::copy_nonoverlapping(str, buf, len + 1);
144 }
145 }
146 buf
147}
148
149#[allow(dead_code)]
151unsafe fn copy_xml_str_content(dest: *mut xmlChar, src: *const xmlChar, max_len: usize) -> bool {
152 if src.is_null() || dest.is_null() || max_len == 0 {
153 return false;
154 }
155 let len = unsafe { crate::abi::exports_xml2::xmlStrlen(src) as usize };
156 if len >= max_len {
157 return false;
158 }
159 unsafe {
160 ptr::copy_nonoverlapping(src, dest, len);
161 *dest.add(len) = 0;
162 }
163 true
164}
165
166pub const unsafe fn xml_strlen(str: *const xmlChar) -> c_int {
183 if str.is_null() {
184 return 0;
185 }
186 let mut len: c_int = 0;
187 while unsafe { *str.add(len as usize) != 0 } {
188 len += 1;
189 }
190 len
191}
192
193pub unsafe fn new_doc(version: *const xmlChar) -> *mut _xmlDoc {
216 let doc = allocator::xmlMallocZero(size_of::<_xmlDoc>() as usize) as *mut _xmlDoc;
218 if doc.is_null() {
219 return ptr::null_mut();
220 }
221
222 unsafe {
223 (*doc).type_ = XML_DOCUMENT_NODE as c_int;
224 (*doc).standalone = -1; (*doc).doc = doc; (*doc).properties = XML_DOC_USERBUILT as c_int;
227 (*doc).compression = -1; (*doc).charset = XML_CHAR_ENCODING_UTF8 as c_int;
229
230 let ver = if version.is_null() {
232 XML_DEFAULT_VERSION.as_ptr() as *const xmlChar
233 } else {
234 version
235 };
236 (*doc).version = dup_xml_str(ver);
237 }
238
239 crate::abi::data_globals::register_node_hook(doc as *mut _xmlNode);
241
242 doc
243}
244
245pub unsafe fn free_doc(doc: *mut _xmlDoc) {
259 if doc.is_null() {
260 return;
261 }
262
263 crate::abi::data_globals::deregister_node_hook(doc as *mut _xmlNode);
266
267 let d = unsafe { &mut *doc };
268
269 let dict = d.dict;
273 let mut ext_subset = d.extSubset;
274 let int_subset = d.intSubset;
275 if !ext_subset.is_null() && ext_subset == int_subset {
276 ext_subset = ptr::null_mut();
277 }
278 if !ext_subset.is_null() {
279 unlink_node_internal(ext_subset as *mut _xmlNode, d as *mut _xmlDoc);
280 d.extSubset = ptr::null_mut();
281 free_dtd(ext_subset);
282 }
283 if !int_subset.is_null() {
284 unlink_node_internal(int_subset as *mut _xmlNode, d as *mut _xmlDoc);
285 d.intSubset = ptr::null_mut();
286 free_dtd(int_subset);
287 }
288
289 if !d.children.is_null() {
291 free_node_list(d.children);
292 }
293
294 if !d.oldNs.is_null() {
296 free_ns_list(d.oldNs);
297 }
298
299 if !d.version.is_null() {
301 allocator::xmlFreeImpl(d.version as *mut c_void);
302 }
303 if !d.encoding.is_null() {
304 allocator::xmlFreeImpl(d.encoding as *mut c_void);
305 }
306 if !d.URL.is_null() {
307 allocator::xmlFreeImpl(d.URL as *mut c_void);
308 }
309
310 allocator::xmlFreeImpl(doc as *mut c_void);
312
313 if !dict.is_null() {
315 crate::abi::exports_xml2::xmlDictFree(dict);
316 }
317}
318
319unsafe fn unlink_node_internal(node: *mut _xmlNode, _doc: *mut _xmlDoc) {
323 if node.is_null() {
324 return;
325 }
326 let parent = (*node).parent;
327 if parent.is_null() {
328 return;
329 }
330 if (*node).prev.is_null() {
331 (*parent).children = (*node).next;
332 } else {
333 (*(*node).prev).next = (*node).next;
334 }
335 if (*node).next.is_null() {
336 (*parent).last = (*node).prev;
337 } else {
338 (*(*node).next).prev = (*node).prev;
339 }
340 (*node).next = ptr::null_mut();
341 (*node).prev = ptr::null_mut();
342 (*node).parent = ptr::null_mut();
343}
344
345pub unsafe fn copy_doc(doc: *const _xmlDoc, recursive: c_int) -> *mut _xmlDoc {
360 if doc.is_null() {
361 return ptr::null_mut();
362 }
363
364 let d = unsafe { &*doc };
365
366 let new_doc = new_doc(d.version);
367 if new_doc.is_null() {
368 return ptr::null_mut();
369 }
370
371 unsafe {
372 (*new_doc).type_ = d.type_;
373 (*new_doc).standalone = d.standalone;
374 (*new_doc).encoding = dup_xml_str(d.encoding);
375 (*new_doc).URL = dup_xml_str(d.URL);
376 (*new_doc).charset = d.charset;
377 (*new_doc).properties = d.properties;
378
379 if !d.intSubset.is_null() {
384 let dtd_copy = crate::xml::dtd::copy_dtd(d.intSubset);
385 if !dtd_copy.is_null() {
386 (*new_doc).intSubset = dtd_copy;
387 }
388 }
389
390 if recursive != 0 && !d.children.is_null() {
391 (*new_doc).children = copy_node_list(d.children, recursive);
392 if !(*new_doc).children.is_null() {
393 (*(*new_doc).children).parent = ptr::null_mut(); (*(*new_doc).children).doc = new_doc;
395 propagate_doc((*new_doc).children, new_doc);
397 }
398 }
399 }
400
401 new_doc
402}
403
404pub unsafe fn doc_set_root_element(doc: *mut _xmlDoc, root: *mut _xmlNode) -> *mut _xmlNode {
420 if doc.is_null() {
421 return ptr::null_mut();
422 }
423
424 let d = unsafe { &mut *doc };
425
426 let old_root = doc_get_root_element(doc);
427
428 if !root.is_null() {
429 unsafe {
430 (*root).parent = ptr::null_mut();
431 (*root).doc = doc;
432 }
433 d.children = root;
434 d.last = root;
435 unsafe {
436 (*root).prev = ptr::null_mut();
437 (*root).next = ptr::null_mut();
438 }
439 } else {
440 d.children = ptr::null_mut();
441 d.last = ptr::null_mut();
442 }
443
444 old_root
445}
446
447pub fn doc_get_root_element(doc: *mut _xmlDoc) -> *mut _xmlNode {
463 if doc.is_null() {
464 return ptr::null_mut();
465 }
466
467 let d = unsafe { &*doc };
468 let mut cur = d.children;
469
470 while !cur.is_null() {
471 let node = unsafe { &*cur };
472 if node.type_ == XML_ELEMENT_NODE as c_int {
473 return cur;
474 }
475 cur = node.next;
476 }
477
478 ptr::null_mut()
479}
480
481pub fn get_line_no(node: *const _xmlNode) -> c_long {
496 unsafe { get_line_no_internal(node, 0) }
497}
498
499unsafe fn get_line_no_internal(node: *const _xmlNode, depth: c_int) -> c_long {
511 if depth >= 5 {
512 return -1;
513 }
514 if node.is_null() {
515 return -1;
516 }
517 let n = unsafe { &*node };
518 if n.type_ == XML_ELEMENT_NODE as c_int
519 || n.type_ == XML_TEXT_NODE as c_int
520 || n.type_ == XML_COMMENT_NODE as c_int
521 || n.type_ == XML_PI_NODE as c_int
522 {
523 if n.line == 65535 {
524 if n.type_ == XML_ELEMENT_NODE as c_int && !n.children.is_null() {
525 let r = unsafe { get_line_no_internal(n.children, depth + 1) };
526 if r != -1 {
527 return r;
528 }
529 }
530 if !n.next.is_null() {
531 let r = unsafe { get_line_no_internal(n.next, depth + 1) };
532 if r != -1 {
533 return r;
534 }
535 }
536 if !n.prev.is_null() {
537 let r = unsafe { get_line_no_internal(n.prev, depth + 1) };
538 if r != -1 {
539 return r;
540 }
541 }
542 }
543 n.line as c_long
544 } else if !n.prev.is_null()
545 && (unsafe { (*n.prev).type_ } == XML_ELEMENT_NODE as c_int
546 || unsafe { (*n.prev).type_ } == XML_TEXT_NODE as c_int
547 || unsafe { (*n.prev).type_ } == XML_COMMENT_NODE as c_int
548 || unsafe { (*n.prev).type_ } == XML_PI_NODE as c_int)
549 {
550 unsafe { get_line_no_internal(n.prev, depth + 1) }
551 } else if !n.parent.is_null() && unsafe { (*n.parent).type_ } == XML_ELEMENT_NODE as c_int {
552 unsafe { get_line_no_internal(n.parent, depth + 1) }
553 } else {
554 -1
555 }
556}
557
558pub unsafe fn node_get_content(node: *mut _xmlNode) -> *mut xmlChar {
593 if node.is_null() {
594 return ptr::null_mut();
595 }
596 let typ = (*node).type_;
597 let mut result: Vec<u8> = Vec::new();
598 match typ {
599 t if t == XML_TEXT_NODE as c_int
600 || t == XML_CDATA_SECTION_NODE as c_int
601 || t == XML_COMMENT_NODE as c_int
602 || t == XML_PI_NODE as c_int =>
603 {
604 if !(*node).content.is_null() {
605 let len = crate::abi::exports_xml2::xmlStrlen((*node).content);
606 result
607 .extend_from_slice(core::slice::from_raw_parts((*node).content, len as usize));
608 } else if t == XML_TEXT_NODE as c_int && !(*node).children.is_null() {
609 let mut child = (*node).children;
612 while !child.is_null() {
613 if !(*child).content.is_null() {
614 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
615 result.extend_from_slice(core::slice::from_raw_parts(
616 (*child).content,
617 len as usize,
618 ));
619 }
620 child = (*child).next;
621 }
622 }
623 }
624 t if t == XML_ATTRIBUTE_NODE as c_int => {
625 if !(*node).children.is_null() {
627 let child = (*node).children;
628 if !(*child).content.is_null() {
629 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
630 result.extend_from_slice(core::slice::from_raw_parts(
631 (*child).content,
632 len as usize,
633 ));
634 }
635 }
636 }
637 t if t == XML_ENTITY_REF_NODE as c_int => {
638 let name = (*node).name;
640 if !name.is_null() && !(*node).doc.is_null() {
641 let ent = crate::xml::tree::get_doc_entity((*node).doc, name);
642 if !ent.is_null() && !(*ent).content.is_null() {
643 let len = crate::abi::exports_xml2::xmlStrlen((*ent).content);
644 result.extend_from_slice(core::slice::from_raw_parts(
645 (*ent).content,
646 len as usize,
647 ));
648 }
649 }
650 }
651 t if t == XML_DOCUMENT_NODE as c_int || t == XML_HTML_DOCUMENT_NODE as c_int => {
652 let root = doc_get_root_element(node as *mut _xmlDoc);
653 if !root.is_null() {
654 let sub = node_get_content(root);
655 if !sub.is_null() {
656 let len = crate::abi::exports_xml2::xmlStrlen(sub);
657 result.extend_from_slice(core::slice::from_raw_parts(sub, len as usize));
658 allocator::xmlFreeImpl(sub as *mut c_void);
659 }
660 }
661 }
662 _ => {
663 let mut child = (*node).children;
668 while !child.is_null() {
669 let ctype = (*child).type_;
670 if ctype == XML_TEXT_NODE as c_int || ctype == XML_CDATA_SECTION_NODE as c_int {
671 if !(*child).content.is_null() {
672 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
673 result.extend_from_slice(core::slice::from_raw_parts(
674 (*child).content,
675 len as usize,
676 ));
677 }
678 } else if ctype == XML_ENTITY_REF_NODE as c_int
679 || ctype == XML_ELEMENT_NODE as c_int
680 {
681 let sub = node_get_content(child);
682 if !sub.is_null() {
683 let len = crate::abi::exports_xml2::xmlStrlen(sub);
684 result.extend_from_slice(core::slice::from_raw_parts(sub, len as usize));
685 allocator::xmlFreeImpl(sub as *mut c_void);
686 }
687 }
688 child = (*child).next;
689 }
690 }
691 }
692 let buf = allocator::xmlMallocImpl(result.len() + 1) as *mut xmlChar;
694 if buf.is_null() {
695 return ptr::null_mut();
696 }
697 if !result.is_empty() {
698 ptr::copy_nonoverlapping(result.as_ptr(), buf, result.len());
699 }
700 *buf.add(result.len()) = 0;
701 buf
702}
703
704pub unsafe fn new_node(ns: *mut _xmlNs, name: *const xmlChar) -> *mut _xmlNode {
723 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
724 if node.is_null() {
725 return ptr::null_mut();
726 }
727
728 unsafe {
729 (*node).type_ = XML_ELEMENT_NODE as c_int;
730 (*node).name = dup_xml_str(name);
731 (*node).ns = ns;
732 (*node).line = 0;
733 (*node).extra = 0;
734
735 if !ns.is_null() {
736 (*ns).context = node as *mut _xmlDoc;
737 }
738 }
739
740 crate::abi::data_globals::register_node_hook(node);
743
744 node
745}
746
747pub unsafe fn free_node(node: *mut _xmlNode) {
762 if node.is_null() {
763 return;
764 }
765
766 let n = unsafe { &mut *node };
767
768 if n.type_ == XML_DTD_NODE as c_int {
772 free_dtd(node as *mut _xmlDtd);
773 return;
774 } else if n.type_ == XML_NAMESPACE_DECL as c_int {
775 free_ns(node as *mut _xmlNs);
776 return;
777 } else if n.type_ == XML_ATTRIBUTE_NODE as c_int {
778 free_prop(node as *mut _xmlAttr);
779 return;
780 } else if n.type_ == XML_ELEMENT_DECL as c_int {
781 crate::xml::dtd::free_element(node as *mut _xmlElement);
782 return;
783 } else if n.type_ == XML_ATTRIBUTE_DECL as c_int {
784 crate::xml::dtd::free_attribute(node as *mut _xmlAttribute);
785 return;
786 } else if n.type_ == XML_ENTITY_DECL as c_int {
787 crate::xml::entities::free_entity(node as *mut _xmlEntity);
788 return;
789 }
790
791 crate::abi::data_globals::deregister_node_hook(node);
794
795 let is_element = n.type_ == XML_ELEMENT_NODE as c_int;
800 if is_element && !n.properties.is_null() {
801 free_prop_list(n.properties);
802 }
803
804 if is_element && !n.nsDef.is_null() {
805 free_ns_list(n.nsDef);
806 }
807
808 if !n.name.is_null() {
810 allocator::xmlFreeImpl(n.name as *mut c_void);
811 }
812
813 if !n.content.is_null() {
818 let node_type = n.type_;
819 if node_type == XML_TEXT_NODE as c_int
820 || node_type == XML_CDATA_SECTION_NODE as c_int
821 || node_type == XML_COMMENT_NODE as c_int
822 || node_type == XML_PI_NODE as c_int
823 {
824 let inline_addr = std::ptr::addr_of_mut!((*node).properties) as *const c_void;
825 if n.content as *const c_void != inline_addr {
826 allocator::xmlFreeImpl(n.content as *mut c_void);
827 }
828 }
829 }
830
831 allocator::xmlFreeImpl(node as *mut c_void);
832}
833
834pub unsafe fn free_node_list(node: *mut _xmlNode) {
853 let mut cur = node;
854 while !cur.is_null() {
855 let next = unsafe { (*cur).next };
856 let t = unsafe { (*cur).type_ };
857
858 if t == XML_DTD_NODE as c_int {
859 unsafe {
861 (*cur).prev = ptr::null_mut();
862 (*cur).next = ptr::null_mut();
863 }
864 cur = next;
865 continue;
866 }
867
868 if t != XML_ENTITY_REF_NODE as c_int && !unsafe { (*cur).children }.is_null() {
871 free_node_list(unsafe { (*cur).children });
872 }
873
874 free_node(cur);
875 cur = next;
876 }
877}
878
879unsafe fn free_prop_list(prop: *mut _xmlAttr) {
885 let mut cur = prop;
886 while !cur.is_null() {
887 let next = unsafe { (*cur).next };
888 free_prop(cur);
889 cur = next;
890 }
891}
892
893unsafe fn free_prop(prop: *mut _xmlAttr) {
899 if prop.is_null() {
900 return;
901 }
902
903 if !unsafe { (*prop).children }.is_null() {
905 free_node_list(unsafe { (*prop).children });
906 }
907
908 if !unsafe { (*prop).name }.is_null() {
910 allocator::xmlFreeImpl(unsafe { (*prop).name } as *mut c_void);
911 }
912
913 allocator::xmlFreeImpl(prop as *mut c_void);
914}
915
916unsafe fn free_ns_list(ns: *mut _xmlNs) {
922 let mut cur = ns;
923 while !cur.is_null() {
924 let next = unsafe { (*cur).next };
925 free_ns(cur);
926 cur = next;
927 }
928}
929
930unsafe fn free_ns(ns: *mut _xmlNs) {
936 if ns.is_null() {
937 return;
938 }
939
940 if !unsafe { (*ns).href }.is_null() {
942 allocator::xmlFreeImpl(unsafe { (*ns).href } as *mut c_void);
943 }
944 if !unsafe { (*ns).prefix }.is_null() {
945 allocator::xmlFreeImpl(unsafe { (*ns).prefix } as *mut c_void);
946 }
947
948 allocator::xmlFreeImpl(ns as *mut c_void);
949}
950
951pub unsafe fn copy_node(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
966 if node.is_null() {
967 return ptr::null_mut();
968 }
969
970 let n = unsafe { &*node };
971
972 let new_node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
973 if new_node.is_null() {
974 return ptr::null_mut();
975 }
976
977 unsafe {
978 (*new_node).type_ = n.type_;
979 (*new_node).name = dup_xml_str(n.name);
980 if n.type_ == XML_ELEMENT_NODE as c_int {
984 (*new_node).line = n.line;
985 }
986 (*new_node).extra = n.extra;
987 (*new_node).psvi = n.psvi;
988 (*new_node)._private = n._private;
989
990 (*new_node).ns = n.ns;
992
993 let is_element = n.type_ == XML_ELEMENT_NODE as c_int;
996 if is_element && !n.nsDef.is_null() {
997 (*new_node).nsDef = copy_ns_list(n.nsDef);
998 }
999
1000 let node_type = n.type_;
1002 if (node_type == XML_TEXT_NODE as c_int
1003 || node_type == XML_CDATA_SECTION_NODE as c_int
1004 || node_type == XML_COMMENT_NODE as c_int
1005 || node_type == XML_PI_NODE as c_int)
1006 && !n.content.is_null()
1007 {
1008 (*new_node).content = dup_xml_str(n.content);
1009 }
1010
1011 if is_element && !n.properties.is_null() {
1013 (*new_node).properties = copy_prop_list(n.properties);
1014 let mut prop = (*new_node).properties;
1016 while !prop.is_null() {
1017 (*prop).parent = new_node;
1018 if !(*prop).children.is_null() {
1019 propagate_doc((*prop).children, (*new_node).doc);
1020 }
1021 prop = (*prop).next;
1022 }
1023 }
1024
1025 if recursive != 0 && !n.children.is_null() {
1028 (*new_node).children = copy_node_list(n.children, recursive);
1029 if !(*new_node).children.is_null() {
1030 let mut child = (*new_node).children;
1031 let mut last_child = child;
1032 while !child.is_null() {
1033 (*child).parent = new_node;
1034 (*child).doc = (*new_node).doc;
1035 propagate_doc(child, (*new_node).doc);
1036 if (*child).next.is_null() {
1037 last_child = child;
1038 }
1039 child = (*child).next;
1040 }
1041 (*new_node).last = last_child;
1042 }
1043 }
1044 }
1045
1046 new_node
1047}
1048
1049unsafe fn copy_node_list(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
1061 if node.is_null() {
1062 return ptr::null_mut();
1063 }
1064
1065 let n = unsafe { &*node };
1066 let new_node = copy_node(node, recursive);
1067 if new_node.is_null() {
1068 return ptr::null_mut();
1069 }
1070
1071 let mut prev = new_node;
1072 let mut cur = n.next;
1073
1074 while !cur.is_null() {
1075 let new_cur = copy_node(cur, recursive);
1076 if new_cur.is_null() {
1077 break;
1078 }
1079 unsafe {
1080 (*prev).next = new_cur;
1081 (*new_cur).prev = prev;
1082 }
1083 prev = new_cur;
1084 cur = unsafe { (*cur).next };
1085 }
1086
1087 new_node
1088}
1089
1090unsafe fn copy_ns_list(ns: *const _xmlNs) -> *mut _xmlNs {
1100 if ns.is_null() {
1101 return ptr::null_mut();
1102 }
1103
1104 let n = unsafe { &*ns };
1105 let new_ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
1106 if new_ns.is_null() {
1107 return ptr::null_mut();
1108 }
1109
1110 unsafe {
1111 (*new_ns).type_ = n.type_;
1112 (*new_ns).href = dup_xml_str(n.href);
1113 (*new_ns).prefix = dup_xml_str(n.prefix);
1114 (*new_ns)._private = n._private;
1115 }
1116
1117 let mut prev = new_ns;
1118 let mut cur = n.next;
1119
1120 while !cur.is_null() {
1121 let c = unsafe { &*cur };
1122 let new_cur = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
1123 if new_cur.is_null() {
1124 break;
1125 }
1126 unsafe {
1127 (*new_cur).type_ = c.type_;
1128 (*new_cur).href = dup_xml_str(c.href);
1129 (*new_cur).prefix = dup_xml_str(c.prefix);
1130 (*new_cur)._private = c._private;
1131 (*prev).next = new_cur;
1132 }
1133 prev = new_cur;
1134 cur = c.next;
1135 }
1136
1137 new_ns
1138}
1139
1140unsafe fn copy_prop_list(prop: *const _xmlAttr) -> *mut _xmlAttr {
1151 if prop.is_null() {
1152 return ptr::null_mut();
1153 }
1154
1155 let p = unsafe { &*prop };
1156 let new_prop = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
1157 if new_prop.is_null() {
1158 return ptr::null_mut();
1159 }
1160
1161 unsafe {
1162 (*new_prop).type_ = p.type_;
1163 (*new_prop).name = dup_xml_str(p.name);
1164 (*new_prop).ns = p.ns;
1165 (*new_prop).atype = p.atype;
1166
1167 if !p.children.is_null() {
1169 (*new_prop).children = copy_node_list(p.children, 1);
1170 if !(*new_prop).children.is_null() {
1171 (*(*new_prop).children).parent = new_prop as *mut _xmlNode;
1172 }
1173 }
1174 }
1175
1176 let mut prev = new_prop;
1177 let mut cur = p.next;
1178
1179 while !cur.is_null() {
1180 let c = unsafe { &*cur };
1181 let new_cur = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
1182 if new_cur.is_null() {
1183 break;
1184 }
1185 unsafe {
1186 (*new_cur).type_ = c.type_;
1187 (*new_cur).name = dup_xml_str(c.name);
1188 (*new_cur).ns = c.ns;
1189 (*new_cur).atype = c.atype;
1190
1191 if !c.children.is_null() {
1192 (*new_cur).children = copy_node_list(c.children, 1);
1193 if !(*new_cur).children.is_null() {
1194 (*(*new_cur).children).parent = new_cur as *mut _xmlNode;
1195 }
1196 }
1197
1198 (*prev).next = new_cur;
1199 }
1200 prev = new_cur;
1201 cur = c.next;
1202 }
1203
1204 new_prop
1205}
1206
1207unsafe fn propagate_doc(node: *mut _xmlNode, doc: *mut _xmlDoc) {
1218 let mut cur = node;
1219 while !cur.is_null() {
1220 unsafe {
1221 (*cur).doc = doc;
1222
1223 if (*cur).type_ == XML_ELEMENT_NODE as c_int {
1227 let mut prop = (*cur).properties;
1228 while !prop.is_null() {
1229 (*prop).doc = doc;
1230 if !(*prop).children.is_null() {
1231 propagate_doc((*prop).children, doc);
1232 }
1233 prop = (*prop).next;
1234 }
1235 }
1236
1237 if !(*cur).children.is_null() {
1239 propagate_doc((*cur).children, doc);
1240 }
1241 }
1242 cur = unsafe { (*cur).next };
1243 }
1244}
1245
1246pub unsafe fn unlink_node(node: *mut _xmlNode) {
1262 if node.is_null() {
1263 return;
1264 }
1265
1266 let n = unsafe { &mut *node };
1267
1268 let prev = n.prev;
1270 let next = n.next;
1271
1272 if !prev.is_null() {
1273 unsafe { (*prev).next = next };
1274 }
1275 if !next.is_null() {
1276 unsafe { (*next).prev = prev };
1277 }
1278
1279 let parent = n.parent;
1281 if !parent.is_null() {
1282 if unsafe { (*parent).children } == node {
1283 unsafe { (*parent).children = next };
1284 }
1285 if unsafe { (*parent).last } == node {
1286 unsafe { (*parent).last = prev };
1287 }
1288 }
1289
1290 let doc = n.doc;
1292 if !doc.is_null() && !parent.is_null() {
1293 }
1295 if !doc.is_null() && parent.is_null() {
1296 if unsafe { (*doc).children } == node {
1298 unsafe { (*doc).children = next };
1299 }
1300 if unsafe { (*doc).last } == node {
1301 unsafe { (*doc).last = prev };
1302 }
1303 }
1304
1305 n.parent = ptr::null_mut();
1307 n.prev = ptr::null_mut();
1308 n.next = ptr::null_mut();
1309}
1310
1311pub unsafe fn add_child(parent: *mut _xmlNode, cur: *mut _xmlNode) -> *mut _xmlNode {
1327 if parent.is_null() || cur.is_null() {
1328 return ptr::null_mut();
1329 }
1330
1331 let p = unsafe { &mut *parent };
1332 let c = unsafe { &mut *cur };
1333
1334 if !c.parent.is_null() || !c.prev.is_null() || !c.next.is_null() {
1336 unlink_node(cur);
1337 }
1338
1339 c.parent = parent;
1341
1342 if p.children.is_null() {
1343 p.children = cur;
1345 p.last = cur;
1346 c.prev = ptr::null_mut();
1347 c.next = ptr::null_mut();
1348 } else {
1349 c.prev = p.last;
1351 c.next = ptr::null_mut();
1352 if !p.last.is_null() {
1353 unsafe { (*p.last).next = cur };
1354 }
1355 p.last = cur;
1356 }
1357
1358 let doc = if !p.doc.is_null() {
1360 p.doc
1361 } else {
1362 ptr::null_mut()
1363 };
1364 if !doc.is_null() && c.doc != doc {
1365 propagate_doc(cur, doc);
1366 }
1367
1368 cur
1369}
1370
1371pub unsafe fn add_sibling(cur: *mut _xmlNode, elem: *mut _xmlNode) -> *mut _xmlNode {
1387 if cur.is_null() || elem.is_null() {
1388 return ptr::null_mut();
1389 }
1390
1391 let c = unsafe { &mut *cur };
1392
1393 let e = unsafe { &mut *elem };
1395 if !e.parent.is_null() || !e.prev.is_null() || !e.next.is_null() {
1396 unlink_node(elem);
1397 }
1398
1399 e.parent = c.parent;
1401
1402 e.prev = cur;
1404 e.next = c.next;
1405
1406 if !c.next.is_null() {
1407 unsafe { (*c.next).prev = elem };
1408 }
1409 c.next = elem;
1410
1411 let parent = c.parent;
1413 if !parent.is_null() && unsafe { (*parent).last } == cur {
1414 unsafe { (*parent).last = elem };
1415 }
1416
1417 if !c.doc.is_null() && e.doc != c.doc {
1419 propagate_doc(elem, c.doc);
1420 }
1421
1422 elem
1423}
1424
1425pub unsafe fn add_sibling_before(cur: *mut _xmlNode, elem: *mut _xmlNode) -> *mut _xmlNode {
1441 if cur.is_null() || elem.is_null() {
1442 return ptr::null_mut();
1443 }
1444
1445 let c = unsafe { &mut *cur };
1446
1447 let e = unsafe { &mut *elem };
1449 if !e.parent.is_null() || !e.prev.is_null() || !e.next.is_null() {
1450 unlink_node(elem);
1451 }
1452
1453 e.parent = c.parent;
1455
1456 e.prev = c.prev;
1458 e.next = cur;
1459
1460 if !c.prev.is_null() {
1461 unsafe { (*c.prev).next = elem };
1462 }
1463 c.prev = elem;
1464
1465 let parent = c.parent;
1467 if !parent.is_null() && unsafe { (*parent).children } == cur {
1468 unsafe { (*parent).children = elem };
1469 }
1470
1471 let doc = c.doc;
1473 if !doc.is_null() && parent.is_null() && unsafe { (*doc).children } == cur {
1474 unsafe { (*doc).children = elem };
1475 }
1476
1477 if !c.doc.is_null() && e.doc != c.doc {
1479 propagate_doc(elem, c.doc);
1480 }
1481
1482 elem
1483}
1484
1485pub unsafe fn new_child(
1500 parent: *mut _xmlNode,
1501 ns: *mut _xmlNs,
1502 name: *const xmlChar,
1503) -> *mut _xmlNode {
1504 let node = new_node(ns, name);
1505 if node.is_null() {
1506 return ptr::null_mut();
1507 }
1508
1509 if !parent.is_null() {
1510 add_child(parent, node);
1511 }
1512
1513 node
1514}
1515
1516pub unsafe fn new_text(content: *const xmlChar) -> *mut _xmlNode {
1535 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1536 if node.is_null() {
1537 return ptr::null_mut();
1538 }
1539
1540 unsafe {
1541 (*node).type_ = XML_TEXT_NODE as c_int;
1542 (*node).name = dup_xml_str(b"text\0" as *const u8 as *const xmlChar);
1543 (*node).content = if content.is_null() {
1544 let empty = allocator::xmlMallocImpl(1) as *mut xmlChar;
1545 if !empty.is_null() {
1546 *empty = 0;
1547 }
1548 empty
1549 } else {
1550 dup_xml_str(content)
1551 };
1552 (*node).line = 0;
1553 }
1554
1555 crate::abi::data_globals::register_node_hook(node);
1558
1559 node
1560}
1561
1562pub unsafe fn new_comment(content: *const xmlChar) -> *mut _xmlNode {
1576 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1577 if node.is_null() {
1578 return ptr::null_mut();
1579 }
1580
1581 unsafe {
1582 (*node).type_ = XML_COMMENT_NODE as c_int;
1583 (*node).name = dup_xml_str(b"comment\0" as *const u8 as *const xmlChar);
1584 (*node).content = dup_xml_str(content);
1585 (*node).line = 0;
1586 }
1587
1588 crate::abi::data_globals::register_node_hook(node);
1591
1592 node
1593}
1594
1595pub unsafe fn new_pi(name: *const xmlChar, content: *const xmlChar) -> *mut _xmlNode {
1610 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1611 if node.is_null() {
1612 return ptr::null_mut();
1613 }
1614
1615 unsafe {
1616 (*node).type_ = XML_PI_NODE as c_int;
1617 (*node).name = dup_xml_str(name);
1618 (*node).content = dup_xml_str(content);
1619 (*node).line = 0;
1620 }
1621
1622 crate::abi::data_globals::register_node_hook(node);
1625
1626 node
1627}
1628
1629pub unsafe fn new_cdata_block(
1645 doc: *mut _xmlDoc,
1646 content: *const xmlChar,
1647 len: c_int,
1648) -> *mut _xmlNode {
1649 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1650 if node.is_null() {
1651 return ptr::null_mut();
1652 }
1653
1654 unsafe {
1655 (*node).type_ = XML_CDATA_SECTION_NODE as c_int;
1656 (*node).doc = doc;
1659
1660 if !content.is_null() && len > 0 {
1661 (*node).content = allocator::xmlMallocImpl((len + 1) as usize) as *mut xmlChar;
1662 if !(*node).content.is_null() {
1663 ptr::copy_nonoverlapping(content, (*node).content, len as usize);
1664 *((*node).content.add(len as usize)) = 0;
1665 }
1666 } else {
1667 let empty = allocator::xmlMallocImpl(1) as *mut xmlChar;
1668 if !empty.is_null() {
1669 *empty = 0;
1670 }
1671 (*node).content = empty;
1672 }
1673
1674 (*node).line = 0;
1675 }
1676
1677 node
1678}
1679
1680pub unsafe fn new_ns(
1704 node: *mut _xmlNode,
1705 href: *const xmlChar,
1706 prefix: *const xmlChar,
1707) -> *mut _xmlNs {
1708 let ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
1709 if ns.is_null() {
1710 return ptr::null_mut();
1711 }
1712
1713 unsafe {
1714 (*ns).type_ = XML_LOCAL_NAMESPACE as c_int;
1715 (*ns).href = dup_xml_str(href);
1716 (*ns).prefix = dup_xml_str(prefix);
1717 (*ns).context = node as *mut _xmlDoc;
1718
1719 if !node.is_null() {
1721 let n = &mut *node;
1722 if n.nsDef.is_null() {
1723 n.nsDef = ns;
1724 } else {
1725 let mut last = n.nsDef;
1727 while !(*last).next.is_null() {
1728 last = (*last).next;
1729 }
1730 (*last).next = ns;
1731 }
1732 }
1733 }
1734
1735 ns
1736}
1737
1738pub unsafe fn set_ns(node: *mut _xmlNode, ns: *mut _xmlNs) {
1751 if node.is_null() {
1752 return;
1753 }
1754 unsafe {
1755 (*node).ns = ns;
1756 }
1757}
1758
1759pub unsafe fn get_ns_list(_doc: *mut _xmlDoc, node: *mut _xmlNode) -> *mut *mut _xmlNs {
1775 if node.is_null() {
1779 return ptr::null_mut();
1780 }
1781
1782 let mut ns_ptrs: Vec<*mut _xmlNs> = Vec::new();
1784 let mut cur = node;
1785
1786 while !cur.is_null() {
1787 let n = unsafe { &*cur };
1788 let mut ns_def = n.nsDef;
1789 while !ns_def.is_null() {
1790 let ns = unsafe { &*ns_def };
1792 let mut found = false;
1793 for &existing in &ns_ptrs {
1794 if existing == ns_def {
1795 found = true;
1796 break;
1797 }
1798 let e = unsafe { &*existing };
1799 if !ns.href.is_null() && !e.href.is_null() {
1800 let href_match =
1801 unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, e.href) != 0 };
1802 if href_match {
1803 if ns.prefix.is_null() && e.prefix.is_null() {
1804 found = true;
1805 break;
1806 }
1807 if !ns.prefix.is_null() && !e.prefix.is_null() {
1808 let prefix_match = unsafe {
1809 crate::abi::exports_xml2::xmlStrEqual(ns.prefix, e.prefix) != 0
1810 };
1811 if prefix_match {
1812 found = true;
1813 break;
1814 }
1815 }
1816 }
1817 }
1818 }
1819 if !found {
1820 ns_ptrs.push(ns_def);
1821 }
1822 ns_def = unsafe { (*ns_def).next };
1823 }
1824 cur = n.parent;
1825 }
1826
1827 if ns_ptrs.is_empty() {
1828 return ptr::null_mut();
1829 }
1830
1831 let arr = allocator::xmlMallocImpl((ns_ptrs.len() + 1) * size_of::<*mut _xmlNs>())
1833 as *mut *mut _xmlNs;
1834 if arr.is_null() {
1835 return ptr::null_mut();
1836 }
1837
1838 for (i, ns) in ns_ptrs.iter().enumerate() {
1839 unsafe { *arr.add(i) = *ns };
1840 }
1841 unsafe { *arr.add(ns_ptrs.len()) = ptr::null_mut() };
1842
1843 arr
1844}
1845
1846pub unsafe fn search_ns(
1863 _doc: *mut _xmlDoc,
1864 node: *mut _xmlNode,
1865 name_space: *const xmlChar,
1866) -> *mut _xmlNs {
1867 if node.is_null() {
1868 return ptr::null_mut();
1869 }
1870
1871 let mut cur = node;
1872 while !cur.is_null() {
1873 let n = unsafe { &*cur };
1874 let mut ns_def = n.nsDef;
1875 while !ns_def.is_null() {
1876 let ns = unsafe { &*ns_def };
1877 let match_prefix = if name_space.is_null() {
1878 ns.prefix.is_null()
1880 } else {
1881 !ns.prefix.is_null()
1882 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.prefix, name_space) != 0 }
1883 };
1884 if match_prefix {
1885 return ns_def;
1886 }
1887 ns_def = unsafe { (*ns_def).next };
1888 }
1889 cur = n.parent;
1890 }
1891
1892 ptr::null_mut()
1893}
1894
1895pub unsafe fn search_ns_by_href(
1911 _doc: *mut _xmlDoc,
1912 node: *mut _xmlNode,
1913 href: *const xmlChar,
1914) -> *mut _xmlNs {
1915 if node.is_null() || href.is_null() {
1916 return ptr::null_mut();
1917 }
1918
1919 let mut cur = node;
1920 while !cur.is_null() {
1921 let n = unsafe { &*cur };
1922 let mut ns_def = n.nsDef;
1923 while !ns_def.is_null() {
1924 let ns = unsafe { &*ns_def };
1925 if !ns.href.is_null()
1926 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, href) != 0 }
1927 {
1928 return ns_def;
1929 }
1930 ns_def = unsafe { (*ns_def).next };
1931 }
1932 cur = n.parent;
1933 }
1934
1935 ptr::null_mut()
1936}
1937
1938pub unsafe fn set_prop(
1962 node: *mut _xmlNode,
1963 name: *const xmlChar,
1964 value: *const xmlChar,
1965) -> *mut _xmlAttr {
1966 if node.is_null() || name.is_null() {
1967 return ptr::null_mut();
1968 }
1969
1970 let n = unsafe { &mut *node };
1971
1972 let mut existing = n.properties;
1974 while !existing.is_null() {
1975 let attr = unsafe { &*existing };
1976 if !attr.name.is_null()
1977 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1978 {
1979 if !attr.children.is_null() {
1982 free_node_list(attr.children);
1983 let attr_mut = existing;
1985 unsafe { (*attr_mut).children = ptr::null_mut() };
1986 unsafe { (*attr_mut).last = ptr::null_mut() };
1987 }
1988 if !value.is_null() {
1990 let text = new_text(value);
1991 if !text.is_null() {
1992 let attr_mut = existing;
1993 unsafe {
1994 (*attr_mut).children = text;
1995 (*attr_mut).last = text;
1996 (*text).parent = existing as *mut _xmlNode;
1997 (*text).doc = n.doc;
1998 }
1999 }
2000 }
2001 return existing;
2002 }
2003 existing = unsafe { (*existing).next };
2004 }
2005
2006 let attr = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
2008 if attr.is_null() {
2009 return ptr::null_mut();
2010 }
2011
2012 unsafe {
2013 (*attr).type_ = XML_ATTRIBUTE_NODE as c_int;
2014 (*attr).name = dup_xml_str(name);
2015 (*attr).parent = node;
2016 (*attr).doc = n.doc;
2017 if !value.is_null() {
2022 let text = new_text(value);
2023 if !text.is_null() {
2024 (*attr).children = text;
2025 (*attr).last = text;
2026 (*text).parent = attr as *mut _xmlNode;
2027 (*text).doc = n.doc;
2028 }
2029 }
2030
2031 if n.properties.is_null() {
2033 n.properties = attr;
2034 } else {
2035 let mut last = n.properties;
2036 while !(*last).next.is_null() {
2037 last = (*last).next;
2038 }
2039 (*last).next = attr;
2040 (*attr).prev = last;
2041 }
2042 }
2043
2044 attr
2045}
2046
2047pub unsafe fn get_prop(node: *mut _xmlNode, name: *const xmlChar) -> *mut xmlChar {
2063 if node.is_null() || name.is_null() {
2064 return ptr::null_mut();
2065 }
2066
2067 let n = unsafe { &*node };
2068 let mut cur = n.properties;
2069
2070 while !cur.is_null() {
2071 let attr = unsafe { &*cur };
2072 if !attr.name.is_null()
2073 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
2074 {
2075 if !attr.children.is_null() {
2077 let text = unsafe { &*attr.children };
2078 if text.type_ == XML_TEXT_NODE as c_int && !text.content.is_null() {
2079 return dup_xml_str(text.content);
2080 }
2081 }
2082 return dup_xml_str(b"\0" as *const u8 as *const xmlChar);
2083 }
2084 cur = unsafe { (*cur).next };
2085 }
2086
2087 ptr::null_mut()
2088}
2089
2090pub unsafe fn get_ns_prop(
2106 node: *mut _xmlNode,
2107 name: *const xmlChar,
2108 _name_space: *const xmlChar,
2109) -> *mut xmlChar {
2110 get_prop(node, name)
2113}
2114
2115pub unsafe fn set_ns_prop(
2130 node: *mut _xmlNode,
2131 _ns: *mut _xmlNs,
2132 name: *const xmlChar,
2133 value: *const xmlChar,
2134) -> *mut _xmlAttr {
2135 set_prop(node, name, value)
2137}
2138
2139pub unsafe fn remove_prop(attr: *mut _xmlAttr) -> c_int {
2154 if attr.is_null() {
2155 return -1;
2156 }
2157
2158 let a = unsafe { &mut *attr };
2159
2160 let parent = a.parent;
2162 if !parent.is_null() {
2163 let p = unsafe { &mut *parent };
2164 if p.properties == attr {
2165 p.properties = a.next;
2166 }
2167 }
2168
2169 if !a.prev.is_null() {
2171 unsafe { (*a.prev).next = a.next };
2172 }
2173 if !a.next.is_null() {
2174 unsafe { (*a.next).prev = a.prev };
2175 }
2176
2177 if !a.children.is_null() {
2179 free_node_list(a.children);
2180 }
2181
2182 if !a.name.is_null() {
2184 allocator::xmlFreeImpl(a.name as *mut c_void);
2185 }
2186
2187 allocator::xmlFreeImpl(attr as *mut c_void);
2188 0
2189}
2190
2191pub unsafe fn has_prop(node: *mut _xmlNode, name: *const xmlChar) -> *mut _xmlAttr {
2199 if node.is_null() || name.is_null() {
2200 return ptr::null_mut();
2201 }
2202 let mut cur = unsafe { (*node).properties };
2203 while !cur.is_null() {
2204 let attr = unsafe { &*cur };
2205 if !attr.name.is_null()
2206 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
2207 && attr.ns.is_null()
2208 {
2209 return cur;
2210 }
2211 cur = unsafe { (*cur).next };
2212 }
2213 ptr::null_mut()
2214}
2215
2216pub unsafe fn has_ns_prop(
2226 node: *mut _xmlNode,
2227 name: *const xmlChar,
2228 name_space: *const xmlChar,
2229) -> *mut _xmlAttr {
2230 if node.is_null() || name.is_null() {
2231 return ptr::null_mut();
2232 }
2233 let mut cur = unsafe { (*node).properties };
2234 while !cur.is_null() {
2235 let attr = unsafe { &*cur };
2236 if !attr.name.is_null()
2237 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
2238 {
2239 if name_space.is_null() {
2240 if attr.ns.is_null() {
2241 return cur;
2242 }
2243 } else if !attr.ns.is_null()
2244 && !(*attr.ns).href.is_null()
2245 && unsafe {
2246 crate::abi::exports_xml2::xmlStrEqual((*attr.ns).href, name_space) != 0
2247 }
2248 {
2249 return cur;
2250 }
2251 }
2252 cur = unsafe { (*cur).next };
2253 }
2254 ptr::null_mut()
2255}
2256
2257pub unsafe fn unset_prop(node: *mut _xmlNode, name: *const xmlChar) -> c_int {
2266 let attr = unsafe { has_prop(node, name) };
2267 if attr.is_null() {
2268 return -1;
2269 }
2270 unsafe { remove_prop(attr) }
2271}
2272
2273pub unsafe fn unset_ns_prop(
2281 node: *mut _xmlNode,
2282 name: *const xmlChar,
2283 name_space: *const xmlChar,
2284) -> c_int {
2285 let attr = unsafe { has_ns_prop(node, name, name_space) };
2286 if attr.is_null() {
2287 return -1;
2288 }
2289 unsafe { remove_prop(attr) }
2290}
2291
2292pub unsafe fn first_element_child(node: *mut _xmlNode) -> *mut _xmlNode {
2299 if node.is_null() {
2300 return ptr::null_mut();
2301 }
2302 let mut cur = unsafe { (*node).children };
2303 while !cur.is_null() {
2304 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2305 return cur;
2306 }
2307 cur = unsafe { (*cur).next };
2308 }
2309 ptr::null_mut()
2310}
2311
2312pub unsafe fn last_element_child(node: *mut _xmlNode) -> *mut _xmlNode {
2319 if node.is_null() {
2320 return ptr::null_mut();
2321 }
2322 let mut cur = unsafe { (*node).last };
2323 while !cur.is_null() {
2324 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2325 return cur;
2326 }
2327 cur = unsafe { (*cur).prev };
2328 }
2329 ptr::null_mut()
2330}
2331
2332pub unsafe fn next_element_sibling(node: *mut _xmlNode) -> *mut _xmlNode {
2339 if node.is_null() {
2340 return ptr::null_mut();
2341 }
2342 let mut cur = unsafe { (*node).next };
2343 while !cur.is_null() {
2344 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2345 return cur;
2346 }
2347 cur = unsafe { (*cur).next };
2348 }
2349 ptr::null_mut()
2350}
2351
2352pub unsafe fn previous_element_sibling(node: *mut _xmlNode) -> *mut _xmlNode {
2359 if node.is_null() {
2360 return ptr::null_mut();
2361 }
2362 let mut cur = unsafe { (*node).prev };
2363 while !cur.is_null() {
2364 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2365 return cur;
2366 }
2367 cur = unsafe { (*cur).prev };
2368 }
2369 ptr::null_mut()
2370}
2371
2372pub unsafe fn child_element_count(node: *mut _xmlNode) -> c_ulong {
2379 if node.is_null() {
2380 return 0;
2381 }
2382 let mut cur = unsafe { (*node).children };
2383 let mut count: c_ulong = 0;
2384 while !cur.is_null() {
2385 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2386 count += 1;
2387 }
2388 cur = unsafe { (*cur).next };
2389 }
2390 count
2391}
2392
2393pub unsafe fn text_concat(node: *mut _xmlNode, str: *const xmlChar, num: c_int) -> c_int {
2402 if node.is_null() || str.is_null() || num <= 0 {
2403 return -1;
2404 }
2405 let cur = unsafe { &mut *node };
2406 if cur.content.is_null() {
2407 let p = unsafe { allocator::xmlMallocImpl(num as usize + 1) as *mut xmlChar };
2408 if p.is_null() {
2409 return -1;
2410 }
2411 unsafe {
2412 ptr::copy_nonoverlapping(str, p, num as usize);
2413 *p.add(num as usize) = 0;
2414 }
2415 cur.content = p;
2416 return 0;
2417 }
2418 let old_len = unsafe { crate::xml::string::xml_strlen(cur.content) };
2419 let p = unsafe {
2420 allocator::xmlReallocImpl(cur.content as *mut c_void, old_len + num as usize + 1)
2421 as *mut xmlChar
2422 };
2423 if p.is_null() {
2424 return -1;
2425 }
2426 unsafe {
2427 ptr::copy_nonoverlapping(str, p.add(old_len), num as usize);
2428 *p.add(old_len + num as usize) = 0;
2429 }
2430 cur.content = p;
2431 0
2432}
2433
2434pub unsafe fn text_merge(text: *mut _xmlNode, ntext: *mut _xmlNode) -> *mut _xmlNode {
2442 if text.is_null() || ntext.is_null() {
2443 return ptr::null_mut();
2444 }
2445 if unsafe { (*ntext).content.is_null() } {
2446 unsafe { free_node(ntext) };
2447 return text;
2448 }
2449 let num = unsafe { crate::xml::string::xml_strlen((*ntext).content) };
2450 if unsafe { text_concat(text, (*ntext).content, num as c_int) } != 0 {
2451 return ptr::null_mut();
2452 }
2453 unsafe { free_node(ntext) };
2454 text
2455}
2456
2457pub const fn get_int_subset(doc: *const _xmlDoc) -> *mut _xmlDtd {
2469 if doc.is_null() {
2470 return ptr::null_mut();
2471 }
2472 let d = unsafe { &*doc };
2473 d.intSubset
2474}
2475
2476pub unsafe fn new_dtd(
2493 doc: *mut _xmlDoc,
2494 name: *const xmlChar,
2495 ExternalID: *const xmlChar,
2496 SystemID: *const xmlChar,
2497) -> *mut _xmlDtd {
2498 let dtd = allocator::xmlMallocZero(size_of::<_xmlDtd>() as usize) as *mut _xmlDtd;
2499 if dtd.is_null() {
2500 return ptr::null_mut();
2501 }
2502
2503 unsafe {
2504 (*dtd).type_ = XML_DTD_NODE as c_int;
2505 (*dtd).name = dup_xml_str(name);
2506 (*dtd).ExternalID = dup_xml_str(ExternalID);
2507 (*dtd).SystemID = dup_xml_str(SystemID);
2508 (*dtd).parent = doc;
2509 (*dtd).doc = doc;
2510
2511 if !doc.is_null() && (*doc).intSubset.is_null() {
2517 (*doc).intSubset = dtd;
2518 }
2519 }
2520
2521 dtd
2522}
2523
2524unsafe fn free_dtd(dtd: *mut _xmlDtd) {
2530 if dtd.is_null() {
2531 return;
2532 }
2533
2534 let _d = unsafe { &mut *dtd };
2535 let d = &mut *dtd;
2536
2537 if !d.children.is_null() {
2544 let mut c = d.children;
2545 while !c.is_null() {
2546 let next = (*c).next;
2547 let t = (*c).type_;
2548 if t != XML_ELEMENT_DECL as c_int
2549 && t != XML_ATTRIBUTE_DECL as c_int
2550 && t != XML_ENTITY_DECL as c_int
2551 {
2552 unlink_node_internal(c, ptr::null_mut());
2553 free_node(c);
2554 }
2555 c = next;
2556 }
2557 }
2558
2559 if !d.name.is_null() {
2561 allocator::xmlFreeImpl(d.name as *mut c_void);
2562 }
2563 if !d.ExternalID.is_null() {
2564 allocator::xmlFreeImpl(d.ExternalID as *mut c_void);
2565 }
2566 if !d.SystemID.is_null() {
2567 allocator::xmlFreeImpl(d.SystemID as *mut c_void);
2568 }
2569
2570 unsafe extern "C" fn free_notation_wrapper(payload: *mut c_void, _name: *mut u8) {
2580 crate::xml::dtd::free_notation(payload as *mut _xmlNotation);
2581 }
2582 unsafe extern "C" fn free_element_wrapper(payload: *mut c_void, _name: *mut u8) {
2591 crate::xml::dtd::free_element(payload as *mut _xmlElement);
2592 }
2593 unsafe extern "C" fn free_attribute_wrapper(payload: *mut c_void, _name: *mut u8) {
2602 crate::xml::dtd::free_attribute(payload as *mut _xmlAttribute);
2603 }
2604 unsafe extern "C" fn free_entity_wrapper(payload: *mut c_void, _name: *mut u8) {
2613 crate::xml::entities::free_entity(payload as *mut _xmlEntity);
2614 }
2615
2616 if !d.notations.is_null() {
2617 crate::xml::hash::hash_free(
2618 d.notations as *mut crate::xml::hash::HashTable,
2619 Some(free_notation_wrapper),
2620 );
2621 d.notations = ptr::null_mut();
2622 }
2623 if !d.elements.is_null() {
2624 crate::xml::hash::hash_free(
2625 d.elements as *mut crate::xml::hash::HashTable,
2626 Some(free_element_wrapper),
2627 );
2628 d.elements = ptr::null_mut();
2629 }
2630 if !d.attributes.is_null() {
2631 crate::xml::hash::hash_free(
2632 d.attributes as *mut crate::xml::hash::HashTable,
2633 Some(free_attribute_wrapper),
2634 );
2635 d.attributes = ptr::null_mut();
2636 }
2637 if !d.entities.is_null() {
2638 crate::xml::hash::hash_free(
2639 d.entities as *mut crate::xml::hash::HashTable,
2640 Some(free_entity_wrapper),
2641 );
2642 d.entities = ptr::null_mut();
2643 }
2644 if !d.pentities.is_null() {
2645 crate::xml::hash::hash_free(
2646 d.pentities as *mut crate::xml::hash::HashTable,
2647 Some(free_entity_wrapper),
2648 );
2649 d.pentities = ptr::null_mut();
2650 }
2651
2652 allocator::xmlFreeImpl(dtd as *mut c_void);
2653}
2654
2655pub unsafe fn new_entity(
2675 _doc: *mut _xmlDoc,
2676 name: *const xmlChar,
2677 etype: c_int,
2678 ExternalID: *const xmlChar,
2679 SystemID: *const xmlChar,
2680 content: *const xmlChar,
2681) -> *mut _xmlEntity {
2682 let entity = allocator::xmlMallocZero(size_of::<_xmlEntity>() as usize) as *mut _xmlEntity;
2683 if entity.is_null() {
2684 return ptr::null_mut();
2685 }
2686
2687 unsafe {
2688 (*entity).type_ = XML_ENTITY_DECL as c_int;
2689 (*entity).name = dup_xml_str(name);
2690 (*entity).etype = etype;
2691 (*entity).ExternalID = dup_xml_str(ExternalID);
2692 (*entity).SystemID = dup_xml_str(SystemID);
2693 (*entity).content = dup_xml_str(content);
2694 (*entity).length = if content.is_null() {
2695 0
2696 } else {
2697 crate::abi::exports_xml2::xmlStrlen(content)
2698 };
2699 (*entity).flags = 0;
2700 (*entity).expandedSize = 0;
2701 }
2702
2703 entity
2704}
2705
2706pub unsafe fn get_doc_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2721 crate::xml::entities::get_entity(doc as *mut _xmlDoc, name)
2722}
2723
2724pub unsafe fn add_doc_entity(
2732 doc: *mut _xmlDoc,
2733 name: *const xmlChar,
2734 etype: c_int,
2735 ExternalID: *const xmlChar,
2736 SystemID: *const xmlChar,
2737 content: *const xmlChar,
2738) -> *mut _xmlEntity {
2739 if doc.is_null() || name.is_null() {
2740 return ptr::null_mut();
2741 }
2742 unsafe {
2743 let mut dtd = (*doc).intSubset;
2744 if dtd.is_null() {
2745 dtd = new_dtd(
2746 doc,
2747 c"internal".as_ptr() as *const xmlChar,
2748 ptr::null(),
2749 ptr::null(),
2750 );
2751 if dtd.is_null() {
2752 return ptr::null_mut();
2753 }
2754 }
2755 crate::xml::entities::add_entity(dtd, name, etype, ExternalID, SystemID, content)
2756 }
2757}
2758
2759pub unsafe fn add_dtd_entity(
2767 doc: *mut _xmlDoc,
2768 name: *const xmlChar,
2769 etype: c_int,
2770 ExternalID: *const xmlChar,
2771 SystemID: *const xmlChar,
2772 content: *const xmlChar,
2773) -> *mut _xmlEntity {
2774 if doc.is_null() || name.is_null() {
2775 return ptr::null_mut();
2776 }
2777 unsafe {
2778 let mut dtd = (*doc).extSubset;
2779 if dtd.is_null() {
2780 dtd = new_dtd(
2781 doc,
2782 c"internal".as_ptr() as *const xmlChar,
2783 ptr::null(),
2784 ptr::null(),
2785 );
2786 if dtd.is_null() {
2787 return ptr::null_mut();
2788 }
2789 (*doc).extSubset = dtd;
2790 }
2791 crate::xml::entities::add_entity(dtd, name, etype, ExternalID, SystemID, content)
2792 }
2793}
2794
2795pub unsafe fn get_dtd_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2803 if doc.is_null() || name.is_null() {
2804 return ptr::null_mut();
2805 }
2806 unsafe {
2807 if !(*doc).intSubset.is_null() {
2808 let e = crate::xml::entities::get_entity_from_dtd((*doc).intSubset, name);
2809 if !e.is_null() {
2810 return e;
2811 }
2812 }
2813 if !(*doc).extSubset.is_null() {
2814 return crate::xml::entities::get_entity_from_dtd((*doc).extSubset, name);
2815 }
2816 ptr::null_mut()
2817 }
2818}
2819
2820pub unsafe fn get_parameter_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2833 crate::xml::entities::get_parameter_entity(doc as *mut _xmlDoc, name)
2834}
2835
2836const ENTITY_LT: &[xmlChar] = b"<";
2845const ENTITY_GT: &[xmlChar] = b">";
2846const ENTITY_AMP: &[xmlChar] = b"&";
2847const ENTITY_QUOT: &[xmlChar] = b""";
2848#[allow(dead_code)]
2849const ENTITY_APOS: &[xmlChar] = b"'";
2850
2851const INDENT: &[xmlChar] = b" ";
2853
2854const MAX_INDENT: c_int = 60;
2856
2857pub(crate) unsafe fn serialize_text(buf: *mut _xmlBuffer, content: *const xmlChar, len: c_int) {
2872 if buf.is_null() || content.is_null() || len <= 0 {
2873 return;
2874 }
2875
2876 let mut i: c_int = 0;
2877 while i < len {
2878 let ch = unsafe { *content.add(i as usize) };
2879
2880 if ch == b']'
2882 && i + 2 < len
2883 && unsafe { *content.add(i as usize + 1) == b']' }
2884 && unsafe { *content.add(i as usize + 2) == b'>' }
2885 {
2886 io::buf_add(buf, &ch as *const u8, 2); io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2889 i += 3;
2890 continue;
2891 }
2892
2893 match ch {
2894 b'<' => {
2895 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
2896 }
2897 b'&' => {
2898 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
2899 }
2900 b'>' => {
2901 io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2905 }
2906 b'\r' => {
2907 io::buf_add(buf, b" " as *const u8, 5);
2909 }
2910 0x01..=0x08 | 0x0B | 0x0C | 0x0E..=0x1F => {
2911 let hex = format!("&#x{:X};", ch);
2913 io::buf_add(buf, hex.as_ptr(), hex.len() as c_int);
2914 }
2915 _ => {
2916 io::buf_add(buf, &ch as *const u8, 1);
2917 }
2918 }
2919 i += 1;
2920 }
2921}
2922
2923pub(crate) unsafe fn serialize_attr_value(buf: *mut _xmlBuffer, value: *const xmlChar) {
2936 if buf.is_null() || value.is_null() {
2937 return;
2938 }
2939
2940 let len = xml_strlen(value);
2941 let mut i: c_int = 0;
2942 while i < len {
2943 let ch = unsafe { *value.add(i as usize) };
2944
2945 match ch {
2946 b'\n' => {
2947 io::buf_add(buf, b" " as *const u8, 5);
2948 }
2949 b'\r' => {
2950 io::buf_add(buf, b" " as *const u8, 5);
2951 }
2952 b'\t' => {
2953 io::buf_add(buf, b"	" as *const u8, 4);
2954 }
2955 b'<' => {
2956 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
2957 }
2958 b'&' => {
2959 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
2960 }
2961 b'"' => {
2962 io::buf_add(buf, ENTITY_QUOT.as_ptr(), ENTITY_QUOT.len() as c_int);
2963 }
2964 b'>' => {
2965 io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2966 }
2967 _ => {
2968 io::buf_add(buf, &ch as *const u8, 1);
2969 }
2970 }
2971 i += 1;
2972 }
2973}
2974
2975unsafe fn write_indent(
2987 buf: *mut _xmlBuffer,
2988 level: c_int,
2989 indent: *const xmlChar,
2990 indent_len: c_int,
2991) {
2992 if buf.is_null() || level <= 0 || indent.is_null() || indent_len <= 0 {
2993 return;
2994 }
2995 let indent_nr = MAX_INDENT / indent_len;
2996 let mut lvl = level;
2997 if lvl > indent_nr {
2998 lvl = indent_nr;
2999 }
3000 for _ in 0..lvl {
3001 io::buf_add(buf, indent, indent_len);
3002 }
3003}
3004
3005unsafe fn is_noenc_text(node: *mut _xmlNode) -> bool {
3019 if node.is_null() {
3020 return false;
3021 }
3022 let n = unsafe { &*node };
3023 if n.name.is_null() {
3024 return false;
3025 }
3026 c_str_eq_bytes(n.name, b"textnoenc")
3027}
3028
3029const unsafe fn c_str_eq_bytes(s: *const xmlChar, b: &[u8]) -> bool {
3037 let mut i = 0usize;
3038 while i < b.len() {
3039 if unsafe { *s.add(i) } != b[i] {
3040 return false;
3041 }
3042 i += 1;
3043 }
3044 unsafe { *s.add(i) == 0 }
3045}
3046
3047#[derive(Clone, Copy)]
3050struct DumpState {
3051 format: c_int,
3053 saved: c_int,
3056 unformatted: *mut _xmlNode,
3059 indent: *const xmlChar,
3062 indent_len: c_int,
3064 no_decl: c_int,
3066 encoding: *const xmlChar,
3070}
3071
3072impl DumpState {
3073 const fn new(format: c_int) -> Self {
3074 let f = if format != 0 { 1 } else { 0 };
3075 DumpState {
3076 format: f,
3077 saved: f,
3078 unformatted: ptr::null_mut(),
3079 indent: INDENT.as_ptr(),
3080 indent_len: INDENT.len() as c_int,
3081 no_decl: 0,
3082 encoding: ptr::null(),
3083 }
3084 }
3085
3086 const unsafe fn with_indent_enc(
3097 format: c_int,
3098 indent: *const xmlChar,
3099 no_decl: c_int,
3100 encoding: *const xmlChar,
3101 ) -> Self {
3102 let f = if format != 0 { 1 } else { 0 };
3103 let (ptr, len) = if indent.is_null() {
3104 (INDENT.as_ptr(), INDENT.len() as c_int)
3105 } else {
3106 let mut n = 0i32;
3107 while unsafe { *indent.add(n as usize) } != 0 {
3108 n += 1;
3109 }
3110 (indent, n)
3111 };
3112 DumpState {
3113 format: f,
3114 saved: f,
3115 unformatted: ptr::null_mut(),
3116 indent: ptr,
3117 indent_len: len,
3118 no_decl,
3119 encoding,
3120 }
3121 }
3122}
3123
3124unsafe fn write_qname(buf: *mut _xmlBuffer, node: *mut _xmlNode) {
3130 let n = unsafe { &*node };
3131 if !n.ns.is_null() {
3132 let ns = unsafe { &*n.ns };
3133 if !ns.prefix.is_null() {
3134 io::buf_cat(buf, ns.prefix);
3135 io::buf_ccat(buf, b':');
3136 }
3137 }
3138 if !n.name.is_null() {
3139 io::buf_cat(buf, n.name);
3140 }
3141}
3142
3143unsafe fn ns_dump_output(buf: *mut _xmlBuffer, cur: *mut _xmlNs) {
3149 if cur.is_null() || buf.is_null() {
3150 return;
3151 }
3152 let ns = unsafe { &*cur };
3153 if ns.type_ == XML_LOCAL_NAMESPACE as c_int && !ns.href.is_null() {
3154 if !ns.prefix.is_null() && c_str_eq_bytes(ns.prefix, b"xml") {
3156 return;
3157 }
3158 io::buf_ccat(buf, b' ');
3159 if !ns.prefix.is_null() {
3160 io::buf_add(buf, b"xmlns:" as *const u8, 6);
3161 io::buf_cat(buf, ns.prefix);
3162 } else {
3163 io::buf_add(buf, b"xmlns" as *const u8, 5);
3164 }
3165 io::buf_add(buf, b"=\"" as *const u8, 2);
3166 serialize_attr_value(buf, ns.href);
3167 io::buf_ccat(buf, b'"');
3168 }
3169}
3170
3171unsafe fn attr_dump_output(buf: *mut _xmlBuffer, cur: *mut _xmlAttr) {
3177 if cur.is_null() || buf.is_null() {
3178 return;
3179 }
3180 io::buf_ccat(buf, b' ');
3181 let a = unsafe { &*cur };
3182 if !a.ns.is_null() {
3183 let ans = unsafe { &*a.ns };
3184 if !ans.prefix.is_null() {
3185 io::buf_cat(buf, ans.prefix);
3186 io::buf_ccat(buf, b':');
3187 }
3188 }
3189 if !a.name.is_null() {
3190 io::buf_cat(buf, a.name);
3191 }
3192 io::buf_add(buf, b"=\"" as *const u8, 2);
3193 let mut child = a.children;
3196 while !child.is_null() {
3197 let ct = unsafe { (*child).type_ };
3198 if ct == XML_TEXT_NODE as c_int && !unsafe { (*child).content }.is_null() {
3199 serialize_attr_value(buf, unsafe { (*child).content });
3200 } else if ct == XML_ENTITY_REF_NODE as c_int && !unsafe { (*child).name }.is_null() {
3201 io::buf_ccat(buf, b'&');
3202 io::buf_cat(buf, unsafe { (*child).name });
3203 io::buf_ccat(buf, b';');
3204 }
3205 child = unsafe { (*child).next };
3206 }
3207 io::buf_ccat(buf, b'"');
3208}
3209
3210unsafe fn dump_notation_decl(buf: *mut _xmlBuffer, nota: *mut _xmlNotation) {
3216 let n = unsafe { &*nota };
3217 io::buf_add(buf, b"<!NOTATION " as *const u8, 11);
3218 if !n.name.is_null() {
3219 io::buf_cat(buf, n.name);
3220 }
3221 if !n.PublicID.is_null() {
3222 io::buf_add(buf, b" PUBLIC " as *const u8, 8);
3223 write_quoted_string(buf, n.PublicID);
3224 if !n.SystemID.is_null() {
3225 io::buf_ccat(buf, b' ');
3226 write_quoted_string(buf, n.SystemID);
3227 }
3228 } else {
3229 io::buf_add(buf, b" SYSTEM " as *const u8, 8);
3230 write_quoted_string(buf, n.SystemID);
3231 }
3232 io::buf_add(buf, b" >\n" as *const u8, 4);
3233}
3234
3235unsafe fn dump_element_occur(buf: *mut _xmlBuffer, ocur: c_int) {
3237 use crate::abi::types::xmlElementContentOccur::*;
3238 if ocur == XML_ELEMENT_CONTENT_OPT as c_int {
3239 io::buf_ccat(buf, b'?');
3240 } else if ocur == XML_ELEMENT_CONTENT_MULT as c_int {
3241 io::buf_ccat(buf, b'*');
3242 } else if ocur == XML_ELEMENT_CONTENT_PLUS as c_int {
3243 io::buf_ccat(buf, b'+');
3244 }
3245}
3246
3247unsafe fn dump_element_content(buf: *mut _xmlBuffer, content: *mut _xmlElementContent) {
3253 use crate::abi::types::xmlElementContentOccur::*;
3254 use crate::abi::types::xmlElementContentType::*;
3255 if content.is_null() {
3256 return;
3257 }
3258 io::buf_ccat(buf, b'(');
3259 let mut cur = content;
3260 loop {
3261 if cur.is_null() {
3262 return;
3263 }
3264 let c = unsafe { &*cur };
3265 match c.type_ {
3266 t if t == XML_ELEMENT_CONTENT_PCDATA as c_int => {
3267 io::buf_add(buf, b"#PCDATA" as *const u8, 7);
3268 }
3269 t if t == XML_ELEMENT_CONTENT_ELEMENT as c_int => {
3270 if !c.prefix.is_null() {
3271 io::buf_cat(buf, c.prefix);
3272 io::buf_ccat(buf, b':');
3273 }
3274 if !c.name.is_null() {
3275 io::buf_cat(buf, c.name);
3276 }
3277 }
3278 t if t == XML_ELEMENT_CONTENT_SEQ as c_int || t == XML_ELEMENT_CONTENT_OR as c_int => {
3279 if cur != content
3280 && !c.parent.is_null()
3281 && (c.type_ != unsafe { (*c.parent).type_ }
3282 || c.ocur != XML_ELEMENT_CONTENT_ONCE as c_int)
3283 {
3284 io::buf_ccat(buf, b'(');
3285 }
3286 cur = c.c1;
3287 continue;
3288 }
3289 _ => {}
3290 }
3291
3292 while cur != content {
3294 let ccur = unsafe { &*cur };
3295 let parent = ccur.parent;
3296 if parent.is_null() {
3297 return;
3298 }
3299 let p = unsafe { &*parent };
3300 if (ccur.type_ == XML_ELEMENT_CONTENT_OR as c_int
3301 || ccur.type_ == XML_ELEMENT_CONTENT_SEQ as c_int)
3302 && (ccur.type_ != p.type_ || ccur.ocur != XML_ELEMENT_CONTENT_ONCE as c_int)
3303 {
3304 io::buf_ccat(buf, b')');
3305 }
3306 dump_element_occur(buf, ccur.ocur);
3307
3308 if ccur.type_ == XML_ELEMENT_CONTENT_SEQ as c_int {
3309 io::buf_add(buf, b" , " as *const u8, 3);
3310 } else if ccur.type_ == XML_ELEMENT_CONTENT_OR as c_int {
3311 io::buf_add(buf, b" | " as *const u8, 3);
3312 }
3313
3314 if cur == p.c1 {
3315 cur = p.c2;
3316 break;
3317 }
3318 cur = parent;
3319 }
3320 if cur == content {
3321 break;
3322 }
3323 }
3324 io::buf_ccat(buf, b')');
3325 let cc = unsafe { &*content };
3326 dump_element_occur(buf, cc.ocur);
3327}
3328
3329unsafe fn dump_element_decl(buf: *mut _xmlBuffer, elem: *mut _xmlElement) {
3335 use crate::abi::types::xmlElementTypeVal::*;
3336 let e = unsafe { &*elem };
3337 io::buf_add(buf, b"<!ELEMENT " as *const u8, 10);
3338 if !e.prefix.is_null() {
3339 io::buf_cat(buf, e.prefix);
3340 io::buf_ccat(buf, b':');
3341 }
3342 if !e.name.is_null() {
3343 io::buf_cat(buf, e.name);
3344 }
3345 io::buf_ccat(buf, b' ');
3346 match e.etype {
3347 t if t == XML_ELEMENT_TYPE_EMPTY as c_int => {
3348 io::buf_add(buf, b"EMPTY" as *const u8, 5);
3349 }
3350 t if t == XML_ELEMENT_TYPE_ANY as c_int => {
3351 io::buf_add(buf, b"ANY" as *const u8, 3);
3352 }
3353 t if t == XML_ELEMENT_TYPE_MIXED as c_int || t == XML_ELEMENT_TYPE_ELEMENT as c_int => {
3354 dump_element_content(buf, e.content);
3355 }
3356 _ => {}
3357 }
3358 io::buf_add(buf, b">\n" as *const u8, 2);
3359}
3360
3361unsafe fn dump_enumeration(buf: *mut _xmlBuffer, cur: *mut _xmlEnumeration) {
3367 let mut e = cur;
3368 while !e.is_null() {
3369 let en = unsafe { &*e };
3370 if !en.name.is_null() {
3371 io::buf_cat(buf, en.name);
3372 }
3373 if !en.next.is_null() {
3374 io::buf_add(buf, b" | " as *const u8, 3);
3375 }
3376 e = en.next;
3377 }
3378 io::buf_ccat(buf, b')');
3379}
3380
3381unsafe fn dump_attribute_decl(buf: *mut _xmlBuffer, attr: *mut _xmlAttribute) {
3387 use crate::abi::types::xmlAttributeDefault::*;
3388 use crate::abi::types::xmlAttributeType::*;
3389 let a = unsafe { &*attr };
3390 io::buf_add(buf, b"<!ATTLIST " as *const u8, 10);
3391 if !a.elem.is_null() {
3392 io::buf_cat(buf, a.elem);
3393 }
3394 io::buf_ccat(buf, b' ');
3395 if !a.prefix.is_null() {
3396 io::buf_cat(buf, a.prefix);
3397 io::buf_ccat(buf, b':');
3398 }
3399 if !a.name.is_null() {
3400 io::buf_cat(buf, a.name);
3401 }
3402 match a.atype {
3403 t if t == XML_ATTRIBUTE_CDATA as c_int => {
3404 io::buf_add(buf, b" CDATA" as *const u8, 6);
3405 }
3406 t if t == XML_ATTRIBUTE_ID as c_int => {
3407 io::buf_add(buf, b" ID" as *const u8, 3);
3408 }
3409 t if t == XML_ATTRIBUTE_IDREF as c_int => {
3410 io::buf_add(buf, b" IDREF" as *const u8, 6);
3411 }
3412 t if t == XML_ATTRIBUTE_IDREFS as c_int => {
3413 io::buf_add(buf, b" IDREFS" as *const u8, 7);
3414 }
3415 t if t == XML_ATTRIBUTE_ENTITY as c_int => {
3416 io::buf_add(buf, b" ENTITY" as *const u8, 7);
3417 }
3418 t if t == XML_ATTRIBUTE_ENTITIES as c_int => {
3419 io::buf_add(buf, b" ENTITIES" as *const u8, 9);
3420 }
3421 t if t == XML_ATTRIBUTE_NMTOKEN as c_int => {
3422 io::buf_add(buf, b" NMTOKEN" as *const u8, 8);
3423 }
3424 t if t == XML_ATTRIBUTE_NMTOKENS as c_int => {
3425 io::buf_add(buf, b" NMTOKENS" as *const u8, 9);
3426 }
3427 t if t == XML_ATTRIBUTE_ENUMERATION as c_int => {
3428 io::buf_add(buf, b" (" as *const u8, 2);
3429 dump_enumeration(buf, a.tree);
3430 }
3431 t if t == XML_ATTRIBUTE_NOTATION as c_int => {
3432 io::buf_add(buf, b" NOTATION (" as *const u8, 11);
3433 dump_enumeration(buf, a.tree);
3434 }
3435 _ => {}
3436 }
3437 match a.def {
3438 t if t == XML_ATTRIBUTE_REQUIRED as c_int => {
3439 io::buf_add(buf, b" #REQUIRED" as *const u8, 10);
3440 }
3441 t if t == XML_ATTRIBUTE_IMPLIED as c_int => {
3442 io::buf_add(buf, b" #IMPLIED" as *const u8, 9);
3443 }
3444 t if t == XML_ATTRIBUTE_FIXED as c_int => {
3445 io::buf_add(buf, b" #FIXED" as *const u8, 7);
3446 }
3447 _ => {}
3448 }
3449 if !a.defaultValue.is_null() {
3450 io::buf_add(buf, b" \"" as *const u8, 2);
3451 serialize_attr_value(buf, a.defaultValue);
3452 io::buf_ccat(buf, b'"');
3453 }
3454 io::buf_add(buf, b">\n" as *const u8, 2);
3455}
3456
3457unsafe fn write_quoted_string(buf: *mut _xmlBuffer, str: *const xmlChar) {
3463 if buf.is_null() {
3464 return;
3465 }
3466 io::buf_ccat(buf, b'"');
3467 if !str.is_null() {
3468 let mut i = 0usize;
3469 while unsafe { *str.add(i) != 0 } {
3470 let ch = unsafe { *str.add(i) };
3471 if ch == b'"' {
3472 io::buf_add(buf, b""" as *const u8, 6);
3473 } else {
3474 io::buf_add(buf, &ch as *const u8, 1);
3475 }
3476 i += 1;
3477 }
3478 }
3479 io::buf_ccat(buf, b'"');
3480}
3481
3482unsafe fn dump_entity_decl(buf: *mut _xmlBuffer, ent: *mut _xmlEntity) {
3488 use crate::abi::types::xmlEntityType::*;
3489 let e = unsafe { &*ent };
3490 if e.etype == XML_INTERNAL_PARAMETER_ENTITY as c_int
3491 || e.etype == XML_EXTERNAL_PARAMETER_ENTITY as c_int
3492 {
3493 io::buf_add(buf, b"<!ENTITY % " as *const u8, 11);
3494 } else {
3495 io::buf_add(buf, b"<!ENTITY " as *const u8, 9);
3496 }
3497 if !e.name.is_null() {
3498 io::buf_cat(buf, e.name);
3499 }
3500 io::buf_ccat(buf, b' ');
3501
3502 if e.etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY as c_int
3503 || e.etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int
3504 || e.etype == XML_EXTERNAL_PARAMETER_ENTITY as c_int
3505 {
3506 if !e.ExternalID.is_null() {
3507 io::buf_add(buf, b"PUBLIC " as *const u8, 7);
3508 write_quoted_string(buf, e.ExternalID);
3509 io::buf_ccat(buf, b' ');
3510 } else {
3511 io::buf_add(buf, b"SYSTEM " as *const u8, 7);
3512 }
3513 write_quoted_string(buf, e.SystemID);
3514 }
3515
3516 if e.etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int && !e.content.is_null() {
3517 io::buf_add(buf, b" NDATA " as *const u8, 7);
3518 if !e.orig.is_null() {
3519 io::buf_cat(buf, e.orig);
3520 } else if !e.content.is_null() {
3521 io::buf_cat(buf, e.content);
3522 }
3523 }
3524
3525 if e.etype == XML_INTERNAL_GENERAL_ENTITY as c_int
3526 || e.etype == XML_INTERNAL_PARAMETER_ENTITY as c_int
3527 {
3528 if !e.orig.is_null() {
3529 write_quoted_string(buf, e.orig);
3530 } else {
3531 io::buf_ccat(buf, b'"');
3533 if !e.content.is_null() {
3534 let mut i = 0usize;
3535 while unsafe { *e.content.add(i) != 0 } {
3536 let ch = unsafe { *e.content.add(i) };
3537 match ch {
3538 b'"' => io::buf_add(buf, b""" as *const u8, 6),
3539 b'%' => io::buf_add(buf, b"%" as *const u8, 6),
3540 _ => io::buf_add(buf, &ch as *const u8, 1),
3541 };
3542 i += 1;
3543 }
3544 }
3545 io::buf_ccat(buf, b'"');
3546 }
3547 }
3548 io::buf_add(buf, b">\n" as *const u8, 2);
3549}
3550
3551unsafe fn dtd_dump_output(
3557 buf: *mut _xmlBuffer,
3558 cur: *mut _xmlNode,
3559 state: &mut DumpState,
3560 level: &mut c_int,
3561) {
3562 let dtd = cur as *mut _xmlDtd;
3563 let d = unsafe { &*dtd };
3564 io::buf_add(buf, b"<!DOCTYPE " as *const u8, 10);
3565 if !d.name.is_null() {
3566 io::buf_cat(buf, d.name);
3567 }
3568 if !d.ExternalID.is_null() {
3569 io::buf_add(buf, b" PUBLIC " as *const u8, 8);
3570 write_quoted_string(buf, d.ExternalID);
3571 io::buf_ccat(buf, b' ');
3572 write_quoted_string(buf, d.SystemID);
3573 } else if !d.SystemID.is_null() {
3574 io::buf_add(buf, b" SYSTEM " as *const u8, 8);
3575 write_quoted_string(buf, d.SystemID);
3576 }
3577 if d.entities.is_null()
3582 && d.elements.is_null()
3583 && d.attributes.is_null()
3584 && d.notations.is_null()
3585 && d.pentities.is_null()
3586 {
3587 io::buf_ccat(buf, b'>');
3588 return;
3589 }
3590 io::buf_add(buf, b" [\n" as *const u8, 3);
3591 let format = state.format;
3597 let lvl = *level;
3598 state.format = 0;
3599 *level = -1;
3600 if !d.notations.is_null() {
3601 crate::xml::hash::hash_scan(
3602 d.notations as *mut crate::xml::hash::HashTable,
3603 Some(dump_notation_decl_cb),
3604 buf as *mut c_void,
3605 );
3606 }
3607 if !d.elements.is_null() {
3608 crate::xml::hash::hash_scan(
3609 d.elements as *mut crate::xml::hash::HashTable,
3610 Some(dump_element_decl_cb),
3611 buf as *mut c_void,
3612 );
3613 }
3614 if !d.attributes.is_null() {
3615 crate::xml::hash::hash_scan(
3616 d.attributes as *mut crate::xml::hash::HashTable,
3617 Some(dump_attribute_decl_cb),
3618 buf as *mut c_void,
3619 );
3620 }
3621 if !d.entities.is_null() {
3622 crate::xml::hash::hash_scan(
3623 d.entities as *mut crate::xml::hash::HashTable,
3624 Some(dump_entity_decl_cb),
3625 buf as *mut c_void,
3626 );
3627 }
3628 if !d.pentities.is_null() {
3629 crate::xml::hash::hash_scan(
3630 d.pentities as *mut crate::xml::hash::HashTable,
3631 Some(dump_entity_decl_cb),
3632 buf as *mut c_void,
3633 );
3634 }
3635 state.format = format;
3636 *level = lvl;
3637 io::buf_add(buf, b"]>" as *const u8, 2);
3638}
3639
3640unsafe extern "C" fn dump_notation_decl_cb(
3642 payload: *mut c_void,
3643 data: *mut c_void,
3644 _name: *const crate::abi::types::xmlChar,
3645) {
3646 if !payload.is_null() && !data.is_null() {
3647 dump_notation_decl(data as *mut _xmlBuffer, payload as *mut _xmlNotation);
3648 }
3649}
3650
3651unsafe extern "C" fn dump_element_decl_cb(
3653 payload: *mut c_void,
3654 data: *mut c_void,
3655 _name: *const crate::abi::types::xmlChar,
3656) {
3657 if !payload.is_null() && !data.is_null() {
3658 dump_element_decl(data as *mut _xmlBuffer, payload as *mut _xmlElement);
3659 }
3660}
3661
3662unsafe extern "C" fn dump_attribute_decl_cb(
3664 payload: *mut c_void,
3665 data: *mut c_void,
3666 _name: *const crate::abi::types::xmlChar,
3667) {
3668 if !payload.is_null() && !data.is_null() {
3669 dump_attribute_decl(data as *mut _xmlBuffer, payload as *mut _xmlAttribute);
3670 }
3671}
3672
3673unsafe extern "C" fn dump_entity_decl_cb(
3675 payload: *mut c_void,
3676 data: *mut c_void,
3677 _name: *const crate::abi::types::xmlChar,
3678) {
3679 if !payload.is_null() && !data.is_null() {
3680 dump_entity_decl(data as *mut _xmlBuffer, payload as *mut _xmlEntity);
3681 }
3682}
3683
3684unsafe fn doc_content_dump_output(
3693 buf: *mut _xmlBuffer,
3694 cur: *mut _xmlNode,
3695 state: &mut DumpState,
3696 level: &mut c_int,
3697) {
3698 let doc = cur as *mut _xmlDoc;
3699 let d = unsafe { &*doc };
3700
3701 if state.no_decl == 0 {
3708 io::buf_add(buf, b"<?xml version=\"" as *const u8, 15);
3709 if !d.version.is_null() {
3710 io::buf_cat(buf, d.version);
3711 } else {
3712 io::buf_add(buf, b"1.0" as *const u8, 3);
3713 }
3714 io::buf_ccat(buf, b'"');
3715 let enc = if state.encoding.is_null() {
3716 d.encoding
3717 } else {
3718 state.encoding
3719 };
3720 if !enc.is_null() {
3721 io::buf_add(buf, b" encoding=\"" as *const u8, 11);
3722 io::buf_cat(buf, enc);
3723 io::buf_ccat(buf, b'"');
3724 }
3725 match d.standalone {
3726 0 => {
3727 io::buf_add(buf, b" standalone=\"no\"" as *const u8, 16);
3728 }
3729 1 => {
3730 io::buf_add(buf, b" standalone=\"yes\"" as *const u8, 17);
3731 }
3732 _ => {}
3733 }
3734 io::buf_add(buf, b"?>\n" as *const u8, 3);
3735 }
3736
3737 if !d.intSubset.is_null() {
3744 let mut in_chain = false;
3745 let mut c = d.children;
3746 while !c.is_null() {
3747 if c as *mut c_void == d.intSubset as *mut c_void {
3748 in_chain = true;
3749 break;
3750 }
3751 c = unsafe { (*c).next };
3752 }
3753 if !in_chain {
3754 let mut lvl = 0;
3755 dtd_dump_output(buf, d.intSubset as *mut _xmlNode, state, &mut lvl);
3756 io::buf_ccat(buf, b'\n');
3757 }
3758 }
3759
3760 if !d.children.is_null() {
3761 let mut child = d.children;
3762 while !child.is_null() {
3763 *level = 0;
3764 node_dump_internal(buf, child, child, cur, state, level);
3765 let ct = unsafe { (*child).type_ };
3766 if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
3767 io::buf_ccat(buf, b'\n');
3768 }
3769 child = unsafe { (*child).next };
3770 }
3771 }
3772}
3773
3774unsafe fn node_dump_internal(
3798 buf: *mut _xmlBuffer,
3799 cur: *mut _xmlNode,
3800 root: *mut _xmlNode,
3801 parent: *mut _xmlNode,
3802 state: &mut DumpState,
3803 level: &mut c_int,
3804) {
3805 if cur.is_null() || buf.is_null() {
3806 return;
3807 }
3808 let n = unsafe { &*cur };
3809 match n.type_ {
3810 t if t == XML_ELEMENT_NODE as c_int => {
3811 if cur != root && state.format == 1 {
3812 write_indent(buf, *level, state.indent, state.indent_len);
3813 }
3814 if !n.parent.is_null() && n.parent != parent && !n.children.is_null() {
3817 let mut sub = DumpState::new(state.format);
3818 let mut sub_level = *level;
3819 node_dump_internal(buf, cur, cur, n.parent, &mut sub, &mut sub_level);
3820 return;
3821 }
3822 io::buf_ccat(buf, b'<');
3824 write_qname(buf, cur);
3825 let mut nsdef = n.nsDef;
3826 while !nsdef.is_null() {
3827 ns_dump_output(buf, nsdef);
3828 nsdef = unsafe { (*nsdef).next };
3829 }
3830 let mut attr = n.properties;
3831 while !attr.is_null() {
3832 attr_dump_output(buf, attr);
3833 attr = unsafe { (*attr).next };
3834 }
3835 if n.children.is_null() {
3836 io::buf_add(buf, b"/>" as *const u8, 2);
3837 } else {
3838 if state.format == 1 {
3839 let mut tmp = n.children;
3842 while !tmp.is_null() {
3843 let tt = unsafe { (*tmp).type_ };
3844 if tt == XML_TEXT_NODE as c_int
3845 || tt == XML_CDATA_SECTION_NODE as c_int
3846 || tt == XML_ENTITY_REF_NODE as c_int
3847 {
3848 state.format = 0;
3849 state.unformatted = cur;
3850 break;
3851 }
3852 tmp = unsafe { (*tmp).next };
3853 }
3854 }
3855 io::buf_ccat(buf, b'>');
3856 if state.format == 1 {
3857 io::buf_ccat(buf, b'\n');
3858 }
3859 if *level >= 0 {
3860 *level += 1;
3861 }
3862 let mut child = n.children;
3863 while !child.is_null() {
3864 node_dump_internal(buf, child, root, cur, state, level);
3865 if state.format == 1 {
3866 let ct = unsafe { (*child).type_ };
3867 if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
3868 io::buf_ccat(buf, b'\n');
3869 }
3870 }
3871 child = unsafe { (*child).next };
3872 }
3873 if *level > 0 {
3875 *level -= 1;
3876 }
3877 if state.format == 1 {
3878 write_indent(buf, *level, state.indent, state.indent_len);
3879 }
3880 io::buf_add(buf, b"</" as *const u8, 2);
3881 write_qname(buf, cur);
3882 io::buf_ccat(buf, b'>');
3883 if cur == state.unformatted {
3884 state.format = state.saved;
3885 state.unformatted = ptr::null_mut();
3886 }
3887 }
3888 }
3889 t if t == XML_TEXT_NODE as c_int => {
3890 if !n.content.is_null() {
3891 if is_noenc_text(cur) {
3892 io::buf_cat(buf, n.content);
3893 } else {
3894 serialize_text(buf, n.content, xml_strlen(n.content));
3895 }
3896 } else if !n.children.is_null() {
3897 let c = node_get_content(cur);
3900 if !c.is_null() {
3901 if is_noenc_text(cur) {
3902 io::buf_cat(buf, c);
3903 } else {
3904 serialize_text(buf, c, xml_strlen(c));
3905 }
3906 allocator::xmlFreeImpl(c as *mut c_void);
3907 }
3908 }
3909 }
3910 t if t == XML_CDATA_SECTION_NODE as c_int => {
3911 if n.content.is_null() || unsafe { *n.content == 0 } {
3912 io::buf_add(buf, b"<![CDATA[]]>" as *const u8, 12);
3913 } else {
3914 let len = xml_strlen(n.content) as usize;
3915 let bytes = core::slice::from_raw_parts(n.content, len);
3916 let mut i = 0usize;
3917 let mut seg_start = 0usize;
3918 while i < len {
3919 if bytes[i] == b']'
3920 && i + 2 < len
3921 && bytes[i + 1] == b']'
3922 && bytes[i + 2] == b'>'
3923 {
3924 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
3925 io::buf_add(buf, n.content.add(seg_start), (i + 2 - seg_start) as c_int);
3926 io::buf_add(buf, b"]]>" as *const u8, 3);
3927 seg_start = i + 2;
3928 i += 3;
3929 continue;
3930 }
3931 i += 1;
3932 }
3933 if seg_start < len {
3934 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
3935 io::buf_add(buf, n.content.add(seg_start), (len - seg_start) as c_int);
3936 io::buf_add(buf, b"]]>" as *const u8, 3);
3937 }
3938 }
3939 }
3940 t if t == XML_COMMENT_NODE as c_int => {
3941 if cur != root && state.format == 1 {
3942 write_indent(buf, *level, state.indent, state.indent_len);
3943 }
3944 if !n.content.is_null() {
3945 io::buf_add(buf, b"<!--" as *const u8, 4);
3946 io::buf_cat(buf, n.content);
3947 io::buf_add(buf, b"-->" as *const u8, 3);
3948 }
3949 }
3950 t if t == XML_PI_NODE as c_int => {
3951 if cur != root && state.format == 1 {
3952 write_indent(buf, *level, state.indent, state.indent_len);
3953 }
3954 io::buf_add(buf, b"<?" as *const u8, 2);
3955 if !n.name.is_null() {
3956 io::buf_cat(buf, n.name);
3957 }
3958 if !n.content.is_null() && unsafe { *n.content != 0 } {
3959 io::buf_ccat(buf, b' ');
3960 io::buf_cat(buf, n.content);
3961 }
3962 io::buf_add(buf, b"?>" as *const u8, 2);
3963 }
3964 t if t == XML_ENTITY_REF_NODE as c_int => {
3965 io::buf_ccat(buf, b'&');
3966 if !n.name.is_null() {
3967 io::buf_cat(buf, n.name);
3968 }
3969 io::buf_ccat(buf, b';');
3970 }
3971 t if t == XML_DOCUMENT_NODE as c_int => {
3972 doc_content_dump_output(buf, cur, state, level);
3973 }
3974 t if t == XML_HTML_DOCUMENT_NODE as c_int => {
3975 crate::xml::html::serialize_node(cur, buf, state.format, *level);
3977 }
3978 t if t == XML_DTD_NODE as c_int => {
3979 dtd_dump_output(buf, cur, state, level);
3980 }
3981 t if t == XML_ATTRIBUTE_NODE as c_int => {
3982 attr_dump_output(buf, cur as *mut _xmlAttr);
3983 }
3984 t if t == XML_NAMESPACE_DECL as c_int => {
3985 ns_dump_output(buf, cur as *mut _xmlNs);
3986 }
3987 t if t == XML_ELEMENT_DECL as c_int => {
3988 dump_element_decl(buf, cur as *mut _xmlElement);
3989 }
3990 t if t == XML_ATTRIBUTE_DECL as c_int => {
3991 dump_attribute_decl(buf, cur as *mut _xmlAttribute);
3992 }
3993 t if t == XML_ENTITY_DECL as c_int => {
3994 dump_entity_decl(buf, cur as *mut _xmlEntity);
3995 }
3996 _ => {}
3997 }
3998}
3999
4000pub(crate) unsafe fn serialize_node(
4014 node: *mut _xmlNode,
4015 buf: *mut _xmlBuffer,
4016 format: c_int,
4017 level: c_int,
4018) {
4019 unsafe { serialize_node_opt(node, buf, format, level, ptr::null()) };
4020}
4021
4022pub(crate) unsafe fn serialize_node_opt(
4030 node: *mut _xmlNode,
4031 buf: *mut _xmlBuffer,
4032 format: c_int,
4033 level: c_int,
4034 indent: *const xmlChar,
4035) {
4036 unsafe { serialize_node_opts(node, buf, format, level, indent, 0) };
4037}
4038
4039pub(crate) unsafe fn serialize_node_opts(
4046 node: *mut _xmlNode,
4047 buf: *mut _xmlBuffer,
4048 format: c_int,
4049 level: c_int,
4050 indent: *const xmlChar,
4051 no_decl: c_int,
4052) {
4053 unsafe { serialize_node_opts_enc(node, buf, format, level, indent, no_decl, ptr::null()) };
4054}
4055
4056pub(crate) unsafe fn serialize_node_opts_enc(
4066 node: *mut _xmlNode,
4067 buf: *mut _xmlBuffer,
4068 format: c_int,
4069 level: c_int,
4070 indent: *const xmlChar,
4071 no_decl: c_int,
4072 encoding: *const xmlChar,
4073) {
4074 if node.is_null() || buf.is_null() {
4075 return;
4076 }
4077 let parent = unsafe { (*node).parent };
4078 let mut state = DumpState::with_indent_enc(format, indent, no_decl, encoding);
4079 let mut lvl = level;
4080 node_dump_internal(buf, node, node, parent, &mut state, &mut lvl);
4081}
4082
4083pub(crate) unsafe fn doc_dump(buf: *mut _xmlBuffer, doc: *mut _xmlDoc) -> c_int {
4093 if buf.is_null() || doc.is_null() {
4094 return -1;
4095 }
4096
4097 let before = io::buf_length(buf);
4098 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
4099 let after = io::buf_length(buf);
4100
4101 if after < 0 || before < 0 {
4102 return -1;
4103 }
4104 after - before
4105}
4106
4107pub(crate) unsafe fn node_dump(
4119 buf: *mut _xmlBuffer,
4120 doc: *mut _xmlDoc,
4121 node: *mut _xmlNode,
4122 level: c_int,
4123 format: c_int,
4124) -> c_int {
4125 let _ = doc; if buf.is_null() || node.is_null() {
4127 return -1;
4128 }
4129
4130 let before = io::buf_length(buf);
4131 serialize_node(node, buf, format, level);
4132 let after = io::buf_length(buf);
4133
4134 if after < 0 || before < 0 {
4135 return -1;
4136 }
4137 after - before
4138}
4139
4140#[allow(dead_code)]
4147pub(crate) unsafe fn save_doc_to_fd(doc: *mut _xmlDoc, fd: c_int, _compression: c_int) -> c_int {
4148 if doc.is_null() || fd < 0 {
4149 return -1;
4150 }
4151
4152 let out = io::output_buffer_create_fd(fd, ptr::null_mut());
4153 if out.is_null() {
4154 return -1;
4155 }
4156
4157 let buf = io::buf_create(-1);
4158 if buf.is_null() {
4159 io::output_buffer_close(out);
4160 return -1;
4161 }
4162
4163 let ret = doc_dump(buf, doc);
4164 if ret >= 0 {
4165 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
4166 io::output_buffer_flush(out);
4167 }
4168
4169 io::buf_free(buf);
4170 io::output_buffer_close(out);
4171 ret
4172}
4173
4174#[allow(dead_code)]
4181pub(crate) unsafe fn save_doc_to_buf(
4182 doc: *mut _xmlDoc,
4183 buf: *mut _xmlBuffer,
4184 compression: c_int,
4185) -> c_int {
4186 let _ = compression;
4187 if doc.is_null() || buf.is_null() {
4188 return -1;
4189 }
4190
4191 doc_dump(buf, doc)
4192}
4193
4194#[allow(dead_code)]
4201pub(crate) unsafe fn save_format_doc_to_buf(
4202 doc: *mut _xmlDoc,
4203 buf: *mut _xmlBuffer,
4204 compression: c_int,
4205) -> c_int {
4206 let _ = compression;
4207 if doc.is_null() || buf.is_null() {
4208 return -1;
4209 }
4210
4211 let before = io::buf_length(buf);
4212 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
4213 let after = io::buf_length(buf);
4214
4215 if after < 0 || before < 0 {
4216 return -1;
4217 }
4218 after - before
4219}
4220
4221#[allow(dead_code)]
4230pub(crate) unsafe fn dump_node(node: *mut _xmlNode) -> *mut xmlChar {
4231 if node.is_null() {
4232 return ptr::null_mut();
4233 }
4234
4235 let buf = io::buf_create(-1);
4236 if buf.is_null() {
4237 return ptr::null_mut();
4238 }
4239
4240 serialize_node(node, buf, 0, 0);
4241
4242 let content = io::buf_content(buf);
4243 if content.is_null() {
4244 io::buf_free(buf);
4245 return ptr::null_mut();
4246 }
4247
4248 let result = dup_xml_str(content);
4250 io::buf_free(buf);
4251 result
4252}
4253
4254pub unsafe fn dump_doc(doc: *mut _xmlDoc) -> *mut xmlChar {
4263 if doc.is_null() {
4264 return ptr::null_mut();
4265 }
4266
4267 let buf = io::buf_create(-1);
4268 if buf.is_null() {
4269 return ptr::null_mut();
4270 }
4271
4272 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
4273
4274 let content = io::buf_content(buf);
4275 if content.is_null() {
4276 io::buf_free(buf);
4277 return ptr::null_mut();
4278 }
4279
4280 let result = dup_xml_str(content);
4281 io::buf_free(buf);
4282 result
4283}
4284
4285pub(crate) unsafe fn xmlNodeDump(
4301 buf: *mut _xmlBuffer,
4302 doc: *mut _xmlDoc,
4303 node: *mut _xmlNode,
4304 level: c_int,
4305 format: c_int,
4306) -> c_int {
4307 node_dump(buf, doc, node, level, format)
4308}
4309
4310pub(crate) unsafe fn xmlDocDump(fp: *mut c_void, doc: *mut _xmlDoc) -> c_int {
4323 if fp.is_null() || doc.is_null() {
4324 return -1;
4325 }
4326
4327 let buf = io::buf_create(-1);
4328 if buf.is_null() {
4329 return -1;
4330 }
4331
4332 let ret = doc_dump(buf, doc);
4333 if ret < 0 {
4334 io::buf_free(buf);
4335 return -1;
4336 }
4337
4338 let content = io::buf_content(buf);
4339 let len = io::buf_length(buf);
4340 if !content.is_null() && len > 0 {
4341 let written = libc::fwrite(
4342 content as *const c_void,
4343 1,
4344 len as usize,
4345 fp as *mut libc::FILE,
4346 );
4347 io::buf_free(buf);
4348 written as c_int
4349 } else {
4350 io::buf_free(buf);
4351 0
4352 }
4353}
4354
4355pub(crate) unsafe fn xmlDocDumpFormatMemory(
4369 doc: *mut _xmlDoc,
4370 mem: *mut *mut xmlChar,
4371 size: *mut c_int,
4372 format: c_int,
4373) {
4374 if doc.is_null() || mem.is_null() || size.is_null() {
4375 return;
4376 }
4377
4378 let buf = io::buf_create(-1);
4379 if buf.is_null() {
4380 unsafe {
4381 *mem = ptr::null_mut();
4382 *size = 0;
4383 }
4384 return;
4385 }
4386
4387 serialize_node(doc as *mut _xmlNode, buf, format, 0);
4388
4389 let content = io::buf_content(buf);
4390 let len = io::buf_length(buf);
4391
4392 if !content.is_null() && len > 0 {
4393 let result = allocator::xmlMallocImpl((len + 1) as usize) as *mut xmlChar;
4395 if !result.is_null() {
4396 ptr::copy_nonoverlapping(content, result, len as usize);
4397 *result.add(len as usize) = 0;
4398 unsafe {
4399 *mem = result;
4400 *size = len;
4401 }
4402 } else {
4403 unsafe {
4404 *mem = ptr::null_mut();
4405 *size = 0;
4406 }
4407 }
4408 } else {
4409 unsafe {
4410 *mem = ptr::null_mut();
4411 *size = 0;
4412 }
4413 }
4414
4415 io::buf_free(buf);
4416}
4417
4418pub(crate) unsafe fn xmlDocDumpMemory(doc: *mut _xmlDoc, mem: *mut *mut xmlChar, size: *mut c_int) {
4432 xmlDocDumpFormatMemory(doc, mem, size, 0)
4433}
4434
4435pub(crate) unsafe fn xmlSaveFile(filename: *const c_char, cur: *mut _xmlDoc) -> c_int {
4449 unsafe { xmlSaveFormatFileEnc(filename, cur, ptr::null(), 0) }
4450}
4451
4452pub(crate) unsafe fn xmlSaveFileEnc(
4467 filename: *const c_char,
4468 cur: *mut _xmlDoc,
4469 encoding: *const c_char,
4470) -> c_int {
4471 unsafe { xmlSaveFormatFileEnc(filename, cur, encoding, 0) }
4472}
4473
4474pub(crate) unsafe fn xmlSaveFormatFile(
4488 filename: *const c_char,
4489 cur: *mut _xmlDoc,
4490 format: c_int,
4491) -> c_int {
4492 unsafe { xmlSaveFormatFileEnc(filename, cur, ptr::null(), format) }
4493}
4494
4495pub(crate) unsafe fn xmlSaveFormatFileEnc(
4515 filename: *const c_char,
4516 cur: *mut _xmlDoc,
4517 encoding: *const c_char,
4518 format: c_int,
4519) -> c_int {
4520 if cur.is_null() {
4521 return -1;
4522 }
4523 let options = if format != 0 {
4524 crate::xml::save::XML_SAVE_FORMAT
4525 } else {
4526 0
4527 };
4528 let ctxt = crate::xml::save::xmlSaveToFilename(filename, encoding, options);
4529 if ctxt.is_null() {
4530 return -1;
4531 }
4532 crate::xml::save::xmlSaveDoc(ctxt, cur);
4533 crate::xml::save::xmlSaveClose(ctxt)
4534}
4535
4536pub(crate) unsafe fn xmlGetDocCompressMode(doc: *mut _xmlDoc) -> c_int {
4548 if doc.is_null() {
4549 return -1;
4550 }
4551 unsafe { (*doc).compression }
4552}
4553
4554pub(crate) unsafe fn xmlSetDocCompressMode(doc: *mut _xmlDoc, mode: c_int) {
4566 if doc.is_null() {
4567 return;
4568 }
4569 unsafe {
4570 (*doc).compression = mode;
4571 }
4572}
4573
4574#[cfg(test)]
4575mod tests {
4576 use super::*;
4577 use core::ffi::c_void;
4578
4579 fn c_str(s: &str) -> *const xmlChar {
4587 let bytes = s.as_bytes();
4588 let buf = unsafe { allocator::xmlMallocImpl(bytes.len() + 1) as *mut u8 };
4589 if !buf.is_null() {
4590 unsafe {
4591 ptr::copy_nonoverlapping(bytes.as_ptr(), buf, bytes.len());
4592 *buf.add(bytes.len()) = 0;
4593 }
4594 }
4595 buf as *const xmlChar
4596 }
4597
4598 #[test]
4605 fn test_new_free_doc() {
4606 unsafe {
4607 let doc = new_doc(ptr::null());
4608 assert!(!doc.is_null());
4609 assert_eq!((*doc).type_, XML_DOCUMENT_NODE as c_int);
4610 assert_eq!((*doc).standalone, -1);
4611 assert_eq!((*doc).doc, doc);
4612 assert!(!(*doc).version.is_null());
4613 free_doc(doc);
4614 }
4615 }
4616
4617 #[test]
4625 fn test_new_doc_with_version() {
4626 unsafe {
4627 let ver = c_str("2.0");
4628 let doc = new_doc(ver);
4629 assert!(!doc.is_null());
4630 let doc_ver = (*doc).version;
4631 assert!(!doc_ver.is_null());
4632 assert!(crate::abi::exports_xml2::xmlStrEqual(doc_ver, ver,) != 0);
4633 allocator::xmlFreeImpl(ver as *mut c_void);
4634 free_doc(doc);
4635 }
4636 }
4637
4638 #[test]
4646 fn test_new_node() {
4647 unsafe {
4648 let doc = new_doc(ptr::null());
4649 let node = new_node(ptr::null_mut(), c_str("root"));
4650 assert!(!node.is_null());
4651 assert_eq!((*node).type_, XML_ELEMENT_NODE as c_int);
4652 assert!(!(*node).name.is_null());
4653 free_node(node);
4654 free_doc(doc);
4655 }
4656 }
4657
4658 #[test]
4666 fn test_node_get_content_recurses_descendants() {
4667 unsafe {
4672 let doc = new_doc(ptr::null());
4673 let root = new_node(ptr::null_mut(), c_str("library"));
4674 doc_set_root_element(doc, root);
4675 let book = new_child(root, ptr::null_mut(), c_str("book"));
4676 let title = new_child(book, ptr::null_mut(), c_str("title"));
4677 let text = new_text(c_str("Rust"));
4678 add_child(title, text);
4679
4680 let content = node_get_content(book);
4681 assert!(!content.is_null());
4682 let s = core::slice::from_raw_parts(
4683 content,
4684 libc::strlen(content as *const libc::c_char) as usize,
4685 );
4686 assert_eq!(s, b"Rust", "descendant text not concatenated");
4687 allocator::xmlFreeImpl(content as *mut c_void);
4688
4689 free_doc(doc);
4690 }
4691 }
4692
4693 #[test]
4700 fn test_doc_set_root_element() {
4701 unsafe {
4702 let doc = new_doc(ptr::null());
4703 let root = new_node(ptr::null_mut(), c_str("root"));
4704 let old = doc_set_root_element(doc, root);
4705 assert!(old.is_null());
4706 assert_eq!(doc_get_root_element(doc), root);
4707 assert_eq!((*doc).children, root);
4708 free_doc(doc);
4709 }
4710 }
4711
4712 #[test]
4720 fn test_add_child_and_sibling() {
4721 unsafe {
4722 let doc = new_doc(ptr::null());
4723 let root = new_node(ptr::null_mut(), c_str("root"));
4724 doc_set_root_element(doc, root);
4725
4726 let child1 = new_child(root, ptr::null_mut(), c_str("child1"));
4727 assert!(!child1.is_null());
4728 assert_eq!((*child1).parent, root);
4729 assert_eq!((*root).children, child1);
4730 assert_eq!((*root).last, child1);
4731
4732 let child2 = new_child(root, ptr::null_mut(), c_str("child2"));
4733 assert!(!child2.is_null());
4734 assert_eq!((*child2).parent, root);
4735 assert_eq!((*child1).next, child2);
4736 assert_eq!((*child2).prev, child1);
4737 assert_eq!((*root).last, child2);
4738
4739 let sibling = new_node(ptr::null_mut(), c_str("sibling"));
4741 add_sibling(child2, sibling);
4742 assert_eq!((*child2).next, sibling);
4743 assert_eq!((*sibling).prev, child2);
4744 assert_eq!((*root).last, sibling);
4745
4746 free_doc(doc);
4747 }
4748 }
4749
4750 #[test]
4758 fn test_unlink_node() {
4759 unsafe {
4760 let doc = new_doc(ptr::null());
4761 let root = new_node(ptr::null_mut(), c_str("root"));
4762 doc_set_root_element(doc, root);
4763
4764 let child1 = new_child(root, ptr::null_mut(), c_str("c1"));
4765 let child2 = new_child(root, ptr::null_mut(), c_str("c2"));
4766
4767 unlink_node(child1);
4768 assert!((*child1).parent.is_null());
4769 assert!((*child1).prev.is_null());
4770 assert!((*child1).next.is_null());
4771 assert_eq!((*root).children, child2);
4772 assert_eq!((*root).last, child2);
4773
4774 free_node(child1);
4775 free_doc(doc);
4776 }
4777 }
4778
4779 #[test]
4786 fn test_text_and_comment_nodes() {
4787 unsafe {
4788 let text = new_text(c_str("hello world"));
4789 assert!(!text.is_null());
4790 assert_eq!((*text).type_, XML_TEXT_NODE as c_int);
4791 assert!(!(*text).content.is_null());
4792 free_node(text);
4793
4794 let comment = new_comment(c_str("my comment"));
4795 assert!(!comment.is_null());
4796 assert_eq!((*comment).type_, XML_COMMENT_NODE as c_int);
4797 free_node(comment);
4798
4799 let pi = new_pi(c_str("xml"), c_str("version='1.0'"));
4800 assert!(!pi.is_null());
4801 assert_eq!((*pi).type_, XML_PI_NODE as c_int);
4802 free_node(pi);
4803 }
4804 }
4805
4806 #[test]
4814 fn test_set_and_get_prop() {
4815 unsafe {
4816 let doc = new_doc(ptr::null());
4817 let root = new_node(ptr::null_mut(), c_str("root"));
4818 doc_set_root_element(doc, root);
4819
4820 let attr = set_prop(root, c_str("id"), c_str("42"));
4821 assert!(!attr.is_null());
4822 assert_eq!((*attr).type_, XML_ATTRIBUTE_NODE as c_int);
4823
4824 let value = get_prop(root, c_str("id"));
4825 assert!(!value.is_null());
4826 assert!(crate::abi::exports_xml2::xmlStrEqual(value, c_str("42")) != 0);
4827 allocator::xmlFreeImpl(value as *mut c_void);
4828
4829 free_doc(doc);
4830 }
4831 }
4832
4833 #[test]
4841 fn test_remove_prop() {
4842 unsafe {
4843 let doc = new_doc(ptr::null());
4844 let root = new_node(ptr::null_mut(), c_str("root"));
4845 doc_set_root_element(doc, root);
4846
4847 set_prop(root, c_str("a"), c_str("1"));
4848 set_prop(root, c_str("b"), c_str("2"));
4849
4850 let value = get_prop(root, c_str("a"));
4851 assert!(!value.is_null());
4852 allocator::xmlFreeImpl(value as *mut c_void);
4853
4854 let attr = (*root).properties;
4856 assert!(!attr.is_null());
4857 let result = remove_prop(attr);
4858 assert_eq!(result, 0);
4859
4860 let value2 = get_prop(root, c_str("a"));
4862 assert!(value2.is_null());
4863
4864 free_doc(doc);
4865 }
4866 }
4867
4868 #[test]
4876 fn test_namespace_operations() {
4877 unsafe {
4878 let doc = new_doc(ptr::null());
4879 let root = new_node(ptr::null_mut(), c_str("root"));
4880 doc_set_root_element(doc, root);
4881
4882 let ns = new_ns(root, c_str("http://example.com"), c_str("ex"));
4883 assert!(!ns.is_null());
4884 assert!(!(*root).nsDef.is_null());
4885
4886 set_ns(root, ns);
4887 assert_eq!((*root).ns, ns);
4888
4889 let found = search_ns(doc, root, c_str("ex"));
4890 assert_eq!(found, ns);
4891
4892 let found_href = search_ns_by_href(doc, root, c_str("http://example.com"));
4893 assert_eq!(found_href, ns);
4894
4895 free_doc(doc);
4896 }
4897 }
4898
4899 #[test]
4907 fn test_new_dtd() {
4908 unsafe {
4909 let doc = new_doc(ptr::null());
4910 let dtd = new_dtd(doc, c_str("root"), c_str("-//TEST//DTD"), c_str("test.dtd"));
4911 assert!(!dtd.is_null());
4912 assert_eq!((*dtd).type_, XML_DTD_NODE as c_int);
4913 assert_eq!(get_int_subset(doc), dtd);
4914 free_doc(doc);
4915 }
4916 }
4917
4918 #[test]
4925 fn test_copy_node_deep() {
4926 unsafe {
4927 let doc = new_doc(ptr::null());
4928 let root = new_node(ptr::null_mut(), c_str("root"));
4929 doc_set_root_element(doc, root);
4930 let _child = new_child(root, ptr::null_mut(), c_str("child"));
4931
4932 let copy = copy_node(root, 1);
4933 assert!(!copy.is_null());
4934 assert_eq!((*copy).type_, XML_ELEMENT_NODE as c_int);
4935 assert!(!(*copy).children.is_null());
4937 assert_eq!((*(*copy).children).type_, XML_ELEMENT_NODE as c_int);
4938
4939 free_node(copy);
4940 free_doc(doc);
4941 }
4942 }
4943
4944 #[test]
4952 fn test_new_cdata_block() {
4953 unsafe {
4954 let doc = new_doc(ptr::null());
4955 let content = c_str("some <cdata> content");
4956 let cdata = new_cdata_block(doc, content, 20);
4957 assert!(!cdata.is_null());
4958 assert_eq!((*cdata).type_, XML_CDATA_SECTION_NODE as c_int);
4959 free_node(cdata);
4960 free_doc(doc);
4961 }
4962 }
4963
4964 #[test]
4973 fn test_null_handling() {
4974 unsafe {
4975 assert!(!new_doc(ptr::null()).is_null()); let doc = new_doc(ptr::null());
4977 assert!(!new_node(ptr::null_mut(), ptr::null()).is_null()); free_node(ptr::null_mut()); free_doc(ptr::null_mut()); unlink_node(ptr::null_mut()); assert!(add_child(ptr::null_mut(), ptr::null_mut()).is_null());
4982 assert!(add_sibling(ptr::null_mut(), ptr::null_mut()).is_null());
4983 free_doc(doc);
4984 }
4985 }
4986
4987 unsafe fn buf_eq_str(buf: *mut _xmlBuffer, expected: &str) -> bool {
4998 let content = io::buf_content(buf);
4999 if content.is_null() {
5000 return expected.is_empty();
5001 }
5002 let len = io::buf_length(buf) as usize;
5003 if len != expected.len() {
5004 return false;
5005 }
5006 let slice = unsafe { core::slice::from_raw_parts(content, len) };
5007 slice == expected.as_bytes()
5008 }
5009
5010 #[test]
5018 fn test_serialize_empty_document() {
5019 unsafe {
5020 let doc = new_doc(ptr::null());
5021 let buf = io::buf_create(-1);
5022 assert!(!buf.is_null());
5023
5024 let ret = doc_dump(buf, doc);
5025 assert!(ret >= 0);
5026
5027 let expected = "<?xml version=\"1.0\"?>\n";
5031 assert!(buf_eq_str(buf, expected));
5032
5033 io::buf_free(buf);
5034 free_doc(doc);
5035 }
5036 }
5037
5038 #[test]
5045 fn test_serialize_element_with_text() {
5046 unsafe {
5047 let doc = new_doc(ptr::null());
5048 let root = new_node(ptr::null_mut(), c_str("root"));
5049 doc_set_root_element(doc, root);
5050
5051 let text = new_text(c_str("hello world"));
5053 add_child(root, text);
5054
5055 let buf = io::buf_create(-1);
5056 assert!(!buf.is_null());
5057
5058 let ret = doc_dump(buf, doc);
5059 assert!(ret >= 0);
5060
5061 let expected = "<?xml version=\"1.0\"?>\n<root>hello world</root>\n";
5062 assert!(buf_eq_str(buf, expected));
5063
5064 io::buf_free(buf);
5065 free_doc(doc);
5066 }
5067 }
5068
5069 #[test]
5076 fn test_serialize_element_with_attributes() {
5077 unsafe {
5078 let doc = new_doc(ptr::null());
5079 let root = new_node(ptr::null_mut(), c_str("root"));
5080 doc_set_root_element(doc, root);
5081
5082 set_prop(root, c_str("id"), c_str("42"));
5083 set_prop(root, c_str("name"), c_str("test"));
5084
5085 let buf = io::buf_create(-1);
5086 assert!(!buf.is_null());
5087
5088 let ret = doc_dump(buf, doc);
5089 assert!(ret >= 0);
5090
5091 let expected = "<?xml version=\"1.0\"?>\n<root id=\"42\" name=\"test\"/>\n";
5092 assert!(buf_eq_str(buf, expected));
5093
5094 io::buf_free(buf);
5095 free_doc(doc);
5096 }
5097 }
5098
5099 #[test]
5106 fn test_serialize_nested_elements() {
5107 unsafe {
5108 let doc = new_doc(ptr::null());
5109 let root = new_node(ptr::null_mut(), c_str("root"));
5110 doc_set_root_element(doc, root);
5111
5112 let child = new_child(root, ptr::null_mut(), c_str("child"));
5113 let grandchild = new_child(child, ptr::null_mut(), c_str("gc"));
5114 let text = new_text(c_str("text"));
5115 add_child(grandchild, text);
5116
5117 let buf = io::buf_create(-1);
5118 assert!(!buf.is_null());
5119
5120 let ret = doc_dump(buf, doc);
5121 assert!(ret >= 0);
5122
5123 let expected = "<?xml version=\"1.0\"?>\n<root><child><gc>text</gc></child></root>\n";
5124 assert!(buf_eq_str(buf, expected));
5125
5126 io::buf_free(buf);
5127 free_doc(doc);
5128 }
5129 }
5130
5131 #[test]
5138 fn test_serialize_with_formatting() {
5139 unsafe {
5140 let doc = new_doc(ptr::null());
5141 let root = new_node(ptr::null_mut(), c_str("root"));
5142 doc_set_root_element(doc, root);
5143
5144 let child = new_child(root, ptr::null_mut(), c_str("child"));
5145 let text = new_text(c_str("text"));
5146 add_child(child, text);
5147
5148 let buf = io::buf_create(-1);
5149 assert!(!buf.is_null());
5150
5151 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
5152
5153 let expected = "<?xml version=\"1.0\"?>\n<root>\n <child>text</child>\n</root>\n";
5154 assert!(buf_eq_str(buf, expected));
5155
5156 io::buf_free(buf);
5157 free_doc(doc);
5158 }
5159 }
5160
5161 #[test]
5168 fn test_serialize_escape_ampersand() {
5169 unsafe {
5170 let doc = new_doc(ptr::null());
5171 let root = new_node(ptr::null_mut(), c_str("root"));
5172 doc_set_root_element(doc, root);
5173
5174 let text = new_text(c_str("a & b"));
5175 add_child(root, text);
5176
5177 let buf = io::buf_create(-1);
5178 assert!(!buf.is_null());
5179
5180 let ret = doc_dump(buf, doc);
5181 assert!(ret >= 0);
5182
5183 let expected = "<?xml version=\"1.0\"?>\n<root>a & b</root>\n";
5184 assert!(buf_eq_str(buf, expected));
5185
5186 io::buf_free(buf);
5187 free_doc(doc);
5188 }
5189 }
5190
5191 #[test]
5198 fn test_serialize_escape_angle_brackets() {
5199 unsafe {
5200 let doc = new_doc(ptr::null());
5201 let root = new_node(ptr::null_mut(), c_str("root"));
5202 doc_set_root_element(doc, root);
5203
5204 let text = new_text(c_str("x < y > z"));
5205 add_child(root, text);
5206
5207 let buf = io::buf_create(-1);
5208 assert!(!buf.is_null());
5209
5210 let ret = doc_dump(buf, doc);
5211 assert!(ret >= 0);
5212
5213 let expected = "<?xml version=\"1.0\"?>\n<root>x < y > z</root>\n";
5214 assert!(buf_eq_str(buf, expected));
5215
5216 io::buf_free(buf);
5217 free_doc(doc);
5218 }
5219 }
5220
5221 #[test]
5228 fn test_serialize_comment() {
5229 unsafe {
5230 let doc = new_doc(ptr::null());
5231 let root = new_node(ptr::null_mut(), c_str("root"));
5232 doc_set_root_element(doc, root);
5233
5234 let comment = new_comment(c_str("my comment"));
5235 add_child(root, comment);
5236
5237 let buf = io::buf_create(-1);
5238 assert!(!buf.is_null());
5239
5240 let ret = doc_dump(buf, doc);
5241 assert!(ret >= 0);
5242
5243 let expected = "<?xml version=\"1.0\"?>\n<root><!--my comment--></root>\n";
5244 assert!(buf_eq_str(buf, expected));
5245
5246 io::buf_free(buf);
5247 free_doc(doc);
5248 }
5249 }
5250
5251 #[test]
5258 fn test_serialize_pi() {
5259 unsafe {
5260 let doc = new_doc(ptr::null());
5261 let root = new_node(ptr::null_mut(), c_str("root"));
5262 doc_set_root_element(doc, root);
5263
5264 let pi = new_pi(
5265 c_str("xml-stylesheet"),
5266 c_str("href=\"style.xsl\" type=\"text/xsl\""),
5267 );
5268 add_child(root, pi);
5269
5270 let buf = io::buf_create(-1);
5271 assert!(!buf.is_null());
5272
5273 let ret = doc_dump(buf, doc);
5274 assert!(ret >= 0);
5275
5276 let expected = "<?xml version=\"1.0\"?>\n<root><?xml-stylesheet href=\"style.xsl\" type=\"text/xsl\"?></root>\n";
5277 assert!(buf_eq_str(buf, expected));
5278
5279 io::buf_free(buf);
5280 free_doc(doc);
5281 }
5282 }
5283
5284 #[test]
5291 fn test_serialize_self_closing() {
5292 unsafe {
5293 let doc = new_doc(ptr::null());
5294 let root = new_node(ptr::null_mut(), c_str("empty"));
5295 doc_set_root_element(doc, root);
5296
5297 let buf = io::buf_create(-1);
5298 assert!(!buf.is_null());
5299
5300 let ret = doc_dump(buf, doc);
5301 assert!(ret >= 0);
5302
5303 let expected = "<?xml version=\"1.0\"?>\n<empty/>\n";
5304 assert!(buf_eq_str(buf, expected));
5305
5306 io::buf_free(buf);
5307 free_doc(doc);
5308 }
5309 }
5310
5311 #[test]
5319 fn test_dump_node_to_string() {
5320 unsafe {
5321 let node = new_node(ptr::null_mut(), c_str("foo"));
5322 let text = new_text(c_str("bar"));
5323 add_child(node, text);
5324
5325 let result = dump_node(node);
5326 assert!(!result.is_null());
5327
5328 let len = xml_strlen(result);
5329 let slice = { core::slice::from_raw_parts(result, len as usize) };
5330 assert_eq!(slice, b"<foo>bar</foo>");
5331
5332 allocator::xmlFreeImpl(result as *mut c_void);
5333 free_node(node);
5334 }
5335 }
5336
5337 #[test]
5345 fn test_dump_doc_to_string() {
5346 unsafe {
5347 let doc = new_doc(ptr::null());
5348 let root = new_node(ptr::null_mut(), c_str("root"));
5349 doc_set_root_element(doc, root);
5350
5351 let result = dump_doc(doc);
5352 assert!(!result.is_null());
5353
5354 let len = xml_strlen(result);
5355 let slice = { core::slice::from_raw_parts(result, len as usize) };
5356 let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
5357 assert_eq!(slice, expected.as_bytes());
5358
5359 allocator::xmlFreeImpl(result as *mut c_void);
5360 free_doc(doc);
5361 }
5362 }
5363
5364 #[test]
5372 fn test_xmlDocDumpFormatMemory() {
5373 unsafe {
5374 let doc = new_doc(ptr::null());
5375 let root = new_node(ptr::null_mut(), c_str("root"));
5376 doc_set_root_element(doc, root);
5377
5378 let mut mem: *mut xmlChar = ptr::null_mut();
5379 let mut size: c_int = 0;
5380
5381 xmlDocDumpFormatMemory(doc, &mut mem, &mut size, 0);
5382
5383 assert!(!mem.is_null());
5384 assert!(size > 0);
5385
5386 let slice = { core::slice::from_raw_parts(mem, size as usize) };
5387 let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
5390 assert_eq!(slice, expected.as_bytes());
5391
5392 allocator::xmlFreeImpl(mem as *mut c_void);
5393 free_doc(doc);
5394 }
5395 }
5396
5397 #[test]
5404 fn test_serialize_escape_attribute() {
5405 unsafe {
5406 let doc = new_doc(ptr::null());
5407 let root = new_node(ptr::null_mut(), c_str("root"));
5408 doc_set_root_element(doc, root);
5409
5410 set_prop(root, c_str("desc"), c_str("a < b & c \"quoted\""));
5412
5413 let buf = io::buf_create(-1);
5414 assert!(!buf.is_null());
5415
5416 let ret = doc_dump(buf, doc);
5417 assert!(ret >= 0);
5418
5419 let expected =
5420 "<?xml version=\"1.0\"?>\n<root desc=\"a < b & c "quoted"\"/>\n";
5421 assert!(buf_eq_str(buf, expected));
5422
5423 io::buf_free(buf);
5424 free_doc(doc);
5425 }
5426 }
5427}