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 d.entities.is_null()
3381 && d.elements.is_null()
3382 && d.attributes.is_null()
3383 && d.notations.is_null()
3384 && d.pentities.is_null()
3385 {
3386 io::buf_ccat(buf, b'>');
3387 return;
3388 }
3389 io::buf_add(buf, b" [\n" as *const u8, 3);
3390 let format = state.format;
3396 let lvl = *level;
3397 state.format = 0;
3398 *level = -1;
3399 if !d.notations.is_null() {
3400 crate::xml::hash::hash_scan(
3401 d.notations as *mut crate::xml::hash::HashTable,
3402 Some(dump_notation_decl_cb),
3403 buf as *mut c_void,
3404 );
3405 }
3406 if !d.elements.is_null() {
3407 crate::xml::hash::hash_scan(
3408 d.elements as *mut crate::xml::hash::HashTable,
3409 Some(dump_element_decl_cb),
3410 buf as *mut c_void,
3411 );
3412 }
3413 if !d.attributes.is_null() {
3414 crate::xml::hash::hash_scan(
3415 d.attributes as *mut crate::xml::hash::HashTable,
3416 Some(dump_attribute_decl_cb),
3417 buf as *mut c_void,
3418 );
3419 }
3420 if !d.entities.is_null() {
3421 crate::xml::hash::hash_scan(
3422 d.entities as *mut crate::xml::hash::HashTable,
3423 Some(dump_entity_decl_cb),
3424 buf as *mut c_void,
3425 );
3426 }
3427 if !d.pentities.is_null() {
3428 crate::xml::hash::hash_scan(
3429 d.pentities as *mut crate::xml::hash::HashTable,
3430 Some(dump_entity_decl_cb),
3431 buf as *mut c_void,
3432 );
3433 }
3434 state.format = format;
3435 *level = lvl;
3436 io::buf_add(buf, b"]>" as *const u8, 2);
3437}
3438
3439unsafe extern "C" fn dump_notation_decl_cb(
3441 payload: *mut c_void,
3442 data: *mut c_void,
3443 _name: *const crate::abi::types::xmlChar,
3444) {
3445 if !payload.is_null() && !data.is_null() {
3446 dump_notation_decl(data as *mut _xmlBuffer, payload as *mut _xmlNotation);
3447 }
3448}
3449
3450unsafe extern "C" fn dump_element_decl_cb(
3452 payload: *mut c_void,
3453 data: *mut c_void,
3454 _name: *const crate::abi::types::xmlChar,
3455) {
3456 if !payload.is_null() && !data.is_null() {
3457 dump_element_decl(data as *mut _xmlBuffer, payload as *mut _xmlElement);
3458 }
3459}
3460
3461unsafe extern "C" fn dump_attribute_decl_cb(
3463 payload: *mut c_void,
3464 data: *mut c_void,
3465 _name: *const crate::abi::types::xmlChar,
3466) {
3467 if !payload.is_null() && !data.is_null() {
3468 dump_attribute_decl(data as *mut _xmlBuffer, payload as *mut _xmlAttribute);
3469 }
3470}
3471
3472unsafe extern "C" fn dump_entity_decl_cb(
3474 payload: *mut c_void,
3475 data: *mut c_void,
3476 _name: *const crate::abi::types::xmlChar,
3477) {
3478 if !payload.is_null() && !data.is_null() {
3479 dump_entity_decl(data as *mut _xmlBuffer, payload as *mut _xmlEntity);
3480 }
3481}
3482
3483unsafe fn doc_content_dump_output(
3492 buf: *mut _xmlBuffer,
3493 cur: *mut _xmlNode,
3494 state: &mut DumpState,
3495 level: &mut c_int,
3496) {
3497 let doc = cur as *mut _xmlDoc;
3498 let d = unsafe { &*doc };
3499
3500 if state.no_decl == 0 {
3504 io::buf_add(buf, b"<?xml version=\"" as *const u8, 15);
3505 if !d.version.is_null() {
3506 io::buf_cat(buf, d.version);
3507 } else {
3508 io::buf_add(buf, b"1.0" as *const u8, 3);
3509 }
3510 io::buf_ccat(buf, b'"');
3511 if !d.encoding.is_null() {
3512 io::buf_add(buf, b" encoding=\"" as *const u8, 11);
3513 io::buf_cat(buf, d.encoding);
3514 io::buf_ccat(buf, b'"');
3515 }
3516 match d.standalone {
3517 0 => {
3518 io::buf_add(buf, b" standalone=\"no\"" as *const u8, 16);
3519 }
3520 1 => {
3521 io::buf_add(buf, b" standalone=\"yes\"" as *const u8, 17);
3522 }
3523 _ => {}
3524 }
3525 io::buf_add(buf, b"?>\n" as *const u8, 3);
3526 }
3527
3528 if !d.intSubset.is_null() {
3535 let mut in_chain = false;
3536 let mut c = d.children;
3537 while !c.is_null() {
3538 if c as *mut c_void == d.intSubset as *mut c_void {
3539 in_chain = true;
3540 break;
3541 }
3542 c = unsafe { (*c).next };
3543 }
3544 if !in_chain {
3545 let mut lvl = 0;
3546 dtd_dump_output(buf, d.intSubset as *mut _xmlNode, state, &mut lvl);
3547 io::buf_ccat(buf, b'\n');
3548 }
3549 }
3550
3551 if !d.children.is_null() {
3552 let mut child = d.children;
3553 while !child.is_null() {
3554 *level = 0;
3555 node_dump_internal(buf, child, child, cur, state, level);
3556 let ct = unsafe { (*child).type_ };
3557 if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
3558 io::buf_ccat(buf, b'\n');
3559 }
3560 child = unsafe { (*child).next };
3561 }
3562 }
3563}
3564
3565unsafe fn node_dump_internal(
3589 buf: *mut _xmlBuffer,
3590 cur: *mut _xmlNode,
3591 root: *mut _xmlNode,
3592 parent: *mut _xmlNode,
3593 state: &mut DumpState,
3594 level: &mut c_int,
3595) {
3596 if cur.is_null() || buf.is_null() {
3597 return;
3598 }
3599 let n = unsafe { &*cur };
3600 match n.type_ {
3601 t if t == XML_ELEMENT_NODE as c_int => {
3602 if cur != root && state.format == 1 {
3603 write_indent(buf, *level, state.indent, state.indent_len);
3604 }
3605 if !n.parent.is_null() && n.parent != parent && !n.children.is_null() {
3608 let mut sub = DumpState::new(state.format);
3609 let mut sub_level = *level;
3610 node_dump_internal(buf, cur, cur, n.parent, &mut sub, &mut sub_level);
3611 return;
3612 }
3613 io::buf_ccat(buf, b'<');
3615 write_qname(buf, cur);
3616 let mut nsdef = n.nsDef;
3617 while !nsdef.is_null() {
3618 ns_dump_output(buf, nsdef);
3619 nsdef = unsafe { (*nsdef).next };
3620 }
3621 let mut attr = n.properties;
3622 while !attr.is_null() {
3623 attr_dump_output(buf, attr);
3624 attr = unsafe { (*attr).next };
3625 }
3626 if n.children.is_null() {
3627 io::buf_add(buf, b"/>" as *const u8, 2);
3628 } else {
3629 if state.format == 1 {
3630 let mut tmp = n.children;
3633 while !tmp.is_null() {
3634 let tt = unsafe { (*tmp).type_ };
3635 if tt == XML_TEXT_NODE as c_int
3636 || tt == XML_CDATA_SECTION_NODE as c_int
3637 || tt == XML_ENTITY_REF_NODE as c_int
3638 {
3639 state.format = 0;
3640 state.unformatted = cur;
3641 break;
3642 }
3643 tmp = unsafe { (*tmp).next };
3644 }
3645 }
3646 io::buf_ccat(buf, b'>');
3647 if state.format == 1 {
3648 io::buf_ccat(buf, b'\n');
3649 }
3650 if *level >= 0 {
3651 *level += 1;
3652 }
3653 let mut child = n.children;
3654 while !child.is_null() {
3655 node_dump_internal(buf, child, root, cur, state, level);
3656 if state.format == 1 {
3657 let ct = unsafe { (*child).type_ };
3658 if ct != XML_XINCLUDE_START as c_int && ct != XML_XINCLUDE_END as c_int {
3659 io::buf_ccat(buf, b'\n');
3660 }
3661 }
3662 child = unsafe { (*child).next };
3663 }
3664 if *level > 0 {
3666 *level -= 1;
3667 }
3668 if state.format == 1 {
3669 write_indent(buf, *level, state.indent, state.indent_len);
3670 }
3671 io::buf_add(buf, b"</" as *const u8, 2);
3672 write_qname(buf, cur);
3673 io::buf_ccat(buf, b'>');
3674 if cur == state.unformatted {
3675 state.format = state.saved;
3676 state.unformatted = ptr::null_mut();
3677 }
3678 }
3679 }
3680 t if t == XML_TEXT_NODE as c_int => {
3681 if !n.content.is_null() {
3682 if is_noenc_text(cur) {
3683 io::buf_cat(buf, n.content);
3684 } else {
3685 serialize_text(buf, n.content, xml_strlen(n.content));
3686 }
3687 } else if !n.children.is_null() {
3688 let c = node_get_content(cur);
3691 if !c.is_null() {
3692 if is_noenc_text(cur) {
3693 io::buf_cat(buf, c);
3694 } else {
3695 serialize_text(buf, c, xml_strlen(c));
3696 }
3697 allocator::xmlFreeImpl(c as *mut c_void);
3698 }
3699 }
3700 }
3701 t if t == XML_CDATA_SECTION_NODE as c_int => {
3702 if n.content.is_null() || unsafe { *n.content == 0 } {
3703 io::buf_add(buf, b"<![CDATA[]]>" as *const u8, 12);
3704 } else {
3705 let len = xml_strlen(n.content) as usize;
3706 let bytes = core::slice::from_raw_parts(n.content, len);
3707 let mut i = 0usize;
3708 let mut seg_start = 0usize;
3709 while i < len {
3710 if bytes[i] == b']'
3711 && i + 2 < len
3712 && bytes[i + 1] == b']'
3713 && bytes[i + 2] == b'>'
3714 {
3715 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
3716 io::buf_add(buf, n.content.add(seg_start), (i + 2 - seg_start) as c_int);
3717 io::buf_add(buf, b"]]>" as *const u8, 3);
3718 seg_start = i + 2;
3719 i += 3;
3720 continue;
3721 }
3722 i += 1;
3723 }
3724 if seg_start < len {
3725 io::buf_add(buf, b"<![CDATA[" as *const u8, 9);
3726 io::buf_add(buf, n.content.add(seg_start), (len - seg_start) as c_int);
3727 io::buf_add(buf, b"]]>" as *const u8, 3);
3728 }
3729 }
3730 }
3731 t if t == XML_COMMENT_NODE as c_int => {
3732 if cur != root && state.format == 1 {
3733 write_indent(buf, *level, state.indent, state.indent_len);
3734 }
3735 if !n.content.is_null() {
3736 io::buf_add(buf, b"<!--" as *const u8, 4);
3737 io::buf_cat(buf, n.content);
3738 io::buf_add(buf, b"-->" as *const u8, 3);
3739 }
3740 }
3741 t if t == XML_PI_NODE as c_int => {
3742 if cur != root && state.format == 1 {
3743 write_indent(buf, *level, state.indent, state.indent_len);
3744 }
3745 io::buf_add(buf, b"<?" as *const u8, 2);
3746 if !n.name.is_null() {
3747 io::buf_cat(buf, n.name);
3748 }
3749 if !n.content.is_null() && unsafe { *n.content != 0 } {
3750 io::buf_ccat(buf, b' ');
3751 io::buf_cat(buf, n.content);
3752 }
3753 io::buf_add(buf, b"?>" as *const u8, 2);
3754 }
3755 t if t == XML_ENTITY_REF_NODE as c_int => {
3756 io::buf_ccat(buf, b'&');
3757 if !n.name.is_null() {
3758 io::buf_cat(buf, n.name);
3759 }
3760 io::buf_ccat(buf, b';');
3761 }
3762 t if t == XML_DOCUMENT_NODE as c_int => {
3763 doc_content_dump_output(buf, cur, state, level);
3764 }
3765 t if t == XML_HTML_DOCUMENT_NODE as c_int => {
3766 crate::xml::html::serialize_node(cur, buf, state.format, *level);
3768 }
3769 t if t == XML_DTD_NODE as c_int => {
3770 dtd_dump_output(buf, cur, state, level);
3771 }
3772 t if t == XML_ATTRIBUTE_NODE as c_int => {
3773 attr_dump_output(buf, cur as *mut _xmlAttr);
3774 }
3775 t if t == XML_NAMESPACE_DECL as c_int => {
3776 ns_dump_output(buf, cur as *mut _xmlNs);
3777 }
3778 t if t == XML_ELEMENT_DECL as c_int => {
3779 dump_element_decl(buf, cur as *mut _xmlElement);
3780 }
3781 t if t == XML_ATTRIBUTE_DECL as c_int => {
3782 dump_attribute_decl(buf, cur as *mut _xmlAttribute);
3783 }
3784 t if t == XML_ENTITY_DECL as c_int => {
3785 dump_entity_decl(buf, cur as *mut _xmlEntity);
3786 }
3787 _ => {}
3788 }
3789}
3790
3791pub(crate) unsafe fn serialize_node(
3805 node: *mut _xmlNode,
3806 buf: *mut _xmlBuffer,
3807 format: c_int,
3808 level: c_int,
3809) {
3810 unsafe { serialize_node_opt(node, buf, format, level, ptr::null()) };
3811}
3812
3813pub(crate) unsafe fn serialize_node_opt(
3821 node: *mut _xmlNode,
3822 buf: *mut _xmlBuffer,
3823 format: c_int,
3824 level: c_int,
3825 indent: *const xmlChar,
3826) {
3827 unsafe { serialize_node_opts(node, buf, format, level, indent, 0) };
3828}
3829
3830pub(crate) unsafe fn serialize_node_opts(
3837 node: *mut _xmlNode,
3838 buf: *mut _xmlBuffer,
3839 format: c_int,
3840 level: c_int,
3841 indent: *const xmlChar,
3842 no_decl: c_int,
3843) {
3844 if node.is_null() || buf.is_null() {
3845 return;
3846 }
3847 let parent = unsafe { (*node).parent };
3848 let mut state = DumpState::with_indent(format, indent, no_decl);
3849 let mut lvl = level;
3850 node_dump_internal(buf, node, node, parent, &mut state, &mut lvl);
3851}
3852
3853pub(crate) unsafe fn doc_dump(buf: *mut _xmlBuffer, doc: *mut _xmlDoc) -> c_int {
3863 if buf.is_null() || doc.is_null() {
3864 return -1;
3865 }
3866
3867 let before = io::buf_length(buf);
3868 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
3869 let after = io::buf_length(buf);
3870
3871 if after < 0 || before < 0 {
3872 return -1;
3873 }
3874 after - before
3875}
3876
3877pub(crate) unsafe fn node_dump(
3889 buf: *mut _xmlBuffer,
3890 doc: *mut _xmlDoc,
3891 node: *mut _xmlNode,
3892 level: c_int,
3893 format: c_int,
3894) -> c_int {
3895 let _ = doc; if buf.is_null() || node.is_null() {
3897 return -1;
3898 }
3899
3900 let before = io::buf_length(buf);
3901 serialize_node(node, buf, format, level);
3902 let after = io::buf_length(buf);
3903
3904 if after < 0 || before < 0 {
3905 return -1;
3906 }
3907 after - before
3908}
3909
3910pub(crate) unsafe fn save_doc_to_filename(
3917 doc: *mut _xmlDoc,
3918 filename: *const c_char,
3919 compression: c_int,
3920) -> c_int {
3921 if doc.is_null() || filename.is_null() {
3922 return -1;
3923 }
3924
3925 let out = io::output_buffer_create_filename(filename, ptr::null_mut(), compression);
3926 if out.is_null() {
3927 return -1;
3928 }
3929
3930 let buf = io::buf_create(-1);
3931 if buf.is_null() {
3932 io::output_buffer_close(out);
3933 return -1;
3934 }
3935
3936 let ret = doc_dump(buf, doc);
3937 if ret >= 0 {
3938 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
3940 io::output_buffer_flush(out);
3941 }
3942
3943 io::buf_free(buf);
3944 io::output_buffer_close(out);
3945 ret
3946}
3947
3948pub(crate) unsafe fn save_doc_to_fd(doc: *mut _xmlDoc, fd: c_int, compression: c_int) -> c_int {
3955 if doc.is_null() || fd < 0 {
3956 return -1;
3957 }
3958
3959 let out = io::output_buffer_create_fd(fd, ptr::null_mut());
3960 if out.is_null() {
3961 return -1;
3962 }
3963
3964 let buf = io::buf_create(-1);
3965 if buf.is_null() {
3966 io::output_buffer_close(out);
3967 return -1;
3968 }
3969
3970 let ret = doc_dump(buf, doc);
3971 if ret >= 0 {
3972 io::output_buffer_write_string(out, io::buf_content(buf) as *const c_char);
3973 io::output_buffer_flush(out);
3974 }
3975
3976 io::buf_free(buf);
3977 io::output_buffer_close(out);
3978 ret
3979}
3980
3981pub(crate) unsafe fn save_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 doc_dump(buf, doc)
3998}
3999
4000pub(crate) unsafe fn save_format_doc_to_buf(
4007 doc: *mut _xmlDoc,
4008 buf: *mut _xmlBuffer,
4009 compression: c_int,
4010) -> c_int {
4011 let _ = compression;
4012 if doc.is_null() || buf.is_null() {
4013 return -1;
4014 }
4015
4016 let before = io::buf_length(buf);
4017 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
4018 let after = io::buf_length(buf);
4019
4020 if after < 0 || before < 0 {
4021 return -1;
4022 }
4023 after - before
4024}
4025
4026pub(crate) unsafe fn dump_node(node: *mut _xmlNode) -> *mut xmlChar {
4035 if node.is_null() {
4036 return ptr::null_mut();
4037 }
4038
4039 let buf = io::buf_create(-1);
4040 if buf.is_null() {
4041 return ptr::null_mut();
4042 }
4043
4044 serialize_node(node, buf, 0, 0);
4045
4046 let content = io::buf_content(buf);
4047 if content.is_null() {
4048 io::buf_free(buf);
4049 return ptr::null_mut();
4050 }
4051
4052 let result = dup_xml_str(content);
4054 io::buf_free(buf);
4055 result
4056}
4057
4058pub unsafe fn dump_doc(doc: *mut _xmlDoc) -> *mut xmlChar {
4067 if doc.is_null() {
4068 return ptr::null_mut();
4069 }
4070
4071 let buf = io::buf_create(-1);
4072 if buf.is_null() {
4073 return ptr::null_mut();
4074 }
4075
4076 serialize_node(doc as *mut _xmlNode, buf, 0, 0);
4077
4078 let content = io::buf_content(buf);
4079 if content.is_null() {
4080 io::buf_free(buf);
4081 return ptr::null_mut();
4082 }
4083
4084 let result = dup_xml_str(content);
4085 io::buf_free(buf);
4086 result
4087}
4088
4089pub(crate) unsafe fn xmlNodeDump(
4105 buf: *mut _xmlBuffer,
4106 doc: *mut _xmlDoc,
4107 node: *mut _xmlNode,
4108 level: c_int,
4109 format: c_int,
4110) -> c_int {
4111 node_dump(buf, doc, node, level, format)
4112}
4113
4114pub(crate) unsafe fn xmlDocDump(fp: *mut c_void, doc: *mut _xmlDoc) -> c_int {
4127 if fp.is_null() || doc.is_null() {
4128 return -1;
4129 }
4130
4131 let buf = io::buf_create(-1);
4132 if buf.is_null() {
4133 return -1;
4134 }
4135
4136 let ret = doc_dump(buf, doc);
4137 if ret < 0 {
4138 io::buf_free(buf);
4139 return -1;
4140 }
4141
4142 let content = io::buf_content(buf);
4143 let len = io::buf_length(buf);
4144 if !content.is_null() && len > 0 {
4145 let written = libc::fwrite(
4146 content as *const c_void,
4147 1,
4148 len as usize,
4149 fp as *mut libc::FILE,
4150 );
4151 io::buf_free(buf);
4152 written as c_int
4153 } else {
4154 io::buf_free(buf);
4155 0
4156 }
4157}
4158
4159pub(crate) unsafe fn xmlDocDumpFormatMemory(
4173 doc: *mut _xmlDoc,
4174 mem: *mut *mut xmlChar,
4175 size: *mut c_int,
4176 format: c_int,
4177) {
4178 if doc.is_null() || mem.is_null() || size.is_null() {
4179 return;
4180 }
4181
4182 let buf = io::buf_create(-1);
4183 if buf.is_null() {
4184 unsafe {
4185 *mem = ptr::null_mut();
4186 *size = 0;
4187 }
4188 return;
4189 }
4190
4191 serialize_node(doc as *mut _xmlNode, buf, format, 0);
4192
4193 let content = io::buf_content(buf);
4194 let len = io::buf_length(buf);
4195
4196 if !content.is_null() && len > 0 {
4197 let result = allocator::xmlMallocImpl((len + 1) as usize) as *mut xmlChar;
4199 if !result.is_null() {
4200 ptr::copy_nonoverlapping(content, result, len as usize);
4201 *result.add(len as usize) = 0;
4202 unsafe {
4203 *mem = result;
4204 *size = len;
4205 }
4206 } else {
4207 unsafe {
4208 *mem = ptr::null_mut();
4209 *size = 0;
4210 }
4211 }
4212 } else {
4213 unsafe {
4214 *mem = ptr::null_mut();
4215 *size = 0;
4216 }
4217 }
4218
4219 io::buf_free(buf);
4220}
4221
4222pub(crate) unsafe fn xmlDocDumpMemory(doc: *mut _xmlDoc, mem: *mut *mut xmlChar, size: *mut c_int) {
4236 xmlDocDumpFormatMemory(doc, mem, size, 0)
4237}
4238
4239pub(crate) unsafe fn xmlSaveFile(filename: *const c_char, cur: *mut _xmlDoc) -> c_int {
4252 save_doc_to_filename(cur, filename, 0)
4253}
4254
4255pub(crate) unsafe fn xmlSaveFileEnc(
4269 filename: *const c_char,
4270 cur: *mut _xmlDoc,
4271 encoding: *const c_char,
4272) -> c_int {
4273 let _ = encoding; save_doc_to_filename(cur, filename, 0)
4275}
4276
4277pub(crate) unsafe fn xmlSaveFormatFile(
4290 filename: *const c_char,
4291 cur: *mut _xmlDoc,
4292 format: c_int,
4293) -> c_int {
4294 let _ = format;
4295 save_doc_to_filename(cur, filename, 0)
4296}
4297
4298pub(crate) unsafe fn xmlSaveFormatFileEnc(
4312 filename: *const c_char,
4313 cur: *mut _xmlDoc,
4314 encoding: *const c_char,
4315 format: c_int,
4316) -> c_int {
4317 let _ = encoding;
4318 let _ = format;
4319 save_doc_to_filename(cur, filename, 0)
4320}
4321
4322pub(crate) unsafe fn xmlGetDocCompressMode(doc: *mut _xmlDoc) -> c_int {
4334 if doc.is_null() {
4335 return -1;
4336 }
4337 unsafe { (*doc).compression }
4338}
4339
4340pub(crate) unsafe fn xmlSetDocCompressMode(doc: *mut _xmlDoc, mode: c_int) {
4352 if doc.is_null() {
4353 return;
4354 }
4355 unsafe {
4356 (*doc).compression = mode;
4357 }
4358}
4359
4360#[cfg(test)]
4361mod tests {
4362 use super::*;
4363 use core::ffi::c_void;
4364
4365 fn c_str(s: &str) -> *const xmlChar {
4366 let bytes = s.as_bytes();
4367 let buf = unsafe { allocator::xmlMallocImpl(bytes.len() + 1) as *mut u8 };
4368 if !buf.is_null() {
4369 unsafe {
4370 ptr::copy_nonoverlapping(bytes.as_ptr(), buf, bytes.len());
4371 *buf.add(bytes.len()) = 0;
4372 }
4373 }
4374 buf as *const xmlChar
4375 }
4376
4377 #[test]
4378 fn test_new_free_doc() {
4379 unsafe {
4380 let doc = new_doc(ptr::null());
4381 assert!(!doc.is_null());
4382 assert_eq!((*doc).type_, XML_DOCUMENT_NODE as c_int);
4383 assert_eq!((*doc).standalone, -1);
4384 assert_eq!((*doc).doc, doc);
4385 assert!(!(*doc).version.is_null());
4386 free_doc(doc);
4387 }
4388 }
4389
4390 #[test]
4391 fn test_new_doc_with_version() {
4392 unsafe {
4393 let ver = c_str("2.0");
4394 let doc = new_doc(ver);
4395 assert!(!doc.is_null());
4396 let doc_ver = (*doc).version;
4397 assert!(!doc_ver.is_null());
4398 assert!(crate::abi::exports_xml2::xmlStrEqual(doc_ver, ver,) != 0);
4399 allocator::xmlFreeImpl(ver as *mut c_void);
4400 free_doc(doc);
4401 }
4402 }
4403
4404 #[test]
4405 fn test_new_node() {
4406 unsafe {
4407 let doc = new_doc(ptr::null());
4408 let node = new_node(ptr::null_mut(), c_str("root"));
4409 assert!(!node.is_null());
4410 assert_eq!((*node).type_, XML_ELEMENT_NODE as c_int);
4411 assert!(!(*node).name.is_null());
4412 free_node(node);
4413 free_doc(doc);
4414 }
4415 }
4416
4417 #[test]
4418 fn test_node_get_content_recurses_descendants() {
4419 unsafe {
4424 let doc = new_doc(ptr::null());
4425 let root = new_node(ptr::null_mut(), c_str("library"));
4426 doc_set_root_element(doc, root);
4427 let book = new_child(root, ptr::null_mut(), c_str("book"));
4428 let title = new_child(book, ptr::null_mut(), c_str("title"));
4429 let text = new_text(c_str("Rust"));
4430 add_child(title, text);
4431
4432 let content = node_get_content(book);
4433 assert!(!content.is_null());
4434 let s = core::slice::from_raw_parts(
4435 content,
4436 libc::strlen(content as *const libc::c_char) as usize,
4437 );
4438 assert_eq!(s, b"Rust", "descendant text not concatenated");
4439 allocator::xmlFreeImpl(content as *mut c_void);
4440
4441 free_doc(doc);
4442 }
4443 }
4444
4445 #[test]
4446 fn test_doc_set_root_element() {
4447 unsafe {
4448 let doc = new_doc(ptr::null());
4449 let root = new_node(ptr::null_mut(), c_str("root"));
4450 let old = doc_set_root_element(doc, root);
4451 assert!(old.is_null());
4452 assert_eq!(doc_get_root_element(doc), root);
4453 assert_eq!((*doc).children, root as *mut _xmlNode);
4454 free_doc(doc);
4455 }
4456 }
4457
4458 #[test]
4459 fn test_add_child_and_sibling() {
4460 unsafe {
4461 let doc = new_doc(ptr::null());
4462 let root = new_node(ptr::null_mut(), c_str("root"));
4463 doc_set_root_element(doc, root);
4464
4465 let child1 = new_child(root, ptr::null_mut(), c_str("child1"));
4466 assert!(!child1.is_null());
4467 assert_eq!((*child1).parent, root);
4468 assert_eq!((*root).children, child1);
4469 assert_eq!((*root).last, child1);
4470
4471 let child2 = new_child(root, ptr::null_mut(), c_str("child2"));
4472 assert!(!child2.is_null());
4473 assert_eq!((*child2).parent, root);
4474 assert_eq!((*child1).next, child2);
4475 assert_eq!((*child2).prev, child1);
4476 assert_eq!((*root).last, child2);
4477
4478 let sibling = new_node(ptr::null_mut(), c_str("sibling"));
4480 add_sibling(child2, sibling);
4481 assert_eq!((*child2).next, sibling);
4482 assert_eq!((*sibling).prev, child2);
4483 assert_eq!((*root).last, sibling);
4484
4485 free_doc(doc);
4486 }
4487 }
4488
4489 #[test]
4490 fn test_unlink_node() {
4491 unsafe {
4492 let doc = new_doc(ptr::null());
4493 let root = new_node(ptr::null_mut(), c_str("root"));
4494 doc_set_root_element(doc, root);
4495
4496 let child1 = new_child(root, ptr::null_mut(), c_str("c1"));
4497 let child2 = new_child(root, ptr::null_mut(), c_str("c2"));
4498
4499 unlink_node(child1);
4500 assert!((*child1).parent.is_null());
4501 assert!((*child1).prev.is_null());
4502 assert!((*child1).next.is_null());
4503 assert_eq!((*root).children, child2);
4504 assert_eq!((*root).last, child2);
4505
4506 free_node(child1);
4507 free_doc(doc);
4508 }
4509 }
4510
4511 #[test]
4512 fn test_text_and_comment_nodes() {
4513 unsafe {
4514 let text = new_text(c_str("hello world"));
4515 assert!(!text.is_null());
4516 assert_eq!((*text).type_, XML_TEXT_NODE as c_int);
4517 assert!(!(*text).content.is_null());
4518 free_node(text);
4519
4520 let comment = new_comment(c_str("my comment"));
4521 assert!(!comment.is_null());
4522 assert_eq!((*comment).type_, XML_COMMENT_NODE as c_int);
4523 free_node(comment);
4524
4525 let pi = new_pi(c_str("xml"), c_str("version='1.0'"));
4526 assert!(!pi.is_null());
4527 assert_eq!((*pi).type_, XML_PI_NODE as c_int);
4528 free_node(pi);
4529 }
4530 }
4531
4532 #[test]
4533 fn test_set_and_get_prop() {
4534 unsafe {
4535 let doc = new_doc(ptr::null());
4536 let root = new_node(ptr::null_mut(), c_str("root"));
4537 doc_set_root_element(doc, root);
4538
4539 let attr = set_prop(root, c_str("id"), c_str("42"));
4540 assert!(!attr.is_null());
4541 assert_eq!((*attr).type_, XML_ATTRIBUTE_NODE as c_int);
4542
4543 let value = get_prop(root, c_str("id"));
4544 assert!(!value.is_null());
4545 assert!(crate::abi::exports_xml2::xmlStrEqual(value, c_str("42")) != 0);
4546 allocator::xmlFreeImpl(value as *mut c_void);
4547
4548 free_doc(doc);
4549 }
4550 }
4551
4552 #[test]
4553 fn test_remove_prop() {
4554 unsafe {
4555 let doc = new_doc(ptr::null());
4556 let root = new_node(ptr::null_mut(), c_str("root"));
4557 doc_set_root_element(doc, root);
4558
4559 set_prop(root, c_str("a"), c_str("1"));
4560 set_prop(root, c_str("b"), c_str("2"));
4561
4562 let value = get_prop(root, c_str("a"));
4563 assert!(!value.is_null());
4564 allocator::xmlFreeImpl(value as *mut c_void);
4565
4566 let attr = (*root).properties;
4568 assert!(!attr.is_null());
4569 let result = remove_prop(attr);
4570 assert_eq!(result, 0);
4571
4572 let value2 = get_prop(root, c_str("a"));
4574 assert!(value2.is_null());
4575
4576 free_doc(doc);
4577 }
4578 }
4579
4580 #[test]
4581 fn test_namespace_operations() {
4582 unsafe {
4583 let doc = new_doc(ptr::null());
4584 let root = new_node(ptr::null_mut(), c_str("root"));
4585 doc_set_root_element(doc, root);
4586
4587 let ns = new_ns(root, c_str("http://example.com"), c_str("ex"));
4588 assert!(!ns.is_null());
4589 assert!(!(*root).nsDef.is_null());
4590
4591 set_ns(root, ns);
4592 assert_eq!((*root).ns, ns);
4593
4594 let found = search_ns(doc, root, c_str("ex"));
4595 assert_eq!(found, ns);
4596
4597 let found_href = search_ns_by_href(doc, root, c_str("http://example.com"));
4598 assert_eq!(found_href, ns);
4599
4600 free_doc(doc);
4601 }
4602 }
4603
4604 #[test]
4605 fn test_new_dtd() {
4606 unsafe {
4607 let doc = new_doc(ptr::null());
4608 let dtd = new_dtd(doc, c_str("root"), c_str("-//TEST//DTD"), c_str("test.dtd"));
4609 assert!(!dtd.is_null());
4610 assert_eq!((*dtd).type_, XML_DTD_NODE as c_int);
4611 assert_eq!(get_int_subset(doc), dtd);
4612 free_doc(doc);
4613 }
4614 }
4615
4616 #[test]
4617 fn test_copy_node_deep() {
4618 unsafe {
4619 let doc = new_doc(ptr::null());
4620 let root = new_node(ptr::null_mut(), c_str("root"));
4621 doc_set_root_element(doc, root);
4622 let child = new_child(root, ptr::null_mut(), c_str("child"));
4623
4624 let copy = copy_node(root, 1);
4625 assert!(!copy.is_null());
4626 assert_eq!((*copy).type_, XML_ELEMENT_NODE as c_int);
4627 assert!(!(*copy).children.is_null());
4629 assert_eq!((*(*copy).children).type_, XML_ELEMENT_NODE as c_int);
4630
4631 free_node(copy);
4632 free_doc(doc);
4633 }
4634 }
4635
4636 #[test]
4637 fn test_new_cdata_block() {
4638 unsafe {
4639 let doc = new_doc(ptr::null());
4640 let content = c_str("some <cdata> content");
4641 let cdata = new_cdata_block(doc, content, 20);
4642 assert!(!cdata.is_null());
4643 assert_eq!((*cdata).type_, XML_CDATA_SECTION_NODE as c_int);
4644 free_node(cdata);
4645 free_doc(doc);
4646 }
4647 }
4648
4649 #[test]
4650 fn test_null_handling() {
4651 unsafe {
4652 assert!(new_doc(ptr::null()).is_null() == false); let doc = new_doc(ptr::null());
4654 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());
4659 assert!(add_sibling(ptr::null_mut(), ptr::null_mut()).is_null());
4660 free_doc(doc);
4661 }
4662 }
4663
4664 unsafe fn buf_eq_str(buf: *mut _xmlBuffer, expected: &str) -> bool {
4670 let content = io::buf_content(buf);
4671 if content.is_null() {
4672 return expected.is_empty();
4673 }
4674 let len = io::buf_length(buf) as usize;
4675 if len != expected.len() {
4676 return false;
4677 }
4678 let slice = unsafe { core::slice::from_raw_parts(content, len) };
4679 slice == expected.as_bytes()
4680 }
4681
4682 #[test]
4683 fn test_serialize_empty_document() {
4684 unsafe {
4685 let doc = new_doc(ptr::null());
4686 let buf = io::buf_create(-1);
4687 assert!(!buf.is_null());
4688
4689 let ret = doc_dump(buf, doc);
4690 assert!(ret >= 0);
4691
4692 let expected = "<?xml version=\"1.0\"?>\n";
4696 assert!(buf_eq_str(buf, expected));
4697
4698 io::buf_free(buf);
4699 free_doc(doc);
4700 }
4701 }
4702
4703 #[test]
4704 fn test_serialize_element_with_text() {
4705 unsafe {
4706 let doc = new_doc(ptr::null());
4707 let root = new_node(ptr::null_mut(), c_str("root"));
4708 doc_set_root_element(doc, root);
4709
4710 let text = new_text(c_str("hello world"));
4712 add_child(root, text);
4713
4714 let buf = io::buf_create(-1);
4715 assert!(!buf.is_null());
4716
4717 let ret = doc_dump(buf, doc);
4718 assert!(ret >= 0);
4719
4720 let expected = "<?xml version=\"1.0\"?>\n<root>hello world</root>\n";
4721 assert!(buf_eq_str(buf, expected));
4722
4723 io::buf_free(buf);
4724 free_doc(doc);
4725 }
4726 }
4727
4728 #[test]
4729 fn test_serialize_element_with_attributes() {
4730 unsafe {
4731 let doc = new_doc(ptr::null());
4732 let root = new_node(ptr::null_mut(), c_str("root"));
4733 doc_set_root_element(doc, root);
4734
4735 set_prop(root, c_str("id"), c_str("42"));
4736 set_prop(root, c_str("name"), c_str("test"));
4737
4738 let buf = io::buf_create(-1);
4739 assert!(!buf.is_null());
4740
4741 let ret = doc_dump(buf, doc);
4742 assert!(ret >= 0);
4743
4744 let expected = "<?xml version=\"1.0\"?>\n<root id=\"42\" name=\"test\"/>\n";
4745 assert!(buf_eq_str(buf, expected));
4746
4747 io::buf_free(buf);
4748 free_doc(doc);
4749 }
4750 }
4751
4752 #[test]
4753 fn test_serialize_nested_elements() {
4754 unsafe {
4755 let doc = new_doc(ptr::null());
4756 let root = new_node(ptr::null_mut(), c_str("root"));
4757 doc_set_root_element(doc, root);
4758
4759 let child = new_child(root, ptr::null_mut(), c_str("child"));
4760 let grandchild = new_child(child, ptr::null_mut(), c_str("gc"));
4761 let text = new_text(c_str("text"));
4762 add_child(grandchild, text);
4763
4764 let buf = io::buf_create(-1);
4765 assert!(!buf.is_null());
4766
4767 let ret = doc_dump(buf, doc);
4768 assert!(ret >= 0);
4769
4770 let expected = "<?xml version=\"1.0\"?>\n<root><child><gc>text</gc></child></root>\n";
4771 assert!(buf_eq_str(buf, expected));
4772
4773 io::buf_free(buf);
4774 free_doc(doc);
4775 }
4776 }
4777
4778 #[test]
4779 fn test_serialize_with_formatting() {
4780 unsafe {
4781 let doc = new_doc(ptr::null());
4782 let root = new_node(ptr::null_mut(), c_str("root"));
4783 doc_set_root_element(doc, root);
4784
4785 let child = new_child(root, ptr::null_mut(), c_str("child"));
4786 let text = new_text(c_str("text"));
4787 add_child(child, text);
4788
4789 let buf = io::buf_create(-1);
4790 assert!(!buf.is_null());
4791
4792 serialize_node(doc as *mut _xmlNode, buf, 1, 0);
4793
4794 let expected = "<?xml version=\"1.0\"?>\n<root>\n <child>text</child>\n</root>\n";
4795 assert!(buf_eq_str(buf, expected));
4796
4797 io::buf_free(buf);
4798 free_doc(doc);
4799 }
4800 }
4801
4802 #[test]
4803 fn test_serialize_escape_ampersand() {
4804 unsafe {
4805 let doc = new_doc(ptr::null());
4806 let root = new_node(ptr::null_mut(), c_str("root"));
4807 doc_set_root_element(doc, root);
4808
4809 let text = new_text(c_str("a & b"));
4810 add_child(root, text);
4811
4812 let buf = io::buf_create(-1);
4813 assert!(!buf.is_null());
4814
4815 let ret = doc_dump(buf, doc);
4816 assert!(ret >= 0);
4817
4818 let expected = "<?xml version=\"1.0\"?>\n<root>a & b</root>\n";
4819 assert!(buf_eq_str(buf, expected));
4820
4821 io::buf_free(buf);
4822 free_doc(doc);
4823 }
4824 }
4825
4826 #[test]
4827 fn test_serialize_escape_angle_brackets() {
4828 unsafe {
4829 let doc = new_doc(ptr::null());
4830 let root = new_node(ptr::null_mut(), c_str("root"));
4831 doc_set_root_element(doc, root);
4832
4833 let text = new_text(c_str("x < y > z"));
4834 add_child(root, text);
4835
4836 let buf = io::buf_create(-1);
4837 assert!(!buf.is_null());
4838
4839 let ret = doc_dump(buf, doc);
4840 assert!(ret >= 0);
4841
4842 let expected = "<?xml version=\"1.0\"?>\n<root>x < y > z</root>\n";
4843 assert!(buf_eq_str(buf, expected));
4844
4845 io::buf_free(buf);
4846 free_doc(doc);
4847 }
4848 }
4849
4850 #[test]
4851 fn test_serialize_comment() {
4852 unsafe {
4853 let doc = new_doc(ptr::null());
4854 let root = new_node(ptr::null_mut(), c_str("root"));
4855 doc_set_root_element(doc, root);
4856
4857 let comment = new_comment(c_str("my comment"));
4858 add_child(root, comment);
4859
4860 let buf = io::buf_create(-1);
4861 assert!(!buf.is_null());
4862
4863 let ret = doc_dump(buf, doc);
4864 assert!(ret >= 0);
4865
4866 let expected = "<?xml version=\"1.0\"?>\n<root><!--my comment--></root>\n";
4867 assert!(buf_eq_str(buf, expected));
4868
4869 io::buf_free(buf);
4870 free_doc(doc);
4871 }
4872 }
4873
4874 #[test]
4875 fn test_serialize_pi() {
4876 unsafe {
4877 let doc = new_doc(ptr::null());
4878 let root = new_node(ptr::null_mut(), c_str("root"));
4879 doc_set_root_element(doc, root);
4880
4881 let pi = new_pi(
4882 c_str("xml-stylesheet"),
4883 c_str("href=\"style.xsl\" type=\"text/xsl\""),
4884 );
4885 add_child(root, pi);
4886
4887 let buf = io::buf_create(-1);
4888 assert!(!buf.is_null());
4889
4890 let ret = doc_dump(buf, doc);
4891 assert!(ret >= 0);
4892
4893 let expected = "<?xml version=\"1.0\"?>\n<root><?xml-stylesheet href=\"style.xsl\" type=\"text/xsl\"?></root>\n";
4894 assert!(buf_eq_str(buf, expected));
4895
4896 io::buf_free(buf);
4897 free_doc(doc);
4898 }
4899 }
4900
4901 #[test]
4902 fn test_serialize_self_closing() {
4903 unsafe {
4904 let doc = new_doc(ptr::null());
4905 let root = new_node(ptr::null_mut(), c_str("empty"));
4906 doc_set_root_element(doc, root);
4907
4908 let buf = io::buf_create(-1);
4909 assert!(!buf.is_null());
4910
4911 let ret = doc_dump(buf, doc);
4912 assert!(ret >= 0);
4913
4914 let expected = "<?xml version=\"1.0\"?>\n<empty/>\n";
4915 assert!(buf_eq_str(buf, expected));
4916
4917 io::buf_free(buf);
4918 free_doc(doc);
4919 }
4920 }
4921
4922 #[test]
4923 fn test_dump_node_to_string() {
4924 unsafe {
4925 let node = new_node(ptr::null_mut(), c_str("foo"));
4926 let text = new_text(c_str("bar"));
4927 add_child(node, text);
4928
4929 let result = dump_node(node);
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 assert_eq!(slice, b"<foo>bar</foo>");
4935
4936 allocator::xmlFreeImpl(result as *mut c_void);
4937 free_node(node);
4938 }
4939 }
4940
4941 #[test]
4942 fn test_dump_doc_to_string() {
4943 unsafe {
4944 let doc = new_doc(ptr::null());
4945 let root = new_node(ptr::null_mut(), c_str("root"));
4946 doc_set_root_element(doc, root);
4947
4948 let result = dump_doc(doc);
4949 assert!(!result.is_null());
4950
4951 let len = xml_strlen(result);
4952 let slice = unsafe { core::slice::from_raw_parts(result, len as usize) };
4953 let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
4954 assert_eq!(slice, expected.as_bytes());
4955
4956 allocator::xmlFreeImpl(result as *mut c_void);
4957 free_doc(doc);
4958 }
4959 }
4960
4961 #[test]
4962 fn test_xmlDocDumpFormatMemory() {
4963 unsafe {
4964 let doc = new_doc(ptr::null());
4965 let root = new_node(ptr::null_mut(), c_str("root"));
4966 doc_set_root_element(doc, root);
4967
4968 let mut mem: *mut xmlChar = ptr::null_mut();
4969 let mut size: c_int = 0;
4970
4971 xmlDocDumpFormatMemory(doc, &mut mem, &mut size, 0);
4972
4973 assert!(!mem.is_null());
4974 assert!(size > 0);
4975
4976 let slice = unsafe { core::slice::from_raw_parts(mem, size as usize) };
4977 let expected = "<?xml version=\"1.0\"?>\n<root/>\n";
4980 assert_eq!(slice, expected.as_bytes());
4981
4982 allocator::xmlFreeImpl(mem as *mut c_void);
4983 free_doc(doc);
4984 }
4985 }
4986
4987 #[test]
4988 fn test_serialize_escape_attribute() {
4989 unsafe {
4990 let doc = new_doc(ptr::null());
4991 let root = new_node(ptr::null_mut(), c_str("root"));
4992 doc_set_root_element(doc, root);
4993
4994 set_prop(root, c_str("desc"), c_str("a < b & c \"quoted\""));
4996
4997 let buf = io::buf_create(-1);
4998 assert!(!buf.is_null());
4999
5000 let ret = doc_dump(buf, doc);
5001 assert!(ret >= 0);
5002
5003 let expected =
5004 "<?xml version=\"1.0\"?>\n<root desc=\"a < b & c "quoted"\"/>\n";
5005 assert!(buf_eq_str(buf, expected));
5006
5007 io::buf_free(buf);
5008 free_doc(doc);
5009 }
5010 }
5011}