1use core::ffi::c_void;
105use core::ptr;
106use std::os::raw::{c_char, c_int, c_long, c_ulong};
107
108use crate::abi::allocator;
109use crate::abi::constants::*;
110use crate::abi::structs::*;
111use crate::abi::types::xmlCharEncoding::XML_CHAR_ENCODING_UTF8;
112use crate::abi::types::xmlDocProperties::XML_DOC_USERBUILT;
113use crate::abi::types::xmlElementType::*;
114use crate::abi::types::*;
115use crate::xml::io;
116
117unsafe fn dup_xml_str(str: *const xmlChar) -> *mut xmlChar {
127 if str.is_null() {
128 return ptr::null_mut();
129 }
130 let len = unsafe { crate::abi::exports_xml2::xmlStrlen(str) as usize };
131 if len == 0 {
132 let buf = unsafe { allocator::xmlMallocImpl(1) as *mut xmlChar };
134 if !buf.is_null() {
135 unsafe { *buf = 0 };
136 }
137 return buf;
138 }
139 let buf = unsafe { allocator::xmlMallocImpl(len + 1) as *mut xmlChar };
140 if !buf.is_null() {
141 unsafe {
142 ptr::copy_nonoverlapping(str, buf, len + 1);
143 }
144 }
145 buf
146}
147
148#[allow(dead_code)]
150unsafe fn copy_xml_str_content(dest: *mut xmlChar, src: *const xmlChar, max_len: usize) -> bool {
151 if src.is_null() || dest.is_null() || max_len == 0 {
152 return false;
153 }
154 let len = unsafe { crate::abi::exports_xml2::xmlStrlen(src) as usize };
155 if len >= max_len {
156 return false;
157 }
158 unsafe {
159 ptr::copy_nonoverlapping(src, dest, len);
160 *dest.add(len) = 0;
161 }
162 true
163}
164
165pub const unsafe fn xml_strlen(str: *const xmlChar) -> c_int {
182 if str.is_null() {
183 return 0;
184 }
185 let mut len: c_int = 0;
186 while unsafe { *str.add(len as usize) != 0 } {
187 len += 1;
188 }
189 len
190}
191
192pub unsafe fn new_doc(version: *const xmlChar) -> *mut _xmlDoc {
215 let doc = allocator::xmlMallocZero(size_of::<_xmlDoc>() as usize) as *mut _xmlDoc;
217 if doc.is_null() {
218 return ptr::null_mut();
219 }
220
221 unsafe {
222 (*doc).type_ = XML_DOCUMENT_NODE as c_int;
223 (*doc).standalone = -1; (*doc).doc = doc; (*doc).properties = XML_DOC_USERBUILT as c_int;
226 (*doc).compression = -1; (*doc).charset = XML_CHAR_ENCODING_UTF8 as c_int;
228
229 let ver = if version.is_null() {
231 XML_DEFAULT_VERSION.as_ptr() as *const xmlChar
232 } else {
233 version
234 };
235 (*doc).version = dup_xml_str(ver);
236 }
237
238 crate::abi::data_globals::register_node_hook(doc as *mut _xmlNode);
240
241 doc
242}
243
244pub unsafe fn free_doc(doc: *mut _xmlDoc) {
258 if doc.is_null() {
259 return;
260 }
261
262 crate::abi::data_globals::deregister_node_hook(doc as *mut _xmlNode);
265
266 let d = unsafe { &mut *doc };
267
268 let dict = d.dict;
272 let mut ext_subset = d.extSubset;
273 let int_subset = d.intSubset;
274 if !ext_subset.is_null() && ext_subset == int_subset {
275 ext_subset = ptr::null_mut();
276 }
277 if !ext_subset.is_null() {
278 unlink_node_internal(ext_subset as *mut _xmlNode, d as *mut _xmlDoc);
279 d.extSubset = ptr::null_mut();
280 free_dtd(ext_subset);
281 }
282 if !int_subset.is_null() {
283 unlink_node_internal(int_subset as *mut _xmlNode, d as *mut _xmlDoc);
284 d.intSubset = ptr::null_mut();
285 free_dtd(int_subset);
286 }
287
288 if !d.children.is_null() {
290 free_node_list(d.children);
291 }
292
293 if !d.oldNs.is_null() {
295 free_ns_list(d.oldNs);
296 }
297
298 if !d.version.is_null() {
300 allocator::xmlFreeImpl(d.version as *mut c_void);
301 }
302 if !d.encoding.is_null() {
303 allocator::xmlFreeImpl(d.encoding as *mut c_void);
304 }
305 if !d.URL.is_null() {
306 allocator::xmlFreeImpl(d.URL as *mut c_void);
307 }
308
309 allocator::xmlFreeImpl(doc as *mut c_void);
311
312 if !dict.is_null() {
314 crate::abi::exports_xml2::xmlDictFree(dict);
315 }
316}
317
318unsafe fn unlink_node_internal(node: *mut _xmlNode, _doc: *mut _xmlDoc) {
322 if node.is_null() {
323 return;
324 }
325 let parent = (*node).parent;
326 if parent.is_null() {
327 return;
328 }
329 if (*node).prev.is_null() {
330 (*parent).children = (*node).next;
331 } else {
332 (*(*node).prev).next = (*node).next;
333 }
334 if (*node).next.is_null() {
335 (*parent).last = (*node).prev;
336 } else {
337 (*(*node).next).prev = (*node).prev;
338 }
339 (*node).next = ptr::null_mut();
340 (*node).prev = ptr::null_mut();
341 (*node).parent = ptr::null_mut();
342}
343
344pub unsafe fn copy_doc(doc: *const _xmlDoc, recursive: c_int) -> *mut _xmlDoc {
359 if doc.is_null() {
360 return ptr::null_mut();
361 }
362
363 let d = unsafe { &*doc };
364
365 let new_doc = new_doc(d.version);
366 if new_doc.is_null() {
367 return ptr::null_mut();
368 }
369
370 unsafe {
371 (*new_doc).type_ = d.type_;
372 (*new_doc).standalone = d.standalone;
373 (*new_doc).encoding = dup_xml_str(d.encoding);
374 (*new_doc).URL = dup_xml_str(d.URL);
375 (*new_doc).charset = d.charset;
376 (*new_doc).properties = d.properties;
377
378 if !d.intSubset.is_null() {
383 let dtd_copy = crate::xml::dtd::copy_dtd(d.intSubset);
384 if !dtd_copy.is_null() {
385 (*new_doc).intSubset = dtd_copy;
386 }
387 }
388
389 if recursive != 0 && !d.children.is_null() {
390 (*new_doc).children = copy_node_list(d.children, recursive);
391 if !(*new_doc).children.is_null() {
392 (*(*new_doc).children).parent = ptr::null_mut(); (*(*new_doc).children).doc = new_doc;
394 propagate_doc((*new_doc).children, new_doc);
396 }
397 }
398 }
399
400 new_doc
401}
402
403pub unsafe fn doc_set_root_element(doc: *mut _xmlDoc, root: *mut _xmlNode) -> *mut _xmlNode {
419 if doc.is_null() {
420 return ptr::null_mut();
421 }
422
423 let d = unsafe { &mut *doc };
424
425 let old_root = doc_get_root_element(doc);
426
427 if !root.is_null() {
428 unsafe {
429 (*root).parent = ptr::null_mut();
430 (*root).doc = doc;
431 }
432 d.children = root;
433 d.last = root;
434 unsafe {
435 (*root).prev = ptr::null_mut();
436 (*root).next = ptr::null_mut();
437 }
438 } else {
439 d.children = ptr::null_mut();
440 d.last = ptr::null_mut();
441 }
442
443 old_root
444}
445
446pub fn doc_get_root_element(doc: *mut _xmlDoc) -> *mut _xmlNode {
462 if doc.is_null() {
463 return ptr::null_mut();
464 }
465
466 let d = unsafe { &*doc };
467 let mut cur = d.children;
468
469 while !cur.is_null() {
470 let node = unsafe { &*cur };
471 if node.type_ == XML_ELEMENT_NODE as c_int {
472 return cur;
473 }
474 cur = node.next;
475 }
476
477 ptr::null_mut()
478}
479
480pub fn get_line_no(node: *const _xmlNode) -> c_long {
495 unsafe { get_line_no_internal(node, 0) }
496}
497
498unsafe fn get_line_no_internal(node: *const _xmlNode, depth: c_int) -> c_long {
510 if depth >= 5 {
511 return -1;
512 }
513 if node.is_null() {
514 return -1;
515 }
516 let n = unsafe { &*node };
517 if n.type_ == XML_ELEMENT_NODE as c_int
518 || n.type_ == XML_TEXT_NODE as c_int
519 || n.type_ == XML_COMMENT_NODE as c_int
520 || n.type_ == XML_PI_NODE as c_int
521 {
522 if n.line == 65535 {
523 if n.type_ == XML_ELEMENT_NODE as c_int && !n.children.is_null() {
524 let r = unsafe { get_line_no_internal(n.children, depth + 1) };
525 if r != -1 {
526 return r;
527 }
528 }
529 if !n.next.is_null() {
530 let r = unsafe { get_line_no_internal(n.next, depth + 1) };
531 if r != -1 {
532 return r;
533 }
534 }
535 if !n.prev.is_null() {
536 let r = unsafe { get_line_no_internal(n.prev, depth + 1) };
537 if r != -1 {
538 return r;
539 }
540 }
541 }
542 n.line as c_long
543 } else if !n.prev.is_null()
544 && (unsafe { (*n.prev).type_ } == XML_ELEMENT_NODE as c_int
545 || unsafe { (*n.prev).type_ } == XML_TEXT_NODE as c_int
546 || unsafe { (*n.prev).type_ } == XML_COMMENT_NODE as c_int
547 || unsafe { (*n.prev).type_ } == XML_PI_NODE as c_int)
548 {
549 unsafe { get_line_no_internal(n.prev, depth + 1) }
550 } else if !n.parent.is_null() && unsafe { (*n.parent).type_ } == XML_ELEMENT_NODE as c_int {
551 unsafe { get_line_no_internal(n.parent, depth + 1) }
552 } else {
553 -1
554 }
555}
556
557pub unsafe fn node_get_content(node: *mut _xmlNode) -> *mut xmlChar {
592 if node.is_null() {
593 return ptr::null_mut();
594 }
595 let typ = (*node).type_;
596 let mut result: Vec<u8> = Vec::new();
597 match typ {
598 t if t == XML_TEXT_NODE as c_int
599 || t == XML_CDATA_SECTION_NODE as c_int
600 || t == XML_COMMENT_NODE as c_int
601 || t == XML_PI_NODE as c_int =>
602 {
603 if !(*node).content.is_null() {
604 let len = crate::abi::exports_xml2::xmlStrlen((*node).content);
605 result
606 .extend_from_slice(core::slice::from_raw_parts((*node).content, len as usize));
607 } else if t == XML_TEXT_NODE as c_int && !(*node).children.is_null() {
608 let mut child = (*node).children;
611 while !child.is_null() {
612 if !(*child).content.is_null() {
613 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
614 result.extend_from_slice(core::slice::from_raw_parts(
615 (*child).content,
616 len as usize,
617 ));
618 }
619 child = (*child).next;
620 }
621 }
622 }
623 t if t == XML_ATTRIBUTE_NODE as c_int => {
624 if !(*node).children.is_null() {
626 let child = (*node).children;
627 if !(*child).content.is_null() {
628 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
629 result.extend_from_slice(core::slice::from_raw_parts(
630 (*child).content,
631 len as usize,
632 ));
633 }
634 }
635 }
636 t if t == XML_ENTITY_REF_NODE as c_int => {
637 let name = (*node).name;
639 if !name.is_null() && !(*node).doc.is_null() {
640 let ent = crate::xml::tree::get_doc_entity((*node).doc, name);
641 if !ent.is_null() && !(*ent).content.is_null() {
642 let len = crate::abi::exports_xml2::xmlStrlen((*ent).content);
643 result.extend_from_slice(core::slice::from_raw_parts(
644 (*ent).content,
645 len as usize,
646 ));
647 }
648 }
649 }
650 t if t == XML_DOCUMENT_NODE as c_int || t == XML_HTML_DOCUMENT_NODE as c_int => {
651 let root = doc_get_root_element(node as *mut _xmlDoc);
652 if !root.is_null() {
653 let sub = node_get_content(root);
654 if !sub.is_null() {
655 let len = crate::abi::exports_xml2::xmlStrlen(sub);
656 result.extend_from_slice(core::slice::from_raw_parts(sub, len as usize));
657 allocator::xmlFreeImpl(sub as *mut c_void);
658 }
659 }
660 }
661 _ => {
662 let mut child = (*node).children;
667 while !child.is_null() {
668 let ctype = (*child).type_;
669 if ctype == XML_TEXT_NODE as c_int || ctype == XML_CDATA_SECTION_NODE as c_int {
670 if !(*child).content.is_null() {
671 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
672 result.extend_from_slice(core::slice::from_raw_parts(
673 (*child).content,
674 len as usize,
675 ));
676 }
677 } else if ctype == XML_ENTITY_REF_NODE as c_int
678 || ctype == XML_ELEMENT_NODE as c_int
679 {
680 let sub = node_get_content(child);
681 if !sub.is_null() {
682 let len = crate::abi::exports_xml2::xmlStrlen(sub);
683 result.extend_from_slice(core::slice::from_raw_parts(sub, len as usize));
684 allocator::xmlFreeImpl(sub as *mut c_void);
685 }
686 }
687 child = (*child).next;
688 }
689 }
690 }
691 let buf = allocator::xmlMallocImpl(result.len() + 1) as *mut xmlChar;
693 if buf.is_null() {
694 return ptr::null_mut();
695 }
696 if !result.is_empty() {
697 ptr::copy_nonoverlapping(result.as_ptr(), buf, result.len());
698 }
699 *buf.add(result.len()) = 0;
700 buf
701}
702
703pub unsafe fn new_node(ns: *mut _xmlNs, name: *const xmlChar) -> *mut _xmlNode {
722 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
723 if node.is_null() {
724 return ptr::null_mut();
725 }
726
727 unsafe {
728 (*node).type_ = XML_ELEMENT_NODE as c_int;
729 (*node).name = dup_xml_str(name);
730 (*node).ns = ns;
731 (*node).line = 0;
732 (*node).extra = 0;
733
734 if !ns.is_null() {
735 (*ns).context = node as *mut _xmlDoc;
736 }
737 }
738
739 crate::abi::data_globals::register_node_hook(node);
742
743 node
744}
745
746pub unsafe fn free_node(node: *mut _xmlNode) {
761 if node.is_null() {
762 return;
763 }
764
765 let n = unsafe { &mut *node };
766
767 if n.type_ == XML_DTD_NODE as c_int {
771 free_dtd(node as *mut _xmlDtd);
772 return;
773 } else if n.type_ == XML_NAMESPACE_DECL as c_int {
774 free_ns(node as *mut _xmlNs);
775 return;
776 } else if n.type_ == XML_ATTRIBUTE_NODE as c_int {
777 free_prop(node as *mut _xmlAttr);
778 return;
779 } else if n.type_ == XML_ELEMENT_DECL as c_int {
780 crate::xml::dtd::free_element(node as *mut _xmlElement);
781 return;
782 } else if n.type_ == XML_ATTRIBUTE_DECL as c_int {
783 crate::xml::dtd::free_attribute(node as *mut _xmlAttribute);
784 return;
785 } else if n.type_ == XML_ENTITY_DECL as c_int {
786 crate::xml::entities::free_entity(node as *mut _xmlEntity);
787 return;
788 }
789
790 crate::abi::data_globals::deregister_node_hook(node);
793
794 let is_element = n.type_ == XML_ELEMENT_NODE as c_int;
799 if is_element && !n.properties.is_null() {
800 free_prop_list(n.properties);
801 }
802
803 if is_element && !n.nsDef.is_null() {
804 free_ns_list(n.nsDef);
805 }
806
807 if !n.name.is_null() {
809 allocator::xmlFreeImpl(n.name as *mut c_void);
810 }
811
812 if !n.content.is_null() {
817 let node_type = n.type_;
818 if node_type == XML_TEXT_NODE as c_int
819 || node_type == XML_CDATA_SECTION_NODE as c_int
820 || node_type == XML_COMMENT_NODE as c_int
821 || node_type == XML_PI_NODE as c_int
822 {
823 let inline_addr = std::ptr::addr_of_mut!((*node).properties) as *const c_void;
824 if n.content as *const c_void != inline_addr {
825 allocator::xmlFreeImpl(n.content as *mut c_void);
826 }
827 }
828 }
829
830 allocator::xmlFreeImpl(node as *mut c_void);
831}
832
833pub unsafe fn free_node_list(node: *mut _xmlNode) {
852 let mut cur = node;
853 while !cur.is_null() {
854 let next = unsafe { (*cur).next };
855 let t = unsafe { (*cur).type_ };
856
857 if t == XML_DTD_NODE as c_int {
858 unsafe {
860 (*cur).prev = ptr::null_mut();
861 (*cur).next = ptr::null_mut();
862 }
863 cur = next;
864 continue;
865 }
866
867 if t != XML_ENTITY_REF_NODE as c_int && !unsafe { (*cur).children }.is_null() {
870 free_node_list(unsafe { (*cur).children });
871 }
872
873 free_node(cur);
874 cur = next;
875 }
876}
877
878unsafe fn free_prop_list(prop: *mut _xmlAttr) {
884 let mut cur = prop;
885 while !cur.is_null() {
886 let next = unsafe { (*cur).next };
887 free_prop(cur);
888 cur = next;
889 }
890}
891
892unsafe fn free_prop(prop: *mut _xmlAttr) {
898 if prop.is_null() {
899 return;
900 }
901
902 if !unsafe { (*prop).children }.is_null() {
904 free_node_list(unsafe { (*prop).children });
905 }
906
907 if !unsafe { (*prop).name }.is_null() {
909 allocator::xmlFreeImpl(unsafe { (*prop).name } as *mut c_void);
910 }
911
912 allocator::xmlFreeImpl(prop as *mut c_void);
913}
914
915unsafe fn free_ns_list(ns: *mut _xmlNs) {
921 let mut cur = ns;
922 while !cur.is_null() {
923 let next = unsafe { (*cur).next };
924 free_ns(cur);
925 cur = next;
926 }
927}
928
929unsafe fn free_ns(ns: *mut _xmlNs) {
935 if ns.is_null() {
936 return;
937 }
938
939 if !unsafe { (*ns).href }.is_null() {
941 allocator::xmlFreeImpl(unsafe { (*ns).href } as *mut c_void);
942 }
943 if !unsafe { (*ns).prefix }.is_null() {
944 allocator::xmlFreeImpl(unsafe { (*ns).prefix } as *mut c_void);
945 }
946
947 allocator::xmlFreeImpl(ns as *mut c_void);
948}
949
950pub unsafe fn copy_node(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
965 if node.is_null() {
966 return ptr::null_mut();
967 }
968
969 let n = unsafe { &*node };
970
971 let new_node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
972 if new_node.is_null() {
973 return ptr::null_mut();
974 }
975
976 unsafe {
977 (*new_node).type_ = n.type_;
978 (*new_node).name = dup_xml_str(n.name);
979 if n.type_ == XML_ELEMENT_NODE as c_int {
983 (*new_node).line = n.line;
984 }
985 (*new_node).extra = n.extra;
986 (*new_node).psvi = n.psvi;
987 (*new_node)._private = n._private;
988
989 (*new_node).ns = n.ns;
991
992 let is_element = n.type_ == XML_ELEMENT_NODE as c_int;
995 if is_element && !n.nsDef.is_null() {
996 (*new_node).nsDef = copy_ns_list(n.nsDef);
997 }
998
999 let node_type = n.type_;
1001 if (node_type == XML_TEXT_NODE as c_int
1002 || node_type == XML_CDATA_SECTION_NODE as c_int
1003 || node_type == XML_COMMENT_NODE as c_int
1004 || node_type == XML_PI_NODE as c_int)
1005 && !n.content.is_null()
1006 {
1007 (*new_node).content = dup_xml_str(n.content);
1008 }
1009
1010 if is_element && !n.properties.is_null() {
1012 (*new_node).properties = copy_prop_list(n.properties);
1013 let mut prop = (*new_node).properties;
1015 while !prop.is_null() {
1016 (*prop).parent = new_node;
1017 if !(*prop).children.is_null() {
1018 propagate_doc((*prop).children, (*new_node).doc);
1019 }
1020 prop = (*prop).next;
1021 }
1022 }
1023
1024 if recursive != 0 && !n.children.is_null() {
1027 (*new_node).children = copy_node_list(n.children, recursive);
1028 if !(*new_node).children.is_null() {
1029 let mut child = (*new_node).children;
1030 let mut last_child = child;
1031 while !child.is_null() {
1032 (*child).parent = new_node;
1033 (*child).doc = (*new_node).doc;
1034 propagate_doc(child, (*new_node).doc);
1035 if (*child).next.is_null() {
1036 last_child = child;
1037 }
1038 child = (*child).next;
1039 }
1040 (*new_node).last = last_child;
1041 }
1042 }
1043 }
1044
1045 new_node
1046}
1047
1048unsafe fn copy_node_list(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
1060 if node.is_null() {
1061 return ptr::null_mut();
1062 }
1063
1064 let n = unsafe { &*node };
1065 let new_node = copy_node(node, recursive);
1066 if new_node.is_null() {
1067 return ptr::null_mut();
1068 }
1069
1070 let mut prev = new_node;
1071 let mut cur = n.next;
1072
1073 while !cur.is_null() {
1074 let new_cur = copy_node(cur, recursive);
1075 if new_cur.is_null() {
1076 break;
1077 }
1078 unsafe {
1079 (*prev).next = new_cur;
1080 (*new_cur).prev = prev;
1081 }
1082 prev = new_cur;
1083 cur = unsafe { (*cur).next };
1084 }
1085
1086 new_node
1087}
1088
1089unsafe fn copy_ns_list(ns: *const _xmlNs) -> *mut _xmlNs {
1099 if ns.is_null() {
1100 return ptr::null_mut();
1101 }
1102
1103 let n = unsafe { &*ns };
1104 let new_ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
1105 if new_ns.is_null() {
1106 return ptr::null_mut();
1107 }
1108
1109 unsafe {
1110 (*new_ns).type_ = n.type_;
1111 (*new_ns).href = dup_xml_str(n.href);
1112 (*new_ns).prefix = dup_xml_str(n.prefix);
1113 (*new_ns)._private = n._private;
1114 }
1115
1116 let mut prev = new_ns;
1117 let mut cur = n.next;
1118
1119 while !cur.is_null() {
1120 let c = unsafe { &*cur };
1121 let new_cur = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
1122 if new_cur.is_null() {
1123 break;
1124 }
1125 unsafe {
1126 (*new_cur).type_ = c.type_;
1127 (*new_cur).href = dup_xml_str(c.href);
1128 (*new_cur).prefix = dup_xml_str(c.prefix);
1129 (*new_cur)._private = c._private;
1130 (*prev).next = new_cur;
1131 }
1132 prev = new_cur;
1133 cur = c.next;
1134 }
1135
1136 new_ns
1137}
1138
1139unsafe fn copy_prop_list(prop: *const _xmlAttr) -> *mut _xmlAttr {
1150 if prop.is_null() {
1151 return ptr::null_mut();
1152 }
1153
1154 let p = unsafe { &*prop };
1155 let new_prop = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
1156 if new_prop.is_null() {
1157 return ptr::null_mut();
1158 }
1159
1160 unsafe {
1161 (*new_prop).type_ = p.type_;
1162 (*new_prop).name = dup_xml_str(p.name);
1163 (*new_prop).ns = p.ns;
1164 (*new_prop).atype = p.atype;
1165
1166 if !p.children.is_null() {
1168 (*new_prop).children = copy_node_list(p.children, 1);
1169 if !(*new_prop).children.is_null() {
1170 (*(*new_prop).children).parent = new_prop as *mut _xmlNode;
1171 }
1172 }
1173 }
1174
1175 let mut prev = new_prop;
1176 let mut cur = p.next;
1177
1178 while !cur.is_null() {
1179 let c = unsafe { &*cur };
1180 let new_cur = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
1181 if new_cur.is_null() {
1182 break;
1183 }
1184 unsafe {
1185 (*new_cur).type_ = c.type_;
1186 (*new_cur).name = dup_xml_str(c.name);
1187 (*new_cur).ns = c.ns;
1188 (*new_cur).atype = c.atype;
1189
1190 if !c.children.is_null() {
1191 (*new_cur).children = copy_node_list(c.children, 1);
1192 if !(*new_cur).children.is_null() {
1193 (*(*new_cur).children).parent = new_cur as *mut _xmlNode;
1194 }
1195 }
1196
1197 (*prev).next = new_cur;
1198 }
1199 prev = new_cur;
1200 cur = c.next;
1201 }
1202
1203 new_prop
1204}
1205
1206unsafe fn propagate_doc(node: *mut _xmlNode, doc: *mut _xmlDoc) {
1217 let mut cur = node;
1218 while !cur.is_null() {
1219 unsafe {
1220 (*cur).doc = doc;
1221
1222 if (*cur).type_ == XML_ELEMENT_NODE as c_int {
1226 let mut prop = (*cur).properties;
1227 while !prop.is_null() {
1228 (*prop).doc = doc;
1229 if !(*prop).children.is_null() {
1230 propagate_doc((*prop).children, doc);
1231 }
1232 prop = (*prop).next;
1233 }
1234 }
1235
1236 if !(*cur).children.is_null() {
1238 propagate_doc((*cur).children, doc);
1239 }
1240 }
1241 cur = unsafe { (*cur).next };
1242 }
1243}
1244
1245pub unsafe fn unlink_node(node: *mut _xmlNode) {
1261 if node.is_null() {
1262 return;
1263 }
1264
1265 let n = unsafe { &mut *node };
1266
1267 let prev = n.prev;
1269 let next = n.next;
1270
1271 if !prev.is_null() {
1272 unsafe { (*prev).next = next };
1273 }
1274 if !next.is_null() {
1275 unsafe { (*next).prev = prev };
1276 }
1277
1278 let parent = n.parent;
1280 if !parent.is_null() {
1281 if unsafe { (*parent).children } == node {
1282 unsafe { (*parent).children = next };
1283 }
1284 if unsafe { (*parent).last } == node {
1285 unsafe { (*parent).last = prev };
1286 }
1287 }
1288
1289 let doc = n.doc;
1291 if !doc.is_null() && !parent.is_null() {
1292 }
1294 if !doc.is_null() && parent.is_null() {
1295 if unsafe { (*doc).children } == node {
1297 unsafe { (*doc).children = next };
1298 }
1299 if unsafe { (*doc).last } == node {
1300 unsafe { (*doc).last = prev };
1301 }
1302 }
1303
1304 n.parent = ptr::null_mut();
1306 n.prev = ptr::null_mut();
1307 n.next = ptr::null_mut();
1308}
1309
1310pub unsafe fn add_child(parent: *mut _xmlNode, cur: *mut _xmlNode) -> *mut _xmlNode {
1326 if parent.is_null() || cur.is_null() {
1327 return ptr::null_mut();
1328 }
1329
1330 let p = unsafe { &mut *parent };
1331 let c = unsafe { &mut *cur };
1332
1333 if !c.parent.is_null() || !c.prev.is_null() || !c.next.is_null() {
1335 unlink_node(cur);
1336 }
1337
1338 c.parent = parent;
1340
1341 if p.children.is_null() {
1342 p.children = cur;
1344 p.last = cur;
1345 c.prev = ptr::null_mut();
1346 c.next = ptr::null_mut();
1347 } else {
1348 c.prev = p.last;
1350 c.next = ptr::null_mut();
1351 if !p.last.is_null() {
1352 unsafe { (*p.last).next = cur };
1353 }
1354 p.last = cur;
1355 }
1356
1357 let doc = if !p.doc.is_null() {
1359 p.doc
1360 } else {
1361 ptr::null_mut()
1362 };
1363 if !doc.is_null() && c.doc != doc {
1364 propagate_doc(cur, doc);
1365 }
1366
1367 cur
1368}
1369
1370pub unsafe fn add_sibling(cur: *mut _xmlNode, elem: *mut _xmlNode) -> *mut _xmlNode {
1386 if cur.is_null() || elem.is_null() {
1387 return ptr::null_mut();
1388 }
1389
1390 let c = unsafe { &mut *cur };
1391
1392 let e = unsafe { &mut *elem };
1394 if !e.parent.is_null() || !e.prev.is_null() || !e.next.is_null() {
1395 unlink_node(elem);
1396 }
1397
1398 e.parent = c.parent;
1400
1401 e.prev = cur;
1403 e.next = c.next;
1404
1405 if !c.next.is_null() {
1406 unsafe { (*c.next).prev = elem };
1407 }
1408 c.next = elem;
1409
1410 let parent = c.parent;
1412 if !parent.is_null() && unsafe { (*parent).last } == cur {
1413 unsafe { (*parent).last = elem };
1414 }
1415
1416 if !c.doc.is_null() && e.doc != c.doc {
1418 propagate_doc(elem, c.doc);
1419 }
1420
1421 elem
1422}
1423
1424pub unsafe fn add_sibling_before(cur: *mut _xmlNode, elem: *mut _xmlNode) -> *mut _xmlNode {
1440 if cur.is_null() || elem.is_null() {
1441 return ptr::null_mut();
1442 }
1443
1444 let c = unsafe { &mut *cur };
1445
1446 let e = unsafe { &mut *elem };
1448 if !e.parent.is_null() || !e.prev.is_null() || !e.next.is_null() {
1449 unlink_node(elem);
1450 }
1451
1452 e.parent = c.parent;
1454
1455 e.prev = c.prev;
1457 e.next = cur;
1458
1459 if !c.prev.is_null() {
1460 unsafe { (*c.prev).next = elem };
1461 }
1462 c.prev = elem;
1463
1464 let parent = c.parent;
1466 if !parent.is_null() && unsafe { (*parent).children } == cur {
1467 unsafe { (*parent).children = elem };
1468 }
1469
1470 let doc = c.doc;
1472 if !doc.is_null() && parent.is_null() && unsafe { (*doc).children } == cur {
1473 unsafe { (*doc).children = elem };
1474 }
1475
1476 if !c.doc.is_null() && e.doc != c.doc {
1478 propagate_doc(elem, c.doc);
1479 }
1480
1481 elem
1482}
1483
1484pub unsafe fn new_child(
1499 parent: *mut _xmlNode,
1500 ns: *mut _xmlNs,
1501 name: *const xmlChar,
1502) -> *mut _xmlNode {
1503 let node = new_node(ns, name);
1504 if node.is_null() {
1505 return ptr::null_mut();
1506 }
1507
1508 if !parent.is_null() {
1509 add_child(parent, node);
1510 }
1511
1512 node
1513}
1514
1515pub unsafe fn new_text(content: *const xmlChar) -> *mut _xmlNode {
1534 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1535 if node.is_null() {
1536 return ptr::null_mut();
1537 }
1538
1539 unsafe {
1540 (*node).type_ = XML_TEXT_NODE as c_int;
1541 (*node).name = dup_xml_str(b"text\0" as *const u8 as *const xmlChar);
1542 (*node).content = if content.is_null() {
1543 let empty = allocator::xmlMallocImpl(1) as *mut xmlChar;
1544 if !empty.is_null() {
1545 *empty = 0;
1546 }
1547 empty
1548 } else {
1549 dup_xml_str(content)
1550 };
1551 (*node).line = 0;
1552 }
1553
1554 crate::abi::data_globals::register_node_hook(node);
1557
1558 node
1559}
1560
1561pub unsafe fn new_comment(content: *const xmlChar) -> *mut _xmlNode {
1575 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1576 if node.is_null() {
1577 return ptr::null_mut();
1578 }
1579
1580 unsafe {
1581 (*node).type_ = XML_COMMENT_NODE as c_int;
1582 (*node).name = dup_xml_str(b"comment\0" as *const u8 as *const xmlChar);
1583 (*node).content = dup_xml_str(content);
1584 (*node).line = 0;
1585 }
1586
1587 crate::abi::data_globals::register_node_hook(node);
1590
1591 node
1592}
1593
1594pub unsafe fn new_pi(name: *const xmlChar, content: *const xmlChar) -> *mut _xmlNode {
1609 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1610 if node.is_null() {
1611 return ptr::null_mut();
1612 }
1613
1614 unsafe {
1615 (*node).type_ = XML_PI_NODE as c_int;
1616 (*node).name = dup_xml_str(name);
1617 (*node).content = dup_xml_str(content);
1618 (*node).line = 0;
1619 }
1620
1621 crate::abi::data_globals::register_node_hook(node);
1624
1625 node
1626}
1627
1628pub unsafe fn new_cdata_block(
1644 doc: *mut _xmlDoc,
1645 content: *const xmlChar,
1646 len: c_int,
1647) -> *mut _xmlNode {
1648 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1649 if node.is_null() {
1650 return ptr::null_mut();
1651 }
1652
1653 unsafe {
1654 (*node).type_ = XML_CDATA_SECTION_NODE as c_int;
1655 (*node).doc = doc;
1658
1659 if !content.is_null() && len > 0 {
1660 (*node).content = allocator::xmlMallocImpl((len + 1) as usize) as *mut xmlChar;
1661 if !(*node).content.is_null() {
1662 ptr::copy_nonoverlapping(content, (*node).content, len as usize);
1663 *((*node).content.add(len as usize)) = 0;
1664 }
1665 } else {
1666 let empty = allocator::xmlMallocImpl(1) as *mut xmlChar;
1667 if !empty.is_null() {
1668 *empty = 0;
1669 }
1670 (*node).content = empty;
1671 }
1672
1673 (*node).line = 0;
1674 }
1675
1676 node
1677}
1678
1679pub unsafe fn new_ns(
1703 node: *mut _xmlNode,
1704 href: *const xmlChar,
1705 prefix: *const xmlChar,
1706) -> *mut _xmlNs {
1707 let ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
1708 if ns.is_null() {
1709 return ptr::null_mut();
1710 }
1711
1712 unsafe {
1713 (*ns).type_ = XML_LOCAL_NAMESPACE as c_int;
1714 (*ns).href = dup_xml_str(href);
1715 (*ns).prefix = dup_xml_str(prefix);
1716 (*ns).context = node as *mut _xmlDoc;
1717
1718 if !node.is_null() {
1720 let n = &mut *node;
1721 if n.nsDef.is_null() {
1722 n.nsDef = ns;
1723 } else {
1724 let mut last = n.nsDef;
1726 while !(*last).next.is_null() {
1727 last = (*last).next;
1728 }
1729 (*last).next = ns;
1730 }
1731 }
1732 }
1733
1734 ns
1735}
1736
1737pub unsafe fn set_ns(node: *mut _xmlNode, ns: *mut _xmlNs) {
1750 if node.is_null() {
1751 return;
1752 }
1753 unsafe {
1754 (*node).ns = ns;
1755 }
1756}
1757
1758pub unsafe fn get_ns_list(_doc: *mut _xmlDoc, node: *mut _xmlNode) -> *mut *mut _xmlNs {
1774 if node.is_null() {
1778 return ptr::null_mut();
1779 }
1780
1781 let mut ns_ptrs: Vec<*mut _xmlNs> = Vec::new();
1783 let mut cur = node;
1784
1785 while !cur.is_null() {
1786 let n = unsafe { &*cur };
1787 let mut ns_def = n.nsDef;
1788 while !ns_def.is_null() {
1789 let ns = unsafe { &*ns_def };
1791 let mut found = false;
1792 for &existing in &ns_ptrs {
1793 if existing == ns_def {
1794 found = true;
1795 break;
1796 }
1797 let e = unsafe { &*existing };
1798 if !ns.href.is_null() && !e.href.is_null() {
1799 let href_match =
1800 unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, e.href) != 0 };
1801 if href_match {
1802 if ns.prefix.is_null() && e.prefix.is_null() {
1803 found = true;
1804 break;
1805 }
1806 if !ns.prefix.is_null() && !e.prefix.is_null() {
1807 let prefix_match = unsafe {
1808 crate::abi::exports_xml2::xmlStrEqual(ns.prefix, e.prefix) != 0
1809 };
1810 if prefix_match {
1811 found = true;
1812 break;
1813 }
1814 }
1815 }
1816 }
1817 }
1818 if !found {
1819 ns_ptrs.push(ns_def);
1820 }
1821 ns_def = unsafe { (*ns_def).next };
1822 }
1823 cur = n.parent;
1824 }
1825
1826 if ns_ptrs.is_empty() {
1827 return ptr::null_mut();
1828 }
1829
1830 let arr = allocator::xmlMallocImpl((ns_ptrs.len() + 1) * size_of::<*mut _xmlNs>())
1832 as *mut *mut _xmlNs;
1833 if arr.is_null() {
1834 return ptr::null_mut();
1835 }
1836
1837 for (i, ns) in ns_ptrs.iter().enumerate() {
1838 unsafe { *arr.add(i) = *ns };
1839 }
1840 unsafe { *arr.add(ns_ptrs.len()) = ptr::null_mut() };
1841
1842 arr
1843}
1844
1845pub unsafe fn search_ns(
1862 _doc: *mut _xmlDoc,
1863 node: *mut _xmlNode,
1864 name_space: *const xmlChar,
1865) -> *mut _xmlNs {
1866 if node.is_null() {
1867 return ptr::null_mut();
1868 }
1869
1870 let mut cur = node;
1871 while !cur.is_null() {
1872 let n = unsafe { &*cur };
1873 let mut ns_def = n.nsDef;
1874 while !ns_def.is_null() {
1875 let ns = unsafe { &*ns_def };
1876 let match_prefix = if name_space.is_null() {
1877 ns.prefix.is_null()
1879 } else {
1880 !ns.prefix.is_null()
1881 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.prefix, name_space) != 0 }
1882 };
1883 if match_prefix {
1884 return ns_def;
1885 }
1886 ns_def = unsafe { (*ns_def).next };
1887 }
1888 cur = n.parent;
1889 }
1890
1891 ptr::null_mut()
1892}
1893
1894pub unsafe fn search_ns_by_href(
1910 _doc: *mut _xmlDoc,
1911 node: *mut _xmlNode,
1912 href: *const xmlChar,
1913) -> *mut _xmlNs {
1914 if node.is_null() || href.is_null() {
1915 return ptr::null_mut();
1916 }
1917
1918 let mut cur = node;
1919 while !cur.is_null() {
1920 let n = unsafe { &*cur };
1921 let mut ns_def = n.nsDef;
1922 while !ns_def.is_null() {
1923 let ns = unsafe { &*ns_def };
1924 if !ns.href.is_null()
1925 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, href) != 0 }
1926 {
1927 return ns_def;
1928 }
1929 ns_def = unsafe { (*ns_def).next };
1930 }
1931 cur = n.parent;
1932 }
1933
1934 ptr::null_mut()
1935}
1936
1937pub unsafe fn set_prop(
1961 node: *mut _xmlNode,
1962 name: *const xmlChar,
1963 value: *const xmlChar,
1964) -> *mut _xmlAttr {
1965 if node.is_null() || name.is_null() {
1966 return ptr::null_mut();
1967 }
1968
1969 let n = unsafe { &mut *node };
1970
1971 let mut existing = n.properties;
1973 while !existing.is_null() {
1974 let attr = unsafe { &*existing };
1975 if !attr.name.is_null()
1976 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1977 {
1978 if !attr.children.is_null() {
1981 free_node_list(attr.children);
1982 let attr_mut = existing;
1984 unsafe { (*attr_mut).children = ptr::null_mut() };
1985 unsafe { (*attr_mut).last = ptr::null_mut() };
1986 }
1987 if !value.is_null() {
1989 let text = new_text(value);
1990 if !text.is_null() {
1991 let attr_mut = existing;
1992 unsafe {
1993 (*attr_mut).children = text;
1994 (*attr_mut).last = text;
1995 (*text).parent = existing as *mut _xmlNode;
1996 (*text).doc = n.doc;
1997 }
1998 }
1999 }
2000 return existing;
2001 }
2002 existing = unsafe { (*existing).next };
2003 }
2004
2005 let attr = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
2007 if attr.is_null() {
2008 return ptr::null_mut();
2009 }
2010
2011 unsafe {
2012 (*attr).type_ = XML_ATTRIBUTE_NODE as c_int;
2013 (*attr).name = dup_xml_str(name);
2014 (*attr).parent = node;
2015 (*attr).doc = n.doc;
2016 if !value.is_null() {
2021 let text = new_text(value);
2022 if !text.is_null() {
2023 (*attr).children = text;
2024 (*attr).last = text;
2025 (*text).parent = attr as *mut _xmlNode;
2026 (*text).doc = n.doc;
2027 }
2028 }
2029
2030 if n.properties.is_null() {
2032 n.properties = attr;
2033 } else {
2034 let mut last = n.properties;
2035 while !(*last).next.is_null() {
2036 last = (*last).next;
2037 }
2038 (*last).next = attr;
2039 (*attr).prev = last;
2040 }
2041 }
2042
2043 attr
2044}
2045
2046pub unsafe fn get_prop(node: *mut _xmlNode, name: *const xmlChar) -> *mut xmlChar {
2062 if node.is_null() || name.is_null() {
2063 return ptr::null_mut();
2064 }
2065
2066 let n = unsafe { &*node };
2067 let mut cur = n.properties;
2068
2069 while !cur.is_null() {
2070 let attr = unsafe { &*cur };
2071 if !attr.name.is_null()
2072 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
2073 {
2074 if !attr.children.is_null() {
2076 let text = unsafe { &*attr.children };
2077 if text.type_ == XML_TEXT_NODE as c_int && !text.content.is_null() {
2078 return dup_xml_str(text.content);
2079 }
2080 }
2081 return dup_xml_str(b"\0" as *const u8 as *const xmlChar);
2082 }
2083 cur = unsafe { (*cur).next };
2084 }
2085
2086 ptr::null_mut()
2087}
2088
2089pub unsafe fn get_ns_prop(
2105 node: *mut _xmlNode,
2106 name: *const xmlChar,
2107 _name_space: *const xmlChar,
2108) -> *mut xmlChar {
2109 get_prop(node, name)
2112}
2113
2114pub unsafe fn set_ns_prop(
2129 node: *mut _xmlNode,
2130 _ns: *mut _xmlNs,
2131 name: *const xmlChar,
2132 value: *const xmlChar,
2133) -> *mut _xmlAttr {
2134 set_prop(node, name, value)
2136}
2137
2138pub unsafe fn remove_prop(attr: *mut _xmlAttr) -> c_int {
2153 if attr.is_null() {
2154 return -1;
2155 }
2156
2157 let a = unsafe { &mut *attr };
2158
2159 let parent = a.parent;
2161 if !parent.is_null() {
2162 let p = unsafe { &mut *parent };
2163 if p.properties == attr {
2164 p.properties = a.next;
2165 }
2166 }
2167
2168 if !a.prev.is_null() {
2170 unsafe { (*a.prev).next = a.next };
2171 }
2172 if !a.next.is_null() {
2173 unsafe { (*a.next).prev = a.prev };
2174 }
2175
2176 if !a.children.is_null() {
2178 free_node_list(a.children);
2179 }
2180
2181 if !a.name.is_null() {
2183 allocator::xmlFreeImpl(a.name as *mut c_void);
2184 }
2185
2186 allocator::xmlFreeImpl(attr as *mut c_void);
2187 0
2188}
2189
2190pub unsafe fn has_prop(node: *mut _xmlNode, name: *const xmlChar) -> *mut _xmlAttr {
2198 if node.is_null() || name.is_null() {
2199 return ptr::null_mut();
2200 }
2201 let mut cur = unsafe { (*node).properties };
2202 while !cur.is_null() {
2203 let attr = unsafe { &*cur };
2204 if !attr.name.is_null()
2205 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
2206 && attr.ns.is_null()
2207 {
2208 return cur;
2209 }
2210 cur = unsafe { (*cur).next };
2211 }
2212 ptr::null_mut()
2213}
2214
2215pub unsafe fn has_ns_prop(
2225 node: *mut _xmlNode,
2226 name: *const xmlChar,
2227 name_space: *const xmlChar,
2228) -> *mut _xmlAttr {
2229 if node.is_null() || name.is_null() {
2230 return ptr::null_mut();
2231 }
2232 let mut cur = unsafe { (*node).properties };
2233 while !cur.is_null() {
2234 let attr = unsafe { &*cur };
2235 if !attr.name.is_null()
2236 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
2237 {
2238 if name_space.is_null() {
2239 if attr.ns.is_null() {
2240 return cur;
2241 }
2242 } else if !attr.ns.is_null()
2243 && !(*attr.ns).href.is_null()
2244 && unsafe {
2245 crate::abi::exports_xml2::xmlStrEqual((*attr.ns).href, name_space) != 0
2246 }
2247 {
2248 return cur;
2249 }
2250 }
2251 cur = unsafe { (*cur).next };
2252 }
2253 ptr::null_mut()
2254}
2255
2256pub unsafe fn unset_prop(node: *mut _xmlNode, name: *const xmlChar) -> c_int {
2265 let attr = unsafe { has_prop(node, name) };
2266 if attr.is_null() {
2267 return -1;
2268 }
2269 unsafe { remove_prop(attr) }
2270}
2271
2272pub unsafe fn unset_ns_prop(
2280 node: *mut _xmlNode,
2281 name: *const xmlChar,
2282 name_space: *const xmlChar,
2283) -> c_int {
2284 let attr = unsafe { has_ns_prop(node, name, name_space) };
2285 if attr.is_null() {
2286 return -1;
2287 }
2288 unsafe { remove_prop(attr) }
2289}
2290
2291pub unsafe fn first_element_child(node: *mut _xmlNode) -> *mut _xmlNode {
2298 if node.is_null() {
2299 return ptr::null_mut();
2300 }
2301 let mut cur = unsafe { (*node).children };
2302 while !cur.is_null() {
2303 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2304 return cur;
2305 }
2306 cur = unsafe { (*cur).next };
2307 }
2308 ptr::null_mut()
2309}
2310
2311pub unsafe fn last_element_child(node: *mut _xmlNode) -> *mut _xmlNode {
2318 if node.is_null() {
2319 return ptr::null_mut();
2320 }
2321 let mut cur = unsafe { (*node).last };
2322 while !cur.is_null() {
2323 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2324 return cur;
2325 }
2326 cur = unsafe { (*cur).prev };
2327 }
2328 ptr::null_mut()
2329}
2330
2331pub unsafe fn next_element_sibling(node: *mut _xmlNode) -> *mut _xmlNode {
2338 if node.is_null() {
2339 return ptr::null_mut();
2340 }
2341 let mut cur = unsafe { (*node).next };
2342 while !cur.is_null() {
2343 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2344 return cur;
2345 }
2346 cur = unsafe { (*cur).next };
2347 }
2348 ptr::null_mut()
2349}
2350
2351pub unsafe fn previous_element_sibling(node: *mut _xmlNode) -> *mut _xmlNode {
2358 if node.is_null() {
2359 return ptr::null_mut();
2360 }
2361 let mut cur = unsafe { (*node).prev };
2362 while !cur.is_null() {
2363 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2364 return cur;
2365 }
2366 cur = unsafe { (*cur).prev };
2367 }
2368 ptr::null_mut()
2369}
2370
2371pub unsafe fn child_element_count(node: *mut _xmlNode) -> c_ulong {
2378 if node.is_null() {
2379 return 0;
2380 }
2381 let mut cur = unsafe { (*node).children };
2382 let mut count: c_ulong = 0;
2383 while !cur.is_null() {
2384 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2385 count += 1;
2386 }
2387 cur = unsafe { (*cur).next };
2388 }
2389 count
2390}
2391
2392pub unsafe fn text_concat(node: *mut _xmlNode, str: *const xmlChar, num: c_int) -> c_int {
2401 if node.is_null() || str.is_null() || num <= 0 {
2402 return -1;
2403 }
2404 let cur = unsafe { &mut *node };
2405 if cur.content.is_null() {
2406 let p = unsafe { allocator::xmlMallocImpl(num as usize + 1) as *mut xmlChar };
2407 if p.is_null() {
2408 return -1;
2409 }
2410 unsafe {
2411 ptr::copy_nonoverlapping(str, p, num as usize);
2412 *p.add(num as usize) = 0;
2413 }
2414 cur.content = p;
2415 return 0;
2416 }
2417 let old_len = unsafe { crate::xml::string::xml_strlen(cur.content) };
2418 let p = unsafe {
2419 allocator::xmlReallocImpl(cur.content as *mut c_void, old_len + num as usize + 1)
2420 as *mut xmlChar
2421 };
2422 if p.is_null() {
2423 return -1;
2424 }
2425 unsafe {
2426 ptr::copy_nonoverlapping(str, p.add(old_len), num as usize);
2427 *p.add(old_len + num as usize) = 0;
2428 }
2429 cur.content = p;
2430 0
2431}
2432
2433pub unsafe fn text_merge(text: *mut _xmlNode, ntext: *mut _xmlNode) -> *mut _xmlNode {
2441 if text.is_null() || ntext.is_null() {
2442 return ptr::null_mut();
2443 }
2444 if unsafe { (*ntext).content.is_null() } {
2445 unsafe { free_node(ntext) };
2446 return text;
2447 }
2448 let num = unsafe { crate::xml::string::xml_strlen((*ntext).content) };
2449 if unsafe { text_concat(text, (*ntext).content, num as c_int) } != 0 {
2450 return ptr::null_mut();
2451 }
2452 unsafe { free_node(ntext) };
2453 text
2454}
2455
2456pub const fn get_int_subset(doc: *const _xmlDoc) -> *mut _xmlDtd {
2468 if doc.is_null() {
2469 return ptr::null_mut();
2470 }
2471 let d = unsafe { &*doc };
2472 d.intSubset
2473}
2474
2475pub unsafe fn new_dtd(
2492 doc: *mut _xmlDoc,
2493 name: *const xmlChar,
2494 ExternalID: *const xmlChar,
2495 SystemID: *const xmlChar,
2496) -> *mut _xmlDtd {
2497 let dtd = allocator::xmlMallocZero(size_of::<_xmlDtd>() as usize) as *mut _xmlDtd;
2498 if dtd.is_null() {
2499 return ptr::null_mut();
2500 }
2501
2502 unsafe {
2503 (*dtd).type_ = XML_DTD_NODE as c_int;
2504 (*dtd).name = dup_xml_str(name);
2505 (*dtd).ExternalID = dup_xml_str(ExternalID);
2506 (*dtd).SystemID = dup_xml_str(SystemID);
2507 (*dtd).parent = doc;
2508 (*dtd).doc = doc;
2509
2510 if !doc.is_null() && (*doc).intSubset.is_null() {
2516 (*doc).intSubset = dtd;
2517 }
2518 }
2519
2520 dtd
2521}
2522
2523unsafe fn free_dtd(dtd: *mut _xmlDtd) {
2529 if dtd.is_null() {
2530 return;
2531 }
2532
2533 let _d = unsafe { &mut *dtd };
2534 let d = &mut *dtd;
2535
2536 if !d.children.is_null() {
2543 let mut c = d.children;
2544 while !c.is_null() {
2545 let next = (*c).next;
2546 let t = (*c).type_;
2547 if t != XML_ELEMENT_DECL as c_int
2548 && t != XML_ATTRIBUTE_DECL as c_int
2549 && t != XML_ENTITY_DECL as c_int
2550 {
2551 unlink_node_internal(c, ptr::null_mut());
2552 free_node(c);
2553 }
2554 c = next;
2555 }
2556 }
2557
2558 if !d.name.is_null() {
2560 allocator::xmlFreeImpl(d.name as *mut c_void);
2561 }
2562 if !d.ExternalID.is_null() {
2563 allocator::xmlFreeImpl(d.ExternalID as *mut c_void);
2564 }
2565 if !d.SystemID.is_null() {
2566 allocator::xmlFreeImpl(d.SystemID as *mut c_void);
2567 }
2568
2569 unsafe extern "C" fn free_notation_wrapper(payload: *mut c_void, _name: *mut u8) {
2579 crate::xml::dtd::free_notation(payload as *mut _xmlNotation);
2580 }
2581 unsafe extern "C" fn free_element_wrapper(payload: *mut c_void, _name: *mut u8) {
2590 crate::xml::dtd::free_element(payload as *mut _xmlElement);
2591 }
2592 unsafe extern "C" fn free_attribute_wrapper(payload: *mut c_void, _name: *mut u8) {
2601 crate::xml::dtd::free_attribute(payload as *mut _xmlAttribute);
2602 }
2603 unsafe extern "C" fn free_entity_wrapper(payload: *mut c_void, _name: *mut u8) {
2612 crate::xml::entities::free_entity(payload as *mut _xmlEntity);
2613 }
2614
2615 if !d.notations.is_null() {
2616 crate::xml::hash::hash_free(
2617 d.notations as *mut crate::xml::hash::HashTable,
2618 Some(free_notation_wrapper),
2619 );
2620 d.notations = ptr::null_mut();
2621 }
2622 if !d.elements.is_null() {
2623 crate::xml::hash::hash_free(
2624 d.elements as *mut crate::xml::hash::HashTable,
2625 Some(free_element_wrapper),
2626 );
2627 d.elements = ptr::null_mut();
2628 }
2629 if !d.attributes.is_null() {
2630 crate::xml::hash::hash_free(
2631 d.attributes as *mut crate::xml::hash::HashTable,
2632 Some(free_attribute_wrapper),
2633 );
2634 d.attributes = ptr::null_mut();
2635 }
2636 if !d.entities.is_null() {
2637 crate::xml::hash::hash_free(
2638 d.entities as *mut crate::xml::hash::HashTable,
2639 Some(free_entity_wrapper),
2640 );
2641 d.entities = ptr::null_mut();
2642 }
2643 if !d.pentities.is_null() {
2644 crate::xml::hash::hash_free(
2645 d.pentities as *mut crate::xml::hash::HashTable,
2646 Some(free_entity_wrapper),
2647 );
2648 d.pentities = ptr::null_mut();
2649 }
2650
2651 allocator::xmlFreeImpl(dtd as *mut c_void);
2652}
2653
2654pub unsafe fn new_entity(
2674 _doc: *mut _xmlDoc,
2675 name: *const xmlChar,
2676 etype: c_int,
2677 ExternalID: *const xmlChar,
2678 SystemID: *const xmlChar,
2679 content: *const xmlChar,
2680) -> *mut _xmlEntity {
2681 let entity = allocator::xmlMallocZero(size_of::<_xmlEntity>() as usize) as *mut _xmlEntity;
2682 if entity.is_null() {
2683 return ptr::null_mut();
2684 }
2685
2686 unsafe {
2687 (*entity).type_ = XML_ENTITY_DECL as c_int;
2688 (*entity).name = dup_xml_str(name);
2689 (*entity).etype = etype;
2690 (*entity).ExternalID = dup_xml_str(ExternalID);
2691 (*entity).SystemID = dup_xml_str(SystemID);
2692 (*entity).content = dup_xml_str(content);
2693 (*entity).length = if content.is_null() {
2694 0
2695 } else {
2696 crate::abi::exports_xml2::xmlStrlen(content)
2697 };
2698 (*entity).flags = 0;
2699 (*entity).expandedSize = 0;
2700 }
2701
2702 entity
2703}
2704
2705pub unsafe fn get_doc_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2720 crate::xml::entities::get_entity(doc as *mut _xmlDoc, name)
2721}
2722
2723pub unsafe fn add_doc_entity(
2731 doc: *mut _xmlDoc,
2732 name: *const xmlChar,
2733 etype: c_int,
2734 ExternalID: *const xmlChar,
2735 SystemID: *const xmlChar,
2736 content: *const xmlChar,
2737) -> *mut _xmlEntity {
2738 if doc.is_null() || name.is_null() {
2739 return ptr::null_mut();
2740 }
2741 unsafe {
2742 let mut dtd = (*doc).intSubset;
2743 if dtd.is_null() {
2744 dtd = new_dtd(
2745 doc,
2746 c"internal".as_ptr() as *const xmlChar,
2747 ptr::null(),
2748 ptr::null(),
2749 );
2750 if dtd.is_null() {
2751 return ptr::null_mut();
2752 }
2753 }
2754 crate::xml::entities::add_entity(dtd, name, etype, ExternalID, SystemID, content)
2755 }
2756}
2757
2758pub unsafe fn add_dtd_entity(
2766 doc: *mut _xmlDoc,
2767 name: *const xmlChar,
2768 etype: c_int,
2769 ExternalID: *const xmlChar,
2770 SystemID: *const xmlChar,
2771 content: *const xmlChar,
2772) -> *mut _xmlEntity {
2773 if doc.is_null() || name.is_null() {
2774 return ptr::null_mut();
2775 }
2776 unsafe {
2777 let mut dtd = (*doc).extSubset;
2778 if dtd.is_null() {
2779 dtd = new_dtd(
2780 doc,
2781 c"internal".as_ptr() as *const xmlChar,
2782 ptr::null(),
2783 ptr::null(),
2784 );
2785 if dtd.is_null() {
2786 return ptr::null_mut();
2787 }
2788 (*doc).extSubset = dtd;
2789 }
2790 crate::xml::entities::add_entity(dtd, name, etype, ExternalID, SystemID, content)
2791 }
2792}
2793
2794pub unsafe fn get_dtd_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2802 if doc.is_null() || name.is_null() {
2803 return ptr::null_mut();
2804 }
2805 unsafe {
2806 if !(*doc).intSubset.is_null() {
2807 let e = crate::xml::entities::get_entity_from_dtd((*doc).intSubset, name);
2808 if !e.is_null() {
2809 return e;
2810 }
2811 }
2812 if !(*doc).extSubset.is_null() {
2813 return crate::xml::entities::get_entity_from_dtd((*doc).extSubset, name);
2814 }
2815 ptr::null_mut()
2816 }
2817}
2818
2819pub unsafe fn get_parameter_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2832 crate::xml::entities::get_parameter_entity(doc as *mut _xmlDoc, name)
2833}
2834
2835const ENTITY_LT: &[xmlChar] = b"<";
2844const ENTITY_GT: &[xmlChar] = b">";
2845const ENTITY_AMP: &[xmlChar] = b"&";
2846const ENTITY_QUOT: &[xmlChar] = b""";
2847#[allow(dead_code)]
2848const ENTITY_APOS: &[xmlChar] = b"'";
2849
2850const INDENT: &[xmlChar] = b" ";
2852
2853const MAX_INDENT: c_int = 60;
2855
2856pub(crate) unsafe fn serialize_text(buf: *mut _xmlBuffer, content: *const xmlChar, len: c_int) {
2871 if buf.is_null() || content.is_null() || len <= 0 {
2872 return;
2873 }
2874
2875 let mut i: c_int = 0;
2876 while i < len {
2877 let ch = unsafe { *content.add(i as usize) };
2878
2879 if ch == b']'
2881 && i + 2 < len
2882 && unsafe { *content.add(i as usize + 1) == b']' }
2883 && unsafe { *content.add(i as usize + 2) == b'>' }
2884 {
2885 io::buf_add(buf, &ch as *const u8, 2); io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2888 i += 3;
2889 continue;
2890 }
2891
2892 match ch {
2893 b'<' => {
2894 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
2895 }
2896 b'&' => {
2897 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
2898 }
2899 b'>' => {
2900 io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2904 }
2905 b'\r' => {
2906 io::buf_add(buf, b" " as *const u8, 5);
2908 }
2909 0x01..=0x08 | 0x0B | 0x0C | 0x0E..=0x1F => {
2910 let hex = format!("&#x{:X};", ch);
2912 io::buf_add(buf, hex.as_ptr(), hex.len() as c_int);
2913 }
2914 _ => {
2915 io::buf_add(buf, &ch as *const u8, 1);
2916 }
2917 }
2918 i += 1;
2919 }
2920}
2921
2922pub(crate) unsafe fn serialize_attr_value(buf: *mut _xmlBuffer, value: *const xmlChar) {
2935 if buf.is_null() || value.is_null() {
2936 return;
2937 }
2938
2939 let len = xml_strlen(value);
2940 let mut i: c_int = 0;
2941 while i < len {
2942 let ch = unsafe { *value.add(i as usize) };
2943
2944 match ch {
2945 b'\n' => {
2946 io::buf_add(buf, b" " as *const u8, 5);
2947 }
2948 b'\r' => {
2949 io::buf_add(buf, b" " as *const u8, 5);
2950 }
2951 b'\t' => {
2952 io::buf_add(buf, b"	" as *const u8, 4);
2953 }
2954 b'<' => {
2955 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
2956 }
2957 b'&' => {
2958 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
2959 }
2960 b'"' => {
2961 io::buf_add(buf, ENTITY_QUOT.as_ptr(), ENTITY_QUOT.len() as c_int);
2962 }
2963 b'>' => {
2964 io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2965 }
2966 _ => {
2967 io::buf_add(buf, &ch as *const u8, 1);
2968 }
2969 }
2970 i += 1;
2971 }
2972}
2973
2974unsafe fn write_indent(
2986 buf: *mut _xmlBuffer,
2987 level: c_int,
2988 indent: *const xmlChar,
2989 indent_len: c_int,
2990) {
2991 if buf.is_null() || level <= 0 || indent.is_null() || indent_len <= 0 {
2992 return;
2993 }
2994 let indent_nr = MAX_INDENT / indent_len;
2995 let mut lvl = level;
2996 if lvl > indent_nr {
2997 lvl = indent_nr;
2998 }
2999 for _ in 0..lvl {
3000 io::buf_add(buf, indent, indent_len);
3001 }
3002}
3003
3004unsafe fn is_noenc_text(node: *mut _xmlNode) -> bool {
3018 if node.is_null() {
3019 return false;
3020 }
3021 let n = unsafe { &*node };
3022 if n.name.is_null() {
3023 return false;
3024 }
3025 c_str_eq_bytes(n.name, b"textnoenc")
3026}
3027
3028const unsafe fn c_str_eq_bytes(s: *const xmlChar, b: &[u8]) -> bool {
3036 let mut i = 0usize;
3037 while i < b.len() {
3038 if unsafe { *s.add(i) } != b[i] {
3039 return false;
3040 }
3041 i += 1;
3042 }
3043 unsafe { *s.add(i) == 0 }
3044}
3045
3046#[derive(Clone, Copy)]
3049struct DumpState {
3050 format: c_int,
3052 saved: c_int,
3055 unformatted: *mut _xmlNode,
3058 indent: *const xmlChar,
3061 indent_len: c_int,
3063 no_decl: c_int,
3065}
3066
3067impl DumpState {
3068 const fn new(format: c_int) -> Self {
3069 let f = if format != 0 { 1 } else { 0 };
3070 DumpState {
3071 format: f,
3072 saved: f,
3073 unformatted: ptr::null_mut(),
3074 indent: INDENT.as_ptr(),
3075 indent_len: INDENT.len() as c_int,
3076 no_decl: 0,
3077 }
3078 }
3079
3080 const unsafe fn with_indent(format: c_int, indent: *const xmlChar, no_decl: c_int) -> Self {
3088 let f = if format != 0 { 1 } else { 0 };
3089 let (ptr, len) = if indent.is_null() {
3090 (INDENT.as_ptr(), INDENT.len() as c_int)
3091 } else {
3092 let mut n = 0i32;
3093 while unsafe { *indent.add(n as usize) } != 0 {
3094 n += 1;
3095 }
3096 (indent, n)
3097 };
3098 DumpState {
3099 format: f,
3100 saved: f,
3101 unformatted: ptr::null_mut(),
3102 indent: ptr,
3103 indent_len: len,
3104 no_decl,
3105 }
3106 }
3107}
3108
3109unsafe fn write_qname(buf: *mut _xmlBuffer, node: *mut _xmlNode) {
3115 let n = unsafe { &*node };
3116 if !n.ns.is_null() {
3117 let ns = unsafe { &*n.ns };
3118 if !ns.prefix.is_null() {
3119 io::buf_cat(buf, ns.prefix);
3120 io::buf_ccat(buf, b':');
3121 }
3122 }
3123 if !n.name.is_null() {
3124 io::buf_cat(buf, n.name);
3125 }
3126}
3127
3128unsafe fn ns_dump_output(buf: *mut _xmlBuffer, cur: *mut _xmlNs) {
3134 if cur.is_null() || buf.is_null() {
3135 return;
3136 }
3137 let ns = unsafe { &*cur };
3138 if ns.type_ == XML_LOCAL_NAMESPACE as c_int && !ns.href.is_null() {
3139 if !ns.prefix.is_null() && c_str_eq_bytes(ns.prefix, b"xml") {
3141 return;
3142 }
3143 io::buf_ccat(buf, b' ');
3144 if !ns.prefix.is_null() {
3145 io::buf_add(buf, b"xmlns:" as *const u8, 6);
3146 io::buf_cat(buf, ns.prefix);
3147 } else {
3148 io::buf_add(buf, b"xmlns" as *const u8, 5);
3149 }
3150 io::buf_add(buf, b"=\"" as *const u8, 2);
3151 serialize_attr_value(buf, ns.href);
3152 io::buf_ccat(buf, b'"');
3153 }
3154}
3155
3156unsafe fn attr_dump_output(buf: *mut _xmlBuffer, cur: *mut _xmlAttr) {
3162 if cur.is_null() || buf.is_null() {
3163 return;
3164 }
3165 io::buf_ccat(buf, b' ');
3166 let a = unsafe { &*cur };
3167 if !a.ns.is_null() {
3168 let ans = unsafe { &*a.ns };
3169 if !ans.prefix.is_null() {
3170 io::buf_cat(buf, ans.prefix);
3171 io::buf_ccat(buf, b':');
3172 }
3173 }
3174 if !a.name.is_null() {
3175 io::buf_cat(buf, a.name);
3176 }
3177 io::buf_add(buf, b"=\"" as *const u8, 2);
3178 let mut child = a.children;
3181 while !child.is_null() {
3182 let ct = unsafe { (*child).type_ };
3183 if ct == XML_TEXT_NODE as c_int && !unsafe { (*child).content }.is_null() {
3184 serialize_attr_value(buf, unsafe { (*child).content });
3185 } else if ct == XML_ENTITY_REF_NODE as c_int && !unsafe { (*child).name }.is_null() {
3186 io::buf_ccat(buf, b'&');
3187 io::buf_cat(buf, unsafe { (*child).name });
3188 io::buf_ccat(buf, b';');
3189 }
3190 child = unsafe { (*child).next };
3191 }
3192 io::buf_ccat(buf, b'"');
3193}
3194
3195unsafe fn dump_notation_decl(buf: *mut _xmlBuffer, nota: *mut _xmlNotation) {
3201 let n = unsafe { &*nota };
3202 io::buf_add(buf, b"<!NOTATION " as *const u8, 11);
3203 if !n.name.is_null() {
3204 io::buf_cat(buf, n.name);
3205 }
3206 if !n.PublicID.is_null() {
3207 io::buf_add(buf, b" PUBLIC " as *const u8, 8);
3208 write_quoted_string(buf, n.PublicID);
3209 if !n.SystemID.is_null() {
3210 io::buf_ccat(buf, b' ');
3211 write_quoted_string(buf, n.SystemID);
3212 }
3213 } else {
3214 io::buf_add(buf, b" SYSTEM " as *const u8, 8);
3215 write_quoted_string(buf, n.SystemID);
3216 }
3217 io::buf_add(buf, b" >\n" as *const u8, 4);
3218}
3219
3220unsafe fn dump_element_occur(buf: *mut _xmlBuffer, ocur: c_int) {
3222 use crate::abi::types::xmlElementContentOccur::*;
3223 if ocur == XML_ELEMENT_CONTENT_OPT as c_int {
3224 io::buf_ccat(buf, b'?');
3225 } else if ocur == XML_ELEMENT_CONTENT_MULT as c_int {
3226 io::buf_ccat(buf, b'*');
3227 } else if ocur == XML_ELEMENT_CONTENT_PLUS as c_int {
3228 io::buf_ccat(buf, b'+');
3229 }
3230}
3231
3232unsafe fn dump_element_content(buf: *mut _xmlBuffer, content: *mut _xmlElementContent) {
3238 use crate::abi::types::xmlElementContentOccur::*;
3239 use crate::abi::types::xmlElementContentType::*;
3240 if content.is_null() {
3241 return;
3242 }
3243 io::buf_ccat(buf, b'(');
3244 let mut cur = content;
3245 loop {
3246 if cur.is_null() {
3247 return;
3248 }
3249 let c = unsafe { &*cur };
3250 match c.type_ {
3251 t if t == XML_ELEMENT_CONTENT_PCDATA as c_int => {
3252 io::buf_add(buf, b"#PCDATA" as *const u8, 7);
3253 }
3254 t if t == XML_ELEMENT_CONTENT_ELEMENT as c_int => {
3255 if !c.prefix.is_null() {
3256 io::buf_cat(buf, c.prefix);
3257 io::buf_ccat(buf, b':');
3258 }
3259 if !c.name.is_null() {
3260 io::buf_cat(buf, c.name);
3261 }
3262 }
3263 t if t == XML_ELEMENT_CONTENT_SEQ as c_int || t == XML_ELEMENT_CONTENT_OR as c_int => {
3264 if cur != content
3265 && !c.parent.is_null()
3266 && (c.type_ != unsafe { (*c.parent).type_ }
3267 || c.ocur != XML_ELEMENT_CONTENT_ONCE as c_int)
3268 {
3269 io::buf_ccat(buf, b'(');
3270 }
3271 cur = c.c1;
3272 continue;
3273 }
3274 _ => {}
3275 }
3276
3277 while cur != content {
3279 let ccur = unsafe { &*cur };
3280 let parent = ccur.parent;
3281 if parent.is_null() {
3282 return;
3283 }
3284 let p = unsafe { &*parent };
3285 if (ccur.type_ == XML_ELEMENT_CONTENT_OR as c_int
3286 || ccur.type_ == XML_ELEMENT_CONTENT_SEQ as c_int)
3287 && (ccur.type_ != p.type_ || ccur.ocur != XML_ELEMENT_CONTENT_ONCE as c_int)
3288 {
3289 io::buf_ccat(buf, b')');
3290 }
3291 dump_element_occur(buf, ccur.ocur);
3292
3293 if ccur.type_ == XML_ELEMENT_CONTENT_SEQ as c_int {
3294 io::buf_add(buf, b" , " as *const u8, 3);
3295 } else if ccur.type_ == XML_ELEMENT_CONTENT_OR as c_int {
3296 io::buf_add(buf, b" | " as *const u8, 3);
3297 }
3298
3299 if cur == p.c1 {
3300 cur = p.c2;
3301 break;
3302 }
3303 cur = parent;
3304 }
3305 if cur == content {
3306 break;
3307 }
3308 }
3309 io::buf_ccat(buf, b')');
3310 let cc = unsafe { &*content };
3311 dump_element_occur(buf, cc.ocur);
3312}
3313
3314unsafe fn dump_element_decl(buf: *mut _xmlBuffer, elem: *mut _xmlElement) {
3320 use crate::abi::types::xmlElementTypeVal::*;
3321 let e = unsafe { &*elem };
3322 io::buf_add(buf, b"<!ELEMENT " as *const u8, 10);
3323 if !e.prefix.is_null() {
3324 io::buf_cat(buf, e.prefix);
3325 io::buf_ccat(buf, b':');
3326 }
3327 if !e.name.is_null() {
3328 io::buf_cat(buf, e.name);
3329 }
3330 io::buf_ccat(buf, b' ');
3331 match e.etype {
3332 t if t == XML_ELEMENT_TYPE_EMPTY as c_int => {
3333 io::buf_add(buf, b"EMPTY" as *const u8, 5);
3334 }
3335 t if t == XML_ELEMENT_TYPE_ANY as c_int => {
3336 io::buf_add(buf, b"ANY" as *const u8, 3);
3337 }
3338 t if t == XML_ELEMENT_TYPE_MIXED as c_int || t == XML_ELEMENT_TYPE_ELEMENT as c_int => {
3339 dump_element_content(buf, e.content);
3340 }
3341 _ => {}
3342 }
3343 io::buf_add(buf, b">\n" as *const u8, 2);
3344}
3345
3346unsafe fn dump_enumeration(buf: *mut _xmlBuffer, cur: *mut _xmlEnumeration) {
3352 let mut e = cur;
3353 while !e.is_null() {
3354 let en = unsafe { &*e };
3355 if !en.name.is_null() {
3356 io::buf_cat(buf, en.name);
3357 }
3358 if !en.next.is_null() {
3359 io::buf_add(buf, b" | " as *const u8, 3);
3360 }
3361 e = en.next;
3362 }
3363 io::buf_ccat(buf, b')');
3364}
3365
3366unsafe fn dump_attribute_decl(buf: *mut _xmlBuffer, attr: *mut _xmlAttribute) {
3372 use crate::abi::types::xmlAttributeDefault::*;
3373 use crate::abi::types::xmlAttributeType::*;
3374 let a = unsafe { &*attr };
3375 io::buf_add(buf, b"<!ATTLIST " as *const u8, 10);
3376 if !a.elem.is_null() {
3377 io::buf_cat(buf, a.elem);
3378 }
3379 io::buf_ccat(buf, b' ');
3380 if !a.prefix.is_null() {
3381 io::buf_cat(buf, a.prefix);
3382 io::buf_ccat(buf, b':');
3383 }
3384 if !a.name.is_null() {
3385 io::buf_cat(buf, a.name);
3386 }
3387 match a.atype {
3388 t if t == XML_ATTRIBUTE_CDATA as c_int => {
3389 io::buf_add(buf, b" CDATA" as *const u8, 6);
3390 }
3391 t if t == XML_ATTRIBUTE_ID as c_int => {
3392 io::buf_add(buf, b" ID" as *const u8, 3);
3393 }
3394 t if t == XML_ATTRIBUTE_IDREF as c_int => {
3395 io::buf_add(buf, b" IDREF" as *const u8, 6);
3396 }
3397 t if t == XML_ATTRIBUTE_IDREFS as c_int => {
3398 io::buf_add(buf, b" IDREFS" as *const u8, 7);
3399 }
3400 t if t == XML_ATTRIBUTE_ENTITY as c_int => {
3401 io::buf_add(buf, b" ENTITY" as *const u8, 7);
3402 }
3403 t if t == XML_ATTRIBUTE_ENTITIES as c_int => {
3404 io::buf_add(buf, b" ENTITIES" as *const u8, 9);
3405 }
3406 t if t == XML_ATTRIBUTE_NMTOKEN as c_int => {
3407 io::buf_add(buf, b" NMTOKEN" as *const u8, 8);
3408 }
3409 t if t == XML_ATTRIBUTE_NMTOKENS as c_int => {
3410 io::buf_add(buf, b" NMTOKENS" as *const u8, 9);
3411 }
3412 t if t == XML_ATTRIBUTE_ENUMERATION as c_int => {
3413 io::buf_add(buf, b" (" as *const u8, 2);
3414 dump_enumeration(buf, a.tree);
3415 }
3416 t if t == XML_ATTRIBUTE_NOTATION as c_int => {
3417 io::buf_add(buf, b" NOTATION (" as *const u8, 11);
3418 dump_enumeration(buf, a.tree);
3419 }
3420 _ => {}
3421 }
3422 match a.def {
3423 t if t == XML_ATTRIBUTE_REQUIRED as c_int => {
3424 io::buf_add(buf, b" #REQUIRED" as *const u8, 10);
3425 }
3426 t if t == XML_ATTRIBUTE_IMPLIED as c_int => {
3427 io::buf_add(buf, b" #IMPLIED" as *const u8, 9);
3428 }
3429 t if t == XML_ATTRIBUTE_FIXED as c_int => {
3430 io::buf_add(buf, b" #FIXED" as *const u8, 7);
3431 }
3432 _ => {}
3433 }
3434 if !a.defaultValue.is_null() {
3435 io::buf_add(buf, b" \"" as *const u8, 2);
3436 serialize_attr_value(buf, a.defaultValue);
3437 io::buf_ccat(buf, b'"');
3438 }
3439 io::buf_add(buf, b">\n" as *const u8, 2);
3440}
3441
3442unsafe fn write_quoted_string(buf: *mut _xmlBuffer, str: *const xmlChar) {
3448 if buf.is_null() {
3449 return;
3450 }
3451 io::buf_ccat(buf, b'"');
3452 if !str.is_null() {
3453 let mut i = 0usize;
3454 while unsafe { *str.add(i) != 0 } {
3455 let ch = unsafe { *str.add(i) };
3456 if ch == b'"' {
3457 io::buf_add(buf, b""" as *const u8, 6);
3458 } else {
3459 io::buf_add(buf, &ch as *const u8, 1);
3460 }
3461 i += 1;
3462 }
3463 }
3464 io::buf_ccat(buf, b'"');
3465}
3466
3467unsafe fn dump_entity_decl(buf: *mut _xmlBuffer, ent: *mut _xmlEntity) {
3473 use crate::abi::types::xmlEntityType::*;
3474 let e = unsafe { &*ent };
3475 if e.etype == XML_INTERNAL_PARAMETER_ENTITY as c_int
3476 || e.etype == XML_EXTERNAL_PARAMETER_ENTITY as c_int
3477 {
3478 io::buf_add(buf, b"<!ENTITY % " as *const u8, 11);
3479 } else {
3480 io::buf_add(buf, b"<!ENTITY " as *const u8, 9);
3481 }
3482 if !e.name.is_null() {
3483 io::buf_cat(buf, e.name);
3484 }
3485 io::buf_ccat(buf, b' ');
3486
3487 if e.etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY as c_int
3488 || e.etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int
3489 || e.etype == XML_EXTERNAL_PARAMETER_ENTITY as c_int
3490 {
3491 if !e.ExternalID.is_null() {
3492 io::buf_add(buf, b"PUBLIC " as *const u8, 7);
3493 write_quoted_string(buf, e.ExternalID);
3494 io::buf_ccat(buf, b' ');
3495 } else {
3496 io::buf_add(buf, b"SYSTEM " as *const u8, 7);
3497 }
3498 write_quoted_string(buf, e.SystemID);
3499 }
3500
3501 if e.etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int && !e.content.is_null() {
3502 io::buf_add(buf, b" NDATA " as *const u8, 7);
3503 if !e.orig.is_null() {
3504 io::buf_cat(buf, e.orig);
3505 } else if !e.content.is_null() {
3506 io::buf_cat(buf, e.content);
3507 }
3508 }
3509
3510 if e.etype == XML_INTERNAL_GENERAL_ENTITY as c_int
3511 || e.etype == XML_INTERNAL_PARAMETER_ENTITY as c_int
3512 {
3513 if !e.orig.is_null() {
3514 write_quoted_string(buf, e.orig);
3515 } else {
3516 io::buf_ccat(buf, b'"');
3518 if !e.content.is_null() {
3519 let mut i = 0usize;
3520 while unsafe { *e.content.add(i) != 0 } {
3521 let ch = unsafe { *e.content.add(i) };
3522 match ch {
3523 b'"' => io::buf_add(buf, b""" as *const u8, 6),
3524 b'%' => io::buf_add(buf, b"%" as *const u8, 6),
3525 _ => io::buf_add(buf, &ch as *const u8, 1),
3526 };
3527 i += 1;
3528 }
3529 }
3530 io::buf_ccat(buf, b'"');
3531 }
3532 }
3533 io::buf_add(buf, b">\n" as *const u8, 2);
3534}
3535
3536unsafe fn dtd_dump_output(
3542 buf: *mut _xmlBuffer,
3543 cur: *mut _xmlNode,
3544 state: &mut DumpState,
3545 level: &mut c_int,
3546) {
3547 let dtd = cur as *mut _xmlDtd;
3548 let d = unsafe { &*dtd };
3549 io::buf_add(buf, b"<!DOCTYPE " as *const u8, 10);
3550 if !d.name.is_null() {
3551 io::buf_cat(buf, d.name);
3552 }
3553 if !d.ExternalID.is_null() {
3554 io::buf_add(buf, b" PUBLIC " as *const u8, 8);
3555 write_quoted_string(buf, d.ExternalID);
3556 io::buf_ccat(buf, b' ');
3557 write_quoted_string(buf, d.SystemID);
3558 } else if !d.SystemID.is_null() {
3559 io::buf_add(buf, b" SYSTEM " as *const u8, 8);
3560 write_quoted_string(buf, d.SystemID);
3561 }
3562 if d.entities.is_null()
3567 && d.elements.is_null()
3568 && d.attributes.is_null()
3569 && d.notations.is_null()
3570 && d.pentities.is_null()
3571 {
3572 io::buf_ccat(buf, b'>');
3573 return;
3574 }
3575 io::buf_add(buf, b" [\n" as *const u8, 3);
3576 let format = state.format;
3582 let lvl = *level;
3583 state.format = 0;
3584 *level = -1;
3585 if !d.notations.is_null() {
3586 crate::xml::hash::hash_scan(
3587 d.notations as *mut crate::xml::hash::HashTable,
3588 Some(dump_notation_decl_cb),
3589 buf as *mut c_void,
3590 );
3591 }
3592 if !d.elements.is_null() {
3593 crate::xml::hash::hash_scan(
3594 d.elements as *mut crate::xml::hash::HashTable,
3595 Some(dump_element_decl_cb),
3596 buf as *mut c_void,
3597 );
3598 }
3599 if !d.attributes.is_null() {
3600 crate::xml::hash::hash_scan(
3601 d.attributes as *mut crate::xml::hash::HashTable,
3602 Some(dump_attribute_decl_cb),
3603 buf as *mut c_void,
3604 );
3605 }
3606 if !d.entities.is_null() {
3607 crate::xml::hash::hash_scan(
3608 d.entities as *mut crate::xml::hash::HashTable,
3609 Some(dump_entity_decl_cb),
3610 buf as *mut c_void,
3611 );
3612 }
3613 if !d.pentities.is_null() {
3614 crate::xml::hash::hash_scan(
3615 d.pentities as *mut crate::xml::hash::HashTable,
3616 Some(dump_entity_decl_cb),
3617 buf as *mut c_void,
3618 );
3619 }
3620 state.format = format;
3621 *level = lvl;
3622 io::buf_add(buf, b"]>" as *const u8, 2);
3623}
3624
3625unsafe extern "C" fn dump_notation_decl_cb(
3627 payload: *mut c_void,
3628 data: *mut c_void,
3629 _name: *const crate::abi::types::xmlChar,
3630) {
3631 if !payload.is_null() && !data.is_null() {
3632 dump_notation_decl(data as *mut _xmlBuffer, payload as *mut _xmlNotation);
3633 }
3634}
3635
3636unsafe extern "C" fn dump_element_decl_cb(
3638 payload: *mut c_void,
3639 data: *mut c_void,
3640 _name: *const crate::abi::types::xmlChar,
3641) {
3642 if !payload.is_null() && !data.is_null() {
3643 dump_element_decl(data as *mut _xmlBuffer, payload as *mut _xmlElement);
3644 }
3645}
3646
3647unsafe extern "C" fn dump_attribute_decl_cb(
3649 payload: *mut c_void,
3650 data: *mut c_void,
3651 _name: *const crate::abi::types::xmlChar,
3652) {
3653 if !payload.is_null() && !data.is_null() {
3654 dump_attribute_decl(data as *mut _xmlBuffer, payload as *mut _xmlAttribute);
3655 }
3656}
3657
3658unsafe extern "C" fn dump_entity_decl_cb(
3660 payload: *mut c_void,
3661 data: *mut c_void,
3662 _name: *const crate::abi::types::xmlChar,
3663) {
3664 if !payload.is_null() && !data.is_null() {
3665 dump_entity_decl(data as *mut _xmlBuffer, payload as *mut _xmlEntity);
3666 }
3667}
3668
3669unsafe fn doc_content_dump_output(
3678 buf: *mut _xmlBuffer,
3679 cur: *mut _xmlNode,
3680 state: &mut DumpState,
3681 level: &mut c_int,
3682) {
3683 let doc = cur as *mut _xmlDoc;
3684 let d = unsafe { &*doc };
3685
3686 if state.no_decl == 0 {
3690 io::buf_add(buf, b"<?xml version=\"" as *const u8, 15);
3691 if !d.version.is_null() {
3692 io::buf_cat(buf, d.version);
3693 } else {
3694 io::buf_add(buf, b"1.0" as *const u8, 3);
3695 }
3696 io::buf_ccat(buf, b'"');
3697 if !d.encoding.is_null() {
3698 io::buf_add(buf, b" encoding=\"" as *const u8, 11);
3699 io::buf_cat(buf, d.encoding);
3700 io::buf_ccat(buf, b'"');
3701 }
3702 match d.standalone {
3703 0 => {
3704 io::buf_add(buf, b" standalone=\"no\"" as *const u8, 16);
3705 }
3706 1 => {
3707 io::buf_add(buf, b" standalone=\"yes\"" as *const u8, 17);
3708 }
3709 _ => {}
3710 }
3711 io::buf_add(buf, b"?>\n" as *const u8, 3);
3712 }
3713
3714 if !d.intSubset.is_null() {
3721 let mut in_chain = false;
3722 let mut c = d.children;
3723 while !c.is_null() {
3724 if c as *mut c_void == d.intSubset as *mut c_void {
3725 in_chain = true;
3726 break;
3727 }
3728 c = unsafe { (*c).next };
3729 }
3730 if !in_chain {
3731 let mut lvl = 0;
3732 dtd_dump_output(buf, d.intSubset as *mut _xmlNode, state, &mut lvl);
3733 io::buf_ccat(buf, b'\n');
3734 }
3735 }
3736
3737 if !d.children.is_null() {
3738 let mut child = d.children;
3739 while !child.is_null() {
3740 *level = 0;
3741 node_dump_internal(buf, child, child, cur, state, level);
3742 let ct = unsafe { (*child).type_ };
3743 if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
3744 io::buf_ccat(buf, b'\n');
3745 }
3746 child = unsafe { (*child).next };
3747 }
3748 }
3749}
3750
3751unsafe fn node_dump_internal(
3775 buf: *mut _xmlBuffer,
3776 cur: *mut _xmlNode,
3777 root: *mut _xmlNode,
3778 parent: *mut _xmlNode,
3779 state: &mut DumpState,
3780 level: &mut c_int,
3781) {
3782 if cur.is_null() || buf.is_null() {
3783 return;
3784 }
3785 let n = unsafe { &*cur };
3786 match n.type_ {
3787 t if t == XML_ELEMENT_NODE as c_int => {
3788 if cur != root && state.format == 1 {
3789 write_indent(buf, *level, state.indent, state.indent_len);
3790 }
3791 if !n.parent.is_null() && n.parent != parent && !n.children.is_null() {
3794 let mut sub = DumpState::new(state.format);
3795 let mut sub_level = *level;
3796 node_dump_internal(buf, cur, cur, n.parent, &mut sub, &mut sub_level);
3797 return;
3798 }
3799 io::buf_ccat(buf, b'<');
3801 write_qname(buf, cur);
3802 let mut nsdef = n.nsDef;
3803 while !nsdef.is_null() {
3804 ns_dump_output(buf, nsdef);
3805 nsdef = unsafe { (*nsdef).next };
3806 }
3807 let mut attr = n.properties;
3808 while !attr.is_null() {
3809 attr_dump_output(buf, attr);
3810 attr = unsafe { (*attr).next };
3811 }
3812 if n.children.is_null() {
3813 io::buf_add(buf, b"/>" as *const u8, 2);
3814 } else {
3815 if state.format == 1 {
3816 let mut tmp = n.children;
3819 while !tmp.is_null() {
3820 let tt = unsafe { (*tmp).type_ };
3821 if tt == XML_TEXT_NODE as c_int
3822 || tt == XML_CDATA_SECTION_NODE as c_int
3823 || tt == XML_ENTITY_REF_NODE as c_int
3824 {
3825 state.format = 0;
3826 state.unformatted = cur;
3827 break;
3828 }
3829 tmp = unsafe { (*tmp).next };
3830 }
3831 }
3832 io::buf_ccat(buf, b'>');
3833 if state.format == 1 {
3834 io::buf_ccat(buf, b'\n');
3835 }
3836 if *level >= 0 {
3837 *level += 1;
3838 }
3839 let mut child = n.children;
3840 while !child.is_null() {
3841 node_dump_internal(buf, child, root, cur, state, level);
3842 if state.format == 1 {
3843 let ct = unsafe { (*child).type_ };
3844 if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
3845 io::buf_ccat(buf, b'\n');
3846 }
3847 }
3848 child = unsafe { (*child).next };
3849 }
3850 if *level > 0 {
3852 *level -= 1;
3853 }
3854 if state.format == 1 {
3855 write_indent(buf, *level, state.indent, state.indent_len);
3856 }
3857 io::buf_add(buf, b"</" as *const u8, 2);
3858 write_qname(buf, cur);
3859 io::buf_ccat(buf, b'>');
3860 if cur == state.unformatted {
3861 state.format = state.saved;
3862 state.unformatted = ptr::null_mut();
3863 }
3864 }
3865 }
3866 t if t == XML_TEXT_NODE as c_int => {
3867 if !n.content.is_null() {
3868 if is_noenc_text(cur) {
3869 io::buf_cat(buf, n.content);
3870 } else {
3871 serialize_text(buf, n.content, xml_strlen(n.content));
3872 }
3873 } else if !n.children.is_null() {
3874 let c = node_get_content(cur);
3877 if !c.is_null() {
3878 if is_noenc_text(cur) {
3879 io::buf_cat(buf, c);
3880 } else {
3881 serialize_text(buf, c, xml_strlen(c));
3882 }
3883 allocator::xmlFreeImpl(c as *mut c_void);
3884 }
3885 }
3886 }
3887 t if t == XML_CDATA_SECTION_NODE as c_int => {
3888 if n.content.is_null() || unsafe { *n.content == 0 } {
3889 io::buf_add(buf, b"<![CDATA[]]>" as *const u8, 12);
3890 } else {
3891 let len = xml_strlen(n.content) as usize;
3892 let bytes = core::slice::from_raw_parts(n.content, len);
3893 let mut i = 0usize;
3894 let mut seg_start = 0usize;
3895 while i < len {
3896 if bytes[i] == b']'
3897 && i + 2 < len
3898 && bytes[i + 1] == b']'
3899 && bytes[i + 2] == b'>'
3900 {
3901 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
3902 io::buf_add(buf, n.content.add(seg_start), (i + 2 - seg_start) as c_int);
3903 io::buf_add(buf, b"]]>" as *const u8, 3);
3904 seg_start = i + 2;
3905 i += 3;
3906 continue;
3907 }
3908 i += 1;
3909 }
3910 if seg_start < len {
3911 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
3912 io::buf_add(buf, n.content.add(seg_start), (len - seg_start) as c_int);
3913 io::buf_add(buf, b"]]>" as *const u8, 3);
3914 }
3915 }
3916 }
3917 t if t == XML_COMMENT_NODE as c_int => {
3918 if cur != root && state.format == 1 {
3919 write_indent(buf, *level, state.indent, state.indent_len);
3920 }
3921 if !n.content.is_null() {
3922 io::buf_add(buf, b"<!--" as *const u8, 4);
3923 io::buf_cat(buf, n.content);
3924 io::buf_add(buf, b"-->" as *const u8, 3);
3925 }
3926 }
3927 t if t == XML_PI_NODE as c_int => {
3928 if cur != root && state.format == 1 {
3929 write_indent(buf, *level, state.indent, state.indent_len);
3930 }
3931 io::buf_add(buf, b"<?" as *const u8, 2);
3932 if !n.name.is_null() {
3933 io::buf_cat(buf, n.name);
3934 }
3935 if !n.content.is_null() && unsafe { *n.content != 0 } {
3936 io::buf_ccat(buf, b' ');
3937 io::buf_cat(buf, n.content);
3938 }
3939 io::buf_add(buf, b"?>" as *const u8, 2);
3940 }
3941 t if t == XML_ENTITY_REF_NODE as c_int => {
3942 io::buf_ccat(buf, b'&');
3943 if !n.name.is_null() {
3944 io::buf_cat(buf, n.name);
3945 }
3946 io::buf_ccat(buf, b';');
3947 }
3948 t if t == XML_DOCUMENT_NODE as c_int => {
3949 doc_content_dump_output(buf, cur, state, level);
3950 }
3951 t if t == XML_HTML_DOCUMENT_NODE as c_int => {
3952 crate::xml::html::serialize_node(cur, buf, state.format, *level);
3954 }
3955 t if t == XML_DTD_NODE as c_int => {
3956 dtd_dump_output(buf, cur, state, level);
3957 }
3958 t if t == XML_ATTRIBUTE_NODE as c_int => {
3959 attr_dump_output(buf, cur as *mut _xmlAttr);
3960 }
3961 t if t == XML_NAMESPACE_DECL as c_int => {
3962 ns_dump_output(buf, cur as *mut _xmlNs);
3963 }
3964 t if t == XML_ELEMENT_DECL as c_int => {
3965 dump_element_decl(buf, cur as *mut _xmlElement);
3966 }
3967 t if t == XML_ATTRIBUTE_DECL as c_int => {
3968 dump_attribute_decl(buf, cur as *mut _xmlAttribute);
3969 }
3970 t if t == XML_ENTITY_DECL as c_int => {
3971 dump_entity_decl(buf, cur as *mut _xmlEntity);
3972 }
3973 _ => {}
3974 }
3975}
3976
3977pub(crate) unsafe fn serialize_node(
3991 node: *mut _xmlNode,
3992 buf: *mut _xmlBuffer,
3993 format: c_int,
3994 level: c_int,
3995) {
3996 unsafe { serialize_node_opt(node, buf, format, level, ptr::null()) };
3997}
3998
3999pub(crate) unsafe fn serialize_node_opt(
4007 node: *mut _xmlNode,
4008 buf: *mut _xmlBuffer,
4009 format: c_int,
4010 level: c_int,
4011 indent: *const xmlChar,
4012) {
4013 unsafe { serialize_node_opts(node, buf, format, level, indent, 0) };
4014}
4015
4016pub(crate) unsafe fn serialize_node_opts(
4023 node: *mut _xmlNode,
4024 buf: *mut _xmlBuffer,
4025 format: c_int,
4026 level: c_int,
4027 indent: *const xmlChar,
4028 no_decl: c_int,
4029) {
4030 if node.is_null() || buf.is_null() {
4031 return;
4032 }
4033 let parent = unsafe { (*node).parent };
4034 let mut state = DumpState::with_indent(format, indent, no_decl);
4035 let mut lvl = level;
4036 node_dump_internal(buf, node, node, parent, &mut state, &mut lvl);
4037}
4038
4039pub(crate) unsafe fn doc_dump(buf: *mut _xmlBuffer, doc: *mut _xmlDoc) -> c_int {
4049 if buf.is_null() || doc.is_null() {
4050 return -1;
4051 }
4052
4053 let before = io::buf_length(buf);
4054 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
4055 let after = io::buf_length(buf);
4056
4057 if after < 0 || before < 0 {
4058 return -1;
4059 }
4060 after - before
4061}
4062
4063pub(crate) unsafe fn node_dump(
4075 buf: *mut _xmlBuffer,
4076 doc: *mut _xmlDoc,
4077 node: *mut _xmlNode,
4078 level: c_int,
4079 format: c_int,
4080) -> c_int {
4081 let _ = doc; if buf.is_null() || node.is_null() {
4083 return -1;
4084 }
4085
4086 let before = io::buf_length(buf);
4087 serialize_node(node, buf, format, level);
4088 let after = io::buf_length(buf);
4089
4090 if after < 0 || before < 0 {
4091 return -1;
4092 }
4093 after - before
4094}
4095
4096pub(crate) unsafe fn save_doc_to_filename(
4103 doc: *mut _xmlDoc,
4104 filename: *const c_char,
4105 compression: c_int,
4106) -> c_int {
4107 if doc.is_null() || filename.is_null() {
4108 return -1;
4109 }
4110
4111 let out = io::output_buffer_create_filename(filename, ptr::null_mut(), compression);
4112 if out.is_null() {
4113 return -1;
4114 }
4115
4116 let buf = io::buf_create(-1);
4117 if buf.is_null() {
4118 io::output_buffer_close(out);
4119 return -1;
4120 }
4121
4122 let ret = doc_dump(buf, doc);
4123 if ret >= 0 {
4124 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
4126 io::output_buffer_flush(out);
4127 }
4128
4129 io::buf_free(buf);
4130 io::output_buffer_close(out);
4131 ret
4132}
4133
4134#[allow(dead_code)]
4141pub(crate) unsafe fn save_doc_to_fd(doc: *mut _xmlDoc, fd: c_int, _compression: c_int) -> c_int {
4142 if doc.is_null() || fd < 0 {
4143 return -1;
4144 }
4145
4146 let out = io::output_buffer_create_fd(fd, ptr::null_mut());
4147 if out.is_null() {
4148 return -1;
4149 }
4150
4151 let buf = io::buf_create(-1);
4152 if buf.is_null() {
4153 io::output_buffer_close(out);
4154 return -1;
4155 }
4156
4157 let ret = doc_dump(buf, doc);
4158 if ret >= 0 {
4159 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
4160 io::output_buffer_flush(out);
4161 }
4162
4163 io::buf_free(buf);
4164 io::output_buffer_close(out);
4165 ret
4166}
4167
4168#[allow(dead_code)]
4175pub(crate) unsafe fn save_doc_to_buf(
4176 doc: *mut _xmlDoc,
4177 buf: *mut _xmlBuffer,
4178 compression: c_int,
4179) -> c_int {
4180 let _ = compression;
4181 if doc.is_null() || buf.is_null() {
4182 return -1;
4183 }
4184
4185 doc_dump(buf, doc)
4186}
4187
4188#[allow(dead_code)]
4195pub(crate) unsafe fn save_format_doc_to_buf(
4196 doc: *mut _xmlDoc,
4197 buf: *mut _xmlBuffer,
4198 compression: c_int,
4199) -> c_int {
4200 let _ = compression;
4201 if doc.is_null() || buf.is_null() {
4202 return -1;
4203 }
4204
4205 let before = io::buf_length(buf);
4206 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
4207 let after = io::buf_length(buf);
4208
4209 if after < 0 || before < 0 {
4210 return -1;
4211 }
4212 after - before
4213}
4214
4215#[allow(dead_code)]
4224pub(crate) unsafe fn dump_node(node: *mut _xmlNode) -> *mut xmlChar {
4225 if node.is_null() {
4226 return ptr::null_mut();
4227 }
4228
4229 let buf = io::buf_create(-1);
4230 if buf.is_null() {
4231 return ptr::null_mut();
4232 }
4233
4234 serialize_node(node, buf, 0, 0);
4235
4236 let content = io::buf_content(buf);
4237 if content.is_null() {
4238 io::buf_free(buf);
4239 return ptr::null_mut();
4240 }
4241
4242 let result = dup_xml_str(content);
4244 io::buf_free(buf);
4245 result
4246}
4247
4248pub unsafe fn dump_doc(doc: *mut _xmlDoc) -> *mut xmlChar {
4257 if doc.is_null() {
4258 return ptr::null_mut();
4259 }
4260
4261 let buf = io::buf_create(-1);
4262 if buf.is_null() {
4263 return ptr::null_mut();
4264 }
4265
4266 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
4267
4268 let content = io::buf_content(buf);
4269 if content.is_null() {
4270 io::buf_free(buf);
4271 return ptr::null_mut();
4272 }
4273
4274 let result = dup_xml_str(content);
4275 io::buf_free(buf);
4276 result
4277}
4278
4279pub(crate) unsafe fn xmlNodeDump(
4295 buf: *mut _xmlBuffer,
4296 doc: *mut _xmlDoc,
4297 node: *mut _xmlNode,
4298 level: c_int,
4299 format: c_int,
4300) -> c_int {
4301 node_dump(buf, doc, node, level, format)
4302}
4303
4304pub(crate) unsafe fn xmlDocDump(fp: *mut c_void, doc: *mut _xmlDoc) -> c_int {
4317 if fp.is_null() || doc.is_null() {
4318 return -1;
4319 }
4320
4321 let buf = io::buf_create(-1);
4322 if buf.is_null() {
4323 return -1;
4324 }
4325
4326 let ret = doc_dump(buf, doc);
4327 if ret < 0 {
4328 io::buf_free(buf);
4329 return -1;
4330 }
4331
4332 let content = io::buf_content(buf);
4333 let len = io::buf_length(buf);
4334 if !content.is_null() && len > 0 {
4335 let written = libc::fwrite(
4336 content as *const c_void,
4337 1,
4338 len as usize,
4339 fp as *mut libc::FILE,
4340 );
4341 io::buf_free(buf);
4342 written as c_int
4343 } else {
4344 io::buf_free(buf);
4345 0
4346 }
4347}
4348
4349pub(crate) unsafe fn xmlDocDumpFormatMemory(
4363 doc: *mut _xmlDoc,
4364 mem: *mut *mut xmlChar,
4365 size: *mut c_int,
4366 format: c_int,
4367) {
4368 if doc.is_null() || mem.is_null() || size.is_null() {
4369 return;
4370 }
4371
4372 let buf = io::buf_create(-1);
4373 if buf.is_null() {
4374 unsafe {
4375 *mem = ptr::null_mut();
4376 *size = 0;
4377 }
4378 return;
4379 }
4380
4381 serialize_node(doc as *mut _xmlNode, buf, format, 0);
4382
4383 let content = io::buf_content(buf);
4384 let len = io::buf_length(buf);
4385
4386 if !content.is_null() && len > 0 {
4387 let result = allocator::xmlMallocImpl((len + 1) as usize) as *mut xmlChar;
4389 if !result.is_null() {
4390 ptr::copy_nonoverlapping(content, result, len as usize);
4391 *result.add(len as usize) = 0;
4392 unsafe {
4393 *mem = result;
4394 *size = len;
4395 }
4396 } else {
4397 unsafe {
4398 *mem = ptr::null_mut();
4399 *size = 0;
4400 }
4401 }
4402 } else {
4403 unsafe {
4404 *mem = ptr::null_mut();
4405 *size = 0;
4406 }
4407 }
4408
4409 io::buf_free(buf);
4410}
4411
4412pub(crate) unsafe fn xmlDocDumpMemory(doc: *mut _xmlDoc, mem: *mut *mut xmlChar, size: *mut c_int) {
4426 xmlDocDumpFormatMemory(doc, mem, size, 0)
4427}
4428
4429pub(crate) unsafe fn xmlSaveFile(filename: *const c_char, cur: *mut _xmlDoc) -> c_int {
4442 save_doc_to_filename(cur, filename, 0)
4443}
4444
4445pub(crate) unsafe fn xmlSaveFileEnc(
4459 filename: *const c_char,
4460 cur: *mut _xmlDoc,
4461 encoding: *const c_char,
4462) -> c_int {
4463 let _ = encoding; save_doc_to_filename(cur, filename, 0)
4465}
4466
4467pub(crate) unsafe fn xmlSaveFormatFile(
4480 filename: *const c_char,
4481 cur: *mut _xmlDoc,
4482 format: c_int,
4483) -> c_int {
4484 let _ = format;
4485 save_doc_to_filename(cur, filename, 0)
4486}
4487
4488pub(crate) unsafe fn xmlSaveFormatFileEnc(
4502 filename: *const c_char,
4503 cur: *mut _xmlDoc,
4504 encoding: *const c_char,
4505 format: c_int,
4506) -> c_int {
4507 let _ = encoding;
4508 let _ = format;
4509 save_doc_to_filename(cur, filename, 0)
4510}
4511
4512pub(crate) unsafe fn xmlGetDocCompressMode(doc: *mut _xmlDoc) -> c_int {
4524 if doc.is_null() {
4525 return -1;
4526 }
4527 unsafe { (*doc).compression }
4528}
4529
4530pub(crate) unsafe fn xmlSetDocCompressMode(doc: *mut _xmlDoc, mode: c_int) {
4542 if doc.is_null() {
4543 return;
4544 }
4545 unsafe {
4546 (*doc).compression = mode;
4547 }
4548}
4549
4550#[cfg(test)]
4551mod tests {
4552 use super::*;
4553 use core::ffi::c_void;
4554
4555 fn c_str(s: &str) -> *const xmlChar {
4563 let bytes = s.as_bytes();
4564 let buf = unsafe { allocator::xmlMallocImpl(bytes.len() + 1) as *mut u8 };
4565 if !buf.is_null() {
4566 unsafe {
4567 ptr::copy_nonoverlapping(bytes.as_ptr(), buf, bytes.len());
4568 *buf.add(bytes.len()) = 0;
4569 }
4570 }
4571 buf as *const xmlChar
4572 }
4573
4574 #[test]
4581 fn test_new_free_doc() {
4582 unsafe {
4583 let doc = new_doc(ptr::null());
4584 assert!(!doc.is_null());
4585 assert_eq!((*doc).type_, XML_DOCUMENT_NODE as c_int);
4586 assert_eq!((*doc).standalone, -1);
4587 assert_eq!((*doc).doc, doc);
4588 assert!(!(*doc).version.is_null());
4589 free_doc(doc);
4590 }
4591 }
4592
4593 #[test]
4601 fn test_new_doc_with_version() {
4602 unsafe {
4603 let ver = c_str("2.0");
4604 let doc = new_doc(ver);
4605 assert!(!doc.is_null());
4606 let doc_ver = (*doc).version;
4607 assert!(!doc_ver.is_null());
4608 assert!(crate::abi::exports_xml2::xmlStrEqual(doc_ver, ver,) != 0);
4609 allocator::xmlFreeImpl(ver as *mut c_void);
4610 free_doc(doc);
4611 }
4612 }
4613
4614 #[test]
4622 fn test_new_node() {
4623 unsafe {
4624 let doc = new_doc(ptr::null());
4625 let node = new_node(ptr::null_mut(), c_str("root"));
4626 assert!(!node.is_null());
4627 assert_eq!((*node).type_, XML_ELEMENT_NODE as c_int);
4628 assert!(!(*node).name.is_null());
4629 free_node(node);
4630 free_doc(doc);
4631 }
4632 }
4633
4634 #[test]
4642 fn test_node_get_content_recurses_descendants() {
4643 unsafe {
4648 let doc = new_doc(ptr::null());
4649 let root = new_node(ptr::null_mut(), c_str("library"));
4650 doc_set_root_element(doc, root);
4651 let book = new_child(root, ptr::null_mut(), c_str("book"));
4652 let title = new_child(book, ptr::null_mut(), c_str("title"));
4653 let text = new_text(c_str("Rust"));
4654 add_child(title, text);
4655
4656 let content = node_get_content(book);
4657 assert!(!content.is_null());
4658 let s = core::slice::from_raw_parts(
4659 content,
4660 libc::strlen(content as *const libc::c_char) as usize,
4661 );
4662 assert_eq!(s, b"Rust", "descendant text not concatenated");
4663 allocator::xmlFreeImpl(content as *mut c_void);
4664
4665 free_doc(doc);
4666 }
4667 }
4668
4669 #[test]
4676 fn test_doc_set_root_element() {
4677 unsafe {
4678 let doc = new_doc(ptr::null());
4679 let root = new_node(ptr::null_mut(), c_str("root"));
4680 let old = doc_set_root_element(doc, root);
4681 assert!(old.is_null());
4682 assert_eq!(doc_get_root_element(doc), root);
4683 assert_eq!((*doc).children, root);
4684 free_doc(doc);
4685 }
4686 }
4687
4688 #[test]
4696 fn test_add_child_and_sibling() {
4697 unsafe {
4698 let doc = new_doc(ptr::null());
4699 let root = new_node(ptr::null_mut(), c_str("root"));
4700 doc_set_root_element(doc, root);
4701
4702 let child1 = new_child(root, ptr::null_mut(), c_str("child1"));
4703 assert!(!child1.is_null());
4704 assert_eq!((*child1).parent, root);
4705 assert_eq!((*root).children, child1);
4706 assert_eq!((*root).last, child1);
4707
4708 let child2 = new_child(root, ptr::null_mut(), c_str("child2"));
4709 assert!(!child2.is_null());
4710 assert_eq!((*child2).parent, root);
4711 assert_eq!((*child1).next, child2);
4712 assert_eq!((*child2).prev, child1);
4713 assert_eq!((*root).last, child2);
4714
4715 let sibling = new_node(ptr::null_mut(), c_str("sibling"));
4717 add_sibling(child2, sibling);
4718 assert_eq!((*child2).next, sibling);
4719 assert_eq!((*sibling).prev, child2);
4720 assert_eq!((*root).last, sibling);
4721
4722 free_doc(doc);
4723 }
4724 }
4725
4726 #[test]
4734 fn test_unlink_node() {
4735 unsafe {
4736 let doc = new_doc(ptr::null());
4737 let root = new_node(ptr::null_mut(), c_str("root"));
4738 doc_set_root_element(doc, root);
4739
4740 let child1 = new_child(root, ptr::null_mut(), c_str("c1"));
4741 let child2 = new_child(root, ptr::null_mut(), c_str("c2"));
4742
4743 unlink_node(child1);
4744 assert!((*child1).parent.is_null());
4745 assert!((*child1).prev.is_null());
4746 assert!((*child1).next.is_null());
4747 assert_eq!((*root).children, child2);
4748 assert_eq!((*root).last, child2);
4749
4750 free_node(child1);
4751 free_doc(doc);
4752 }
4753 }
4754
4755 #[test]
4762 fn test_text_and_comment_nodes() {
4763 unsafe {
4764 let text = new_text(c_str("hello world"));
4765 assert!(!text.is_null());
4766 assert_eq!((*text).type_, XML_TEXT_NODE as c_int);
4767 assert!(!(*text).content.is_null());
4768 free_node(text);
4769
4770 let comment = new_comment(c_str("my comment"));
4771 assert!(!comment.is_null());
4772 assert_eq!((*comment).type_, XML_COMMENT_NODE as c_int);
4773 free_node(comment);
4774
4775 let pi = new_pi(c_str("xml"), c_str("version='1.0'"));
4776 assert!(!pi.is_null());
4777 assert_eq!((*pi).type_, XML_PI_NODE as c_int);
4778 free_node(pi);
4779 }
4780 }
4781
4782 #[test]
4790 fn test_set_and_get_prop() {
4791 unsafe {
4792 let doc = new_doc(ptr::null());
4793 let root = new_node(ptr::null_mut(), c_str("root"));
4794 doc_set_root_element(doc, root);
4795
4796 let attr = set_prop(root, c_str("id"), c_str("42"));
4797 assert!(!attr.is_null());
4798 assert_eq!((*attr).type_, XML_ATTRIBUTE_NODE as c_int);
4799
4800 let value = get_prop(root, c_str("id"));
4801 assert!(!value.is_null());
4802 assert!(crate::abi::exports_xml2::xmlStrEqual(value, c_str("42")) != 0);
4803 allocator::xmlFreeImpl(value as *mut c_void);
4804
4805 free_doc(doc);
4806 }
4807 }
4808
4809 #[test]
4817 fn test_remove_prop() {
4818 unsafe {
4819 let doc = new_doc(ptr::null());
4820 let root = new_node(ptr::null_mut(), c_str("root"));
4821 doc_set_root_element(doc, root);
4822
4823 set_prop(root, c_str("a"), c_str("1"));
4824 set_prop(root, c_str("b"), c_str("2"));
4825
4826 let value = get_prop(root, c_str("a"));
4827 assert!(!value.is_null());
4828 allocator::xmlFreeImpl(value as *mut c_void);
4829
4830 let attr = (*root).properties;
4832 assert!(!attr.is_null());
4833 let result = remove_prop(attr);
4834 assert_eq!(result, 0);
4835
4836 let value2 = get_prop(root, c_str("a"));
4838 assert!(value2.is_null());
4839
4840 free_doc(doc);
4841 }
4842 }
4843
4844 #[test]
4852 fn test_namespace_operations() {
4853 unsafe {
4854 let doc = new_doc(ptr::null());
4855 let root = new_node(ptr::null_mut(), c_str("root"));
4856 doc_set_root_element(doc, root);
4857
4858 let ns = new_ns(root, c_str("http://example.com"), c_str("ex"));
4859 assert!(!ns.is_null());
4860 assert!(!(*root).nsDef.is_null());
4861
4862 set_ns(root, ns);
4863 assert_eq!((*root).ns, ns);
4864
4865 let found = search_ns(doc, root, c_str("ex"));
4866 assert_eq!(found, ns);
4867
4868 let found_href = search_ns_by_href(doc, root, c_str("http://example.com"));
4869 assert_eq!(found_href, ns);
4870
4871 free_doc(doc);
4872 }
4873 }
4874
4875 #[test]
4883 fn test_new_dtd() {
4884 unsafe {
4885 let doc = new_doc(ptr::null());
4886 let dtd = new_dtd(doc, c_str("root"), c_str("-//TEST//DTD"), c_str("test.dtd"));
4887 assert!(!dtd.is_null());
4888 assert_eq!((*dtd).type_, XML_DTD_NODE as c_int);
4889 assert_eq!(get_int_subset(doc), dtd);
4890 free_doc(doc);
4891 }
4892 }
4893
4894 #[test]
4901 fn test_copy_node_deep() {
4902 unsafe {
4903 let doc = new_doc(ptr::null());
4904 let root = new_node(ptr::null_mut(), c_str("root"));
4905 doc_set_root_element(doc, root);
4906 let _child = new_child(root, ptr::null_mut(), c_str("child"));
4907
4908 let copy = copy_node(root, 1);
4909 assert!(!copy.is_null());
4910 assert_eq!((*copy).type_, XML_ELEMENT_NODE as c_int);
4911 assert!(!(*copy).children.is_null());
4913 assert_eq!((*(*copy).children).type_, XML_ELEMENT_NODE as c_int);
4914
4915 free_node(copy);
4916 free_doc(doc);
4917 }
4918 }
4919
4920 #[test]
4928 fn test_new_cdata_block() {
4929 unsafe {
4930 let doc = new_doc(ptr::null());
4931 let content = c_str("some <cdata> content");
4932 let cdata = new_cdata_block(doc, content, 20);
4933 assert!(!cdata.is_null());
4934 assert_eq!((*cdata).type_, XML_CDATA_SECTION_NODE as c_int);
4935 free_node(cdata);
4936 free_doc(doc);
4937 }
4938 }
4939
4940 #[test]
4949 fn test_null_handling() {
4950 unsafe {
4951 assert!(!new_doc(ptr::null()).is_null()); let doc = new_doc(ptr::null());
4953 assert!(!new_node(ptr::null_mut(), ptr::null()).is_null()); free_node(ptr::null_mut()); free_doc(ptr::null_mut()); unlink_node(ptr::null_mut()); assert!(add_child(ptr::null_mut(), ptr::null_mut()).is_null());
4958 assert!(add_sibling(ptr::null_mut(), ptr::null_mut()).is_null());
4959 free_doc(doc);
4960 }
4961 }
4962
4963 unsafe fn buf_eq_str(buf: *mut _xmlBuffer, expected: &str) -> bool {
4974 let content = io::buf_content(buf);
4975 if content.is_null() {
4976 return expected.is_empty();
4977 }
4978 let len = io::buf_length(buf) as usize;
4979 if len != expected.len() {
4980 return false;
4981 }
4982 let slice = unsafe { core::slice::from_raw_parts(content, len) };
4983 slice == expected.as_bytes()
4984 }
4985
4986 #[test]
4994 fn test_serialize_empty_document() {
4995 unsafe {
4996 let doc = new_doc(ptr::null());
4997 let buf = io::buf_create(-1);
4998 assert!(!buf.is_null());
4999
5000 let ret = doc_dump(buf, doc);
5001 assert!(ret >= 0);
5002
5003 let expected = "<?xml version=\"1.0\"?>\n";
5007 assert!(buf_eq_str(buf, expected));
5008
5009 io::buf_free(buf);
5010 free_doc(doc);
5011 }
5012 }
5013
5014 #[test]
5021 fn test_serialize_element_with_text() {
5022 unsafe {
5023 let doc = new_doc(ptr::null());
5024 let root = new_node(ptr::null_mut(), c_str("root"));
5025 doc_set_root_element(doc, root);
5026
5027 let text = new_text(c_str("hello world"));
5029 add_child(root, text);
5030
5031 let buf = io::buf_create(-1);
5032 assert!(!buf.is_null());
5033
5034 let ret = doc_dump(buf, doc);
5035 assert!(ret >= 0);
5036
5037 let expected = "<?xml version=\"1.0\"?>\n<root>hello world</root>\n";
5038 assert!(buf_eq_str(buf, expected));
5039
5040 io::buf_free(buf);
5041 free_doc(doc);
5042 }
5043 }
5044
5045 #[test]
5052 fn test_serialize_element_with_attributes() {
5053 unsafe {
5054 let doc = new_doc(ptr::null());
5055 let root = new_node(ptr::null_mut(), c_str("root"));
5056 doc_set_root_element(doc, root);
5057
5058 set_prop(root, c_str("id"), c_str("42"));
5059 set_prop(root, c_str("name"), c_str("test"));
5060
5061 let buf = io::buf_create(-1);
5062 assert!(!buf.is_null());
5063
5064 let ret = doc_dump(buf, doc);
5065 assert!(ret >= 0);
5066
5067 let expected = "<?xml version=\"1.0\"?>\n<root id=\"42\" name=\"test\"/>\n";
5068 assert!(buf_eq_str(buf, expected));
5069
5070 io::buf_free(buf);
5071 free_doc(doc);
5072 }
5073 }
5074
5075 #[test]
5082 fn test_serialize_nested_elements() {
5083 unsafe {
5084 let doc = new_doc(ptr::null());
5085 let root = new_node(ptr::null_mut(), c_str("root"));
5086 doc_set_root_element(doc, root);
5087
5088 let child = new_child(root, ptr::null_mut(), c_str("child"));
5089 let grandchild = new_child(child, ptr::null_mut(), c_str("gc"));
5090 let text = new_text(c_str("text"));
5091 add_child(grandchild, text);
5092
5093 let buf = io::buf_create(-1);
5094 assert!(!buf.is_null());
5095
5096 let ret = doc_dump(buf, doc);
5097 assert!(ret >= 0);
5098
5099 let expected = "<?xml version=\"1.0\"?>\n<root><child><gc>text</gc></child></root>\n";
5100 assert!(buf_eq_str(buf, expected));
5101
5102 io::buf_free(buf);
5103 free_doc(doc);
5104 }
5105 }
5106
5107 #[test]
5114 fn test_serialize_with_formatting() {
5115 unsafe {
5116 let doc = new_doc(ptr::null());
5117 let root = new_node(ptr::null_mut(), c_str("root"));
5118 doc_set_root_element(doc, root);
5119
5120 let child = new_child(root, ptr::null_mut(), c_str("child"));
5121 let text = new_text(c_str("text"));
5122 add_child(child, text);
5123
5124 let buf = io::buf_create(-1);
5125 assert!(!buf.is_null());
5126
5127 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
5128
5129 let expected = "<?xml version=\"1.0\"?>\n<root>\n <child>text</child>\n</root>\n";
5130 assert!(buf_eq_str(buf, expected));
5131
5132 io::buf_free(buf);
5133 free_doc(doc);
5134 }
5135 }
5136
5137 #[test]
5144 fn test_serialize_escape_ampersand() {
5145 unsafe {
5146 let doc = new_doc(ptr::null());
5147 let root = new_node(ptr::null_mut(), c_str("root"));
5148 doc_set_root_element(doc, root);
5149
5150 let text = new_text(c_str("a & b"));
5151 add_child(root, text);
5152
5153 let buf = io::buf_create(-1);
5154 assert!(!buf.is_null());
5155
5156 let ret = doc_dump(buf, doc);
5157 assert!(ret >= 0);
5158
5159 let expected = "<?xml version=\"1.0\"?>\n<root>a & b</root>\n";
5160 assert!(buf_eq_str(buf, expected));
5161
5162 io::buf_free(buf);
5163 free_doc(doc);
5164 }
5165 }
5166
5167 #[test]
5174 fn test_serialize_escape_angle_brackets() {
5175 unsafe {
5176 let doc = new_doc(ptr::null());
5177 let root = new_node(ptr::null_mut(), c_str("root"));
5178 doc_set_root_element(doc, root);
5179
5180 let text = new_text(c_str("x < y > z"));
5181 add_child(root, text);
5182
5183 let buf = io::buf_create(-1);
5184 assert!(!buf.is_null());
5185
5186 let ret = doc_dump(buf, doc);
5187 assert!(ret >= 0);
5188
5189 let expected = "<?xml version=\"1.0\"?>\n<root>x < y > z</root>\n";
5190 assert!(buf_eq_str(buf, expected));
5191
5192 io::buf_free(buf);
5193 free_doc(doc);
5194 }
5195 }
5196
5197 #[test]
5204 fn test_serialize_comment() {
5205 unsafe {
5206 let doc = new_doc(ptr::null());
5207 let root = new_node(ptr::null_mut(), c_str("root"));
5208 doc_set_root_element(doc, root);
5209
5210 let comment = new_comment(c_str("my comment"));
5211 add_child(root, comment);
5212
5213 let buf = io::buf_create(-1);
5214 assert!(!buf.is_null());
5215
5216 let ret = doc_dump(buf, doc);
5217 assert!(ret >= 0);
5218
5219 let expected = "<?xml version=\"1.0\"?>\n<root><!--my comment--></root>\n";
5220 assert!(buf_eq_str(buf, expected));
5221
5222 io::buf_free(buf);
5223 free_doc(doc);
5224 }
5225 }
5226
5227 #[test]
5234 fn test_serialize_pi() {
5235 unsafe {
5236 let doc = new_doc(ptr::null());
5237 let root = new_node(ptr::null_mut(), c_str("root"));
5238 doc_set_root_element(doc, root);
5239
5240 let pi = new_pi(
5241 c_str("xml-stylesheet"),
5242 c_str("href=\"style.xsl\" type=\"text/xsl\""),
5243 );
5244 add_child(root, pi);
5245
5246 let buf = io::buf_create(-1);
5247 assert!(!buf.is_null());
5248
5249 let ret = doc_dump(buf, doc);
5250 assert!(ret >= 0);
5251
5252 let expected = "<?xml version=\"1.0\"?>\n<root><?xml-stylesheet href=\"style.xsl\" type=\"text/xsl\"?></root>\n";
5253 assert!(buf_eq_str(buf, expected));
5254
5255 io::buf_free(buf);
5256 free_doc(doc);
5257 }
5258 }
5259
5260 #[test]
5267 fn test_serialize_self_closing() {
5268 unsafe {
5269 let doc = new_doc(ptr::null());
5270 let root = new_node(ptr::null_mut(), c_str("empty"));
5271 doc_set_root_element(doc, root);
5272
5273 let buf = io::buf_create(-1);
5274 assert!(!buf.is_null());
5275
5276 let ret = doc_dump(buf, doc);
5277 assert!(ret >= 0);
5278
5279 let expected = "<?xml version=\"1.0\"?>\n<empty/>\n";
5280 assert!(buf_eq_str(buf, expected));
5281
5282 io::buf_free(buf);
5283 free_doc(doc);
5284 }
5285 }
5286
5287 #[test]
5295 fn test_dump_node_to_string() {
5296 unsafe {
5297 let node = new_node(ptr::null_mut(), c_str("foo"));
5298 let text = new_text(c_str("bar"));
5299 add_child(node, text);
5300
5301 let result = dump_node(node);
5302 assert!(!result.is_null());
5303
5304 let len = xml_strlen(result);
5305 let slice = { core::slice::from_raw_parts(result, len as usize) };
5306 assert_eq!(slice, b"<foo>bar</foo>");
5307
5308 allocator::xmlFreeImpl(result as *mut c_void);
5309 free_node(node);
5310 }
5311 }
5312
5313 #[test]
5321 fn test_dump_doc_to_string() {
5322 unsafe {
5323 let doc = new_doc(ptr::null());
5324 let root = new_node(ptr::null_mut(), c_str("root"));
5325 doc_set_root_element(doc, root);
5326
5327 let result = dump_doc(doc);
5328 assert!(!result.is_null());
5329
5330 let len = xml_strlen(result);
5331 let slice = { core::slice::from_raw_parts(result, len as usize) };
5332 let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
5333 assert_eq!(slice, expected.as_bytes());
5334
5335 allocator::xmlFreeImpl(result as *mut c_void);
5336 free_doc(doc);
5337 }
5338 }
5339
5340 #[test]
5348 fn test_xmlDocDumpFormatMemory() {
5349 unsafe {
5350 let doc = new_doc(ptr::null());
5351 let root = new_node(ptr::null_mut(), c_str("root"));
5352 doc_set_root_element(doc, root);
5353
5354 let mut mem: *mut xmlChar = ptr::null_mut();
5355 let mut size: c_int = 0;
5356
5357 xmlDocDumpFormatMemory(doc, &mut mem, &mut size, 0);
5358
5359 assert!(!mem.is_null());
5360 assert!(size > 0);
5361
5362 let slice = { core::slice::from_raw_parts(mem, size as usize) };
5363 let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
5366 assert_eq!(slice, expected.as_bytes());
5367
5368 allocator::xmlFreeImpl(mem as *mut c_void);
5369 free_doc(doc);
5370 }
5371 }
5372
5373 #[test]
5380 fn test_serialize_escape_attribute() {
5381 unsafe {
5382 let doc = new_doc(ptr::null());
5383 let root = new_node(ptr::null_mut(), c_str("root"));
5384 doc_set_root_element(doc, root);
5385
5386 set_prop(root, c_str("desc"), c_str("a < b & c \"quoted\""));
5388
5389 let buf = io::buf_create(-1);
5390 assert!(!buf.is_null());
5391
5392 let ret = doc_dump(buf, doc);
5393 assert!(ret >= 0);
5394
5395 let expected =
5396 "<?xml version=\"1.0\"?>\n<root desc=\"a < b & c "quoted"\"/>\n";
5397 assert!(buf_eq_str(buf, expected));
5398
5399 io::buf_free(buf);
5400 free_doc(doc);
5401 }
5402 }
5403}