1use core::ffi::c_void;
37use core::ptr;
38use std::os::raw::{c_char, c_int, c_long, c_ulong};
39
40use crate::abi::allocator;
41use crate::abi::constants::*;
42use crate::abi::structs::*;
43use crate::abi::types::xmlCharEncoding::XML_CHAR_ENCODING_UTF8;
44use crate::abi::types::xmlDocProperties::XML_DOC_USERBUILT;
45use crate::abi::types::xmlElementType::*;
46use crate::abi::types::*;
47use crate::xml::io;
48
49unsafe fn dup_xml_str(str: *const xmlChar) -> *mut xmlChar {
59 if str.is_null() {
60 return ptr::null_mut();
61 }
62 let len = unsafe { crate::abi::exports_xml2::xmlStrlen(str) as usize };
63 if len == 0 {
64 let buf = unsafe { allocator::xmlMallocImpl(1) as *mut xmlChar };
66 if !buf.is_null() {
67 unsafe { *buf = 0 };
68 }
69 return buf;
70 }
71 let buf = unsafe { allocator::xmlMallocImpl(len + 1) as *mut xmlChar };
72 if !buf.is_null() {
73 unsafe {
74 ptr::copy_nonoverlapping(str, buf, len + 1);
75 }
76 }
77 buf
78}
79
80#[allow(dead_code)]
82unsafe fn copy_xml_str_content(dest: *mut xmlChar, src: *const xmlChar, max_len: usize) -> bool {
83 if src.is_null() || dest.is_null() || max_len == 0 {
84 return false;
85 }
86 let len = unsafe { crate::abi::exports_xml2::xmlStrlen(src) as usize };
87 if len >= max_len {
88 return false;
89 }
90 unsafe {
91 ptr::copy_nonoverlapping(src, dest, len);
92 *dest.add(len) = 0;
93 }
94 true
95}
96
97pub const unsafe fn xml_strlen(str: *const xmlChar) -> c_int {
114 if str.is_null() {
115 return 0;
116 }
117 let mut len: c_int = 0;
118 while unsafe { *str.add(len as usize) != 0 } {
119 len += 1;
120 }
121 len
122}
123
124pub unsafe fn new_doc(version: *const xmlChar) -> *mut _xmlDoc {
147 let doc = allocator::xmlMallocZero(size_of::<_xmlDoc>() as usize) as *mut _xmlDoc;
149 if doc.is_null() {
150 return ptr::null_mut();
151 }
152
153 unsafe {
154 (*doc).type_ = XML_DOCUMENT_NODE as c_int;
155 (*doc).standalone = -1; (*doc).doc = doc; (*doc).properties = XML_DOC_USERBUILT as c_int;
158 (*doc).compression = -1; (*doc).charset = XML_CHAR_ENCODING_UTF8 as c_int;
160
161 let ver = if version.is_null() {
163 XML_DEFAULT_VERSION.as_ptr() as *const xmlChar
164 } else {
165 version
166 };
167 (*doc).version = dup_xml_str(ver);
168 }
169
170 crate::abi::data_globals::register_node_hook(doc as *mut _xmlNode);
172
173 doc
174}
175
176pub unsafe fn free_doc(doc: *mut _xmlDoc) {
190 if doc.is_null() {
191 return;
192 }
193
194 crate::abi::data_globals::deregister_node_hook(doc as *mut _xmlNode);
197
198 let d = unsafe { &mut *doc };
199
200 let dict = d.dict;
204 let mut ext_subset = d.extSubset;
205 let int_subset = d.intSubset;
206 if !ext_subset.is_null() && ext_subset == int_subset {
207 ext_subset = ptr::null_mut();
208 }
209 if !ext_subset.is_null() {
210 unlink_node_internal(ext_subset as *mut _xmlNode, d as *mut _xmlDoc);
211 d.extSubset = ptr::null_mut();
212 free_dtd(ext_subset);
213 }
214 if !int_subset.is_null() {
215 unlink_node_internal(int_subset as *mut _xmlNode, d as *mut _xmlDoc);
216 d.intSubset = ptr::null_mut();
217 free_dtd(int_subset);
218 }
219
220 if !d.children.is_null() {
222 free_node_list(d.children);
223 }
224
225 if !d.oldNs.is_null() {
227 free_ns_list(d.oldNs);
228 }
229
230 if !d.version.is_null() {
232 allocator::xmlFreeImpl(d.version as *mut c_void);
233 }
234 if !d.encoding.is_null() {
235 allocator::xmlFreeImpl(d.encoding as *mut c_void);
236 }
237 if !d.URL.is_null() {
238 allocator::xmlFreeImpl(d.URL as *mut c_void);
239 }
240
241 allocator::xmlFreeImpl(doc as *mut c_void);
243
244 if !dict.is_null() {
246 crate::abi::exports_xml2::xmlDictFree(dict);
247 }
248}
249
250unsafe fn unlink_node_internal(node: *mut _xmlNode, _doc: *mut _xmlDoc) {
254 if node.is_null() {
255 return;
256 }
257 let parent = (*node).parent;
258 if parent.is_null() {
259 return;
260 }
261 if (*node).prev.is_null() {
262 (*parent).children = (*node).next;
263 } else {
264 (*(*node).prev).next = (*node).next;
265 }
266 if (*node).next.is_null() {
267 (*parent).last = (*node).prev;
268 } else {
269 (*(*node).next).prev = (*node).prev;
270 }
271 (*node).next = ptr::null_mut();
272 (*node).prev = ptr::null_mut();
273 (*node).parent = ptr::null_mut();
274}
275
276pub unsafe fn copy_doc(doc: *const _xmlDoc, recursive: c_int) -> *mut _xmlDoc {
291 if doc.is_null() {
292 return ptr::null_mut();
293 }
294
295 let d = unsafe { &*doc };
296
297 let new_doc = new_doc(d.version);
298 if new_doc.is_null() {
299 return ptr::null_mut();
300 }
301
302 unsafe {
303 (*new_doc).type_ = d.type_;
304 (*new_doc).standalone = d.standalone;
305 (*new_doc).encoding = dup_xml_str(d.encoding);
306 (*new_doc).URL = dup_xml_str(d.URL);
307 (*new_doc).charset = d.charset;
308 (*new_doc).properties = d.properties;
309
310 if !d.intSubset.is_null() {
315 let dtd_copy = crate::xml::dtd::copy_dtd(d.intSubset);
316 if !dtd_copy.is_null() {
317 (*new_doc).intSubset = dtd_copy;
318 }
319 }
320
321 if recursive != 0 && !d.children.is_null() {
322 (*new_doc).children = copy_node_list(d.children, recursive);
323 if !(*new_doc).children.is_null() {
324 (*(*new_doc).children).parent = ptr::null_mut(); (*(*new_doc).children).doc = new_doc;
326 propagate_doc((*new_doc).children, new_doc);
328 }
329 }
330 }
331
332 new_doc
333}
334
335pub unsafe fn doc_set_root_element(doc: *mut _xmlDoc, root: *mut _xmlNode) -> *mut _xmlNode {
351 if doc.is_null() {
352 return ptr::null_mut();
353 }
354
355 let d = unsafe { &mut *doc };
356
357 let old_root = doc_get_root_element(doc);
358
359 if !root.is_null() {
360 unsafe {
361 (*root).parent = ptr::null_mut();
362 (*root).doc = doc;
363 }
364 d.children = root;
365 d.last = root;
366 unsafe {
367 (*root).prev = ptr::null_mut();
368 (*root).next = ptr::null_mut();
369 }
370 } else {
371 d.children = ptr::null_mut();
372 d.last = ptr::null_mut();
373 }
374
375 old_root
376}
377
378pub fn doc_get_root_element(doc: *mut _xmlDoc) -> *mut _xmlNode {
389 if doc.is_null() {
390 return ptr::null_mut();
391 }
392
393 let d = unsafe { &*doc };
394 let mut cur = d.children;
395
396 while !cur.is_null() {
397 let node = unsafe { &*cur };
398 if node.type_ == XML_ELEMENT_NODE as c_int {
399 return cur;
400 }
401 cur = node.next;
402 }
403
404 ptr::null_mut()
405}
406
407pub fn get_line_no(node: *const _xmlNode) -> c_long {
417 unsafe { get_line_no_internal(node, 0) }
418}
419
420unsafe fn get_line_no_internal(node: *const _xmlNode, depth: c_int) -> c_long {
425 if depth >= 5 {
426 return -1;
427 }
428 if node.is_null() {
429 return -1;
430 }
431 let n = unsafe { &*node };
432 if n.type_ == XML_ELEMENT_NODE as c_int
433 || n.type_ == XML_TEXT_NODE as c_int
434 || n.type_ == XML_COMMENT_NODE as c_int
435 || n.type_ == XML_PI_NODE as c_int
436 {
437 if n.line == 65535 {
438 if n.type_ == XML_ELEMENT_NODE as c_int && !n.children.is_null() {
439 let r = unsafe { get_line_no_internal(n.children, depth + 1) };
440 if r != -1 {
441 return r;
442 }
443 }
444 if !n.next.is_null() {
445 let r = unsafe { get_line_no_internal(n.next, depth + 1) };
446 if r != -1 {
447 return r;
448 }
449 }
450 if !n.prev.is_null() {
451 let r = unsafe { get_line_no_internal(n.prev, depth + 1) };
452 if r != -1 {
453 return r;
454 }
455 }
456 }
457 n.line as c_long
458 } else if !n.prev.is_null()
459 && (unsafe { (*n.prev).type_ } == XML_ELEMENT_NODE as c_int
460 || unsafe { (*n.prev).type_ } == XML_TEXT_NODE as c_int
461 || unsafe { (*n.prev).type_ } == XML_COMMENT_NODE as c_int
462 || unsafe { (*n.prev).type_ } == XML_PI_NODE as c_int)
463 {
464 unsafe { get_line_no_internal(n.prev, depth + 1) }
465 } else if !n.parent.is_null() && unsafe { (*n.parent).type_ } == XML_ELEMENT_NODE as c_int {
466 unsafe { get_line_no_internal(n.parent, depth + 1) }
467 } else {
468 -1
469 }
470}
471
472pub unsafe fn node_get_content(node: *mut _xmlNode) -> *mut xmlChar {
507 if node.is_null() {
508 return ptr::null_mut();
509 }
510 let typ = (*node).type_;
511 let mut result: Vec<u8> = Vec::new();
512 match typ {
513 t if t == XML_TEXT_NODE as c_int
514 || t == XML_CDATA_SECTION_NODE as c_int
515 || t == XML_COMMENT_NODE as c_int
516 || t == XML_PI_NODE as c_int =>
517 {
518 if !(*node).content.is_null() {
519 let len = crate::abi::exports_xml2::xmlStrlen((*node).content);
520 result
521 .extend_from_slice(core::slice::from_raw_parts((*node).content, len as usize));
522 } else if t == XML_TEXT_NODE as c_int && !(*node).children.is_null() {
523 let mut child = (*node).children;
526 while !child.is_null() {
527 if !(*child).content.is_null() {
528 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
529 result.extend_from_slice(core::slice::from_raw_parts(
530 (*child).content,
531 len as usize,
532 ));
533 }
534 child = (*child).next;
535 }
536 }
537 }
538 t if t == XML_ATTRIBUTE_NODE as c_int => {
539 if !(*node).children.is_null() {
541 let child = (*node).children;
542 if !(*child).content.is_null() {
543 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
544 result.extend_from_slice(core::slice::from_raw_parts(
545 (*child).content,
546 len as usize,
547 ));
548 }
549 }
550 }
551 t if t == XML_ENTITY_REF_NODE as c_int => {
552 let name = (*node).name;
554 if !name.is_null() && !(*node).doc.is_null() {
555 let ent = crate::xml::tree::get_doc_entity((*node).doc, name);
556 if !ent.is_null() && !(*ent).content.is_null() {
557 let len = crate::abi::exports_xml2::xmlStrlen((*ent).content);
558 result.extend_from_slice(core::slice::from_raw_parts(
559 (*ent).content,
560 len as usize,
561 ));
562 }
563 }
564 }
565 t if t == XML_DOCUMENT_NODE as c_int || t == XML_HTML_DOCUMENT_NODE as c_int => {
566 let root = doc_get_root_element(node as *mut _xmlDoc);
567 if !root.is_null() {
568 let sub = node_get_content(root);
569 if !sub.is_null() {
570 let len = crate::abi::exports_xml2::xmlStrlen(sub);
571 result.extend_from_slice(core::slice::from_raw_parts(sub, len as usize));
572 allocator::xmlFreeImpl(sub as *mut c_void);
573 }
574 }
575 }
576 _ => {
577 let mut child = (*node).children;
582 while !child.is_null() {
583 let ctype = (*child).type_;
584 if ctype == XML_TEXT_NODE as c_int || ctype == XML_CDATA_SECTION_NODE as c_int {
585 if !(*child).content.is_null() {
586 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
587 result.extend_from_slice(core::slice::from_raw_parts(
588 (*child).content,
589 len as usize,
590 ));
591 }
592 } else if ctype == XML_ENTITY_REF_NODE as c_int
593 || ctype == XML_ELEMENT_NODE as c_int
594 {
595 let sub = node_get_content(child);
596 if !sub.is_null() {
597 let len = crate::abi::exports_xml2::xmlStrlen(sub);
598 result.extend_from_slice(core::slice::from_raw_parts(sub, len as usize));
599 allocator::xmlFreeImpl(sub as *mut c_void);
600 }
601 }
602 child = (*child).next;
603 }
604 }
605 }
606 let buf = allocator::xmlMallocImpl(result.len() + 1) as *mut xmlChar;
608 if buf.is_null() {
609 return ptr::null_mut();
610 }
611 if !result.is_empty() {
612 ptr::copy_nonoverlapping(result.as_ptr(), buf, result.len());
613 }
614 *buf.add(result.len()) = 0;
615 buf
616}
617
618pub unsafe fn new_node(ns: *mut _xmlNs, name: *const xmlChar) -> *mut _xmlNode {
637 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
638 if node.is_null() {
639 return ptr::null_mut();
640 }
641
642 unsafe {
643 (*node).type_ = XML_ELEMENT_NODE as c_int;
644 (*node).name = dup_xml_str(name);
645 (*node).ns = ns;
646 (*node).line = 0;
647 (*node).extra = 0;
648
649 if !ns.is_null() {
650 (*ns).context = node as *mut _xmlDoc;
651 }
652 }
653
654 crate::abi::data_globals::register_node_hook(node);
657
658 node
659}
660
661pub unsafe fn free_node(node: *mut _xmlNode) {
676 if node.is_null() {
677 return;
678 }
679
680 let n = unsafe { &mut *node };
681
682 if n.type_ == XML_DTD_NODE as c_int {
686 free_dtd(node as *mut _xmlDtd);
687 return;
688 } else if n.type_ == XML_NAMESPACE_DECL as c_int {
689 free_ns(node as *mut _xmlNs);
690 return;
691 } else if n.type_ == XML_ATTRIBUTE_NODE as c_int {
692 free_prop(node as *mut _xmlAttr);
693 return;
694 } else if n.type_ == XML_ELEMENT_DECL as c_int {
695 crate::xml::dtd::free_element(node as *mut _xmlElement);
696 return;
697 } else if n.type_ == XML_ATTRIBUTE_DECL as c_int {
698 crate::xml::dtd::free_attribute(node as *mut _xmlAttribute);
699 return;
700 } else if n.type_ == XML_ENTITY_DECL as c_int {
701 crate::xml::entities::free_entity(node as *mut _xmlEntity);
702 return;
703 }
704
705 crate::abi::data_globals::deregister_node_hook(node);
708
709 let is_element = n.type_ == XML_ELEMENT_NODE as c_int;
714 if is_element && !n.properties.is_null() {
715 free_prop_list(n.properties);
716 }
717
718 if is_element && !n.nsDef.is_null() {
719 free_ns_list(n.nsDef);
720 }
721
722 if !n.name.is_null() {
724 allocator::xmlFreeImpl(n.name as *mut c_void);
725 }
726
727 if !n.content.is_null() {
732 let node_type = n.type_;
733 if node_type == XML_TEXT_NODE as c_int
734 || node_type == XML_CDATA_SECTION_NODE as c_int
735 || node_type == XML_COMMENT_NODE as c_int
736 || node_type == XML_PI_NODE as c_int
737 {
738 let inline_addr = std::ptr::addr_of_mut!((*node).properties) as *const c_void;
739 if n.content as *const c_void != inline_addr {
740 allocator::xmlFreeImpl(n.content as *mut c_void);
741 }
742 }
743 }
744
745 allocator::xmlFreeImpl(node as *mut c_void);
746}
747
748pub unsafe fn free_node_list(node: *mut _xmlNode) {
767 let mut cur = node;
768 while !cur.is_null() {
769 let next = unsafe { (*cur).next };
770 let t = unsafe { (*cur).type_ };
771
772 if t == XML_DTD_NODE as c_int {
773 unsafe {
775 (*cur).prev = ptr::null_mut();
776 (*cur).next = ptr::null_mut();
777 }
778 cur = next;
779 continue;
780 }
781
782 if t != XML_ENTITY_REF_NODE as c_int && !unsafe { (*cur).children }.is_null() {
785 free_node_list(unsafe { (*cur).children });
786 }
787
788 free_node(cur);
789 cur = next;
790 }
791}
792
793unsafe fn free_prop_list(prop: *mut _xmlAttr) {
799 let mut cur = prop;
800 while !cur.is_null() {
801 let next = unsafe { (*cur).next };
802 free_prop(cur);
803 cur = next;
804 }
805}
806
807unsafe fn free_prop(prop: *mut _xmlAttr) {
813 if prop.is_null() {
814 return;
815 }
816
817 if !unsafe { (*prop).children }.is_null() {
819 free_node_list(unsafe { (*prop).children });
820 }
821
822 if !unsafe { (*prop).name }.is_null() {
824 allocator::xmlFreeImpl(unsafe { (*prop).name } as *mut c_void);
825 }
826
827 allocator::xmlFreeImpl(prop as *mut c_void);
828}
829
830unsafe fn free_ns_list(ns: *mut _xmlNs) {
836 let mut cur = ns;
837 while !cur.is_null() {
838 let next = unsafe { (*cur).next };
839 free_ns(cur);
840 cur = next;
841 }
842}
843
844unsafe fn free_ns(ns: *mut _xmlNs) {
850 if ns.is_null() {
851 return;
852 }
853
854 if !unsafe { (*ns).href }.is_null() {
856 allocator::xmlFreeImpl(unsafe { (*ns).href } as *mut c_void);
857 }
858 if !unsafe { (*ns).prefix }.is_null() {
859 allocator::xmlFreeImpl(unsafe { (*ns).prefix } as *mut c_void);
860 }
861
862 allocator::xmlFreeImpl(ns as *mut c_void);
863}
864
865pub unsafe fn copy_node(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
880 if node.is_null() {
881 return ptr::null_mut();
882 }
883
884 let n = unsafe { &*node };
885
886 let new_node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
887 if new_node.is_null() {
888 return ptr::null_mut();
889 }
890
891 unsafe {
892 (*new_node).type_ = n.type_;
893 (*new_node).name = dup_xml_str(n.name);
894 if n.type_ == XML_ELEMENT_NODE as c_int {
898 (*new_node).line = n.line;
899 }
900 (*new_node).extra = n.extra;
901 (*new_node).psvi = n.psvi;
902 (*new_node)._private = n._private;
903
904 (*new_node).ns = n.ns;
906
907 let is_element = n.type_ == XML_ELEMENT_NODE as c_int;
910 if is_element && !n.nsDef.is_null() {
911 (*new_node).nsDef = copy_ns_list(n.nsDef);
912 }
913
914 let node_type = n.type_;
916 if (node_type == XML_TEXT_NODE as c_int
917 || node_type == XML_CDATA_SECTION_NODE as c_int
918 || node_type == XML_COMMENT_NODE as c_int
919 || node_type == XML_PI_NODE as c_int)
920 && !n.content.is_null()
921 {
922 (*new_node).content = dup_xml_str(n.content);
923 }
924
925 if is_element && !n.properties.is_null() {
927 (*new_node).properties = copy_prop_list(n.properties);
928 let mut prop = (*new_node).properties;
930 while !prop.is_null() {
931 (*prop).parent = new_node;
932 if !(*prop).children.is_null() {
933 propagate_doc((*prop).children, (*new_node).doc);
934 }
935 prop = (*prop).next;
936 }
937 }
938
939 if recursive != 0 && !n.children.is_null() {
942 (*new_node).children = copy_node_list(n.children, recursive);
943 if !(*new_node).children.is_null() {
944 let mut child = (*new_node).children;
945 let mut last_child = child;
946 while !child.is_null() {
947 (*child).parent = new_node;
948 (*child).doc = (*new_node).doc;
949 propagate_doc(child, (*new_node).doc);
950 if (*child).next.is_null() {
951 last_child = child;
952 }
953 child = (*child).next;
954 }
955 (*new_node).last = last_child;
956 }
957 }
958 }
959
960 new_node
961}
962
963unsafe fn copy_node_list(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
967 if node.is_null() {
968 return ptr::null_mut();
969 }
970
971 let n = unsafe { &*node };
972 let new_node = copy_node(node, recursive);
973 if new_node.is_null() {
974 return ptr::null_mut();
975 }
976
977 let mut prev = new_node;
978 let mut cur = n.next;
979
980 while !cur.is_null() {
981 let new_cur = copy_node(cur, recursive);
982 if new_cur.is_null() {
983 break;
984 }
985 unsafe {
986 (*prev).next = new_cur;
987 (*new_cur).prev = prev;
988 }
989 prev = new_cur;
990 cur = unsafe { (*cur).next };
991 }
992
993 new_node
994}
995
996unsafe fn copy_ns_list(ns: *const _xmlNs) -> *mut _xmlNs {
998 if ns.is_null() {
999 return ptr::null_mut();
1000 }
1001
1002 let n = unsafe { &*ns };
1003 let new_ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
1004 if new_ns.is_null() {
1005 return ptr::null_mut();
1006 }
1007
1008 unsafe {
1009 (*new_ns).type_ = n.type_;
1010 (*new_ns).href = dup_xml_str(n.href);
1011 (*new_ns).prefix = dup_xml_str(n.prefix);
1012 (*new_ns)._private = n._private;
1013 }
1014
1015 let mut prev = new_ns;
1016 let mut cur = n.next;
1017
1018 while !cur.is_null() {
1019 let c = unsafe { &*cur };
1020 let new_cur = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
1021 if new_cur.is_null() {
1022 break;
1023 }
1024 unsafe {
1025 (*new_cur).type_ = c.type_;
1026 (*new_cur).href = dup_xml_str(c.href);
1027 (*new_cur).prefix = dup_xml_str(c.prefix);
1028 (*new_cur)._private = c._private;
1029 (*prev).next = new_cur;
1030 }
1031 prev = new_cur;
1032 cur = c.next;
1033 }
1034
1035 new_ns
1036}
1037
1038unsafe fn copy_prop_list(prop: *const _xmlAttr) -> *mut _xmlAttr {
1040 if prop.is_null() {
1041 return ptr::null_mut();
1042 }
1043
1044 let p = unsafe { &*prop };
1045 let new_prop = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
1046 if new_prop.is_null() {
1047 return ptr::null_mut();
1048 }
1049
1050 unsafe {
1051 (*new_prop).type_ = p.type_;
1052 (*new_prop).name = dup_xml_str(p.name);
1053 (*new_prop).ns = p.ns;
1054 (*new_prop).atype = p.atype;
1055
1056 if !p.children.is_null() {
1058 (*new_prop).children = copy_node_list(p.children, 1);
1059 if !(*new_prop).children.is_null() {
1060 (*(*new_prop).children).parent = new_prop as *mut _xmlNode;
1061 }
1062 }
1063 }
1064
1065 let mut prev = new_prop;
1066 let mut cur = p.next;
1067
1068 while !cur.is_null() {
1069 let c = unsafe { &*cur };
1070 let new_cur = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
1071 if new_cur.is_null() {
1072 break;
1073 }
1074 unsafe {
1075 (*new_cur).type_ = c.type_;
1076 (*new_cur).name = dup_xml_str(c.name);
1077 (*new_cur).ns = c.ns;
1078 (*new_cur).atype = c.atype;
1079
1080 if !c.children.is_null() {
1081 (*new_cur).children = copy_node_list(c.children, 1);
1082 if !(*new_cur).children.is_null() {
1083 (*(*new_cur).children).parent = new_cur as *mut _xmlNode;
1084 }
1085 }
1086
1087 (*prev).next = new_cur;
1088 }
1089 prev = new_cur;
1090 cur = c.next;
1091 }
1092
1093 new_prop
1094}
1095
1096unsafe fn propagate_doc(node: *mut _xmlNode, doc: *mut _xmlDoc) {
1098 let mut cur = node;
1099 while !cur.is_null() {
1100 unsafe {
1101 (*cur).doc = doc;
1102
1103 if (*cur).type_ == XML_ELEMENT_NODE as c_int {
1107 let mut prop = (*cur).properties;
1108 while !prop.is_null() {
1109 (*prop).doc = doc;
1110 if !(*prop).children.is_null() {
1111 propagate_doc((*prop).children, doc);
1112 }
1113 prop = (*prop).next;
1114 }
1115 }
1116
1117 if !(*cur).children.is_null() {
1119 propagate_doc((*cur).children, doc);
1120 }
1121 }
1122 cur = unsafe { (*cur).next };
1123 }
1124}
1125
1126pub unsafe fn unlink_node(node: *mut _xmlNode) {
1142 if node.is_null() {
1143 return;
1144 }
1145
1146 let n = unsafe { &mut *node };
1147
1148 let prev = n.prev;
1150 let next = n.next;
1151
1152 if !prev.is_null() {
1153 unsafe { (*prev).next = next };
1154 }
1155 if !next.is_null() {
1156 unsafe { (*next).prev = prev };
1157 }
1158
1159 let parent = n.parent;
1161 if !parent.is_null() {
1162 if unsafe { (*parent).children } == node {
1163 unsafe { (*parent).children = next };
1164 }
1165 if unsafe { (*parent).last } == node {
1166 unsafe { (*parent).last = prev };
1167 }
1168 }
1169
1170 let doc = n.doc;
1172 if !doc.is_null() && !parent.is_null() {
1173 }
1175 if !doc.is_null() && parent.is_null() {
1176 if unsafe { (*doc).children } == node {
1178 unsafe { (*doc).children = next };
1179 }
1180 if unsafe { (*doc).last } == node {
1181 unsafe { (*doc).last = prev };
1182 }
1183 }
1184
1185 n.parent = ptr::null_mut();
1187 n.prev = ptr::null_mut();
1188 n.next = ptr::null_mut();
1189}
1190
1191pub unsafe fn add_child(parent: *mut _xmlNode, cur: *mut _xmlNode) -> *mut _xmlNode {
1207 if parent.is_null() || cur.is_null() {
1208 return ptr::null_mut();
1209 }
1210
1211 let p = unsafe { &mut *parent };
1212 let c = unsafe { &mut *cur };
1213
1214 if !c.parent.is_null() || !c.prev.is_null() || !c.next.is_null() {
1216 unlink_node(cur);
1217 }
1218
1219 c.parent = parent;
1221
1222 if p.children.is_null() {
1223 p.children = cur;
1225 p.last = cur;
1226 c.prev = ptr::null_mut();
1227 c.next = ptr::null_mut();
1228 } else {
1229 c.prev = p.last;
1231 c.next = ptr::null_mut();
1232 if !p.last.is_null() {
1233 unsafe { (*p.last).next = cur };
1234 }
1235 p.last = cur;
1236 }
1237
1238 let doc = if !p.doc.is_null() {
1240 p.doc
1241 } else {
1242 ptr::null_mut()
1243 };
1244 if !doc.is_null() && c.doc != doc {
1245 propagate_doc(cur, doc);
1246 }
1247
1248 cur
1249}
1250
1251pub unsafe fn add_sibling(cur: *mut _xmlNode, elem: *mut _xmlNode) -> *mut _xmlNode {
1267 if cur.is_null() || elem.is_null() {
1268 return ptr::null_mut();
1269 }
1270
1271 let c = unsafe { &mut *cur };
1272
1273 let e = unsafe { &mut *elem };
1275 if !e.parent.is_null() || !e.prev.is_null() || !e.next.is_null() {
1276 unlink_node(elem);
1277 }
1278
1279 e.parent = c.parent;
1281
1282 e.prev = cur;
1284 e.next = c.next;
1285
1286 if !c.next.is_null() {
1287 unsafe { (*c.next).prev = elem };
1288 }
1289 c.next = elem;
1290
1291 let parent = c.parent;
1293 if !parent.is_null() && unsafe { (*parent).last } == cur {
1294 unsafe { (*parent).last = elem };
1295 }
1296
1297 if !c.doc.is_null() && e.doc != c.doc {
1299 propagate_doc(elem, c.doc);
1300 }
1301
1302 elem
1303}
1304
1305pub unsafe fn add_sibling_before(cur: *mut _xmlNode, elem: *mut _xmlNode) -> *mut _xmlNode {
1321 if cur.is_null() || elem.is_null() {
1322 return ptr::null_mut();
1323 }
1324
1325 let c = unsafe { &mut *cur };
1326
1327 let e = unsafe { &mut *elem };
1329 if !e.parent.is_null() || !e.prev.is_null() || !e.next.is_null() {
1330 unlink_node(elem);
1331 }
1332
1333 e.parent = c.parent;
1335
1336 e.prev = c.prev;
1338 e.next = cur;
1339
1340 if !c.prev.is_null() {
1341 unsafe { (*c.prev).next = elem };
1342 }
1343 c.prev = elem;
1344
1345 let parent = c.parent;
1347 if !parent.is_null() && unsafe { (*parent).children } == cur {
1348 unsafe { (*parent).children = elem };
1349 }
1350
1351 let doc = c.doc;
1353 if !doc.is_null() && parent.is_null() && unsafe { (*doc).children } == cur {
1354 unsafe { (*doc).children = elem };
1355 }
1356
1357 if !c.doc.is_null() && e.doc != c.doc {
1359 propagate_doc(elem, c.doc);
1360 }
1361
1362 elem
1363}
1364
1365pub unsafe fn new_child(
1380 parent: *mut _xmlNode,
1381 ns: *mut _xmlNs,
1382 name: *const xmlChar,
1383) -> *mut _xmlNode {
1384 let node = new_node(ns, name);
1385 if node.is_null() {
1386 return ptr::null_mut();
1387 }
1388
1389 if !parent.is_null() {
1390 add_child(parent, node);
1391 }
1392
1393 node
1394}
1395
1396pub unsafe fn new_text(content: *const xmlChar) -> *mut _xmlNode {
1415 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1416 if node.is_null() {
1417 return ptr::null_mut();
1418 }
1419
1420 unsafe {
1421 (*node).type_ = XML_TEXT_NODE as c_int;
1422 (*node).name = dup_xml_str(b"text\0" as *const u8 as *const xmlChar);
1423 (*node).content = if content.is_null() {
1424 let empty = allocator::xmlMallocImpl(1) as *mut xmlChar;
1425 if !empty.is_null() {
1426 *empty = 0;
1427 }
1428 empty
1429 } else {
1430 dup_xml_str(content)
1431 };
1432 (*node).line = 0;
1433 }
1434
1435 crate::abi::data_globals::register_node_hook(node);
1438
1439 node
1440}
1441
1442pub unsafe fn new_comment(content: *const xmlChar) -> *mut _xmlNode {
1456 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1457 if node.is_null() {
1458 return ptr::null_mut();
1459 }
1460
1461 unsafe {
1462 (*node).type_ = XML_COMMENT_NODE as c_int;
1463 (*node).name = dup_xml_str(b"comment\0" as *const u8 as *const xmlChar);
1464 (*node).content = dup_xml_str(content);
1465 (*node).line = 0;
1466 }
1467
1468 crate::abi::data_globals::register_node_hook(node);
1471
1472 node
1473}
1474
1475pub unsafe fn new_pi(name: *const xmlChar, content: *const xmlChar) -> *mut _xmlNode {
1490 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1491 if node.is_null() {
1492 return ptr::null_mut();
1493 }
1494
1495 unsafe {
1496 (*node).type_ = XML_PI_NODE as c_int;
1497 (*node).name = dup_xml_str(name);
1498 (*node).content = dup_xml_str(content);
1499 (*node).line = 0;
1500 }
1501
1502 crate::abi::data_globals::register_node_hook(node);
1505
1506 node
1507}
1508
1509pub unsafe fn new_cdata_block(
1525 doc: *mut _xmlDoc,
1526 content: *const xmlChar,
1527 len: c_int,
1528) -> *mut _xmlNode {
1529 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1530 if node.is_null() {
1531 return ptr::null_mut();
1532 }
1533
1534 unsafe {
1535 (*node).type_ = XML_CDATA_SECTION_NODE as c_int;
1536 (*node).doc = doc;
1539
1540 if !content.is_null() && len > 0 {
1541 (*node).content = allocator::xmlMallocImpl((len + 1) as usize) as *mut xmlChar;
1542 if !(*node).content.is_null() {
1543 ptr::copy_nonoverlapping(content, (*node).content, len as usize);
1544 *((*node).content.add(len as usize)) = 0;
1545 }
1546 } else {
1547 let empty = allocator::xmlMallocImpl(1) as *mut xmlChar;
1548 if !empty.is_null() {
1549 *empty = 0;
1550 }
1551 (*node).content = empty;
1552 }
1553
1554 (*node).line = 0;
1555 }
1556
1557 node
1558}
1559
1560pub unsafe fn new_ns(
1584 node: *mut _xmlNode,
1585 href: *const xmlChar,
1586 prefix: *const xmlChar,
1587) -> *mut _xmlNs {
1588 let ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
1589 if ns.is_null() {
1590 return ptr::null_mut();
1591 }
1592
1593 unsafe {
1594 (*ns).type_ = XML_LOCAL_NAMESPACE as c_int;
1595 (*ns).href = dup_xml_str(href);
1596 (*ns).prefix = dup_xml_str(prefix);
1597 (*ns).context = node as *mut _xmlDoc;
1598
1599 if !node.is_null() {
1601 let n = &mut *node;
1602 if n.nsDef.is_null() {
1603 n.nsDef = ns;
1604 } else {
1605 let mut last = n.nsDef;
1607 while !(*last).next.is_null() {
1608 last = (*last).next;
1609 }
1610 (*last).next = ns;
1611 }
1612 }
1613 }
1614
1615 ns
1616}
1617
1618pub unsafe fn set_ns(node: *mut _xmlNode, ns: *mut _xmlNs) {
1631 if node.is_null() {
1632 return;
1633 }
1634 unsafe {
1635 (*node).ns = ns;
1636 }
1637}
1638
1639pub unsafe fn get_ns_list(_doc: *mut _xmlDoc, node: *mut _xmlNode) -> *mut *mut _xmlNs {
1655 if node.is_null() {
1659 return ptr::null_mut();
1660 }
1661
1662 let mut ns_ptrs: Vec<*mut _xmlNs> = Vec::new();
1664 let mut cur = node;
1665
1666 while !cur.is_null() {
1667 let n = unsafe { &*cur };
1668 let mut ns_def = n.nsDef;
1669 while !ns_def.is_null() {
1670 let ns = unsafe { &*ns_def };
1672 let mut found = false;
1673 for &existing in &ns_ptrs {
1674 if existing == ns_def {
1675 found = true;
1676 break;
1677 }
1678 let e = unsafe { &*existing };
1679 if !ns.href.is_null() && !e.href.is_null() {
1680 let href_match =
1681 unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, e.href) != 0 };
1682 if href_match {
1683 if ns.prefix.is_null() && e.prefix.is_null() {
1684 found = true;
1685 break;
1686 }
1687 if !ns.prefix.is_null() && !e.prefix.is_null() {
1688 let prefix_match = unsafe {
1689 crate::abi::exports_xml2::xmlStrEqual(ns.prefix, e.prefix) != 0
1690 };
1691 if prefix_match {
1692 found = true;
1693 break;
1694 }
1695 }
1696 }
1697 }
1698 }
1699 if !found {
1700 ns_ptrs.push(ns_def);
1701 }
1702 ns_def = unsafe { (*ns_def).next };
1703 }
1704 cur = n.parent;
1705 }
1706
1707 if ns_ptrs.is_empty() {
1708 return ptr::null_mut();
1709 }
1710
1711 let arr = allocator::xmlMallocImpl((ns_ptrs.len() + 1) * size_of::<*mut _xmlNs>())
1713 as *mut *mut _xmlNs;
1714 if arr.is_null() {
1715 return ptr::null_mut();
1716 }
1717
1718 for (i, ns) in ns_ptrs.iter().enumerate() {
1719 unsafe { *arr.add(i) = *ns };
1720 }
1721 unsafe { *arr.add(ns_ptrs.len()) = ptr::null_mut() };
1722
1723 arr
1724}
1725
1726pub unsafe fn search_ns(
1743 _doc: *mut _xmlDoc,
1744 node: *mut _xmlNode,
1745 name_space: *const xmlChar,
1746) -> *mut _xmlNs {
1747 if node.is_null() {
1748 return ptr::null_mut();
1749 }
1750
1751 let mut cur = node;
1752 while !cur.is_null() {
1753 let n = unsafe { &*cur };
1754 let mut ns_def = n.nsDef;
1755 while !ns_def.is_null() {
1756 let ns = unsafe { &*ns_def };
1757 let match_prefix = if name_space.is_null() {
1758 ns.prefix.is_null()
1760 } else {
1761 !ns.prefix.is_null()
1762 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.prefix, name_space) != 0 }
1763 };
1764 if match_prefix {
1765 return ns_def;
1766 }
1767 ns_def = unsafe { (*ns_def).next };
1768 }
1769 cur = n.parent;
1770 }
1771
1772 ptr::null_mut()
1773}
1774
1775pub unsafe fn search_ns_by_href(
1791 _doc: *mut _xmlDoc,
1792 node: *mut _xmlNode,
1793 href: *const xmlChar,
1794) -> *mut _xmlNs {
1795 if node.is_null() || href.is_null() {
1796 return ptr::null_mut();
1797 }
1798
1799 let mut cur = node;
1800 while !cur.is_null() {
1801 let n = unsafe { &*cur };
1802 let mut ns_def = n.nsDef;
1803 while !ns_def.is_null() {
1804 let ns = unsafe { &*ns_def };
1805 if !ns.href.is_null()
1806 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, href) != 0 }
1807 {
1808 return ns_def;
1809 }
1810 ns_def = unsafe { (*ns_def).next };
1811 }
1812 cur = n.parent;
1813 }
1814
1815 ptr::null_mut()
1816}
1817
1818pub unsafe fn set_prop(
1842 node: *mut _xmlNode,
1843 name: *const xmlChar,
1844 value: *const xmlChar,
1845) -> *mut _xmlAttr {
1846 if node.is_null() || name.is_null() {
1847 return ptr::null_mut();
1848 }
1849
1850 let n = unsafe { &mut *node };
1851
1852 let mut existing = n.properties;
1854 while !existing.is_null() {
1855 let attr = unsafe { &*existing };
1856 if !attr.name.is_null()
1857 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1858 {
1859 if !attr.children.is_null() {
1862 free_node_list(attr.children);
1863 let attr_mut = existing;
1865 unsafe { (*attr_mut).children = ptr::null_mut() };
1866 unsafe { (*attr_mut).last = ptr::null_mut() };
1867 }
1868 if !value.is_null() {
1870 let text = new_text(value);
1871 if !text.is_null() {
1872 let attr_mut = existing;
1873 unsafe {
1874 (*attr_mut).children = text;
1875 (*attr_mut).last = text;
1876 (*text).parent = existing as *mut _xmlNode;
1877 (*text).doc = n.doc;
1878 }
1879 }
1880 }
1881 return existing;
1882 }
1883 existing = unsafe { (*existing).next };
1884 }
1885
1886 let attr = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
1888 if attr.is_null() {
1889 return ptr::null_mut();
1890 }
1891
1892 unsafe {
1893 (*attr).type_ = XML_ATTRIBUTE_NODE as c_int;
1894 (*attr).name = dup_xml_str(name);
1895 (*attr).parent = node;
1896 (*attr).doc = n.doc;
1897 if !value.is_null() {
1902 let text = new_text(value);
1903 if !text.is_null() {
1904 (*attr).children = text;
1905 (*attr).last = text;
1906 (*text).parent = attr as *mut _xmlNode;
1907 (*text).doc = n.doc;
1908 }
1909 }
1910
1911 if n.properties.is_null() {
1913 n.properties = attr;
1914 } else {
1915 let mut last = n.properties;
1916 while !(*last).next.is_null() {
1917 last = (*last).next;
1918 }
1919 (*last).next = attr;
1920 (*attr).prev = last;
1921 }
1922 }
1923
1924 attr
1925}
1926
1927pub unsafe fn get_prop(node: *mut _xmlNode, name: *const xmlChar) -> *mut xmlChar {
1943 if node.is_null() || name.is_null() {
1944 return ptr::null_mut();
1945 }
1946
1947 let n = unsafe { &*node };
1948 let mut cur = n.properties;
1949
1950 while !cur.is_null() {
1951 let attr = unsafe { &*cur };
1952 if !attr.name.is_null()
1953 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1954 {
1955 if !attr.children.is_null() {
1957 let text = unsafe { &*attr.children };
1958 if text.type_ == XML_TEXT_NODE as c_int && !text.content.is_null() {
1959 return dup_xml_str(text.content);
1960 }
1961 }
1962 return dup_xml_str(b"\0" as *const u8 as *const xmlChar);
1963 }
1964 cur = unsafe { (*cur).next };
1965 }
1966
1967 ptr::null_mut()
1968}
1969
1970pub unsafe fn get_ns_prop(
1986 node: *mut _xmlNode,
1987 name: *const xmlChar,
1988 _name_space: *const xmlChar,
1989) -> *mut xmlChar {
1990 get_prop(node, name)
1993}
1994
1995pub unsafe fn set_ns_prop(
2010 node: *mut _xmlNode,
2011 _ns: *mut _xmlNs,
2012 name: *const xmlChar,
2013 value: *const xmlChar,
2014) -> *mut _xmlAttr {
2015 set_prop(node, name, value)
2017}
2018
2019pub unsafe fn remove_prop(attr: *mut _xmlAttr) -> c_int {
2034 if attr.is_null() {
2035 return -1;
2036 }
2037
2038 let a = unsafe { &mut *attr };
2039
2040 let parent = a.parent;
2042 if !parent.is_null() {
2043 let p = unsafe { &mut *parent };
2044 if p.properties == attr {
2045 p.properties = a.next;
2046 }
2047 }
2048
2049 if !a.prev.is_null() {
2051 unsafe { (*a.prev).next = a.next };
2052 }
2053 if !a.next.is_null() {
2054 unsafe { (*a.next).prev = a.prev };
2055 }
2056
2057 if !a.children.is_null() {
2059 free_node_list(a.children);
2060 }
2061
2062 if !a.name.is_null() {
2064 allocator::xmlFreeImpl(a.name as *mut c_void);
2065 }
2066
2067 allocator::xmlFreeImpl(attr as *mut c_void);
2068 0
2069}
2070
2071pub unsafe fn has_prop(node: *mut _xmlNode, name: *const xmlChar) -> *mut _xmlAttr {
2079 if node.is_null() || name.is_null() {
2080 return ptr::null_mut();
2081 }
2082 let mut cur = unsafe { (*node).properties };
2083 while !cur.is_null() {
2084 let attr = unsafe { &*cur };
2085 if !attr.name.is_null()
2086 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
2087 && attr.ns.is_null()
2088 {
2089 return cur;
2090 }
2091 cur = unsafe { (*cur).next };
2092 }
2093 ptr::null_mut()
2094}
2095
2096pub unsafe fn has_ns_prop(
2106 node: *mut _xmlNode,
2107 name: *const xmlChar,
2108 name_space: *const xmlChar,
2109) -> *mut _xmlAttr {
2110 if node.is_null() || name.is_null() {
2111 return ptr::null_mut();
2112 }
2113 let mut cur = unsafe { (*node).properties };
2114 while !cur.is_null() {
2115 let attr = unsafe { &*cur };
2116 if !attr.name.is_null()
2117 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
2118 {
2119 if name_space.is_null() {
2120 if attr.ns.is_null() {
2121 return cur;
2122 }
2123 } else if !attr.ns.is_null()
2124 && !(*attr.ns).href.is_null()
2125 && unsafe {
2126 crate::abi::exports_xml2::xmlStrEqual((*attr.ns).href, name_space) != 0
2127 }
2128 {
2129 return cur;
2130 }
2131 }
2132 cur = unsafe { (*cur).next };
2133 }
2134 ptr::null_mut()
2135}
2136
2137pub unsafe fn unset_prop(node: *mut _xmlNode, name: *const xmlChar) -> c_int {
2146 let attr = unsafe { has_prop(node, name) };
2147 if attr.is_null() {
2148 return -1;
2149 }
2150 unsafe { remove_prop(attr) }
2151}
2152
2153pub unsafe fn unset_ns_prop(
2161 node: *mut _xmlNode,
2162 name: *const xmlChar,
2163 name_space: *const xmlChar,
2164) -> c_int {
2165 let attr = unsafe { has_ns_prop(node, name, name_space) };
2166 if attr.is_null() {
2167 return -1;
2168 }
2169 unsafe { remove_prop(attr) }
2170}
2171
2172pub unsafe fn first_element_child(node: *mut _xmlNode) -> *mut _xmlNode {
2179 if node.is_null() {
2180 return ptr::null_mut();
2181 }
2182 let mut cur = unsafe { (*node).children };
2183 while !cur.is_null() {
2184 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2185 return cur;
2186 }
2187 cur = unsafe { (*cur).next };
2188 }
2189 ptr::null_mut()
2190}
2191
2192pub unsafe fn last_element_child(node: *mut _xmlNode) -> *mut _xmlNode {
2199 if node.is_null() {
2200 return ptr::null_mut();
2201 }
2202 let mut cur = unsafe { (*node).last };
2203 while !cur.is_null() {
2204 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2205 return cur;
2206 }
2207 cur = unsafe { (*cur).prev };
2208 }
2209 ptr::null_mut()
2210}
2211
2212pub unsafe fn next_element_sibling(node: *mut _xmlNode) -> *mut _xmlNode {
2219 if node.is_null() {
2220 return ptr::null_mut();
2221 }
2222 let mut cur = unsafe { (*node).next };
2223 while !cur.is_null() {
2224 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2225 return cur;
2226 }
2227 cur = unsafe { (*cur).next };
2228 }
2229 ptr::null_mut()
2230}
2231
2232pub unsafe fn previous_element_sibling(node: *mut _xmlNode) -> *mut _xmlNode {
2239 if node.is_null() {
2240 return ptr::null_mut();
2241 }
2242 let mut cur = unsafe { (*node).prev };
2243 while !cur.is_null() {
2244 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2245 return cur;
2246 }
2247 cur = unsafe { (*cur).prev };
2248 }
2249 ptr::null_mut()
2250}
2251
2252pub unsafe fn child_element_count(node: *mut _xmlNode) -> c_ulong {
2259 if node.is_null() {
2260 return 0;
2261 }
2262 let mut cur = unsafe { (*node).children };
2263 let mut count: c_ulong = 0;
2264 while !cur.is_null() {
2265 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2266 count += 1;
2267 }
2268 cur = unsafe { (*cur).next };
2269 }
2270 count
2271}
2272
2273pub unsafe fn text_concat(node: *mut _xmlNode, str: *const xmlChar, num: c_int) -> c_int {
2282 if node.is_null() || str.is_null() || num <= 0 {
2283 return -1;
2284 }
2285 let cur = unsafe { &mut *node };
2286 if cur.content.is_null() {
2287 let p = unsafe { allocator::xmlMallocImpl(num as usize + 1) as *mut xmlChar };
2288 if p.is_null() {
2289 return -1;
2290 }
2291 unsafe {
2292 ptr::copy_nonoverlapping(str, p, num as usize);
2293 *p.add(num as usize) = 0;
2294 }
2295 cur.content = p;
2296 return 0;
2297 }
2298 let old_len = unsafe { crate::xml::string::xml_strlen(cur.content) };
2299 let p = unsafe {
2300 allocator::xmlReallocImpl(cur.content as *mut c_void, old_len + num as usize + 1)
2301 as *mut xmlChar
2302 };
2303 if p.is_null() {
2304 return -1;
2305 }
2306 unsafe {
2307 ptr::copy_nonoverlapping(str, p.add(old_len), num as usize);
2308 *p.add(old_len + num as usize) = 0;
2309 }
2310 cur.content = p;
2311 0
2312}
2313
2314pub unsafe fn text_merge(text: *mut _xmlNode, ntext: *mut _xmlNode) -> *mut _xmlNode {
2322 if text.is_null() || ntext.is_null() {
2323 return ptr::null_mut();
2324 }
2325 if unsafe { (*ntext).content.is_null() } {
2326 unsafe { free_node(ntext) };
2327 return text;
2328 }
2329 let num = unsafe { crate::xml::string::xml_strlen((*ntext).content) };
2330 if unsafe { text_concat(text, (*ntext).content, num as c_int) } != 0 {
2331 return ptr::null_mut();
2332 }
2333 unsafe { free_node(ntext) };
2334 text
2335}
2336
2337pub const fn get_int_subset(doc: *const _xmlDoc) -> *mut _xmlDtd {
2349 if doc.is_null() {
2350 return ptr::null_mut();
2351 }
2352 let d = unsafe { &*doc };
2353 d.intSubset
2354}
2355
2356pub unsafe fn new_dtd(
2373 doc: *mut _xmlDoc,
2374 name: *const xmlChar,
2375 ExternalID: *const xmlChar,
2376 SystemID: *const xmlChar,
2377) -> *mut _xmlDtd {
2378 let dtd = allocator::xmlMallocZero(size_of::<_xmlDtd>() as usize) as *mut _xmlDtd;
2379 if dtd.is_null() {
2380 return ptr::null_mut();
2381 }
2382
2383 unsafe {
2384 (*dtd).type_ = XML_DTD_NODE as c_int;
2385 (*dtd).name = dup_xml_str(name);
2386 (*dtd).ExternalID = dup_xml_str(ExternalID);
2387 (*dtd).SystemID = dup_xml_str(SystemID);
2388 (*dtd).parent = doc;
2389 (*dtd).doc = doc;
2390
2391 if !doc.is_null() && (*doc).intSubset.is_null() {
2397 (*doc).intSubset = dtd;
2398 }
2399 }
2400
2401 dtd
2402}
2403
2404unsafe fn free_dtd(dtd: *mut _xmlDtd) {
2410 if dtd.is_null() {
2411 return;
2412 }
2413
2414 let _d = unsafe { &mut *dtd };
2415 let d = &mut *dtd;
2416
2417 if !d.children.is_null() {
2424 let mut c = d.children;
2425 while !c.is_null() {
2426 let next = (*c).next;
2427 let t = (*c).type_;
2428 if t != XML_ELEMENT_DECL as c_int
2429 && t != XML_ATTRIBUTE_DECL as c_int
2430 && t != XML_ENTITY_DECL as c_int
2431 {
2432 unlink_node_internal(c, ptr::null_mut());
2433 free_node(c);
2434 }
2435 c = next;
2436 }
2437 }
2438
2439 if !d.name.is_null() {
2441 allocator::xmlFreeImpl(d.name as *mut c_void);
2442 }
2443 if !d.ExternalID.is_null() {
2444 allocator::xmlFreeImpl(d.ExternalID as *mut c_void);
2445 }
2446 if !d.SystemID.is_null() {
2447 allocator::xmlFreeImpl(d.SystemID as *mut c_void);
2448 }
2449
2450 unsafe extern "C" fn free_notation_wrapper(payload: *mut c_void, _name: *mut u8) {
2452 crate::xml::dtd::free_notation(payload as *mut _xmlNotation);
2453 }
2454 unsafe extern "C" fn free_element_wrapper(payload: *mut c_void, _name: *mut u8) {
2455 crate::xml::dtd::free_element(payload as *mut _xmlElement);
2456 }
2457 unsafe extern "C" fn free_attribute_wrapper(payload: *mut c_void, _name: *mut u8) {
2458 crate::xml::dtd::free_attribute(payload as *mut _xmlAttribute);
2459 }
2460 unsafe extern "C" fn free_entity_wrapper(payload: *mut c_void, _name: *mut u8) {
2461 crate::xml::entities::free_entity(payload as *mut _xmlEntity);
2462 }
2463
2464 if !d.notations.is_null() {
2465 crate::xml::hash::hash_free(
2466 d.notations as *mut crate::xml::hash::HashTable,
2467 Some(free_notation_wrapper),
2468 );
2469 d.notations = ptr::null_mut();
2470 }
2471 if !d.elements.is_null() {
2472 crate::xml::hash::hash_free(
2473 d.elements as *mut crate::xml::hash::HashTable,
2474 Some(free_element_wrapper),
2475 );
2476 d.elements = ptr::null_mut();
2477 }
2478 if !d.attributes.is_null() {
2479 crate::xml::hash::hash_free(
2480 d.attributes as *mut crate::xml::hash::HashTable,
2481 Some(free_attribute_wrapper),
2482 );
2483 d.attributes = ptr::null_mut();
2484 }
2485 if !d.entities.is_null() {
2486 crate::xml::hash::hash_free(
2487 d.entities as *mut crate::xml::hash::HashTable,
2488 Some(free_entity_wrapper),
2489 );
2490 d.entities = ptr::null_mut();
2491 }
2492 if !d.pentities.is_null() {
2493 crate::xml::hash::hash_free(
2494 d.pentities as *mut crate::xml::hash::HashTable,
2495 Some(free_entity_wrapper),
2496 );
2497 d.pentities = ptr::null_mut();
2498 }
2499
2500 allocator::xmlFreeImpl(dtd as *mut c_void);
2501}
2502
2503pub unsafe fn new_entity(
2523 _doc: *mut _xmlDoc,
2524 name: *const xmlChar,
2525 etype: c_int,
2526 ExternalID: *const xmlChar,
2527 SystemID: *const xmlChar,
2528 content: *const xmlChar,
2529) -> *mut _xmlEntity {
2530 let entity = allocator::xmlMallocZero(size_of::<_xmlEntity>() as usize) as *mut _xmlEntity;
2531 if entity.is_null() {
2532 return ptr::null_mut();
2533 }
2534
2535 unsafe {
2536 (*entity).type_ = XML_ENTITY_DECL as c_int;
2537 (*entity).name = dup_xml_str(name);
2538 (*entity).etype = etype;
2539 (*entity).ExternalID = dup_xml_str(ExternalID);
2540 (*entity).SystemID = dup_xml_str(SystemID);
2541 (*entity).content = dup_xml_str(content);
2542 (*entity).length = if content.is_null() {
2543 0
2544 } else {
2545 crate::abi::exports_xml2::xmlStrlen(content)
2546 };
2547 (*entity).flags = 0;
2548 (*entity).expandedSize = 0;
2549 }
2550
2551 entity
2552}
2553
2554pub unsafe fn get_doc_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2569 crate::xml::entities::get_entity(doc as *mut _xmlDoc, name)
2570}
2571
2572pub unsafe fn add_doc_entity(
2580 doc: *mut _xmlDoc,
2581 name: *const xmlChar,
2582 etype: c_int,
2583 ExternalID: *const xmlChar,
2584 SystemID: *const xmlChar,
2585 content: *const xmlChar,
2586) -> *mut _xmlEntity {
2587 if doc.is_null() || name.is_null() {
2588 return ptr::null_mut();
2589 }
2590 unsafe {
2591 let mut dtd = (*doc).intSubset;
2592 if dtd.is_null() {
2593 dtd = new_dtd(
2594 doc,
2595 c"internal".as_ptr() as *const xmlChar,
2596 ptr::null(),
2597 ptr::null(),
2598 );
2599 if dtd.is_null() {
2600 return ptr::null_mut();
2601 }
2602 }
2603 crate::xml::entities::add_entity(dtd, name, etype, ExternalID, SystemID, content)
2604 }
2605}
2606
2607pub unsafe fn add_dtd_entity(
2615 doc: *mut _xmlDoc,
2616 name: *const xmlChar,
2617 etype: c_int,
2618 ExternalID: *const xmlChar,
2619 SystemID: *const xmlChar,
2620 content: *const xmlChar,
2621) -> *mut _xmlEntity {
2622 if doc.is_null() || name.is_null() {
2623 return ptr::null_mut();
2624 }
2625 unsafe {
2626 let mut dtd = (*doc).extSubset;
2627 if dtd.is_null() {
2628 dtd = new_dtd(
2629 doc,
2630 c"internal".as_ptr() as *const xmlChar,
2631 ptr::null(),
2632 ptr::null(),
2633 );
2634 if dtd.is_null() {
2635 return ptr::null_mut();
2636 }
2637 (*doc).extSubset = dtd;
2638 }
2639 crate::xml::entities::add_entity(dtd, name, etype, ExternalID, SystemID, content)
2640 }
2641}
2642
2643pub unsafe fn get_dtd_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2651 if doc.is_null() || name.is_null() {
2652 return ptr::null_mut();
2653 }
2654 unsafe {
2655 if !(*doc).intSubset.is_null() {
2656 let e = crate::xml::entities::get_entity_from_dtd((*doc).intSubset, name);
2657 if !e.is_null() {
2658 return e;
2659 }
2660 }
2661 if !(*doc).extSubset.is_null() {
2662 return crate::xml::entities::get_entity_from_dtd((*doc).extSubset, name);
2663 }
2664 ptr::null_mut()
2665 }
2666}
2667
2668pub unsafe fn get_parameter_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2681 crate::xml::entities::get_parameter_entity(doc as *mut _xmlDoc, name)
2682}
2683
2684const ENTITY_LT: &[xmlChar] = b"<";
2693const ENTITY_GT: &[xmlChar] = b">";
2694const ENTITY_AMP: &[xmlChar] = b"&";
2695const ENTITY_QUOT: &[xmlChar] = b""";
2696#[allow(dead_code)]
2697const ENTITY_APOS: &[xmlChar] = b"'";
2698
2699const INDENT: &[xmlChar] = b" ";
2701
2702const MAX_INDENT: c_int = 60;
2704
2705pub(crate) unsafe fn serialize_text(buf: *mut _xmlBuffer, content: *const xmlChar, len: c_int) {
2720 if buf.is_null() || content.is_null() || len <= 0 {
2721 return;
2722 }
2723
2724 let mut i: c_int = 0;
2725 while i < len {
2726 let ch = unsafe { *content.add(i as usize) };
2727
2728 if ch == b']'
2730 && i + 2 < len
2731 && unsafe { *content.add(i as usize + 1) == b']' }
2732 && unsafe { *content.add(i as usize + 2) == b'>' }
2733 {
2734 io::buf_add(buf, &ch as *const u8, 2); io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2737 i += 3;
2738 continue;
2739 }
2740
2741 match ch {
2742 b'<' => {
2743 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
2744 }
2745 b'&' => {
2746 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
2747 }
2748 b'>' => {
2749 io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2753 }
2754 b'\r' => {
2755 io::buf_add(buf, b" " as *const u8, 5);
2757 }
2758 0x01..=0x08 | 0x0B | 0x0C | 0x0E..=0x1F => {
2759 let hex = format!("&#x{:X};", ch);
2761 io::buf_add(buf, hex.as_ptr(), hex.len() as c_int);
2762 }
2763 _ => {
2764 io::buf_add(buf, &ch as *const u8, 1);
2765 }
2766 }
2767 i += 1;
2768 }
2769}
2770
2771pub(crate) unsafe fn serialize_attr_value(buf: *mut _xmlBuffer, value: *const xmlChar) {
2784 if buf.is_null() || value.is_null() {
2785 return;
2786 }
2787
2788 let len = xml_strlen(value);
2789 let mut i: c_int = 0;
2790 while i < len {
2791 let ch = unsafe { *value.add(i as usize) };
2792
2793 match ch {
2794 b'\n' => {
2795 io::buf_add(buf, b" " as *const u8, 5);
2796 }
2797 b'\r' => {
2798 io::buf_add(buf, b" " as *const u8, 5);
2799 }
2800 b'\t' => {
2801 io::buf_add(buf, b"	" as *const u8, 4);
2802 }
2803 b'<' => {
2804 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
2805 }
2806 b'&' => {
2807 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
2808 }
2809 b'"' => {
2810 io::buf_add(buf, ENTITY_QUOT.as_ptr(), ENTITY_QUOT.len() as c_int);
2811 }
2812 b'>' => {
2813 io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2814 }
2815 _ => {
2816 io::buf_add(buf, &ch as *const u8, 1);
2817 }
2818 }
2819 i += 1;
2820 }
2821}
2822
2823unsafe fn write_indent(
2835 buf: *mut _xmlBuffer,
2836 level: c_int,
2837 indent: *const xmlChar,
2838 indent_len: c_int,
2839) {
2840 if buf.is_null() || level <= 0 || indent.is_null() || indent_len <= 0 {
2841 return;
2842 }
2843 let indent_nr = MAX_INDENT / indent_len;
2844 let mut lvl = level;
2845 if lvl > indent_nr {
2846 lvl = indent_nr;
2847 }
2848 for _ in 0..lvl {
2849 io::buf_add(buf, indent, indent_len);
2850 }
2851}
2852
2853unsafe fn is_noenc_text(node: *mut _xmlNode) -> bool {
2861 if node.is_null() {
2862 return false;
2863 }
2864 let n = unsafe { &*node };
2865 if n.name.is_null() {
2866 return false;
2867 }
2868 c_str_eq_bytes(n.name, b"textnoenc")
2869}
2870
2871const unsafe fn c_str_eq_bytes(s: *const xmlChar, b: &[u8]) -> bool {
2873 let mut i = 0usize;
2874 while i < b.len() {
2875 if unsafe { *s.add(i) } != b[i] {
2876 return false;
2877 }
2878 i += 1;
2879 }
2880 unsafe { *s.add(i) == 0 }
2881}
2882
2883#[derive(Clone, Copy)]
2886struct DumpState {
2887 format: c_int,
2889 saved: c_int,
2892 unformatted: *mut _xmlNode,
2895 indent: *const xmlChar,
2898 indent_len: c_int,
2900 no_decl: c_int,
2902}
2903
2904impl DumpState {
2905 const fn new(format: c_int) -> Self {
2906 let f = if format != 0 { 1 } else { 0 };
2907 DumpState {
2908 format: f,
2909 saved: f,
2910 unformatted: ptr::null_mut(),
2911 indent: INDENT.as_ptr(),
2912 indent_len: INDENT.len() as c_int,
2913 no_decl: 0,
2914 }
2915 }
2916
2917 const unsafe fn with_indent(format: c_int, indent: *const xmlChar, no_decl: c_int) -> Self {
2925 let f = if format != 0 { 1 } else { 0 };
2926 let (ptr, len) = if indent.is_null() {
2927 (INDENT.as_ptr(), INDENT.len() as c_int)
2928 } else {
2929 let mut n = 0i32;
2930 while unsafe { *indent.add(n as usize) } != 0 {
2931 n += 1;
2932 }
2933 (indent, n)
2934 };
2935 DumpState {
2936 format: f,
2937 saved: f,
2938 unformatted: ptr::null_mut(),
2939 indent: ptr,
2940 indent_len: len,
2941 no_decl,
2942 }
2943 }
2944}
2945
2946unsafe fn write_qname(buf: *mut _xmlBuffer, node: *mut _xmlNode) {
2952 let n = unsafe { &*node };
2953 if !n.ns.is_null() {
2954 let ns = unsafe { &*n.ns };
2955 if !ns.prefix.is_null() {
2956 io::buf_cat(buf, ns.prefix);
2957 io::buf_ccat(buf, b':');
2958 }
2959 }
2960 if !n.name.is_null() {
2961 io::buf_cat(buf, n.name);
2962 }
2963}
2964
2965unsafe fn ns_dump_output(buf: *mut _xmlBuffer, cur: *mut _xmlNs) {
2971 if cur.is_null() || buf.is_null() {
2972 return;
2973 }
2974 let ns = unsafe { &*cur };
2975 if ns.type_ == XML_LOCAL_NAMESPACE as c_int && !ns.href.is_null() {
2976 if !ns.prefix.is_null() && c_str_eq_bytes(ns.prefix, b"xml") {
2978 return;
2979 }
2980 io::buf_ccat(buf, b' ');
2981 if !ns.prefix.is_null() {
2982 io::buf_add(buf, b"xmlns:" as *const u8, 6);
2983 io::buf_cat(buf, ns.prefix);
2984 } else {
2985 io::buf_add(buf, b"xmlns" as *const u8, 5);
2986 }
2987 io::buf_add(buf, b"=\"" as *const u8, 2);
2988 serialize_attr_value(buf, ns.href);
2989 io::buf_ccat(buf, b'"');
2990 }
2991}
2992
2993unsafe fn attr_dump_output(buf: *mut _xmlBuffer, cur: *mut _xmlAttr) {
2999 if cur.is_null() || buf.is_null() {
3000 return;
3001 }
3002 io::buf_ccat(buf, b' ');
3003 let a = unsafe { &*cur };
3004 if !a.ns.is_null() {
3005 let ans = unsafe { &*a.ns };
3006 if !ans.prefix.is_null() {
3007 io::buf_cat(buf, ans.prefix);
3008 io::buf_ccat(buf, b':');
3009 }
3010 }
3011 if !a.name.is_null() {
3012 io::buf_cat(buf, a.name);
3013 }
3014 io::buf_add(buf, b"=\"" as *const u8, 2);
3015 let mut child = a.children;
3018 while !child.is_null() {
3019 let ct = unsafe { (*child).type_ };
3020 if ct == XML_TEXT_NODE as c_int && !unsafe { (*child).content }.is_null() {
3021 serialize_attr_value(buf, unsafe { (*child).content });
3022 } else if ct == XML_ENTITY_REF_NODE as c_int && !unsafe { (*child).name }.is_null() {
3023 io::buf_ccat(buf, b'&');
3024 io::buf_cat(buf, unsafe { (*child).name });
3025 io::buf_ccat(buf, b';');
3026 }
3027 child = unsafe { (*child).next };
3028 }
3029 io::buf_ccat(buf, b'"');
3030}
3031
3032unsafe fn dump_notation_decl(buf: *mut _xmlBuffer, nota: *mut _xmlNotation) {
3038 let n = unsafe { &*nota };
3039 io::buf_add(buf, b"<!NOTATION " as *const u8, 11);
3040 if !n.name.is_null() {
3041 io::buf_cat(buf, n.name);
3042 }
3043 if !n.PublicID.is_null() {
3044 io::buf_add(buf, b" PUBLIC " as *const u8, 8);
3045 write_quoted_string(buf, n.PublicID);
3046 if !n.SystemID.is_null() {
3047 io::buf_ccat(buf, b' ');
3048 write_quoted_string(buf, n.SystemID);
3049 }
3050 } else {
3051 io::buf_add(buf, b" SYSTEM " as *const u8, 8);
3052 write_quoted_string(buf, n.SystemID);
3053 }
3054 io::buf_add(buf, b" >\n" as *const u8, 4);
3055}
3056
3057unsafe fn dump_element_occur(buf: *mut _xmlBuffer, ocur: c_int) {
3059 use crate::abi::types::xmlElementContentOccur::*;
3060 if ocur == XML_ELEMENT_CONTENT_OPT as c_int {
3061 io::buf_ccat(buf, b'?');
3062 } else if ocur == XML_ELEMENT_CONTENT_MULT as c_int {
3063 io::buf_ccat(buf, b'*');
3064 } else if ocur == XML_ELEMENT_CONTENT_PLUS as c_int {
3065 io::buf_ccat(buf, b'+');
3066 }
3067}
3068
3069unsafe fn dump_element_content(buf: *mut _xmlBuffer, content: *mut _xmlElementContent) {
3075 use crate::abi::types::xmlElementContentOccur::*;
3076 use crate::abi::types::xmlElementContentType::*;
3077 if content.is_null() {
3078 return;
3079 }
3080 io::buf_ccat(buf, b'(');
3081 let mut cur = content;
3082 loop {
3083 if cur.is_null() {
3084 return;
3085 }
3086 let c = unsafe { &*cur };
3087 match c.type_ {
3088 t if t == XML_ELEMENT_CONTENT_PCDATA as c_int => {
3089 io::buf_add(buf, b"#PCDATA" as *const u8, 7);
3090 }
3091 t if t == XML_ELEMENT_CONTENT_ELEMENT as c_int => {
3092 if !c.prefix.is_null() {
3093 io::buf_cat(buf, c.prefix);
3094 io::buf_ccat(buf, b':');
3095 }
3096 if !c.name.is_null() {
3097 io::buf_cat(buf, c.name);
3098 }
3099 }
3100 t if t == XML_ELEMENT_CONTENT_SEQ as c_int || t == XML_ELEMENT_CONTENT_OR as c_int => {
3101 if cur != content
3102 && !c.parent.is_null()
3103 && (c.type_ != unsafe { (*c.parent).type_ }
3104 || c.ocur != XML_ELEMENT_CONTENT_ONCE as c_int)
3105 {
3106 io::buf_ccat(buf, b'(');
3107 }
3108 cur = c.c1;
3109 continue;
3110 }
3111 _ => {}
3112 }
3113
3114 while cur != content {
3116 let ccur = unsafe { &*cur };
3117 let parent = ccur.parent;
3118 if parent.is_null() {
3119 return;
3120 }
3121 let p = unsafe { &*parent };
3122 if (ccur.type_ == XML_ELEMENT_CONTENT_OR as c_int
3123 || ccur.type_ == XML_ELEMENT_CONTENT_SEQ as c_int)
3124 && (ccur.type_ != p.type_ || ccur.ocur != XML_ELEMENT_CONTENT_ONCE as c_int)
3125 {
3126 io::buf_ccat(buf, b')');
3127 }
3128 dump_element_occur(buf, ccur.ocur);
3129
3130 if ccur.type_ == XML_ELEMENT_CONTENT_SEQ as c_int {
3131 io::buf_add(buf, b" , " as *const u8, 3);
3132 } else if ccur.type_ == XML_ELEMENT_CONTENT_OR as c_int {
3133 io::buf_add(buf, b" | " as *const u8, 3);
3134 }
3135
3136 if cur == p.c1 {
3137 cur = p.c2;
3138 break;
3139 }
3140 cur = parent;
3141 }
3142 if cur == content {
3143 break;
3144 }
3145 }
3146 io::buf_ccat(buf, b')');
3147 let cc = unsafe { &*content };
3148 dump_element_occur(buf, cc.ocur);
3149}
3150
3151unsafe fn dump_element_decl(buf: *mut _xmlBuffer, elem: *mut _xmlElement) {
3157 use crate::abi::types::xmlElementTypeVal::*;
3158 let e = unsafe { &*elem };
3159 io::buf_add(buf, b"<!ELEMENT " as *const u8, 10);
3160 if !e.prefix.is_null() {
3161 io::buf_cat(buf, e.prefix);
3162 io::buf_ccat(buf, b':');
3163 }
3164 if !e.name.is_null() {
3165 io::buf_cat(buf, e.name);
3166 }
3167 io::buf_ccat(buf, b' ');
3168 match e.etype {
3169 t if t == XML_ELEMENT_TYPE_EMPTY as c_int => {
3170 io::buf_add(buf, b"EMPTY" as *const u8, 5);
3171 }
3172 t if t == XML_ELEMENT_TYPE_ANY as c_int => {
3173 io::buf_add(buf, b"ANY" as *const u8, 3);
3174 }
3175 t if t == XML_ELEMENT_TYPE_MIXED as c_int || t == XML_ELEMENT_TYPE_ELEMENT as c_int => {
3176 dump_element_content(buf, e.content);
3177 }
3178 _ => {}
3179 }
3180 io::buf_add(buf, b">\n" as *const u8, 2);
3181}
3182
3183unsafe fn dump_enumeration(buf: *mut _xmlBuffer, cur: *mut _xmlEnumeration) {
3189 let mut e = cur;
3190 while !e.is_null() {
3191 let en = unsafe { &*e };
3192 if !en.name.is_null() {
3193 io::buf_cat(buf, en.name);
3194 }
3195 if !en.next.is_null() {
3196 io::buf_add(buf, b" | " as *const u8, 3);
3197 }
3198 e = en.next;
3199 }
3200 io::buf_ccat(buf, b')');
3201}
3202
3203unsafe fn dump_attribute_decl(buf: *mut _xmlBuffer, attr: *mut _xmlAttribute) {
3209 use crate::abi::types::xmlAttributeDefault::*;
3210 use crate::abi::types::xmlAttributeType::*;
3211 let a = unsafe { &*attr };
3212 io::buf_add(buf, b"<!ATTLIST " as *const u8, 10);
3213 if !a.elem.is_null() {
3214 io::buf_cat(buf, a.elem);
3215 }
3216 io::buf_ccat(buf, b' ');
3217 if !a.prefix.is_null() {
3218 io::buf_cat(buf, a.prefix);
3219 io::buf_ccat(buf, b':');
3220 }
3221 if !a.name.is_null() {
3222 io::buf_cat(buf, a.name);
3223 }
3224 match a.atype {
3225 t if t == XML_ATTRIBUTE_CDATA as c_int => {
3226 io::buf_add(buf, b" CDATA" as *const u8, 6);
3227 }
3228 t if t == XML_ATTRIBUTE_ID as c_int => {
3229 io::buf_add(buf, b" ID" as *const u8, 3);
3230 }
3231 t if t == XML_ATTRIBUTE_IDREF as c_int => {
3232 io::buf_add(buf, b" IDREF" as *const u8, 6);
3233 }
3234 t if t == XML_ATTRIBUTE_IDREFS as c_int => {
3235 io::buf_add(buf, b" IDREFS" as *const u8, 7);
3236 }
3237 t if t == XML_ATTRIBUTE_ENTITY as c_int => {
3238 io::buf_add(buf, b" ENTITY" as *const u8, 7);
3239 }
3240 t if t == XML_ATTRIBUTE_ENTITIES as c_int => {
3241 io::buf_add(buf, b" ENTITIES" as *const u8, 9);
3242 }
3243 t if t == XML_ATTRIBUTE_NMTOKEN as c_int => {
3244 io::buf_add(buf, b" NMTOKEN" as *const u8, 8);
3245 }
3246 t if t == XML_ATTRIBUTE_NMTOKENS as c_int => {
3247 io::buf_add(buf, b" NMTOKENS" as *const u8, 9);
3248 }
3249 t if t == XML_ATTRIBUTE_ENUMERATION as c_int => {
3250 io::buf_add(buf, b" (" as *const u8, 2);
3251 dump_enumeration(buf, a.tree);
3252 }
3253 t if t == XML_ATTRIBUTE_NOTATION as c_int => {
3254 io::buf_add(buf, b" NOTATION (" as *const u8, 11);
3255 dump_enumeration(buf, a.tree);
3256 }
3257 _ => {}
3258 }
3259 match a.def {
3260 t if t == XML_ATTRIBUTE_REQUIRED as c_int => {
3261 io::buf_add(buf, b" #REQUIRED" as *const u8, 10);
3262 }
3263 t if t == XML_ATTRIBUTE_IMPLIED as c_int => {
3264 io::buf_add(buf, b" #IMPLIED" as *const u8, 9);
3265 }
3266 t if t == XML_ATTRIBUTE_FIXED as c_int => {
3267 io::buf_add(buf, b" #FIXED" as *const u8, 7);
3268 }
3269 _ => {}
3270 }
3271 if !a.defaultValue.is_null() {
3272 io::buf_add(buf, b" \"" as *const u8, 2);
3273 serialize_attr_value(buf, a.defaultValue);
3274 io::buf_ccat(buf, b'"');
3275 }
3276 io::buf_add(buf, b">\n" as *const u8, 2);
3277}
3278
3279unsafe fn write_quoted_string(buf: *mut _xmlBuffer, str: *const xmlChar) {
3285 if buf.is_null() {
3286 return;
3287 }
3288 io::buf_ccat(buf, b'"');
3289 if !str.is_null() {
3290 let mut i = 0usize;
3291 while unsafe { *str.add(i) != 0 } {
3292 let ch = unsafe { *str.add(i) };
3293 if ch == b'"' {
3294 io::buf_add(buf, b""" as *const u8, 6);
3295 } else {
3296 io::buf_add(buf, &ch as *const u8, 1);
3297 }
3298 i += 1;
3299 }
3300 }
3301 io::buf_ccat(buf, b'"');
3302}
3303
3304unsafe fn dump_entity_decl(buf: *mut _xmlBuffer, ent: *mut _xmlEntity) {
3310 use crate::abi::types::xmlEntityType::*;
3311 let e = unsafe { &*ent };
3312 if e.etype == XML_INTERNAL_PARAMETER_ENTITY as c_int
3313 || e.etype == XML_EXTERNAL_PARAMETER_ENTITY as c_int
3314 {
3315 io::buf_add(buf, b"<!ENTITY % " as *const u8, 11);
3316 } else {
3317 io::buf_add(buf, b"<!ENTITY " as *const u8, 9);
3318 }
3319 if !e.name.is_null() {
3320 io::buf_cat(buf, e.name);
3321 }
3322 io::buf_ccat(buf, b' ');
3323
3324 if e.etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY as c_int
3325 || e.etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int
3326 || e.etype == XML_EXTERNAL_PARAMETER_ENTITY as c_int
3327 {
3328 if !e.ExternalID.is_null() {
3329 io::buf_add(buf, b"PUBLIC " as *const u8, 7);
3330 write_quoted_string(buf, e.ExternalID);
3331 io::buf_ccat(buf, b' ');
3332 } else {
3333 io::buf_add(buf, b"SYSTEM " as *const u8, 7);
3334 }
3335 write_quoted_string(buf, e.SystemID);
3336 }
3337
3338 if e.etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int && !e.content.is_null() {
3339 io::buf_add(buf, b" NDATA " as *const u8, 7);
3340 if !e.orig.is_null() {
3341 io::buf_cat(buf, e.orig);
3342 } else if !e.content.is_null() {
3343 io::buf_cat(buf, e.content);
3344 }
3345 }
3346
3347 if e.etype == XML_INTERNAL_GENERAL_ENTITY as c_int
3348 || e.etype == XML_INTERNAL_PARAMETER_ENTITY as c_int
3349 {
3350 if !e.orig.is_null() {
3351 write_quoted_string(buf, e.orig);
3352 } else {
3353 io::buf_ccat(buf, b'"');
3355 if !e.content.is_null() {
3356 let mut i = 0usize;
3357 while unsafe { *e.content.add(i) != 0 } {
3358 let ch = unsafe { *e.content.add(i) };
3359 match ch {
3360 b'"' => io::buf_add(buf, b""" as *const u8, 6),
3361 b'%' => io::buf_add(buf, b"%" as *const u8, 6),
3362 _ => io::buf_add(buf, &ch as *const u8, 1),
3363 };
3364 i += 1;
3365 }
3366 }
3367 io::buf_ccat(buf, b'"');
3368 }
3369 }
3370 io::buf_add(buf, b">\n" as *const u8, 2);
3371}
3372
3373unsafe fn dtd_dump_output(
3379 buf: *mut _xmlBuffer,
3380 cur: *mut _xmlNode,
3381 state: &mut DumpState,
3382 level: &mut c_int,
3383) {
3384 let dtd = cur as *mut _xmlDtd;
3385 let d = unsafe { &*dtd };
3386 io::buf_add(buf, b"<!DOCTYPE " as *const u8, 10);
3387 if !d.name.is_null() {
3388 io::buf_cat(buf, d.name);
3389 }
3390 if !d.ExternalID.is_null() {
3391 io::buf_add(buf, b" PUBLIC " as *const u8, 8);
3392 write_quoted_string(buf, d.ExternalID);
3393 io::buf_ccat(buf, b' ');
3394 write_quoted_string(buf, d.SystemID);
3395 } else if !d.SystemID.is_null() {
3396 io::buf_add(buf, b" SYSTEM " as *const u8, 8);
3397 write_quoted_string(buf, d.SystemID);
3398 }
3399 if d.entities.is_null()
3404 && d.elements.is_null()
3405 && d.attributes.is_null()
3406 && d.notations.is_null()
3407 && d.pentities.is_null()
3408 {
3409 io::buf_ccat(buf, b'>');
3410 return;
3411 }
3412 io::buf_add(buf, b" [\n" as *const u8, 3);
3413 let format = state.format;
3419 let lvl = *level;
3420 state.format = 0;
3421 *level = -1;
3422 if !d.notations.is_null() {
3423 crate::xml::hash::hash_scan(
3424 d.notations as *mut crate::xml::hash::HashTable,
3425 Some(dump_notation_decl_cb),
3426 buf as *mut c_void,
3427 );
3428 }
3429 if !d.elements.is_null() {
3430 crate::xml::hash::hash_scan(
3431 d.elements as *mut crate::xml::hash::HashTable,
3432 Some(dump_element_decl_cb),
3433 buf as *mut c_void,
3434 );
3435 }
3436 if !d.attributes.is_null() {
3437 crate::xml::hash::hash_scan(
3438 d.attributes as *mut crate::xml::hash::HashTable,
3439 Some(dump_attribute_decl_cb),
3440 buf as *mut c_void,
3441 );
3442 }
3443 if !d.entities.is_null() {
3444 crate::xml::hash::hash_scan(
3445 d.entities as *mut crate::xml::hash::HashTable,
3446 Some(dump_entity_decl_cb),
3447 buf as *mut c_void,
3448 );
3449 }
3450 if !d.pentities.is_null() {
3451 crate::xml::hash::hash_scan(
3452 d.pentities as *mut crate::xml::hash::HashTable,
3453 Some(dump_entity_decl_cb),
3454 buf as *mut c_void,
3455 );
3456 }
3457 state.format = format;
3458 *level = lvl;
3459 io::buf_add(buf, b"]>" as *const u8, 2);
3460}
3461
3462unsafe extern "C" fn dump_notation_decl_cb(
3464 payload: *mut c_void,
3465 data: *mut c_void,
3466 _name: *const crate::abi::types::xmlChar,
3467) {
3468 if !payload.is_null() && !data.is_null() {
3469 dump_notation_decl(data as *mut _xmlBuffer, payload as *mut _xmlNotation);
3470 }
3471}
3472
3473unsafe extern "C" fn dump_element_decl_cb(
3475 payload: *mut c_void,
3476 data: *mut c_void,
3477 _name: *const crate::abi::types::xmlChar,
3478) {
3479 if !payload.is_null() && !data.is_null() {
3480 dump_element_decl(data as *mut _xmlBuffer, payload as *mut _xmlElement);
3481 }
3482}
3483
3484unsafe extern "C" fn dump_attribute_decl_cb(
3486 payload: *mut c_void,
3487 data: *mut c_void,
3488 _name: *const crate::abi::types::xmlChar,
3489) {
3490 if !payload.is_null() && !data.is_null() {
3491 dump_attribute_decl(data as *mut _xmlBuffer, payload as *mut _xmlAttribute);
3492 }
3493}
3494
3495unsafe extern "C" fn dump_entity_decl_cb(
3497 payload: *mut c_void,
3498 data: *mut c_void,
3499 _name: *const crate::abi::types::xmlChar,
3500) {
3501 if !payload.is_null() && !data.is_null() {
3502 dump_entity_decl(data as *mut _xmlBuffer, payload as *mut _xmlEntity);
3503 }
3504}
3505
3506unsafe fn doc_content_dump_output(
3515 buf: *mut _xmlBuffer,
3516 cur: *mut _xmlNode,
3517 state: &mut DumpState,
3518 level: &mut c_int,
3519) {
3520 let doc = cur as *mut _xmlDoc;
3521 let d = unsafe { &*doc };
3522
3523 if state.no_decl == 0 {
3527 io::buf_add(buf, b"<?xml version=\"" as *const u8, 15);
3528 if !d.version.is_null() {
3529 io::buf_cat(buf, d.version);
3530 } else {
3531 io::buf_add(buf, b"1.0" as *const u8, 3);
3532 }
3533 io::buf_ccat(buf, b'"');
3534 if !d.encoding.is_null() {
3535 io::buf_add(buf, b" encoding=\"" as *const u8, 11);
3536 io::buf_cat(buf, d.encoding);
3537 io::buf_ccat(buf, b'"');
3538 }
3539 match d.standalone {
3540 0 => {
3541 io::buf_add(buf, b" standalone=\"no\"" as *const u8, 16);
3542 }
3543 1 => {
3544 io::buf_add(buf, b" standalone=\"yes\"" as *const u8, 17);
3545 }
3546 _ => {}
3547 }
3548 io::buf_add(buf, b"?>\n" as *const u8, 3);
3549 }
3550
3551 if !d.intSubset.is_null() {
3558 let mut in_chain = false;
3559 let mut c = d.children;
3560 while !c.is_null() {
3561 if c as *mut c_void == d.intSubset as *mut c_void {
3562 in_chain = true;
3563 break;
3564 }
3565 c = unsafe { (*c).next };
3566 }
3567 if !in_chain {
3568 let mut lvl = 0;
3569 dtd_dump_output(buf, d.intSubset as *mut _xmlNode, state, &mut lvl);
3570 io::buf_ccat(buf, b'\n');
3571 }
3572 }
3573
3574 if !d.children.is_null() {
3575 let mut child = d.children;
3576 while !child.is_null() {
3577 *level = 0;
3578 node_dump_internal(buf, child, child, cur, state, level);
3579 let ct = unsafe { (*child).type_ };
3580 if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
3581 io::buf_ccat(buf, b'\n');
3582 }
3583 child = unsafe { (*child).next };
3584 }
3585 }
3586}
3587
3588unsafe fn node_dump_internal(
3612 buf: *mut _xmlBuffer,
3613 cur: *mut _xmlNode,
3614 root: *mut _xmlNode,
3615 parent: *mut _xmlNode,
3616 state: &mut DumpState,
3617 level: &mut c_int,
3618) {
3619 if cur.is_null() || buf.is_null() {
3620 return;
3621 }
3622 let n = unsafe { &*cur };
3623 match n.type_ {
3624 t if t == XML_ELEMENT_NODE as c_int => {
3625 if cur != root && state.format == 1 {
3626 write_indent(buf, *level, state.indent, state.indent_len);
3627 }
3628 if !n.parent.is_null() && n.parent != parent && !n.children.is_null() {
3631 let mut sub = DumpState::new(state.format);
3632 let mut sub_level = *level;
3633 node_dump_internal(buf, cur, cur, n.parent, &mut sub, &mut sub_level);
3634 return;
3635 }
3636 io::buf_ccat(buf, b'<');
3638 write_qname(buf, cur);
3639 let mut nsdef = n.nsDef;
3640 while !nsdef.is_null() {
3641 ns_dump_output(buf, nsdef);
3642 nsdef = unsafe { (*nsdef).next };
3643 }
3644 let mut attr = n.properties;
3645 while !attr.is_null() {
3646 attr_dump_output(buf, attr);
3647 attr = unsafe { (*attr).next };
3648 }
3649 if n.children.is_null() {
3650 io::buf_add(buf, b"/>" as *const u8, 2);
3651 } else {
3652 if state.format == 1 {
3653 let mut tmp = n.children;
3656 while !tmp.is_null() {
3657 let tt = unsafe { (*tmp).type_ };
3658 if tt == XML_TEXT_NODE as c_int
3659 || tt == XML_CDATA_SECTION_NODE as c_int
3660 || tt == XML_ENTITY_REF_NODE as c_int
3661 {
3662 state.format = 0;
3663 state.unformatted = cur;
3664 break;
3665 }
3666 tmp = unsafe { (*tmp).next };
3667 }
3668 }
3669 io::buf_ccat(buf, b'>');
3670 if state.format == 1 {
3671 io::buf_ccat(buf, b'\n');
3672 }
3673 if *level >= 0 {
3674 *level += 1;
3675 }
3676 let mut child = n.children;
3677 while !child.is_null() {
3678 node_dump_internal(buf, child, root, cur, state, level);
3679 if state.format == 1 {
3680 let ct = unsafe { (*child).type_ };
3681 if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
3682 io::buf_ccat(buf, b'\n');
3683 }
3684 }
3685 child = unsafe { (*child).next };
3686 }
3687 if *level > 0 {
3689 *level -= 1;
3690 }
3691 if state.format == 1 {
3692 write_indent(buf, *level, state.indent, state.indent_len);
3693 }
3694 io::buf_add(buf, b"</" as *const u8, 2);
3695 write_qname(buf, cur);
3696 io::buf_ccat(buf, b'>');
3697 if cur == state.unformatted {
3698 state.format = state.saved;
3699 state.unformatted = ptr::null_mut();
3700 }
3701 }
3702 }
3703 t if t == XML_TEXT_NODE as c_int => {
3704 if !n.content.is_null() {
3705 if is_noenc_text(cur) {
3706 io::buf_cat(buf, n.content);
3707 } else {
3708 serialize_text(buf, n.content, xml_strlen(n.content));
3709 }
3710 } else if !n.children.is_null() {
3711 let c = node_get_content(cur);
3714 if !c.is_null() {
3715 if is_noenc_text(cur) {
3716 io::buf_cat(buf, c);
3717 } else {
3718 serialize_text(buf, c, xml_strlen(c));
3719 }
3720 allocator::xmlFreeImpl(c as *mut c_void);
3721 }
3722 }
3723 }
3724 t if t == XML_CDATA_SECTION_NODE as c_int => {
3725 if n.content.is_null() || unsafe { *n.content == 0 } {
3726 io::buf_add(buf, b"<![CDATA[]]>" as *const u8, 12);
3727 } else {
3728 let len = xml_strlen(n.content) as usize;
3729 let bytes = core::slice::from_raw_parts(n.content, len);
3730 let mut i = 0usize;
3731 let mut seg_start = 0usize;
3732 while i < len {
3733 if bytes[i] == b']'
3734 && i + 2 < len
3735 && bytes[i + 1] == b']'
3736 && bytes[i + 2] == b'>'
3737 {
3738 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
3739 io::buf_add(buf, n.content.add(seg_start), (i + 2 - seg_start) as c_int);
3740 io::buf_add(buf, b"]]>" as *const u8, 3);
3741 seg_start = i + 2;
3742 i += 3;
3743 continue;
3744 }
3745 i += 1;
3746 }
3747 if seg_start < len {
3748 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
3749 io::buf_add(buf, n.content.add(seg_start), (len - seg_start) as c_int);
3750 io::buf_add(buf, b"]]>" as *const u8, 3);
3751 }
3752 }
3753 }
3754 t if t == XML_COMMENT_NODE as c_int => {
3755 if cur != root && state.format == 1 {
3756 write_indent(buf, *level, state.indent, state.indent_len);
3757 }
3758 if !n.content.is_null() {
3759 io::buf_add(buf, b"<!--" as *const u8, 4);
3760 io::buf_cat(buf, n.content);
3761 io::buf_add(buf, b"-->" as *const u8, 3);
3762 }
3763 }
3764 t if t == XML_PI_NODE as c_int => {
3765 if cur != root && state.format == 1 {
3766 write_indent(buf, *level, state.indent, state.indent_len);
3767 }
3768 io::buf_add(buf, b"<?" as *const u8, 2);
3769 if !n.name.is_null() {
3770 io::buf_cat(buf, n.name);
3771 }
3772 if !n.content.is_null() && unsafe { *n.content != 0 } {
3773 io::buf_ccat(buf, b' ');
3774 io::buf_cat(buf, n.content);
3775 }
3776 io::buf_add(buf, b"?>" as *const u8, 2);
3777 }
3778 t if t == XML_ENTITY_REF_NODE as c_int => {
3779 io::buf_ccat(buf, b'&');
3780 if !n.name.is_null() {
3781 io::buf_cat(buf, n.name);
3782 }
3783 io::buf_ccat(buf, b';');
3784 }
3785 t if t == XML_DOCUMENT_NODE as c_int => {
3786 doc_content_dump_output(buf, cur, state, level);
3787 }
3788 t if t == XML_HTML_DOCUMENT_NODE as c_int => {
3789 crate::xml::html::serialize_node(cur, buf, state.format, *level);
3791 }
3792 t if t == XML_DTD_NODE as c_int => {
3793 dtd_dump_output(buf, cur, state, level);
3794 }
3795 t if t == XML_ATTRIBUTE_NODE as c_int => {
3796 attr_dump_output(buf, cur as *mut _xmlAttr);
3797 }
3798 t if t == XML_NAMESPACE_DECL as c_int => {
3799 ns_dump_output(buf, cur as *mut _xmlNs);
3800 }
3801 t if t == XML_ELEMENT_DECL as c_int => {
3802 dump_element_decl(buf, cur as *mut _xmlElement);
3803 }
3804 t if t == XML_ATTRIBUTE_DECL as c_int => {
3805 dump_attribute_decl(buf, cur as *mut _xmlAttribute);
3806 }
3807 t if t == XML_ENTITY_DECL as c_int => {
3808 dump_entity_decl(buf, cur as *mut _xmlEntity);
3809 }
3810 _ => {}
3811 }
3812}
3813
3814pub(crate) unsafe fn serialize_node(
3828 node: *mut _xmlNode,
3829 buf: *mut _xmlBuffer,
3830 format: c_int,
3831 level: c_int,
3832) {
3833 unsafe { serialize_node_opt(node, buf, format, level, ptr::null()) };
3834}
3835
3836pub(crate) unsafe fn serialize_node_opt(
3844 node: *mut _xmlNode,
3845 buf: *mut _xmlBuffer,
3846 format: c_int,
3847 level: c_int,
3848 indent: *const xmlChar,
3849) {
3850 unsafe { serialize_node_opts(node, buf, format, level, indent, 0) };
3851}
3852
3853pub(crate) unsafe fn serialize_node_opts(
3860 node: *mut _xmlNode,
3861 buf: *mut _xmlBuffer,
3862 format: c_int,
3863 level: c_int,
3864 indent: *const xmlChar,
3865 no_decl: c_int,
3866) {
3867 if node.is_null() || buf.is_null() {
3868 return;
3869 }
3870 let parent = unsafe { (*node).parent };
3871 let mut state = DumpState::with_indent(format, indent, no_decl);
3872 let mut lvl = level;
3873 node_dump_internal(buf, node, node, parent, &mut state, &mut lvl);
3874}
3875
3876pub(crate) unsafe fn doc_dump(buf: *mut _xmlBuffer, doc: *mut _xmlDoc) -> c_int {
3886 if buf.is_null() || doc.is_null() {
3887 return -1;
3888 }
3889
3890 let before = io::buf_length(buf);
3891 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
3892 let after = io::buf_length(buf);
3893
3894 if after < 0 || before < 0 {
3895 return -1;
3896 }
3897 after - before
3898}
3899
3900pub(crate) unsafe fn node_dump(
3912 buf: *mut _xmlBuffer,
3913 doc: *mut _xmlDoc,
3914 node: *mut _xmlNode,
3915 level: c_int,
3916 format: c_int,
3917) -> c_int {
3918 let _ = doc; if buf.is_null() || node.is_null() {
3920 return -1;
3921 }
3922
3923 let before = io::buf_length(buf);
3924 serialize_node(node, buf, format, level);
3925 let after = io::buf_length(buf);
3926
3927 if after < 0 || before < 0 {
3928 return -1;
3929 }
3930 after - before
3931}
3932
3933pub(crate) unsafe fn save_doc_to_filename(
3940 doc: *mut _xmlDoc,
3941 filename: *const c_char,
3942 compression: c_int,
3943) -> c_int {
3944 if doc.is_null() || filename.is_null() {
3945 return -1;
3946 }
3947
3948 let out = io::output_buffer_create_filename(filename, ptr::null_mut(), compression);
3949 if out.is_null() {
3950 return -1;
3951 }
3952
3953 let buf = io::buf_create(-1);
3954 if buf.is_null() {
3955 io::output_buffer_close(out);
3956 return -1;
3957 }
3958
3959 let ret = doc_dump(buf, doc);
3960 if ret >= 0 {
3961 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
3963 io::output_buffer_flush(out);
3964 }
3965
3966 io::buf_free(buf);
3967 io::output_buffer_close(out);
3968 ret
3969}
3970
3971#[allow(dead_code)]
3978pub(crate) unsafe fn save_doc_to_fd(doc: *mut _xmlDoc, fd: c_int, _compression: c_int) -> c_int {
3979 if doc.is_null() || fd < 0 {
3980 return -1;
3981 }
3982
3983 let out = io::output_buffer_create_fd(fd, ptr::null_mut());
3984 if out.is_null() {
3985 return -1;
3986 }
3987
3988 let buf = io::buf_create(-1);
3989 if buf.is_null() {
3990 io::output_buffer_close(out);
3991 return -1;
3992 }
3993
3994 let ret = doc_dump(buf, doc);
3995 if ret >= 0 {
3996 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
3997 io::output_buffer_flush(out);
3998 }
3999
4000 io::buf_free(buf);
4001 io::output_buffer_close(out);
4002 ret
4003}
4004
4005#[allow(dead_code)]
4012pub(crate) unsafe fn save_doc_to_buf(
4013 doc: *mut _xmlDoc,
4014 buf: *mut _xmlBuffer,
4015 compression: c_int,
4016) -> c_int {
4017 let _ = compression;
4018 if doc.is_null() || buf.is_null() {
4019 return -1;
4020 }
4021
4022 doc_dump(buf, doc)
4023}
4024
4025#[allow(dead_code)]
4032pub(crate) unsafe fn save_format_doc_to_buf(
4033 doc: *mut _xmlDoc,
4034 buf: *mut _xmlBuffer,
4035 compression: c_int,
4036) -> c_int {
4037 let _ = compression;
4038 if doc.is_null() || buf.is_null() {
4039 return -1;
4040 }
4041
4042 let before = io::buf_length(buf);
4043 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
4044 let after = io::buf_length(buf);
4045
4046 if after < 0 || before < 0 {
4047 return -1;
4048 }
4049 after - before
4050}
4051
4052#[allow(dead_code)]
4061pub(crate) unsafe fn dump_node(node: *mut _xmlNode) -> *mut xmlChar {
4062 if node.is_null() {
4063 return ptr::null_mut();
4064 }
4065
4066 let buf = io::buf_create(-1);
4067 if buf.is_null() {
4068 return ptr::null_mut();
4069 }
4070
4071 serialize_node(node, buf, 0, 0);
4072
4073 let content = io::buf_content(buf);
4074 if content.is_null() {
4075 io::buf_free(buf);
4076 return ptr::null_mut();
4077 }
4078
4079 let result = dup_xml_str(content);
4081 io::buf_free(buf);
4082 result
4083}
4084
4085pub unsafe fn dump_doc(doc: *mut _xmlDoc) -> *mut xmlChar {
4094 if doc.is_null() {
4095 return ptr::null_mut();
4096 }
4097
4098 let buf = io::buf_create(-1);
4099 if buf.is_null() {
4100 return ptr::null_mut();
4101 }
4102
4103 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
4104
4105 let content = io::buf_content(buf);
4106 if content.is_null() {
4107 io::buf_free(buf);
4108 return ptr::null_mut();
4109 }
4110
4111 let result = dup_xml_str(content);
4112 io::buf_free(buf);
4113 result
4114}
4115
4116pub(crate) unsafe fn xmlNodeDump(
4132 buf: *mut _xmlBuffer,
4133 doc: *mut _xmlDoc,
4134 node: *mut _xmlNode,
4135 level: c_int,
4136 format: c_int,
4137) -> c_int {
4138 node_dump(buf, doc, node, level, format)
4139}
4140
4141pub(crate) unsafe fn xmlDocDump(fp: *mut c_void, doc: *mut _xmlDoc) -> c_int {
4154 if fp.is_null() || doc.is_null() {
4155 return -1;
4156 }
4157
4158 let buf = io::buf_create(-1);
4159 if buf.is_null() {
4160 return -1;
4161 }
4162
4163 let ret = doc_dump(buf, doc);
4164 if ret < 0 {
4165 io::buf_free(buf);
4166 return -1;
4167 }
4168
4169 let content = io::buf_content(buf);
4170 let len = io::buf_length(buf);
4171 if !content.is_null() && len > 0 {
4172 let written = libc::fwrite(
4173 content as *const c_void,
4174 1,
4175 len as usize,
4176 fp as *mut libc::FILE,
4177 );
4178 io::buf_free(buf);
4179 written as c_int
4180 } else {
4181 io::buf_free(buf);
4182 0
4183 }
4184}
4185
4186pub(crate) unsafe fn xmlDocDumpFormatMemory(
4200 doc: *mut _xmlDoc,
4201 mem: *mut *mut xmlChar,
4202 size: *mut c_int,
4203 format: c_int,
4204) {
4205 if doc.is_null() || mem.is_null() || size.is_null() {
4206 return;
4207 }
4208
4209 let buf = io::buf_create(-1);
4210 if buf.is_null() {
4211 unsafe {
4212 *mem = ptr::null_mut();
4213 *size = 0;
4214 }
4215 return;
4216 }
4217
4218 serialize_node(doc as *mut _xmlNode, buf, format, 0);
4219
4220 let content = io::buf_content(buf);
4221 let len = io::buf_length(buf);
4222
4223 if !content.is_null() && len > 0 {
4224 let result = allocator::xmlMallocImpl((len + 1) as usize) as *mut xmlChar;
4226 if !result.is_null() {
4227 ptr::copy_nonoverlapping(content, result, len as usize);
4228 *result.add(len as usize) = 0;
4229 unsafe {
4230 *mem = result;
4231 *size = len;
4232 }
4233 } else {
4234 unsafe {
4235 *mem = ptr::null_mut();
4236 *size = 0;
4237 }
4238 }
4239 } else {
4240 unsafe {
4241 *mem = ptr::null_mut();
4242 *size = 0;
4243 }
4244 }
4245
4246 io::buf_free(buf);
4247}
4248
4249pub(crate) unsafe fn xmlDocDumpMemory(doc: *mut _xmlDoc, mem: *mut *mut xmlChar, size: *mut c_int) {
4263 xmlDocDumpFormatMemory(doc, mem, size, 0)
4264}
4265
4266pub(crate) unsafe fn xmlSaveFile(filename: *const c_char, cur: *mut _xmlDoc) -> c_int {
4279 save_doc_to_filename(cur, filename, 0)
4280}
4281
4282pub(crate) unsafe fn xmlSaveFileEnc(
4296 filename: *const c_char,
4297 cur: *mut _xmlDoc,
4298 encoding: *const c_char,
4299) -> c_int {
4300 let _ = encoding; save_doc_to_filename(cur, filename, 0)
4302}
4303
4304pub(crate) unsafe fn xmlSaveFormatFile(
4317 filename: *const c_char,
4318 cur: *mut _xmlDoc,
4319 format: c_int,
4320) -> c_int {
4321 let _ = format;
4322 save_doc_to_filename(cur, filename, 0)
4323}
4324
4325pub(crate) unsafe fn xmlSaveFormatFileEnc(
4339 filename: *const c_char,
4340 cur: *mut _xmlDoc,
4341 encoding: *const c_char,
4342 format: c_int,
4343) -> c_int {
4344 let _ = encoding;
4345 let _ = format;
4346 save_doc_to_filename(cur, filename, 0)
4347}
4348
4349pub(crate) unsafe fn xmlGetDocCompressMode(doc: *mut _xmlDoc) -> c_int {
4361 if doc.is_null() {
4362 return -1;
4363 }
4364 unsafe { (*doc).compression }
4365}
4366
4367pub(crate) unsafe fn xmlSetDocCompressMode(doc: *mut _xmlDoc, mode: c_int) {
4379 if doc.is_null() {
4380 return;
4381 }
4382 unsafe {
4383 (*doc).compression = mode;
4384 }
4385}
4386
4387#[cfg(test)]
4388mod tests {
4389 use super::*;
4390 use core::ffi::c_void;
4391
4392 fn c_str(s: &str) -> *const xmlChar {
4393 let bytes = s.as_bytes();
4394 let buf = unsafe { allocator::xmlMallocImpl(bytes.len() + 1) as *mut u8 };
4395 if !buf.is_null() {
4396 unsafe {
4397 ptr::copy_nonoverlapping(bytes.as_ptr(), buf, bytes.len());
4398 *buf.add(bytes.len()) = 0;
4399 }
4400 }
4401 buf as *const xmlChar
4402 }
4403
4404 #[test]
4405 fn test_new_free_doc() {
4406 unsafe {
4407 let doc = new_doc(ptr::null());
4408 assert!(!doc.is_null());
4409 assert_eq!((*doc).type_, XML_DOCUMENT_NODE as c_int);
4410 assert_eq!((*doc).standalone, -1);
4411 assert_eq!((*doc).doc, doc);
4412 assert!(!(*doc).version.is_null());
4413 free_doc(doc);
4414 }
4415 }
4416
4417 #[test]
4418 fn test_new_doc_with_version() {
4419 unsafe {
4420 let ver = c_str("2.0");
4421 let doc = new_doc(ver);
4422 assert!(!doc.is_null());
4423 let doc_ver = (*doc).version;
4424 assert!(!doc_ver.is_null());
4425 assert!(crate::abi::exports_xml2::xmlStrEqual(doc_ver, ver,) != 0);
4426 allocator::xmlFreeImpl(ver as *mut c_void);
4427 free_doc(doc);
4428 }
4429 }
4430
4431 #[test]
4432 fn test_new_node() {
4433 unsafe {
4434 let doc = new_doc(ptr::null());
4435 let node = new_node(ptr::null_mut(), c_str("root"));
4436 assert!(!node.is_null());
4437 assert_eq!((*node).type_, XML_ELEMENT_NODE as c_int);
4438 assert!(!(*node).name.is_null());
4439 free_node(node);
4440 free_doc(doc);
4441 }
4442 }
4443
4444 #[test]
4445 fn test_node_get_content_recurses_descendants() {
4446 unsafe {
4451 let doc = new_doc(ptr::null());
4452 let root = new_node(ptr::null_mut(), c_str("library"));
4453 doc_set_root_element(doc, root);
4454 let book = new_child(root, ptr::null_mut(), c_str("book"));
4455 let title = new_child(book, ptr::null_mut(), c_str("title"));
4456 let text = new_text(c_str("Rust"));
4457 add_child(title, text);
4458
4459 let content = node_get_content(book);
4460 assert!(!content.is_null());
4461 let s = core::slice::from_raw_parts(
4462 content,
4463 libc::strlen(content as *const libc::c_char) as usize,
4464 );
4465 assert_eq!(s, b"Rust", "descendant text not concatenated");
4466 allocator::xmlFreeImpl(content as *mut c_void);
4467
4468 free_doc(doc);
4469 }
4470 }
4471
4472 #[test]
4473 fn test_doc_set_root_element() {
4474 unsafe {
4475 let doc = new_doc(ptr::null());
4476 let root = new_node(ptr::null_mut(), c_str("root"));
4477 let old = doc_set_root_element(doc, root);
4478 assert!(old.is_null());
4479 assert_eq!(doc_get_root_element(doc), root);
4480 assert_eq!((*doc).children, root);
4481 free_doc(doc);
4482 }
4483 }
4484
4485 #[test]
4486 fn test_add_child_and_sibling() {
4487 unsafe {
4488 let doc = new_doc(ptr::null());
4489 let root = new_node(ptr::null_mut(), c_str("root"));
4490 doc_set_root_element(doc, root);
4491
4492 let child1 = new_child(root, ptr::null_mut(), c_str("child1"));
4493 assert!(!child1.is_null());
4494 assert_eq!((*child1).parent, root);
4495 assert_eq!((*root).children, child1);
4496 assert_eq!((*root).last, child1);
4497
4498 let child2 = new_child(root, ptr::null_mut(), c_str("child2"));
4499 assert!(!child2.is_null());
4500 assert_eq!((*child2).parent, root);
4501 assert_eq!((*child1).next, child2);
4502 assert_eq!((*child2).prev, child1);
4503 assert_eq!((*root).last, child2);
4504
4505 let sibling = new_node(ptr::null_mut(), c_str("sibling"));
4507 add_sibling(child2, sibling);
4508 assert_eq!((*child2).next, sibling);
4509 assert_eq!((*sibling).prev, child2);
4510 assert_eq!((*root).last, sibling);
4511
4512 free_doc(doc);
4513 }
4514 }
4515
4516 #[test]
4517 fn test_unlink_node() {
4518 unsafe {
4519 let doc = new_doc(ptr::null());
4520 let root = new_node(ptr::null_mut(), c_str("root"));
4521 doc_set_root_element(doc, root);
4522
4523 let child1 = new_child(root, ptr::null_mut(), c_str("c1"));
4524 let child2 = new_child(root, ptr::null_mut(), c_str("c2"));
4525
4526 unlink_node(child1);
4527 assert!((*child1).parent.is_null());
4528 assert!((*child1).prev.is_null());
4529 assert!((*child1).next.is_null());
4530 assert_eq!((*root).children, child2);
4531 assert_eq!((*root).last, child2);
4532
4533 free_node(child1);
4534 free_doc(doc);
4535 }
4536 }
4537
4538 #[test]
4539 fn test_text_and_comment_nodes() {
4540 unsafe {
4541 let text = new_text(c_str("hello world"));
4542 assert!(!text.is_null());
4543 assert_eq!((*text).type_, XML_TEXT_NODE as c_int);
4544 assert!(!(*text).content.is_null());
4545 free_node(text);
4546
4547 let comment = new_comment(c_str("my comment"));
4548 assert!(!comment.is_null());
4549 assert_eq!((*comment).type_, XML_COMMENT_NODE as c_int);
4550 free_node(comment);
4551
4552 let pi = new_pi(c_str("xml"), c_str("version='1.0'"));
4553 assert!(!pi.is_null());
4554 assert_eq!((*pi).type_, XML_PI_NODE as c_int);
4555 free_node(pi);
4556 }
4557 }
4558
4559 #[test]
4560 fn test_set_and_get_prop() {
4561 unsafe {
4562 let doc = new_doc(ptr::null());
4563 let root = new_node(ptr::null_mut(), c_str("root"));
4564 doc_set_root_element(doc, root);
4565
4566 let attr = set_prop(root, c_str("id"), c_str("42"));
4567 assert!(!attr.is_null());
4568 assert_eq!((*attr).type_, XML_ATTRIBUTE_NODE as c_int);
4569
4570 let value = get_prop(root, c_str("id"));
4571 assert!(!value.is_null());
4572 assert!(crate::abi::exports_xml2::xmlStrEqual(value, c_str("42")) != 0);
4573 allocator::xmlFreeImpl(value as *mut c_void);
4574
4575 free_doc(doc);
4576 }
4577 }
4578
4579 #[test]
4580 fn test_remove_prop() {
4581 unsafe {
4582 let doc = new_doc(ptr::null());
4583 let root = new_node(ptr::null_mut(), c_str("root"));
4584 doc_set_root_element(doc, root);
4585
4586 set_prop(root, c_str("a"), c_str("1"));
4587 set_prop(root, c_str("b"), c_str("2"));
4588
4589 let value = get_prop(root, c_str("a"));
4590 assert!(!value.is_null());
4591 allocator::xmlFreeImpl(value as *mut c_void);
4592
4593 let attr = (*root).properties;
4595 assert!(!attr.is_null());
4596 let result = remove_prop(attr);
4597 assert_eq!(result, 0);
4598
4599 let value2 = get_prop(root, c_str("a"));
4601 assert!(value2.is_null());
4602
4603 free_doc(doc);
4604 }
4605 }
4606
4607 #[test]
4608 fn test_namespace_operations() {
4609 unsafe {
4610 let doc = new_doc(ptr::null());
4611 let root = new_node(ptr::null_mut(), c_str("root"));
4612 doc_set_root_element(doc, root);
4613
4614 let ns = new_ns(root, c_str("http://example.com"), c_str("ex"));
4615 assert!(!ns.is_null());
4616 assert!(!(*root).nsDef.is_null());
4617
4618 set_ns(root, ns);
4619 assert_eq!((*root).ns, ns);
4620
4621 let found = search_ns(doc, root, c_str("ex"));
4622 assert_eq!(found, ns);
4623
4624 let found_href = search_ns_by_href(doc, root, c_str("http://example.com"));
4625 assert_eq!(found_href, ns);
4626
4627 free_doc(doc);
4628 }
4629 }
4630
4631 #[test]
4632 fn test_new_dtd() {
4633 unsafe {
4634 let doc = new_doc(ptr::null());
4635 let dtd = new_dtd(doc, c_str("root"), c_str("-//TEST//DTD"), c_str("test.dtd"));
4636 assert!(!dtd.is_null());
4637 assert_eq!((*dtd).type_, XML_DTD_NODE as c_int);
4638 assert_eq!(get_int_subset(doc), dtd);
4639 free_doc(doc);
4640 }
4641 }
4642
4643 #[test]
4644 fn test_copy_node_deep() {
4645 unsafe {
4646 let doc = new_doc(ptr::null());
4647 let root = new_node(ptr::null_mut(), c_str("root"));
4648 doc_set_root_element(doc, root);
4649 let _child = new_child(root, ptr::null_mut(), c_str("child"));
4650
4651 let copy = copy_node(root, 1);
4652 assert!(!copy.is_null());
4653 assert_eq!((*copy).type_, XML_ELEMENT_NODE as c_int);
4654 assert!(!(*copy).children.is_null());
4656 assert_eq!((*(*copy).children).type_, XML_ELEMENT_NODE as c_int);
4657
4658 free_node(copy);
4659 free_doc(doc);
4660 }
4661 }
4662
4663 #[test]
4664 fn test_new_cdata_block() {
4665 unsafe {
4666 let doc = new_doc(ptr::null());
4667 let content = c_str("some <cdata> content");
4668 let cdata = new_cdata_block(doc, content, 20);
4669 assert!(!cdata.is_null());
4670 assert_eq!((*cdata).type_, XML_CDATA_SECTION_NODE as c_int);
4671 free_node(cdata);
4672 free_doc(doc);
4673 }
4674 }
4675
4676 #[test]
4677 fn test_null_handling() {
4678 unsafe {
4679 assert!(!new_doc(ptr::null()).is_null()); let doc = new_doc(ptr::null());
4681 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());
4686 assert!(add_sibling(ptr::null_mut(), ptr::null_mut()).is_null());
4687 free_doc(doc);
4688 }
4689 }
4690
4691 unsafe fn buf_eq_str(buf: *mut _xmlBuffer, expected: &str) -> bool {
4697 let content = io::buf_content(buf);
4698 if content.is_null() {
4699 return expected.is_empty();
4700 }
4701 let len = io::buf_length(buf) as usize;
4702 if len != expected.len() {
4703 return false;
4704 }
4705 let slice = unsafe { core::slice::from_raw_parts(content, len) };
4706 slice == expected.as_bytes()
4707 }
4708
4709 #[test]
4710 fn test_serialize_empty_document() {
4711 unsafe {
4712 let doc = new_doc(ptr::null());
4713 let buf = io::buf_create(-1);
4714 assert!(!buf.is_null());
4715
4716 let ret = doc_dump(buf, doc);
4717 assert!(ret >= 0);
4718
4719 let expected = "<?xml version=\"1.0\"?>\n";
4723 assert!(buf_eq_str(buf, expected));
4724
4725 io::buf_free(buf);
4726 free_doc(doc);
4727 }
4728 }
4729
4730 #[test]
4731 fn test_serialize_element_with_text() {
4732 unsafe {
4733 let doc = new_doc(ptr::null());
4734 let root = new_node(ptr::null_mut(), c_str("root"));
4735 doc_set_root_element(doc, root);
4736
4737 let text = new_text(c_str("hello world"));
4739 add_child(root, text);
4740
4741 let buf = io::buf_create(-1);
4742 assert!(!buf.is_null());
4743
4744 let ret = doc_dump(buf, doc);
4745 assert!(ret >= 0);
4746
4747 let expected = "<?xml version=\"1.0\"?>\n<root>hello world</root>\n";
4748 assert!(buf_eq_str(buf, expected));
4749
4750 io::buf_free(buf);
4751 free_doc(doc);
4752 }
4753 }
4754
4755 #[test]
4756 fn test_serialize_element_with_attributes() {
4757 unsafe {
4758 let doc = new_doc(ptr::null());
4759 let root = new_node(ptr::null_mut(), c_str("root"));
4760 doc_set_root_element(doc, root);
4761
4762 set_prop(root, c_str("id"), c_str("42"));
4763 set_prop(root, c_str("name"), c_str("test"));
4764
4765 let buf = io::buf_create(-1);
4766 assert!(!buf.is_null());
4767
4768 let ret = doc_dump(buf, doc);
4769 assert!(ret >= 0);
4770
4771 let expected = "<?xml version=\"1.0\"?>\n<root id=\"42\" name=\"test\"/>\n";
4772 assert!(buf_eq_str(buf, expected));
4773
4774 io::buf_free(buf);
4775 free_doc(doc);
4776 }
4777 }
4778
4779 #[test]
4780 fn test_serialize_nested_elements() {
4781 unsafe {
4782 let doc = new_doc(ptr::null());
4783 let root = new_node(ptr::null_mut(), c_str("root"));
4784 doc_set_root_element(doc, root);
4785
4786 let child = new_child(root, ptr::null_mut(), c_str("child"));
4787 let grandchild = new_child(child, ptr::null_mut(), c_str("gc"));
4788 let text = new_text(c_str("text"));
4789 add_child(grandchild, text);
4790
4791 let buf = io::buf_create(-1);
4792 assert!(!buf.is_null());
4793
4794 let ret = doc_dump(buf, doc);
4795 assert!(ret >= 0);
4796
4797 let expected = "<?xml version=\"1.0\"?>\n<root><child><gc>text</gc></child></root>\n";
4798 assert!(buf_eq_str(buf, expected));
4799
4800 io::buf_free(buf);
4801 free_doc(doc);
4802 }
4803 }
4804
4805 #[test]
4806 fn test_serialize_with_formatting() {
4807 unsafe {
4808 let doc = new_doc(ptr::null());
4809 let root = new_node(ptr::null_mut(), c_str("root"));
4810 doc_set_root_element(doc, root);
4811
4812 let child = new_child(root, ptr::null_mut(), c_str("child"));
4813 let text = new_text(c_str("text"));
4814 add_child(child, text);
4815
4816 let buf = io::buf_create(-1);
4817 assert!(!buf.is_null());
4818
4819 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
4820
4821 let expected = "<?xml version=\"1.0\"?>\n<root>\n <child>text</child>\n</root>\n";
4822 assert!(buf_eq_str(buf, expected));
4823
4824 io::buf_free(buf);
4825 free_doc(doc);
4826 }
4827 }
4828
4829 #[test]
4830 fn test_serialize_escape_ampersand() {
4831 unsafe {
4832 let doc = new_doc(ptr::null());
4833 let root = new_node(ptr::null_mut(), c_str("root"));
4834 doc_set_root_element(doc, root);
4835
4836 let text = new_text(c_str("a & b"));
4837 add_child(root, text);
4838
4839 let buf = io::buf_create(-1);
4840 assert!(!buf.is_null());
4841
4842 let ret = doc_dump(buf, doc);
4843 assert!(ret >= 0);
4844
4845 let expected = "<?xml version=\"1.0\"?>\n<root>a & b</root>\n";
4846 assert!(buf_eq_str(buf, expected));
4847
4848 io::buf_free(buf);
4849 free_doc(doc);
4850 }
4851 }
4852
4853 #[test]
4854 fn test_serialize_escape_angle_brackets() {
4855 unsafe {
4856 let doc = new_doc(ptr::null());
4857 let root = new_node(ptr::null_mut(), c_str("root"));
4858 doc_set_root_element(doc, root);
4859
4860 let text = new_text(c_str("x < y > z"));
4861 add_child(root, text);
4862
4863 let buf = io::buf_create(-1);
4864 assert!(!buf.is_null());
4865
4866 let ret = doc_dump(buf, doc);
4867 assert!(ret >= 0);
4868
4869 let expected = "<?xml version=\"1.0\"?>\n<root>x < y > z</root>\n";
4870 assert!(buf_eq_str(buf, expected));
4871
4872 io::buf_free(buf);
4873 free_doc(doc);
4874 }
4875 }
4876
4877 #[test]
4878 fn test_serialize_comment() {
4879 unsafe {
4880 let doc = new_doc(ptr::null());
4881 let root = new_node(ptr::null_mut(), c_str("root"));
4882 doc_set_root_element(doc, root);
4883
4884 let comment = new_comment(c_str("my comment"));
4885 add_child(root, comment);
4886
4887 let buf = io::buf_create(-1);
4888 assert!(!buf.is_null());
4889
4890 let ret = doc_dump(buf, doc);
4891 assert!(ret >= 0);
4892
4893 let expected = "<?xml version=\"1.0\"?>\n<root><!--my comment--></root>\n";
4894 assert!(buf_eq_str(buf, expected));
4895
4896 io::buf_free(buf);
4897 free_doc(doc);
4898 }
4899 }
4900
4901 #[test]
4902 fn test_serialize_pi() {
4903 unsafe {
4904 let doc = new_doc(ptr::null());
4905 let root = new_node(ptr::null_mut(), c_str("root"));
4906 doc_set_root_element(doc, root);
4907
4908 let pi = new_pi(
4909 c_str("xml-stylesheet"),
4910 c_str("href=\"style.xsl\" type=\"text/xsl\""),
4911 );
4912 add_child(root, pi);
4913
4914 let buf = io::buf_create(-1);
4915 assert!(!buf.is_null());
4916
4917 let ret = doc_dump(buf, doc);
4918 assert!(ret >= 0);
4919
4920 let expected = "<?xml version=\"1.0\"?>\n<root><?xml-stylesheet href=\"style.xsl\" type=\"text/xsl\"?></root>\n";
4921 assert!(buf_eq_str(buf, expected));
4922
4923 io::buf_free(buf);
4924 free_doc(doc);
4925 }
4926 }
4927
4928 #[test]
4929 fn test_serialize_self_closing() {
4930 unsafe {
4931 let doc = new_doc(ptr::null());
4932 let root = new_node(ptr::null_mut(), c_str("empty"));
4933 doc_set_root_element(doc, root);
4934
4935 let buf = io::buf_create(-1);
4936 assert!(!buf.is_null());
4937
4938 let ret = doc_dump(buf, doc);
4939 assert!(ret >= 0);
4940
4941 let expected = "<?xml version=\"1.0\"?>\n<empty/>\n";
4942 assert!(buf_eq_str(buf, expected));
4943
4944 io::buf_free(buf);
4945 free_doc(doc);
4946 }
4947 }
4948
4949 #[test]
4950 fn test_dump_node_to_string() {
4951 unsafe {
4952 let node = new_node(ptr::null_mut(), c_str("foo"));
4953 let text = new_text(c_str("bar"));
4954 add_child(node, text);
4955
4956 let result = dump_node(node);
4957 assert!(!result.is_null());
4958
4959 let len = xml_strlen(result);
4960 let slice = { core::slice::from_raw_parts(result, len as usize) };
4961 assert_eq!(slice, b"<foo>bar</foo>");
4962
4963 allocator::xmlFreeImpl(result as *mut c_void);
4964 free_node(node);
4965 }
4966 }
4967
4968 #[test]
4969 fn test_dump_doc_to_string() {
4970 unsafe {
4971 let doc = new_doc(ptr::null());
4972 let root = new_node(ptr::null_mut(), c_str("root"));
4973 doc_set_root_element(doc, root);
4974
4975 let result = dump_doc(doc);
4976 assert!(!result.is_null());
4977
4978 let len = xml_strlen(result);
4979 let slice = { core::slice::from_raw_parts(result, len as usize) };
4980 let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
4981 assert_eq!(slice, expected.as_bytes());
4982
4983 allocator::xmlFreeImpl(result as *mut c_void);
4984 free_doc(doc);
4985 }
4986 }
4987
4988 #[test]
4989 fn test_xmlDocDumpFormatMemory() {
4990 unsafe {
4991 let doc = new_doc(ptr::null());
4992 let root = new_node(ptr::null_mut(), c_str("root"));
4993 doc_set_root_element(doc, root);
4994
4995 let mut mem: *mut xmlChar = ptr::null_mut();
4996 let mut size: c_int = 0;
4997
4998 xmlDocDumpFormatMemory(doc, &mut mem, &mut size, 0);
4999
5000 assert!(!mem.is_null());
5001 assert!(size > 0);
5002
5003 let slice = { core::slice::from_raw_parts(mem, size as usize) };
5004 let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
5007 assert_eq!(slice, expected.as_bytes());
5008
5009 allocator::xmlFreeImpl(mem as *mut c_void);
5010 free_doc(doc);
5011 }
5012 }
5013
5014 #[test]
5015 fn test_serialize_escape_attribute() {
5016 unsafe {
5017 let doc = new_doc(ptr::null());
5018 let root = new_node(ptr::null_mut(), c_str("root"));
5019 doc_set_root_element(doc, root);
5020
5021 set_prop(root, c_str("desc"), c_str("a < b & c \"quoted\""));
5023
5024 let buf = io::buf_create(-1);
5025 assert!(!buf.is_null());
5026
5027 let ret = doc_dump(buf, doc);
5028 assert!(ret >= 0);
5029
5030 let expected =
5031 "<?xml version=\"1.0\"?>\n<root desc=\"a < b & c "quoted"\"/>\n";
5032 assert!(buf_eq_str(buf, expected));
5033
5034 io::buf_free(buf);
5035 free_doc(doc);
5036 }
5037 }
5038}