1use core::ffi::c_void;
37use core::ptr;
38use std::os::raw::{c_char, c_int, c_long, c_uint, c_ulong};
39
40use crate::abi::allocator;
41use crate::abi::constants::*;
42use crate::abi::structs::*;
43use crate::abi::types::xmlAttributeType::XML_ATTRIBUTE_CDATA;
44use crate::abi::types::xmlCharEncoding::XML_CHAR_ENCODING_UTF8;
45use crate::abi::types::xmlDocProperties::{
46 XML_DOC_DTDVALID, XML_DOC_NSVALID, XML_DOC_USERBUILT, XML_DOC_WELLFORMED,
47};
48use crate::abi::types::xmlElementType::*;
49use crate::abi::types::*;
50use crate::xml::globals;
51use crate::xml::io;
52
53unsafe fn dup_xml_str(str: *const xmlChar) -> *mut xmlChar {
63 if str.is_null() {
64 return ptr::null_mut();
65 }
66 let len = unsafe { crate::abi::exports_xml2::xmlStrlen(str) as usize };
67 if len == 0 {
68 let buf = unsafe { allocator::xmlMallocImpl(1) as *mut xmlChar };
70 if !buf.is_null() {
71 unsafe { *buf = 0 };
72 }
73 return buf;
74 }
75 let buf = unsafe { allocator::xmlMallocImpl(len + 1) as *mut xmlChar };
76 if !buf.is_null() {
77 unsafe {
78 ptr::copy_nonoverlapping(str, buf, len + 1);
79 }
80 }
81 buf
82}
83
84unsafe fn copy_xml_str_content(dest: *mut xmlChar, src: *const xmlChar, max_len: usize) -> bool {
86 if src.is_null() || dest.is_null() || max_len == 0 {
87 return false;
88 }
89 let len = unsafe { crate::abi::exports_xml2::xmlStrlen(src) as usize };
90 if len >= max_len {
91 return false;
92 }
93 unsafe {
94 ptr::copy_nonoverlapping(src, dest, len);
95 *dest.add(len) = 0;
96 }
97 true
98}
99
100pub unsafe fn xml_strlen(str: *const xmlChar) -> c_int {
102 if str.is_null() {
103 return 0;
104 }
105 let mut len: c_int = 0;
106 while unsafe { *str.add(len as usize) != 0 } {
107 len += 1;
108 }
109 len
110}
111
112pub unsafe fn new_doc(version: *const xmlChar) -> *mut _xmlDoc {
135 let doc = allocator::xmlMallocZero(size_of::<_xmlDoc>() as usize) as *mut _xmlDoc;
137 if doc.is_null() {
138 return ptr::null_mut();
139 }
140
141 unsafe {
142 (*doc).type_ = XML_DOCUMENT_NODE as c_int;
143 (*doc).standalone = -1; (*doc).doc = doc; (*doc).properties = XML_DOC_USERBUILT as c_int;
146 (*doc).compression = -1; (*doc).charset = XML_CHAR_ENCODING_UTF8 as c_int;
148
149 let ver = if version.is_null() {
151 XML_DEFAULT_VERSION.as_ptr() as *const xmlChar
152 } else {
153 version
154 };
155 (*doc).version = dup_xml_str(ver);
156 }
157
158 crate::abi::data_globals::register_node_hook(doc as *mut _xmlNode);
160
161 doc
162}
163
164pub unsafe fn free_doc(doc: *mut _xmlDoc) {
178 if doc.is_null() {
179 return;
180 }
181
182 crate::abi::data_globals::deregister_node_hook(doc as *mut _xmlNode);
185
186 let d = unsafe { &mut *doc };
187
188 let dict = d.dict;
192 let mut ext_subset = d.extSubset;
193 let int_subset = d.intSubset;
194 if !ext_subset.is_null() && ext_subset == int_subset {
195 ext_subset = ptr::null_mut();
196 }
197 if !ext_subset.is_null() {
198 unlink_node_internal(ext_subset as *mut _xmlNode, d as *mut _xmlDoc);
199 d.extSubset = ptr::null_mut();
200 free_dtd(ext_subset);
201 }
202 if !int_subset.is_null() {
203 unlink_node_internal(int_subset as *mut _xmlNode, d as *mut _xmlDoc);
204 d.intSubset = ptr::null_mut();
205 free_dtd(int_subset);
206 }
207
208 if !d.children.is_null() {
210 free_node_list(d.children);
211 }
212
213 if !d.oldNs.is_null() {
215 free_ns_list(d.oldNs);
216 }
217
218 if !d.version.is_null() {
220 allocator::xmlFreeImpl(d.version as *mut c_void);
221 }
222 if !d.encoding.is_null() {
223 allocator::xmlFreeImpl(d.encoding as *mut c_void);
224 }
225 if !d.URL.is_null() {
226 allocator::xmlFreeImpl(d.URL as *mut c_void);
227 }
228
229 allocator::xmlFreeImpl(doc as *mut c_void);
231
232 if !dict.is_null() {
234 crate::abi::exports_xml2::xmlDictFree(dict);
235 }
236}
237
238unsafe fn unlink_node_internal(node: *mut _xmlNode, _doc: *mut _xmlDoc) {
242 if node.is_null() {
243 return;
244 }
245 let parent = (*node).parent;
246 if parent.is_null() {
247 return;
248 }
249 if (*node).prev.is_null() {
250 (*parent).children = (*node).next;
251 } else {
252 (*(*node).prev).next = (*node).next;
253 }
254 if (*node).next.is_null() {
255 (*parent).last = (*node).prev;
256 } else {
257 (*(*node).next).prev = (*node).prev;
258 }
259 (*node).next = ptr::null_mut();
260 (*node).prev = ptr::null_mut();
261 (*node).parent = ptr::null_mut();
262}
263
264pub unsafe fn copy_doc(doc: *const _xmlDoc, recursive: c_int) -> *mut _xmlDoc {
279 if doc.is_null() {
280 return ptr::null_mut();
281 }
282
283 let d = unsafe { &*doc };
284
285 let new_doc = new_doc(d.version);
286 if new_doc.is_null() {
287 return ptr::null_mut();
288 }
289
290 unsafe {
291 (*new_doc).type_ = d.type_;
292 (*new_doc).standalone = d.standalone;
293 (*new_doc).encoding = dup_xml_str(d.encoding);
294 (*new_doc).URL = dup_xml_str(d.URL);
295 (*new_doc).charset = d.charset;
296 (*new_doc).properties = d.properties;
297
298 if !d.intSubset.is_null() {
303 let dtd_copy = crate::xml::dtd::copy_dtd(d.intSubset);
304 if !dtd_copy.is_null() {
305 (*new_doc).intSubset = dtd_copy;
306 }
307 }
308
309 if recursive != 0 && !d.children.is_null() {
310 (*new_doc).children = copy_node_list(d.children, recursive);
311 if !(*new_doc).children.is_null() {
312 (*(*new_doc).children).parent = ptr::null_mut(); (*(*new_doc).children).doc = new_doc;
314 propagate_doc((*new_doc).children, new_doc);
316 }
317 }
318 }
319
320 new_doc
321}
322
323pub unsafe fn doc_set_root_element(doc: *mut _xmlDoc, root: *mut _xmlNode) -> *mut _xmlNode {
339 if doc.is_null() {
340 return ptr::null_mut();
341 }
342
343 let d = unsafe { &mut *doc };
344
345 let old_root = doc_get_root_element(doc);
346
347 if !root.is_null() {
348 unsafe {
349 (*root).parent = ptr::null_mut();
350 (*root).doc = doc;
351 }
352 d.children = root;
353 d.last = root;
354 unsafe {
355 (*root).prev = ptr::null_mut();
356 (*root).next = ptr::null_mut();
357 }
358 } else {
359 d.children = ptr::null_mut();
360 d.last = ptr::null_mut();
361 }
362
363 old_root
364}
365
366pub fn doc_get_root_element(doc: *mut _xmlDoc) -> *mut _xmlNode {
377 if doc.is_null() {
378 return ptr::null_mut();
379 }
380
381 let d = unsafe { &*doc };
382 let mut cur = d.children;
383
384 while !cur.is_null() {
385 let node = unsafe { &*cur };
386 if node.type_ == XML_ELEMENT_NODE as c_int {
387 return cur;
388 }
389 cur = node.next;
390 }
391
392 ptr::null_mut()
393}
394
395pub fn get_line_no(node: *const _xmlNode) -> c_long {
405 unsafe { get_line_no_internal(node, 0) }
406}
407
408unsafe fn get_line_no_internal(node: *const _xmlNode, depth: c_int) -> c_long {
413 if depth >= 5 {
414 return -1;
415 }
416 if node.is_null() {
417 return -1;
418 }
419 let n = unsafe { &*node };
420 if n.type_ == XML_ELEMENT_NODE as c_int
421 || n.type_ == XML_TEXT_NODE as c_int
422 || n.type_ == XML_COMMENT_NODE as c_int
423 || n.type_ == XML_PI_NODE as c_int
424 {
425 if n.line == 65535 {
426 if n.type_ == XML_ELEMENT_NODE as c_int && !n.children.is_null() {
427 let r = unsafe { get_line_no_internal(n.children, depth + 1) };
428 if r != -1 {
429 return r;
430 }
431 }
432 if !n.next.is_null() {
433 let r = unsafe { get_line_no_internal(n.next, depth + 1) };
434 if r != -1 {
435 return r;
436 }
437 }
438 if !n.prev.is_null() {
439 let r = unsafe { get_line_no_internal(n.prev, depth + 1) };
440 if r != -1 {
441 return r;
442 }
443 }
444 }
445 n.line as c_long
446 } else if !n.prev.is_null()
447 && (unsafe { (*n.prev).type_ } == XML_ELEMENT_NODE as c_int
448 || unsafe { (*n.prev).type_ } == XML_TEXT_NODE as c_int
449 || unsafe { (*n.prev).type_ } == XML_COMMENT_NODE as c_int
450 || unsafe { (*n.prev).type_ } == XML_PI_NODE as c_int)
451 {
452 unsafe { get_line_no_internal(n.prev, depth + 1) }
453 } else if !n.parent.is_null() && unsafe { (*n.parent).type_ } == XML_ELEMENT_NODE as c_int {
454 unsafe { get_line_no_internal(n.parent, depth + 1) }
455 } else {
456 -1
457 }
458}
459
460pub unsafe fn node_get_content(node: *mut _xmlNode) -> *mut xmlChar {
480 if node.is_null() {
481 return ptr::null_mut();
482 }
483 let typ = (*node).type_;
484 let mut result: Vec<u8> = Vec::new();
485 match typ {
486 t if t == XML_TEXT_NODE as c_int
487 || t == XML_CDATA_SECTION_NODE as c_int
488 || t == XML_COMMENT_NODE as c_int
489 || t == XML_PI_NODE as c_int =>
490 {
491 if !(*node).content.is_null() {
492 let len = crate::abi::exports_xml2::xmlStrlen((*node).content);
493 result
494 .extend_from_slice(core::slice::from_raw_parts((*node).content, len as usize));
495 } else if t == XML_TEXT_NODE as c_int && !(*node).children.is_null() {
496 let mut child = (*node).children;
499 while !child.is_null() {
500 if !(*child).content.is_null() {
501 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
502 result.extend_from_slice(core::slice::from_raw_parts(
503 (*child).content,
504 len as usize,
505 ));
506 }
507 child = (*child).next;
508 }
509 }
510 }
511 t if t == XML_ATTRIBUTE_NODE as c_int => {
512 if !(*node).children.is_null() {
514 let child = (*node).children;
515 if !(*child).content.is_null() {
516 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
517 result.extend_from_slice(core::slice::from_raw_parts(
518 (*child).content,
519 len as usize,
520 ));
521 }
522 }
523 }
524 t if t == XML_ENTITY_REF_NODE as c_int => {
525 let name = (*node).name;
527 if !name.is_null() && !(*node).doc.is_null() {
528 let ent = crate::xml::tree::get_doc_entity((*node).doc, name);
529 if !ent.is_null() && !(*ent).content.is_null() {
530 let len = crate::abi::exports_xml2::xmlStrlen((*ent).content);
531 result.extend_from_slice(core::slice::from_raw_parts(
532 (*ent).content,
533 len as usize,
534 ));
535 }
536 }
537 }
538 t if t == XML_DOCUMENT_NODE as c_int || t == XML_HTML_DOCUMENT_NODE as c_int => {
539 let root = doc_get_root_element(node as *mut _xmlDoc);
540 if !root.is_null() {
541 let sub = node_get_content(root);
542 if !sub.is_null() {
543 let len = crate::abi::exports_xml2::xmlStrlen(sub);
544 result.extend_from_slice(core::slice::from_raw_parts(sub, len as usize));
545 allocator::xmlFreeImpl(sub as *mut c_void);
546 }
547 }
548 }
549 _ => {
550 let mut child = (*node).children;
555 while !child.is_null() {
556 let ctype = (*child).type_;
557 if ctype == XML_TEXT_NODE as c_int || ctype == XML_CDATA_SECTION_NODE as c_int {
558 if !(*child).content.is_null() {
559 let len = crate::abi::exports_xml2::xmlStrlen((*child).content);
560 result.extend_from_slice(core::slice::from_raw_parts(
561 (*child).content,
562 len as usize,
563 ));
564 }
565 } else if ctype == XML_ENTITY_REF_NODE as c_int
566 || ctype == XML_ELEMENT_NODE as c_int
567 {
568 let sub = node_get_content(child);
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 child = (*child).next;
576 }
577 }
578 }
579 let buf = allocator::xmlMallocImpl(result.len() + 1) as *mut xmlChar;
581 if buf.is_null() {
582 return ptr::null_mut();
583 }
584 if !result.is_empty() {
585 ptr::copy_nonoverlapping(result.as_ptr(), buf, result.len());
586 }
587 *buf.add(result.len()) = 0;
588 buf
589}
590
591pub unsafe fn new_node(ns: *mut _xmlNs, name: *const xmlChar) -> *mut _xmlNode {
610 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
611 if node.is_null() {
612 return ptr::null_mut();
613 }
614
615 unsafe {
616 (*node).type_ = XML_ELEMENT_NODE as c_int;
617 (*node).name = dup_xml_str(name);
618 (*node).ns = ns;
619 (*node).line = 0;
620 (*node).extra = 0;
621
622 if !ns.is_null() {
623 (*ns).context = node as *mut _xmlDoc;
624 }
625 }
626
627 crate::abi::data_globals::register_node_hook(node);
630
631 node
632}
633
634pub unsafe fn free_node(node: *mut _xmlNode) {
649 if node.is_null() {
650 return;
651 }
652
653 let n = unsafe { &mut *node };
654
655 if n.type_ == XML_DTD_NODE as c_int {
659 free_dtd(node as *mut _xmlDtd);
660 return;
661 } else if n.type_ == XML_NAMESPACE_DECL as c_int {
662 free_ns(node as *mut _xmlNs);
663 return;
664 } else if n.type_ == XML_ATTRIBUTE_NODE as c_int {
665 free_prop(node as *mut _xmlAttr);
666 return;
667 } else if n.type_ == XML_ELEMENT_DECL as c_int {
668 crate::xml::dtd::free_element(node as *mut _xmlElement);
669 return;
670 } else if n.type_ == XML_ATTRIBUTE_DECL as c_int {
671 crate::xml::dtd::free_attribute(node as *mut _xmlAttribute);
672 return;
673 } else if n.type_ == XML_ENTITY_DECL as c_int {
674 crate::xml::entities::free_entity(node as *mut _xmlEntity);
675 return;
676 }
677
678 crate::abi::data_globals::deregister_node_hook(node);
681
682 let is_element = n.type_ == XML_ELEMENT_NODE as c_int;
687 if is_element && !n.properties.is_null() {
688 free_prop_list(n.properties);
689 }
690
691 if is_element && !n.nsDef.is_null() {
692 free_ns_list(n.nsDef);
693 }
694
695 if !n.name.is_null() {
697 allocator::xmlFreeImpl(n.name as *mut c_void);
698 }
699
700 if !n.content.is_null() {
705 let node_type = n.type_;
706 if node_type == XML_TEXT_NODE as c_int
707 || node_type == XML_CDATA_SECTION_NODE as c_int
708 || node_type == XML_COMMENT_NODE as c_int
709 || node_type == XML_PI_NODE as c_int
710 {
711 let inline_addr = std::ptr::addr_of_mut!((*node).properties) as *const c_void;
712 if n.content as *const c_void != inline_addr {
713 allocator::xmlFreeImpl(n.content as *mut c_void);
714 }
715 }
716 }
717
718 allocator::xmlFreeImpl(node as *mut c_void);
719}
720
721pub unsafe fn free_node_list(node: *mut _xmlNode) {
740 let mut cur = node;
741 while !cur.is_null() {
742 let next = unsafe { (*cur).next };
743 let t = unsafe { (*cur).type_ };
744
745 if t == XML_DTD_NODE as c_int {
746 unsafe {
748 (*cur).prev = ptr::null_mut();
749 (*cur).next = ptr::null_mut();
750 }
751 cur = next;
752 continue;
753 }
754
755 if t != XML_ENTITY_REF_NODE as c_int && !unsafe { (*cur).children }.is_null() {
758 free_node_list(unsafe { (*cur).children });
759 }
760
761 free_node(cur);
762 cur = next;
763 }
764}
765
766unsafe fn free_prop_list(prop: *mut _xmlAttr) {
772 let mut cur = prop;
773 while !cur.is_null() {
774 let next = unsafe { (*cur).next };
775 free_prop(cur);
776 cur = next;
777 }
778}
779
780unsafe fn free_prop(prop: *mut _xmlAttr) {
786 if prop.is_null() {
787 return;
788 }
789
790 if !unsafe { (*prop).children }.is_null() {
792 free_node_list(unsafe { (*prop).children });
793 }
794
795 if !unsafe { (*prop).name }.is_null() {
797 allocator::xmlFreeImpl(unsafe { (*prop).name } as *mut c_void);
798 }
799
800 allocator::xmlFreeImpl(prop as *mut c_void);
801}
802
803unsafe fn free_ns_list(ns: *mut _xmlNs) {
809 let mut cur = ns;
810 while !cur.is_null() {
811 let next = unsafe { (*cur).next };
812 free_ns(cur);
813 cur = next;
814 }
815}
816
817unsafe fn free_ns(ns: *mut _xmlNs) {
823 if ns.is_null() {
824 return;
825 }
826
827 if !unsafe { (*ns).href }.is_null() {
829 allocator::xmlFreeImpl(unsafe { (*ns).href } as *mut c_void);
830 }
831 if !unsafe { (*ns).prefix }.is_null() {
832 allocator::xmlFreeImpl(unsafe { (*ns).prefix } as *mut c_void);
833 }
834
835 allocator::xmlFreeImpl(ns as *mut c_void);
836}
837
838pub unsafe fn copy_node(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
853 if node.is_null() {
854 return ptr::null_mut();
855 }
856
857 let n = unsafe { &*node };
858
859 let new_node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
860 if new_node.is_null() {
861 return ptr::null_mut();
862 }
863
864 unsafe {
865 (*new_node).type_ = n.type_;
866 (*new_node).name = dup_xml_str(n.name);
867 if n.type_ == XML_ELEMENT_NODE as c_int {
871 (*new_node).line = n.line;
872 }
873 (*new_node).extra = n.extra;
874 (*new_node).psvi = n.psvi;
875 (*new_node)._private = n._private;
876
877 (*new_node).ns = n.ns;
879
880 let is_element = n.type_ == XML_ELEMENT_NODE as c_int;
883 if is_element && !n.nsDef.is_null() {
884 (*new_node).nsDef = copy_ns_list(n.nsDef);
885 }
886
887 let node_type = n.type_;
889 if (node_type == XML_TEXT_NODE as c_int
890 || node_type == XML_CDATA_SECTION_NODE as c_int
891 || node_type == XML_COMMENT_NODE as c_int
892 || node_type == XML_PI_NODE as c_int)
893 && !n.content.is_null()
894 {
895 (*new_node).content = dup_xml_str(n.content);
896 }
897
898 if is_element && !n.properties.is_null() {
900 (*new_node).properties = copy_prop_list(n.properties);
901 let mut prop = (*new_node).properties;
903 while !prop.is_null() {
904 (*prop).parent = new_node;
905 if !(*prop).children.is_null() {
906 propagate_doc((*prop).children, (*new_node).doc);
907 }
908 prop = (*prop).next;
909 }
910 }
911
912 if recursive != 0 && !n.children.is_null() {
915 (*new_node).children = copy_node_list(n.children, recursive);
916 if !(*new_node).children.is_null() {
917 let mut child = (*new_node).children;
918 let mut last_child = child;
919 while !child.is_null() {
920 (*child).parent = new_node;
921 (*child).doc = (*new_node).doc;
922 propagate_doc(child, (*new_node).doc);
923 if (*child).next.is_null() {
924 last_child = child;
925 }
926 child = (*child).next;
927 }
928 (*new_node).last = last_child;
929 }
930 }
931 }
932
933 new_node
934}
935
936unsafe fn copy_node_list(node: *const _xmlNode, recursive: c_int) -> *mut _xmlNode {
940 if node.is_null() {
941 return ptr::null_mut();
942 }
943
944 let n = unsafe { &*node };
945 let new_node = copy_node(node, recursive);
946 if new_node.is_null() {
947 return ptr::null_mut();
948 }
949
950 let mut prev = new_node;
951 let mut cur = n.next;
952
953 while !cur.is_null() {
954 let new_cur = copy_node(cur, recursive);
955 if new_cur.is_null() {
956 break;
957 }
958 unsafe {
959 (*prev).next = new_cur;
960 (*new_cur).prev = prev;
961 }
962 prev = new_cur;
963 cur = unsafe { (*cur).next };
964 }
965
966 new_node
967}
968
969unsafe fn copy_ns_list(ns: *const _xmlNs) -> *mut _xmlNs {
971 if ns.is_null() {
972 return ptr::null_mut();
973 }
974
975 let n = unsafe { &*ns };
976 let new_ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
977 if new_ns.is_null() {
978 return ptr::null_mut();
979 }
980
981 unsafe {
982 (*new_ns).type_ = n.type_;
983 (*new_ns).href = dup_xml_str(n.href);
984 (*new_ns).prefix = dup_xml_str(n.prefix);
985 (*new_ns)._private = n._private;
986 }
987
988 let mut prev = new_ns;
989 let mut cur = n.next;
990
991 while !cur.is_null() {
992 let c = unsafe { &*cur };
993 let new_cur = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
994 if new_cur.is_null() {
995 break;
996 }
997 unsafe {
998 (*new_cur).type_ = c.type_;
999 (*new_cur).href = dup_xml_str(c.href);
1000 (*new_cur).prefix = dup_xml_str(c.prefix);
1001 (*new_cur)._private = c._private;
1002 (*prev).next = new_cur;
1003 }
1004 prev = new_cur;
1005 cur = c.next;
1006 }
1007
1008 new_ns
1009}
1010
1011unsafe fn copy_prop_list(prop: *const _xmlAttr) -> *mut _xmlAttr {
1013 if prop.is_null() {
1014 return ptr::null_mut();
1015 }
1016
1017 let p = unsafe { &*prop };
1018 let new_prop = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
1019 if new_prop.is_null() {
1020 return ptr::null_mut();
1021 }
1022
1023 unsafe {
1024 (*new_prop).type_ = p.type_;
1025 (*new_prop).name = dup_xml_str(p.name);
1026 (*new_prop).ns = p.ns;
1027 (*new_prop).atype = p.atype;
1028
1029 if !p.children.is_null() {
1031 (*new_prop).children = copy_node_list(p.children, 1);
1032 if !(*new_prop).children.is_null() {
1033 (*(*new_prop).children).parent = new_prop as *mut _xmlNode;
1034 }
1035 }
1036 }
1037
1038 let mut prev = new_prop;
1039 let mut cur = p.next;
1040
1041 while !cur.is_null() {
1042 let c = unsafe { &*cur };
1043 let new_cur = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
1044 if new_cur.is_null() {
1045 break;
1046 }
1047 unsafe {
1048 (*new_cur).type_ = c.type_;
1049 (*new_cur).name = dup_xml_str(c.name);
1050 (*new_cur).ns = c.ns;
1051 (*new_cur).atype = c.atype;
1052
1053 if !c.children.is_null() {
1054 (*new_cur).children = copy_node_list(c.children, 1);
1055 if !(*new_cur).children.is_null() {
1056 (*(*new_cur).children).parent = new_cur as *mut _xmlNode;
1057 }
1058 }
1059
1060 (*prev).next = new_cur;
1061 }
1062 prev = new_cur;
1063 cur = c.next;
1064 }
1065
1066 new_prop
1067}
1068
1069unsafe fn propagate_doc(node: *mut _xmlNode, doc: *mut _xmlDoc) {
1071 let mut cur = node;
1072 while !cur.is_null() {
1073 unsafe {
1074 (*cur).doc = doc;
1075
1076 if (*cur).type_ == XML_ELEMENT_NODE as c_int {
1080 let mut prop = (*cur).properties;
1081 while !prop.is_null() {
1082 (*prop).doc = doc;
1083 if !(*prop).children.is_null() {
1084 propagate_doc((*prop).children, doc);
1085 }
1086 prop = (*prop).next;
1087 }
1088 }
1089
1090 if !(*cur).children.is_null() {
1092 propagate_doc((*cur).children, doc);
1093 }
1094 }
1095 cur = unsafe { (*cur).next };
1096 }
1097}
1098
1099pub unsafe fn unlink_node(node: *mut _xmlNode) {
1115 if node.is_null() {
1116 return;
1117 }
1118
1119 let n = unsafe { &mut *node };
1120
1121 let prev = n.prev;
1123 let next = n.next;
1124
1125 if !prev.is_null() {
1126 unsafe { (*prev).next = next };
1127 }
1128 if !next.is_null() {
1129 unsafe { (*next).prev = prev };
1130 }
1131
1132 let parent = n.parent;
1134 if !parent.is_null() {
1135 if unsafe { (*parent).children } == node {
1136 unsafe { (*parent).children = next };
1137 }
1138 if unsafe { (*parent).last } == node {
1139 unsafe { (*parent).last = prev };
1140 }
1141 }
1142
1143 let doc = n.doc;
1145 if !doc.is_null() && !parent.is_null() {
1146 }
1148 if !doc.is_null() && parent.is_null() {
1149 if unsafe { (*doc).children } == node {
1151 unsafe { (*doc).children = next };
1152 }
1153 if unsafe { (*doc).last } == node {
1154 unsafe { (*doc).last = prev };
1155 }
1156 }
1157
1158 n.parent = ptr::null_mut();
1160 n.prev = ptr::null_mut();
1161 n.next = ptr::null_mut();
1162}
1163
1164pub unsafe fn add_child(parent: *mut _xmlNode, cur: *mut _xmlNode) -> *mut _xmlNode {
1180 if parent.is_null() || cur.is_null() {
1181 return ptr::null_mut();
1182 }
1183
1184 let p = unsafe { &mut *parent };
1185 let c = unsafe { &mut *cur };
1186
1187 if !c.parent.is_null() || !c.prev.is_null() || !c.next.is_null() {
1189 unlink_node(cur);
1190 }
1191
1192 c.parent = parent;
1194
1195 if p.children.is_null() {
1196 p.children = cur;
1198 p.last = cur;
1199 c.prev = ptr::null_mut();
1200 c.next = ptr::null_mut();
1201 } else {
1202 c.prev = p.last;
1204 c.next = ptr::null_mut();
1205 if !p.last.is_null() {
1206 unsafe { (*p.last).next = cur };
1207 }
1208 p.last = cur;
1209 }
1210
1211 let doc = if !p.doc.is_null() {
1213 p.doc
1214 } else {
1215 ptr::null_mut()
1216 };
1217 if !doc.is_null() && c.doc != doc {
1218 propagate_doc(cur, doc);
1219 }
1220
1221 cur
1222}
1223
1224pub unsafe fn add_sibling(cur: *mut _xmlNode, elem: *mut _xmlNode) -> *mut _xmlNode {
1240 if cur.is_null() || elem.is_null() {
1241 return ptr::null_mut();
1242 }
1243
1244 let c = unsafe { &mut *cur };
1245
1246 let e = unsafe { &mut *elem };
1248 if !e.parent.is_null() || !e.prev.is_null() || !e.next.is_null() {
1249 unlink_node(elem);
1250 }
1251
1252 e.parent = c.parent;
1254
1255 e.prev = cur;
1257 e.next = c.next;
1258
1259 if !c.next.is_null() {
1260 unsafe { (*c.next).prev = elem };
1261 }
1262 c.next = elem;
1263
1264 let parent = c.parent;
1266 if !parent.is_null() && unsafe { (*parent).last } == cur {
1267 unsafe { (*parent).last = elem };
1268 }
1269
1270 if !c.doc.is_null() && e.doc != c.doc {
1272 propagate_doc(elem, c.doc);
1273 }
1274
1275 elem
1276}
1277
1278pub unsafe fn add_sibling_before(cur: *mut _xmlNode, elem: *mut _xmlNode) -> *mut _xmlNode {
1294 if cur.is_null() || elem.is_null() {
1295 return ptr::null_mut();
1296 }
1297
1298 let c = unsafe { &mut *cur };
1299
1300 let e = unsafe { &mut *elem };
1302 if !e.parent.is_null() || !e.prev.is_null() || !e.next.is_null() {
1303 unlink_node(elem);
1304 }
1305
1306 e.parent = c.parent;
1308
1309 e.prev = c.prev;
1311 e.next = cur;
1312
1313 if !c.prev.is_null() {
1314 unsafe { (*c.prev).next = elem };
1315 }
1316 c.prev = elem;
1317
1318 let parent = c.parent;
1320 if !parent.is_null() && unsafe { (*parent).children } == cur {
1321 unsafe { (*parent).children = elem };
1322 }
1323
1324 let doc = c.doc;
1326 if !doc.is_null() && parent.is_null() {
1327 if unsafe { (*doc).children } == cur {
1328 unsafe { (*doc).children = elem };
1329 }
1330 }
1331
1332 if !c.doc.is_null() && e.doc != c.doc {
1334 propagate_doc(elem, c.doc);
1335 }
1336
1337 elem
1338}
1339
1340pub unsafe fn new_child(
1355 parent: *mut _xmlNode,
1356 ns: *mut _xmlNs,
1357 name: *const xmlChar,
1358) -> *mut _xmlNode {
1359 let node = new_node(ns, name);
1360 if node.is_null() {
1361 return ptr::null_mut();
1362 }
1363
1364 if !parent.is_null() {
1365 add_child(parent, node);
1366 }
1367
1368 node
1369}
1370
1371pub unsafe fn new_text(content: *const xmlChar) -> *mut _xmlNode {
1390 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1391 if node.is_null() {
1392 return ptr::null_mut();
1393 }
1394
1395 unsafe {
1396 (*node).type_ = XML_TEXT_NODE as c_int;
1397 (*node).name = dup_xml_str(b"text\0" as *const u8 as *const xmlChar);
1398 (*node).content = if content.is_null() {
1399 let empty = allocator::xmlMallocImpl(1) as *mut xmlChar;
1400 if !empty.is_null() {
1401 *empty = 0;
1402 }
1403 empty
1404 } else {
1405 dup_xml_str(content)
1406 };
1407 (*node).line = 0;
1408 }
1409
1410 crate::abi::data_globals::register_node_hook(node);
1413
1414 node
1415}
1416
1417pub unsafe fn new_comment(content: *const xmlChar) -> *mut _xmlNode {
1431 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1432 if node.is_null() {
1433 return ptr::null_mut();
1434 }
1435
1436 unsafe {
1437 (*node).type_ = XML_COMMENT_NODE as c_int;
1438 (*node).name = dup_xml_str(b"comment\0" as *const u8 as *const xmlChar);
1439 (*node).content = dup_xml_str(content);
1440 (*node).line = 0;
1441 }
1442
1443 crate::abi::data_globals::register_node_hook(node);
1446
1447 node
1448}
1449
1450pub unsafe fn new_pi(name: *const xmlChar, content: *const xmlChar) -> *mut _xmlNode {
1465 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1466 if node.is_null() {
1467 return ptr::null_mut();
1468 }
1469
1470 unsafe {
1471 (*node).type_ = XML_PI_NODE as c_int;
1472 (*node).name = dup_xml_str(name);
1473 (*node).content = dup_xml_str(content);
1474 (*node).line = 0;
1475 }
1476
1477 crate::abi::data_globals::register_node_hook(node);
1480
1481 node
1482}
1483
1484pub unsafe fn new_cdata_block(
1500 doc: *mut _xmlDoc,
1501 content: *const xmlChar,
1502 len: c_int,
1503) -> *mut _xmlNode {
1504 let node = allocator::xmlMallocZero(size_of::<_xmlNode>() as usize) as *mut _xmlNode;
1505 if node.is_null() {
1506 return ptr::null_mut();
1507 }
1508
1509 unsafe {
1510 (*node).type_ = XML_CDATA_SECTION_NODE as c_int;
1511 (*node).doc = doc;
1514
1515 if !content.is_null() && len > 0 {
1516 (*node).content = allocator::xmlMallocImpl((len + 1) as usize) as *mut xmlChar;
1517 if !(*node).content.is_null() {
1518 ptr::copy_nonoverlapping(content, (*node).content, len as usize);
1519 *((*node).content.add(len as usize)) = 0;
1520 }
1521 } else {
1522 let empty = allocator::xmlMallocImpl(1) as *mut xmlChar;
1523 if !empty.is_null() {
1524 *empty = 0;
1525 }
1526 (*node).content = empty;
1527 }
1528
1529 (*node).line = 0;
1530 }
1531
1532 node
1533}
1534
1535pub unsafe fn new_ns(
1559 node: *mut _xmlNode,
1560 href: *const xmlChar,
1561 prefix: *const xmlChar,
1562) -> *mut _xmlNs {
1563 let ns = allocator::xmlMallocZero(size_of::<_xmlNs>() as usize) as *mut _xmlNs;
1564 if ns.is_null() {
1565 return ptr::null_mut();
1566 }
1567
1568 unsafe {
1569 (*ns).type_ = XML_LOCAL_NAMESPACE as c_int;
1570 (*ns).href = dup_xml_str(href);
1571 (*ns).prefix = dup_xml_str(prefix);
1572 (*ns).context = node as *mut _xmlDoc;
1573
1574 if !node.is_null() {
1576 let n = &mut *node;
1577 if n.nsDef.is_null() {
1578 n.nsDef = ns;
1579 } else {
1580 let mut last = n.nsDef;
1582 while !(*last).next.is_null() {
1583 last = (*last).next;
1584 }
1585 (*last).next = ns;
1586 }
1587 }
1588 }
1589
1590 ns
1591}
1592
1593pub unsafe fn set_ns(node: *mut _xmlNode, ns: *mut _xmlNs) {
1606 if node.is_null() {
1607 return;
1608 }
1609 unsafe {
1610 (*node).ns = ns;
1611 }
1612}
1613
1614pub unsafe fn get_ns_list(doc: *mut _xmlDoc, node: *mut _xmlNode) -> *mut *mut _xmlNs {
1630 if node.is_null() {
1634 return ptr::null_mut();
1635 }
1636
1637 let mut ns_ptrs: Vec<*mut _xmlNs> = Vec::new();
1639 let mut cur = node;
1640
1641 while !cur.is_null() {
1642 let n = unsafe { &*cur };
1643 let mut ns_def = n.nsDef;
1644 while !ns_def.is_null() {
1645 let ns = unsafe { &*ns_def };
1647 let mut found = false;
1648 for &existing in &ns_ptrs {
1649 if existing == ns_def {
1650 found = true;
1651 break;
1652 }
1653 let e = unsafe { &*existing };
1654 if !ns.href.is_null() && !e.href.is_null() {
1655 let href_match =
1656 unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, e.href) != 0 };
1657 if href_match {
1658 if ns.prefix.is_null() && e.prefix.is_null() {
1659 found = true;
1660 break;
1661 }
1662 if !ns.prefix.is_null() && !e.prefix.is_null() {
1663 let prefix_match = unsafe {
1664 crate::abi::exports_xml2::xmlStrEqual(ns.prefix, e.prefix) != 0
1665 };
1666 if prefix_match {
1667 found = true;
1668 break;
1669 }
1670 }
1671 }
1672 }
1673 }
1674 if !found {
1675 ns_ptrs.push(ns_def);
1676 }
1677 ns_def = unsafe { (*ns_def).next };
1678 }
1679 cur = n.parent;
1680 }
1681
1682 if ns_ptrs.is_empty() {
1683 return ptr::null_mut();
1684 }
1685
1686 let arr = allocator::xmlMallocImpl((ns_ptrs.len() + 1) * size_of::<*mut _xmlNs>())
1688 as *mut *mut _xmlNs;
1689 if arr.is_null() {
1690 return ptr::null_mut();
1691 }
1692
1693 for (i, ns) in ns_ptrs.iter().enumerate() {
1694 unsafe { *arr.add(i) = *ns };
1695 }
1696 unsafe { *arr.add(ns_ptrs.len()) = ptr::null_mut() };
1697
1698 arr
1699}
1700
1701pub unsafe fn search_ns(
1718 doc: *mut _xmlDoc,
1719 node: *mut _xmlNode,
1720 name_space: *const xmlChar,
1721) -> *mut _xmlNs {
1722 if node.is_null() {
1723 return ptr::null_mut();
1724 }
1725
1726 let mut cur = node;
1727 while !cur.is_null() {
1728 let n = unsafe { &*cur };
1729 let mut ns_def = n.nsDef;
1730 while !ns_def.is_null() {
1731 let ns = unsafe { &*ns_def };
1732 let match_prefix = if name_space.is_null() {
1733 ns.prefix.is_null()
1735 } else {
1736 !ns.prefix.is_null()
1737 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.prefix, name_space) != 0 }
1738 };
1739 if match_prefix {
1740 return ns_def;
1741 }
1742 ns_def = unsafe { (*ns_def).next };
1743 }
1744 cur = n.parent;
1745 }
1746
1747 ptr::null_mut()
1748}
1749
1750pub unsafe fn search_ns_by_href(
1766 doc: *mut _xmlDoc,
1767 node: *mut _xmlNode,
1768 href: *const xmlChar,
1769) -> *mut _xmlNs {
1770 if node.is_null() || href.is_null() {
1771 return ptr::null_mut();
1772 }
1773
1774 let mut cur = node;
1775 while !cur.is_null() {
1776 let n = unsafe { &*cur };
1777 let mut ns_def = n.nsDef;
1778 while !ns_def.is_null() {
1779 let ns = unsafe { &*ns_def };
1780 if !ns.href.is_null()
1781 && unsafe { crate::abi::exports_xml2::xmlStrEqual(ns.href, href) != 0 }
1782 {
1783 return ns_def;
1784 }
1785 ns_def = unsafe { (*ns_def).next };
1786 }
1787 cur = n.parent;
1788 }
1789
1790 ptr::null_mut()
1791}
1792
1793pub unsafe fn set_prop(
1817 node: *mut _xmlNode,
1818 name: *const xmlChar,
1819 value: *const xmlChar,
1820) -> *mut _xmlAttr {
1821 if node.is_null() || name.is_null() {
1822 return ptr::null_mut();
1823 }
1824
1825 let n = unsafe { &mut *node };
1826
1827 let mut existing = n.properties;
1829 while !existing.is_null() {
1830 let attr = unsafe { &*existing };
1831 if !attr.name.is_null()
1832 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1833 {
1834 if !attr.children.is_null() {
1837 free_node_list(attr.children);
1838 let attr_mut = existing as *mut _xmlAttr;
1840 unsafe { (*attr_mut).children = ptr::null_mut() };
1841 unsafe { (*attr_mut).last = ptr::null_mut() };
1842 }
1843 if !value.is_null() {
1845 let text = new_text(value);
1846 if !text.is_null() {
1847 let attr_mut = existing as *mut _xmlAttr;
1848 unsafe {
1849 (*attr_mut).children = text;
1850 (*attr_mut).last = text;
1851 (*text).parent = existing as *mut _xmlNode;
1852 (*text).doc = n.doc;
1853 }
1854 }
1855 }
1856 return existing;
1857 }
1858 existing = unsafe { (*existing).next };
1859 }
1860
1861 let attr = allocator::xmlMallocZero(size_of::<_xmlAttr>() as usize) as *mut _xmlAttr;
1863 if attr.is_null() {
1864 return ptr::null_mut();
1865 }
1866
1867 unsafe {
1868 (*attr).type_ = XML_ATTRIBUTE_NODE as c_int;
1869 (*attr).name = dup_xml_str(name);
1870 (*attr).parent = node;
1871 (*attr).doc = n.doc;
1872 if !value.is_null() {
1877 let text = new_text(value);
1878 if !text.is_null() {
1879 (*attr).children = text;
1880 (*attr).last = text;
1881 (*text).parent = attr as *mut _xmlNode;
1882 (*text).doc = n.doc;
1883 }
1884 }
1885
1886 if n.properties.is_null() {
1888 n.properties = attr;
1889 } else {
1890 let mut last = n.properties;
1891 while !(*last).next.is_null() {
1892 last = (*last).next;
1893 }
1894 (*last).next = attr;
1895 (*attr).prev = last;
1896 }
1897 }
1898
1899 attr
1900}
1901
1902pub unsafe fn get_prop(node: *mut _xmlNode, name: *const xmlChar) -> *mut xmlChar {
1918 if node.is_null() || name.is_null() {
1919 return ptr::null_mut();
1920 }
1921
1922 let n = unsafe { &*node };
1923 let mut cur = n.properties;
1924
1925 while !cur.is_null() {
1926 let attr = unsafe { &*cur };
1927 if !attr.name.is_null()
1928 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
1929 {
1930 if !attr.children.is_null() {
1932 let text = unsafe { &*attr.children };
1933 if text.type_ == XML_TEXT_NODE as c_int && !text.content.is_null() {
1934 return dup_xml_str(text.content);
1935 }
1936 }
1937 return dup_xml_str(b"\0" as *const u8 as *const xmlChar);
1938 }
1939 cur = unsafe { (*cur).next };
1940 }
1941
1942 ptr::null_mut()
1943}
1944
1945pub unsafe fn get_ns_prop(
1961 node: *mut _xmlNode,
1962 name: *const xmlChar,
1963 _name_space: *const xmlChar,
1964) -> *mut xmlChar {
1965 get_prop(node, name)
1968}
1969
1970pub unsafe fn set_ns_prop(
1985 node: *mut _xmlNode,
1986 _ns: *mut _xmlNs,
1987 name: *const xmlChar,
1988 value: *const xmlChar,
1989) -> *mut _xmlAttr {
1990 set_prop(node, name, value)
1992}
1993
1994pub unsafe fn remove_prop(attr: *mut _xmlAttr) -> c_int {
2009 if attr.is_null() {
2010 return -1;
2011 }
2012
2013 let a = unsafe { &mut *attr };
2014
2015 let parent = a.parent;
2017 if !parent.is_null() {
2018 let p = unsafe { &mut *parent };
2019 if p.properties == attr {
2020 p.properties = a.next;
2021 }
2022 }
2023
2024 if !a.prev.is_null() {
2026 unsafe { (*a.prev).next = a.next };
2027 }
2028 if !a.next.is_null() {
2029 unsafe { (*a.next).prev = a.prev };
2030 }
2031
2032 if !a.children.is_null() {
2034 free_node_list(a.children);
2035 }
2036
2037 if !a.name.is_null() {
2039 allocator::xmlFreeImpl(a.name as *mut c_void);
2040 }
2041
2042 allocator::xmlFreeImpl(attr as *mut c_void);
2043 0
2044}
2045
2046pub unsafe fn has_prop(node: *mut _xmlNode, name: *const xmlChar) -> *mut _xmlAttr {
2054 if node.is_null() || name.is_null() {
2055 return ptr::null_mut();
2056 }
2057 let mut cur = unsafe { (*node).properties };
2058 while !cur.is_null() {
2059 let attr = unsafe { &*cur };
2060 if !attr.name.is_null()
2061 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
2062 && attr.ns.is_null()
2063 {
2064 return cur;
2065 }
2066 cur = unsafe { (*cur).next };
2067 }
2068 ptr::null_mut()
2069}
2070
2071pub unsafe fn has_ns_prop(
2081 node: *mut _xmlNode,
2082 name: *const xmlChar,
2083 name_space: *const xmlChar,
2084) -> *mut _xmlAttr {
2085 if node.is_null() || name.is_null() {
2086 return ptr::null_mut();
2087 }
2088 let mut cur = unsafe { (*node).properties };
2089 while !cur.is_null() {
2090 let attr = unsafe { &*cur };
2091 if !attr.name.is_null()
2092 && unsafe { crate::abi::exports_xml2::xmlStrEqual(attr.name, name) != 0 }
2093 {
2094 if name_space.is_null() {
2095 if attr.ns.is_null() {
2096 return cur;
2097 }
2098 } else if !attr.ns.is_null() && !(*attr.ns).href.is_null() {
2099 if unsafe {
2100 crate::abi::exports_xml2::xmlStrEqual((*attr.ns).href, name_space) != 0
2101 } {
2102 return cur;
2103 }
2104 }
2105 }
2106 cur = unsafe { (*cur).next };
2107 }
2108 ptr::null_mut()
2109}
2110
2111pub unsafe fn unset_prop(node: *mut _xmlNode, name: *const xmlChar) -> c_int {
2120 let attr = unsafe { has_prop(node, name) };
2121 if attr.is_null() {
2122 return -1;
2123 }
2124 unsafe { remove_prop(attr) }
2125}
2126
2127pub unsafe fn unset_ns_prop(
2135 node: *mut _xmlNode,
2136 name: *const xmlChar,
2137 name_space: *const xmlChar,
2138) -> c_int {
2139 let attr = unsafe { has_ns_prop(node, name, name_space) };
2140 if attr.is_null() {
2141 return -1;
2142 }
2143 unsafe { remove_prop(attr) }
2144}
2145
2146pub unsafe fn first_element_child(node: *mut _xmlNode) -> *mut _xmlNode {
2153 if node.is_null() {
2154 return ptr::null_mut();
2155 }
2156 let mut cur = unsafe { (*node).children };
2157 while !cur.is_null() {
2158 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2159 return cur;
2160 }
2161 cur = unsafe { (*cur).next };
2162 }
2163 ptr::null_mut()
2164}
2165
2166pub unsafe fn last_element_child(node: *mut _xmlNode) -> *mut _xmlNode {
2173 if node.is_null() {
2174 return ptr::null_mut();
2175 }
2176 let mut cur = unsafe { (*node).last };
2177 while !cur.is_null() {
2178 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2179 return cur;
2180 }
2181 cur = unsafe { (*cur).prev };
2182 }
2183 ptr::null_mut()
2184}
2185
2186pub unsafe fn next_element_sibling(node: *mut _xmlNode) -> *mut _xmlNode {
2193 if node.is_null() {
2194 return ptr::null_mut();
2195 }
2196 let mut cur = unsafe { (*node).next };
2197 while !cur.is_null() {
2198 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2199 return cur;
2200 }
2201 cur = unsafe { (*cur).next };
2202 }
2203 ptr::null_mut()
2204}
2205
2206pub unsafe fn previous_element_sibling(node: *mut _xmlNode) -> *mut _xmlNode {
2213 if node.is_null() {
2214 return ptr::null_mut();
2215 }
2216 let mut cur = unsafe { (*node).prev };
2217 while !cur.is_null() {
2218 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2219 return cur;
2220 }
2221 cur = unsafe { (*cur).prev };
2222 }
2223 ptr::null_mut()
2224}
2225
2226pub unsafe fn child_element_count(node: *mut _xmlNode) -> c_ulong {
2233 if node.is_null() {
2234 return 0;
2235 }
2236 let mut cur = unsafe { (*node).children };
2237 let mut count: c_ulong = 0;
2238 while !cur.is_null() {
2239 if unsafe { (*cur).type_ } == XML_ELEMENT_NODE as c_int {
2240 count += 1;
2241 }
2242 cur = unsafe { (*cur).next };
2243 }
2244 count
2245}
2246
2247pub unsafe fn text_concat(node: *mut _xmlNode, str: *const xmlChar, num: c_int) -> c_int {
2256 if node.is_null() || str.is_null() || num <= 0 {
2257 return -1;
2258 }
2259 let cur = unsafe { &mut *node };
2260 if cur.content.is_null() {
2261 let p = unsafe { allocator::xmlMallocImpl(num as usize + 1) as *mut xmlChar };
2262 if p.is_null() {
2263 return -1;
2264 }
2265 unsafe {
2266 ptr::copy_nonoverlapping(str, p, num as usize);
2267 *p.add(num as usize) = 0;
2268 }
2269 cur.content = p;
2270 return 0;
2271 }
2272 let old_len = unsafe { crate::xml::string::xml_strlen(cur.content) };
2273 let p = unsafe {
2274 allocator::xmlReallocImpl(cur.content as *mut c_void, old_len + num as usize + 1)
2275 as *mut xmlChar
2276 };
2277 if p.is_null() {
2278 return -1;
2279 }
2280 unsafe {
2281 ptr::copy_nonoverlapping(str, p.add(old_len), num as usize);
2282 *p.add(old_len + num as usize) = 0;
2283 }
2284 cur.content = p;
2285 0
2286}
2287
2288pub unsafe fn text_merge(text: *mut _xmlNode, ntext: *mut _xmlNode) -> *mut _xmlNode {
2296 if text.is_null() || ntext.is_null() {
2297 return ptr::null_mut();
2298 }
2299 if unsafe { (*ntext).content.is_null() } {
2300 unsafe { free_node(ntext) };
2301 return text;
2302 }
2303 let num = unsafe { crate::xml::string::xml_strlen((*ntext).content) };
2304 if unsafe { text_concat(text, (*ntext).content, num as c_int) } != 0 {
2305 return ptr::null_mut();
2306 }
2307 unsafe { free_node(ntext) };
2308 text
2309}
2310
2311pub fn get_int_subset(doc: *const _xmlDoc) -> *mut _xmlDtd {
2323 if doc.is_null() {
2324 return ptr::null_mut();
2325 }
2326 let d = unsafe { &*doc };
2327 d.intSubset
2328}
2329
2330pub unsafe fn new_dtd(
2347 doc: *mut _xmlDoc,
2348 name: *const xmlChar,
2349 ExternalID: *const xmlChar,
2350 SystemID: *const xmlChar,
2351) -> *mut _xmlDtd {
2352 let dtd = allocator::xmlMallocZero(size_of::<_xmlDtd>() as usize) as *mut _xmlDtd;
2353 if dtd.is_null() {
2354 return ptr::null_mut();
2355 }
2356
2357 unsafe {
2358 (*dtd).type_ = XML_DTD_NODE as c_int;
2359 (*dtd).name = dup_xml_str(name);
2360 (*dtd).ExternalID = dup_xml_str(ExternalID);
2361 (*dtd).SystemID = dup_xml_str(SystemID);
2362 (*dtd).parent = doc;
2363 (*dtd).doc = doc;
2364
2365 if !doc.is_null() {
2371 if (*doc).intSubset.is_null() {
2372 (*doc).intSubset = dtd;
2373 }
2374 }
2375 }
2376
2377 dtd
2378}
2379
2380unsafe fn free_dtd(dtd: *mut _xmlDtd) {
2386 if dtd.is_null() {
2387 return;
2388 }
2389
2390 let d = unsafe { &mut *dtd };
2391 let d = &mut *dtd;
2392
2393 if !d.children.is_null() {
2400 let mut c = d.children;
2401 while !c.is_null() {
2402 let next = (*c).next;
2403 let t = (*c).type_;
2404 if t != XML_ELEMENT_DECL as c_int
2405 && t != XML_ATTRIBUTE_DECL as c_int
2406 && t != XML_ENTITY_DECL as c_int
2407 {
2408 unlink_node_internal(c, ptr::null_mut());
2409 free_node(c);
2410 }
2411 c = next;
2412 }
2413 }
2414
2415 if !d.name.is_null() {
2417 allocator::xmlFreeImpl(d.name as *mut c_void);
2418 }
2419 if !d.ExternalID.is_null() {
2420 allocator::xmlFreeImpl(d.ExternalID as *mut c_void);
2421 }
2422 if !d.SystemID.is_null() {
2423 allocator::xmlFreeImpl(d.SystemID as *mut c_void);
2424 }
2425
2426 unsafe extern "C" fn free_notation_wrapper(payload: *mut c_void, _name: *mut u8) {
2428 crate::xml::dtd::free_notation(payload as *mut _xmlNotation);
2429 }
2430 unsafe extern "C" fn free_element_wrapper(payload: *mut c_void, _name: *mut u8) {
2431 crate::xml::dtd::free_element(payload as *mut _xmlElement);
2432 }
2433 unsafe extern "C" fn free_attribute_wrapper(payload: *mut c_void, _name: *mut u8) {
2434 crate::xml::dtd::free_attribute(payload as *mut _xmlAttribute);
2435 }
2436 unsafe extern "C" fn free_entity_wrapper(payload: *mut c_void, _name: *mut u8) {
2437 crate::xml::entities::free_entity(payload as *mut _xmlEntity);
2438 }
2439
2440 if !d.notations.is_null() {
2441 crate::xml::hash::hash_free(
2442 d.notations as *mut crate::xml::hash::HashTable,
2443 Some(free_notation_wrapper),
2444 );
2445 d.notations = ptr::null_mut();
2446 }
2447 if !d.elements.is_null() {
2448 crate::xml::hash::hash_free(
2449 d.elements as *mut crate::xml::hash::HashTable,
2450 Some(free_element_wrapper),
2451 );
2452 d.elements = ptr::null_mut();
2453 }
2454 if !d.attributes.is_null() {
2455 crate::xml::hash::hash_free(
2456 d.attributes as *mut crate::xml::hash::HashTable,
2457 Some(free_attribute_wrapper),
2458 );
2459 d.attributes = ptr::null_mut();
2460 }
2461 if !d.entities.is_null() {
2462 crate::xml::hash::hash_free(
2463 d.entities as *mut crate::xml::hash::HashTable,
2464 Some(free_entity_wrapper),
2465 );
2466 d.entities = ptr::null_mut();
2467 }
2468 if !d.pentities.is_null() {
2469 crate::xml::hash::hash_free(
2470 d.pentities as *mut crate::xml::hash::HashTable,
2471 Some(free_entity_wrapper),
2472 );
2473 d.pentities = ptr::null_mut();
2474 }
2475
2476 allocator::xmlFreeImpl(dtd as *mut c_void);
2477}
2478
2479pub unsafe fn new_entity(
2499 _doc: *mut _xmlDoc,
2500 name: *const xmlChar,
2501 etype: c_int,
2502 ExternalID: *const xmlChar,
2503 SystemID: *const xmlChar,
2504 content: *const xmlChar,
2505) -> *mut _xmlEntity {
2506 let entity = allocator::xmlMallocZero(size_of::<_xmlEntity>() as usize) as *mut _xmlEntity;
2507 if entity.is_null() {
2508 return ptr::null_mut();
2509 }
2510
2511 unsafe {
2512 (*entity).type_ = XML_ENTITY_DECL as c_int;
2513 (*entity).name = dup_xml_str(name);
2514 (*entity).etype = etype;
2515 (*entity).ExternalID = dup_xml_str(ExternalID);
2516 (*entity).SystemID = dup_xml_str(SystemID);
2517 (*entity).content = dup_xml_str(content);
2518 (*entity).length = if content.is_null() {
2519 0
2520 } else {
2521 crate::abi::exports_xml2::xmlStrlen(content)
2522 };
2523 (*entity).flags = 0;
2524 (*entity).expandedSize = 0;
2525 }
2526
2527 entity
2528}
2529
2530pub unsafe fn get_doc_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2545 crate::xml::entities::get_entity(doc as *mut _xmlDoc, name)
2546}
2547
2548pub unsafe fn add_doc_entity(
2556 doc: *mut _xmlDoc,
2557 name: *const xmlChar,
2558 etype: c_int,
2559 ExternalID: *const xmlChar,
2560 SystemID: *const xmlChar,
2561 content: *const xmlChar,
2562) -> *mut _xmlEntity {
2563 if doc.is_null() || name.is_null() {
2564 return ptr::null_mut();
2565 }
2566 unsafe {
2567 let mut dtd = (*doc).intSubset;
2568 if dtd.is_null() {
2569 dtd = new_dtd(
2570 doc,
2571 b"internal\0".as_ptr() as *const xmlChar,
2572 ptr::null(),
2573 ptr::null(),
2574 );
2575 if dtd.is_null() {
2576 return ptr::null_mut();
2577 }
2578 }
2579 crate::xml::entities::add_entity(dtd, name, etype, ExternalID, SystemID, content)
2580 }
2581}
2582
2583pub unsafe fn add_dtd_entity(
2591 doc: *mut _xmlDoc,
2592 name: *const xmlChar,
2593 etype: c_int,
2594 ExternalID: *const xmlChar,
2595 SystemID: *const xmlChar,
2596 content: *const xmlChar,
2597) -> *mut _xmlEntity {
2598 if doc.is_null() || name.is_null() {
2599 return ptr::null_mut();
2600 }
2601 unsafe {
2602 let mut dtd = (*doc).extSubset;
2603 if dtd.is_null() {
2604 dtd = new_dtd(
2605 doc,
2606 b"internal\0".as_ptr() as *const xmlChar,
2607 ptr::null(),
2608 ptr::null(),
2609 );
2610 if dtd.is_null() {
2611 return ptr::null_mut();
2612 }
2613 (*doc).extSubset = dtd;
2614 }
2615 crate::xml::entities::add_entity(dtd, name, etype, ExternalID, SystemID, content)
2616 }
2617}
2618
2619pub unsafe fn get_dtd_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2627 if doc.is_null() || name.is_null() {
2628 return ptr::null_mut();
2629 }
2630 unsafe {
2631 if !(*doc).intSubset.is_null() {
2632 let e = crate::xml::entities::get_entity_from_dtd((*doc).intSubset, name);
2633 if !e.is_null() {
2634 return e;
2635 }
2636 }
2637 if !(*doc).extSubset.is_null() {
2638 return crate::xml::entities::get_entity_from_dtd((*doc).extSubset, name);
2639 }
2640 ptr::null_mut()
2641 }
2642}
2643
2644pub unsafe fn get_parameter_entity(doc: *const _xmlDoc, name: *const xmlChar) -> *mut _xmlEntity {
2657 crate::xml::entities::get_parameter_entity(doc as *mut _xmlDoc, name)
2658}
2659
2660const ENTITY_LT: &[xmlChar] = b"<";
2669const ENTITY_GT: &[xmlChar] = b">";
2670const ENTITY_AMP: &[xmlChar] = b"&";
2671const ENTITY_QUOT: &[xmlChar] = b""";
2672const ENTITY_APOS: &[xmlChar] = b"'";
2673
2674const INDENT: &[xmlChar] = b" ";
2676
2677const MAX_INDENT: c_int = 60;
2679
2680pub(crate) unsafe fn serialize_text(buf: *mut _xmlBuffer, content: *const xmlChar, len: c_int) {
2695 if buf.is_null() || content.is_null() || len <= 0 {
2696 return;
2697 }
2698
2699 let mut i: c_int = 0;
2700 while i < len {
2701 let ch = unsafe { *content.add(i as usize) };
2702
2703 if ch == b']'
2705 && i + 2 < len
2706 && unsafe { *content.add(i as usize + 1) == b']' }
2707 && unsafe { *content.add(i as usize + 2) == b'>' }
2708 {
2709 io::buf_add(buf, &ch as *const u8, 2); io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2712 i += 3;
2713 continue;
2714 }
2715
2716 match ch {
2717 b'<' => {
2718 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
2719 }
2720 b'&' => {
2721 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
2722 }
2723 b'>' => {
2724 io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2728 }
2729 b'\r' => {
2730 io::buf_add(buf, b" " as *const u8, 5);
2732 }
2733 0x01..=0x08 | 0x0B | 0x0C | 0x0E..=0x1F => {
2734 let hex = format!("&#x{:X};", ch);
2736 io::buf_add(buf, hex.as_ptr(), hex.len() as c_int);
2737 }
2738 _ => {
2739 io::buf_add(buf, &ch as *const u8, 1);
2740 }
2741 }
2742 i += 1;
2743 }
2744}
2745
2746pub(crate) unsafe fn serialize_attr_value(buf: *mut _xmlBuffer, value: *const xmlChar) {
2759 if buf.is_null() || value.is_null() {
2760 return;
2761 }
2762
2763 let len = xml_strlen(value);
2764 let mut i: c_int = 0;
2765 while i < len {
2766 let ch = unsafe { *value.add(i as usize) };
2767
2768 match ch {
2769 b'\n' => {
2770 io::buf_add(buf, b" " as *const u8, 5);
2771 }
2772 b'\r' => {
2773 io::buf_add(buf, b" " as *const u8, 5);
2774 }
2775 b'\t' => {
2776 io::buf_add(buf, b"	" as *const u8, 4);
2777 }
2778 b'<' => {
2779 io::buf_add(buf, ENTITY_LT.as_ptr(), ENTITY_LT.len() as c_int);
2780 }
2781 b'&' => {
2782 io::buf_add(buf, ENTITY_AMP.as_ptr(), ENTITY_AMP.len() as c_int);
2783 }
2784 b'"' => {
2785 io::buf_add(buf, ENTITY_QUOT.as_ptr(), ENTITY_QUOT.len() as c_int);
2786 }
2787 b'>' => {
2788 io::buf_add(buf, ENTITY_GT.as_ptr(), ENTITY_GT.len() as c_int);
2789 }
2790 _ => {
2791 io::buf_add(buf, &ch as *const u8, 1);
2792 }
2793 }
2794 i += 1;
2795 }
2796}
2797
2798unsafe fn write_indent(
2810 buf: *mut _xmlBuffer,
2811 level: c_int,
2812 indent: *const xmlChar,
2813 indent_len: c_int,
2814) {
2815 if buf.is_null() || level <= 0 || indent.is_null() || indent_len <= 0 {
2816 return;
2817 }
2818 let indent_nr = MAX_INDENT / indent_len;
2819 let mut lvl = level;
2820 if lvl > indent_nr {
2821 lvl = indent_nr;
2822 }
2823 for _ in 0..lvl {
2824 io::buf_add(buf, indent, indent_len);
2825 }
2826}
2827
2828unsafe fn is_noenc_text(node: *mut _xmlNode) -> bool {
2836 if node.is_null() {
2837 return false;
2838 }
2839 let n = unsafe { &*node };
2840 if n.name.is_null() {
2841 return false;
2842 }
2843 c_str_eq_bytes(n.name, b"textnoenc")
2844}
2845
2846unsafe fn c_str_eq_bytes(s: *const xmlChar, b: &[u8]) -> bool {
2848 let mut i = 0usize;
2849 while i < b.len() {
2850 if unsafe { *s.add(i) } != b[i] {
2851 return false;
2852 }
2853 i += 1;
2854 }
2855 unsafe { *s.add(i) == 0 }
2856}
2857
2858#[derive(Clone, Copy)]
2861struct DumpState {
2862 format: c_int,
2864 saved: c_int,
2867 unformatted: *mut _xmlNode,
2870 indent: *const xmlChar,
2873 indent_len: c_int,
2875 no_decl: c_int,
2877}
2878
2879impl DumpState {
2880 fn new(format: c_int) -> Self {
2881 let f = if format != 0 { 1 } else { 0 };
2882 DumpState {
2883 format: f,
2884 saved: f,
2885 unformatted: ptr::null_mut(),
2886 indent: INDENT.as_ptr(),
2887 indent_len: INDENT.len() as c_int,
2888 no_decl: 0,
2889 }
2890 }
2891
2892 unsafe fn with_indent(format: c_int, indent: *const xmlChar, no_decl: c_int) -> Self {
2900 let f = if format != 0 { 1 } else { 0 };
2901 let (ptr, len) = if indent.is_null() {
2902 (INDENT.as_ptr(), INDENT.len() as c_int)
2903 } else {
2904 let mut n = 0i32;
2905 while unsafe { *indent.add(n as usize) } != 0 {
2906 n += 1;
2907 }
2908 (indent, n)
2909 };
2910 DumpState {
2911 format: f,
2912 saved: f,
2913 unformatted: ptr::null_mut(),
2914 indent: ptr,
2915 indent_len: len,
2916 no_decl,
2917 }
2918 }
2919}
2920
2921unsafe fn write_qname(buf: *mut _xmlBuffer, node: *mut _xmlNode) {
2927 let n = unsafe { &*node };
2928 if !n.ns.is_null() {
2929 let ns = unsafe { &*n.ns };
2930 if !ns.prefix.is_null() {
2931 io::buf_cat(buf, ns.prefix);
2932 io::buf_ccat(buf, b':');
2933 }
2934 }
2935 if !n.name.is_null() {
2936 io::buf_cat(buf, n.name);
2937 }
2938}
2939
2940unsafe fn ns_dump_output(buf: *mut _xmlBuffer, cur: *mut _xmlNs) {
2946 if cur.is_null() || buf.is_null() {
2947 return;
2948 }
2949 let ns = unsafe { &*cur };
2950 if ns.type_ == XML_LOCAL_NAMESPACE as c_int && !ns.href.is_null() {
2951 if !ns.prefix.is_null() && c_str_eq_bytes(ns.prefix, b"xml") {
2953 return;
2954 }
2955 io::buf_ccat(buf, b' ');
2956 if !ns.prefix.is_null() {
2957 io::buf_add(buf, b"xmlns:" as *const u8, 6);
2958 io::buf_cat(buf, ns.prefix);
2959 } else {
2960 io::buf_add(buf, b"xmlns" as *const u8, 5);
2961 }
2962 io::buf_add(buf, b"=\"" as *const u8, 2);
2963 serialize_attr_value(buf, ns.href);
2964 io::buf_ccat(buf, b'"');
2965 }
2966}
2967
2968unsafe fn attr_dump_output(buf: *mut _xmlBuffer, cur: *mut _xmlAttr) {
2974 if cur.is_null() || buf.is_null() {
2975 return;
2976 }
2977 io::buf_ccat(buf, b' ');
2978 let a = unsafe { &*cur };
2979 if !a.ns.is_null() {
2980 let ans = unsafe { &*a.ns };
2981 if !ans.prefix.is_null() {
2982 io::buf_cat(buf, ans.prefix);
2983 io::buf_ccat(buf, b':');
2984 }
2985 }
2986 if !a.name.is_null() {
2987 io::buf_cat(buf, a.name);
2988 }
2989 io::buf_add(buf, b"=\"" as *const u8, 2);
2990 let mut child = a.children;
2993 while !child.is_null() {
2994 let ct = unsafe { (*child).type_ };
2995 if ct == XML_TEXT_NODE as c_int && !unsafe { (*child).content }.is_null() {
2996 serialize_attr_value(buf, unsafe { (*child).content });
2997 } else if ct == XML_ENTITY_REF_NODE as c_int && !unsafe { (*child).name }.is_null() {
2998 io::buf_ccat(buf, b'&');
2999 io::buf_cat(buf, unsafe { (*child).name });
3000 io::buf_ccat(buf, b';');
3001 }
3002 child = unsafe { (*child).next };
3003 }
3004 io::buf_ccat(buf, b'"');
3005}
3006
3007unsafe fn dump_notation_decl(buf: *mut _xmlBuffer, nota: *mut _xmlNotation) {
3013 let n = unsafe { &*nota };
3014 io::buf_add(buf, b"<!NOTATION " as *const u8, 11);
3015 if !n.name.is_null() {
3016 io::buf_cat(buf, n.name);
3017 }
3018 if !n.PublicID.is_null() {
3019 io::buf_add(buf, b" PUBLIC " as *const u8, 8);
3020 write_quoted_string(buf, n.PublicID);
3021 if !n.SystemID.is_null() {
3022 io::buf_ccat(buf, b' ');
3023 write_quoted_string(buf, n.SystemID);
3024 }
3025 } else {
3026 io::buf_add(buf, b" SYSTEM " as *const u8, 8);
3027 write_quoted_string(buf, n.SystemID);
3028 }
3029 io::buf_add(buf, b" >\n" as *const u8, 4);
3030}
3031
3032unsafe fn dump_element_occur(buf: *mut _xmlBuffer, ocur: c_int) {
3034 use crate::abi::types::xmlElementContentOccur::*;
3035 if ocur == XML_ELEMENT_CONTENT_OPT as c_int {
3036 io::buf_ccat(buf, b'?');
3037 } else if ocur == XML_ELEMENT_CONTENT_MULT as c_int {
3038 io::buf_ccat(buf, b'*');
3039 } else if ocur == XML_ELEMENT_CONTENT_PLUS as c_int {
3040 io::buf_ccat(buf, b'+');
3041 }
3042}
3043
3044unsafe fn dump_element_content(buf: *mut _xmlBuffer, content: *mut _xmlElementContent) {
3050 use crate::abi::types::xmlElementContentOccur::*;
3051 use crate::abi::types::xmlElementContentType::*;
3052 if content.is_null() {
3053 return;
3054 }
3055 io::buf_ccat(buf, b'(');
3056 let mut cur = content;
3057 loop {
3058 if cur.is_null() {
3059 return;
3060 }
3061 let c = unsafe { &*cur };
3062 match c.type_ {
3063 t if t == XML_ELEMENT_CONTENT_PCDATA as c_int => {
3064 io::buf_add(buf, b"#PCDATA" as *const u8, 7);
3065 }
3066 t if t == XML_ELEMENT_CONTENT_ELEMENT as c_int => {
3067 if !c.prefix.is_null() {
3068 io::buf_cat(buf, c.prefix);
3069 io::buf_ccat(buf, b':');
3070 }
3071 if !c.name.is_null() {
3072 io::buf_cat(buf, c.name);
3073 }
3074 }
3075 t if t == XML_ELEMENT_CONTENT_SEQ as c_int || t == XML_ELEMENT_CONTENT_OR as c_int => {
3076 if cur != content
3077 && !c.parent.is_null()
3078 && (c.type_ != unsafe { (*c.parent).type_ }
3079 || c.ocur != XML_ELEMENT_CONTENT_ONCE as c_int)
3080 {
3081 io::buf_ccat(buf, b'(');
3082 }
3083 cur = c.c1;
3084 continue;
3085 }
3086 _ => {}
3087 }
3088
3089 while cur != content {
3091 let ccur = unsafe { &*cur };
3092 let parent = ccur.parent;
3093 if parent.is_null() {
3094 return;
3095 }
3096 let p = unsafe { &*parent };
3097 if ((ccur.type_ == XML_ELEMENT_CONTENT_OR as c_int
3098 || ccur.type_ == XML_ELEMENT_CONTENT_SEQ as c_int)
3099 && (ccur.type_ != p.type_ || ccur.ocur != XML_ELEMENT_CONTENT_ONCE as c_int))
3100 {
3101 io::buf_ccat(buf, b')');
3102 }
3103 dump_element_occur(buf, ccur.ocur);
3104
3105 if ccur.type_ == XML_ELEMENT_CONTENT_SEQ as c_int {
3106 io::buf_add(buf, b" , " as *const u8, 3);
3107 } else if ccur.type_ == XML_ELEMENT_CONTENT_OR as c_int {
3108 io::buf_add(buf, b" | " as *const u8, 3);
3109 }
3110
3111 if cur == p.c1 {
3112 cur = p.c2;
3113 break;
3114 }
3115 cur = parent;
3116 }
3117 if cur == content {
3118 break;
3119 }
3120 }
3121 io::buf_ccat(buf, b')');
3122 let cc = unsafe { &*content };
3123 dump_element_occur(buf, cc.ocur);
3124}
3125
3126unsafe fn dump_element_decl(buf: *mut _xmlBuffer, elem: *mut _xmlElement) {
3132 use crate::abi::types::xmlElementTypeVal::*;
3133 let e = unsafe { &*elem };
3134 io::buf_add(buf, b"<!ELEMENT " as *const u8, 10);
3135 if !e.prefix.is_null() {
3136 io::buf_cat(buf, e.prefix);
3137 io::buf_ccat(buf, b':');
3138 }
3139 if !e.name.is_null() {
3140 io::buf_cat(buf, e.name);
3141 }
3142 io::buf_ccat(buf, b' ');
3143 match e.etype {
3144 t if t == XML_ELEMENT_TYPE_EMPTY as c_int => {
3145 io::buf_add(buf, b"EMPTY" as *const u8, 5);
3146 }
3147 t if t == XML_ELEMENT_TYPE_ANY as c_int => {
3148 io::buf_add(buf, b"ANY" as *const u8, 3);
3149 }
3150 t if t == XML_ELEMENT_TYPE_MIXED as c_int || t == XML_ELEMENT_TYPE_ELEMENT as c_int => {
3151 dump_element_content(buf, e.content);
3152 }
3153 _ => {}
3154 }
3155 io::buf_add(buf, b">\n" as *const u8, 2);
3156}
3157
3158unsafe fn dump_enumeration(buf: *mut _xmlBuffer, cur: *mut _xmlEnumeration) {
3164 let mut e = cur;
3165 while !e.is_null() {
3166 let en = unsafe { &*e };
3167 if !en.name.is_null() {
3168 io::buf_cat(buf, en.name);
3169 }
3170 if !en.next.is_null() {
3171 io::buf_add(buf, b" | " as *const u8, 3);
3172 }
3173 e = en.next;
3174 }
3175 io::buf_ccat(buf, b')');
3176}
3177
3178unsafe fn dump_attribute_decl(buf: *mut _xmlBuffer, attr: *mut _xmlAttribute) {
3184 use crate::abi::types::xmlAttributeDefault::*;
3185 use crate::abi::types::xmlAttributeType::*;
3186 let a = unsafe { &*attr };
3187 io::buf_add(buf, b"<!ATTLIST " as *const u8, 10);
3188 if !a.elem.is_null() {
3189 io::buf_cat(buf, a.elem);
3190 }
3191 io::buf_ccat(buf, b' ');
3192 if !a.prefix.is_null() {
3193 io::buf_cat(buf, a.prefix);
3194 io::buf_ccat(buf, b':');
3195 }
3196 if !a.name.is_null() {
3197 io::buf_cat(buf, a.name);
3198 }
3199 match a.atype {
3200 t if t == XML_ATTRIBUTE_CDATA as c_int => {
3201 io::buf_add(buf, b" CDATA" as *const u8, 6);
3202 }
3203 t if t == XML_ATTRIBUTE_ID as c_int => {
3204 io::buf_add(buf, b" ID" as *const u8, 3);
3205 }
3206 t if t == XML_ATTRIBUTE_IDREF as c_int => {
3207 io::buf_add(buf, b" IDREF" as *const u8, 6);
3208 }
3209 t if t == XML_ATTRIBUTE_IDREFS as c_int => {
3210 io::buf_add(buf, b" IDREFS" as *const u8, 7);
3211 }
3212 t if t == XML_ATTRIBUTE_ENTITY as c_int => {
3213 io::buf_add(buf, b" ENTITY" as *const u8, 7);
3214 }
3215 t if t == XML_ATTRIBUTE_ENTITIES as c_int => {
3216 io::buf_add(buf, b" ENTITIES" as *const u8, 9);
3217 }
3218 t if t == XML_ATTRIBUTE_NMTOKEN as c_int => {
3219 io::buf_add(buf, b" NMTOKEN" as *const u8, 8);
3220 }
3221 t if t == XML_ATTRIBUTE_NMTOKENS as c_int => {
3222 io::buf_add(buf, b" NMTOKENS" as *const u8, 9);
3223 }
3224 t if t == XML_ATTRIBUTE_ENUMERATION as c_int => {
3225 io::buf_add(buf, b" (" as *const u8, 2);
3226 dump_enumeration(buf, a.tree);
3227 }
3228 t if t == XML_ATTRIBUTE_NOTATION as c_int => {
3229 io::buf_add(buf, b" NOTATION (" as *const u8, 11);
3230 dump_enumeration(buf, a.tree);
3231 }
3232 _ => {}
3233 }
3234 match a.def {
3235 t if t == XML_ATTRIBUTE_REQUIRED as c_int => {
3236 io::buf_add(buf, b" #REQUIRED" as *const u8, 10);
3237 }
3238 t if t == XML_ATTRIBUTE_IMPLIED as c_int => {
3239 io::buf_add(buf, b" #IMPLIED" as *const u8, 9);
3240 }
3241 t if t == XML_ATTRIBUTE_FIXED as c_int => {
3242 io::buf_add(buf, b" #FIXED" as *const u8, 7);
3243 }
3244 _ => {}
3245 }
3246 if !a.defaultValue.is_null() {
3247 io::buf_add(buf, b" \"" as *const u8, 2);
3248 serialize_attr_value(buf, a.defaultValue);
3249 io::buf_ccat(buf, b'"');
3250 }
3251 io::buf_add(buf, b">\n" as *const u8, 2);
3252}
3253
3254unsafe fn write_quoted_string(buf: *mut _xmlBuffer, str: *const xmlChar) {
3260 if buf.is_null() {
3261 return;
3262 }
3263 io::buf_ccat(buf, b'"');
3264 if !str.is_null() {
3265 let mut i = 0usize;
3266 while unsafe { *str.add(i) != 0 } {
3267 let ch = unsafe { *str.add(i) };
3268 if ch == b'"' {
3269 io::buf_add(buf, b""" as *const u8, 6);
3270 } else {
3271 io::buf_add(buf, &ch as *const u8, 1);
3272 }
3273 i += 1;
3274 }
3275 }
3276 io::buf_ccat(buf, b'"');
3277}
3278
3279unsafe fn dump_entity_decl(buf: *mut _xmlBuffer, ent: *mut _xmlEntity) {
3285 use crate::abi::types::xmlEntityType::*;
3286 let e = unsafe { &*ent };
3287 if e.etype == XML_INTERNAL_PARAMETER_ENTITY as c_int
3288 || e.etype == XML_EXTERNAL_PARAMETER_ENTITY as c_int
3289 {
3290 io::buf_add(buf, b"<!ENTITY % " as *const u8, 11);
3291 } else {
3292 io::buf_add(buf, b"<!ENTITY " as *const u8, 9);
3293 }
3294 if !e.name.is_null() {
3295 io::buf_cat(buf, e.name);
3296 }
3297 io::buf_ccat(buf, b' ');
3298
3299 if e.etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY as c_int
3300 || e.etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int
3301 || e.etype == XML_EXTERNAL_PARAMETER_ENTITY as c_int
3302 {
3303 if !e.ExternalID.is_null() {
3304 io::buf_add(buf, b"PUBLIC " as *const u8, 7);
3305 write_quoted_string(buf, e.ExternalID);
3306 io::buf_ccat(buf, b' ');
3307 } else {
3308 io::buf_add(buf, b"SYSTEM " as *const u8, 7);
3309 }
3310 write_quoted_string(buf, e.SystemID);
3311 }
3312
3313 if e.etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY as c_int {
3314 if !e.content.is_null() {
3315 io::buf_add(buf, b" NDATA " as *const u8, 7);
3316 if !e.orig.is_null() {
3317 io::buf_cat(buf, e.orig);
3318 } else if !e.content.is_null() {
3319 io::buf_cat(buf, e.content);
3320 }
3321 }
3322 }
3323
3324 if e.etype == XML_INTERNAL_GENERAL_ENTITY as c_int
3325 || e.etype == XML_INTERNAL_PARAMETER_ENTITY as c_int
3326 {
3327 if !e.orig.is_null() {
3328 write_quoted_string(buf, e.orig);
3329 } else {
3330 io::buf_ccat(buf, b'"');
3332 if !e.content.is_null() {
3333 let mut i = 0usize;
3334 while unsafe { *e.content.add(i) != 0 } {
3335 let ch = unsafe { *e.content.add(i) };
3336 match ch {
3337 b'"' => io::buf_add(buf, b""" as *const u8, 6),
3338 b'%' => io::buf_add(buf, b"%" as *const u8, 6),
3339 _ => io::buf_add(buf, &ch as *const u8, 1),
3340 };
3341 i += 1;
3342 }
3343 }
3344 io::buf_ccat(buf, b'"');
3345 }
3346 }
3347 io::buf_add(buf, b">\n" as *const u8, 2);
3348}
3349
3350unsafe fn dtd_dump_output(
3356 buf: *mut _xmlBuffer,
3357 cur: *mut _xmlNode,
3358 state: &mut DumpState,
3359 level: &mut c_int,
3360) {
3361 let dtd = cur as *mut _xmlDtd;
3362 let d = unsafe { &*dtd };
3363 io::buf_add(buf, b"<!DOCTYPE " as *const u8, 10);
3364 if !d.name.is_null() {
3365 io::buf_cat(buf, d.name);
3366 }
3367 if !d.ExternalID.is_null() {
3368 io::buf_add(buf, b" PUBLIC " as *const u8, 8);
3369 write_quoted_string(buf, d.ExternalID);
3370 io::buf_ccat(buf, b' ');
3371 write_quoted_string(buf, d.SystemID);
3372 } else if !d.SystemID.is_null() {
3373 io::buf_add(buf, b" SYSTEM " as *const u8, 8);
3374 write_quoted_string(buf, d.SystemID);
3375 }
3376 if crate::xml::hash::hash_size(d.entities as *mut crate::xml::hash::HashTable) == 0
3377 && crate::xml::hash::hash_size(d.elements as *mut crate::xml::hash::HashTable) == 0
3378 && crate::xml::hash::hash_size(d.attributes as *mut crate::xml::hash::HashTable) == 0
3379 && crate::xml::hash::hash_size(d.notations as *mut crate::xml::hash::HashTable) == 0
3380 && crate::xml::hash::hash_size(d.pentities as *mut crate::xml::hash::HashTable) == 0
3381 {
3382 io::buf_ccat(buf, b'>');
3383 return;
3384 }
3385 io::buf_add(buf, b" [\n" as *const u8, 3);
3386 let format = state.format;
3392 let lvl = *level;
3393 state.format = 0;
3394 *level = -1;
3395 if !d.notations.is_null() {
3396 crate::xml::hash::hash_scan(
3397 d.notations as *mut crate::xml::hash::HashTable,
3398 Some(dump_notation_decl_cb),
3399 buf as *mut c_void,
3400 );
3401 }
3402 if !d.elements.is_null() {
3403 crate::xml::hash::hash_scan(
3404 d.elements as *mut crate::xml::hash::HashTable,
3405 Some(dump_element_decl_cb),
3406 buf as *mut c_void,
3407 );
3408 }
3409 if !d.attributes.is_null() {
3410 crate::xml::hash::hash_scan(
3411 d.attributes as *mut crate::xml::hash::HashTable,
3412 Some(dump_attribute_decl_cb),
3413 buf as *mut c_void,
3414 );
3415 }
3416 if !d.entities.is_null() {
3417 crate::xml::hash::hash_scan(
3418 d.entities as *mut crate::xml::hash::HashTable,
3419 Some(dump_entity_decl_cb),
3420 buf as *mut c_void,
3421 );
3422 }
3423 if !d.pentities.is_null() {
3424 crate::xml::hash::hash_scan(
3425 d.pentities as *mut crate::xml::hash::HashTable,
3426 Some(dump_entity_decl_cb),
3427 buf as *mut c_void,
3428 );
3429 }
3430 state.format = format;
3431 *level = lvl;
3432 io::buf_add(buf, b"]>" as *const u8, 2);
3433}
3434
3435unsafe extern "C" fn dump_notation_decl_cb(
3437 payload: *mut c_void,
3438 data: *mut c_void,
3439 _name: *const crate::abi::types::xmlChar,
3440) {
3441 if !payload.is_null() && !data.is_null() {
3442 dump_notation_decl(data as *mut _xmlBuffer, payload as *mut _xmlNotation);
3443 }
3444}
3445
3446unsafe extern "C" fn dump_element_decl_cb(
3448 payload: *mut c_void,
3449 data: *mut c_void,
3450 _name: *const crate::abi::types::xmlChar,
3451) {
3452 if !payload.is_null() && !data.is_null() {
3453 dump_element_decl(data as *mut _xmlBuffer, payload as *mut _xmlElement);
3454 }
3455}
3456
3457unsafe extern "C" fn dump_attribute_decl_cb(
3459 payload: *mut c_void,
3460 data: *mut c_void,
3461 _name: *const crate::abi::types::xmlChar,
3462) {
3463 if !payload.is_null() && !data.is_null() {
3464 dump_attribute_decl(data as *mut _xmlBuffer, payload as *mut _xmlAttribute);
3465 }
3466}
3467
3468unsafe extern "C" fn dump_entity_decl_cb(
3470 payload: *mut c_void,
3471 data: *mut c_void,
3472 _name: *const crate::abi::types::xmlChar,
3473) {
3474 if !payload.is_null() && !data.is_null() {
3475 dump_entity_decl(data as *mut _xmlBuffer, payload as *mut _xmlEntity);
3476 }
3477}
3478
3479unsafe fn doc_content_dump_output(
3488 buf: *mut _xmlBuffer,
3489 cur: *mut _xmlNode,
3490 state: &mut DumpState,
3491 level: &mut c_int,
3492) {
3493 let doc = cur as *mut _xmlDoc;
3494 let d = unsafe { &*doc };
3495
3496 if state.no_decl == 0 {
3500 io::buf_add(buf, b"<?xml version=\"" as *const u8, 15);
3501 if !d.version.is_null() {
3502 io::buf_cat(buf, d.version);
3503 } else {
3504 io::buf_add(buf, b"1.0" as *const u8, 3);
3505 }
3506 io::buf_ccat(buf, b'"');
3507 if !d.encoding.is_null() {
3508 io::buf_add(buf, b" encoding=\"" as *const u8, 11);
3509 io::buf_cat(buf, d.encoding);
3510 io::buf_ccat(buf, b'"');
3511 }
3512 match d.standalone {
3513 0 => {
3514 io::buf_add(buf, b" standalone=\"no\"" as *const u8, 16);
3515 }
3516 1 => {
3517 io::buf_add(buf, b" standalone=\"yes\"" as *const u8, 17);
3518 }
3519 _ => {}
3520 }
3521 io::buf_add(buf, b"?>\n" as *const u8, 3);
3522 }
3523
3524 if !d.intSubset.is_null() {
3527 let mut lvl = 0;
3528 dtd_dump_output(buf, d.intSubset as *mut _xmlNode, state, &mut lvl);
3529 io::buf_ccat(buf, b'\n');
3530 }
3531
3532 if !d.children.is_null() {
3533 let mut child = d.children;
3534 while !child.is_null() {
3535 *level = 0;
3536 node_dump_internal(buf, child, child, cur, state, level);
3537 let ct = unsafe { (*child).type_ };
3538 if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
3539 io::buf_ccat(buf, b'\n');
3540 }
3541 child = unsafe { (*child).next };
3542 }
3543 }
3544}
3545
3546unsafe fn node_dump_internal(
3570 buf: *mut _xmlBuffer,
3571 cur: *mut _xmlNode,
3572 root: *mut _xmlNode,
3573 parent: *mut _xmlNode,
3574 state: &mut DumpState,
3575 level: &mut c_int,
3576) {
3577 if cur.is_null() || buf.is_null() {
3578 return;
3579 }
3580 let n = unsafe { &*cur };
3581 match n.type_ {
3582 t if t == XML_ELEMENT_NODE as c_int => {
3583 if cur != root && state.format == 1 {
3584 write_indent(buf, *level, state.indent, state.indent_len);
3585 }
3586 if !n.parent.is_null() && n.parent != parent && !n.children.is_null() {
3589 let mut sub = DumpState::new(state.format);
3590 let mut sub_level = *level;
3591 node_dump_internal(buf, cur, cur, n.parent, &mut sub, &mut sub_level);
3592 return;
3593 }
3594 io::buf_ccat(buf, b'<');
3596 write_qname(buf, cur);
3597 let mut nsdef = n.nsDef;
3598 while !nsdef.is_null() {
3599 ns_dump_output(buf, nsdef);
3600 nsdef = unsafe { (*nsdef).next };
3601 }
3602 let mut attr = n.properties;
3603 while !attr.is_null() {
3604 attr_dump_output(buf, attr);
3605 attr = unsafe { (*attr).next };
3606 }
3607 if n.children.is_null() {
3608 io::buf_add(buf, b"/>" as *const u8, 2);
3609 } else {
3610 if state.format == 1 {
3611 let mut tmp = n.children;
3614 while !tmp.is_null() {
3615 let tt = unsafe { (*tmp).type_ };
3616 if tt == XML_TEXT_NODE as c_int
3617 || tt == XML_CDATA_SECTION_NODE as c_int
3618 || tt == XML_ENTITY_REF_NODE as c_int
3619 {
3620 state.format = 0;
3621 state.unformatted = cur;
3622 break;
3623 }
3624 tmp = unsafe { (*tmp).next };
3625 }
3626 }
3627 io::buf_ccat(buf, b'>');
3628 if state.format == 1 {
3629 io::buf_ccat(buf, b'\n');
3630 }
3631 if *level >= 0 {
3632 *level += 1;
3633 }
3634 let mut child = n.children;
3635 while !child.is_null() {
3636 node_dump_internal(buf, child, root, cur, state, level);
3637 if state.format == 1 {
3638 let ct = unsafe { (*child).type_ };
3639 if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
3640 io::buf_ccat(buf, b'\n');
3641 }
3642 }
3643 child = unsafe { (*child).next };
3644 }
3645 if *level > 0 {
3647 *level -= 1;
3648 }
3649 if state.format == 1 {
3650 write_indent(buf, *level, state.indent, state.indent_len);
3651 }
3652 io::buf_add(buf, b"</" as *const u8, 2);
3653 write_qname(buf, cur);
3654 io::buf_ccat(buf, b'>');
3655 if cur == state.unformatted {
3656 state.format = state.saved;
3657 state.unformatted = ptr::null_mut();
3658 }
3659 }
3660 }
3661 t if t == XML_TEXT_NODE as c_int => {
3662 if !n.content.is_null() {
3663 if is_noenc_text(cur) {
3664 io::buf_cat(buf, n.content);
3665 } else {
3666 serialize_text(buf, n.content, xml_strlen(n.content));
3667 }
3668 } else if !n.children.is_null() {
3669 let c = node_get_content(cur);
3672 if !c.is_null() {
3673 if is_noenc_text(cur) {
3674 io::buf_cat(buf, c);
3675 } else {
3676 serialize_text(buf, c, xml_strlen(c));
3677 }
3678 allocator::xmlFreeImpl(c as *mut c_void);
3679 }
3680 }
3681 }
3682 t if t == XML_CDATA_SECTION_NODE as c_int => {
3683 if n.content.is_null() || unsafe { *n.content == 0 } {
3684 io::buf_add(buf, b"<![CDATA[]]>" as *const u8, 12);
3685 } else {
3686 let len = xml_strlen(n.content) as usize;
3687 let bytes = core::slice::from_raw_parts(n.content, len);
3688 let mut i = 0usize;
3689 let mut seg_start = 0usize;
3690 while i < len {
3691 if bytes[i] == b']'
3692 && i + 2 < len
3693 && bytes[i + 1] == b']'
3694 && bytes[i + 2] == b'>'
3695 {
3696 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
3697 io::buf_add(buf, n.content.add(seg_start), (i + 2 - seg_start) as c_int);
3698 io::buf_add(buf, b"]]>" as *const u8, 3);
3699 seg_start = i + 2;
3700 i += 3;
3701 continue;
3702 }
3703 i += 1;
3704 }
3705 if seg_start < len {
3706 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
3707 io::buf_add(buf, n.content.add(seg_start), (len - seg_start) as c_int);
3708 io::buf_add(buf, b"]]>" as *const u8, 3);
3709 }
3710 }
3711 }
3712 t if t == XML_COMMENT_NODE as c_int => {
3713 if cur != root && state.format == 1 {
3714 write_indent(buf, *level, state.indent, state.indent_len);
3715 }
3716 if !n.content.is_null() {
3717 io::buf_add(buf, b"<!--" as *const u8, 4);
3718 io::buf_cat(buf, n.content);
3719 io::buf_add(buf, b"-->" as *const u8, 3);
3720 }
3721 }
3722 t if t == XML_PI_NODE as c_int => {
3723 if cur != root && state.format == 1 {
3724 write_indent(buf, *level, state.indent, state.indent_len);
3725 }
3726 io::buf_add(buf, b"<?" as *const u8, 2);
3727 if !n.name.is_null() {
3728 io::buf_cat(buf, n.name);
3729 }
3730 if !n.content.is_null() && unsafe { *n.content != 0 } {
3731 io::buf_ccat(buf, b' ');
3732 io::buf_cat(buf, n.content);
3733 }
3734 io::buf_add(buf, b"?>" as *const u8, 2);
3735 }
3736 t if t == XML_ENTITY_REF_NODE as c_int => {
3737 io::buf_ccat(buf, b'&');
3738 if !n.name.is_null() {
3739 io::buf_cat(buf, n.name);
3740 }
3741 io::buf_ccat(buf, b';');
3742 }
3743 t if t == XML_DOCUMENT_NODE as c_int => {
3744 doc_content_dump_output(buf, cur, state, level);
3745 }
3746 t if t == XML_HTML_DOCUMENT_NODE as c_int => {
3747 crate::xml::html::serialize_node(cur, buf, state.format, *level);
3749 }
3750 t if t == XML_DTD_NODE as c_int => {
3751 dtd_dump_output(buf, cur, state, level);
3752 }
3753 t if t == XML_ATTRIBUTE_NODE as c_int => {
3754 attr_dump_output(buf, cur as *mut _xmlAttr);
3755 }
3756 t if t == XML_NAMESPACE_DECL as c_int => {
3757 ns_dump_output(buf, cur as *mut _xmlNs);
3758 }
3759 t if t == XML_ELEMENT_DECL as c_int => {
3760 dump_element_decl(buf, cur as *mut _xmlElement);
3761 }
3762 t if t == XML_ATTRIBUTE_DECL as c_int => {
3763 dump_attribute_decl(buf, cur as *mut _xmlAttribute);
3764 }
3765 t if t == XML_ENTITY_DECL as c_int => {
3766 dump_entity_decl(buf, cur as *mut _xmlEntity);
3767 }
3768 _ => {}
3769 }
3770}
3771
3772pub(crate) unsafe fn serialize_node(
3786 node: *mut _xmlNode,
3787 buf: *mut _xmlBuffer,
3788 format: c_int,
3789 level: c_int,
3790) {
3791 unsafe { serialize_node_opt(node, buf, format, level, ptr::null()) };
3792}
3793
3794pub(crate) unsafe fn serialize_node_opt(
3802 node: *mut _xmlNode,
3803 buf: *mut _xmlBuffer,
3804 format: c_int,
3805 level: c_int,
3806 indent: *const xmlChar,
3807) {
3808 unsafe { serialize_node_opts(node, buf, format, level, indent, 0) };
3809}
3810
3811pub(crate) unsafe fn serialize_node_opts(
3818 node: *mut _xmlNode,
3819 buf: *mut _xmlBuffer,
3820 format: c_int,
3821 level: c_int,
3822 indent: *const xmlChar,
3823 no_decl: c_int,
3824) {
3825 if node.is_null() || buf.is_null() {
3826 return;
3827 }
3828 let parent = unsafe { (*node).parent };
3829 let mut state = DumpState::with_indent(format, indent, no_decl);
3830 let mut lvl = level;
3831 node_dump_internal(buf, node, node, parent, &mut state, &mut lvl);
3832}
3833
3834pub(crate) unsafe fn doc_dump(buf: *mut _xmlBuffer, doc: *mut _xmlDoc) -> c_int {
3844 if buf.is_null() || doc.is_null() {
3845 return -1;
3846 }
3847
3848 let before = io::buf_length(buf);
3849 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
3850 let after = io::buf_length(buf);
3851
3852 if after < 0 || before < 0 {
3853 return -1;
3854 }
3855 after - before
3856}
3857
3858pub(crate) unsafe fn node_dump(
3870 buf: *mut _xmlBuffer,
3871 doc: *mut _xmlDoc,
3872 node: *mut _xmlNode,
3873 level: c_int,
3874 format: c_int,
3875) -> c_int {
3876 let _ = doc; if buf.is_null() || node.is_null() {
3878 return -1;
3879 }
3880
3881 let before = io::buf_length(buf);
3882 serialize_node(node, buf, format, level);
3883 let after = io::buf_length(buf);
3884
3885 if after < 0 || before < 0 {
3886 return -1;
3887 }
3888 after - before
3889}
3890
3891pub(crate) unsafe fn save_doc_to_filename(
3898 doc: *mut _xmlDoc,
3899 filename: *const c_char,
3900 compression: c_int,
3901) -> c_int {
3902 if doc.is_null() || filename.is_null() {
3903 return -1;
3904 }
3905
3906 let out = io::output_buffer_create_filename(filename, ptr::null_mut(), compression);
3907 if out.is_null() {
3908 return -1;
3909 }
3910
3911 let buf = io::buf_create(-1);
3912 if buf.is_null() {
3913 io::output_buffer_close(out);
3914 return -1;
3915 }
3916
3917 let ret = doc_dump(buf, doc);
3918 if ret >= 0 {
3919 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
3921 io::output_buffer_flush(out);
3922 }
3923
3924 io::buf_free(buf);
3925 io::output_buffer_close(out);
3926 ret
3927}
3928
3929pub(crate) unsafe fn save_doc_to_fd(doc: *mut _xmlDoc, fd: c_int, compression: c_int) -> c_int {
3936 if doc.is_null() || fd < 0 {
3937 return -1;
3938 }
3939
3940 let out = io::output_buffer_create_fd(fd, ptr::null_mut());
3941 if out.is_null() {
3942 return -1;
3943 }
3944
3945 let buf = io::buf_create(-1);
3946 if buf.is_null() {
3947 io::output_buffer_close(out);
3948 return -1;
3949 }
3950
3951 let ret = doc_dump(buf, doc);
3952 if ret >= 0 {
3953 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
3954 io::output_buffer_flush(out);
3955 }
3956
3957 io::buf_free(buf);
3958 io::output_buffer_close(out);
3959 ret
3960}
3961
3962pub(crate) unsafe fn save_doc_to_buf(
3969 doc: *mut _xmlDoc,
3970 buf: *mut _xmlBuffer,
3971 compression: c_int,
3972) -> c_int {
3973 let _ = compression;
3974 if doc.is_null() || buf.is_null() {
3975 return -1;
3976 }
3977
3978 doc_dump(buf, doc)
3979}
3980
3981pub(crate) unsafe fn save_format_doc_to_buf(
3988 doc: *mut _xmlDoc,
3989 buf: *mut _xmlBuffer,
3990 compression: c_int,
3991) -> c_int {
3992 let _ = compression;
3993 if doc.is_null() || buf.is_null() {
3994 return -1;
3995 }
3996
3997 let before = io::buf_length(buf);
3998 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
3999 let after = io::buf_length(buf);
4000
4001 if after < 0 || before < 0 {
4002 return -1;
4003 }
4004 after - before
4005}
4006
4007pub(crate) unsafe fn dump_node(node: *mut _xmlNode) -> *mut xmlChar {
4016 if node.is_null() {
4017 return ptr::null_mut();
4018 }
4019
4020 let buf = io::buf_create(-1);
4021 if buf.is_null() {
4022 return ptr::null_mut();
4023 }
4024
4025 serialize_node(node, buf, 0, 0);
4026
4027 let content = io::buf_content(buf);
4028 if content.is_null() {
4029 io::buf_free(buf);
4030 return ptr::null_mut();
4031 }
4032
4033 let result = dup_xml_str(content);
4035 io::buf_free(buf);
4036 result
4037}
4038
4039pub unsafe fn dump_doc(doc: *mut _xmlDoc) -> *mut xmlChar {
4048 if doc.is_null() {
4049 return ptr::null_mut();
4050 }
4051
4052 let buf = io::buf_create(-1);
4053 if buf.is_null() {
4054 return ptr::null_mut();
4055 }
4056
4057 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
4058
4059 let content = io::buf_content(buf);
4060 if content.is_null() {
4061 io::buf_free(buf);
4062 return ptr::null_mut();
4063 }
4064
4065 let result = dup_xml_str(content);
4066 io::buf_free(buf);
4067 result
4068}
4069
4070pub(crate) unsafe fn xmlNodeDump(
4086 buf: *mut _xmlBuffer,
4087 doc: *mut _xmlDoc,
4088 node: *mut _xmlNode,
4089 level: c_int,
4090 format: c_int,
4091) -> c_int {
4092 node_dump(buf, doc, node, level, format)
4093}
4094
4095pub(crate) unsafe fn xmlDocDump(fp: *mut c_void, doc: *mut _xmlDoc) -> c_int {
4108 if fp.is_null() || doc.is_null() {
4109 return -1;
4110 }
4111
4112 let buf = io::buf_create(-1);
4113 if buf.is_null() {
4114 return -1;
4115 }
4116
4117 let ret = doc_dump(buf, doc);
4118 if ret < 0 {
4119 io::buf_free(buf);
4120 return -1;
4121 }
4122
4123 let content = io::buf_content(buf);
4124 let len = io::buf_length(buf);
4125 if !content.is_null() && len > 0 {
4126 let written = libc::fwrite(
4127 content as *const c_void,
4128 1,
4129 len as usize,
4130 fp as *mut libc::FILE,
4131 );
4132 io::buf_free(buf);
4133 written as c_int
4134 } else {
4135 io::buf_free(buf);
4136 0
4137 }
4138}
4139
4140pub(crate) unsafe fn xmlDocDumpFormatMemory(
4154 doc: *mut _xmlDoc,
4155 mem: *mut *mut xmlChar,
4156 size: *mut c_int,
4157 format: c_int,
4158) {
4159 if doc.is_null() || mem.is_null() || size.is_null() {
4160 return;
4161 }
4162
4163 let buf = io::buf_create(-1);
4164 if buf.is_null() {
4165 unsafe {
4166 *mem = ptr::null_mut();
4167 *size = 0;
4168 }
4169 return;
4170 }
4171
4172 serialize_node(doc as *mut _xmlNode, buf, format, 0);
4173
4174 let content = io::buf_content(buf);
4175 let len = io::buf_length(buf);
4176
4177 if !content.is_null() && len > 0 {
4178 let result = allocator::xmlMallocImpl((len + 1) as usize) as *mut xmlChar;
4180 if !result.is_null() {
4181 ptr::copy_nonoverlapping(content, result, len as usize);
4182 *result.add(len as usize) = 0;
4183 unsafe {
4184 *mem = result;
4185 *size = len;
4186 }
4187 } else {
4188 unsafe {
4189 *mem = ptr::null_mut();
4190 *size = 0;
4191 }
4192 }
4193 } else {
4194 unsafe {
4195 *mem = ptr::null_mut();
4196 *size = 0;
4197 }
4198 }
4199
4200 io::buf_free(buf);
4201}
4202
4203pub(crate) unsafe fn xmlDocDumpMemory(doc: *mut _xmlDoc, mem: *mut *mut xmlChar, size: *mut c_int) {
4217 xmlDocDumpFormatMemory(doc, mem, size, 0)
4218}
4219
4220pub(crate) unsafe fn xmlSaveFile(filename: *const c_char, cur: *mut _xmlDoc) -> c_int {
4233 save_doc_to_filename(cur, filename, 0)
4234}
4235
4236pub(crate) unsafe fn xmlSaveFileEnc(
4250 filename: *const c_char,
4251 cur: *mut _xmlDoc,
4252 encoding: *const c_char,
4253) -> c_int {
4254 let _ = encoding; save_doc_to_filename(cur, filename, 0)
4256}
4257
4258pub(crate) unsafe fn xmlSaveFormatFile(
4271 filename: *const c_char,
4272 cur: *mut _xmlDoc,
4273 format: c_int,
4274) -> c_int {
4275 let _ = format;
4276 save_doc_to_filename(cur, filename, 0)
4277}
4278
4279pub(crate) unsafe fn xmlSaveFormatFileEnc(
4293 filename: *const c_char,
4294 cur: *mut _xmlDoc,
4295 encoding: *const c_char,
4296 format: c_int,
4297) -> c_int {
4298 let _ = encoding;
4299 let _ = format;
4300 save_doc_to_filename(cur, filename, 0)
4301}
4302
4303pub(crate) unsafe fn xmlGetDocCompressMode(doc: *mut _xmlDoc) -> c_int {
4315 if doc.is_null() {
4316 return -1;
4317 }
4318 unsafe { (*doc).compression }
4319}
4320
4321pub(crate) unsafe fn xmlSetDocCompressMode(doc: *mut _xmlDoc, mode: c_int) {
4333 if doc.is_null() {
4334 return;
4335 }
4336 unsafe {
4337 (*doc).compression = mode;
4338 }
4339}
4340
4341#[cfg(test)]
4342mod tests {
4343 use super::*;
4344 use core::ffi::c_void;
4345
4346 fn c_str(s: &str) -> *const xmlChar {
4347 let bytes = s.as_bytes();
4348 let buf = unsafe { allocator::xmlMallocImpl(bytes.len() + 1) as *mut u8 };
4349 if !buf.is_null() {
4350 unsafe {
4351 ptr::copy_nonoverlapping(bytes.as_ptr(), buf, bytes.len());
4352 *buf.add(bytes.len()) = 0;
4353 }
4354 }
4355 buf as *const xmlChar
4356 }
4357
4358 #[test]
4359 fn test_new_free_doc() {
4360 unsafe {
4361 let doc = new_doc(ptr::null());
4362 assert!(!doc.is_null());
4363 assert_eq!((*doc).type_, XML_DOCUMENT_NODE as c_int);
4364 assert_eq!((*doc).standalone, -1);
4365 assert_eq!((*doc).doc, doc);
4366 assert!(!(*doc).version.is_null());
4367 free_doc(doc);
4368 }
4369 }
4370
4371 #[test]
4372 fn test_new_doc_with_version() {
4373 unsafe {
4374 let ver = c_str("2.0");
4375 let doc = new_doc(ver);
4376 assert!(!doc.is_null());
4377 let doc_ver = (*doc).version;
4378 assert!(!doc_ver.is_null());
4379 assert!(crate::abi::exports_xml2::xmlStrEqual(doc_ver, ver,) != 0);
4380 allocator::xmlFreeImpl(ver as *mut c_void);
4381 free_doc(doc);
4382 }
4383 }
4384
4385 #[test]
4386 fn test_new_node() {
4387 unsafe {
4388 let doc = new_doc(ptr::null());
4389 let node = new_node(ptr::null_mut(), c_str("root"));
4390 assert!(!node.is_null());
4391 assert_eq!((*node).type_, XML_ELEMENT_NODE as c_int);
4392 assert!(!(*node).name.is_null());
4393 free_node(node);
4394 free_doc(doc);
4395 }
4396 }
4397
4398 #[test]
4399 fn test_node_get_content_recurses_descendants() {
4400 unsafe {
4405 let doc = new_doc(ptr::null());
4406 let root = new_node(ptr::null_mut(), c_str("library"));
4407 doc_set_root_element(doc, root);
4408 let book = new_child(root, ptr::null_mut(), c_str("book"));
4409 let title = new_child(book, ptr::null_mut(), c_str("title"));
4410 let text = new_text(c_str("Rust"));
4411 add_child(title, text);
4412
4413 let content = node_get_content(book);
4414 assert!(!content.is_null());
4415 let s = core::slice::from_raw_parts(
4416 content,
4417 libc::strlen(content as *const libc::c_char) as usize,
4418 );
4419 assert_eq!(s, b"Rust", "descendant text not concatenated");
4420 allocator::xmlFreeImpl(content as *mut c_void);
4421
4422 free_doc(doc);
4423 }
4424 }
4425
4426 #[test]
4427 fn test_doc_set_root_element() {
4428 unsafe {
4429 let doc = new_doc(ptr::null());
4430 let root = new_node(ptr::null_mut(), c_str("root"));
4431 let old = doc_set_root_element(doc, root);
4432 assert!(old.is_null());
4433 assert_eq!(doc_get_root_element(doc), root);
4434 assert_eq!((*doc).children, root as *mut _xmlNode);
4435 free_doc(doc);
4436 }
4437 }
4438
4439 #[test]
4440 fn test_add_child_and_sibling() {
4441 unsafe {
4442 let doc = new_doc(ptr::null());
4443 let root = new_node(ptr::null_mut(), c_str("root"));
4444 doc_set_root_element(doc, root);
4445
4446 let child1 = new_child(root, ptr::null_mut(), c_str("child1"));
4447 assert!(!child1.is_null());
4448 assert_eq!((*child1).parent, root);
4449 assert_eq!((*root).children, child1);
4450 assert_eq!((*root).last, child1);
4451
4452 let child2 = new_child(root, ptr::null_mut(), c_str("child2"));
4453 assert!(!child2.is_null());
4454 assert_eq!((*child2).parent, root);
4455 assert_eq!((*child1).next, child2);
4456 assert_eq!((*child2).prev, child1);
4457 assert_eq!((*root).last, child2);
4458
4459 let sibling = new_node(ptr::null_mut(), c_str("sibling"));
4461 add_sibling(child2, sibling);
4462 assert_eq!((*child2).next, sibling);
4463 assert_eq!((*sibling).prev, child2);
4464 assert_eq!((*root).last, sibling);
4465
4466 free_doc(doc);
4467 }
4468 }
4469
4470 #[test]
4471 fn test_unlink_node() {
4472 unsafe {
4473 let doc = new_doc(ptr::null());
4474 let root = new_node(ptr::null_mut(), c_str("root"));
4475 doc_set_root_element(doc, root);
4476
4477 let child1 = new_child(root, ptr::null_mut(), c_str("c1"));
4478 let child2 = new_child(root, ptr::null_mut(), c_str("c2"));
4479
4480 unlink_node(child1);
4481 assert!((*child1).parent.is_null());
4482 assert!((*child1).prev.is_null());
4483 assert!((*child1).next.is_null());
4484 assert_eq!((*root).children, child2);
4485 assert_eq!((*root).last, child2);
4486
4487 free_node(child1);
4488 free_doc(doc);
4489 }
4490 }
4491
4492 #[test]
4493 fn test_text_and_comment_nodes() {
4494 unsafe {
4495 let text = new_text(c_str("hello world"));
4496 assert!(!text.is_null());
4497 assert_eq!((*text).type_, XML_TEXT_NODE as c_int);
4498 assert!(!(*text).content.is_null());
4499 free_node(text);
4500
4501 let comment = new_comment(c_str("my comment"));
4502 assert!(!comment.is_null());
4503 assert_eq!((*comment).type_, XML_COMMENT_NODE as c_int);
4504 free_node(comment);
4505
4506 let pi = new_pi(c_str("xml"), c_str("version='1.0'"));
4507 assert!(!pi.is_null());
4508 assert_eq!((*pi).type_, XML_PI_NODE as c_int);
4509 free_node(pi);
4510 }
4511 }
4512
4513 #[test]
4514 fn test_set_and_get_prop() {
4515 unsafe {
4516 let doc = new_doc(ptr::null());
4517 let root = new_node(ptr::null_mut(), c_str("root"));
4518 doc_set_root_element(doc, root);
4519
4520 let attr = set_prop(root, c_str("id"), c_str("42"));
4521 assert!(!attr.is_null());
4522 assert_eq!((*attr).type_, XML_ATTRIBUTE_NODE as c_int);
4523
4524 let value = get_prop(root, c_str("id"));
4525 assert!(!value.is_null());
4526 assert!(crate::abi::exports_xml2::xmlStrEqual(value, c_str("42")) != 0);
4527 allocator::xmlFreeImpl(value as *mut c_void);
4528
4529 free_doc(doc);
4530 }
4531 }
4532
4533 #[test]
4534 fn test_remove_prop() {
4535 unsafe {
4536 let doc = new_doc(ptr::null());
4537 let root = new_node(ptr::null_mut(), c_str("root"));
4538 doc_set_root_element(doc, root);
4539
4540 set_prop(root, c_str("a"), c_str("1"));
4541 set_prop(root, c_str("b"), c_str("2"));
4542
4543 let value = get_prop(root, c_str("a"));
4544 assert!(!value.is_null());
4545 allocator::xmlFreeImpl(value as *mut c_void);
4546
4547 let attr = (*root).properties;
4549 assert!(!attr.is_null());
4550 let result = remove_prop(attr);
4551 assert_eq!(result, 0);
4552
4553 let value2 = get_prop(root, c_str("a"));
4555 assert!(value2.is_null());
4556
4557 free_doc(doc);
4558 }
4559 }
4560
4561 #[test]
4562 fn test_namespace_operations() {
4563 unsafe {
4564 let doc = new_doc(ptr::null());
4565 let root = new_node(ptr::null_mut(), c_str("root"));
4566 doc_set_root_element(doc, root);
4567
4568 let ns = new_ns(root, c_str("http://example.com"), c_str("ex"));
4569 assert!(!ns.is_null());
4570 assert!(!(*root).nsDef.is_null());
4571
4572 set_ns(root, ns);
4573 assert_eq!((*root).ns, ns);
4574
4575 let found = search_ns(doc, root, c_str("ex"));
4576 assert_eq!(found, ns);
4577
4578 let found_href = search_ns_by_href(doc, root, c_str("http://example.com"));
4579 assert_eq!(found_href, ns);
4580
4581 free_doc(doc);
4582 }
4583 }
4584
4585 #[test]
4586 fn test_new_dtd() {
4587 unsafe {
4588 let doc = new_doc(ptr::null());
4589 let dtd = new_dtd(doc, c_str("root"), c_str("-//TEST//DTD"), c_str("test.dtd"));
4590 assert!(!dtd.is_null());
4591 assert_eq!((*dtd).type_, XML_DTD_NODE as c_int);
4592 assert_eq!(get_int_subset(doc), dtd);
4593 free_doc(doc);
4594 }
4595 }
4596
4597 #[test]
4598 fn test_copy_node_deep() {
4599 unsafe {
4600 let doc = new_doc(ptr::null());
4601 let root = new_node(ptr::null_mut(), c_str("root"));
4602 doc_set_root_element(doc, root);
4603 let child = new_child(root, ptr::null_mut(), c_str("child"));
4604
4605 let copy = copy_node(root, 1);
4606 assert!(!copy.is_null());
4607 assert_eq!((*copy).type_, XML_ELEMENT_NODE as c_int);
4608 assert!(!(*copy).children.is_null());
4610 assert_eq!((*(*copy).children).type_, XML_ELEMENT_NODE as c_int);
4611
4612 free_node(copy);
4613 free_doc(doc);
4614 }
4615 }
4616
4617 #[test]
4618 fn test_new_cdata_block() {
4619 unsafe {
4620 let doc = new_doc(ptr::null());
4621 let content = c_str("some <cdata> content");
4622 let cdata = new_cdata_block(doc, content, 20);
4623 assert!(!cdata.is_null());
4624 assert_eq!((*cdata).type_, XML_CDATA_SECTION_NODE as c_int);
4625 free_node(cdata);
4626 free_doc(doc);
4627 }
4628 }
4629
4630 #[test]
4631 fn test_null_handling() {
4632 unsafe {
4633 assert!(new_doc(ptr::null()).is_null() == false); let doc = new_doc(ptr::null());
4635 assert!(new_node(ptr::null_mut(), ptr::null()).is_null() == false); free_node(ptr::null_mut()); free_doc(ptr::null_mut()); assert!(unlink_node(ptr::null_mut()) == ()); assert!(add_child(ptr::null_mut(), ptr::null_mut()).is_null());
4640 assert!(add_sibling(ptr::null_mut(), ptr::null_mut()).is_null());
4641 free_doc(doc);
4642 }
4643 }
4644
4645 unsafe fn buf_eq_str(buf: *mut _xmlBuffer, expected: &str) -> bool {
4651 let content = io::buf_content(buf);
4652 if content.is_null() {
4653 return expected.is_empty();
4654 }
4655 let len = io::buf_length(buf) as usize;
4656 if len != expected.len() {
4657 return false;
4658 }
4659 let slice = unsafe { core::slice::from_raw_parts(content, len) };
4660 slice == expected.as_bytes()
4661 }
4662
4663 #[test]
4664 fn test_serialize_empty_document() {
4665 unsafe {
4666 let doc = new_doc(ptr::null());
4667 let buf = io::buf_create(-1);
4668 assert!(!buf.is_null());
4669
4670 let ret = doc_dump(buf, doc);
4671 assert!(ret >= 0);
4672
4673 let expected = "<?xml version=\"1.0\"?>\n";
4677 assert!(buf_eq_str(buf, expected));
4678
4679 io::buf_free(buf);
4680 free_doc(doc);
4681 }
4682 }
4683
4684 #[test]
4685 fn test_serialize_element_with_text() {
4686 unsafe {
4687 let doc = new_doc(ptr::null());
4688 let root = new_node(ptr::null_mut(), c_str("root"));
4689 doc_set_root_element(doc, root);
4690
4691 let text = new_text(c_str("hello world"));
4693 add_child(root, text);
4694
4695 let buf = io::buf_create(-1);
4696 assert!(!buf.is_null());
4697
4698 let ret = doc_dump(buf, doc);
4699 assert!(ret >= 0);
4700
4701 let expected = "<?xml version=\"1.0\"?>\n<root>hello world</root>\n";
4702 assert!(buf_eq_str(buf, expected));
4703
4704 io::buf_free(buf);
4705 free_doc(doc);
4706 }
4707 }
4708
4709 #[test]
4710 fn test_serialize_element_with_attributes() {
4711 unsafe {
4712 let doc = new_doc(ptr::null());
4713 let root = new_node(ptr::null_mut(), c_str("root"));
4714 doc_set_root_element(doc, root);
4715
4716 set_prop(root, c_str("id"), c_str("42"));
4717 set_prop(root, c_str("name"), c_str("test"));
4718
4719 let buf = io::buf_create(-1);
4720 assert!(!buf.is_null());
4721
4722 let ret = doc_dump(buf, doc);
4723 assert!(ret >= 0);
4724
4725 let expected = "<?xml version=\"1.0\"?>\n<root id=\"42\" name=\"test\"/>\n";
4726 assert!(buf_eq_str(buf, expected));
4727
4728 io::buf_free(buf);
4729 free_doc(doc);
4730 }
4731 }
4732
4733 #[test]
4734 fn test_serialize_nested_elements() {
4735 unsafe {
4736 let doc = new_doc(ptr::null());
4737 let root = new_node(ptr::null_mut(), c_str("root"));
4738 doc_set_root_element(doc, root);
4739
4740 let child = new_child(root, ptr::null_mut(), c_str("child"));
4741 let grandchild = new_child(child, ptr::null_mut(), c_str("gc"));
4742 let text = new_text(c_str("text"));
4743 add_child(grandchild, text);
4744
4745 let buf = io::buf_create(-1);
4746 assert!(!buf.is_null());
4747
4748 let ret = doc_dump(buf, doc);
4749 assert!(ret >= 0);
4750
4751 let expected = "<?xml version=\"1.0\"?>\n<root><child><gc>text</gc></child></root>\n";
4752 assert!(buf_eq_str(buf, expected));
4753
4754 io::buf_free(buf);
4755 free_doc(doc);
4756 }
4757 }
4758
4759 #[test]
4760 fn test_serialize_with_formatting() {
4761 unsafe {
4762 let doc = new_doc(ptr::null());
4763 let root = new_node(ptr::null_mut(), c_str("root"));
4764 doc_set_root_element(doc, root);
4765
4766 let child = new_child(root, ptr::null_mut(), c_str("child"));
4767 let text = new_text(c_str("text"));
4768 add_child(child, text);
4769
4770 let buf = io::buf_create(-1);
4771 assert!(!buf.is_null());
4772
4773 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
4774
4775 let expected = "<?xml version=\"1.0\"?>\n<root>\n <child>text</child>\n</root>\n";
4776 assert!(buf_eq_str(buf, expected));
4777
4778 io::buf_free(buf);
4779 free_doc(doc);
4780 }
4781 }
4782
4783 #[test]
4784 fn test_serialize_escape_ampersand() {
4785 unsafe {
4786 let doc = new_doc(ptr::null());
4787 let root = new_node(ptr::null_mut(), c_str("root"));
4788 doc_set_root_element(doc, root);
4789
4790 let text = new_text(c_str("a & b"));
4791 add_child(root, text);
4792
4793 let buf = io::buf_create(-1);
4794 assert!(!buf.is_null());
4795
4796 let ret = doc_dump(buf, doc);
4797 assert!(ret >= 0);
4798
4799 let expected = "<?xml version=\"1.0\"?>\n<root>a & b</root>\n";
4800 assert!(buf_eq_str(buf, expected));
4801
4802 io::buf_free(buf);
4803 free_doc(doc);
4804 }
4805 }
4806
4807 #[test]
4808 fn test_serialize_escape_angle_brackets() {
4809 unsafe {
4810 let doc = new_doc(ptr::null());
4811 let root = new_node(ptr::null_mut(), c_str("root"));
4812 doc_set_root_element(doc, root);
4813
4814 let text = new_text(c_str("x < y > z"));
4815 add_child(root, text);
4816
4817 let buf = io::buf_create(-1);
4818 assert!(!buf.is_null());
4819
4820 let ret = doc_dump(buf, doc);
4821 assert!(ret >= 0);
4822
4823 let expected = "<?xml version=\"1.0\"?>\n<root>x < y > z</root>\n";
4824 assert!(buf_eq_str(buf, expected));
4825
4826 io::buf_free(buf);
4827 free_doc(doc);
4828 }
4829 }
4830
4831 #[test]
4832 fn test_serialize_comment() {
4833 unsafe {
4834 let doc = new_doc(ptr::null());
4835 let root = new_node(ptr::null_mut(), c_str("root"));
4836 doc_set_root_element(doc, root);
4837
4838 let comment = new_comment(c_str("my comment"));
4839 add_child(root, comment);
4840
4841 let buf = io::buf_create(-1);
4842 assert!(!buf.is_null());
4843
4844 let ret = doc_dump(buf, doc);
4845 assert!(ret >= 0);
4846
4847 let expected = "<?xml version=\"1.0\"?>\n<root><!--my comment--></root>\n";
4848 assert!(buf_eq_str(buf, expected));
4849
4850 io::buf_free(buf);
4851 free_doc(doc);
4852 }
4853 }
4854
4855 #[test]
4856 fn test_serialize_pi() {
4857 unsafe {
4858 let doc = new_doc(ptr::null());
4859 let root = new_node(ptr::null_mut(), c_str("root"));
4860 doc_set_root_element(doc, root);
4861
4862 let pi = new_pi(
4863 c_str("xml-stylesheet"),
4864 c_str("href=\"style.xsl\" type=\"text/xsl\""),
4865 );
4866 add_child(root, pi);
4867
4868 let buf = io::buf_create(-1);
4869 assert!(!buf.is_null());
4870
4871 let ret = doc_dump(buf, doc);
4872 assert!(ret >= 0);
4873
4874 let expected = "<?xml version=\"1.0\"?>\n<root><?xml-stylesheet href=\"style.xsl\" type=\"text/xsl\"?></root>\n";
4875 assert!(buf_eq_str(buf, expected));
4876
4877 io::buf_free(buf);
4878 free_doc(doc);
4879 }
4880 }
4881
4882 #[test]
4883 fn test_serialize_self_closing() {
4884 unsafe {
4885 let doc = new_doc(ptr::null());
4886 let root = new_node(ptr::null_mut(), c_str("empty"));
4887 doc_set_root_element(doc, root);
4888
4889 let buf = io::buf_create(-1);
4890 assert!(!buf.is_null());
4891
4892 let ret = doc_dump(buf, doc);
4893 assert!(ret >= 0);
4894
4895 let expected = "<?xml version=\"1.0\"?>\n<empty/>\n";
4896 assert!(buf_eq_str(buf, expected));
4897
4898 io::buf_free(buf);
4899 free_doc(doc);
4900 }
4901 }
4902
4903 #[test]
4904 fn test_dump_node_to_string() {
4905 unsafe {
4906 let node = new_node(ptr::null_mut(), c_str("foo"));
4907 let text = new_text(c_str("bar"));
4908 add_child(node, text);
4909
4910 let result = dump_node(node);
4911 assert!(!result.is_null());
4912
4913 let len = xml_strlen(result);
4914 let slice = unsafe { core::slice::from_raw_parts(result, len as usize) };
4915 assert_eq!(slice, b"<foo>bar</foo>");
4916
4917 allocator::xmlFreeImpl(result as *mut c_void);
4918 free_node(node);
4919 }
4920 }
4921
4922 #[test]
4923 fn test_dump_doc_to_string() {
4924 unsafe {
4925 let doc = new_doc(ptr::null());
4926 let root = new_node(ptr::null_mut(), c_str("root"));
4927 doc_set_root_element(doc, root);
4928
4929 let result = dump_doc(doc);
4930 assert!(!result.is_null());
4931
4932 let len = xml_strlen(result);
4933 let slice = unsafe { core::slice::from_raw_parts(result, len as usize) };
4934 let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
4935 assert_eq!(slice, expected.as_bytes());
4936
4937 allocator::xmlFreeImpl(result as *mut c_void);
4938 free_doc(doc);
4939 }
4940 }
4941
4942 #[test]
4943 fn test_xmlDocDumpFormatMemory() {
4944 unsafe {
4945 let doc = new_doc(ptr::null());
4946 let root = new_node(ptr::null_mut(), c_str("root"));
4947 doc_set_root_element(doc, root);
4948
4949 let mut mem: *mut xmlChar = ptr::null_mut();
4950 let mut size: c_int = 0;
4951
4952 xmlDocDumpFormatMemory(doc, &mut mem, &mut size, 0);
4953
4954 assert!(!mem.is_null());
4955 assert!(size > 0);
4956
4957 let slice = unsafe { core::slice::from_raw_parts(mem, size as usize) };
4958 let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
4961 assert_eq!(slice, expected.as_bytes());
4962
4963 allocator::xmlFreeImpl(mem as *mut c_void);
4964 free_doc(doc);
4965 }
4966 }
4967
4968 #[test]
4969 fn test_serialize_escape_attribute() {
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 set_prop(root, c_str("desc"), c_str("a < b & c \"quoted\""));
4977
4978 let buf = io::buf_create(-1);
4979 assert!(!buf.is_null());
4980
4981 let ret = doc_dump(buf, doc);
4982 assert!(ret >= 0);
4983
4984 let expected =
4985 "<?xml version=\"1.0\"?>\n<root desc=\"a < b & c "quoted"\"/>\n";
4986 assert!(buf_eq_str(buf, expected));
4987
4988 io::buf_free(buf);
4989 free_doc(doc);
4990 }
4991 }
4992}