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 {
725 if name.is_null() {
726 return ptr::null_mut();
727 }
728 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
729 if node.is_null() {
730 return ptr::null_mut();
731 }
732
733 unsafe {
734 (*node).type_ = XML_ELEMENT_NODE as c_int;
735 (*node).name = dup_xml_str(name);
736 (*node).ns = ns;
737 (*node).line = 0;
738 (*node).extra = 0;
739
740 if !ns.is_null() {
741 (*ns).context = node as *mut _xmlDoc;
742 }
743 }
744
745 crate::abi::data_globals::register_node_hook(node);
748
749 node
750}
751
752pub unsafe fn free_node(node: *mut _xmlNode) {
767 if node.is_null() {
768 return;
769 }
770
771 let n = unsafe { &mut *node };
772
773 if n.type_ == XML_DTD_NODE as c_int {
777 free_dtd(node as *mut _xmlDtd);
778 return;
779 } else if n.type_ == XML_NAMESPACE_DECL as c_int {
780 free_ns(node as *mut _xmlNs);
781 return;
782 } else if n.type_ == XML_ATTRIBUTE_NODE as c_int {
783 free_prop(node as *mut _xmlAttr);
784 return;
785 } else if n.type_ == XML_ELEMENT_DECL as c_int {
786 crate::xml::dtd::free_element(node as *mut _xmlElement);
787 return;
788 } else if n.type_ == XML_ATTRIBUTE_DECL as c_int {
789 crate::xml::dtd::free_attribute(node as *mut _xmlAttribute);
790 return;
791 } else if n.type_ == XML_ENTITY_DECL as c_int {
792 crate::xml::entities::free_entity(node as *mut _xmlEntity);
793 return;
794 }
795
796 crate::abi::data_globals::deregister_node_hook(node);
799
800 let is_element = n.type_ == XML_ELEMENT_NODE as c_int;
805 if is_element && !n.properties.is_null() {
806 free_prop_list(n.properties);
807 }
808
809 if is_element && !n.nsDef.is_null() {
810 free_ns_list(n.nsDef);
811 }
812
813 if !n.name.is_null() {
815 allocator::xmlFreeImpl(n.name as *mut c_void);
816 }
817
818 if !n.content.is_null() {
823 let node_type = n.type_;
824 if node_type == XML_TEXT_NODE as c_int
825 || node_type == XML_CDATA_SECTION_NODE as c_int
826 || node_type == XML_COMMENT_NODE as c_int
827 || node_type == XML_PI_NODE as c_int
828 {
829 let inline_addr = std::ptr::addr_of_mut!((*node).properties) as *const c_void;
830 if n.content as *const c_void != inline_addr {
831 allocator::xmlFreeImpl(n.content as *mut c_void);
832 }
833 }
834 }
835
836 allocator::xmlFreeImpl(node as *mut c_void);
837}
838
839pub unsafe fn free_node_list(node: *mut _xmlNode) {
858 let mut cur = node;
859 while !cur.is_null() {
860 let next = unsafe { (*cur).next };
861 let t = unsafe { (*cur).type_ };
862
863 if t == XML_DTD_NODE as c_int {
864 unsafe {
866 (*cur).prev = ptr::null_mut();
867 (*cur).next = ptr::null_mut();
868 }
869 cur = next;
870 continue;
871 }
872
873 if t != XML_ENTITY_REF_NODE as c_int && !unsafe { (*cur).children }.is_null() {
876 free_node_list(unsafe { (*cur).children });
877 }
878
879 free_node(cur);
880 cur = next;
881 }
882}
883
884unsafe fn free_prop_list(prop: *mut _xmlAttr) {
890 let mut cur = prop;
891 while !cur.is_null() {
892 let next = unsafe { (*cur).next };
893 free_prop(cur);
894 cur = next;
895 }
896}
897
898unsafe fn free_prop(prop: *mut _xmlAttr) {
904 if prop.is_null() {
905 return;
906 }
907
908 if !unsafe { (*prop).children }.is_null() {
910 free_node_list(unsafe { (*prop).children });
911 }
912
913 if !unsafe { (*prop).name }.is_null() {
915 allocator::xmlFreeImpl(unsafe { (*prop).name } as *mut c_void);
916 }
917
918 allocator::xmlFreeImpl(prop as *mut c_void);
919}
920
921unsafe fn free_ns_list(ns: *mut _xmlNs) {
927 let mut cur = ns;
928 while !cur.is_null() {
929 let next = unsafe { (*cur).next };
930 free_ns(cur);
931 cur = next;
932 }
933}
934
935unsafe fn free_ns(ns: *mut _xmlNs) {
941 if ns.is_null() {
942 return;
943 }
944
945 if !unsafe { (*ns).href }.is_null() {
947 allocator::xmlFreeImpl(unsafe { (*ns).href } as *mut c_void);
948 }
949 if !unsafe { (*ns).prefix }.is_null() {
950 allocator::xmlFreeImpl(unsafe { (*ns).prefix } as *mut c_void);
951 }
952
953 allocator::xmlFreeImpl(ns as *mut c_void);
954}
955
956pub unsafe fn copy_node(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
971 if node.is_null() {
972 return ptr::null_mut();
973 }
974
975 let n = unsafe { &*node };
976
977 let new_node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
978 if new_node.is_null() {
979 return ptr::null_mut();
980 }
981
982 unsafe {
983 (*new_node).type_ = n.type_;
984 (*new_node).name = dup_xml_str(n.name);
985 if n.type_ == XML_ELEMENT_NODE as c_int {
989 (*new_node).line = n.line;
990 }
991 (*new_node).extra = n.extra;
992 (*new_node).psvi = n.psvi;
993 (*new_node)._private = n._private;
994
995 (*new_node).ns = n.ns;
997
998 let is_element = n.type_ == XML_ELEMENT_NODE as c_int;
1001 if is_element && !n.nsDef.is_null() {
1002 (*new_node).nsDef = copy_ns_list(n.nsDef);
1003 }
1004
1005 let node_type = n.type_;
1007 if (node_type == XML_TEXT_NODE as c_int
1008 || node_type == XML_CDATA_SECTION_NODE as c_int
1009 || node_type == XML_COMMENT_NODE as c_int
1010 || node_type == XML_PI_NODE as c_int)
1011 && !n.content.is_null()
1012 {
1013 (*new_node).content = dup_xml_str(n.content);
1014 }
1015
1016 if is_element && !n.properties.is_null() {
1018 (*new_node).properties = copy_prop_list(n.properties);
1019 let mut prop = (*new_node).properties;
1021 while !prop.is_null() {
1022 (*prop).parent = new_node;
1023 if !(*prop).children.is_null() {
1024 propagate_doc((*prop).children, (*new_node).doc);
1025 }
1026 prop = (*prop).next;
1027 }
1028 }
1029
1030 if recursive != 0 && !n.children.is_null() {
1033 (*new_node).children = copy_node_list(n.children, recursive);
1034 if !(*new_node).children.is_null() {
1035 let mut child = (*new_node).children;
1036 let mut last_child = child;
1037 while !child.is_null() {
1038 (*child).parent = new_node;
1039 (*child).doc = (*new_node).doc;
1040 propagate_doc(child, (*new_node).doc);
1041 if (*child).next.is_null() {
1042 last_child = child;
1043 }
1044 child = (*child).next;
1045 }
1046 (*new_node).last = last_child;
1047 }
1048 }
1049 }
1050
1051 new_node
1052}
1053
1054unsafe fn copy_node_list(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
1066 if node.is_null() {
1067 return ptr::null_mut();
1068 }
1069
1070 let n = unsafe { &*node };
1071 let new_node = copy_node(node, recursive);
1072 if new_node.is_null() {
1073 return ptr::null_mut();
1074 }
1075
1076 let mut prev = new_node;
1077 let mut cur = n.next;
1078
1079 while !cur.is_null() {
1080 let new_cur = copy_node(cur, recursive);
1081 if new_cur.is_null() {
1082 break;
1083 }
1084 unsafe {
1085 (*prev).next = new_cur;
1086 (*new_cur).prev = prev;
1087 }
1088 prev = new_cur;
1089 cur = unsafe { (*cur).next };
1090 }
1091
1092 new_node
1093}
1094
1095unsafe fn copy_ns_list(ns: *const _xmlNs) -> *mut _xmlNs {
1105 if ns.is_null() {
1106 return ptr::null_mut();
1107 }
1108
1109 let n = unsafe { &*ns };
1110 let new_ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
1111 if new_ns.is_null() {
1112 return ptr::null_mut();
1113 }
1114
1115 unsafe {
1116 (*new_ns).type_ = n.type_;
1117 (*new_ns).href = dup_xml_str(n.href);
1118 (*new_ns).prefix = dup_xml_str(n.prefix);
1119 (*new_ns)._private = n._private;
1120 }
1121
1122 let mut prev = new_ns;
1123 let mut cur = n.next;
1124
1125 while !cur.is_null() {
1126 let c = unsafe { &*cur };
1127 let new_cur = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
1128 if new_cur.is_null() {
1129 break;
1130 }
1131 unsafe {
1132 (*new_cur).type_ = c.type_;
1133 (*new_cur).href = dup_xml_str(c.href);
1134 (*new_cur).prefix = dup_xml_str(c.prefix);
1135 (*new_cur)._private = c._private;
1136 (*prev).next = new_cur;
1137 }
1138 prev = new_cur;
1139 cur = c.next;
1140 }
1141
1142 new_ns
1143}
1144
1145unsafe fn copy_prop_list(prop: *const _xmlAttr) -> *mut _xmlAttr {
1156 if prop.is_null() {
1157 return ptr::null_mut();
1158 }
1159
1160 let p = unsafe { &*prop };
1161 let new_prop = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
1162 if new_prop.is_null() {
1163 return ptr::null_mut();
1164 }
1165
1166 unsafe {
1167 (*new_prop).type_ = p.type_;
1168 (*new_prop).name = dup_xml_str(p.name);
1169 (*new_prop).ns = p.ns;
1170 (*new_prop).atype = p.atype;
1171
1172 if !p.children.is_null() {
1174 (*new_prop).children = copy_node_list(p.children, 1);
1175 if !(*new_prop).children.is_null() {
1176 (*(*new_prop).children).parent = new_prop as *mut _xmlNode;
1177 }
1178 }
1179 }
1180
1181 let mut prev = new_prop;
1182 let mut cur = p.next;
1183
1184 while !cur.is_null() {
1185 let c = unsafe { &*cur };
1186 let new_cur = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
1187 if new_cur.is_null() {
1188 break;
1189 }
1190 unsafe {
1191 (*new_cur).type_ = c.type_;
1192 (*new_cur).name = dup_xml_str(c.name);
1193 (*new_cur).ns = c.ns;
1194 (*new_cur).atype = c.atype;
1195
1196 if !c.children.is_null() {
1197 (*new_cur).children = copy_node_list(c.children, 1);
1198 if !(*new_cur).children.is_null() {
1199 (*(*new_cur).children).parent = new_cur as *mut _xmlNode;
1200 }
1201 }
1202
1203 (*prev).next = new_cur;
1204 }
1205 prev = new_cur;
1206 cur = c.next;
1207 }
1208
1209 new_prop
1210}
1211
1212unsafe fn propagate_doc(node: *mut _xmlNode, doc: *mut _xmlDoc) {
1223 let mut cur = node;
1224 while !cur.is_null() {
1225 unsafe {
1226 (*cur).doc = doc;
1227
1228 if (*cur).type_ == XML_ELEMENT_NODE as c_int {
1232 let mut prop = (*cur).properties;
1233 while !prop.is_null() {
1234 (*prop).doc = doc;
1235 if !(*prop).children.is_null() {
1236 propagate_doc((*prop).children, doc);
1237 }
1238 prop = (*prop).next;
1239 }
1240 }
1241
1242 if !(*cur).children.is_null() {
1244 propagate_doc((*cur).children, doc);
1245 }
1246 }
1247 cur = unsafe { (*cur).next };
1248 }
1249}
1250
1251pub unsafe fn unlink_node(node: *mut _xmlNode) {
1267 if node.is_null() {
1268 return;
1269 }
1270
1271 let n = unsafe { &mut *node };
1272
1273 let prev = n.prev;
1275 let next = n.next;
1276
1277 if !prev.is_null() {
1278 unsafe { (*prev).next = next };
1279 }
1280 if !next.is_null() {
1281 unsafe { (*next).prev = prev };
1282 }
1283
1284 let parent = n.parent;
1286 if !parent.is_null() {
1287 if unsafe { (*parent).children } == node {
1288 unsafe { (*parent).children = next };
1289 }
1290 if unsafe { (*parent).last } == node {
1291 unsafe { (*parent).last = prev };
1292 }
1293 }
1294
1295 let doc = n.doc;
1297 if !doc.is_null() && !parent.is_null() {
1298 }
1300 if !doc.is_null() && parent.is_null() {
1301 if unsafe { (*doc).children } == node {
1303 unsafe { (*doc).children = next };
1304 }
1305 if unsafe { (*doc).last } == node {
1306 unsafe { (*doc).last = prev };
1307 }
1308 }
1309
1310 n.parent = ptr::null_mut();
1312 n.prev = ptr::null_mut();
1313 n.next = ptr::null_mut();
1314}
1315
1316pub unsafe fn add_child(parent: *mut _xmlNode, cur: *mut _xmlNode) -> *mut _xmlNode {
1332 if parent.is_null() || cur.is_null() {
1333 return ptr::null_mut();
1334 }
1335
1336 let p = unsafe { &mut *parent };
1337 let c = unsafe { &mut *cur };
1338
1339 if !c.parent.is_null() || !c.prev.is_null() || !c.next.is_null() {
1341 unlink_node(cur);
1342 }
1343
1344 c.parent = parent;
1346
1347 if p.children.is_null() {
1348 p.children = cur;
1350 p.last = cur;
1351 c.prev = ptr::null_mut();
1352 c.next = ptr::null_mut();
1353 } else {
1354 c.prev = p.last;
1356 c.next = ptr::null_mut();
1357 if !p.last.is_null() {
1358 unsafe { (*p.last).next = cur };
1359 }
1360 p.last = cur;
1361 }
1362
1363 let doc = if !p.doc.is_null() {
1365 p.doc
1366 } else {
1367 ptr::null_mut()
1368 };
1369 if !doc.is_null() && c.doc != doc {
1370 propagate_doc(cur, doc);
1371 }
1372
1373 cur
1374}
1375
1376pub unsafe fn add_sibling(cur: *mut _xmlNode, elem: *mut _xmlNode) -> *mut _xmlNode {
1392 if cur.is_null() || elem.is_null() {
1393 return ptr::null_mut();
1394 }
1395
1396 let c = unsafe { &mut *cur };
1397
1398 let e = unsafe { &mut *elem };
1400 if !e.parent.is_null() || !e.prev.is_null() || !e.next.is_null() {
1401 unlink_node(elem);
1402 }
1403
1404 e.parent = c.parent;
1406
1407 e.prev = cur;
1409 e.next = c.next;
1410
1411 if !c.next.is_null() {
1412 unsafe { (*c.next).prev = elem };
1413 }
1414 c.next = elem;
1415
1416 let parent = c.parent;
1418 if !parent.is_null() && unsafe { (*parent).last } == cur {
1419 unsafe { (*parent).last = elem };
1420 }
1421
1422 if !c.doc.is_null() && e.doc != c.doc {
1424 propagate_doc(elem, c.doc);
1425 }
1426
1427 elem
1428}
1429
1430pub unsafe fn add_sibling_before(cur: *mut _xmlNode, elem: *mut _xmlNode) -> *mut _xmlNode {
1446 if cur.is_null() || elem.is_null() {
1447 return ptr::null_mut();
1448 }
1449
1450 let c = unsafe { &mut *cur };
1451
1452 let e = unsafe { &mut *elem };
1454 if !e.parent.is_null() || !e.prev.is_null() || !e.next.is_null() {
1455 unlink_node(elem);
1456 }
1457
1458 e.parent = c.parent;
1460
1461 e.prev = c.prev;
1463 e.next = cur;
1464
1465 if !c.prev.is_null() {
1466 unsafe { (*c.prev).next = elem };
1467 }
1468 c.prev = elem;
1469
1470 let parent = c.parent;
1472 if !parent.is_null() && unsafe { (*parent).children } == cur {
1473 unsafe { (*parent).children = elem };
1474 }
1475
1476 let doc = c.doc;
1478 if !doc.is_null() && parent.is_null() && unsafe { (*doc).children } == cur {
1479 unsafe { (*doc).children = elem };
1480 }
1481
1482 if !c.doc.is_null() && e.doc != c.doc {
1484 propagate_doc(elem, c.doc);
1485 }
1486
1487 elem
1488}
1489
1490pub unsafe fn new_child(
1505 parent: *mut _xmlNode,
1506 ns: *mut _xmlNs,
1507 name: *const xmlChar,
1508) -> *mut _xmlNode {
1509 let node = new_node(ns, name);
1510 if node.is_null() {
1511 return ptr::null_mut();
1512 }
1513
1514 if !parent.is_null() {
1515 add_child(parent, node);
1516 }
1517
1518 node
1519}
1520
1521pub unsafe fn new_text(content: *const xmlChar) -> *mut _xmlNode {
1540 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1541 if node.is_null() {
1542 return ptr::null_mut();
1543 }
1544
1545 unsafe {
1546 (*node).type_ = XML_TEXT_NODE as c_int;
1547 (*node).name = dup_xml_str(b"text\0" as *const u8 as *const xmlChar);
1548 (*node).content = if content.is_null() {
1549 let empty = allocator::xmlMallocImpl(1) as *mut xmlChar;
1550 if !empty.is_null() {
1551 *empty = 0;
1552 }
1553 empty
1554 } else {
1555 dup_xml_str(content)
1556 };
1557 (*node).line = 0;
1558 }
1559
1560 crate::abi::data_globals::register_node_hook(node);
1563
1564 node
1565}
1566
1567pub unsafe fn new_comment(content: *const xmlChar) -> *mut _xmlNode {
1581 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1582 if node.is_null() {
1583 return ptr::null_mut();
1584 }
1585
1586 unsafe {
1587 (*node).type_ = XML_COMMENT_NODE as c_int;
1588 (*node).name = dup_xml_str(b"comment\0" as *const u8 as *const xmlChar);
1589 (*node).content = dup_xml_str(content);
1590 (*node).line = 0;
1591 }
1592
1593 crate::abi::data_globals::register_node_hook(node);
1596
1597 node
1598}
1599
1600pub unsafe fn new_pi(name: *const xmlChar, content: *const xmlChar) -> *mut _xmlNode {
1615 if name.is_null() {
1618 return ptr::null_mut();
1619 }
1620 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1621 if node.is_null() {
1622 return ptr::null_mut();
1623 }
1624
1625 unsafe {
1626 (*node).type_ = XML_PI_NODE as c_int;
1627 (*node).name = dup_xml_str(name);
1628 (*node).content = dup_xml_str(content);
1629 (*node).line = 0;
1630 }
1631
1632 crate::abi::data_globals::register_node_hook(node);
1635
1636 node
1637}
1638
1639pub unsafe fn new_cdata_block(
1655 doc: *mut _xmlDoc,
1656 content: *const xmlChar,
1657 len: c_int,
1658) -> *mut _xmlNode {
1659 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1660 if node.is_null() {
1661 return ptr::null_mut();
1662 }
1663
1664 unsafe {
1665 (*node).type_ = XML_CDATA_SECTION_NODE as c_int;
1666 (*node).doc = doc;
1669
1670 if !content.is_null() && len > 0 {
1671 (*node).content = allocator::xmlMallocImpl((len + 1) as usize) as *mut xmlChar;
1672 if !(*node).content.is_null() {
1673 ptr::copy_nonoverlapping(content, (*node).content, len as usize);
1674 *((*node).content.add(len as usize)) = 0;
1675 }
1676 } else {
1677 let empty = allocator::xmlMallocImpl(1) as *mut xmlChar;
1678 if !empty.is_null() {
1679 *empty = 0;
1680 }
1681 (*node).content = empty;
1682 }
1683
1684 (*node).line = 0;
1685 }
1686
1687 node
1688}
1689
1690pub unsafe fn new_ns(
1714 node: *mut _xmlNode,
1715 href: *const xmlChar,
1716 prefix: *const xmlChar,
1717) -> *mut _xmlNs {
1718 let ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
1719 if ns.is_null() {
1720 return ptr::null_mut();
1721 }
1722
1723 unsafe {
1724 (*ns).type_ = XML_LOCAL_NAMESPACE as c_int;
1725 (*ns).href = dup_xml_str(href);
1726 (*ns).prefix = dup_xml_str(prefix);
1727 (*ns).context = node as *mut _xmlDoc;
1728
1729 if !node.is_null() {
1731 let n = &mut *node;
1732 if n.nsDef.is_null() {
1733 n.nsDef = ns;
1734 } else {
1735 let mut last = n.nsDef;
1737 while !(*last).next.is_null() {
1738 last = (*last).next;
1739 }
1740 (*last).next = ns;
1741 }
1742 }
1743 }
1744
1745 ns
1746}
1747
1748pub unsafe fn set_ns(node: *mut _xmlNode, ns: *mut _xmlNs) {
1761 if node.is_null() {
1762 return;
1763 }
1764 unsafe {
1765 (*node).ns = ns;
1766 }
1767}
1768
1769pub unsafe fn get_ns_list(_doc: *mut _xmlDoc, node: *mut _xmlNode) -> *mut *mut _xmlNs {
1785 if node.is_null() {
1789 return ptr::null_mut();
1790 }
1791
1792 let mut ns_ptrs: Vec<*mut _xmlNs> = Vec::new();
1794 let mut cur = node;
1795
1796 while !cur.is_null() {
1797 let n = unsafe { &*cur };
1798 let mut ns_def = n.nsDef;
1799 while !ns_def.is_null() {
1800 let ns = unsafe { &*ns_def };
1802 let mut found = false;
1803 for &existing in &ns_ptrs {
1804 if existing == ns_def {
1805 found = true;
1806 break;
1807 }
1808 let e = unsafe { &*existing };
1809 if !ns.href.is_null() && !e.href.is_null() {
1810 let href_match =
1811 unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, e.href) != 0 };
1812 if href_match {
1813 if ns.prefix.is_null() && e.prefix.is_null() {
1814 found = true;
1815 break;
1816 }
1817 if !ns.prefix.is_null() && !e.prefix.is_null() {
1818 let prefix_match = unsafe {
1819 crate::abi::exports_xml2::xmlStrEqual(ns.prefix, e.prefix) != 0
1820 };
1821 if prefix_match {
1822 found = true;
1823 break;
1824 }
1825 }
1826 }
1827 }
1828 }
1829 if !found {
1830 ns_ptrs.push(ns_def);
1831 }
1832 ns_def = unsafe { (*ns_def).next };
1833 }
1834 cur = n.parent;
1835 }
1836
1837 if ns_ptrs.is_empty() {
1838 return ptr::null_mut();
1839 }
1840
1841 let arr = allocator::xmlMallocImpl((ns_ptrs.len() + 1) * size_of::<*mut _xmlNs>())
1843 as *mut *mut _xmlNs;
1844 if arr.is_null() {
1845 return ptr::null_mut();
1846 }
1847
1848 for (i, ns) in ns_ptrs.iter().enumerate() {
1849 unsafe { *arr.add(i) = *ns };
1850 }
1851 unsafe { *arr.add(ns_ptrs.len()) = ptr::null_mut() };
1852
1853 arr
1854}
1855
1856pub unsafe fn search_ns(
1873 _doc: *mut _xmlDoc,
1874 node: *mut _xmlNode,
1875 name_space: *const xmlChar,
1876) -> *mut _xmlNs {
1877 if node.is_null() {
1878 return ptr::null_mut();
1879 }
1880
1881 let mut cur = node;
1882 while !cur.is_null() {
1883 let n = unsafe { &*cur };
1884 let mut ns_def = n.nsDef;
1885 while !ns_def.is_null() {
1886 let ns = unsafe { &*ns_def };
1887 let match_prefix = if name_space.is_null() {
1888 ns.prefix.is_null()
1890 } else {
1891 !ns.prefix.is_null()
1892 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.prefix, name_space) != 0 }
1893 };
1894 if match_prefix {
1895 return ns_def;
1896 }
1897 ns_def = unsafe { (*ns_def).next };
1898 }
1899 cur = n.parent;
1900 }
1901
1902 ptr::null_mut()
1903}
1904
1905pub unsafe fn search_ns_by_href(
1921 _doc: *mut _xmlDoc,
1922 node: *mut _xmlNode,
1923 href: *const xmlChar,
1924) -> *mut _xmlNs {
1925 if node.is_null() || href.is_null() {
1926 return ptr::null_mut();
1927 }
1928
1929 let mut cur = node;
1930 while !cur.is_null() {
1931 let n = unsafe { &*cur };
1932 let mut ns_def = n.nsDef;
1933 while !ns_def.is_null() {
1934 let ns = unsafe { &*ns_def };
1935 if !ns.href.is_null()
1936 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, href) != 0 }
1937 {
1938 return ns_def;
1939 }
1940 ns_def = unsafe { (*ns_def).next };
1941 }
1942 cur = n.parent;
1943 }
1944
1945 ptr::null_mut()
1946}
1947
1948pub unsafe fn set_prop(
1972 node: *mut _xmlNode,
1973 name: *const xmlChar,
1974 value: *const xmlChar,
1975) -> *mut _xmlAttr {
1976 if node.is_null() || name.is_null() {
1977 return ptr::null_mut();
1978 }
1979
1980 let n = unsafe { &mut *node };
1981
1982 let mut existing = n.properties;
1984 while !existing.is_null() {
1985 let attr = unsafe { &*existing };
1986 if !attr.name.is_null()
1987 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1988 {
1989 if !attr.children.is_null() {
1992 free_node_list(attr.children);
1993 let attr_mut = existing;
1995 unsafe { (*attr_mut).children = ptr::null_mut() };
1996 unsafe { (*attr_mut).last = ptr::null_mut() };
1997 }
1998 if !value.is_null() {
2000 let text = new_text(value);
2001 if !text.is_null() {
2002 let attr_mut = existing;
2003 unsafe {
2004 (*attr_mut).children = text;
2005 (*attr_mut).last = text;
2006 (*text).parent = existing as *mut _xmlNode;
2007 (*text).doc = n.doc;
2008 }
2009 }
2010 }
2011 return existing;
2012 }
2013 existing = unsafe { (*existing).next };
2014 }
2015
2016 let attr = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
2018 if attr.is_null() {
2019 return ptr::null_mut();
2020 }
2021
2022 unsafe {
2023 (*attr).type_ = XML_ATTRIBUTE_NODE as c_int;
2024 (*attr).name = dup_xml_str(name);
2025 (*attr).parent = node;
2026 (*attr).doc = n.doc;
2027 if !value.is_null() {
2032 let text = new_text(value);
2033 if !text.is_null() {
2034 (*attr).children = text;
2035 (*attr).last = text;
2036 (*text).parent = attr as *mut _xmlNode;
2037 (*text).doc = n.doc;
2038 }
2039 }
2040
2041 if n.properties.is_null() {
2043 n.properties = attr;
2044 } else {
2045 let mut last = n.properties;
2046 while !(*last).next.is_null() {
2047 last = (*last).next;
2048 }
2049 (*last).next = attr;
2050 (*attr).prev = last;
2051 }
2052 }
2053
2054 attr
2055}
2056
2057pub unsafe fn get_prop(node: *mut _xmlNode, name: *const xmlChar) -> *mut xmlChar {
2073 if node.is_null() || name.is_null() {
2074 return ptr::null_mut();
2075 }
2076
2077 let n = unsafe { &*node };
2078 let mut cur = n.properties;
2079
2080 while !cur.is_null() {
2081 let attr = unsafe { &*cur };
2082 if !attr.name.is_null()
2083 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
2084 {
2085 if !attr.children.is_null() {
2087 let text = unsafe { &*attr.children };
2088 if text.type_ == XML_TEXT_NODE as c_int && !text.content.is_null() {
2089 return dup_xml_str(text.content);
2090 }
2091 }
2092 return dup_xml_str(b"\0" as *const u8 as *const xmlChar);
2093 }
2094 cur = unsafe { (*cur).next };
2095 }
2096
2097 ptr::null_mut()
2098}
2099
2100pub unsafe fn get_ns_prop(
2116 node: *mut _xmlNode,
2117 name: *const xmlChar,
2118 _name_space: *const xmlChar,
2119) -> *mut xmlChar {
2120 get_prop(node, name)
2123}
2124
2125pub unsafe fn set_ns_prop(
2140 node: *mut _xmlNode,
2141 _ns: *mut _xmlNs,
2142 name: *const xmlChar,
2143 value: *const xmlChar,
2144) -> *mut _xmlAttr {
2145 set_prop(node, name, value)
2147}
2148
2149pub unsafe fn remove_prop(attr: *mut _xmlAttr) -> c_int {
2164 if attr.is_null() {
2165 return -1;
2166 }
2167
2168 let a = unsafe { &mut *attr };
2169
2170 let parent = a.parent;
2172 if !parent.is_null() {
2173 let p = unsafe { &mut *parent };
2174 if p.properties == attr {
2175 p.properties = a.next;
2176 }
2177 }
2178
2179 if !a.prev.is_null() {
2181 unsafe { (*a.prev).next = a.next };
2182 }
2183 if !a.next.is_null() {
2184 unsafe { (*a.next).prev = a.prev };
2185 }
2186
2187 if !a.children.is_null() {
2189 free_node_list(a.children);
2190 }
2191
2192 if !a.name.is_null() {
2194 allocator::xmlFreeImpl(a.name as *mut c_void);
2195 }
2196
2197 allocator::xmlFreeImpl(attr as *mut c_void);
2198 0
2199}
2200
2201pub unsafe fn has_prop(node: *mut _xmlNode, name: *const xmlChar) -> *mut _xmlAttr {
2209 if node.is_null() || name.is_null() {
2210 return ptr::null_mut();
2211 }
2212 let mut cur = unsafe { (*node).properties };
2213 while !cur.is_null() {
2214 let attr = unsafe { &*cur };
2215 if !attr.name.is_null()
2216 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
2217 && attr.ns.is_null()
2218 {
2219 return cur;
2220 }
2221 cur = unsafe { (*cur).next };
2222 }
2223 ptr::null_mut()
2224}
2225
2226pub unsafe fn has_ns_prop(
2236 node: *mut _xmlNode,
2237 name: *const xmlChar,
2238 name_space: *const xmlChar,
2239) -> *mut _xmlAttr {
2240 if node.is_null() || name.is_null() {
2241 return ptr::null_mut();
2242 }
2243 let mut cur = unsafe { (*node).properties };
2244 while !cur.is_null() {
2245 let attr = unsafe { &*cur };
2246 if !attr.name.is_null()
2247 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
2248 {
2249 if name_space.is_null() {
2250 if attr.ns.is_null() {
2251 return cur;
2252 }
2253 } else if !attr.ns.is_null()
2254 && !(*attr.ns).href.is_null()
2255 && unsafe {
2256 crate::abi::exports_xml2::xmlStrEqual((*attr.ns).href, name_space) != 0
2257 }
2258 {
2259 return cur;
2260 }
2261 }
2262 cur = unsafe { (*cur).next };
2263 }
2264 ptr::null_mut()
2265}
2266
2267pub unsafe fn unset_prop(node: *mut _xmlNode, name: *const xmlChar) -> c_int {
2276 let attr = unsafe { has_prop(node, name) };
2277 if attr.is_null() {
2278 return -1;
2279 }
2280 unsafe { remove_prop(attr) }
2281}
2282
2283pub unsafe fn unset_ns_prop(
2291 node: *mut _xmlNode,
2292 name: *const xmlChar,
2293 name_space: *const xmlChar,
2294) -> c_int {
2295 let attr = unsafe { has_ns_prop(node, name, name_space) };
2296 if attr.is_null() {
2297 return -1;
2298 }
2299 unsafe { remove_prop(attr) }
2300}
2301
2302pub unsafe fn first_element_child(node: *mut _xmlNode) -> *mut _xmlNode {
2309 if node.is_null() {
2310 return ptr::null_mut();
2311 }
2312 let mut cur = unsafe { (*node).children };
2313 while !cur.is_null() {
2314 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2315 return cur;
2316 }
2317 cur = unsafe { (*cur).next };
2318 }
2319 ptr::null_mut()
2320}
2321
2322pub unsafe fn last_element_child(node: *mut _xmlNode) -> *mut _xmlNode {
2329 if node.is_null() {
2330 return ptr::null_mut();
2331 }
2332 let mut cur = unsafe { (*node).last };
2333 while !cur.is_null() {
2334 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2335 return cur;
2336 }
2337 cur = unsafe { (*cur).prev };
2338 }
2339 ptr::null_mut()
2340}
2341
2342pub unsafe fn next_element_sibling(node: *mut _xmlNode) -> *mut _xmlNode {
2349 if node.is_null() {
2350 return ptr::null_mut();
2351 }
2352 let mut cur = unsafe { (*node).next };
2353 while !cur.is_null() {
2354 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2355 return cur;
2356 }
2357 cur = unsafe { (*cur).next };
2358 }
2359 ptr::null_mut()
2360}
2361
2362pub unsafe fn previous_element_sibling(node: *mut _xmlNode) -> *mut _xmlNode {
2369 if node.is_null() {
2370 return ptr::null_mut();
2371 }
2372 let mut cur = unsafe { (*node).prev };
2373 while !cur.is_null() {
2374 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2375 return cur;
2376 }
2377 cur = unsafe { (*cur).prev };
2378 }
2379 ptr::null_mut()
2380}
2381
2382pub unsafe fn child_element_count(node: *mut _xmlNode) -> c_ulong {
2389 if node.is_null() {
2390 return 0;
2391 }
2392 let mut cur = unsafe { (*node).children };
2393 let mut count: c_ulong = 0;
2394 while !cur.is_null() {
2395 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2396 count += 1;
2397 }
2398 cur = unsafe { (*cur).next };
2399 }
2400 count
2401}
2402
2403pub unsafe fn text_concat(node: *mut _xmlNode, str: *const xmlChar, num: c_int) -> c_int {
2412 if node.is_null() || str.is_null() || num <= 0 {
2413 return -1;
2414 }
2415 let cur = unsafe { &mut *node };
2416 if cur.content.is_null() {
2417 let p = unsafe { allocator::xmlMallocImpl(num as usize + 1) as *mut xmlChar };
2418 if p.is_null() {
2419 return -1;
2420 }
2421 unsafe {
2422 ptr::copy_nonoverlapping(str, p, num as usize);
2423 *p.add(num as usize) = 0;
2424 }
2425 cur.content = p;
2426 return 0;
2427 }
2428 let old_len = unsafe { crate::xml::string::xml_strlen(cur.content) };
2429 let p = unsafe {
2430 allocator::xmlReallocImpl(cur.content as *mut c_void, old_len + num as usize + 1)
2431 as *mut xmlChar
2432 };
2433 if p.is_null() {
2434 return -1;
2435 }
2436 unsafe {
2437 ptr::copy_nonoverlapping(str, p.add(old_len), num as usize);
2438 *p.add(old_len + num as usize) = 0;
2439 }
2440 cur.content = p;
2441 0
2442}
2443
2444pub unsafe fn text_merge(text: *mut _xmlNode, ntext: *mut _xmlNode) -> *mut _xmlNode {
2452 if text.is_null() || ntext.is_null() {
2453 return ptr::null_mut();
2454 }
2455 if unsafe { (*ntext).content.is_null() } {
2456 unsafe { free_node(ntext) };
2457 return text;
2458 }
2459 let num = unsafe { crate::xml::string::xml_strlen((*ntext).content) };
2460 if unsafe { text_concat(text, (*ntext).content, num as c_int) } != 0 {
2461 return ptr::null_mut();
2462 }
2463 unsafe { free_node(ntext) };
2464 text
2465}
2466
2467pub const fn get_int_subset(doc: *const _xmlDoc) -> *mut _xmlDtd {
2479 if doc.is_null() {
2480 return ptr::null_mut();
2481 }
2482 let d = unsafe { &*doc };
2483 d.intSubset
2484}
2485
2486pub unsafe fn new_dtd(
2503 doc: *mut _xmlDoc,
2504 name: *const xmlChar,
2505 ExternalID: *const xmlChar,
2506 SystemID: *const xmlChar,
2507) -> *mut _xmlDtd {
2508 let dtd = allocator::xmlMallocZero(size_of::<_xmlDtd>() as usize) as *mut _xmlDtd;
2509 if dtd.is_null() {
2510 return ptr::null_mut();
2511 }
2512
2513 unsafe {
2514 (*dtd).type_ = XML_DTD_NODE as c_int;
2515 (*dtd).name = dup_xml_str(name);
2516 (*dtd).ExternalID = dup_xml_str(ExternalID);
2517 (*dtd).SystemID = dup_xml_str(SystemID);
2518 (*dtd).parent = doc;
2519 (*dtd).doc = doc;
2520
2521 if !doc.is_null() && (*doc).intSubset.is_null() {
2527 (*doc).intSubset = dtd;
2528 }
2529 }
2530
2531 dtd
2532}
2533
2534unsafe fn free_dtd(dtd: *mut _xmlDtd) {
2540 if dtd.is_null() {
2541 return;
2542 }
2543
2544 let _d = unsafe { &mut *dtd };
2545 let d = &mut *dtd;
2546
2547 if !d.children.is_null() {
2554 let mut c = d.children;
2555 while !c.is_null() {
2556 let next = (*c).next;
2557 let t = (*c).type_;
2558 if t != XML_ELEMENT_DECL as c_int
2559 && t != XML_ATTRIBUTE_DECL as c_int
2560 && t != XML_ENTITY_DECL as c_int
2561 {
2562 unlink_node_internal(c, ptr::null_mut());
2563 free_node(c);
2564 }
2565 c = next;
2566 }
2567 }
2568
2569 if !d.name.is_null() {
2571 allocator::xmlFreeImpl(d.name as *mut c_void);
2572 }
2573 if !d.ExternalID.is_null() {
2574 allocator::xmlFreeImpl(d.ExternalID as *mut c_void);
2575 }
2576 if !d.SystemID.is_null() {
2577 allocator::xmlFreeImpl(d.SystemID as *mut c_void);
2578 }
2579
2580 unsafe extern "C" fn free_notation_wrapper(payload: *mut c_void, _name: *mut u8) {
2590 crate::xml::dtd::free_notation(payload as *mut _xmlNotation);
2591 }
2592 unsafe extern "C" fn free_element_wrapper(payload: *mut c_void, _name: *mut u8) {
2601 crate::xml::dtd::free_element(payload as *mut _xmlElement);
2602 }
2603 unsafe extern "C" fn free_attribute_wrapper(payload: *mut c_void, _name: *mut u8) {
2612 crate::xml::dtd::free_attribute(payload as *mut _xmlAttribute);
2613 }
2614 unsafe extern "C" fn free_entity_wrapper(payload: *mut c_void, _name: *mut u8) {
2623 crate::xml::entities::free_entity(payload as *mut _xmlEntity);
2624 }
2625
2626 if !d.notations.is_null() {
2627 crate::xml::hash::hash_free(
2628 d.notations as *mut crate::xml::hash::HashTable,
2629 Some(free_notation_wrapper),
2630 );
2631 d.notations = ptr::null_mut();
2632 }
2633 if !d.elements.is_null() {
2634 crate::xml::hash::hash_free(
2635 d.elements as *mut crate::xml::hash::HashTable,
2636 Some(free_element_wrapper),
2637 );
2638 d.elements = ptr::null_mut();
2639 }
2640 if !d.attributes.is_null() {
2641 crate::xml::hash::hash_free(
2642 d.attributes as *mut crate::xml::hash::HashTable,
2643 Some(free_attribute_wrapper),
2644 );
2645 d.attributes = ptr::null_mut();
2646 }
2647 if !d.entities.is_null() {
2648 crate::xml::hash::hash_free(
2649 d.entities as *mut crate::xml::hash::HashTable,
2650 Some(free_entity_wrapper),
2651 );
2652 d.entities = ptr::null_mut();
2653 }
2654 if !d.pentities.is_null() {
2655 crate::xml::hash::hash_free(
2656 d.pentities as *mut crate::xml::hash::HashTable,
2657 Some(free_entity_wrapper),
2658 );
2659 d.pentities = ptr::null_mut();
2660 }
2661
2662 allocator::xmlFreeImpl(dtd as *mut c_void);
2663}
2664
2665pub unsafe fn new_entity(
2685 _doc: *mut _xmlDoc,
2686 name: *const xmlChar,
2687 etype: c_int,
2688 ExternalID: *const xmlChar,
2689 SystemID: *const xmlChar,
2690 content: *const xmlChar,
2691) -> *mut _xmlEntity {
2692 let entity = allocator::xmlMallocZero(size_of::<_xmlEntity>() as usize) as *mut _xmlEntity;
2693 if entity.is_null() {
2694 return ptr::null_mut();
2695 }
2696
2697 unsafe {
2698 (*entity).type_ = XML_ENTITY_DECL as c_int;
2699 (*entity).name = dup_xml_str(name);
2700 (*entity).etype = etype;
2701 (*entity).ExternalID = dup_xml_str(ExternalID);
2702 (*entity).SystemID = dup_xml_str(SystemID);
2703 (*entity).content = dup_xml_str(content);
2704 (*entity).length = if content.is_null() {
2705 0
2706 } else {
2707 crate::abi::exports_xml2::xmlStrlen(content)
2708 };
2709 (*entity).flags = 0;
2710 (*entity).expandedSize = 0;
2711 }
2712
2713 entity
2714}
2715
2716pub unsafe fn get_doc_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2731 crate::xml::entities::get_entity(doc as *mut _xmlDoc, name)
2732}
2733
2734pub unsafe fn add_doc_entity(
2742 doc: *mut _xmlDoc,
2743 name: *const xmlChar,
2744 etype: c_int,
2745 ExternalID: *const xmlChar,
2746 SystemID: *const xmlChar,
2747 content: *const xmlChar,
2748) -> *mut _xmlEntity {
2749 if doc.is_null() || name.is_null() {
2750 return ptr::null_mut();
2751 }
2752 unsafe {
2753 let mut dtd = (*doc).intSubset;
2754 if dtd.is_null() {
2755 dtd = new_dtd(
2756 doc,
2757 c"internal".as_ptr() as *const xmlChar,
2758 ptr::null(),
2759 ptr::null(),
2760 );
2761 if dtd.is_null() {
2762 return ptr::null_mut();
2763 }
2764 }
2765 crate::xml::entities::add_entity(dtd, name, etype, ExternalID, SystemID, content)
2766 }
2767}
2768
2769pub unsafe fn add_dtd_entity(
2777 doc: *mut _xmlDoc,
2778 name: *const xmlChar,
2779 etype: c_int,
2780 ExternalID: *const xmlChar,
2781 SystemID: *const xmlChar,
2782 content: *const xmlChar,
2783) -> *mut _xmlEntity {
2784 if doc.is_null() || name.is_null() {
2785 return ptr::null_mut();
2786 }
2787 unsafe {
2788 let mut dtd = (*doc).extSubset;
2789 if dtd.is_null() {
2790 dtd = new_dtd(
2791 doc,
2792 c"internal".as_ptr() as *const xmlChar,
2793 ptr::null(),
2794 ptr::null(),
2795 );
2796 if dtd.is_null() {
2797 return ptr::null_mut();
2798 }
2799 (*doc).extSubset = dtd;
2800 }
2801 crate::xml::entities::add_entity(dtd, name, etype, ExternalID, SystemID, content)
2802 }
2803}
2804
2805pub unsafe fn get_dtd_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2813 if doc.is_null() || name.is_null() {
2814 return ptr::null_mut();
2815 }
2816 unsafe {
2817 if !(*doc).intSubset.is_null() {
2818 let e = crate::xml::entities::get_entity_from_dtd((*doc).intSubset, name);
2819 if !e.is_null() {
2820 return e;
2821 }
2822 }
2823 if !(*doc).extSubset.is_null() {
2824 return crate::xml::entities::get_entity_from_dtd((*doc).extSubset, name);
2825 }
2826 ptr::null_mut()
2827 }
2828}
2829
2830pub unsafe fn get_parameter_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2843 crate::xml::entities::get_parameter_entity(doc as *mut _xmlDoc, name)
2844}
2845
2846const ENTITY_LT: &[xmlChar] = b"<";
2855const ENTITY_GT: &[xmlChar] = b">";
2856const ENTITY_AMP: &[xmlChar] = b"&";
2857const ENTITY_QUOT: &[xmlChar] = b""";
2858#[allow(dead_code)]
2859const ENTITY_APOS: &[xmlChar] = b"'";
2860
2861const INDENT: &[xmlChar] = b" ";
2863
2864const MAX_INDENT: c_int = 60;
2866
2867pub(crate) unsafe fn serialize_text(buf: *mut _xmlBuffer, content: *const xmlChar, len: c_int) {
2882 if buf.is_null() || content.is_null() || len <= 0 {
2883 return;
2884 }
2885
2886 let mut i: c_int = 0;
2887 while i < len {
2888 let ch = unsafe { *content.add(i as usize) };
2889
2890 if ch == b']'
2892 && i + 2 < len
2893 && unsafe { *content.add(i as usize + 1) == b']' }
2894 && unsafe { *content.add(i as usize + 2) == b'>' }
2895 {
2896 io::buf_add(buf, &ch as *const u8, 2); io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2899 i += 3;
2900 continue;
2901 }
2902
2903 match ch {
2904 b'<' => {
2905 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
2906 }
2907 b'&' => {
2908 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
2909 }
2910 b'>' => {
2911 io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2915 }
2916 b'\r' => {
2917 io::buf_add(buf, b" " as *const u8, 5);
2919 }
2920 0x01..=0x08 | 0x0B | 0x0C | 0x0E..=0x1F => {
2921 let hex = format!("&#x{:X};", ch);
2923 io::buf_add(buf, hex.as_ptr(), hex.len() as c_int);
2924 }
2925 _ => {
2926 io::buf_add(buf, &ch as *const u8, 1);
2927 }
2928 }
2929 i += 1;
2930 }
2931}
2932
2933pub(crate) unsafe fn serialize_attr_value(buf: *mut _xmlBuffer, value: *const xmlChar) {
2946 if buf.is_null() || value.is_null() {
2947 return;
2948 }
2949
2950 let len = xml_strlen(value);
2951 let mut i: c_int = 0;
2952 while i < len {
2953 let ch = unsafe { *value.add(i as usize) };
2954
2955 match ch {
2956 b'\n' => {
2957 io::buf_add(buf, b" " as *const u8, 5);
2958 }
2959 b'\r' => {
2960 io::buf_add(buf, b" " as *const u8, 5);
2961 }
2962 b'\t' => {
2963 io::buf_add(buf, b"	" as *const u8, 4);
2964 }
2965 b'<' => {
2966 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
2967 }
2968 b'&' => {
2969 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
2970 }
2971 b'"' => {
2972 io::buf_add(buf, ENTITY_QUOT.as_ptr(), ENTITY_QUOT.len() as c_int);
2973 }
2974 b'>' => {
2975 io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2976 }
2977 _ => {
2978 io::buf_add(buf, &ch as *const u8, 1);
2979 }
2980 }
2981 i += 1;
2982 }
2983}
2984
2985unsafe fn write_indent(
2997 buf: *mut _xmlBuffer,
2998 level: c_int,
2999 indent: *const xmlChar,
3000 indent_len: c_int,
3001) {
3002 if buf.is_null() || level <= 0 || indent.is_null() || indent_len <= 0 {
3003 return;
3004 }
3005 let indent_nr = MAX_INDENT / indent_len;
3006 let mut lvl = level;
3007 if lvl > indent_nr {
3008 lvl = indent_nr;
3009 }
3010 for _ in 0..lvl {
3011 io::buf_add(buf, indent, indent_len);
3012 }
3013}
3014
3015unsafe fn is_noenc_text(node: *mut _xmlNode) -> bool {
3029 if node.is_null() {
3030 return false;
3031 }
3032 let n = unsafe { &*node };
3033 if n.name.is_null() {
3034 return false;
3035 }
3036 c_str_eq_bytes(n.name, b"textnoenc")
3037}
3038
3039const unsafe fn c_str_eq_bytes(s: *const xmlChar, b: &[u8]) -> bool {
3047 let mut i = 0usize;
3048 while i < b.len() {
3049 if unsafe { *s.add(i) } != b[i] {
3050 return false;
3051 }
3052 i += 1;
3053 }
3054 unsafe { *s.add(i) == 0 }
3055}
3056
3057#[derive(Clone, Copy)]
3060struct DumpState {
3061 format: c_int,
3063 saved: c_int,
3066 unformatted: *mut _xmlNode,
3069 indent: *const xmlChar,
3072 indent_len: c_int,
3074 no_decl: c_int,
3076 encoding: *const xmlChar,
3080}
3081
3082impl DumpState {
3083 const fn new(format: c_int) -> Self {
3084 let f = if format != 0 { 1 } else { 0 };
3085 DumpState {
3086 format: f,
3087 saved: f,
3088 unformatted: ptr::null_mut(),
3089 indent: INDENT.as_ptr(),
3090 indent_len: INDENT.len() as c_int,
3091 no_decl: 0,
3092 encoding: ptr::null(),
3093 }
3094 }
3095
3096 const unsafe fn with_indent_enc(
3107 format: c_int,
3108 indent: *const xmlChar,
3109 no_decl: c_int,
3110 encoding: *const xmlChar,
3111 ) -> Self {
3112 let f = if format != 0 { 1 } else { 0 };
3113 let (ptr, len) = if indent.is_null() {
3114 (INDENT.as_ptr(), INDENT.len() as c_int)
3115 } else {
3116 let mut n = 0i32;
3117 while unsafe { *indent.add(n as usize) } != 0 {
3118 n += 1;
3119 }
3120 (indent, n)
3121 };
3122 DumpState {
3123 format: f,
3124 saved: f,
3125 unformatted: ptr::null_mut(),
3126 indent: ptr,
3127 indent_len: len,
3128 no_decl,
3129 encoding,
3130 }
3131 }
3132}
3133
3134unsafe fn write_qname(buf: *mut _xmlBuffer, node: *mut _xmlNode) {
3140 let n = unsafe { &*node };
3141 if !n.ns.is_null() {
3142 let ns = unsafe { &*n.ns };
3143 if !ns.prefix.is_null() {
3144 io::buf_cat(buf, ns.prefix);
3145 io::buf_ccat(buf, b':');
3146 }
3147 }
3148 if !n.name.is_null() {
3149 io::buf_cat(buf, n.name);
3150 }
3151}
3152
3153unsafe fn ns_dump_output(buf: *mut _xmlBuffer, cur: *mut _xmlNs) {
3159 if cur.is_null() || buf.is_null() {
3160 return;
3161 }
3162 let ns = unsafe { &*cur };
3163 if ns.type_ == XML_LOCAL_NAMESPACE as c_int && !ns.href.is_null() {
3164 if !ns.prefix.is_null() && c_str_eq_bytes(ns.prefix, b"xml") {
3166 return;
3167 }
3168 io::buf_ccat(buf, b' ');
3169 if !ns.prefix.is_null() {
3170 io::buf_add(buf, b"xmlns:" as *const u8, 6);
3171 io::buf_cat(buf, ns.prefix);
3172 } else {
3173 io::buf_add(buf, b"xmlns" as *const u8, 5);
3174 }
3175 io::buf_add(buf, b"=\"" as *const u8, 2);
3176 serialize_attr_value(buf, ns.href);
3177 io::buf_ccat(buf, b'"');
3178 }
3179}
3180
3181unsafe fn attr_dump_output(buf: *mut _xmlBuffer, cur: *mut _xmlAttr) {
3187 if cur.is_null() || buf.is_null() {
3188 return;
3189 }
3190 io::buf_ccat(buf, b' ');
3191 let a = unsafe { &*cur };
3192 if !a.ns.is_null() {
3193 let ans = unsafe { &*a.ns };
3194 if !ans.prefix.is_null() {
3195 io::buf_cat(buf, ans.prefix);
3196 io::buf_ccat(buf, b':');
3197 }
3198 }
3199 if !a.name.is_null() {
3200 io::buf_cat(buf, a.name);
3201 }
3202 io::buf_add(buf, b"=\"" as *const u8, 2);
3203 let mut child = a.children;
3206 while !child.is_null() {
3207 let ct = unsafe { (*child).type_ };
3208 if ct == XML_TEXT_NODE as c_int && !unsafe { (*child).content }.is_null() {
3209 serialize_attr_value(buf, unsafe { (*child).content });
3210 } else if ct == XML_ENTITY_REF_NODE as c_int && !unsafe { (*child).name }.is_null() {
3211 io::buf_ccat(buf, b'&');
3212 io::buf_cat(buf, unsafe { (*child).name });
3213 io::buf_ccat(buf, b';');
3214 }
3215 child = unsafe { (*child).next };
3216 }
3217 io::buf_ccat(buf, b'"');
3218}
3219
3220unsafe fn dump_notation_decl(buf: *mut _xmlBuffer, nota: *mut _xmlNotation) {
3226 let n = unsafe { &*nota };
3227 io::buf_add(buf, b"<!NOTATION " as *const u8, 11);
3228 if !n.name.is_null() {
3229 io::buf_cat(buf, n.name);
3230 }
3231 if !n.PublicID.is_null() {
3232 io::buf_add(buf, b" PUBLIC " as *const u8, 8);
3233 write_quoted_string(buf, n.PublicID);
3234 if !n.SystemID.is_null() {
3235 io::buf_ccat(buf, b' ');
3236 write_quoted_string(buf, n.SystemID);
3237 }
3238 } else {
3239 io::buf_add(buf, b" SYSTEM " as *const u8, 8);
3240 write_quoted_string(buf, n.SystemID);
3241 }
3242 io::buf_add(buf, b" >\n" as *const u8, 4);
3243}
3244
3245unsafe fn dump_element_occur(buf: *mut _xmlBuffer, ocur: c_int) {
3247 use crate::abi::types::xmlElementContentOccur::*;
3248 if ocur == XML_ELEMENT_CONTENT_OPT as c_int {
3249 io::buf_ccat(buf, b'?');
3250 } else if ocur == XML_ELEMENT_CONTENT_MULT as c_int {
3251 io::buf_ccat(buf, b'*');
3252 } else if ocur == XML_ELEMENT_CONTENT_PLUS as c_int {
3253 io::buf_ccat(buf, b'+');
3254 }
3255}
3256
3257unsafe fn dump_element_content(buf: *mut _xmlBuffer, content: *mut _xmlElementContent) {
3263 use crate::abi::types::xmlElementContentOccur::*;
3264 use crate::abi::types::xmlElementContentType::*;
3265 if content.is_null() {
3266 return;
3267 }
3268 io::buf_ccat(buf, b'(');
3269 let mut cur = content;
3270 loop {
3271 if cur.is_null() {
3272 return;
3273 }
3274 let c = unsafe { &*cur };
3275 match c.type_ {
3276 t if t == XML_ELEMENT_CONTENT_PCDATA as c_int => {
3277 io::buf_add(buf, b"#PCDATA" as *const u8, 7);
3278 }
3279 t if t == XML_ELEMENT_CONTENT_ELEMENT as c_int => {
3280 if !c.prefix.is_null() {
3281 io::buf_cat(buf, c.prefix);
3282 io::buf_ccat(buf, b':');
3283 }
3284 if !c.name.is_null() {
3285 io::buf_cat(buf, c.name);
3286 }
3287 }
3288 t if t == XML_ELEMENT_CONTENT_SEQ as c_int || t == XML_ELEMENT_CONTENT_OR as c_int => {
3289 if cur != content
3290 && !c.parent.is_null()
3291 && (c.type_ != unsafe { (*c.parent).type_ }
3292 || c.ocur != XML_ELEMENT_CONTENT_ONCE as c_int)
3293 {
3294 io::buf_ccat(buf, b'(');
3295 }
3296 cur = c.c1;
3297 continue;
3298 }
3299 _ => {}
3300 }
3301
3302 while cur != content {
3304 let ccur = unsafe { &*cur };
3305 let parent = ccur.parent;
3306 if parent.is_null() {
3307 return;
3308 }
3309 let p = unsafe { &*parent };
3310 if (ccur.type_ == XML_ELEMENT_CONTENT_OR as c_int
3311 || ccur.type_ == XML_ELEMENT_CONTENT_SEQ as c_int)
3312 && (ccur.type_ != p.type_ || ccur.ocur != XML_ELEMENT_CONTENT_ONCE as c_int)
3313 {
3314 io::buf_ccat(buf, b')');
3315 }
3316 dump_element_occur(buf, ccur.ocur);
3317
3318 if ccur.type_ == XML_ELEMENT_CONTENT_SEQ as c_int {
3319 io::buf_add(buf, b" , " as *const u8, 3);
3320 } else if ccur.type_ == XML_ELEMENT_CONTENT_OR as c_int {
3321 io::buf_add(buf, b" | " as *const u8, 3);
3322 }
3323
3324 if cur == p.c1 {
3325 cur = p.c2;
3326 break;
3327 }
3328 cur = parent;
3329 }
3330 if cur == content {
3331 break;
3332 }
3333 }
3334 io::buf_ccat(buf, b')');
3335 let cc = unsafe { &*content };
3336 dump_element_occur(buf, cc.ocur);
3337}
3338
3339unsafe fn dump_element_decl(buf: *mut _xmlBuffer, elem: *mut _xmlElement) {
3345 use crate::abi::types::xmlElementTypeVal::*;
3346 let e = unsafe { &*elem };
3347 io::buf_add(buf, b"<!ELEMENT " as *const u8, 10);
3348 if !e.prefix.is_null() {
3349 io::buf_cat(buf, e.prefix);
3350 io::buf_ccat(buf, b':');
3351 }
3352 if !e.name.is_null() {
3353 io::buf_cat(buf, e.name);
3354 }
3355 io::buf_ccat(buf, b' ');
3356 match e.etype {
3357 t if t == XML_ELEMENT_TYPE_EMPTY as c_int => {
3358 io::buf_add(buf, b"EMPTY" as *const u8, 5);
3359 }
3360 t if t == XML_ELEMENT_TYPE_ANY as c_int => {
3361 io::buf_add(buf, b"ANY" as *const u8, 3);
3362 }
3363 t if t == XML_ELEMENT_TYPE_MIXED as c_int || t == XML_ELEMENT_TYPE_ELEMENT as c_int => {
3364 dump_element_content(buf, e.content);
3365 }
3366 _ => {}
3367 }
3368 io::buf_add(buf, b">\n" as *const u8, 2);
3369}
3370
3371unsafe fn dump_enumeration(buf: *mut _xmlBuffer, cur: *mut _xmlEnumeration) {
3377 let mut e = cur;
3378 while !e.is_null() {
3379 let en = unsafe { &*e };
3380 if !en.name.is_null() {
3381 io::buf_cat(buf, en.name);
3382 }
3383 if !en.next.is_null() {
3384 io::buf_add(buf, b" | " as *const u8, 3);
3385 }
3386 e = en.next;
3387 }
3388 io::buf_ccat(buf, b')');
3389}
3390
3391unsafe fn dump_attribute_decl(buf: *mut _xmlBuffer, attr: *mut _xmlAttribute) {
3397 use crate::abi::types::xmlAttributeDefault::*;
3398 use crate::abi::types::xmlAttributeType::*;
3399 let a = unsafe { &*attr };
3400 io::buf_add(buf, b"<!ATTLIST " as *const u8, 10);
3401 if !a.elem.is_null() {
3402 io::buf_cat(buf, a.elem);
3403 }
3404 io::buf_ccat(buf, b' ');
3405 if !a.prefix.is_null() {
3406 io::buf_cat(buf, a.prefix);
3407 io::buf_ccat(buf, b':');
3408 }
3409 if !a.name.is_null() {
3410 io::buf_cat(buf, a.name);
3411 }
3412 match a.atype {
3413 t if t == XML_ATTRIBUTE_CDATA as c_int => {
3414 io::buf_add(buf, b" CDATA" as *const u8, 6);
3415 }
3416 t if t == XML_ATTRIBUTE_ID as c_int => {
3417 io::buf_add(buf, b" ID" as *const u8, 3);
3418 }
3419 t if t == XML_ATTRIBUTE_IDREF as c_int => {
3420 io::buf_add(buf, b" IDREF" as *const u8, 6);
3421 }
3422 t if t == XML_ATTRIBUTE_IDREFS as c_int => {
3423 io::buf_add(buf, b" IDREFS" as *const u8, 7);
3424 }
3425 t if t == XML_ATTRIBUTE_ENTITY as c_int => {
3426 io::buf_add(buf, b" ENTITY" as *const u8, 7);
3427 }
3428 t if t == XML_ATTRIBUTE_ENTITIES as c_int => {
3429 io::buf_add(buf, b" ENTITIES" as *const u8, 9);
3430 }
3431 t if t == XML_ATTRIBUTE_NMTOKEN as c_int => {
3432 io::buf_add(buf, b" NMTOKEN" as *const u8, 8);
3433 }
3434 t if t == XML_ATTRIBUTE_NMTOKENS as c_int => {
3435 io::buf_add(buf, b" NMTOKENS" as *const u8, 9);
3436 }
3437 t if t == XML_ATTRIBUTE_ENUMERATION as c_int => {
3438 io::buf_add(buf, b" (" as *const u8, 2);
3439 dump_enumeration(buf, a.tree);
3440 }
3441 t if t == XML_ATTRIBUTE_NOTATION as c_int => {
3442 io::buf_add(buf, b" NOTATION (" as *const u8, 11);
3443 dump_enumeration(buf, a.tree);
3444 }
3445 _ => {}
3446 }
3447 match a.def {
3448 t if t == XML_ATTRIBUTE_REQUIRED as c_int => {
3449 io::buf_add(buf, b" #REQUIRED" as *const u8, 10);
3450 }
3451 t if t == XML_ATTRIBUTE_IMPLIED as c_int => {
3452 io::buf_add(buf, b" #IMPLIED" as *const u8, 9);
3453 }
3454 t if t == XML_ATTRIBUTE_FIXED as c_int => {
3455 io::buf_add(buf, b" #FIXED" as *const u8, 7);
3456 }
3457 _ => {}
3458 }
3459 if !a.defaultValue.is_null() {
3460 io::buf_add(buf, b" \"" as *const u8, 2);
3461 serialize_attr_value(buf, a.defaultValue);
3462 io::buf_ccat(buf, b'"');
3463 }
3464 io::buf_add(buf, b">\n" as *const u8, 2);
3465}
3466
3467unsafe fn write_quoted_string(buf: *mut _xmlBuffer, str: *const xmlChar) {
3473 if buf.is_null() {
3474 return;
3475 }
3476 io::buf_ccat(buf, b'"');
3477 if !str.is_null() {
3478 let mut i = 0usize;
3479 while unsafe { *str.add(i) != 0 } {
3480 let ch = unsafe { *str.add(i) };
3481 if ch == b'"' {
3482 io::buf_add(buf, b""" as *const u8, 6);
3483 } else {
3484 io::buf_add(buf, &ch as *const u8, 1);
3485 }
3486 i += 1;
3487 }
3488 }
3489 io::buf_ccat(buf, b'"');
3490}
3491
3492unsafe fn dump_entity_decl(buf: *mut _xmlBuffer, ent: *mut _xmlEntity) {
3498 use crate::abi::types::xmlEntityType::*;
3499 let e = unsafe { &*ent };
3500 if e.etype == XML_INTERNAL_PARAMETER_ENTITY as c_int
3501 || e.etype == XML_EXTERNAL_PARAMETER_ENTITY as c_int
3502 {
3503 io::buf_add(buf, b"<!ENTITY % " as *const u8, 11);
3504 } else {
3505 io::buf_add(buf, b"<!ENTITY " as *const u8, 9);
3506 }
3507 if !e.name.is_null() {
3508 io::buf_cat(buf, e.name);
3509 }
3510 io::buf_ccat(buf, b' ');
3511
3512 if e.etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY as c_int
3513 || e.etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int
3514 || e.etype == XML_EXTERNAL_PARAMETER_ENTITY as c_int
3515 {
3516 if !e.ExternalID.is_null() {
3517 io::buf_add(buf, b"PUBLIC " as *const u8, 7);
3518 write_quoted_string(buf, e.ExternalID);
3519 io::buf_ccat(buf, b' ');
3520 } else {
3521 io::buf_add(buf, b"SYSTEM " as *const u8, 7);
3522 }
3523 write_quoted_string(buf, e.SystemID);
3524 }
3525
3526 if e.etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int && !e.content.is_null() {
3527 io::buf_add(buf, b" NDATA " as *const u8, 7);
3528 if !e.orig.is_null() {
3529 io::buf_cat(buf, e.orig);
3530 } else if !e.content.is_null() {
3531 io::buf_cat(buf, e.content);
3532 }
3533 }
3534
3535 if e.etype == XML_INTERNAL_GENERAL_ENTITY as c_int
3536 || e.etype == XML_INTERNAL_PARAMETER_ENTITY as c_int
3537 {
3538 if !e.orig.is_null() {
3539 write_quoted_string(buf, e.orig);
3540 } else {
3541 io::buf_ccat(buf, b'"');
3543 if !e.content.is_null() {
3544 let mut i = 0usize;
3545 while unsafe { *e.content.add(i) != 0 } {
3546 let ch = unsafe { *e.content.add(i) };
3547 match ch {
3548 b'"' => io::buf_add(buf, b""" as *const u8, 6),
3549 b'%' => io::buf_add(buf, b"%" as *const u8, 6),
3550 _ => io::buf_add(buf, &ch as *const u8, 1),
3551 };
3552 i += 1;
3553 }
3554 }
3555 io::buf_ccat(buf, b'"');
3556 }
3557 }
3558 io::buf_add(buf, b">\n" as *const u8, 2);
3559}
3560
3561unsafe fn dtd_dump_output(
3567 buf: *mut _xmlBuffer,
3568 cur: *mut _xmlNode,
3569 state: &mut DumpState,
3570 level: &mut c_int,
3571) {
3572 let dtd = cur as *mut _xmlDtd;
3573 let d = unsafe { &*dtd };
3574 io::buf_add(buf, b"<!DOCTYPE " as *const u8, 10);
3575 if !d.name.is_null() {
3576 io::buf_cat(buf, d.name);
3577 }
3578 if !d.ExternalID.is_null() {
3579 io::buf_add(buf, b" PUBLIC " as *const u8, 8);
3580 write_quoted_string(buf, d.ExternalID);
3581 io::buf_ccat(buf, b' ');
3582 write_quoted_string(buf, d.SystemID);
3583 } else if !d.SystemID.is_null() {
3584 io::buf_add(buf, b" SYSTEM " as *const u8, 8);
3585 write_quoted_string(buf, d.SystemID);
3586 }
3587 if d.entities.is_null()
3592 && d.elements.is_null()
3593 && d.attributes.is_null()
3594 && d.notations.is_null()
3595 && d.pentities.is_null()
3596 {
3597 io::buf_ccat(buf, b'>');
3598 return;
3599 }
3600 io::buf_add(buf, b" [\n" as *const u8, 3);
3601 let format = state.format;
3607 let lvl = *level;
3608 state.format = 0;
3609 *level = -1;
3610 if !d.notations.is_null() {
3611 crate::xml::hash::hash_scan(
3612 d.notations as *mut crate::xml::hash::HashTable,
3613 Some(dump_notation_decl_cb),
3614 buf as *mut c_void,
3615 );
3616 }
3617 if !d.elements.is_null() {
3618 crate::xml::hash::hash_scan(
3619 d.elements as *mut crate::xml::hash::HashTable,
3620 Some(dump_element_decl_cb),
3621 buf as *mut c_void,
3622 );
3623 }
3624 if !d.attributes.is_null() {
3625 crate::xml::hash::hash_scan(
3626 d.attributes as *mut crate::xml::hash::HashTable,
3627 Some(dump_attribute_decl_cb),
3628 buf as *mut c_void,
3629 );
3630 }
3631 if !d.entities.is_null() {
3632 crate::xml::hash::hash_scan(
3633 d.entities as *mut crate::xml::hash::HashTable,
3634 Some(dump_entity_decl_cb),
3635 buf as *mut c_void,
3636 );
3637 }
3638 if !d.pentities.is_null() {
3639 crate::xml::hash::hash_scan(
3640 d.pentities as *mut crate::xml::hash::HashTable,
3641 Some(dump_entity_decl_cb),
3642 buf as *mut c_void,
3643 );
3644 }
3645 state.format = format;
3646 *level = lvl;
3647 io::buf_add(buf, b"]>" as *const u8, 2);
3648}
3649
3650unsafe extern "C" fn dump_notation_decl_cb(
3652 payload: *mut c_void,
3653 data: *mut c_void,
3654 _name: *const crate::abi::types::xmlChar,
3655) {
3656 if !payload.is_null() && !data.is_null() {
3657 dump_notation_decl(data as *mut _xmlBuffer, payload as *mut _xmlNotation);
3658 }
3659}
3660
3661unsafe extern "C" fn dump_element_decl_cb(
3663 payload: *mut c_void,
3664 data: *mut c_void,
3665 _name: *const crate::abi::types::xmlChar,
3666) {
3667 if !payload.is_null() && !data.is_null() {
3668 dump_element_decl(data as *mut _xmlBuffer, payload as *mut _xmlElement);
3669 }
3670}
3671
3672unsafe extern "C" fn dump_attribute_decl_cb(
3674 payload: *mut c_void,
3675 data: *mut c_void,
3676 _name: *const crate::abi::types::xmlChar,
3677) {
3678 if !payload.is_null() && !data.is_null() {
3679 dump_attribute_decl(data as *mut _xmlBuffer, payload as *mut _xmlAttribute);
3680 }
3681}
3682
3683unsafe extern "C" fn dump_entity_decl_cb(
3685 payload: *mut c_void,
3686 data: *mut c_void,
3687 _name: *const crate::abi::types::xmlChar,
3688) {
3689 if !payload.is_null() && !data.is_null() {
3690 dump_entity_decl(data as *mut _xmlBuffer, payload as *mut _xmlEntity);
3691 }
3692}
3693
3694unsafe fn doc_content_dump_output(
3703 buf: *mut _xmlBuffer,
3704 cur: *mut _xmlNode,
3705 state: &mut DumpState,
3706 level: &mut c_int,
3707) {
3708 let doc = cur as *mut _xmlDoc;
3709 let d = unsafe { &*doc };
3710
3711 if state.no_decl == 0 {
3718 io::buf_add(buf, b"<?xml version=\"" as *const u8, 15);
3719 if !d.version.is_null() {
3720 io::buf_cat(buf, d.version);
3721 } else {
3722 io::buf_add(buf, b"1.0" as *const u8, 3);
3723 }
3724 io::buf_ccat(buf, b'"');
3725 let enc = if state.encoding.is_null() {
3726 d.encoding
3727 } else {
3728 state.encoding
3729 };
3730 if !enc.is_null() {
3731 io::buf_add(buf, b" encoding=\"" as *const u8, 11);
3732 io::buf_cat(buf, enc);
3733 io::buf_ccat(buf, b'"');
3734 }
3735 match d.standalone {
3736 0 => {
3737 io::buf_add(buf, b" standalone=\"no\"" as *const u8, 16);
3738 }
3739 1 => {
3740 io::buf_add(buf, b" standalone=\"yes\"" as *const u8, 17);
3741 }
3742 _ => {}
3743 }
3744 io::buf_add(buf, b"?>\n" as *const u8, 3);
3745 }
3746
3747 if !d.intSubset.is_null() {
3754 let mut in_chain = false;
3755 let mut c = d.children;
3756 while !c.is_null() {
3757 if c as *mut c_void == d.intSubset as *mut c_void {
3758 in_chain = true;
3759 break;
3760 }
3761 c = unsafe { (*c).next };
3762 }
3763 if !in_chain {
3764 let mut lvl = 0;
3765 dtd_dump_output(buf, d.intSubset as *mut _xmlNode, state, &mut lvl);
3766 io::buf_ccat(buf, b'\n');
3767 }
3768 }
3769
3770 if !d.children.is_null() {
3771 let mut child = d.children;
3772 while !child.is_null() {
3773 *level = 0;
3774 node_dump_internal(buf, child, child, cur, state, level);
3775 let ct = unsafe { (*child).type_ };
3776 if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
3777 io::buf_ccat(buf, b'\n');
3778 }
3779 child = unsafe { (*child).next };
3780 }
3781 }
3782}
3783
3784unsafe fn node_dump_internal(
3808 buf: *mut _xmlBuffer,
3809 cur: *mut _xmlNode,
3810 root: *mut _xmlNode,
3811 parent: *mut _xmlNode,
3812 state: &mut DumpState,
3813 level: &mut c_int,
3814) {
3815 if cur.is_null() || buf.is_null() {
3816 return;
3817 }
3818 let n = unsafe { &*cur };
3819 match n.type_ {
3820 t if t == XML_ELEMENT_NODE as c_int => {
3821 if cur != root && state.format == 1 {
3822 write_indent(buf, *level, state.indent, state.indent_len);
3823 }
3824 if !n.parent.is_null() && n.parent != parent && !n.children.is_null() {
3827 let mut sub = DumpState::new(state.format);
3828 let mut sub_level = *level;
3829 node_dump_internal(buf, cur, cur, n.parent, &mut sub, &mut sub_level);
3830 return;
3831 }
3832 io::buf_ccat(buf, b'<');
3834 write_qname(buf, cur);
3835 let mut nsdef = n.nsDef;
3836 while !nsdef.is_null() {
3837 ns_dump_output(buf, nsdef);
3838 nsdef = unsafe { (*nsdef).next };
3839 }
3840 let mut attr = n.properties;
3841 while !attr.is_null() {
3842 attr_dump_output(buf, attr);
3843 attr = unsafe { (*attr).next };
3844 }
3845 if n.children.is_null() {
3846 io::buf_add(buf, b"/>" as *const u8, 2);
3847 } else {
3848 if state.format == 1 {
3849 let mut tmp = n.children;
3852 while !tmp.is_null() {
3853 let tt = unsafe { (*tmp).type_ };
3854 if tt == XML_TEXT_NODE as c_int
3855 || tt == XML_CDATA_SECTION_NODE as c_int
3856 || tt == XML_ENTITY_REF_NODE as c_int
3857 {
3858 state.format = 0;
3859 state.unformatted = cur;
3860 break;
3861 }
3862 tmp = unsafe { (*tmp).next };
3863 }
3864 }
3865 io::buf_ccat(buf, b'>');
3866 if state.format == 1 {
3867 io::buf_ccat(buf, b'\n');
3868 }
3869 if *level >= 0 {
3870 *level += 1;
3871 }
3872 let mut child = n.children;
3873 while !child.is_null() {
3874 node_dump_internal(buf, child, root, cur, state, level);
3875 if state.format == 1 {
3876 let ct = unsafe { (*child).type_ };
3877 if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
3878 io::buf_ccat(buf, b'\n');
3879 }
3880 }
3881 child = unsafe { (*child).next };
3882 }
3883 if *level > 0 {
3885 *level -= 1;
3886 }
3887 if state.format == 1 {
3888 write_indent(buf, *level, state.indent, state.indent_len);
3889 }
3890 io::buf_add(buf, b"</" as *const u8, 2);
3891 write_qname(buf, cur);
3892 io::buf_ccat(buf, b'>');
3893 if cur == state.unformatted {
3894 state.format = state.saved;
3895 state.unformatted = ptr::null_mut();
3896 }
3897 }
3898 }
3899 t if t == XML_TEXT_NODE as c_int => {
3900 if !n.content.is_null() {
3901 if is_noenc_text(cur) {
3902 io::buf_cat(buf, n.content);
3903 } else {
3904 serialize_text(buf, n.content, xml_strlen(n.content));
3905 }
3906 } else if !n.children.is_null() {
3907 let c = node_get_content(cur);
3910 if !c.is_null() {
3911 if is_noenc_text(cur) {
3912 io::buf_cat(buf, c);
3913 } else {
3914 serialize_text(buf, c, xml_strlen(c));
3915 }
3916 allocator::xmlFreeImpl(c as *mut c_void);
3917 }
3918 }
3919 }
3920 t if t == XML_CDATA_SECTION_NODE as c_int => {
3921 if n.content.is_null() || unsafe { *n.content == 0 } {
3922 io::buf_add(buf, b"<![CDATA[]]>" as *const u8, 12);
3923 } else {
3924 let len = xml_strlen(n.content) as usize;
3925 let bytes = core::slice::from_raw_parts(n.content, len);
3926 let mut i = 0usize;
3927 let mut seg_start = 0usize;
3928 while i < len {
3929 if bytes[i] == b']'
3930 && i + 2 < len
3931 && bytes[i + 1] == b']'
3932 && bytes[i + 2] == b'>'
3933 {
3934 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
3935 io::buf_add(buf, n.content.add(seg_start), (i + 2 - seg_start) as c_int);
3936 io::buf_add(buf, b"]]>" as *const u8, 3);
3937 seg_start = i + 2;
3938 i += 3;
3939 continue;
3940 }
3941 i += 1;
3942 }
3943 if seg_start < len {
3944 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
3945 io::buf_add(buf, n.content.add(seg_start), (len - seg_start) as c_int);
3946 io::buf_add(buf, b"]]>" as *const u8, 3);
3947 }
3948 }
3949 }
3950 t if t == XML_COMMENT_NODE as c_int => {
3951 if cur != root && state.format == 1 {
3952 write_indent(buf, *level, state.indent, state.indent_len);
3953 }
3954 if !n.content.is_null() {
3955 io::buf_add(buf, b"<!--" as *const u8, 4);
3956 io::buf_cat(buf, n.content);
3957 io::buf_add(buf, b"-->" as *const u8, 3);
3958 }
3959 }
3960 t if t == XML_PI_NODE as c_int => {
3961 if cur != root && state.format == 1 {
3962 write_indent(buf, *level, state.indent, state.indent_len);
3963 }
3964 io::buf_add(buf, b"<?" as *const u8, 2);
3965 if !n.name.is_null() {
3966 io::buf_cat(buf, n.name);
3967 }
3968 if !n.content.is_null() && unsafe { *n.content != 0 } {
3969 io::buf_ccat(buf, b' ');
3970 io::buf_cat(buf, n.content);
3971 }
3972 io::buf_add(buf, b"?>" as *const u8, 2);
3973 }
3974 t if t == XML_ENTITY_REF_NODE as c_int => {
3975 io::buf_ccat(buf, b'&');
3976 if !n.name.is_null() {
3977 io::buf_cat(buf, n.name);
3978 }
3979 io::buf_ccat(buf, b';');
3980 }
3981 t if t == XML_DOCUMENT_NODE as c_int => {
3982 doc_content_dump_output(buf, cur, state, level);
3983 }
3984 t if t == XML_HTML_DOCUMENT_NODE as c_int => {
3985 crate::xml::html::serialize_node(cur, buf, state.format, *level);
3987 }
3988 t if t == XML_DTD_NODE as c_int => {
3989 dtd_dump_output(buf, cur, state, level);
3990 }
3991 t if t == XML_ATTRIBUTE_NODE as c_int => {
3992 attr_dump_output(buf, cur as *mut _xmlAttr);
3993 }
3994 t if t == XML_NAMESPACE_DECL as c_int => {
3995 ns_dump_output(buf, cur as *mut _xmlNs);
3996 }
3997 t if t == XML_ELEMENT_DECL as c_int => {
3998 dump_element_decl(buf, cur as *mut _xmlElement);
3999 }
4000 t if t == XML_ATTRIBUTE_DECL as c_int => {
4001 dump_attribute_decl(buf, cur as *mut _xmlAttribute);
4002 }
4003 t if t == XML_ENTITY_DECL as c_int => {
4004 dump_entity_decl(buf, cur as *mut _xmlEntity);
4005 }
4006 _ => {}
4007 }
4008}
4009
4010pub(crate) unsafe fn serialize_node(
4024 node: *mut _xmlNode,
4025 buf: *mut _xmlBuffer,
4026 format: c_int,
4027 level: c_int,
4028) {
4029 unsafe { serialize_node_opt(node, buf, format, level, ptr::null()) };
4030}
4031
4032pub(crate) unsafe fn serialize_node_opt(
4040 node: *mut _xmlNode,
4041 buf: *mut _xmlBuffer,
4042 format: c_int,
4043 level: c_int,
4044 indent: *const xmlChar,
4045) {
4046 unsafe { serialize_node_opts(node, buf, format, level, indent, 0) };
4047}
4048
4049pub(crate) unsafe fn serialize_node_opts(
4056 node: *mut _xmlNode,
4057 buf: *mut _xmlBuffer,
4058 format: c_int,
4059 level: c_int,
4060 indent: *const xmlChar,
4061 no_decl: c_int,
4062) {
4063 unsafe { serialize_node_opts_enc(node, buf, format, level, indent, no_decl, ptr::null()) };
4064}
4065
4066pub(crate) unsafe fn serialize_node_opts_enc(
4076 node: *mut _xmlNode,
4077 buf: *mut _xmlBuffer,
4078 format: c_int,
4079 level: c_int,
4080 indent: *const xmlChar,
4081 no_decl: c_int,
4082 encoding: *const xmlChar,
4083) {
4084 if node.is_null() || buf.is_null() {
4085 return;
4086 }
4087 let parent = unsafe { (*node).parent };
4088 let mut state = DumpState::with_indent_enc(format, indent, no_decl, encoding);
4089 let mut lvl = level;
4090 node_dump_internal(buf, node, node, parent, &mut state, &mut lvl);
4091}
4092
4093pub(crate) unsafe fn doc_dump(buf: *mut _xmlBuffer, doc: *mut _xmlDoc) -> c_int {
4103 if buf.is_null() || doc.is_null() {
4104 return -1;
4105 }
4106
4107 let before = io::buf_length(buf);
4108 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
4109 let after = io::buf_length(buf);
4110
4111 if after < 0 || before < 0 {
4112 return -1;
4113 }
4114 after - before
4115}
4116
4117pub(crate) unsafe fn node_dump(
4129 buf: *mut _xmlBuffer,
4130 doc: *mut _xmlDoc,
4131 node: *mut _xmlNode,
4132 level: c_int,
4133 format: c_int,
4134) -> c_int {
4135 let _ = doc; if buf.is_null() || node.is_null() {
4137 return -1;
4138 }
4139
4140 let before = io::buf_length(buf);
4141 serialize_node(node, buf, format, level);
4142 let after = io::buf_length(buf);
4143
4144 if after < 0 || before < 0 {
4145 return -1;
4146 }
4147 after - before
4148}
4149
4150#[allow(dead_code)]
4157pub(crate) unsafe fn save_doc_to_fd(doc: *mut _xmlDoc, fd: c_int, _compression: c_int) -> c_int {
4158 if doc.is_null() || fd < 0 {
4159 return -1;
4160 }
4161
4162 let out = io::output_buffer_create_fd(fd, ptr::null_mut());
4163 if out.is_null() {
4164 return -1;
4165 }
4166
4167 let buf = io::buf_create(-1);
4168 if buf.is_null() {
4169 io::output_buffer_close(out);
4170 return -1;
4171 }
4172
4173 let ret = doc_dump(buf, doc);
4174 if ret >= 0 {
4175 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
4176 io::output_buffer_flush(out);
4177 }
4178
4179 io::buf_free(buf);
4180 io::output_buffer_close(out);
4181 ret
4182}
4183
4184#[allow(dead_code)]
4191pub(crate) unsafe fn save_doc_to_buf(
4192 doc: *mut _xmlDoc,
4193 buf: *mut _xmlBuffer,
4194 compression: c_int,
4195) -> c_int {
4196 let _ = compression;
4197 if doc.is_null() || buf.is_null() {
4198 return -1;
4199 }
4200
4201 doc_dump(buf, doc)
4202}
4203
4204#[allow(dead_code)]
4211pub(crate) unsafe fn save_format_doc_to_buf(
4212 doc: *mut _xmlDoc,
4213 buf: *mut _xmlBuffer,
4214 compression: c_int,
4215) -> c_int {
4216 let _ = compression;
4217 if doc.is_null() || buf.is_null() {
4218 return -1;
4219 }
4220
4221 let before = io::buf_length(buf);
4222 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
4223 let after = io::buf_length(buf);
4224
4225 if after < 0 || before < 0 {
4226 return -1;
4227 }
4228 after - before
4229}
4230
4231#[allow(dead_code)]
4240pub(crate) unsafe fn dump_node(node: *mut _xmlNode) -> *mut xmlChar {
4241 if node.is_null() {
4242 return ptr::null_mut();
4243 }
4244
4245 let buf = io::buf_create(-1);
4246 if buf.is_null() {
4247 return ptr::null_mut();
4248 }
4249
4250 serialize_node(node, buf, 0, 0);
4251
4252 let content = io::buf_content(buf);
4253 if content.is_null() {
4254 io::buf_free(buf);
4255 return ptr::null_mut();
4256 }
4257
4258 let result = dup_xml_str(content);
4260 io::buf_free(buf);
4261 result
4262}
4263
4264pub unsafe fn dump_doc(doc: *mut _xmlDoc) -> *mut xmlChar {
4273 if doc.is_null() {
4274 return ptr::null_mut();
4275 }
4276
4277 let buf = io::buf_create(-1);
4278 if buf.is_null() {
4279 return ptr::null_mut();
4280 }
4281
4282 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
4283
4284 let content = io::buf_content(buf);
4285 if content.is_null() {
4286 io::buf_free(buf);
4287 return ptr::null_mut();
4288 }
4289
4290 let result = dup_xml_str(content);
4291 io::buf_free(buf);
4292 result
4293}
4294
4295pub(crate) unsafe fn xmlNodeDump(
4311 buf: *mut _xmlBuffer,
4312 doc: *mut _xmlDoc,
4313 node: *mut _xmlNode,
4314 level: c_int,
4315 format: c_int,
4316) -> c_int {
4317 node_dump(buf, doc, node, level, format)
4318}
4319
4320pub(crate) unsafe fn xmlDocDump(fp: *mut c_void, doc: *mut _xmlDoc) -> c_int {
4333 if fp.is_null() || doc.is_null() {
4334 return -1;
4335 }
4336
4337 let buf = io::buf_create(-1);
4338 if buf.is_null() {
4339 return -1;
4340 }
4341
4342 let ret = doc_dump(buf, doc);
4343 if ret < 0 {
4344 io::buf_free(buf);
4345 return -1;
4346 }
4347
4348 let content = io::buf_content(buf);
4349 let len = io::buf_length(buf);
4350 if !content.is_null() && len > 0 {
4351 let written = libc::fwrite(
4352 content as *const c_void,
4353 1,
4354 len as usize,
4355 fp as *mut libc::FILE,
4356 );
4357 io::buf_free(buf);
4358 written as c_int
4359 } else {
4360 io::buf_free(buf);
4361 0
4362 }
4363}
4364
4365pub(crate) unsafe fn xmlDocDumpFormatMemory(
4379 doc: *mut _xmlDoc,
4380 mem: *mut *mut xmlChar,
4381 size: *mut c_int,
4382 format: c_int,
4383) {
4384 if doc.is_null() || mem.is_null() || size.is_null() {
4385 return;
4386 }
4387
4388 let buf = io::buf_create(-1);
4389 if buf.is_null() {
4390 unsafe {
4391 *mem = ptr::null_mut();
4392 *size = 0;
4393 }
4394 return;
4395 }
4396
4397 serialize_node(doc as *mut _xmlNode, buf, format, 0);
4398
4399 let content = io::buf_content(buf);
4400 let len = io::buf_length(buf);
4401
4402 if !content.is_null() && len > 0 {
4403 let result = allocator::xmlMallocImpl((len + 1) as usize) as *mut xmlChar;
4405 if !result.is_null() {
4406 ptr::copy_nonoverlapping(content, result, len as usize);
4407 *result.add(len as usize) = 0;
4408 unsafe {
4409 *mem = result;
4410 *size = len;
4411 }
4412 } else {
4413 unsafe {
4414 *mem = ptr::null_mut();
4415 *size = 0;
4416 }
4417 }
4418 } else {
4419 unsafe {
4420 *mem = ptr::null_mut();
4421 *size = 0;
4422 }
4423 }
4424
4425 io::buf_free(buf);
4426}
4427
4428pub(crate) unsafe fn xmlDocDumpMemory(doc: *mut _xmlDoc, mem: *mut *mut xmlChar, size: *mut c_int) {
4442 xmlDocDumpFormatMemory(doc, mem, size, 0)
4443}
4444
4445pub(crate) unsafe fn xmlSaveFile(filename: *const c_char, cur: *mut _xmlDoc) -> c_int {
4459 unsafe { xmlSaveFormatFileEnc(filename, cur, ptr::null(), 0) }
4460}
4461
4462pub(crate) unsafe fn xmlSaveFileEnc(
4477 filename: *const c_char,
4478 cur: *mut _xmlDoc,
4479 encoding: *const c_char,
4480) -> c_int {
4481 unsafe { xmlSaveFormatFileEnc(filename, cur, encoding, 0) }
4482}
4483
4484pub(crate) unsafe fn xmlSaveFormatFile(
4498 filename: *const c_char,
4499 cur: *mut _xmlDoc,
4500 format: c_int,
4501) -> c_int {
4502 unsafe { xmlSaveFormatFileEnc(filename, cur, ptr::null(), format) }
4503}
4504
4505pub(crate) unsafe fn xmlSaveFormatFileEnc(
4525 filename: *const c_char,
4526 cur: *mut _xmlDoc,
4527 encoding: *const c_char,
4528 format: c_int,
4529) -> c_int {
4530 if cur.is_null() {
4531 return -1;
4532 }
4533 let options = if format != 0 {
4534 crate::xml::save::XML_SAVE_FORMAT
4535 } else {
4536 0
4537 };
4538 let ctxt = crate::xml::save::xmlSaveToFilename(filename, encoding, options);
4539 if ctxt.is_null() {
4540 return -1;
4541 }
4542 crate::xml::save::xmlSaveDoc(ctxt, cur);
4543 crate::xml::save::xmlSaveClose(ctxt)
4544}
4545
4546pub(crate) unsafe fn xmlGetDocCompressMode(doc: *mut _xmlDoc) -> c_int {
4558 if doc.is_null() {
4559 return -1;
4560 }
4561 unsafe { (*doc).compression }
4562}
4563
4564pub(crate) unsafe fn xmlSetDocCompressMode(doc: *mut _xmlDoc, mode: c_int) {
4576 if doc.is_null() {
4577 return;
4578 }
4579 unsafe {
4580 (*doc).compression = mode;
4581 }
4582}
4583
4584#[cfg(test)]
4585mod tests {
4586 use super::*;
4587 use core::ffi::c_void;
4588
4589 fn c_str(s: &str) -> *const xmlChar {
4597 let bytes = s.as_bytes();
4598 let buf = unsafe { allocator::xmlMallocImpl(bytes.len() + 1) as *mut u8 };
4599 if !buf.is_null() {
4600 unsafe {
4601 ptr::copy_nonoverlapping(bytes.as_ptr(), buf, bytes.len());
4602 *buf.add(bytes.len()) = 0;
4603 }
4604 }
4605 buf as *const xmlChar
4606 }
4607
4608 #[test]
4615 fn test_new_free_doc() {
4616 unsafe {
4617 let doc = new_doc(ptr::null());
4618 assert!(!doc.is_null());
4619 assert_eq!((*doc).type_, XML_DOCUMENT_NODE as c_int);
4620 assert_eq!((*doc).standalone, -1);
4621 assert_eq!((*doc).doc, doc);
4622 assert!(!(*doc).version.is_null());
4623 free_doc(doc);
4624 }
4625 }
4626
4627 #[test]
4635 fn test_new_doc_with_version() {
4636 unsafe {
4637 let ver = c_str("2.0");
4638 let doc = new_doc(ver);
4639 assert!(!doc.is_null());
4640 let doc_ver = (*doc).version;
4641 assert!(!doc_ver.is_null());
4642 assert!(crate::abi::exports_xml2::xmlStrEqual(doc_ver, ver,) != 0);
4643 allocator::xmlFreeImpl(ver as *mut c_void);
4644 free_doc(doc);
4645 }
4646 }
4647
4648 #[test]
4656 fn test_new_node() {
4657 unsafe {
4658 let doc = new_doc(ptr::null());
4659 let node = new_node(ptr::null_mut(), c_str("root"));
4660 assert!(!node.is_null());
4661 assert_eq!((*node).type_, XML_ELEMENT_NODE as c_int);
4662 assert!(!(*node).name.is_null());
4663 free_node(node);
4664 free_doc(doc);
4665 }
4666 }
4667
4668 #[test]
4676 fn test_node_get_content_recurses_descendants() {
4677 unsafe {
4682 let doc = new_doc(ptr::null());
4683 let root = new_node(ptr::null_mut(), c_str("library"));
4684 doc_set_root_element(doc, root);
4685 let book = new_child(root, ptr::null_mut(), c_str("book"));
4686 let title = new_child(book, ptr::null_mut(), c_str("title"));
4687 let text = new_text(c_str("Rust"));
4688 add_child(title, text);
4689
4690 let content = node_get_content(book);
4691 assert!(!content.is_null());
4692 let s = core::slice::from_raw_parts(
4693 content,
4694 libc::strlen(content as *const libc::c_char) as usize,
4695 );
4696 assert_eq!(s, b"Rust", "descendant text not concatenated");
4697 allocator::xmlFreeImpl(content as *mut c_void);
4698
4699 free_doc(doc);
4700 }
4701 }
4702
4703 #[test]
4710 fn test_doc_set_root_element() {
4711 unsafe {
4712 let doc = new_doc(ptr::null());
4713 let root = new_node(ptr::null_mut(), c_str("root"));
4714 let old = doc_set_root_element(doc, root);
4715 assert!(old.is_null());
4716 assert_eq!(doc_get_root_element(doc), root);
4717 assert_eq!((*doc).children, root);
4718 free_doc(doc);
4719 }
4720 }
4721
4722 #[test]
4730 fn test_add_child_and_sibling() {
4731 unsafe {
4732 let doc = new_doc(ptr::null());
4733 let root = new_node(ptr::null_mut(), c_str("root"));
4734 doc_set_root_element(doc, root);
4735
4736 let child1 = new_child(root, ptr::null_mut(), c_str("child1"));
4737 assert!(!child1.is_null());
4738 assert_eq!((*child1).parent, root);
4739 assert_eq!((*root).children, child1);
4740 assert_eq!((*root).last, child1);
4741
4742 let child2 = new_child(root, ptr::null_mut(), c_str("child2"));
4743 assert!(!child2.is_null());
4744 assert_eq!((*child2).parent, root);
4745 assert_eq!((*child1).next, child2);
4746 assert_eq!((*child2).prev, child1);
4747 assert_eq!((*root).last, child2);
4748
4749 let sibling = new_node(ptr::null_mut(), c_str("sibling"));
4751 add_sibling(child2, sibling);
4752 assert_eq!((*child2).next, sibling);
4753 assert_eq!((*sibling).prev, child2);
4754 assert_eq!((*root).last, sibling);
4755
4756 free_doc(doc);
4757 }
4758 }
4759
4760 #[test]
4768 fn test_unlink_node() {
4769 unsafe {
4770 let doc = new_doc(ptr::null());
4771 let root = new_node(ptr::null_mut(), c_str("root"));
4772 doc_set_root_element(doc, root);
4773
4774 let child1 = new_child(root, ptr::null_mut(), c_str("c1"));
4775 let child2 = new_child(root, ptr::null_mut(), c_str("c2"));
4776
4777 unlink_node(child1);
4778 assert!((*child1).parent.is_null());
4779 assert!((*child1).prev.is_null());
4780 assert!((*child1).next.is_null());
4781 assert_eq!((*root).children, child2);
4782 assert_eq!((*root).last, child2);
4783
4784 free_node(child1);
4785 free_doc(doc);
4786 }
4787 }
4788
4789 #[test]
4796 fn test_text_and_comment_nodes() {
4797 unsafe {
4798 let text = new_text(c_str("hello world"));
4799 assert!(!text.is_null());
4800 assert_eq!((*text).type_, XML_TEXT_NODE as c_int);
4801 assert!(!(*text).content.is_null());
4802 free_node(text);
4803
4804 let comment = new_comment(c_str("my comment"));
4805 assert!(!comment.is_null());
4806 assert_eq!((*comment).type_, XML_COMMENT_NODE as c_int);
4807 free_node(comment);
4808
4809 let pi = new_pi(c_str("xml"), c_str("version='1.0'"));
4810 assert!(!pi.is_null());
4811 assert_eq!((*pi).type_, XML_PI_NODE as c_int);
4812 free_node(pi);
4813 }
4814 }
4815
4816 #[test]
4824 fn test_set_and_get_prop() {
4825 unsafe {
4826 let doc = new_doc(ptr::null());
4827 let root = new_node(ptr::null_mut(), c_str("root"));
4828 doc_set_root_element(doc, root);
4829
4830 let attr = set_prop(root, c_str("id"), c_str("42"));
4831 assert!(!attr.is_null());
4832 assert_eq!((*attr).type_, XML_ATTRIBUTE_NODE as c_int);
4833
4834 let value = get_prop(root, c_str("id"));
4835 assert!(!value.is_null());
4836 assert!(crate::abi::exports_xml2::xmlStrEqual(value, c_str("42")) != 0);
4837 allocator::xmlFreeImpl(value as *mut c_void);
4838
4839 free_doc(doc);
4840 }
4841 }
4842
4843 #[test]
4851 fn test_remove_prop() {
4852 unsafe {
4853 let doc = new_doc(ptr::null());
4854 let root = new_node(ptr::null_mut(), c_str("root"));
4855 doc_set_root_element(doc, root);
4856
4857 set_prop(root, c_str("a"), c_str("1"));
4858 set_prop(root, c_str("b"), c_str("2"));
4859
4860 let value = get_prop(root, c_str("a"));
4861 assert!(!value.is_null());
4862 allocator::xmlFreeImpl(value as *mut c_void);
4863
4864 let attr = (*root).properties;
4866 assert!(!attr.is_null());
4867 let result = remove_prop(attr);
4868 assert_eq!(result, 0);
4869
4870 let value2 = get_prop(root, c_str("a"));
4872 assert!(value2.is_null());
4873
4874 free_doc(doc);
4875 }
4876 }
4877
4878 #[test]
4886 fn test_namespace_operations() {
4887 unsafe {
4888 let doc = new_doc(ptr::null());
4889 let root = new_node(ptr::null_mut(), c_str("root"));
4890 doc_set_root_element(doc, root);
4891
4892 let ns = new_ns(root, c_str("http://example.com"), c_str("ex"));
4893 assert!(!ns.is_null());
4894 assert!(!(*root).nsDef.is_null());
4895
4896 set_ns(root, ns);
4897 assert_eq!((*root).ns, ns);
4898
4899 let found = search_ns(doc, root, c_str("ex"));
4900 assert_eq!(found, ns);
4901
4902 let found_href = search_ns_by_href(doc, root, c_str("http://example.com"));
4903 assert_eq!(found_href, ns);
4904
4905 free_doc(doc);
4906 }
4907 }
4908
4909 #[test]
4917 fn test_new_dtd() {
4918 unsafe {
4919 let doc = new_doc(ptr::null());
4920 let dtd = new_dtd(doc, c_str("root"), c_str("-//TEST//DTD"), c_str("test.dtd"));
4921 assert!(!dtd.is_null());
4922 assert_eq!((*dtd).type_, XML_DTD_NODE as c_int);
4923 assert_eq!(get_int_subset(doc), dtd);
4924 free_doc(doc);
4925 }
4926 }
4927
4928 #[test]
4935 fn test_copy_node_deep() {
4936 unsafe {
4937 let doc = new_doc(ptr::null());
4938 let root = new_node(ptr::null_mut(), c_str("root"));
4939 doc_set_root_element(doc, root);
4940 let _child = new_child(root, ptr::null_mut(), c_str("child"));
4941
4942 let copy = copy_node(root, 1);
4943 assert!(!copy.is_null());
4944 assert_eq!((*copy).type_, XML_ELEMENT_NODE as c_int);
4945 assert!(!(*copy).children.is_null());
4947 assert_eq!((*(*copy).children).type_, XML_ELEMENT_NODE as c_int);
4948
4949 free_node(copy);
4950 free_doc(doc);
4951 }
4952 }
4953
4954 #[test]
4962 fn test_new_cdata_block() {
4963 unsafe {
4964 let doc = new_doc(ptr::null());
4965 let content = c_str("some <cdata> content");
4966 let cdata = new_cdata_block(doc, content, 20);
4967 assert!(!cdata.is_null());
4968 assert_eq!((*cdata).type_, XML_CDATA_SECTION_NODE as c_int);
4969 free_node(cdata);
4970 free_doc(doc);
4971 }
4972 }
4973
4974 #[test]
4983 fn test_null_handling() {
4984 unsafe {
4985 assert!(!new_doc(ptr::null()).is_null()); let doc = new_doc(ptr::null());
4987 assert!(new_node(ptr::null_mut(), ptr::null()).is_null());
4990 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());
4994 assert!(add_sibling(ptr::null_mut(), ptr::null_mut()).is_null());
4995 free_doc(doc);
4996 }
4997 }
4998
4999 unsafe fn buf_eq_str(buf: *mut _xmlBuffer, expected: &str) -> bool {
5010 let content = io::buf_content(buf);
5011 if content.is_null() {
5012 return expected.is_empty();
5013 }
5014 let len = io::buf_length(buf) as usize;
5015 if len != expected.len() {
5016 return false;
5017 }
5018 let slice = unsafe { core::slice::from_raw_parts(content, len) };
5019 slice == expected.as_bytes()
5020 }
5021
5022 #[test]
5030 fn test_serialize_empty_document() {
5031 unsafe {
5032 let doc = new_doc(ptr::null());
5033 let buf = io::buf_create(-1);
5034 assert!(!buf.is_null());
5035
5036 let ret = doc_dump(buf, doc);
5037 assert!(ret >= 0);
5038
5039 let expected = "<?xml version=\"1.0\"?>\n";
5043 assert!(buf_eq_str(buf, expected));
5044
5045 io::buf_free(buf);
5046 free_doc(doc);
5047 }
5048 }
5049
5050 #[test]
5057 fn test_serialize_element_with_text() {
5058 unsafe {
5059 let doc = new_doc(ptr::null());
5060 let root = new_node(ptr::null_mut(), c_str("root"));
5061 doc_set_root_element(doc, root);
5062
5063 let text = new_text(c_str("hello world"));
5065 add_child(root, text);
5066
5067 let buf = io::buf_create(-1);
5068 assert!(!buf.is_null());
5069
5070 let ret = doc_dump(buf, doc);
5071 assert!(ret >= 0);
5072
5073 let expected = "<?xml version=\"1.0\"?>\n<root>hello world</root>\n";
5074 assert!(buf_eq_str(buf, expected));
5075
5076 io::buf_free(buf);
5077 free_doc(doc);
5078 }
5079 }
5080
5081 #[test]
5088 fn test_serialize_element_with_attributes() {
5089 unsafe {
5090 let doc = new_doc(ptr::null());
5091 let root = new_node(ptr::null_mut(), c_str("root"));
5092 doc_set_root_element(doc, root);
5093
5094 set_prop(root, c_str("id"), c_str("42"));
5095 set_prop(root, c_str("name"), c_str("test"));
5096
5097 let buf = io::buf_create(-1);
5098 assert!(!buf.is_null());
5099
5100 let ret = doc_dump(buf, doc);
5101 assert!(ret >= 0);
5102
5103 let expected = "<?xml version=\"1.0\"?>\n<root id=\"42\" name=\"test\"/>\n";
5104 assert!(buf_eq_str(buf, expected));
5105
5106 io::buf_free(buf);
5107 free_doc(doc);
5108 }
5109 }
5110
5111 #[test]
5118 fn test_serialize_nested_elements() {
5119 unsafe {
5120 let doc = new_doc(ptr::null());
5121 let root = new_node(ptr::null_mut(), c_str("root"));
5122 doc_set_root_element(doc, root);
5123
5124 let child = new_child(root, ptr::null_mut(), c_str("child"));
5125 let grandchild = new_child(child, ptr::null_mut(), c_str("gc"));
5126 let text = new_text(c_str("text"));
5127 add_child(grandchild, text);
5128
5129 let buf = io::buf_create(-1);
5130 assert!(!buf.is_null());
5131
5132 let ret = doc_dump(buf, doc);
5133 assert!(ret >= 0);
5134
5135 let expected = "<?xml version=\"1.0\"?>\n<root><child><gc>text</gc></child></root>\n";
5136 assert!(buf_eq_str(buf, expected));
5137
5138 io::buf_free(buf);
5139 free_doc(doc);
5140 }
5141 }
5142
5143 #[test]
5150 fn test_serialize_with_formatting() {
5151 unsafe {
5152 let doc = new_doc(ptr::null());
5153 let root = new_node(ptr::null_mut(), c_str("root"));
5154 doc_set_root_element(doc, root);
5155
5156 let child = new_child(root, ptr::null_mut(), c_str("child"));
5157 let text = new_text(c_str("text"));
5158 add_child(child, text);
5159
5160 let buf = io::buf_create(-1);
5161 assert!(!buf.is_null());
5162
5163 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
5164
5165 let expected = "<?xml version=\"1.0\"?>\n<root>\n <child>text</child>\n</root>\n";
5166 assert!(buf_eq_str(buf, expected));
5167
5168 io::buf_free(buf);
5169 free_doc(doc);
5170 }
5171 }
5172
5173 #[test]
5180 fn test_serialize_escape_ampersand() {
5181 unsafe {
5182 let doc = new_doc(ptr::null());
5183 let root = new_node(ptr::null_mut(), c_str("root"));
5184 doc_set_root_element(doc, root);
5185
5186 let text = new_text(c_str("a & b"));
5187 add_child(root, text);
5188
5189 let buf = io::buf_create(-1);
5190 assert!(!buf.is_null());
5191
5192 let ret = doc_dump(buf, doc);
5193 assert!(ret >= 0);
5194
5195 let expected = "<?xml version=\"1.0\"?>\n<root>a & b</root>\n";
5196 assert!(buf_eq_str(buf, expected));
5197
5198 io::buf_free(buf);
5199 free_doc(doc);
5200 }
5201 }
5202
5203 #[test]
5210 fn test_serialize_escape_angle_brackets() {
5211 unsafe {
5212 let doc = new_doc(ptr::null());
5213 let root = new_node(ptr::null_mut(), c_str("root"));
5214 doc_set_root_element(doc, root);
5215
5216 let text = new_text(c_str("x < y > z"));
5217 add_child(root, text);
5218
5219 let buf = io::buf_create(-1);
5220 assert!(!buf.is_null());
5221
5222 let ret = doc_dump(buf, doc);
5223 assert!(ret >= 0);
5224
5225 let expected = "<?xml version=\"1.0\"?>\n<root>x < y > z</root>\n";
5226 assert!(buf_eq_str(buf, expected));
5227
5228 io::buf_free(buf);
5229 free_doc(doc);
5230 }
5231 }
5232
5233 #[test]
5240 fn test_serialize_comment() {
5241 unsafe {
5242 let doc = new_doc(ptr::null());
5243 let root = new_node(ptr::null_mut(), c_str("root"));
5244 doc_set_root_element(doc, root);
5245
5246 let comment = new_comment(c_str("my comment"));
5247 add_child(root, comment);
5248
5249 let buf = io::buf_create(-1);
5250 assert!(!buf.is_null());
5251
5252 let ret = doc_dump(buf, doc);
5253 assert!(ret >= 0);
5254
5255 let expected = "<?xml version=\"1.0\"?>\n<root><!--my comment--></root>\n";
5256 assert!(buf_eq_str(buf, expected));
5257
5258 io::buf_free(buf);
5259 free_doc(doc);
5260 }
5261 }
5262
5263 #[test]
5270 fn test_serialize_pi() {
5271 unsafe {
5272 let doc = new_doc(ptr::null());
5273 let root = new_node(ptr::null_mut(), c_str("root"));
5274 doc_set_root_element(doc, root);
5275
5276 let pi = new_pi(
5277 c_str("xml-stylesheet"),
5278 c_str("href=\"style.xsl\" type=\"text/xsl\""),
5279 );
5280 add_child(root, pi);
5281
5282 let buf = io::buf_create(-1);
5283 assert!(!buf.is_null());
5284
5285 let ret = doc_dump(buf, doc);
5286 assert!(ret >= 0);
5287
5288 let expected = "<?xml version=\"1.0\"?>\n<root><?xml-stylesheet href=\"style.xsl\" type=\"text/xsl\"?></root>\n";
5289 assert!(buf_eq_str(buf, expected));
5290
5291 io::buf_free(buf);
5292 free_doc(doc);
5293 }
5294 }
5295
5296 #[test]
5303 fn test_serialize_self_closing() {
5304 unsafe {
5305 let doc = new_doc(ptr::null());
5306 let root = new_node(ptr::null_mut(), c_str("empty"));
5307 doc_set_root_element(doc, root);
5308
5309 let buf = io::buf_create(-1);
5310 assert!(!buf.is_null());
5311
5312 let ret = doc_dump(buf, doc);
5313 assert!(ret >= 0);
5314
5315 let expected = "<?xml version=\"1.0\"?>\n<empty/>\n";
5316 assert!(buf_eq_str(buf, expected));
5317
5318 io::buf_free(buf);
5319 free_doc(doc);
5320 }
5321 }
5322
5323 #[test]
5331 fn test_dump_node_to_string() {
5332 unsafe {
5333 let node = new_node(ptr::null_mut(), c_str("foo"));
5334 let text = new_text(c_str("bar"));
5335 add_child(node, text);
5336
5337 let result = dump_node(node);
5338 assert!(!result.is_null());
5339
5340 let len = xml_strlen(result);
5341 let slice = { core::slice::from_raw_parts(result, len as usize) };
5342 assert_eq!(slice, b"<foo>bar</foo>");
5343
5344 allocator::xmlFreeImpl(result as *mut c_void);
5345 free_node(node);
5346 }
5347 }
5348
5349 #[test]
5357 fn test_dump_doc_to_string() {
5358 unsafe {
5359 let doc = new_doc(ptr::null());
5360 let root = new_node(ptr::null_mut(), c_str("root"));
5361 doc_set_root_element(doc, root);
5362
5363 let result = dump_doc(doc);
5364 assert!(!result.is_null());
5365
5366 let len = xml_strlen(result);
5367 let slice = { core::slice::from_raw_parts(result, len as usize) };
5368 let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
5369 assert_eq!(slice, expected.as_bytes());
5370
5371 allocator::xmlFreeImpl(result as *mut c_void);
5372 free_doc(doc);
5373 }
5374 }
5375
5376 #[test]
5384 fn test_xmlDocDumpFormatMemory() {
5385 unsafe {
5386 let doc = new_doc(ptr::null());
5387 let root = new_node(ptr::null_mut(), c_str("root"));
5388 doc_set_root_element(doc, root);
5389
5390 let mut mem: *mut xmlChar = ptr::null_mut();
5391 let mut size: c_int = 0;
5392
5393 xmlDocDumpFormatMemory(doc, &mut mem, &mut size, 0);
5394
5395 assert!(!mem.is_null());
5396 assert!(size > 0);
5397
5398 let slice = { core::slice::from_raw_parts(mem, size as usize) };
5399 let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
5402 assert_eq!(slice, expected.as_bytes());
5403
5404 allocator::xmlFreeImpl(mem as *mut c_void);
5405 free_doc(doc);
5406 }
5407 }
5408
5409 #[test]
5416 fn test_serialize_escape_attribute() {
5417 unsafe {
5418 let doc = new_doc(ptr::null());
5419 let root = new_node(ptr::null_mut(), c_str("root"));
5420 doc_set_root_element(doc, root);
5421
5422 set_prop(root, c_str("desc"), c_str("a < b & c \"quoted\""));
5424
5425 let buf = io::buf_create(-1);
5426 assert!(!buf.is_null());
5427
5428 let ret = doc_dump(buf, doc);
5429 assert!(ret >= 0);
5430
5431 let expected =
5432 "<?xml version=\"1.0\"?>\n<root desc=\"a < b & c "quoted"\"/>\n";
5433 assert!(buf_eq_str(buf, expected));
5434
5435 io::buf_free(buf);
5436 free_doc(doc);
5437 }
5438 }
5439}