1use crate::abi::allocator::xmlFree;
9use crate::abi::structs::{_xmlAttr, _xmlDoc, _xmlNode, _xmlNs};
10use core::ffi::{c_char, c_int, c_void};
11use core::ptr;
12
13const MAX_DEPTH: c_int = 100;
15
16fn is_xinclude_node(node: *mut _xmlNode) -> bool {
20 if node.is_null() {
21 return false;
22 }
23 unsafe {
24 let ns = (*node).ns;
25 if ns.is_null() {
26 return false;
27 }
28 let ns_href = (*ns).href;
29 let ns_prefix = (*ns).prefix;
30 if ns_href.is_null() {
31 return false;
32 }
33 let href = core::slice::from_raw_parts(ns_href as *const u8, 30);
35 let xi_ns = b"http://www.w3.org/2001/XInclude\0";
36 let mut matches = true;
37 for i in 0..30 {
38 if i >= href.len() || href[i] != xi_ns[i] {
39 matches = false;
40 break;
41 }
42 }
43 if !matches {
44 return false;
45 }
46 let name_bytes = if !(*node).name.is_null() {
48 core::slice::from_raw_parts((*node).name as *const u8, 8)
49 } else {
50 return false;
51 };
52 name_bytes.len() >= 7 && &name_bytes[..7] == b"include"
53 }
54}
55
56#[no_mangle]
60pub unsafe extern "C" fn xmlBoolToText(boolval: c_int) -> *const c_char {
61 if boolval != 0 {
62 b"true\0".as_ptr() as *const c_char
63 } else {
64 b"false\0".as_ptr() as *const c_char
65 }
66}
67
68#[no_mangle]
72pub unsafe extern "C" fn xmlDebugDumpString(output: *mut _IO_FILE, str_val: *const u8) {
73 if output.is_null() {
74 return;
75 }
76 if str_val.is_null() {
77 unsafe {
78 libc::fprintf(output, b"(null)\0".as_ptr() as *const c_char);
79 }
80 return;
81 }
82 unsafe {
83 let mut i = 0;
84 loop {
85 let c = *str_val.add(i);
86 if c == 0 {
87 break;
88 }
89 if c == b'\n' {
90 libc::fprintf(output, b"\\n\0".as_ptr() as *const c_char);
91 } else if c == b'\r' {
92 libc::fprintf(output, b"\\r\0".as_ptr() as *const c_char);
93 } else if c == b'\t' {
94 libc::fprintf(output, b"\\t\0".as_ptr() as *const c_char);
95 } else if c < 0x20 || c >= 0x7f {
96 libc::fprintf(output, b"\\x%02x\0".as_ptr() as *const c_char, c as c_int);
97 } else {
98 libc::fprintf(output, b"%c\0".as_ptr() as *const c_char, c as c_int);
99 }
100 i += 1;
101 }
102 }
103}
104
105#[no_mangle]
109pub unsafe extern "C" fn xmlDebugDumpAttr(
110 output: *mut _IO_FILE,
111 attr: *mut _xmlAttr,
112 depth: c_int,
113) {
114 if output.is_null() || attr.is_null() {
115 return;
116 }
117 unsafe {
118 for _ in 0..depth {
119 libc::fprintf(output, b" \0".as_ptr() as *const c_char);
120 }
121 libc::fprintf(output, b"ATTRIBUTE \0".as_ptr() as *const c_char);
122 xmlDebugDumpString(output, (*attr).name as *const u8);
123 if !(*attr).ns.is_null() && !(*(*attr).ns).prefix.is_null() {
124 libc::fprintf(
125 output,
126 b":%s\0".as_ptr() as *const c_char,
127 (*(*attr).ns).prefix,
128 );
129 }
130 libc::fprintf(output, b"\n\0".as_ptr() as *const c_char);
131 if !(*attr).children.is_null() {
132 for _ in 0..(depth + 1) {
133 libc::fprintf(output, b" \0".as_ptr() as *const c_char);
134 }
135 libc::fprintf(output, b"VALUE: \0".as_ptr() as *const c_char);
136 let text = (*attr).children;
137 if !text.is_null() && !(*text).content.is_null() {
138 xmlDebugDumpString(output, (*text).content as *const u8);
139 }
140 libc::fprintf(output, b"\n\0".as_ptr() as *const c_char);
141 }
142 }
143}
144
145#[no_mangle]
149pub unsafe extern "C" fn xmlDebugDumpAttrList(
150 output: *mut _IO_FILE,
151 attr: *mut _xmlAttr,
152 depth: c_int,
153) {
154 if output.is_null() {
155 return;
156 }
157 let mut cur = attr;
158 while !cur.is_null() {
159 unsafe {
160 xmlDebugDumpAttr(output, cur, depth);
161 cur = (*cur).next;
162 }
163 }
164}
165
166#[no_mangle]
170pub unsafe extern "C" fn xmlDebugDumpOneNode(
171 output: *mut _IO_FILE,
172 node: *mut _xmlNode,
173 depth: c_int,
174) {
175 if output.is_null() || node.is_null() {
176 return;
177 }
178 unsafe {
179 for _ in 0..depth {
181 libc::fprintf(output, b" \0".as_ptr() as *const c_char);
182 }
183
184 match (*node).type_ {
186 1 => {
187 libc::fprintf(output, b"ELEMENT \0".as_ptr() as *const c_char);
189 xmlDebugDumpString(output, (*node).name as *const u8);
190 if !(*node).ns.is_null() {
191 if !(*(*node).ns).prefix.is_null() {
192 libc::fprintf(
193 output,
194 b" (ns=%s)\0".as_ptr() as *const c_char,
195 (*(*node).ns).prefix,
196 );
197 }
198 }
199 }
200 2 => {
201 libc::fprintf(output, b"ATTRIBUTE \0".as_ptr() as *const c_char);
203 xmlDebugDumpString(output, (*node).name as *const u8);
204 }
205 3 => {
206 libc::fprintf(output, b"TEXT\0".as_ptr() as *const c_char);
208 if !(*node).content.is_null() {
209 libc::fprintf(output, b"\n\0".as_ptr() as *const c_char);
210 for _ in 0..(depth + 1) {
211 libc::fprintf(output, b" \0".as_ptr() as *const c_char);
212 }
213 libc::fprintf(output, b"CONTENT: \0".as_ptr() as *const c_char);
214 xmlDebugDumpString(output, (*node).content as *const u8);
215 }
216 }
217 4 => {
218 libc::fprintf(output, b"CDATA\0".as_ptr() as *const c_char);
220 }
221 5 => {
222 libc::fprintf(output, b"ENTITY_REF \0".as_ptr() as *const c_char);
224 xmlDebugDumpString(output, (*node).name as *const u8);
225 }
226 6 => {
227 libc::fprintf(output, b"ENTITY \0".as_ptr() as *const c_char);
229 xmlDebugDumpString(output, (*node).name as *const u8);
230 }
231 7 => {
232 libc::fprintf(output, b"PI \0".as_ptr() as *const c_char);
234 xmlDebugDumpString(output, (*node).name as *const u8);
235 }
236 8 => {
237 libc::fprintf(output, b"COMMENT\0".as_ptr() as *const c_char);
239 }
240 9 => {
241 libc::fprintf(output, b"DOCUMENT\0".as_ptr() as *const c_char);
243 }
244 10 => {
245 libc::fprintf(output, b"DOCTYPE\0".as_ptr() as *const c_char);
247 }
248 11 => {
249 libc::fprintf(output, b"DOCUMENT_FRAG\0".as_ptr() as *const c_char);
251 }
252 13 => {
253 libc::fprintf(output, b"NAMESPACE\0".as_ptr() as *const c_char);
255 if !(*node).ns.is_null() && !(*(*node).ns).prefix.is_null() {
256 libc::fprintf(
257 output,
258 b" %s=%s\0".as_ptr() as *const c_char,
259 (*(*node).ns).prefix,
260 (*(*node).ns).href,
261 );
262 }
263 }
264 14 => {
265 if is_xinclude_node(node) {
267 libc::fprintf(output, b"XINCLUDE\0".as_ptr() as *const c_char);
268 } else {
269 libc::fprintf(output, b"XINCLUDE_START\0".as_ptr() as *const c_char);
270 }
271 }
272 15 => {
273 libc::fprintf(output, b"XINCLUDE_END\0".as_ptr() as *const c_char);
275 }
276 _ => {
277 libc::fprintf(
278 output,
279 b"UNKNOWN (%d)\0".as_ptr() as *const c_char,
280 (*node).type_ as c_int,
281 );
282 }
283 }
284 libc::fprintf(output, b"\n\0".as_ptr() as *const c_char);
285
286 if !(*node).properties.is_null() {
288 xmlDebugDumpAttrList(output, (*node).properties, depth + 1);
289 }
290 }
291}
292
293#[no_mangle]
297pub unsafe extern "C" fn xmlDebugDumpNode(
298 output: *mut _IO_FILE,
299 node: *mut _xmlNode,
300 depth: c_int,
301) {
302 if output.is_null() || node.is_null() || depth > MAX_DEPTH {
303 return;
304 }
305 unsafe {
306 xmlDebugDumpOneNode(output, node, depth);
307
308 if !(*node).children.is_null() {
310 let mut child = (*node).children;
311 while !child.is_null() {
312 xmlDebugDumpNode(output, child, depth + 1);
313 child = (*child).next;
314 }
315 }
316 }
317}
318
319#[no_mangle]
323pub unsafe extern "C" fn xmlDebugDumpNodeList(
324 output: *mut _IO_FILE,
325 node: *mut _xmlNode,
326 depth: c_int,
327) {
328 if output.is_null() {
329 return;
330 }
331 let mut cur = node;
332 while !cur.is_null() {
333 unsafe {
334 xmlDebugDumpNode(output, cur, depth);
335 cur = (*cur).next;
336 }
337 }
338}
339
340#[no_mangle]
344pub unsafe extern "C" fn xmlDebugDumpDocument(output: *mut _IO_FILE, doc: *mut _xmlDoc) {
345 if output.is_null() || doc.is_null() {
346 return;
347 }
348 unsafe {
349 libc::fprintf(output, b"DOCUMENT\0".as_ptr() as *const c_char);
350 if !(*doc).name.is_null() {
351 libc::fprintf(output, b" %s\0".as_ptr() as *const c_char, (*doc).name);
352 }
353 if !(*doc).URL.is_null() {
354 libc::fprintf(output, b" URL=%s\0".as_ptr() as *const c_char, (*doc).URL);
355 }
356 libc::fprintf(output, b"\n\0".as_ptr() as *const c_char);
357
358 if !(*doc).children.is_null() {
360 let mut child = (*doc).children;
361 while !child.is_null() {
362 xmlDebugDumpNode(output, child, 1);
363 child = (*child).next;
364 }
365 }
366 }
367}
368
369#[no_mangle]
373pub unsafe extern "C" fn xmlDebugDumpDocumentHead(output: *mut _IO_FILE, doc: *mut _xmlDoc) {
374 if output.is_null() || doc.is_null() {
375 return;
376 }
377 unsafe {
378 xmlDebugDumpDocument(output, doc);
379 }
380}
381
382#[no_mangle]
386pub unsafe extern "C" fn xmlLsCountNode(node: *mut _xmlNode) -> c_int {
387 if node.is_null() {
388 return 0;
389 }
390 let mut count: c_int = 0;
391 let mut cur = node;
392 while !cur.is_null() {
393 count += 1;
394 unsafe {
395 cur = (*cur).next;
396 }
397 }
398 count
399}
400
401#[no_mangle]
405pub unsafe extern "C" fn xmlLsOneNode(output: *mut _IO_FILE, node: *mut _xmlNode) {
406 if output.is_null() || node.is_null() {
407 return;
408 }
409 unsafe {
410 match (*node).type_ {
411 1 => {
412 libc::fprintf(output, b"E \0".as_ptr() as *const c_char);
414 if !(*node).ns.is_null() && !(*(*node).ns).prefix.is_null() {
415 libc::fprintf(
416 output,
417 b"%s:\0".as_ptr() as *const c_char,
418 (*(*node).ns).prefix,
419 );
420 }
421 xmlDebugDumpString(output, (*node).name as *const u8);
422 }
423 2 => {
424 libc::fprintf(output, b"A \0".as_ptr() as *const c_char);
425 xmlDebugDumpString(output, (*node).name as *const u8);
426 }
427 3 => {
428 libc::fprintf(output, b"T \0".as_ptr() as *const c_char);
429 if !(*node).content.is_null() {
430 xmlDebugDumpString(output, (*node).content as *const u8);
431 }
432 }
433 4 => {
434 libc::fprintf(output, b"C \0".as_ptr() as *const c_char);
435 }
436 5 => {
437 libc::fprintf(output, b"E \0".as_ptr() as *const c_char);
438 xmlDebugDumpString(output, (*node).name as *const u8);
439 }
440 6 => {
441 libc::fprintf(output, b"E \0".as_ptr() as *const c_char);
442 xmlDebugDumpString(output, (*node).name as *const u8);
443 }
444 7 => {
445 libc::fprintf(output, b"PI \0".as_ptr() as *const c_char);
446 xmlDebugDumpString(output, (*node).name as *const u8);
447 }
448 8 => {
449 libc::fprintf(output, b"C \0".as_ptr() as *const c_char);
450 }
451 9 => {
452 libc::fprintf(output, b"D \0".as_ptr() as *const c_char);
453 }
454 10 => {
455 libc::fprintf(output, b"DTD \0".as_ptr() as *const c_char);
456 }
457 14 => {
458 libc::fprintf(output, b"X \0".as_ptr() as *const c_char);
459 }
460 _ => {
461 libc::fprintf(
462 output,
463 b"? (%d)\0".as_ptr() as *const c_char,
464 (*node).type_ as c_int,
465 );
466 }
467 }
468 libc::fprintf(output, b"\n\0".as_ptr() as *const c_char);
469 }
470}
471
472pub type _IO_FILE = libc::FILE;
477
478#[cfg(test)]
483mod tests {
484 use super::*;
485 use crate::abi::allocator::xmlMalloc;
486 use crate::abi::structs::*;
487 use crate::abi::types::xmlChar;
488 use crate::xml::tree::*;
489
490 unsafe fn create_test_doc() -> *mut _xmlDoc {
492 let doc = new_doc(b"1.0\0".as_ptr() as *const xmlChar);
493 let root = new_node(ptr::null_mut(), b"root\0".as_ptr() as *const xmlChar);
494 doc_set_root_element(doc, root);
495 let child = new_child(root, ptr::null_mut(), b"child\0".as_ptr() as *const xmlChar);
496 set_prop(
498 child,
499 b"attr1\0".as_ptr() as *const xmlChar,
500 b"value1\0".as_ptr() as *const xmlChar,
501 );
502 doc
503 }
504
505 #[test]
506 fn test_xml_bool_to_text() {
507 unsafe {
508 let t = xmlBoolToText(1);
509 assert!(!t.is_null());
510 let f = xmlBoolToText(0);
511 assert!(!f.is_null());
512 assert_eq!(*t as u8, b't');
514 assert_eq!(*f as u8, b'f');
515 }
516 }
517
518 #[test]
519 fn test_debug_dump_string_null() {
520 unsafe {
521 xmlDebugDumpString(ptr::null_mut(), ptr::null());
523 let f = libc::fmemopen(ptr::null_mut(), 0, b"w\0".as_ptr() as *const c_char);
525 if !f.is_null() {
526 xmlDebugDumpString(f, ptr::null());
527 libc::fclose(f);
528 }
529 }
530 }
531
532 #[test]
533 fn test_debug_dump_document_null() {
534 unsafe {
535 xmlDebugDumpDocument(ptr::null_mut(), ptr::null_mut());
536 let f = libc::fmemopen(ptr::null_mut(), 0, b"w\0".as_ptr() as *const c_char);
537 if !f.is_null() {
538 xmlDebugDumpDocument(f, ptr::null_mut());
539 libc::fclose(f);
540 }
541 }
542 }
543
544 #[test]
545 fn test_debug_dump_node_null() {
546 unsafe {
547 xmlDebugDumpNode(ptr::null_mut(), ptr::null_mut(), 0);
548 let f = libc::fmemopen(ptr::null_mut(), 0, b"w\0".as_ptr() as *const c_char);
549 if !f.is_null() {
550 xmlDebugDumpNode(f, ptr::null_mut(), 0);
551 libc::fclose(f);
552 }
553 }
554 }
555
556 #[test]
557 fn test_ls_count_node() {
558 unsafe {
559 let node = new_node(ptr::null_mut(), b"test\0".as_ptr() as *const xmlChar);
560 assert!(!node.is_null());
561 let count = xmlLsCountNode(node);
562 assert_eq!(count, 1);
563
564 let sibling = new_node(ptr::null_mut(), b"sibling\0".as_ptr() as *const xmlChar);
566 add_sibling(node, sibling);
567 let count = xmlLsCountNode(node);
568 assert_eq!(count, 2);
569
570 free_node(node);
571 }
572 }
573
574 #[test]
575 fn test_debug_dump_attr_null() {
576 unsafe {
577 xmlDebugDumpAttr(ptr::null_mut(), ptr::null_mut(), 0);
578 let f = libc::fmemopen(ptr::null_mut(), 0, b"w\0".as_ptr() as *const c_char);
579 if !f.is_null() {
580 xmlDebugDumpAttr(f, ptr::null_mut(), 0);
581 libc::fclose(f);
582 }
583 }
584 }
585
586 #[test]
587 fn test_debug_dump_attr_list_null() {
588 unsafe {
589 xmlDebugDumpAttrList(ptr::null_mut(), ptr::null_mut(), 0);
590 }
591 }
592
593 #[test]
594 fn test_debug_dump_node_list_null() {
595 unsafe {
596 xmlDebugDumpNodeList(ptr::null_mut(), ptr::null_mut(), 0);
597 }
598 }
599
600 #[test]
601 fn test_ls_one_node_null() {
602 unsafe {
603 xmlLsOneNode(ptr::null_mut(), ptr::null_mut());
604 let f = libc::fmemopen(ptr::null_mut(), 0, b"w\0".as_ptr() as *const c_char);
605 if !f.is_null() {
606 xmlLsOneNode(f, ptr::null_mut());
607 libc::fclose(f);
608 }
609 }
610 }
611
612 #[test]
613 fn test_dump_document_head_null() {
614 unsafe {
615 xmlDebugDumpDocumentHead(ptr::null_mut(), ptr::null_mut());
616 }
617 }
618
619 #[test]
620 fn test_ls_count_node_null() {
621 assert_eq!(unsafe { xmlLsCountNode(ptr::null_mut()) }, 0);
622 }
623}