1use core::ffi::c_void;
93use core::ptr;
94use std::os::raw::{c_char, c_int, c_long, c_ulong};
95
96use crate::abi::allocator;
97use crate::abi::constants::*;
98use crate::abi::structs::*;
99use crate::abi::types::xmlCharEncoding::XML_CHAR_ENCODING_UTF8;
100use crate::abi::types::xmlDocProperties::XML_DOC_USERBUILT;
101use crate::abi::types::xmlElementType::*;
102use crate::abi::types::*;
103use crate::xml::io;
104
105unsafe fn dup_xml_str(str: *const xmlChar) -> *mut xmlChar {
115 if str.is_null() {
116 return ptr::null_mut();
117 }
118 let len = unsafe { crate::abi::exports_xml2::xmlStrlen(str) as usize };
119 if len == 0 {
120 let buf = unsafe { allocator::xmlMallocImpl(1) as *mut xmlChar };
122 if !buf.is_null() {
123 unsafe { *buf = 0 };
124 }
125 return buf;
126 }
127 let buf = unsafe { allocator::xmlMallocImpl(len + 1) as *mut xmlChar };
128 if !buf.is_null() {
129 unsafe {
130 ptr::copy_nonoverlapping(str, buf, len + 1);
131 }
132 }
133 buf
134}
135
136#[allow(dead_code)]
138unsafe fn copy_xml_str_content(dest: *mut xmlChar, src: *const xmlChar, max_len: usize) -> bool {
139 if src.is_null() || dest.is_null() || max_len == 0 {
140 return false;
141 }
142 let len = unsafe { crate::abi::exports_xml2::xmlStrlen(src) as usize };
143 if len >= max_len {
144 return false;
145 }
146 unsafe {
147 ptr::copy_nonoverlapping(src, dest, len);
148 *dest.add(len) = 0;
149 }
150 true
151}
152
153pub const unsafe fn xml_strlen(str: *const xmlChar) -> c_int {
170 if str.is_null() {
171 return 0;
172 }
173 let mut len: c_int = 0;
174 while unsafe { *str.add(len as usize) != 0 } {
175 len += 1;
176 }
177 len
178}
179
180pub unsafe fn new_doc(version: *const xmlChar) -> *mut _xmlDoc {
203 let doc = allocator::xmlMallocZero(size_of::<_xmlDoc>() as usize) as *mut _xmlDoc;
205 if doc.is_null() {
206 return ptr::null_mut();
207 }
208
209 unsafe {
210 (*doc).type_ = XML_DOCUMENT_NODE as c_int;
211 (*doc).standalone = -1; (*doc).doc = doc; (*doc).properties = XML_DOC_USERBUILT as c_int;
214 (*doc).compression = -1; (*doc).charset = XML_CHAR_ENCODING_UTF8 as c_int;
216
217 let ver = if version.is_null() {
219 XML_DEFAULT_VERSION.as_ptr() as *const xmlChar
220 } else {
221 version
222 };
223 (*doc).version = dup_xml_str(ver);
224 }
225
226 crate::abi::data_globals::register_node_hook(doc as *mut _xmlNode);
228
229 doc
230}
231
232pub unsafe fn free_doc(doc: *mut _xmlDoc) {
246 if doc.is_null() {
247 return;
248 }
249
250 crate::abi::data_globals::deregister_node_hook(doc as *mut _xmlNode);
253
254 let d = unsafe { &mut *doc };
255
256 let dict = d.dict;
260 let mut ext_subset = d.extSubset;
261 let int_subset = d.intSubset;
262 if !ext_subset.is_null() && ext_subset == int_subset {
263 ext_subset = ptr::null_mut();
264 }
265 if !ext_subset.is_null() {
266 unlink_node_internal(ext_subset as *mut _xmlNode, d as *mut _xmlDoc);
267 d.extSubset = ptr::null_mut();
268 free_dtd(ext_subset);
269 }
270 if !int_subset.is_null() {
271 unlink_node_internal(int_subset as *mut _xmlNode, d as *mut _xmlDoc);
272 d.intSubset = ptr::null_mut();
273 free_dtd(int_subset);
274 }
275
276 if !d.children.is_null() {
278 free_node_list(d.children);
279 }
280
281 if !d.oldNs.is_null() {
283 free_ns_list(d.oldNs);
284 }
285
286 if !d.version.is_null() {
288 allocator::xmlFreeImpl(d.version as *mut c_void);
289 }
290 if !d.encoding.is_null() {
291 allocator::xmlFreeImpl(d.encoding as *mut c_void);
292 }
293 if !d.URL.is_null() {
294 allocator::xmlFreeImpl(d.URL as *mut c_void);
295 }
296
297 allocator::xmlFreeImpl(doc as *mut c_void);
299
300 if !dict.is_null() {
302 crate::abi::exports_xml2::xmlDictFree(dict);
303 }
304}
305
306unsafe fn unlink_node_internal(node: *mut _xmlNode, _doc: *mut _xmlDoc) {
310 if node.is_null() {
311 return;
312 }
313 let parent = (*node).parent;
314 if parent.is_null() {
315 return;
316 }
317 if (*node).prev.is_null() {
318 (*parent).children = (*node).next;
319 } else {
320 (*(*node).prev).next = (*node).next;
321 }
322 if (*node).next.is_null() {
323 (*parent).last = (*node).prev;
324 } else {
325 (*(*node).next).prev = (*node).prev;
326 }
327 (*node).next = ptr::null_mut();
328 (*node).prev = ptr::null_mut();
329 (*node).parent = ptr::null_mut();
330}
331
332pub unsafe fn copy_doc(doc: *const _xmlDoc, recursive: c_int) -> *mut _xmlDoc {
347 if doc.is_null() {
348 return ptr::null_mut();
349 }
350
351 let d = unsafe { &*doc };
352
353 let new_doc = new_doc(d.version);
354 if new_doc.is_null() {
355 return ptr::null_mut();
356 }
357
358 unsafe {
359 (*new_doc).type_ = d.type_;
360 (*new_doc).standalone = d.standalone;
361 (*new_doc).encoding = dup_xml_str(d.encoding);
362 (*new_doc).URL = dup_xml_str(d.URL);
363 (*new_doc).charset = d.charset;
364 (*new_doc).properties = d.properties;
365
366 if !d.intSubset.is_null() {
371 let dtd_copy = crate::xml::dtd::copy_dtd(d.intSubset);
372 if !dtd_copy.is_null() {
373 (*new_doc).intSubset = dtd_copy;
374 }
375 }
376
377 if recursive != 0 && !d.children.is_null() {
378 (*new_doc).children = copy_node_list(d.children, recursive);
379 if !(*new_doc).children.is_null() {
380 (*(*new_doc).children).parent = ptr::null_mut(); (*(*new_doc).children).doc = new_doc;
382 propagate_doc((*new_doc).children, new_doc);
384 }
385 }
386 }
387
388 new_doc
389}
390
391pub unsafe fn doc_set_root_element(doc: *mut _xmlDoc, root: *mut _xmlNode) -> *mut _xmlNode {
407 if doc.is_null() {
408 return ptr::null_mut();
409 }
410
411 let d = unsafe { &mut *doc };
412
413 let old_root = doc_get_root_element(doc);
414
415 if !root.is_null() {
416 unsafe {
417 (*root).parent = ptr::null_mut();
418 (*root).doc = doc;
419 }
420 d.children = root;
421 d.last = root;
422 unsafe {
423 (*root).prev = ptr::null_mut();
424 (*root).next = ptr::null_mut();
425 }
426 } else {
427 d.children = ptr::null_mut();
428 d.last = ptr::null_mut();
429 }
430
431 old_root
432}
433
434pub fn doc_get_root_element(doc: *mut _xmlDoc) -> *mut _xmlNode {
445 if doc.is_null() {
446 return ptr::null_mut();
447 }
448
449 let d = unsafe { &*doc };
450 let mut cur = d.children;
451
452 while !cur.is_null() {
453 let node = unsafe { &*cur };
454 if node.type_ == XML_ELEMENT_NODE as c_int {
455 return cur;
456 }
457 cur = node.next;
458 }
459
460 ptr::null_mut()
461}
462
463pub fn get_line_no(node: *const _xmlNode) -> c_long {
473 unsafe { get_line_no_internal(node, 0) }
474}
475
476unsafe fn get_line_no_internal(node: *const _xmlNode, depth: c_int) -> c_long {
481 if depth >= 5 {
482 return -1;
483 }
484 if node.is_null() {
485 return -1;
486 }
487 let n = unsafe { &*node };
488 if n.type_ == XML_ELEMENT_NODE as c_int
489 || n.type_ == XML_TEXT_NODE as c_int
490 || n.type_ == XML_COMMENT_NODE as c_int
491 || n.type_ == XML_PI_NODE as c_int
492 {
493 if n.line == 65535 {
494 if n.type_ == XML_ELEMENT_NODE as c_int && !n.children.is_null() {
495 let r = unsafe { get_line_no_internal(n.children, depth + 1) };
496 if r != -1 {
497 return r;
498 }
499 }
500 if !n.next.is_null() {
501 let r = unsafe { get_line_no_internal(n.next, depth + 1) };
502 if r != -1 {
503 return r;
504 }
505 }
506 if !n.prev.is_null() {
507 let r = unsafe { get_line_no_internal(n.prev, depth + 1) };
508 if r != -1 {
509 return r;
510 }
511 }
512 }
513 n.line as c_long
514 } else if !n.prev.is_null()
515 && (unsafe { (*n.prev).type_ } == XML_ELEMENT_NODE as c_int
516 || unsafe { (*n.prev).type_ } == XML_TEXT_NODE as c_int
517 || unsafe { (*n.prev).type_ } == XML_COMMENT_NODE as c_int
518 || unsafe { (*n.prev).type_ } == XML_PI_NODE as c_int)
519 {
520 unsafe { get_line_no_internal(n.prev, depth + 1) }
521 } else if !n.parent.is_null() && unsafe { (*n.parent).type_ } == XML_ELEMENT_NODE as c_int {
522 unsafe { get_line_no_internal(n.parent, depth + 1) }
523 } else {
524 -1
525 }
526}
527
528pub unsafe fn node_get_content(node: *mut _xmlNode) -> *mut xmlChar {
563 if node.is_null() {
564 return ptr::null_mut();
565 }
566 let typ = (*node).type_;
567 let mut result: Vec<u8> = Vec::new();
568 match typ {
569 t if t == XML_TEXT_NODE as c_int
570 || t == XML_CDATA_SECTION_NODE as c_int
571 || t == XML_COMMENT_NODE as c_int
572 || t == XML_PI_NODE as c_int =>
573 {
574 if !(*node).content.is_null() {
575 let len = crate::abi::exports_xml2::xmlStrlen((*node).content);
576 result
577 .extend_from_slice(core::slice::from_raw_parts((*node).content, len as usize));
578 } else if t == XML_TEXT_NODE as c_int && !(*node).children.is_null() {
579 let mut child = (*node).children;
582 while !child.is_null() {
583 if !(*child).content.is_null() {
584 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
585 result.extend_from_slice(core::slice::from_raw_parts(
586 (*child).content,
587 len as usize,
588 ));
589 }
590 child = (*child).next;
591 }
592 }
593 }
594 t if t == XML_ATTRIBUTE_NODE as c_int => {
595 if !(*node).children.is_null() {
597 let child = (*node).children;
598 if !(*child).content.is_null() {
599 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
600 result.extend_from_slice(core::slice::from_raw_parts(
601 (*child).content,
602 len as usize,
603 ));
604 }
605 }
606 }
607 t if t == XML_ENTITY_REF_NODE as c_int => {
608 let name = (*node).name;
610 if !name.is_null() && !(*node).doc.is_null() {
611 let ent = crate::xml::tree::get_doc_entity((*node).doc, name);
612 if !ent.is_null() && !(*ent).content.is_null() {
613 let len = crate::abi::exports_xml2::xmlStrlen((*ent).content);
614 result.extend_from_slice(core::slice::from_raw_parts(
615 (*ent).content,
616 len as usize,
617 ));
618 }
619 }
620 }
621 t if t == XML_DOCUMENT_NODE as c_int || t == XML_HTML_DOCUMENT_NODE as c_int => {
622 let root = doc_get_root_element(node as *mut _xmlDoc);
623 if !root.is_null() {
624 let sub = node_get_content(root);
625 if !sub.is_null() {
626 let len = crate::abi::exports_xml2::xmlStrlen(sub);
627 result.extend_from_slice(core::slice::from_raw_parts(sub, len as usize));
628 allocator::xmlFreeImpl(sub as *mut c_void);
629 }
630 }
631 }
632 _ => {
633 let mut child = (*node).children;
638 while !child.is_null() {
639 let ctype = (*child).type_;
640 if ctype == XML_TEXT_NODE as c_int || ctype == XML_CDATA_SECTION_NODE as c_int {
641 if !(*child).content.is_null() {
642 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
643 result.extend_from_slice(core::slice::from_raw_parts(
644 (*child).content,
645 len as usize,
646 ));
647 }
648 } else if ctype == XML_ENTITY_REF_NODE as c_int
649 || ctype == XML_ELEMENT_NODE as c_int
650 {
651 let sub = node_get_content(child);
652 if !sub.is_null() {
653 let len = crate::abi::exports_xml2::xmlStrlen(sub);
654 result.extend_from_slice(core::slice::from_raw_parts(sub, len as usize));
655 allocator::xmlFreeImpl(sub as *mut c_void);
656 }
657 }
658 child = (*child).next;
659 }
660 }
661 }
662 let buf = allocator::xmlMallocImpl(result.len() + 1) as *mut xmlChar;
664 if buf.is_null() {
665 return ptr::null_mut();
666 }
667 if !result.is_empty() {
668 ptr::copy_nonoverlapping(result.as_ptr(), buf, result.len());
669 }
670 *buf.add(result.len()) = 0;
671 buf
672}
673
674pub unsafe fn new_node(ns: *mut _xmlNs, name: *const xmlChar) -> *mut _xmlNode {
693 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
694 if node.is_null() {
695 return ptr::null_mut();
696 }
697
698 unsafe {
699 (*node).type_ = XML_ELEMENT_NODE as c_int;
700 (*node).name = dup_xml_str(name);
701 (*node).ns = ns;
702 (*node).line = 0;
703 (*node).extra = 0;
704
705 if !ns.is_null() {
706 (*ns).context = node as *mut _xmlDoc;
707 }
708 }
709
710 crate::abi::data_globals::register_node_hook(node);
713
714 node
715}
716
717pub unsafe fn free_node(node: *mut _xmlNode) {
732 if node.is_null() {
733 return;
734 }
735
736 let n = unsafe { &mut *node };
737
738 if n.type_ == XML_DTD_NODE as c_int {
742 free_dtd(node as *mut _xmlDtd);
743 return;
744 } else if n.type_ == XML_NAMESPACE_DECL as c_int {
745 free_ns(node as *mut _xmlNs);
746 return;
747 } else if n.type_ == XML_ATTRIBUTE_NODE as c_int {
748 free_prop(node as *mut _xmlAttr);
749 return;
750 } else if n.type_ == XML_ELEMENT_DECL as c_int {
751 crate::xml::dtd::free_element(node as *mut _xmlElement);
752 return;
753 } else if n.type_ == XML_ATTRIBUTE_DECL as c_int {
754 crate::xml::dtd::free_attribute(node as *mut _xmlAttribute);
755 return;
756 } else if n.type_ == XML_ENTITY_DECL as c_int {
757 crate::xml::entities::free_entity(node as *mut _xmlEntity);
758 return;
759 }
760
761 crate::abi::data_globals::deregister_node_hook(node);
764
765 let is_element = n.type_ == XML_ELEMENT_NODE as c_int;
770 if is_element && !n.properties.is_null() {
771 free_prop_list(n.properties);
772 }
773
774 if is_element && !n.nsDef.is_null() {
775 free_ns_list(n.nsDef);
776 }
777
778 if !n.name.is_null() {
780 allocator::xmlFreeImpl(n.name as *mut c_void);
781 }
782
783 if !n.content.is_null() {
788 let node_type = n.type_;
789 if node_type == XML_TEXT_NODE as c_int
790 || node_type == XML_CDATA_SECTION_NODE as c_int
791 || node_type == XML_COMMENT_NODE as c_int
792 || node_type == XML_PI_NODE as c_int
793 {
794 let inline_addr = std::ptr::addr_of_mut!((*node).properties) as *const c_void;
795 if n.content as *const c_void != inline_addr {
796 allocator::xmlFreeImpl(n.content as *mut c_void);
797 }
798 }
799 }
800
801 allocator::xmlFreeImpl(node as *mut c_void);
802}
803
804pub unsafe fn free_node_list(node: *mut _xmlNode) {
823 let mut cur = node;
824 while !cur.is_null() {
825 let next = unsafe { (*cur).next };
826 let t = unsafe { (*cur).type_ };
827
828 if t == XML_DTD_NODE as c_int {
829 unsafe {
831 (*cur).prev = ptr::null_mut();
832 (*cur).next = ptr::null_mut();
833 }
834 cur = next;
835 continue;
836 }
837
838 if t != XML_ENTITY_REF_NODE as c_int && !unsafe { (*cur).children }.is_null() {
841 free_node_list(unsafe { (*cur).children });
842 }
843
844 free_node(cur);
845 cur = next;
846 }
847}
848
849unsafe fn free_prop_list(prop: *mut _xmlAttr) {
855 let mut cur = prop;
856 while !cur.is_null() {
857 let next = unsafe { (*cur).next };
858 free_prop(cur);
859 cur = next;
860 }
861}
862
863unsafe fn free_prop(prop: *mut _xmlAttr) {
869 if prop.is_null() {
870 return;
871 }
872
873 if !unsafe { (*prop).children }.is_null() {
875 free_node_list(unsafe { (*prop).children });
876 }
877
878 if !unsafe { (*prop).name }.is_null() {
880 allocator::xmlFreeImpl(unsafe { (*prop).name } as *mut c_void);
881 }
882
883 allocator::xmlFreeImpl(prop as *mut c_void);
884}
885
886unsafe fn free_ns_list(ns: *mut _xmlNs) {
892 let mut cur = ns;
893 while !cur.is_null() {
894 let next = unsafe { (*cur).next };
895 free_ns(cur);
896 cur = next;
897 }
898}
899
900unsafe fn free_ns(ns: *mut _xmlNs) {
906 if ns.is_null() {
907 return;
908 }
909
910 if !unsafe { (*ns).href }.is_null() {
912 allocator::xmlFreeImpl(unsafe { (*ns).href } as *mut c_void);
913 }
914 if !unsafe { (*ns).prefix }.is_null() {
915 allocator::xmlFreeImpl(unsafe { (*ns).prefix } as *mut c_void);
916 }
917
918 allocator::xmlFreeImpl(ns as *mut c_void);
919}
920
921pub unsafe fn copy_node(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
936 if node.is_null() {
937 return ptr::null_mut();
938 }
939
940 let n = unsafe { &*node };
941
942 let new_node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
943 if new_node.is_null() {
944 return ptr::null_mut();
945 }
946
947 unsafe {
948 (*new_node).type_ = n.type_;
949 (*new_node).name = dup_xml_str(n.name);
950 if n.type_ == XML_ELEMENT_NODE as c_int {
954 (*new_node).line = n.line;
955 }
956 (*new_node).extra = n.extra;
957 (*new_node).psvi = n.psvi;
958 (*new_node)._private = n._private;
959
960 (*new_node).ns = n.ns;
962
963 let is_element = n.type_ == XML_ELEMENT_NODE as c_int;
966 if is_element && !n.nsDef.is_null() {
967 (*new_node).nsDef = copy_ns_list(n.nsDef);
968 }
969
970 let node_type = n.type_;
972 if (node_type == XML_TEXT_NODE as c_int
973 || node_type == XML_CDATA_SECTION_NODE as c_int
974 || node_type == XML_COMMENT_NODE as c_int
975 || node_type == XML_PI_NODE as c_int)
976 && !n.content.is_null()
977 {
978 (*new_node).content = dup_xml_str(n.content);
979 }
980
981 if is_element && !n.properties.is_null() {
983 (*new_node).properties = copy_prop_list(n.properties);
984 let mut prop = (*new_node).properties;
986 while !prop.is_null() {
987 (*prop).parent = new_node;
988 if !(*prop).children.is_null() {
989 propagate_doc((*prop).children, (*new_node).doc);
990 }
991 prop = (*prop).next;
992 }
993 }
994
995 if recursive != 0 && !n.children.is_null() {
998 (*new_node).children = copy_node_list(n.children, recursive);
999 if !(*new_node).children.is_null() {
1000 let mut child = (*new_node).children;
1001 let mut last_child = child;
1002 while !child.is_null() {
1003 (*child).parent = new_node;
1004 (*child).doc = (*new_node).doc;
1005 propagate_doc(child, (*new_node).doc);
1006 if (*child).next.is_null() {
1007 last_child = child;
1008 }
1009 child = (*child).next;
1010 }
1011 (*new_node).last = last_child;
1012 }
1013 }
1014 }
1015
1016 new_node
1017}
1018
1019unsafe fn copy_node_list(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
1023 if node.is_null() {
1024 return ptr::null_mut();
1025 }
1026
1027 let n = unsafe { &*node };
1028 let new_node = copy_node(node, recursive);
1029 if new_node.is_null() {
1030 return ptr::null_mut();
1031 }
1032
1033 let mut prev = new_node;
1034 let mut cur = n.next;
1035
1036 while !cur.is_null() {
1037 let new_cur = copy_node(cur, recursive);
1038 if new_cur.is_null() {
1039 break;
1040 }
1041 unsafe {
1042 (*prev).next = new_cur;
1043 (*new_cur).prev = prev;
1044 }
1045 prev = new_cur;
1046 cur = unsafe { (*cur).next };
1047 }
1048
1049 new_node
1050}
1051
1052unsafe fn copy_ns_list(ns: *const _xmlNs) -> *mut _xmlNs {
1054 if ns.is_null() {
1055 return ptr::null_mut();
1056 }
1057
1058 let n = unsafe { &*ns };
1059 let new_ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
1060 if new_ns.is_null() {
1061 return ptr::null_mut();
1062 }
1063
1064 unsafe {
1065 (*new_ns).type_ = n.type_;
1066 (*new_ns).href = dup_xml_str(n.href);
1067 (*new_ns).prefix = dup_xml_str(n.prefix);
1068 (*new_ns)._private = n._private;
1069 }
1070
1071 let mut prev = new_ns;
1072 let mut cur = n.next;
1073
1074 while !cur.is_null() {
1075 let c = unsafe { &*cur };
1076 let new_cur = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
1077 if new_cur.is_null() {
1078 break;
1079 }
1080 unsafe {
1081 (*new_cur).type_ = c.type_;
1082 (*new_cur).href = dup_xml_str(c.href);
1083 (*new_cur).prefix = dup_xml_str(c.prefix);
1084 (*new_cur)._private = c._private;
1085 (*prev).next = new_cur;
1086 }
1087 prev = new_cur;
1088 cur = c.next;
1089 }
1090
1091 new_ns
1092}
1093
1094unsafe fn copy_prop_list(prop: *const _xmlAttr) -> *mut _xmlAttr {
1096 if prop.is_null() {
1097 return ptr::null_mut();
1098 }
1099
1100 let p = unsafe { &*prop };
1101 let new_prop = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
1102 if new_prop.is_null() {
1103 return ptr::null_mut();
1104 }
1105
1106 unsafe {
1107 (*new_prop).type_ = p.type_;
1108 (*new_prop).name = dup_xml_str(p.name);
1109 (*new_prop).ns = p.ns;
1110 (*new_prop).atype = p.atype;
1111
1112 if !p.children.is_null() {
1114 (*new_prop).children = copy_node_list(p.children, 1);
1115 if !(*new_prop).children.is_null() {
1116 (*(*new_prop).children).parent = new_prop as *mut _xmlNode;
1117 }
1118 }
1119 }
1120
1121 let mut prev = new_prop;
1122 let mut cur = p.next;
1123
1124 while !cur.is_null() {
1125 let c = unsafe { &*cur };
1126 let new_cur = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
1127 if new_cur.is_null() {
1128 break;
1129 }
1130 unsafe {
1131 (*new_cur).type_ = c.type_;
1132 (*new_cur).name = dup_xml_str(c.name);
1133 (*new_cur).ns = c.ns;
1134 (*new_cur).atype = c.atype;
1135
1136 if !c.children.is_null() {
1137 (*new_cur).children = copy_node_list(c.children, 1);
1138 if !(*new_cur).children.is_null() {
1139 (*(*new_cur).children).parent = new_cur as *mut _xmlNode;
1140 }
1141 }
1142
1143 (*prev).next = new_cur;
1144 }
1145 prev = new_cur;
1146 cur = c.next;
1147 }
1148
1149 new_prop
1150}
1151
1152unsafe fn propagate_doc(node: *mut _xmlNode, doc: *mut _xmlDoc) {
1154 let mut cur = node;
1155 while !cur.is_null() {
1156 unsafe {
1157 (*cur).doc = doc;
1158
1159 if (*cur).type_ == XML_ELEMENT_NODE as c_int {
1163 let mut prop = (*cur).properties;
1164 while !prop.is_null() {
1165 (*prop).doc = doc;
1166 if !(*prop).children.is_null() {
1167 propagate_doc((*prop).children, doc);
1168 }
1169 prop = (*prop).next;
1170 }
1171 }
1172
1173 if !(*cur).children.is_null() {
1175 propagate_doc((*cur).children, doc);
1176 }
1177 }
1178 cur = unsafe { (*cur).next };
1179 }
1180}
1181
1182pub unsafe fn unlink_node(node: *mut _xmlNode) {
1198 if node.is_null() {
1199 return;
1200 }
1201
1202 let n = unsafe { &mut *node };
1203
1204 let prev = n.prev;
1206 let next = n.next;
1207
1208 if !prev.is_null() {
1209 unsafe { (*prev).next = next };
1210 }
1211 if !next.is_null() {
1212 unsafe { (*next).prev = prev };
1213 }
1214
1215 let parent = n.parent;
1217 if !parent.is_null() {
1218 if unsafe { (*parent).children } == node {
1219 unsafe { (*parent).children = next };
1220 }
1221 if unsafe { (*parent).last } == node {
1222 unsafe { (*parent).last = prev };
1223 }
1224 }
1225
1226 let doc = n.doc;
1228 if !doc.is_null() && !parent.is_null() {
1229 }
1231 if !doc.is_null() && parent.is_null() {
1232 if unsafe { (*doc).children } == node {
1234 unsafe { (*doc).children = next };
1235 }
1236 if unsafe { (*doc).last } == node {
1237 unsafe { (*doc).last = prev };
1238 }
1239 }
1240
1241 n.parent = ptr::null_mut();
1243 n.prev = ptr::null_mut();
1244 n.next = ptr::null_mut();
1245}
1246
1247pub unsafe fn add_child(parent: *mut _xmlNode, cur: *mut _xmlNode) -> *mut _xmlNode {
1263 if parent.is_null() || cur.is_null() {
1264 return ptr::null_mut();
1265 }
1266
1267 let p = unsafe { &mut *parent };
1268 let c = unsafe { &mut *cur };
1269
1270 if !c.parent.is_null() || !c.prev.is_null() || !c.next.is_null() {
1272 unlink_node(cur);
1273 }
1274
1275 c.parent = parent;
1277
1278 if p.children.is_null() {
1279 p.children = cur;
1281 p.last = cur;
1282 c.prev = ptr::null_mut();
1283 c.next = ptr::null_mut();
1284 } else {
1285 c.prev = p.last;
1287 c.next = ptr::null_mut();
1288 if !p.last.is_null() {
1289 unsafe { (*p.last).next = cur };
1290 }
1291 p.last = cur;
1292 }
1293
1294 let doc = if !p.doc.is_null() {
1296 p.doc
1297 } else {
1298 ptr::null_mut()
1299 };
1300 if !doc.is_null() && c.doc != doc {
1301 propagate_doc(cur, doc);
1302 }
1303
1304 cur
1305}
1306
1307pub unsafe fn add_sibling(cur: *mut _xmlNode, elem: *mut _xmlNode) -> *mut _xmlNode {
1323 if cur.is_null() || elem.is_null() {
1324 return ptr::null_mut();
1325 }
1326
1327 let c = unsafe { &mut *cur };
1328
1329 let e = unsafe { &mut *elem };
1331 if !e.parent.is_null() || !e.prev.is_null() || !e.next.is_null() {
1332 unlink_node(elem);
1333 }
1334
1335 e.parent = c.parent;
1337
1338 e.prev = cur;
1340 e.next = c.next;
1341
1342 if !c.next.is_null() {
1343 unsafe { (*c.next).prev = elem };
1344 }
1345 c.next = elem;
1346
1347 let parent = c.parent;
1349 if !parent.is_null() && unsafe { (*parent).last } == cur {
1350 unsafe { (*parent).last = elem };
1351 }
1352
1353 if !c.doc.is_null() && e.doc != c.doc {
1355 propagate_doc(elem, c.doc);
1356 }
1357
1358 elem
1359}
1360
1361pub unsafe fn add_sibling_before(cur: *mut _xmlNode, elem: *mut _xmlNode) -> *mut _xmlNode {
1377 if cur.is_null() || elem.is_null() {
1378 return ptr::null_mut();
1379 }
1380
1381 let c = unsafe { &mut *cur };
1382
1383 let e = unsafe { &mut *elem };
1385 if !e.parent.is_null() || !e.prev.is_null() || !e.next.is_null() {
1386 unlink_node(elem);
1387 }
1388
1389 e.parent = c.parent;
1391
1392 e.prev = c.prev;
1394 e.next = cur;
1395
1396 if !c.prev.is_null() {
1397 unsafe { (*c.prev).next = elem };
1398 }
1399 c.prev = elem;
1400
1401 let parent = c.parent;
1403 if !parent.is_null() && unsafe { (*parent).children } == cur {
1404 unsafe { (*parent).children = elem };
1405 }
1406
1407 let doc = c.doc;
1409 if !doc.is_null() && parent.is_null() && unsafe { (*doc).children } == cur {
1410 unsafe { (*doc).children = elem };
1411 }
1412
1413 if !c.doc.is_null() && e.doc != c.doc {
1415 propagate_doc(elem, c.doc);
1416 }
1417
1418 elem
1419}
1420
1421pub unsafe fn new_child(
1436 parent: *mut _xmlNode,
1437 ns: *mut _xmlNs,
1438 name: *const xmlChar,
1439) -> *mut _xmlNode {
1440 let node = new_node(ns, name);
1441 if node.is_null() {
1442 return ptr::null_mut();
1443 }
1444
1445 if !parent.is_null() {
1446 add_child(parent, node);
1447 }
1448
1449 node
1450}
1451
1452pub unsafe fn new_text(content: *const xmlChar) -> *mut _xmlNode {
1471 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1472 if node.is_null() {
1473 return ptr::null_mut();
1474 }
1475
1476 unsafe {
1477 (*node).type_ = XML_TEXT_NODE as c_int;
1478 (*node).name = dup_xml_str(b"text\0" as *const u8 as *const xmlChar);
1479 (*node).content = if content.is_null() {
1480 let empty = allocator::xmlMallocImpl(1) as *mut xmlChar;
1481 if !empty.is_null() {
1482 *empty = 0;
1483 }
1484 empty
1485 } else {
1486 dup_xml_str(content)
1487 };
1488 (*node).line = 0;
1489 }
1490
1491 crate::abi::data_globals::register_node_hook(node);
1494
1495 node
1496}
1497
1498pub unsafe fn new_comment(content: *const xmlChar) -> *mut _xmlNode {
1512 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1513 if node.is_null() {
1514 return ptr::null_mut();
1515 }
1516
1517 unsafe {
1518 (*node).type_ = XML_COMMENT_NODE as c_int;
1519 (*node).name = dup_xml_str(b"comment\0" as *const u8 as *const xmlChar);
1520 (*node).content = dup_xml_str(content);
1521 (*node).line = 0;
1522 }
1523
1524 crate::abi::data_globals::register_node_hook(node);
1527
1528 node
1529}
1530
1531pub unsafe fn new_pi(name: *const xmlChar, content: *const xmlChar) -> *mut _xmlNode {
1546 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1547 if node.is_null() {
1548 return ptr::null_mut();
1549 }
1550
1551 unsafe {
1552 (*node).type_ = XML_PI_NODE as c_int;
1553 (*node).name = dup_xml_str(name);
1554 (*node).content = dup_xml_str(content);
1555 (*node).line = 0;
1556 }
1557
1558 crate::abi::data_globals::register_node_hook(node);
1561
1562 node
1563}
1564
1565pub unsafe fn new_cdata_block(
1581 doc: *mut _xmlDoc,
1582 content: *const xmlChar,
1583 len: c_int,
1584) -> *mut _xmlNode {
1585 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1586 if node.is_null() {
1587 return ptr::null_mut();
1588 }
1589
1590 unsafe {
1591 (*node).type_ = XML_CDATA_SECTION_NODE as c_int;
1592 (*node).doc = doc;
1595
1596 if !content.is_null() && len > 0 {
1597 (*node).content = allocator::xmlMallocImpl((len + 1) as usize) as *mut xmlChar;
1598 if !(*node).content.is_null() {
1599 ptr::copy_nonoverlapping(content, (*node).content, len as usize);
1600 *((*node).content.add(len as usize)) = 0;
1601 }
1602 } else {
1603 let empty = allocator::xmlMallocImpl(1) as *mut xmlChar;
1604 if !empty.is_null() {
1605 *empty = 0;
1606 }
1607 (*node).content = empty;
1608 }
1609
1610 (*node).line = 0;
1611 }
1612
1613 node
1614}
1615
1616pub unsafe fn new_ns(
1640 node: *mut _xmlNode,
1641 href: *const xmlChar,
1642 prefix: *const xmlChar,
1643) -> *mut _xmlNs {
1644 let ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
1645 if ns.is_null() {
1646 return ptr::null_mut();
1647 }
1648
1649 unsafe {
1650 (*ns).type_ = XML_LOCAL_NAMESPACE as c_int;
1651 (*ns).href = dup_xml_str(href);
1652 (*ns).prefix = dup_xml_str(prefix);
1653 (*ns).context = node as *mut _xmlDoc;
1654
1655 if !node.is_null() {
1657 let n = &mut *node;
1658 if n.nsDef.is_null() {
1659 n.nsDef = ns;
1660 } else {
1661 let mut last = n.nsDef;
1663 while !(*last).next.is_null() {
1664 last = (*last).next;
1665 }
1666 (*last).next = ns;
1667 }
1668 }
1669 }
1670
1671 ns
1672}
1673
1674pub unsafe fn set_ns(node: *mut _xmlNode, ns: *mut _xmlNs) {
1687 if node.is_null() {
1688 return;
1689 }
1690 unsafe {
1691 (*node).ns = ns;
1692 }
1693}
1694
1695pub unsafe fn get_ns_list(_doc: *mut _xmlDoc, node: *mut _xmlNode) -> *mut *mut _xmlNs {
1711 if node.is_null() {
1715 return ptr::null_mut();
1716 }
1717
1718 let mut ns_ptrs: Vec<*mut _xmlNs> = Vec::new();
1720 let mut cur = node;
1721
1722 while !cur.is_null() {
1723 let n = unsafe { &*cur };
1724 let mut ns_def = n.nsDef;
1725 while !ns_def.is_null() {
1726 let ns = unsafe { &*ns_def };
1728 let mut found = false;
1729 for &existing in &ns_ptrs {
1730 if existing == ns_def {
1731 found = true;
1732 break;
1733 }
1734 let e = unsafe { &*existing };
1735 if !ns.href.is_null() && !e.href.is_null() {
1736 let href_match =
1737 unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, e.href) != 0 };
1738 if href_match {
1739 if ns.prefix.is_null() && e.prefix.is_null() {
1740 found = true;
1741 break;
1742 }
1743 if !ns.prefix.is_null() && !e.prefix.is_null() {
1744 let prefix_match = unsafe {
1745 crate::abi::exports_xml2::xmlStrEqual(ns.prefix, e.prefix) != 0
1746 };
1747 if prefix_match {
1748 found = true;
1749 break;
1750 }
1751 }
1752 }
1753 }
1754 }
1755 if !found {
1756 ns_ptrs.push(ns_def);
1757 }
1758 ns_def = unsafe { (*ns_def).next };
1759 }
1760 cur = n.parent;
1761 }
1762
1763 if ns_ptrs.is_empty() {
1764 return ptr::null_mut();
1765 }
1766
1767 let arr = allocator::xmlMallocImpl((ns_ptrs.len() + 1) * size_of::<*mut _xmlNs>())
1769 as *mut *mut _xmlNs;
1770 if arr.is_null() {
1771 return ptr::null_mut();
1772 }
1773
1774 for (i, ns) in ns_ptrs.iter().enumerate() {
1775 unsafe { *arr.add(i) = *ns };
1776 }
1777 unsafe { *arr.add(ns_ptrs.len()) = ptr::null_mut() };
1778
1779 arr
1780}
1781
1782pub unsafe fn search_ns(
1799 _doc: *mut _xmlDoc,
1800 node: *mut _xmlNode,
1801 name_space: *const xmlChar,
1802) -> *mut _xmlNs {
1803 if node.is_null() {
1804 return ptr::null_mut();
1805 }
1806
1807 let mut cur = node;
1808 while !cur.is_null() {
1809 let n = unsafe { &*cur };
1810 let mut ns_def = n.nsDef;
1811 while !ns_def.is_null() {
1812 let ns = unsafe { &*ns_def };
1813 let match_prefix = if name_space.is_null() {
1814 ns.prefix.is_null()
1816 } else {
1817 !ns.prefix.is_null()
1818 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.prefix, name_space) != 0 }
1819 };
1820 if match_prefix {
1821 return ns_def;
1822 }
1823 ns_def = unsafe { (*ns_def).next };
1824 }
1825 cur = n.parent;
1826 }
1827
1828 ptr::null_mut()
1829}
1830
1831pub unsafe fn search_ns_by_href(
1847 _doc: *mut _xmlDoc,
1848 node: *mut _xmlNode,
1849 href: *const xmlChar,
1850) -> *mut _xmlNs {
1851 if node.is_null() || href.is_null() {
1852 return ptr::null_mut();
1853 }
1854
1855 let mut cur = node;
1856 while !cur.is_null() {
1857 let n = unsafe { &*cur };
1858 let mut ns_def = n.nsDef;
1859 while !ns_def.is_null() {
1860 let ns = unsafe { &*ns_def };
1861 if !ns.href.is_null()
1862 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, href) != 0 }
1863 {
1864 return ns_def;
1865 }
1866 ns_def = unsafe { (*ns_def).next };
1867 }
1868 cur = n.parent;
1869 }
1870
1871 ptr::null_mut()
1872}
1873
1874pub unsafe fn set_prop(
1898 node: *mut _xmlNode,
1899 name: *const xmlChar,
1900 value: *const xmlChar,
1901) -> *mut _xmlAttr {
1902 if node.is_null() || name.is_null() {
1903 return ptr::null_mut();
1904 }
1905
1906 let n = unsafe { &mut *node };
1907
1908 let mut existing = n.properties;
1910 while !existing.is_null() {
1911 let attr = unsafe { &*existing };
1912 if !attr.name.is_null()
1913 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1914 {
1915 if !attr.children.is_null() {
1918 free_node_list(attr.children);
1919 let attr_mut = existing;
1921 unsafe { (*attr_mut).children = ptr::null_mut() };
1922 unsafe { (*attr_mut).last = ptr::null_mut() };
1923 }
1924 if !value.is_null() {
1926 let text = new_text(value);
1927 if !text.is_null() {
1928 let attr_mut = existing;
1929 unsafe {
1930 (*attr_mut).children = text;
1931 (*attr_mut).last = text;
1932 (*text).parent = existing as *mut _xmlNode;
1933 (*text).doc = n.doc;
1934 }
1935 }
1936 }
1937 return existing;
1938 }
1939 existing = unsafe { (*existing).next };
1940 }
1941
1942 let attr = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
1944 if attr.is_null() {
1945 return ptr::null_mut();
1946 }
1947
1948 unsafe {
1949 (*attr).type_ = XML_ATTRIBUTE_NODE as c_int;
1950 (*attr).name = dup_xml_str(name);
1951 (*attr).parent = node;
1952 (*attr).doc = n.doc;
1953 if !value.is_null() {
1958 let text = new_text(value);
1959 if !text.is_null() {
1960 (*attr).children = text;
1961 (*attr).last = text;
1962 (*text).parent = attr as *mut _xmlNode;
1963 (*text).doc = n.doc;
1964 }
1965 }
1966
1967 if n.properties.is_null() {
1969 n.properties = attr;
1970 } else {
1971 let mut last = n.properties;
1972 while !(*last).next.is_null() {
1973 last = (*last).next;
1974 }
1975 (*last).next = attr;
1976 (*attr).prev = last;
1977 }
1978 }
1979
1980 attr
1981}
1982
1983pub unsafe fn get_prop(node: *mut _xmlNode, name: *const xmlChar) -> *mut xmlChar {
1999 if node.is_null() || name.is_null() {
2000 return ptr::null_mut();
2001 }
2002
2003 let n = unsafe { &*node };
2004 let mut cur = n.properties;
2005
2006 while !cur.is_null() {
2007 let attr = unsafe { &*cur };
2008 if !attr.name.is_null()
2009 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
2010 {
2011 if !attr.children.is_null() {
2013 let text = unsafe { &*attr.children };
2014 if text.type_ == XML_TEXT_NODE as c_int && !text.content.is_null() {
2015 return dup_xml_str(text.content);
2016 }
2017 }
2018 return dup_xml_str(b"\0" as *const u8 as *const xmlChar);
2019 }
2020 cur = unsafe { (*cur).next };
2021 }
2022
2023 ptr::null_mut()
2024}
2025
2026pub unsafe fn get_ns_prop(
2042 node: *mut _xmlNode,
2043 name: *const xmlChar,
2044 _name_space: *const xmlChar,
2045) -> *mut xmlChar {
2046 get_prop(node, name)
2049}
2050
2051pub unsafe fn set_ns_prop(
2066 node: *mut _xmlNode,
2067 _ns: *mut _xmlNs,
2068 name: *const xmlChar,
2069 value: *const xmlChar,
2070) -> *mut _xmlAttr {
2071 set_prop(node, name, value)
2073}
2074
2075pub unsafe fn remove_prop(attr: *mut _xmlAttr) -> c_int {
2090 if attr.is_null() {
2091 return -1;
2092 }
2093
2094 let a = unsafe { &mut *attr };
2095
2096 let parent = a.parent;
2098 if !parent.is_null() {
2099 let p = unsafe { &mut *parent };
2100 if p.properties == attr {
2101 p.properties = a.next;
2102 }
2103 }
2104
2105 if !a.prev.is_null() {
2107 unsafe { (*a.prev).next = a.next };
2108 }
2109 if !a.next.is_null() {
2110 unsafe { (*a.next).prev = a.prev };
2111 }
2112
2113 if !a.children.is_null() {
2115 free_node_list(a.children);
2116 }
2117
2118 if !a.name.is_null() {
2120 allocator::xmlFreeImpl(a.name as *mut c_void);
2121 }
2122
2123 allocator::xmlFreeImpl(attr as *mut c_void);
2124 0
2125}
2126
2127pub unsafe fn has_prop(node: *mut _xmlNode, name: *const xmlChar) -> *mut _xmlAttr {
2135 if node.is_null() || name.is_null() {
2136 return ptr::null_mut();
2137 }
2138 let mut cur = unsafe { (*node).properties };
2139 while !cur.is_null() {
2140 let attr = unsafe { &*cur };
2141 if !attr.name.is_null()
2142 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
2143 && attr.ns.is_null()
2144 {
2145 return cur;
2146 }
2147 cur = unsafe { (*cur).next };
2148 }
2149 ptr::null_mut()
2150}
2151
2152pub unsafe fn has_ns_prop(
2162 node: *mut _xmlNode,
2163 name: *const xmlChar,
2164 name_space: *const xmlChar,
2165) -> *mut _xmlAttr {
2166 if node.is_null() || name.is_null() {
2167 return ptr::null_mut();
2168 }
2169 let mut cur = unsafe { (*node).properties };
2170 while !cur.is_null() {
2171 let attr = unsafe { &*cur };
2172 if !attr.name.is_null()
2173 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
2174 {
2175 if name_space.is_null() {
2176 if attr.ns.is_null() {
2177 return cur;
2178 }
2179 } else if !attr.ns.is_null()
2180 && !(*attr.ns).href.is_null()
2181 && unsafe {
2182 crate::abi::exports_xml2::xmlStrEqual((*attr.ns).href, name_space) != 0
2183 }
2184 {
2185 return cur;
2186 }
2187 }
2188 cur = unsafe { (*cur).next };
2189 }
2190 ptr::null_mut()
2191}
2192
2193pub unsafe fn unset_prop(node: *mut _xmlNode, name: *const xmlChar) -> c_int {
2202 let attr = unsafe { has_prop(node, name) };
2203 if attr.is_null() {
2204 return -1;
2205 }
2206 unsafe { remove_prop(attr) }
2207}
2208
2209pub unsafe fn unset_ns_prop(
2217 node: *mut _xmlNode,
2218 name: *const xmlChar,
2219 name_space: *const xmlChar,
2220) -> c_int {
2221 let attr = unsafe { has_ns_prop(node, name, name_space) };
2222 if attr.is_null() {
2223 return -1;
2224 }
2225 unsafe { remove_prop(attr) }
2226}
2227
2228pub unsafe fn first_element_child(node: *mut _xmlNode) -> *mut _xmlNode {
2235 if node.is_null() {
2236 return ptr::null_mut();
2237 }
2238 let mut cur = unsafe { (*node).children };
2239 while !cur.is_null() {
2240 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2241 return cur;
2242 }
2243 cur = unsafe { (*cur).next };
2244 }
2245 ptr::null_mut()
2246}
2247
2248pub unsafe fn last_element_child(node: *mut _xmlNode) -> *mut _xmlNode {
2255 if node.is_null() {
2256 return ptr::null_mut();
2257 }
2258 let mut cur = unsafe { (*node).last };
2259 while !cur.is_null() {
2260 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2261 return cur;
2262 }
2263 cur = unsafe { (*cur).prev };
2264 }
2265 ptr::null_mut()
2266}
2267
2268pub unsafe fn next_element_sibling(node: *mut _xmlNode) -> *mut _xmlNode {
2275 if node.is_null() {
2276 return ptr::null_mut();
2277 }
2278 let mut cur = unsafe { (*node).next };
2279 while !cur.is_null() {
2280 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2281 return cur;
2282 }
2283 cur = unsafe { (*cur).next };
2284 }
2285 ptr::null_mut()
2286}
2287
2288pub unsafe fn previous_element_sibling(node: *mut _xmlNode) -> *mut _xmlNode {
2295 if node.is_null() {
2296 return ptr::null_mut();
2297 }
2298 let mut cur = unsafe { (*node).prev };
2299 while !cur.is_null() {
2300 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2301 return cur;
2302 }
2303 cur = unsafe { (*cur).prev };
2304 }
2305 ptr::null_mut()
2306}
2307
2308pub unsafe fn child_element_count(node: *mut _xmlNode) -> c_ulong {
2315 if node.is_null() {
2316 return 0;
2317 }
2318 let mut cur = unsafe { (*node).children };
2319 let mut count: c_ulong = 0;
2320 while !cur.is_null() {
2321 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2322 count += 1;
2323 }
2324 cur = unsafe { (*cur).next };
2325 }
2326 count
2327}
2328
2329pub unsafe fn text_concat(node: *mut _xmlNode, str: *const xmlChar, num: c_int) -> c_int {
2338 if node.is_null() || str.is_null() || num <= 0 {
2339 return -1;
2340 }
2341 let cur = unsafe { &mut *node };
2342 if cur.content.is_null() {
2343 let p = unsafe { allocator::xmlMallocImpl(num as usize + 1) as *mut xmlChar };
2344 if p.is_null() {
2345 return -1;
2346 }
2347 unsafe {
2348 ptr::copy_nonoverlapping(str, p, num as usize);
2349 *p.add(num as usize) = 0;
2350 }
2351 cur.content = p;
2352 return 0;
2353 }
2354 let old_len = unsafe { crate::xml::string::xml_strlen(cur.content) };
2355 let p = unsafe {
2356 allocator::xmlReallocImpl(cur.content as *mut c_void, old_len + num as usize + 1)
2357 as *mut xmlChar
2358 };
2359 if p.is_null() {
2360 return -1;
2361 }
2362 unsafe {
2363 ptr::copy_nonoverlapping(str, p.add(old_len), num as usize);
2364 *p.add(old_len + num as usize) = 0;
2365 }
2366 cur.content = p;
2367 0
2368}
2369
2370pub unsafe fn text_merge(text: *mut _xmlNode, ntext: *mut _xmlNode) -> *mut _xmlNode {
2378 if text.is_null() || ntext.is_null() {
2379 return ptr::null_mut();
2380 }
2381 if unsafe { (*ntext).content.is_null() } {
2382 unsafe { free_node(ntext) };
2383 return text;
2384 }
2385 let num = unsafe { crate::xml::string::xml_strlen((*ntext).content) };
2386 if unsafe { text_concat(text, (*ntext).content, num as c_int) } != 0 {
2387 return ptr::null_mut();
2388 }
2389 unsafe { free_node(ntext) };
2390 text
2391}
2392
2393pub const fn get_int_subset(doc: *const _xmlDoc) -> *mut _xmlDtd {
2405 if doc.is_null() {
2406 return ptr::null_mut();
2407 }
2408 let d = unsafe { &*doc };
2409 d.intSubset
2410}
2411
2412pub unsafe fn new_dtd(
2429 doc: *mut _xmlDoc,
2430 name: *const xmlChar,
2431 ExternalID: *const xmlChar,
2432 SystemID: *const xmlChar,
2433) -> *mut _xmlDtd {
2434 let dtd = allocator::xmlMallocZero(size_of::<_xmlDtd>() as usize) as *mut _xmlDtd;
2435 if dtd.is_null() {
2436 return ptr::null_mut();
2437 }
2438
2439 unsafe {
2440 (*dtd).type_ = XML_DTD_NODE as c_int;
2441 (*dtd).name = dup_xml_str(name);
2442 (*dtd).ExternalID = dup_xml_str(ExternalID);
2443 (*dtd).SystemID = dup_xml_str(SystemID);
2444 (*dtd).parent = doc;
2445 (*dtd).doc = doc;
2446
2447 if !doc.is_null() && (*doc).intSubset.is_null() {
2453 (*doc).intSubset = dtd;
2454 }
2455 }
2456
2457 dtd
2458}
2459
2460unsafe fn free_dtd(dtd: *mut _xmlDtd) {
2466 if dtd.is_null() {
2467 return;
2468 }
2469
2470 let _d = unsafe { &mut *dtd };
2471 let d = &mut *dtd;
2472
2473 if !d.children.is_null() {
2480 let mut c = d.children;
2481 while !c.is_null() {
2482 let next = (*c).next;
2483 let t = (*c).type_;
2484 if t != XML_ELEMENT_DECL as c_int
2485 && t != XML_ATTRIBUTE_DECL as c_int
2486 && t != XML_ENTITY_DECL as c_int
2487 {
2488 unlink_node_internal(c, ptr::null_mut());
2489 free_node(c);
2490 }
2491 c = next;
2492 }
2493 }
2494
2495 if !d.name.is_null() {
2497 allocator::xmlFreeImpl(d.name as *mut c_void);
2498 }
2499 if !d.ExternalID.is_null() {
2500 allocator::xmlFreeImpl(d.ExternalID as *mut c_void);
2501 }
2502 if !d.SystemID.is_null() {
2503 allocator::xmlFreeImpl(d.SystemID as *mut c_void);
2504 }
2505
2506 unsafe extern "C" fn free_notation_wrapper(payload: *mut c_void, _name: *mut u8) {
2508 crate::xml::dtd::free_notation(payload as *mut _xmlNotation);
2509 }
2510 unsafe extern "C" fn free_element_wrapper(payload: *mut c_void, _name: *mut u8) {
2511 crate::xml::dtd::free_element(payload as *mut _xmlElement);
2512 }
2513 unsafe extern "C" fn free_attribute_wrapper(payload: *mut c_void, _name: *mut u8) {
2514 crate::xml::dtd::free_attribute(payload as *mut _xmlAttribute);
2515 }
2516 unsafe extern "C" fn free_entity_wrapper(payload: *mut c_void, _name: *mut u8) {
2517 crate::xml::entities::free_entity(payload as *mut _xmlEntity);
2518 }
2519
2520 if !d.notations.is_null() {
2521 crate::xml::hash::hash_free(
2522 d.notations as *mut crate::xml::hash::HashTable,
2523 Some(free_notation_wrapper),
2524 );
2525 d.notations = ptr::null_mut();
2526 }
2527 if !d.elements.is_null() {
2528 crate::xml::hash::hash_free(
2529 d.elements as *mut crate::xml::hash::HashTable,
2530 Some(free_element_wrapper),
2531 );
2532 d.elements = ptr::null_mut();
2533 }
2534 if !d.attributes.is_null() {
2535 crate::xml::hash::hash_free(
2536 d.attributes as *mut crate::xml::hash::HashTable,
2537 Some(free_attribute_wrapper),
2538 );
2539 d.attributes = ptr::null_mut();
2540 }
2541 if !d.entities.is_null() {
2542 crate::xml::hash::hash_free(
2543 d.entities as *mut crate::xml::hash::HashTable,
2544 Some(free_entity_wrapper),
2545 );
2546 d.entities = ptr::null_mut();
2547 }
2548 if !d.pentities.is_null() {
2549 crate::xml::hash::hash_free(
2550 d.pentities as *mut crate::xml::hash::HashTable,
2551 Some(free_entity_wrapper),
2552 );
2553 d.pentities = ptr::null_mut();
2554 }
2555
2556 allocator::xmlFreeImpl(dtd as *mut c_void);
2557}
2558
2559pub unsafe fn new_entity(
2579 _doc: *mut _xmlDoc,
2580 name: *const xmlChar,
2581 etype: c_int,
2582 ExternalID: *const xmlChar,
2583 SystemID: *const xmlChar,
2584 content: *const xmlChar,
2585) -> *mut _xmlEntity {
2586 let entity = allocator::xmlMallocZero(size_of::<_xmlEntity>() as usize) as *mut _xmlEntity;
2587 if entity.is_null() {
2588 return ptr::null_mut();
2589 }
2590
2591 unsafe {
2592 (*entity).type_ = XML_ENTITY_DECL as c_int;
2593 (*entity).name = dup_xml_str(name);
2594 (*entity).etype = etype;
2595 (*entity).ExternalID = dup_xml_str(ExternalID);
2596 (*entity).SystemID = dup_xml_str(SystemID);
2597 (*entity).content = dup_xml_str(content);
2598 (*entity).length = if content.is_null() {
2599 0
2600 } else {
2601 crate::abi::exports_xml2::xmlStrlen(content)
2602 };
2603 (*entity).flags = 0;
2604 (*entity).expandedSize = 0;
2605 }
2606
2607 entity
2608}
2609
2610pub unsafe fn get_doc_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2625 crate::xml::entities::get_entity(doc as *mut _xmlDoc, name)
2626}
2627
2628pub unsafe fn add_doc_entity(
2636 doc: *mut _xmlDoc,
2637 name: *const xmlChar,
2638 etype: c_int,
2639 ExternalID: *const xmlChar,
2640 SystemID: *const xmlChar,
2641 content: *const xmlChar,
2642) -> *mut _xmlEntity {
2643 if doc.is_null() || name.is_null() {
2644 return ptr::null_mut();
2645 }
2646 unsafe {
2647 let mut dtd = (*doc).intSubset;
2648 if dtd.is_null() {
2649 dtd = new_dtd(
2650 doc,
2651 c"internal".as_ptr() as *const xmlChar,
2652 ptr::null(),
2653 ptr::null(),
2654 );
2655 if dtd.is_null() {
2656 return ptr::null_mut();
2657 }
2658 }
2659 crate::xml::entities::add_entity(dtd, name, etype, ExternalID, SystemID, content)
2660 }
2661}
2662
2663pub unsafe fn add_dtd_entity(
2671 doc: *mut _xmlDoc,
2672 name: *const xmlChar,
2673 etype: c_int,
2674 ExternalID: *const xmlChar,
2675 SystemID: *const xmlChar,
2676 content: *const xmlChar,
2677) -> *mut _xmlEntity {
2678 if doc.is_null() || name.is_null() {
2679 return ptr::null_mut();
2680 }
2681 unsafe {
2682 let mut dtd = (*doc).extSubset;
2683 if dtd.is_null() {
2684 dtd = new_dtd(
2685 doc,
2686 c"internal".as_ptr() as *const xmlChar,
2687 ptr::null(),
2688 ptr::null(),
2689 );
2690 if dtd.is_null() {
2691 return ptr::null_mut();
2692 }
2693 (*doc).extSubset = dtd;
2694 }
2695 crate::xml::entities::add_entity(dtd, name, etype, ExternalID, SystemID, content)
2696 }
2697}
2698
2699pub unsafe fn get_dtd_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2707 if doc.is_null() || name.is_null() {
2708 return ptr::null_mut();
2709 }
2710 unsafe {
2711 if !(*doc).intSubset.is_null() {
2712 let e = crate::xml::entities::get_entity_from_dtd((*doc).intSubset, name);
2713 if !e.is_null() {
2714 return e;
2715 }
2716 }
2717 if !(*doc).extSubset.is_null() {
2718 return crate::xml::entities::get_entity_from_dtd((*doc).extSubset, name);
2719 }
2720 ptr::null_mut()
2721 }
2722}
2723
2724pub unsafe fn get_parameter_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2737 crate::xml::entities::get_parameter_entity(doc as *mut _xmlDoc, name)
2738}
2739
2740const ENTITY_LT: &[xmlChar] = b"<";
2749const ENTITY_GT: &[xmlChar] = b">";
2750const ENTITY_AMP: &[xmlChar] = b"&";
2751const ENTITY_QUOT: &[xmlChar] = b""";
2752#[allow(dead_code)]
2753const ENTITY_APOS: &[xmlChar] = b"'";
2754
2755const INDENT: &[xmlChar] = b" ";
2757
2758const MAX_INDENT: c_int = 60;
2760
2761pub(crate) unsafe fn serialize_text(buf: *mut _xmlBuffer, content: *const xmlChar, len: c_int) {
2776 if buf.is_null() || content.is_null() || len <= 0 {
2777 return;
2778 }
2779
2780 let mut i: c_int = 0;
2781 while i < len {
2782 let ch = unsafe { *content.add(i as usize) };
2783
2784 if ch == b']'
2786 && i + 2 < len
2787 && unsafe { *content.add(i as usize + 1) == b']' }
2788 && unsafe { *content.add(i as usize + 2) == b'>' }
2789 {
2790 io::buf_add(buf, &ch as *const u8, 2); io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2793 i += 3;
2794 continue;
2795 }
2796
2797 match ch {
2798 b'<' => {
2799 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
2800 }
2801 b'&' => {
2802 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
2803 }
2804 b'>' => {
2805 io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2809 }
2810 b'\r' => {
2811 io::buf_add(buf, b" " as *const u8, 5);
2813 }
2814 0x01..=0x08 | 0x0B | 0x0C | 0x0E..=0x1F => {
2815 let hex = format!("&#x{:X};", ch);
2817 io::buf_add(buf, hex.as_ptr(), hex.len() as c_int);
2818 }
2819 _ => {
2820 io::buf_add(buf, &ch as *const u8, 1);
2821 }
2822 }
2823 i += 1;
2824 }
2825}
2826
2827pub(crate) unsafe fn serialize_attr_value(buf: *mut _xmlBuffer, value: *const xmlChar) {
2840 if buf.is_null() || value.is_null() {
2841 return;
2842 }
2843
2844 let len = xml_strlen(value);
2845 let mut i: c_int = 0;
2846 while i < len {
2847 let ch = unsafe { *value.add(i as usize) };
2848
2849 match ch {
2850 b'\n' => {
2851 io::buf_add(buf, b" " as *const u8, 5);
2852 }
2853 b'\r' => {
2854 io::buf_add(buf, b" " as *const u8, 5);
2855 }
2856 b'\t' => {
2857 io::buf_add(buf, b"	" as *const u8, 4);
2858 }
2859 b'<' => {
2860 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
2861 }
2862 b'&' => {
2863 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
2864 }
2865 b'"' => {
2866 io::buf_add(buf, ENTITY_QUOT.as_ptr(), ENTITY_QUOT.len() as c_int);
2867 }
2868 b'>' => {
2869 io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2870 }
2871 _ => {
2872 io::buf_add(buf, &ch as *const u8, 1);
2873 }
2874 }
2875 i += 1;
2876 }
2877}
2878
2879unsafe fn write_indent(
2891 buf: *mut _xmlBuffer,
2892 level: c_int,
2893 indent: *const xmlChar,
2894 indent_len: c_int,
2895) {
2896 if buf.is_null() || level <= 0 || indent.is_null() || indent_len <= 0 {
2897 return;
2898 }
2899 let indent_nr = MAX_INDENT / indent_len;
2900 let mut lvl = level;
2901 if lvl > indent_nr {
2902 lvl = indent_nr;
2903 }
2904 for _ in 0..lvl {
2905 io::buf_add(buf, indent, indent_len);
2906 }
2907}
2908
2909unsafe fn is_noenc_text(node: *mut _xmlNode) -> bool {
2917 if node.is_null() {
2918 return false;
2919 }
2920 let n = unsafe { &*node };
2921 if n.name.is_null() {
2922 return false;
2923 }
2924 c_str_eq_bytes(n.name, b"textnoenc")
2925}
2926
2927const unsafe fn c_str_eq_bytes(s: *const xmlChar, b: &[u8]) -> bool {
2929 let mut i = 0usize;
2930 while i < b.len() {
2931 if unsafe { *s.add(i) } != b[i] {
2932 return false;
2933 }
2934 i += 1;
2935 }
2936 unsafe { *s.add(i) == 0 }
2937}
2938
2939#[derive(Clone, Copy)]
2942struct DumpState {
2943 format: c_int,
2945 saved: c_int,
2948 unformatted: *mut _xmlNode,
2951 indent: *const xmlChar,
2954 indent_len: c_int,
2956 no_decl: c_int,
2958}
2959
2960impl DumpState {
2961 const fn new(format: c_int) -> Self {
2962 let f = if format != 0 { 1 } else { 0 };
2963 DumpState {
2964 format: f,
2965 saved: f,
2966 unformatted: ptr::null_mut(),
2967 indent: INDENT.as_ptr(),
2968 indent_len: INDENT.len() as c_int,
2969 no_decl: 0,
2970 }
2971 }
2972
2973 const unsafe fn with_indent(format: c_int, indent: *const xmlChar, no_decl: c_int) -> Self {
2981 let f = if format != 0 { 1 } else { 0 };
2982 let (ptr, len) = if indent.is_null() {
2983 (INDENT.as_ptr(), INDENT.len() as c_int)
2984 } else {
2985 let mut n = 0i32;
2986 while unsafe { *indent.add(n as usize) } != 0 {
2987 n += 1;
2988 }
2989 (indent, n)
2990 };
2991 DumpState {
2992 format: f,
2993 saved: f,
2994 unformatted: ptr::null_mut(),
2995 indent: ptr,
2996 indent_len: len,
2997 no_decl,
2998 }
2999 }
3000}
3001
3002unsafe fn write_qname(buf: *mut _xmlBuffer, node: *mut _xmlNode) {
3008 let n = unsafe { &*node };
3009 if !n.ns.is_null() {
3010 let ns = unsafe { &*n.ns };
3011 if !ns.prefix.is_null() {
3012 io::buf_cat(buf, ns.prefix);
3013 io::buf_ccat(buf, b':');
3014 }
3015 }
3016 if !n.name.is_null() {
3017 io::buf_cat(buf, n.name);
3018 }
3019}
3020
3021unsafe fn ns_dump_output(buf: *mut _xmlBuffer, cur: *mut _xmlNs) {
3027 if cur.is_null() || buf.is_null() {
3028 return;
3029 }
3030 let ns = unsafe { &*cur };
3031 if ns.type_ == XML_LOCAL_NAMESPACE as c_int && !ns.href.is_null() {
3032 if !ns.prefix.is_null() && c_str_eq_bytes(ns.prefix, b"xml") {
3034 return;
3035 }
3036 io::buf_ccat(buf, b' ');
3037 if !ns.prefix.is_null() {
3038 io::buf_add(buf, b"xmlns:" as *const u8, 6);
3039 io::buf_cat(buf, ns.prefix);
3040 } else {
3041 io::buf_add(buf, b"xmlns" as *const u8, 5);
3042 }
3043 io::buf_add(buf, b"=\"" as *const u8, 2);
3044 serialize_attr_value(buf, ns.href);
3045 io::buf_ccat(buf, b'"');
3046 }
3047}
3048
3049unsafe fn attr_dump_output(buf: *mut _xmlBuffer, cur: *mut _xmlAttr) {
3055 if cur.is_null() || buf.is_null() {
3056 return;
3057 }
3058 io::buf_ccat(buf, b' ');
3059 let a = unsafe { &*cur };
3060 if !a.ns.is_null() {
3061 let ans = unsafe { &*a.ns };
3062 if !ans.prefix.is_null() {
3063 io::buf_cat(buf, ans.prefix);
3064 io::buf_ccat(buf, b':');
3065 }
3066 }
3067 if !a.name.is_null() {
3068 io::buf_cat(buf, a.name);
3069 }
3070 io::buf_add(buf, b"=\"" as *const u8, 2);
3071 let mut child = a.children;
3074 while !child.is_null() {
3075 let ct = unsafe { (*child).type_ };
3076 if ct == XML_TEXT_NODE as c_int && !unsafe { (*child).content }.is_null() {
3077 serialize_attr_value(buf, unsafe { (*child).content });
3078 } else if ct == XML_ENTITY_REF_NODE as c_int && !unsafe { (*child).name }.is_null() {
3079 io::buf_ccat(buf, b'&');
3080 io::buf_cat(buf, unsafe { (*child).name });
3081 io::buf_ccat(buf, b';');
3082 }
3083 child = unsafe { (*child).next };
3084 }
3085 io::buf_ccat(buf, b'"');
3086}
3087
3088unsafe fn dump_notation_decl(buf: *mut _xmlBuffer, nota: *mut _xmlNotation) {
3094 let n = unsafe { &*nota };
3095 io::buf_add(buf, b"<!NOTATION " as *const u8, 11);
3096 if !n.name.is_null() {
3097 io::buf_cat(buf, n.name);
3098 }
3099 if !n.PublicID.is_null() {
3100 io::buf_add(buf, b" PUBLIC " as *const u8, 8);
3101 write_quoted_string(buf, n.PublicID);
3102 if !n.SystemID.is_null() {
3103 io::buf_ccat(buf, b' ');
3104 write_quoted_string(buf, n.SystemID);
3105 }
3106 } else {
3107 io::buf_add(buf, b" SYSTEM " as *const u8, 8);
3108 write_quoted_string(buf, n.SystemID);
3109 }
3110 io::buf_add(buf, b" >\n" as *const u8, 4);
3111}
3112
3113unsafe fn dump_element_occur(buf: *mut _xmlBuffer, ocur: c_int) {
3115 use crate::abi::types::xmlElementContentOccur::*;
3116 if ocur == XML_ELEMENT_CONTENT_OPT as c_int {
3117 io::buf_ccat(buf, b'?');
3118 } else if ocur == XML_ELEMENT_CONTENT_MULT as c_int {
3119 io::buf_ccat(buf, b'*');
3120 } else if ocur == XML_ELEMENT_CONTENT_PLUS as c_int {
3121 io::buf_ccat(buf, b'+');
3122 }
3123}
3124
3125unsafe fn dump_element_content(buf: *mut _xmlBuffer, content: *mut _xmlElementContent) {
3131 use crate::abi::types::xmlElementContentOccur::*;
3132 use crate::abi::types::xmlElementContentType::*;
3133 if content.is_null() {
3134 return;
3135 }
3136 io::buf_ccat(buf, b'(');
3137 let mut cur = content;
3138 loop {
3139 if cur.is_null() {
3140 return;
3141 }
3142 let c = unsafe { &*cur };
3143 match c.type_ {
3144 t if t == XML_ELEMENT_CONTENT_PCDATA as c_int => {
3145 io::buf_add(buf, b"#PCDATA" as *const u8, 7);
3146 }
3147 t if t == XML_ELEMENT_CONTENT_ELEMENT as c_int => {
3148 if !c.prefix.is_null() {
3149 io::buf_cat(buf, c.prefix);
3150 io::buf_ccat(buf, b':');
3151 }
3152 if !c.name.is_null() {
3153 io::buf_cat(buf, c.name);
3154 }
3155 }
3156 t if t == XML_ELEMENT_CONTENT_SEQ as c_int || t == XML_ELEMENT_CONTENT_OR as c_int => {
3157 if cur != content
3158 && !c.parent.is_null()
3159 && (c.type_ != unsafe { (*c.parent).type_ }
3160 || c.ocur != XML_ELEMENT_CONTENT_ONCE as c_int)
3161 {
3162 io::buf_ccat(buf, b'(');
3163 }
3164 cur = c.c1;
3165 continue;
3166 }
3167 _ => {}
3168 }
3169
3170 while cur != content {
3172 let ccur = unsafe { &*cur };
3173 let parent = ccur.parent;
3174 if parent.is_null() {
3175 return;
3176 }
3177 let p = unsafe { &*parent };
3178 if (ccur.type_ == XML_ELEMENT_CONTENT_OR as c_int
3179 || ccur.type_ == XML_ELEMENT_CONTENT_SEQ as c_int)
3180 && (ccur.type_ != p.type_ || ccur.ocur != XML_ELEMENT_CONTENT_ONCE as c_int)
3181 {
3182 io::buf_ccat(buf, b')');
3183 }
3184 dump_element_occur(buf, ccur.ocur);
3185
3186 if ccur.type_ == XML_ELEMENT_CONTENT_SEQ as c_int {
3187 io::buf_add(buf, b" , " as *const u8, 3);
3188 } else if ccur.type_ == XML_ELEMENT_CONTENT_OR as c_int {
3189 io::buf_add(buf, b" | " as *const u8, 3);
3190 }
3191
3192 if cur == p.c1 {
3193 cur = p.c2;
3194 break;
3195 }
3196 cur = parent;
3197 }
3198 if cur == content {
3199 break;
3200 }
3201 }
3202 io::buf_ccat(buf, b')');
3203 let cc = unsafe { &*content };
3204 dump_element_occur(buf, cc.ocur);
3205}
3206
3207unsafe fn dump_element_decl(buf: *mut _xmlBuffer, elem: *mut _xmlElement) {
3213 use crate::abi::types::xmlElementTypeVal::*;
3214 let e = unsafe { &*elem };
3215 io::buf_add(buf, b"<!ELEMENT " as *const u8, 10);
3216 if !e.prefix.is_null() {
3217 io::buf_cat(buf, e.prefix);
3218 io::buf_ccat(buf, b':');
3219 }
3220 if !e.name.is_null() {
3221 io::buf_cat(buf, e.name);
3222 }
3223 io::buf_ccat(buf, b' ');
3224 match e.etype {
3225 t if t == XML_ELEMENT_TYPE_EMPTY as c_int => {
3226 io::buf_add(buf, b"EMPTY" as *const u8, 5);
3227 }
3228 t if t == XML_ELEMENT_TYPE_ANY as c_int => {
3229 io::buf_add(buf, b"ANY" as *const u8, 3);
3230 }
3231 t if t == XML_ELEMENT_TYPE_MIXED as c_int || t == XML_ELEMENT_TYPE_ELEMENT as c_int => {
3232 dump_element_content(buf, e.content);
3233 }
3234 _ => {}
3235 }
3236 io::buf_add(buf, b">\n" as *const u8, 2);
3237}
3238
3239unsafe fn dump_enumeration(buf: *mut _xmlBuffer, cur: *mut _xmlEnumeration) {
3245 let mut e = cur;
3246 while !e.is_null() {
3247 let en = unsafe { &*e };
3248 if !en.name.is_null() {
3249 io::buf_cat(buf, en.name);
3250 }
3251 if !en.next.is_null() {
3252 io::buf_add(buf, b" | " as *const u8, 3);
3253 }
3254 e = en.next;
3255 }
3256 io::buf_ccat(buf, b')');
3257}
3258
3259unsafe fn dump_attribute_decl(buf: *mut _xmlBuffer, attr: *mut _xmlAttribute) {
3265 use crate::abi::types::xmlAttributeDefault::*;
3266 use crate::abi::types::xmlAttributeType::*;
3267 let a = unsafe { &*attr };
3268 io::buf_add(buf, b"<!ATTLIST " as *const u8, 10);
3269 if !a.elem.is_null() {
3270 io::buf_cat(buf, a.elem);
3271 }
3272 io::buf_ccat(buf, b' ');
3273 if !a.prefix.is_null() {
3274 io::buf_cat(buf, a.prefix);
3275 io::buf_ccat(buf, b':');
3276 }
3277 if !a.name.is_null() {
3278 io::buf_cat(buf, a.name);
3279 }
3280 match a.atype {
3281 t if t == XML_ATTRIBUTE_CDATA as c_int => {
3282 io::buf_add(buf, b" CDATA" as *const u8, 6);
3283 }
3284 t if t == XML_ATTRIBUTE_ID as c_int => {
3285 io::buf_add(buf, b" ID" as *const u8, 3);
3286 }
3287 t if t == XML_ATTRIBUTE_IDREF as c_int => {
3288 io::buf_add(buf, b" IDREF" as *const u8, 6);
3289 }
3290 t if t == XML_ATTRIBUTE_IDREFS as c_int => {
3291 io::buf_add(buf, b" IDREFS" as *const u8, 7);
3292 }
3293 t if t == XML_ATTRIBUTE_ENTITY as c_int => {
3294 io::buf_add(buf, b" ENTITY" as *const u8, 7);
3295 }
3296 t if t == XML_ATTRIBUTE_ENTITIES as c_int => {
3297 io::buf_add(buf, b" ENTITIES" as *const u8, 9);
3298 }
3299 t if t == XML_ATTRIBUTE_NMTOKEN as c_int => {
3300 io::buf_add(buf, b" NMTOKEN" as *const u8, 8);
3301 }
3302 t if t == XML_ATTRIBUTE_NMTOKENS as c_int => {
3303 io::buf_add(buf, b" NMTOKENS" as *const u8, 9);
3304 }
3305 t if t == XML_ATTRIBUTE_ENUMERATION as c_int => {
3306 io::buf_add(buf, b" (" as *const u8, 2);
3307 dump_enumeration(buf, a.tree);
3308 }
3309 t if t == XML_ATTRIBUTE_NOTATION as c_int => {
3310 io::buf_add(buf, b" NOTATION (" as *const u8, 11);
3311 dump_enumeration(buf, a.tree);
3312 }
3313 _ => {}
3314 }
3315 match a.def {
3316 t if t == XML_ATTRIBUTE_REQUIRED as c_int => {
3317 io::buf_add(buf, b" #REQUIRED" as *const u8, 10);
3318 }
3319 t if t == XML_ATTRIBUTE_IMPLIED as c_int => {
3320 io::buf_add(buf, b" #IMPLIED" as *const u8, 9);
3321 }
3322 t if t == XML_ATTRIBUTE_FIXED as c_int => {
3323 io::buf_add(buf, b" #FIXED" as *const u8, 7);
3324 }
3325 _ => {}
3326 }
3327 if !a.defaultValue.is_null() {
3328 io::buf_add(buf, b" \"" as *const u8, 2);
3329 serialize_attr_value(buf, a.defaultValue);
3330 io::buf_ccat(buf, b'"');
3331 }
3332 io::buf_add(buf, b">\n" as *const u8, 2);
3333}
3334
3335unsafe fn write_quoted_string(buf: *mut _xmlBuffer, str: *const xmlChar) {
3341 if buf.is_null() {
3342 return;
3343 }
3344 io::buf_ccat(buf, b'"');
3345 if !str.is_null() {
3346 let mut i = 0usize;
3347 while unsafe { *str.add(i) != 0 } {
3348 let ch = unsafe { *str.add(i) };
3349 if ch == b'"' {
3350 io::buf_add(buf, b""" as *const u8, 6);
3351 } else {
3352 io::buf_add(buf, &ch as *const u8, 1);
3353 }
3354 i += 1;
3355 }
3356 }
3357 io::buf_ccat(buf, b'"');
3358}
3359
3360unsafe fn dump_entity_decl(buf: *mut _xmlBuffer, ent: *mut _xmlEntity) {
3366 use crate::abi::types::xmlEntityType::*;
3367 let e = unsafe { &*ent };
3368 if e.etype == XML_INTERNAL_PARAMETER_ENTITY as c_int
3369 || e.etype == XML_EXTERNAL_PARAMETER_ENTITY as c_int
3370 {
3371 io::buf_add(buf, b"<!ENTITY % " as *const u8, 11);
3372 } else {
3373 io::buf_add(buf, b"<!ENTITY " as *const u8, 9);
3374 }
3375 if !e.name.is_null() {
3376 io::buf_cat(buf, e.name);
3377 }
3378 io::buf_ccat(buf, b' ');
3379
3380 if e.etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY as c_int
3381 || e.etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int
3382 || e.etype == XML_EXTERNAL_PARAMETER_ENTITY as c_int
3383 {
3384 if !e.ExternalID.is_null() {
3385 io::buf_add(buf, b"PUBLIC " as *const u8, 7);
3386 write_quoted_string(buf, e.ExternalID);
3387 io::buf_ccat(buf, b' ');
3388 } else {
3389 io::buf_add(buf, b"SYSTEM " as *const u8, 7);
3390 }
3391 write_quoted_string(buf, e.SystemID);
3392 }
3393
3394 if e.etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int && !e.content.is_null() {
3395 io::buf_add(buf, b" NDATA " as *const u8, 7);
3396 if !e.orig.is_null() {
3397 io::buf_cat(buf, e.orig);
3398 } else if !e.content.is_null() {
3399 io::buf_cat(buf, e.content);
3400 }
3401 }
3402
3403 if e.etype == XML_INTERNAL_GENERAL_ENTITY as c_int
3404 || e.etype == XML_INTERNAL_PARAMETER_ENTITY as c_int
3405 {
3406 if !e.orig.is_null() {
3407 write_quoted_string(buf, e.orig);
3408 } else {
3409 io::buf_ccat(buf, b'"');
3411 if !e.content.is_null() {
3412 let mut i = 0usize;
3413 while unsafe { *e.content.add(i) != 0 } {
3414 let ch = unsafe { *e.content.add(i) };
3415 match ch {
3416 b'"' => io::buf_add(buf, b""" as *const u8, 6),
3417 b'%' => io::buf_add(buf, b"%" as *const u8, 6),
3418 _ => io::buf_add(buf, &ch as *const u8, 1),
3419 };
3420 i += 1;
3421 }
3422 }
3423 io::buf_ccat(buf, b'"');
3424 }
3425 }
3426 io::buf_add(buf, b">\n" as *const u8, 2);
3427}
3428
3429unsafe fn dtd_dump_output(
3435 buf: *mut _xmlBuffer,
3436 cur: *mut _xmlNode,
3437 state: &mut DumpState,
3438 level: &mut c_int,
3439) {
3440 let dtd = cur as *mut _xmlDtd;
3441 let d = unsafe { &*dtd };
3442 io::buf_add(buf, b"<!DOCTYPE " as *const u8, 10);
3443 if !d.name.is_null() {
3444 io::buf_cat(buf, d.name);
3445 }
3446 if !d.ExternalID.is_null() {
3447 io::buf_add(buf, b" PUBLIC " as *const u8, 8);
3448 write_quoted_string(buf, d.ExternalID);
3449 io::buf_ccat(buf, b' ');
3450 write_quoted_string(buf, d.SystemID);
3451 } else if !d.SystemID.is_null() {
3452 io::buf_add(buf, b" SYSTEM " as *const u8, 8);
3453 write_quoted_string(buf, d.SystemID);
3454 }
3455 if d.entities.is_null()
3460 && d.elements.is_null()
3461 && d.attributes.is_null()
3462 && d.notations.is_null()
3463 && d.pentities.is_null()
3464 {
3465 io::buf_ccat(buf, b'>');
3466 return;
3467 }
3468 io::buf_add(buf, b" [\n" as *const u8, 3);
3469 let format = state.format;
3475 let lvl = *level;
3476 state.format = 0;
3477 *level = -1;
3478 if !d.notations.is_null() {
3479 crate::xml::hash::hash_scan(
3480 d.notations as *mut crate::xml::hash::HashTable,
3481 Some(dump_notation_decl_cb),
3482 buf as *mut c_void,
3483 );
3484 }
3485 if !d.elements.is_null() {
3486 crate::xml::hash::hash_scan(
3487 d.elements as *mut crate::xml::hash::HashTable,
3488 Some(dump_element_decl_cb),
3489 buf as *mut c_void,
3490 );
3491 }
3492 if !d.attributes.is_null() {
3493 crate::xml::hash::hash_scan(
3494 d.attributes as *mut crate::xml::hash::HashTable,
3495 Some(dump_attribute_decl_cb),
3496 buf as *mut c_void,
3497 );
3498 }
3499 if !d.entities.is_null() {
3500 crate::xml::hash::hash_scan(
3501 d.entities as *mut crate::xml::hash::HashTable,
3502 Some(dump_entity_decl_cb),
3503 buf as *mut c_void,
3504 );
3505 }
3506 if !d.pentities.is_null() {
3507 crate::xml::hash::hash_scan(
3508 d.pentities as *mut crate::xml::hash::HashTable,
3509 Some(dump_entity_decl_cb),
3510 buf as *mut c_void,
3511 );
3512 }
3513 state.format = format;
3514 *level = lvl;
3515 io::buf_add(buf, b"]>" as *const u8, 2);
3516}
3517
3518unsafe extern "C" fn dump_notation_decl_cb(
3520 payload: *mut c_void,
3521 data: *mut c_void,
3522 _name: *const crate::abi::types::xmlChar,
3523) {
3524 if !payload.is_null() && !data.is_null() {
3525 dump_notation_decl(data as *mut _xmlBuffer, payload as *mut _xmlNotation);
3526 }
3527}
3528
3529unsafe extern "C" fn dump_element_decl_cb(
3531 payload: *mut c_void,
3532 data: *mut c_void,
3533 _name: *const crate::abi::types::xmlChar,
3534) {
3535 if !payload.is_null() && !data.is_null() {
3536 dump_element_decl(data as *mut _xmlBuffer, payload as *mut _xmlElement);
3537 }
3538}
3539
3540unsafe extern "C" fn dump_attribute_decl_cb(
3542 payload: *mut c_void,
3543 data: *mut c_void,
3544 _name: *const crate::abi::types::xmlChar,
3545) {
3546 if !payload.is_null() && !data.is_null() {
3547 dump_attribute_decl(data as *mut _xmlBuffer, payload as *mut _xmlAttribute);
3548 }
3549}
3550
3551unsafe extern "C" fn dump_entity_decl_cb(
3553 payload: *mut c_void,
3554 data: *mut c_void,
3555 _name: *const crate::abi::types::xmlChar,
3556) {
3557 if !payload.is_null() && !data.is_null() {
3558 dump_entity_decl(data as *mut _xmlBuffer, payload as *mut _xmlEntity);
3559 }
3560}
3561
3562unsafe fn doc_content_dump_output(
3571 buf: *mut _xmlBuffer,
3572 cur: *mut _xmlNode,
3573 state: &mut DumpState,
3574 level: &mut c_int,
3575) {
3576 let doc = cur as *mut _xmlDoc;
3577 let d = unsafe { &*doc };
3578
3579 if state.no_decl == 0 {
3583 io::buf_add(buf, b"<?xml version=\"" as *const u8, 15);
3584 if !d.version.is_null() {
3585 io::buf_cat(buf, d.version);
3586 } else {
3587 io::buf_add(buf, b"1.0" as *const u8, 3);
3588 }
3589 io::buf_ccat(buf, b'"');
3590 if !d.encoding.is_null() {
3591 io::buf_add(buf, b" encoding=\"" as *const u8, 11);
3592 io::buf_cat(buf, d.encoding);
3593 io::buf_ccat(buf, b'"');
3594 }
3595 match d.standalone {
3596 0 => {
3597 io::buf_add(buf, b" standalone=\"no\"" as *const u8, 16);
3598 }
3599 1 => {
3600 io::buf_add(buf, b" standalone=\"yes\"" as *const u8, 17);
3601 }
3602 _ => {}
3603 }
3604 io::buf_add(buf, b"?>\n" as *const u8, 3);
3605 }
3606
3607 if !d.intSubset.is_null() {
3614 let mut in_chain = false;
3615 let mut c = d.children;
3616 while !c.is_null() {
3617 if c as *mut c_void == d.intSubset as *mut c_void {
3618 in_chain = true;
3619 break;
3620 }
3621 c = unsafe { (*c).next };
3622 }
3623 if !in_chain {
3624 let mut lvl = 0;
3625 dtd_dump_output(buf, d.intSubset as *mut _xmlNode, state, &mut lvl);
3626 io::buf_ccat(buf, b'\n');
3627 }
3628 }
3629
3630 if !d.children.is_null() {
3631 let mut child = d.children;
3632 while !child.is_null() {
3633 *level = 0;
3634 node_dump_internal(buf, child, child, cur, state, level);
3635 let ct = unsafe { (*child).type_ };
3636 if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
3637 io::buf_ccat(buf, b'\n');
3638 }
3639 child = unsafe { (*child).next };
3640 }
3641 }
3642}
3643
3644unsafe fn node_dump_internal(
3668 buf: *mut _xmlBuffer,
3669 cur: *mut _xmlNode,
3670 root: *mut _xmlNode,
3671 parent: *mut _xmlNode,
3672 state: &mut DumpState,
3673 level: &mut c_int,
3674) {
3675 if cur.is_null() || buf.is_null() {
3676 return;
3677 }
3678 let n = unsafe { &*cur };
3679 match n.type_ {
3680 t if t == XML_ELEMENT_NODE as c_int => {
3681 if cur != root && state.format == 1 {
3682 write_indent(buf, *level, state.indent, state.indent_len);
3683 }
3684 if !n.parent.is_null() && n.parent != parent && !n.children.is_null() {
3687 let mut sub = DumpState::new(state.format);
3688 let mut sub_level = *level;
3689 node_dump_internal(buf, cur, cur, n.parent, &mut sub, &mut sub_level);
3690 return;
3691 }
3692 io::buf_ccat(buf, b'<');
3694 write_qname(buf, cur);
3695 let mut nsdef = n.nsDef;
3696 while !nsdef.is_null() {
3697 ns_dump_output(buf, nsdef);
3698 nsdef = unsafe { (*nsdef).next };
3699 }
3700 let mut attr = n.properties;
3701 while !attr.is_null() {
3702 attr_dump_output(buf, attr);
3703 attr = unsafe { (*attr).next };
3704 }
3705 if n.children.is_null() {
3706 io::buf_add(buf, b"/>" as *const u8, 2);
3707 } else {
3708 if state.format == 1 {
3709 let mut tmp = n.children;
3712 while !tmp.is_null() {
3713 let tt = unsafe { (*tmp).type_ };
3714 if tt == XML_TEXT_NODE as c_int
3715 || tt == XML_CDATA_SECTION_NODE as c_int
3716 || tt == XML_ENTITY_REF_NODE as c_int
3717 {
3718 state.format = 0;
3719 state.unformatted = cur;
3720 break;
3721 }
3722 tmp = unsafe { (*tmp).next };
3723 }
3724 }
3725 io::buf_ccat(buf, b'>');
3726 if state.format == 1 {
3727 io::buf_ccat(buf, b'\n');
3728 }
3729 if *level >= 0 {
3730 *level += 1;
3731 }
3732 let mut child = n.children;
3733 while !child.is_null() {
3734 node_dump_internal(buf, child, root, cur, state, level);
3735 if state.format == 1 {
3736 let ct = unsafe { (*child).type_ };
3737 if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
3738 io::buf_ccat(buf, b'\n');
3739 }
3740 }
3741 child = unsafe { (*child).next };
3742 }
3743 if *level > 0 {
3745 *level -= 1;
3746 }
3747 if state.format == 1 {
3748 write_indent(buf, *level, state.indent, state.indent_len);
3749 }
3750 io::buf_add(buf, b"</" as *const u8, 2);
3751 write_qname(buf, cur);
3752 io::buf_ccat(buf, b'>');
3753 if cur == state.unformatted {
3754 state.format = state.saved;
3755 state.unformatted = ptr::null_mut();
3756 }
3757 }
3758 }
3759 t if t == XML_TEXT_NODE as c_int => {
3760 if !n.content.is_null() {
3761 if is_noenc_text(cur) {
3762 io::buf_cat(buf, n.content);
3763 } else {
3764 serialize_text(buf, n.content, xml_strlen(n.content));
3765 }
3766 } else if !n.children.is_null() {
3767 let c = node_get_content(cur);
3770 if !c.is_null() {
3771 if is_noenc_text(cur) {
3772 io::buf_cat(buf, c);
3773 } else {
3774 serialize_text(buf, c, xml_strlen(c));
3775 }
3776 allocator::xmlFreeImpl(c as *mut c_void);
3777 }
3778 }
3779 }
3780 t if t == XML_CDATA_SECTION_NODE as c_int => {
3781 if n.content.is_null() || unsafe { *n.content == 0 } {
3782 io::buf_add(buf, b"<![CDATA[]]>" as *const u8, 12);
3783 } else {
3784 let len = xml_strlen(n.content) as usize;
3785 let bytes = core::slice::from_raw_parts(n.content, len);
3786 let mut i = 0usize;
3787 let mut seg_start = 0usize;
3788 while i < len {
3789 if bytes[i] == b']'
3790 && i + 2 < len
3791 && bytes[i + 1] == b']'
3792 && bytes[i + 2] == b'>'
3793 {
3794 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
3795 io::buf_add(buf, n.content.add(seg_start), (i + 2 - seg_start) as c_int);
3796 io::buf_add(buf, b"]]>" as *const u8, 3);
3797 seg_start = i + 2;
3798 i += 3;
3799 continue;
3800 }
3801 i += 1;
3802 }
3803 if seg_start < len {
3804 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
3805 io::buf_add(buf, n.content.add(seg_start), (len - seg_start) as c_int);
3806 io::buf_add(buf, b"]]>" as *const u8, 3);
3807 }
3808 }
3809 }
3810 t if t == XML_COMMENT_NODE as c_int => {
3811 if cur != root && state.format == 1 {
3812 write_indent(buf, *level, state.indent, state.indent_len);
3813 }
3814 if !n.content.is_null() {
3815 io::buf_add(buf, b"<!--" as *const u8, 4);
3816 io::buf_cat(buf, n.content);
3817 io::buf_add(buf, b"-->" as *const u8, 3);
3818 }
3819 }
3820 t if t == XML_PI_NODE as c_int => {
3821 if cur != root && state.format == 1 {
3822 write_indent(buf, *level, state.indent, state.indent_len);
3823 }
3824 io::buf_add(buf, b"<?" as *const u8, 2);
3825 if !n.name.is_null() {
3826 io::buf_cat(buf, n.name);
3827 }
3828 if !n.content.is_null() && unsafe { *n.content != 0 } {
3829 io::buf_ccat(buf, b' ');
3830 io::buf_cat(buf, n.content);
3831 }
3832 io::buf_add(buf, b"?>" as *const u8, 2);
3833 }
3834 t if t == XML_ENTITY_REF_NODE as c_int => {
3835 io::buf_ccat(buf, b'&');
3836 if !n.name.is_null() {
3837 io::buf_cat(buf, n.name);
3838 }
3839 io::buf_ccat(buf, b';');
3840 }
3841 t if t == XML_DOCUMENT_NODE as c_int => {
3842 doc_content_dump_output(buf, cur, state, level);
3843 }
3844 t if t == XML_HTML_DOCUMENT_NODE as c_int => {
3845 crate::xml::html::serialize_node(cur, buf, state.format, *level);
3847 }
3848 t if t == XML_DTD_NODE as c_int => {
3849 dtd_dump_output(buf, cur, state, level);
3850 }
3851 t if t == XML_ATTRIBUTE_NODE as c_int => {
3852 attr_dump_output(buf, cur as *mut _xmlAttr);
3853 }
3854 t if t == XML_NAMESPACE_DECL as c_int => {
3855 ns_dump_output(buf, cur as *mut _xmlNs);
3856 }
3857 t if t == XML_ELEMENT_DECL as c_int => {
3858 dump_element_decl(buf, cur as *mut _xmlElement);
3859 }
3860 t if t == XML_ATTRIBUTE_DECL as c_int => {
3861 dump_attribute_decl(buf, cur as *mut _xmlAttribute);
3862 }
3863 t if t == XML_ENTITY_DECL as c_int => {
3864 dump_entity_decl(buf, cur as *mut _xmlEntity);
3865 }
3866 _ => {}
3867 }
3868}
3869
3870pub(crate) unsafe fn serialize_node(
3884 node: *mut _xmlNode,
3885 buf: *mut _xmlBuffer,
3886 format: c_int,
3887 level: c_int,
3888) {
3889 unsafe { serialize_node_opt(node, buf, format, level, ptr::null()) };
3890}
3891
3892pub(crate) unsafe fn serialize_node_opt(
3900 node: *mut _xmlNode,
3901 buf: *mut _xmlBuffer,
3902 format: c_int,
3903 level: c_int,
3904 indent: *const xmlChar,
3905) {
3906 unsafe { serialize_node_opts(node, buf, format, level, indent, 0) };
3907}
3908
3909pub(crate) unsafe fn serialize_node_opts(
3916 node: *mut _xmlNode,
3917 buf: *mut _xmlBuffer,
3918 format: c_int,
3919 level: c_int,
3920 indent: *const xmlChar,
3921 no_decl: c_int,
3922) {
3923 if node.is_null() || buf.is_null() {
3924 return;
3925 }
3926 let parent = unsafe { (*node).parent };
3927 let mut state = DumpState::with_indent(format, indent, no_decl);
3928 let mut lvl = level;
3929 node_dump_internal(buf, node, node, parent, &mut state, &mut lvl);
3930}
3931
3932pub(crate) unsafe fn doc_dump(buf: *mut _xmlBuffer, doc: *mut _xmlDoc) -> c_int {
3942 if buf.is_null() || doc.is_null() {
3943 return -1;
3944 }
3945
3946 let before = io::buf_length(buf);
3947 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
3948 let after = io::buf_length(buf);
3949
3950 if after < 0 || before < 0 {
3951 return -1;
3952 }
3953 after - before
3954}
3955
3956pub(crate) unsafe fn node_dump(
3968 buf: *mut _xmlBuffer,
3969 doc: *mut _xmlDoc,
3970 node: *mut _xmlNode,
3971 level: c_int,
3972 format: c_int,
3973) -> c_int {
3974 let _ = doc; if buf.is_null() || node.is_null() {
3976 return -1;
3977 }
3978
3979 let before = io::buf_length(buf);
3980 serialize_node(node, buf, format, level);
3981 let after = io::buf_length(buf);
3982
3983 if after < 0 || before < 0 {
3984 return -1;
3985 }
3986 after - before
3987}
3988
3989pub(crate) unsafe fn save_doc_to_filename(
3996 doc: *mut _xmlDoc,
3997 filename: *const c_char,
3998 compression: c_int,
3999) -> c_int {
4000 if doc.is_null() || filename.is_null() {
4001 return -1;
4002 }
4003
4004 let out = io::output_buffer_create_filename(filename, ptr::null_mut(), compression);
4005 if out.is_null() {
4006 return -1;
4007 }
4008
4009 let buf = io::buf_create(-1);
4010 if buf.is_null() {
4011 io::output_buffer_close(out);
4012 return -1;
4013 }
4014
4015 let ret = doc_dump(buf, doc);
4016 if ret >= 0 {
4017 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
4019 io::output_buffer_flush(out);
4020 }
4021
4022 io::buf_free(buf);
4023 io::output_buffer_close(out);
4024 ret
4025}
4026
4027#[allow(dead_code)]
4034pub(crate) unsafe fn save_doc_to_fd(doc: *mut _xmlDoc, fd: c_int, _compression: c_int) -> c_int {
4035 if doc.is_null() || fd < 0 {
4036 return -1;
4037 }
4038
4039 let out = io::output_buffer_create_fd(fd, ptr::null_mut());
4040 if out.is_null() {
4041 return -1;
4042 }
4043
4044 let buf = io::buf_create(-1);
4045 if buf.is_null() {
4046 io::output_buffer_close(out);
4047 return -1;
4048 }
4049
4050 let ret = doc_dump(buf, doc);
4051 if ret >= 0 {
4052 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
4053 io::output_buffer_flush(out);
4054 }
4055
4056 io::buf_free(buf);
4057 io::output_buffer_close(out);
4058 ret
4059}
4060
4061#[allow(dead_code)]
4068pub(crate) unsafe fn save_doc_to_buf(
4069 doc: *mut _xmlDoc,
4070 buf: *mut _xmlBuffer,
4071 compression: c_int,
4072) -> c_int {
4073 let _ = compression;
4074 if doc.is_null() || buf.is_null() {
4075 return -1;
4076 }
4077
4078 doc_dump(buf, doc)
4079}
4080
4081#[allow(dead_code)]
4088pub(crate) unsafe fn save_format_doc_to_buf(
4089 doc: *mut _xmlDoc,
4090 buf: *mut _xmlBuffer,
4091 compression: c_int,
4092) -> c_int {
4093 let _ = compression;
4094 if doc.is_null() || buf.is_null() {
4095 return -1;
4096 }
4097
4098 let before = io::buf_length(buf);
4099 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
4100 let after = io::buf_length(buf);
4101
4102 if after < 0 || before < 0 {
4103 return -1;
4104 }
4105 after - before
4106}
4107
4108#[allow(dead_code)]
4117pub(crate) unsafe fn dump_node(node: *mut _xmlNode) -> *mut xmlChar {
4118 if node.is_null() {
4119 return ptr::null_mut();
4120 }
4121
4122 let buf = io::buf_create(-1);
4123 if buf.is_null() {
4124 return ptr::null_mut();
4125 }
4126
4127 serialize_node(node, buf, 0, 0);
4128
4129 let content = io::buf_content(buf);
4130 if content.is_null() {
4131 io::buf_free(buf);
4132 return ptr::null_mut();
4133 }
4134
4135 let result = dup_xml_str(content);
4137 io::buf_free(buf);
4138 result
4139}
4140
4141pub unsafe fn dump_doc(doc: *mut _xmlDoc) -> *mut xmlChar {
4150 if doc.is_null() {
4151 return ptr::null_mut();
4152 }
4153
4154 let buf = io::buf_create(-1);
4155 if buf.is_null() {
4156 return ptr::null_mut();
4157 }
4158
4159 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
4160
4161 let content = io::buf_content(buf);
4162 if content.is_null() {
4163 io::buf_free(buf);
4164 return ptr::null_mut();
4165 }
4166
4167 let result = dup_xml_str(content);
4168 io::buf_free(buf);
4169 result
4170}
4171
4172pub(crate) unsafe fn xmlNodeDump(
4188 buf: *mut _xmlBuffer,
4189 doc: *mut _xmlDoc,
4190 node: *mut _xmlNode,
4191 level: c_int,
4192 format: c_int,
4193) -> c_int {
4194 node_dump(buf, doc, node, level, format)
4195}
4196
4197pub(crate) unsafe fn xmlDocDump(fp: *mut c_void, doc: *mut _xmlDoc) -> c_int {
4210 if fp.is_null() || doc.is_null() {
4211 return -1;
4212 }
4213
4214 let buf = io::buf_create(-1);
4215 if buf.is_null() {
4216 return -1;
4217 }
4218
4219 let ret = doc_dump(buf, doc);
4220 if ret < 0 {
4221 io::buf_free(buf);
4222 return -1;
4223 }
4224
4225 let content = io::buf_content(buf);
4226 let len = io::buf_length(buf);
4227 if !content.is_null() && len > 0 {
4228 let written = libc::fwrite(
4229 content as *const c_void,
4230 1,
4231 len as usize,
4232 fp as *mut libc::FILE,
4233 );
4234 io::buf_free(buf);
4235 written as c_int
4236 } else {
4237 io::buf_free(buf);
4238 0
4239 }
4240}
4241
4242pub(crate) unsafe fn xmlDocDumpFormatMemory(
4256 doc: *mut _xmlDoc,
4257 mem: *mut *mut xmlChar,
4258 size: *mut c_int,
4259 format: c_int,
4260) {
4261 if doc.is_null() || mem.is_null() || size.is_null() {
4262 return;
4263 }
4264
4265 let buf = io::buf_create(-1);
4266 if buf.is_null() {
4267 unsafe {
4268 *mem = ptr::null_mut();
4269 *size = 0;
4270 }
4271 return;
4272 }
4273
4274 serialize_node(doc as *mut _xmlNode, buf, format, 0);
4275
4276 let content = io::buf_content(buf);
4277 let len = io::buf_length(buf);
4278
4279 if !content.is_null() && len > 0 {
4280 let result = allocator::xmlMallocImpl((len + 1) as usize) as *mut xmlChar;
4282 if !result.is_null() {
4283 ptr::copy_nonoverlapping(content, result, len as usize);
4284 *result.add(len as usize) = 0;
4285 unsafe {
4286 *mem = result;
4287 *size = len;
4288 }
4289 } else {
4290 unsafe {
4291 *mem = ptr::null_mut();
4292 *size = 0;
4293 }
4294 }
4295 } else {
4296 unsafe {
4297 *mem = ptr::null_mut();
4298 *size = 0;
4299 }
4300 }
4301
4302 io::buf_free(buf);
4303}
4304
4305pub(crate) unsafe fn xmlDocDumpMemory(doc: *mut _xmlDoc, mem: *mut *mut xmlChar, size: *mut c_int) {
4319 xmlDocDumpFormatMemory(doc, mem, size, 0)
4320}
4321
4322pub(crate) unsafe fn xmlSaveFile(filename: *const c_char, cur: *mut _xmlDoc) -> c_int {
4335 save_doc_to_filename(cur, filename, 0)
4336}
4337
4338pub(crate) unsafe fn xmlSaveFileEnc(
4352 filename: *const c_char,
4353 cur: *mut _xmlDoc,
4354 encoding: *const c_char,
4355) -> c_int {
4356 let _ = encoding; save_doc_to_filename(cur, filename, 0)
4358}
4359
4360pub(crate) unsafe fn xmlSaveFormatFile(
4373 filename: *const c_char,
4374 cur: *mut _xmlDoc,
4375 format: c_int,
4376) -> c_int {
4377 let _ = format;
4378 save_doc_to_filename(cur, filename, 0)
4379}
4380
4381pub(crate) unsafe fn xmlSaveFormatFileEnc(
4395 filename: *const c_char,
4396 cur: *mut _xmlDoc,
4397 encoding: *const c_char,
4398 format: c_int,
4399) -> c_int {
4400 let _ = encoding;
4401 let _ = format;
4402 save_doc_to_filename(cur, filename, 0)
4403}
4404
4405pub(crate) unsafe fn xmlGetDocCompressMode(doc: *mut _xmlDoc) -> c_int {
4417 if doc.is_null() {
4418 return -1;
4419 }
4420 unsafe { (*doc).compression }
4421}
4422
4423pub(crate) unsafe fn xmlSetDocCompressMode(doc: *mut _xmlDoc, mode: c_int) {
4435 if doc.is_null() {
4436 return;
4437 }
4438 unsafe {
4439 (*doc).compression = mode;
4440 }
4441}
4442
4443#[cfg(test)]
4444mod tests {
4445 use super::*;
4446 use core::ffi::c_void;
4447
4448 fn c_str(s: &str) -> *const xmlChar {
4449 let bytes = s.as_bytes();
4450 let buf = unsafe { allocator::xmlMallocImpl(bytes.len() + 1) as *mut u8 };
4451 if !buf.is_null() {
4452 unsafe {
4453 ptr::copy_nonoverlapping(bytes.as_ptr(), buf, bytes.len());
4454 *buf.add(bytes.len()) = 0;
4455 }
4456 }
4457 buf as *const xmlChar
4458 }
4459
4460 #[test]
4461 fn test_new_free_doc() {
4462 unsafe {
4463 let doc = new_doc(ptr::null());
4464 assert!(!doc.is_null());
4465 assert_eq!((*doc).type_, XML_DOCUMENT_NODE as c_int);
4466 assert_eq!((*doc).standalone, -1);
4467 assert_eq!((*doc).doc, doc);
4468 assert!(!(*doc).version.is_null());
4469 free_doc(doc);
4470 }
4471 }
4472
4473 #[test]
4474 fn test_new_doc_with_version() {
4475 unsafe {
4476 let ver = c_str("2.0");
4477 let doc = new_doc(ver);
4478 assert!(!doc.is_null());
4479 let doc_ver = (*doc).version;
4480 assert!(!doc_ver.is_null());
4481 assert!(crate::abi::exports_xml2::xmlStrEqual(doc_ver, ver,) != 0);
4482 allocator::xmlFreeImpl(ver as *mut c_void);
4483 free_doc(doc);
4484 }
4485 }
4486
4487 #[test]
4488 fn test_new_node() {
4489 unsafe {
4490 let doc = new_doc(ptr::null());
4491 let node = new_node(ptr::null_mut(), c_str("root"));
4492 assert!(!node.is_null());
4493 assert_eq!((*node).type_, XML_ELEMENT_NODE as c_int);
4494 assert!(!(*node).name.is_null());
4495 free_node(node);
4496 free_doc(doc);
4497 }
4498 }
4499
4500 #[test]
4501 fn test_node_get_content_recurses_descendants() {
4502 unsafe {
4507 let doc = new_doc(ptr::null());
4508 let root = new_node(ptr::null_mut(), c_str("library"));
4509 doc_set_root_element(doc, root);
4510 let book = new_child(root, ptr::null_mut(), c_str("book"));
4511 let title = new_child(book, ptr::null_mut(), c_str("title"));
4512 let text = new_text(c_str("Rust"));
4513 add_child(title, text);
4514
4515 let content = node_get_content(book);
4516 assert!(!content.is_null());
4517 let s = core::slice::from_raw_parts(
4518 content,
4519 libc::strlen(content as *const libc::c_char) as usize,
4520 );
4521 assert_eq!(s, b"Rust", "descendant text not concatenated");
4522 allocator::xmlFreeImpl(content as *mut c_void);
4523
4524 free_doc(doc);
4525 }
4526 }
4527
4528 #[test]
4529 fn test_doc_set_root_element() {
4530 unsafe {
4531 let doc = new_doc(ptr::null());
4532 let root = new_node(ptr::null_mut(), c_str("root"));
4533 let old = doc_set_root_element(doc, root);
4534 assert!(old.is_null());
4535 assert_eq!(doc_get_root_element(doc), root);
4536 assert_eq!((*doc).children, root);
4537 free_doc(doc);
4538 }
4539 }
4540
4541 #[test]
4542 fn test_add_child_and_sibling() {
4543 unsafe {
4544 let doc = new_doc(ptr::null());
4545 let root = new_node(ptr::null_mut(), c_str("root"));
4546 doc_set_root_element(doc, root);
4547
4548 let child1 = new_child(root, ptr::null_mut(), c_str("child1"));
4549 assert!(!child1.is_null());
4550 assert_eq!((*child1).parent, root);
4551 assert_eq!((*root).children, child1);
4552 assert_eq!((*root).last, child1);
4553
4554 let child2 = new_child(root, ptr::null_mut(), c_str("child2"));
4555 assert!(!child2.is_null());
4556 assert_eq!((*child2).parent, root);
4557 assert_eq!((*child1).next, child2);
4558 assert_eq!((*child2).prev, child1);
4559 assert_eq!((*root).last, child2);
4560
4561 let sibling = new_node(ptr::null_mut(), c_str("sibling"));
4563 add_sibling(child2, sibling);
4564 assert_eq!((*child2).next, sibling);
4565 assert_eq!((*sibling).prev, child2);
4566 assert_eq!((*root).last, sibling);
4567
4568 free_doc(doc);
4569 }
4570 }
4571
4572 #[test]
4573 fn test_unlink_node() {
4574 unsafe {
4575 let doc = new_doc(ptr::null());
4576 let root = new_node(ptr::null_mut(), c_str("root"));
4577 doc_set_root_element(doc, root);
4578
4579 let child1 = new_child(root, ptr::null_mut(), c_str("c1"));
4580 let child2 = new_child(root, ptr::null_mut(), c_str("c2"));
4581
4582 unlink_node(child1);
4583 assert!((*child1).parent.is_null());
4584 assert!((*child1).prev.is_null());
4585 assert!((*child1).next.is_null());
4586 assert_eq!((*root).children, child2);
4587 assert_eq!((*root).last, child2);
4588
4589 free_node(child1);
4590 free_doc(doc);
4591 }
4592 }
4593
4594 #[test]
4595 fn test_text_and_comment_nodes() {
4596 unsafe {
4597 let text = new_text(c_str("hello world"));
4598 assert!(!text.is_null());
4599 assert_eq!((*text).type_, XML_TEXT_NODE as c_int);
4600 assert!(!(*text).content.is_null());
4601 free_node(text);
4602
4603 let comment = new_comment(c_str("my comment"));
4604 assert!(!comment.is_null());
4605 assert_eq!((*comment).type_, XML_COMMENT_NODE as c_int);
4606 free_node(comment);
4607
4608 let pi = new_pi(c_str("xml"), c_str("version='1.0'"));
4609 assert!(!pi.is_null());
4610 assert_eq!((*pi).type_, XML_PI_NODE as c_int);
4611 free_node(pi);
4612 }
4613 }
4614
4615 #[test]
4616 fn test_set_and_get_prop() {
4617 unsafe {
4618 let doc = new_doc(ptr::null());
4619 let root = new_node(ptr::null_mut(), c_str("root"));
4620 doc_set_root_element(doc, root);
4621
4622 let attr = set_prop(root, c_str("id"), c_str("42"));
4623 assert!(!attr.is_null());
4624 assert_eq!((*attr).type_, XML_ATTRIBUTE_NODE as c_int);
4625
4626 let value = get_prop(root, c_str("id"));
4627 assert!(!value.is_null());
4628 assert!(crate::abi::exports_xml2::xmlStrEqual(value, c_str("42")) != 0);
4629 allocator::xmlFreeImpl(value as *mut c_void);
4630
4631 free_doc(doc);
4632 }
4633 }
4634
4635 #[test]
4636 fn test_remove_prop() {
4637 unsafe {
4638 let doc = new_doc(ptr::null());
4639 let root = new_node(ptr::null_mut(), c_str("root"));
4640 doc_set_root_element(doc, root);
4641
4642 set_prop(root, c_str("a"), c_str("1"));
4643 set_prop(root, c_str("b"), c_str("2"));
4644
4645 let value = get_prop(root, c_str("a"));
4646 assert!(!value.is_null());
4647 allocator::xmlFreeImpl(value as *mut c_void);
4648
4649 let attr = (*root).properties;
4651 assert!(!attr.is_null());
4652 let result = remove_prop(attr);
4653 assert_eq!(result, 0);
4654
4655 let value2 = get_prop(root, c_str("a"));
4657 assert!(value2.is_null());
4658
4659 free_doc(doc);
4660 }
4661 }
4662
4663 #[test]
4664 fn test_namespace_operations() {
4665 unsafe {
4666 let doc = new_doc(ptr::null());
4667 let root = new_node(ptr::null_mut(), c_str("root"));
4668 doc_set_root_element(doc, root);
4669
4670 let ns = new_ns(root, c_str("http://example.com"), c_str("ex"));
4671 assert!(!ns.is_null());
4672 assert!(!(*root).nsDef.is_null());
4673
4674 set_ns(root, ns);
4675 assert_eq!((*root).ns, ns);
4676
4677 let found = search_ns(doc, root, c_str("ex"));
4678 assert_eq!(found, ns);
4679
4680 let found_href = search_ns_by_href(doc, root, c_str("http://example.com"));
4681 assert_eq!(found_href, ns);
4682
4683 free_doc(doc);
4684 }
4685 }
4686
4687 #[test]
4688 fn test_new_dtd() {
4689 unsafe {
4690 let doc = new_doc(ptr::null());
4691 let dtd = new_dtd(doc, c_str("root"), c_str("-//TEST//DTD"), c_str("test.dtd"));
4692 assert!(!dtd.is_null());
4693 assert_eq!((*dtd).type_, XML_DTD_NODE as c_int);
4694 assert_eq!(get_int_subset(doc), dtd);
4695 free_doc(doc);
4696 }
4697 }
4698
4699 #[test]
4700 fn test_copy_node_deep() {
4701 unsafe {
4702 let doc = new_doc(ptr::null());
4703 let root = new_node(ptr::null_mut(), c_str("root"));
4704 doc_set_root_element(doc, root);
4705 let _child = new_child(root, ptr::null_mut(), c_str("child"));
4706
4707 let copy = copy_node(root, 1);
4708 assert!(!copy.is_null());
4709 assert_eq!((*copy).type_, XML_ELEMENT_NODE as c_int);
4710 assert!(!(*copy).children.is_null());
4712 assert_eq!((*(*copy).children).type_, XML_ELEMENT_NODE as c_int);
4713
4714 free_node(copy);
4715 free_doc(doc);
4716 }
4717 }
4718
4719 #[test]
4720 fn test_new_cdata_block() {
4721 unsafe {
4722 let doc = new_doc(ptr::null());
4723 let content = c_str("some <cdata> content");
4724 let cdata = new_cdata_block(doc, content, 20);
4725 assert!(!cdata.is_null());
4726 assert_eq!((*cdata).type_, XML_CDATA_SECTION_NODE as c_int);
4727 free_node(cdata);
4728 free_doc(doc);
4729 }
4730 }
4731
4732 #[test]
4733 fn test_null_handling() {
4734 unsafe {
4735 assert!(!new_doc(ptr::null()).is_null()); let doc = new_doc(ptr::null());
4737 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());
4742 assert!(add_sibling(ptr::null_mut(), ptr::null_mut()).is_null());
4743 free_doc(doc);
4744 }
4745 }
4746
4747 unsafe fn buf_eq_str(buf: *mut _xmlBuffer, expected: &str) -> bool {
4753 let content = io::buf_content(buf);
4754 if content.is_null() {
4755 return expected.is_empty();
4756 }
4757 let len = io::buf_length(buf) as usize;
4758 if len != expected.len() {
4759 return false;
4760 }
4761 let slice = unsafe { core::slice::from_raw_parts(content, len) };
4762 slice == expected.as_bytes()
4763 }
4764
4765 #[test]
4766 fn test_serialize_empty_document() {
4767 unsafe {
4768 let doc = new_doc(ptr::null());
4769 let buf = io::buf_create(-1);
4770 assert!(!buf.is_null());
4771
4772 let ret = doc_dump(buf, doc);
4773 assert!(ret >= 0);
4774
4775 let expected = "<?xml version=\"1.0\"?>\n";
4779 assert!(buf_eq_str(buf, expected));
4780
4781 io::buf_free(buf);
4782 free_doc(doc);
4783 }
4784 }
4785
4786 #[test]
4787 fn test_serialize_element_with_text() {
4788 unsafe {
4789 let doc = new_doc(ptr::null());
4790 let root = new_node(ptr::null_mut(), c_str("root"));
4791 doc_set_root_element(doc, root);
4792
4793 let text = new_text(c_str("hello world"));
4795 add_child(root, text);
4796
4797 let buf = io::buf_create(-1);
4798 assert!(!buf.is_null());
4799
4800 let ret = doc_dump(buf, doc);
4801 assert!(ret >= 0);
4802
4803 let expected = "<?xml version=\"1.0\"?>\n<root>hello world</root>\n";
4804 assert!(buf_eq_str(buf, expected));
4805
4806 io::buf_free(buf);
4807 free_doc(doc);
4808 }
4809 }
4810
4811 #[test]
4812 fn test_serialize_element_with_attributes() {
4813 unsafe {
4814 let doc = new_doc(ptr::null());
4815 let root = new_node(ptr::null_mut(), c_str("root"));
4816 doc_set_root_element(doc, root);
4817
4818 set_prop(root, c_str("id"), c_str("42"));
4819 set_prop(root, c_str("name"), c_str("test"));
4820
4821 let buf = io::buf_create(-1);
4822 assert!(!buf.is_null());
4823
4824 let ret = doc_dump(buf, doc);
4825 assert!(ret >= 0);
4826
4827 let expected = "<?xml version=\"1.0\"?>\n<root id=\"42\" name=\"test\"/>\n";
4828 assert!(buf_eq_str(buf, expected));
4829
4830 io::buf_free(buf);
4831 free_doc(doc);
4832 }
4833 }
4834
4835 #[test]
4836 fn test_serialize_nested_elements() {
4837 unsafe {
4838 let doc = new_doc(ptr::null());
4839 let root = new_node(ptr::null_mut(), c_str("root"));
4840 doc_set_root_element(doc, root);
4841
4842 let child = new_child(root, ptr::null_mut(), c_str("child"));
4843 let grandchild = new_child(child, ptr::null_mut(), c_str("gc"));
4844 let text = new_text(c_str("text"));
4845 add_child(grandchild, text);
4846
4847 let buf = io::buf_create(-1);
4848 assert!(!buf.is_null());
4849
4850 let ret = doc_dump(buf, doc);
4851 assert!(ret >= 0);
4852
4853 let expected = "<?xml version=\"1.0\"?>\n<root><child><gc>text</gc></child></root>\n";
4854 assert!(buf_eq_str(buf, expected));
4855
4856 io::buf_free(buf);
4857 free_doc(doc);
4858 }
4859 }
4860
4861 #[test]
4862 fn test_serialize_with_formatting() {
4863 unsafe {
4864 let doc = new_doc(ptr::null());
4865 let root = new_node(ptr::null_mut(), c_str("root"));
4866 doc_set_root_element(doc, root);
4867
4868 let child = new_child(root, ptr::null_mut(), c_str("child"));
4869 let text = new_text(c_str("text"));
4870 add_child(child, text);
4871
4872 let buf = io::buf_create(-1);
4873 assert!(!buf.is_null());
4874
4875 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
4876
4877 let expected = "<?xml version=\"1.0\"?>\n<root>\n <child>text</child>\n</root>\n";
4878 assert!(buf_eq_str(buf, expected));
4879
4880 io::buf_free(buf);
4881 free_doc(doc);
4882 }
4883 }
4884
4885 #[test]
4886 fn test_serialize_escape_ampersand() {
4887 unsafe {
4888 let doc = new_doc(ptr::null());
4889 let root = new_node(ptr::null_mut(), c_str("root"));
4890 doc_set_root_element(doc, root);
4891
4892 let text = new_text(c_str("a & b"));
4893 add_child(root, text);
4894
4895 let buf = io::buf_create(-1);
4896 assert!(!buf.is_null());
4897
4898 let ret = doc_dump(buf, doc);
4899 assert!(ret >= 0);
4900
4901 let expected = "<?xml version=\"1.0\"?>\n<root>a & b</root>\n";
4902 assert!(buf_eq_str(buf, expected));
4903
4904 io::buf_free(buf);
4905 free_doc(doc);
4906 }
4907 }
4908
4909 #[test]
4910 fn test_serialize_escape_angle_brackets() {
4911 unsafe {
4912 let doc = new_doc(ptr::null());
4913 let root = new_node(ptr::null_mut(), c_str("root"));
4914 doc_set_root_element(doc, root);
4915
4916 let text = new_text(c_str("x < y > z"));
4917 add_child(root, text);
4918
4919 let buf = io::buf_create(-1);
4920 assert!(!buf.is_null());
4921
4922 let ret = doc_dump(buf, doc);
4923 assert!(ret >= 0);
4924
4925 let expected = "<?xml version=\"1.0\"?>\n<root>x < y > z</root>\n";
4926 assert!(buf_eq_str(buf, expected));
4927
4928 io::buf_free(buf);
4929 free_doc(doc);
4930 }
4931 }
4932
4933 #[test]
4934 fn test_serialize_comment() {
4935 unsafe {
4936 let doc = new_doc(ptr::null());
4937 let root = new_node(ptr::null_mut(), c_str("root"));
4938 doc_set_root_element(doc, root);
4939
4940 let comment = new_comment(c_str("my comment"));
4941 add_child(root, comment);
4942
4943 let buf = io::buf_create(-1);
4944 assert!(!buf.is_null());
4945
4946 let ret = doc_dump(buf, doc);
4947 assert!(ret >= 0);
4948
4949 let expected = "<?xml version=\"1.0\"?>\n<root><!--my comment--></root>\n";
4950 assert!(buf_eq_str(buf, expected));
4951
4952 io::buf_free(buf);
4953 free_doc(doc);
4954 }
4955 }
4956
4957 #[test]
4958 fn test_serialize_pi() {
4959 unsafe {
4960 let doc = new_doc(ptr::null());
4961 let root = new_node(ptr::null_mut(), c_str("root"));
4962 doc_set_root_element(doc, root);
4963
4964 let pi = new_pi(
4965 c_str("xml-stylesheet"),
4966 c_str("href=\"style.xsl\" type=\"text/xsl\""),
4967 );
4968 add_child(root, pi);
4969
4970 let buf = io::buf_create(-1);
4971 assert!(!buf.is_null());
4972
4973 let ret = doc_dump(buf, doc);
4974 assert!(ret >= 0);
4975
4976 let expected = "<?xml version=\"1.0\"?>\n<root><?xml-stylesheet href=\"style.xsl\" type=\"text/xsl\"?></root>\n";
4977 assert!(buf_eq_str(buf, expected));
4978
4979 io::buf_free(buf);
4980 free_doc(doc);
4981 }
4982 }
4983
4984 #[test]
4985 fn test_serialize_self_closing() {
4986 unsafe {
4987 let doc = new_doc(ptr::null());
4988 let root = new_node(ptr::null_mut(), c_str("empty"));
4989 doc_set_root_element(doc, root);
4990
4991 let buf = io::buf_create(-1);
4992 assert!(!buf.is_null());
4993
4994 let ret = doc_dump(buf, doc);
4995 assert!(ret >= 0);
4996
4997 let expected = "<?xml version=\"1.0\"?>\n<empty/>\n";
4998 assert!(buf_eq_str(buf, expected));
4999
5000 io::buf_free(buf);
5001 free_doc(doc);
5002 }
5003 }
5004
5005 #[test]
5006 fn test_dump_node_to_string() {
5007 unsafe {
5008 let node = new_node(ptr::null_mut(), c_str("foo"));
5009 let text = new_text(c_str("bar"));
5010 add_child(node, text);
5011
5012 let result = dump_node(node);
5013 assert!(!result.is_null());
5014
5015 let len = xml_strlen(result);
5016 let slice = { core::slice::from_raw_parts(result, len as usize) };
5017 assert_eq!(slice, b"<foo>bar</foo>");
5018
5019 allocator::xmlFreeImpl(result as *mut c_void);
5020 free_node(node);
5021 }
5022 }
5023
5024 #[test]
5025 fn test_dump_doc_to_string() {
5026 unsafe {
5027 let doc = new_doc(ptr::null());
5028 let root = new_node(ptr::null_mut(), c_str("root"));
5029 doc_set_root_element(doc, root);
5030
5031 let result = dump_doc(doc);
5032 assert!(!result.is_null());
5033
5034 let len = xml_strlen(result);
5035 let slice = { core::slice::from_raw_parts(result, len as usize) };
5036 let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
5037 assert_eq!(slice, expected.as_bytes());
5038
5039 allocator::xmlFreeImpl(result as *mut c_void);
5040 free_doc(doc);
5041 }
5042 }
5043
5044 #[test]
5045 fn test_xmlDocDumpFormatMemory() {
5046 unsafe {
5047 let doc = new_doc(ptr::null());
5048 let root = new_node(ptr::null_mut(), c_str("root"));
5049 doc_set_root_element(doc, root);
5050
5051 let mut mem: *mut xmlChar = ptr::null_mut();
5052 let mut size: c_int = 0;
5053
5054 xmlDocDumpFormatMemory(doc, &mut mem, &mut size, 0);
5055
5056 assert!(!mem.is_null());
5057 assert!(size > 0);
5058
5059 let slice = { core::slice::from_raw_parts(mem, size as usize) };
5060 let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
5063 assert_eq!(slice, expected.as_bytes());
5064
5065 allocator::xmlFreeImpl(mem as *mut c_void);
5066 free_doc(doc);
5067 }
5068 }
5069
5070 #[test]
5071 fn test_serialize_escape_attribute() {
5072 unsafe {
5073 let doc = new_doc(ptr::null());
5074 let root = new_node(ptr::null_mut(), c_str("root"));
5075 doc_set_root_element(doc, root);
5076
5077 set_prop(root, c_str("desc"), c_str("a < b & c \"quoted\""));
5079
5080 let buf = io::buf_create(-1);
5081 assert!(!buf.is_null());
5082
5083 let ret = doc_dump(buf, doc);
5084 assert!(ret >= 0);
5085
5086 let expected =
5087 "<?xml version=\"1.0\"?>\n<root desc=\"a < b & c "quoted"\"/>\n";
5088 assert!(buf_eq_str(buf, expected));
5089
5090 io::buf_free(buf);
5091 free_doc(doc);
5092 }
5093 }
5094}