1#![allow(
10 clippy::cast_possible_truncation,
11 clippy::cast_sign_loss,
12 clippy::cast_ptr_alignment,
13 clippy::missing_safety_doc
14)]
15
16use std::ffi::CStr;
17use std::os::raw::{c_char, c_int, c_uint, c_ulong, c_void};
18use std::ptr;
19
20use libc;
21
22use crate::abi::allocator::{xmlFreeImpl, xmlMallocImpl, xmlReallocImpl};
23use crate::abi::callbacks::{
24 xmlInputCloseCallback, xmlInputReadCallback, xmlOutputCloseCallback, xmlOutputWriteCallback,
25};
26use crate::abi::structs::{
27 _xmlBuf, _xmlBuffer, _xmlCharEncodingHandler, _xmlOutputBuffer, _xmlParserInputBuffer,
28};
29use crate::abi::types::{xmlChar, xmlCharEncoding, xmlCharPtr};
30use crate::xml::encoding;
31
32pub(crate) const DEFAULT_BUFFER_SIZE: c_uint = 4000;
38
39const MIN_BUFFER_SIZE: c_uint = 256;
41
42const XML_BUFFER_ALLOC_DOUBLEIT: c_int = 0;
44
45const XML_BUFFER_ALLOC_EXACT: c_int = 1;
47
48const XML_BUFFER_ALLOC_IMMUTABLE: c_int = 2;
50
51pub(crate) fn buf_create(size: c_int) -> *mut _xmlBuffer {
62 let buf_size = if size <= 0 {
63 DEFAULT_BUFFER_SIZE
64 } else {
65 size as c_uint
66 };
67
68 let buf_size = buf_size.max(MIN_BUFFER_SIZE);
70
71 let buf = unsafe { xmlMallocImpl(size_of::<_xmlBuffer>()) as *mut _xmlBuffer };
72 if buf.is_null() {
73 return ptr::null_mut();
74 }
75
76 let content = unsafe { xmlMallocImpl(buf_size as usize) as *mut xmlChar };
77 if content.is_null() {
78 unsafe { xmlFreeImpl(buf as *mut c_void) };
79 return ptr::null_mut();
80 }
81
82 unsafe {
84 ptr::write(content, 0);
85 }
86
87 unsafe {
88 ptr::write(
89 buf,
90 _xmlBuffer {
91 content,
92 use_: 0,
93 size: buf_size,
94 alloc: XML_BUFFER_ALLOC_DOUBLEIT,
95 contentIO: content, },
97 );
98 }
99
100 buf
101}
102
103pub(crate) fn buf_create_static(str: *const xmlChar, size: c_int) -> *mut _xmlBuffer {
111 if str.is_null() {
112 return ptr::null_mut();
113 }
114
115 let len = if size <= 0 {
116 let mut len: c_uint = 0;
118 unsafe {
119 while *str.add(len as usize) != 0 {
120 len += 1;
121 }
122 }
123 len
124 } else {
125 size as c_uint
126 };
127
128 let buf = unsafe { xmlMallocImpl(size_of::<_xmlBuffer>()) as *mut _xmlBuffer };
129 if buf.is_null() {
130 return ptr::null_mut();
131 }
132
133 unsafe {
134 ptr::write(
135 buf,
136 _xmlBuffer {
137 content: str as *mut xmlChar,
138 use_: len,
139 size: len + 1, alloc: XML_BUFFER_ALLOC_IMMUTABLE,
141 contentIO: ptr::null_mut(),
142 },
143 );
144 }
145
146 buf
147}
148
149pub(crate) fn buf_free(buf: *mut _xmlBuffer) {
154 if buf.is_null() {
155 return;
156 }
157
158 unsafe {
159 let alloc = (*buf).alloc;
160 let content = (*buf).content;
161 let content_io = (*buf).contentIO;
162
163 if alloc != XML_BUFFER_ALLOC_IMMUTABLE {
164 let base = if !content_io.is_null() {
168 content_io
169 } else {
170 content
171 };
172 if !base.is_null() {
173 xmlFreeImpl(base as *mut c_void);
174 }
175 }
176
177 xmlFreeImpl(buf as *mut c_void);
178 }
179}
180
181pub(crate) fn buf_empty(buf: *mut _xmlBuffer) {
185 if buf.is_null() {
186 return;
187 }
188
189 unsafe {
190 (*buf).use_ = 0;
191 if !(*buf).content.is_null() {
192 ptr::write((*buf).content, 0);
193 }
194 }
195}
196
197pub(crate) fn buf_content(buf: *mut _xmlBuffer) -> *mut xmlChar {
199 if buf.is_null() {
200 return ptr::null_mut();
201 }
202 unsafe { (*buf).content }
203}
204
205pub(crate) fn buf_length(buf: *mut _xmlBuffer) -> c_int {
207 if buf.is_null() {
208 return -1;
209 }
210 unsafe { (*buf).use_ as c_int }
211}
212
213pub(crate) fn buf_add(buf: *mut _xmlBuffer, str: *const xmlChar, len: c_int) -> c_int {
218 if buf.is_null() || str.is_null() || len <= 0 {
219 return 0;
220 }
221
222 let len = len as c_uint;
223 let b = unsafe { &mut *buf };
224
225 if b.alloc == XML_BUFFER_ALLOC_IMMUTABLE {
227 return -1;
228 }
229
230 let needed = b.use_.saturating_add(len).saturating_add(1);
232 if needed > b.size {
233 let new_size = if b.alloc == XML_BUFFER_ALLOC_EXACT {
235 needed
236 } else {
237 let mut doubled = b.size.saturating_mul(2).max(MIN_BUFFER_SIZE);
239 while doubled < needed {
240 doubled = doubled.saturating_mul(2);
241 }
242 doubled
243 };
244
245 let new_content =
246 unsafe { xmlReallocImpl(b.content as *mut c_void, new_size as usize) as *mut xmlChar };
247 if new_content.is_null() {
248 return -1;
249 }
250 b.content = new_content;
251 b.contentIO = new_content; b.size = new_size;
253 }
254
255 unsafe {
257 ptr::copy_nonoverlapping(str, b.content.add(b.use_ as usize), len as usize);
258 }
259 b.use_ = b.use_.saturating_add(len);
260
261 unsafe {
263 ptr::write(b.content.add(b.use_ as usize), 0);
264 }
265
266 len as c_int
267}
268
269pub(crate) fn buf_cat(buf: *mut _xmlBuffer, str: *const xmlChar) -> c_int {
271 if buf.is_null() || str.is_null() {
272 return -1;
273 }
274
275 let len = unsafe {
277 let mut i: c_uint = 0;
278 while *str.add(i as usize) != 0 {
279 i += 1;
280 }
281 i
282 };
283
284 buf_add(buf, str, len as c_int)
285}
286
287pub(crate) fn buf_ccat(buf: *mut _xmlBuffer, c: xmlChar) -> c_int {
289 buf_add(buf, &c as *const xmlChar, 1)
290}
291
292pub(crate) fn buf_shrink(buf: *mut _xmlBuffer, len: c_uint) -> c_int {
297 if buf.is_null() {
298 return -1;
299 }
300
301 let b = unsafe { &mut *buf };
302 if b.use_ == 0 {
303 return 0;
304 }
305
306 b.use_ = if len >= b.use_ { 0 } else { b.use_ - len };
307
308 unsafe {
310 ptr::write(b.content.add(b.use_ as usize), 0);
311 }
312
313 b.use_ as c_int
314}
315
316pub(crate) fn buf_add_head(buf: *mut _xmlBuffer, str: *const xmlChar, len: c_int) -> c_int {
323 if buf.is_null() || str.is_null() || len <= 0 {
324 return -1;
325 }
326 let len = len as c_uint;
327 unsafe {
328 let b = &mut *buf;
329 let needed = b.use_.saturating_add(len).saturating_add(1);
330 if needed > b.size {
331 let new_size = needed.saturating_mul(2).max(MIN_BUFFER_SIZE);
332 let new_content =
333 xmlReallocImpl(b.content as *mut c_void, new_size as usize) as *mut xmlChar;
334 if new_content.is_null() {
335 return -1;
336 }
337 b.content = new_content;
338 b.contentIO = new_content;
339 b.size = new_size;
340 }
341 if b.use_ > 0 {
343 core::ptr::copy(b.content, b.content.add(len as usize), b.use_ as usize);
344 }
345 core::ptr::copy_nonoverlapping(str, b.content, len as usize);
347 b.use_ = b.use_.saturating_add(len);
348 *b.content.add(b.use_ as usize) = 0;
349 }
350 0
351}
352
353pub(crate) fn buf_grow(buf: *mut _xmlBuffer, size: c_uint) -> c_int {
354 if buf.is_null() {
355 return -1;
356 }
357
358 let b = unsafe { &mut *buf };
359
360 if size <= b.size {
361 return 0; }
363
364 let new_content =
365 unsafe { xmlReallocImpl(b.content as *mut c_void, size as usize) as *mut xmlChar };
366 if new_content.is_null() {
367 return -1;
368 }
369
370 b.content = new_content;
371 b.contentIO = new_content;
372 b.size = size;
373
374 0
375}
376
377pub(crate) fn xml_buf_create(size: c_int) -> *mut _xmlBuf {
386 let buf_size = if size <= 0 {
387 DEFAULT_BUFFER_SIZE
388 } else {
389 size as c_uint
390 };
391 let buf_size = buf_size.max(MIN_BUFFER_SIZE);
392
393 let buf = unsafe { xmlMallocImpl(size_of::<_xmlBuf>()) as *mut _xmlBuf };
394 if buf.is_null() {
395 return ptr::null_mut();
396 }
397
398 let content = unsafe { xmlMallocImpl(buf_size as usize) as *mut xmlChar };
399 if content.is_null() {
400 unsafe { xmlFreeImpl(buf as *mut c_void) };
401 return ptr::null_mut();
402 }
403
404 unsafe {
405 ptr::write(content, 0);
406 }
407
408 unsafe {
409 ptr::write(
410 buf,
411 _xmlBuf {
412 content,
413 use_: 0,
414 size: buf_size,
415 alloc: XML_BUFFER_ALLOC_DOUBLEIT,
416 error: 0,
417 buffer: 0,
418 io: 0,
419 },
420 );
421 }
422
423 buf
424}
425
426pub(crate) fn xml_buf_free(buf: *mut _xmlBuf) {
430 if buf.is_null() {
431 return;
432 }
433
434 unsafe {
435 if !(*buf).content.is_null() {
436 xmlFreeImpl((*buf).content as *mut c_void);
437 }
438 xmlFreeImpl(buf as *mut c_void);
439 }
440}
441
442pub(crate) fn xml_buf_content(buf: *mut _xmlBuf) -> *mut xmlChar {
444 if buf.is_null() {
445 return ptr::null_mut();
446 }
447 unsafe { (*buf).content }
448}
449
450pub(crate) fn xml_buf_length(buf: *mut _xmlBuf) -> c_int {
452 if buf.is_null() {
453 return -1;
454 }
455 unsafe { (*buf).use_ as c_int }
456}
457
458pub(crate) fn xml_buf_add(buf: *mut _xmlBuf, str: *const xmlChar, len: c_int) -> c_int {
462 if buf.is_null() || str.is_null() || len <= 0 {
463 return 0;
464 }
465
466 let len = len as c_uint;
467 let b = unsafe { &mut *buf };
468
469 let needed = b.use_.saturating_add(len).saturating_add(1);
470 if needed > b.size {
471 let new_size = needed.saturating_mul(2).max(MIN_BUFFER_SIZE);
472 let new_content =
473 unsafe { xmlReallocImpl(b.content as *mut c_void, new_size as usize) as *mut xmlChar };
474 if new_content.is_null() {
475 return -1;
476 }
477 b.content = new_content;
478 b.size = new_size;
479 }
480
481 unsafe {
482 ptr::copy_nonoverlapping(str, b.content.add(b.use_ as usize), len as usize);
483 }
484 b.use_ = b.use_.saturating_add(len);
485
486 unsafe {
487 ptr::write(b.content.add(b.use_ as usize), 0);
488 }
489
490 len as c_int
491}
492
493pub(crate) fn xml_buf_cat(buf: *mut _xmlBuf, str: *const xmlChar) -> c_int {
495 if buf.is_null() || str.is_null() {
496 return -1;
497 }
498
499 let len = unsafe {
500 let mut i: c_uint = 0;
501 while *str.add(i as usize) != 0 {
502 i += 1;
503 }
504 i
505 };
506
507 xml_buf_add(buf, str, len as c_int)
508}
509
510pub(crate) fn xml_buf_grow(buf: *mut _xmlBuf, size: c_uint) -> c_int {
514 if buf.is_null() {
515 return -1;
516 }
517
518 let b = unsafe { &mut *buf };
519 if size <= b.size {
520 return 0;
521 }
522
523 let new_content =
524 unsafe { xmlReallocImpl(b.content as *mut c_void, size as usize) as *mut xmlChar };
525 if new_content.is_null() {
526 return -1;
527 }
528
529 b.content = new_content;
530 b.size = size;
531 0
532}
533
534pub(crate) fn xml_buf_shrink(buf: *mut _xmlBuf, len: c_uint) -> c_int {
538 if buf.is_null() {
539 return -1;
540 }
541
542 let b = unsafe { &mut *buf };
543 if b.use_ == 0 {
544 return 0;
545 }
546
547 b.use_ = if len >= b.use_ { 0 } else { b.use_ - len };
548
549 unsafe {
550 ptr::write(b.content.add(b.use_ as usize), 0);
551 }
552
553 b.use_ as c_int
554}
555
556fn encoding_from_int(enc: c_int) -> xmlCharEncoding {
562 match enc {
563 -1 => xmlCharEncoding::XML_CHAR_ENCODING_ERROR,
564 0 => xmlCharEncoding::XML_CHAR_ENCODING_NONE,
565 1 => xmlCharEncoding::XML_CHAR_ENCODING_UTF8,
566 2 => xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE,
567 3 => xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE,
568 4 => xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE,
569 5 => xmlCharEncoding::XML_CHAR_ENCODING_UCS4BE,
570 6 => xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC,
571 7 => xmlCharEncoding::XML_CHAR_ENCODING_UCS4_2143,
572 8 => xmlCharEncoding::XML_CHAR_ENCODING_UCS4_3412,
573 9 => xmlCharEncoding::XML_CHAR_ENCODING_UCS2,
574 10 => xmlCharEncoding::XML_CHAR_ENCODING_8859_1,
575 11 => xmlCharEncoding::XML_CHAR_ENCODING_8859_2,
576 12 => xmlCharEncoding::XML_CHAR_ENCODING_8859_3,
577 13 => xmlCharEncoding::XML_CHAR_ENCODING_8859_4,
578 14 => xmlCharEncoding::XML_CHAR_ENCODING_8859_5,
579 15 => xmlCharEncoding::XML_CHAR_ENCODING_8859_6,
580 16 => xmlCharEncoding::XML_CHAR_ENCODING_8859_7,
581 17 => xmlCharEncoding::XML_CHAR_ENCODING_8859_8,
582 18 => xmlCharEncoding::XML_CHAR_ENCODING_8859_9,
583 19 => xmlCharEncoding::XML_CHAR_ENCODING_2022_JP,
584 20 => xmlCharEncoding::XML_CHAR_ENCODING_SHIFT_JIS,
585 21 => xmlCharEncoding::XML_CHAR_ENCODING_EUC_JP,
586 22 => xmlCharEncoding::XML_CHAR_ENCODING_ASCII,
587 _ => xmlCharEncoding::XML_CHAR_ENCODING_ERROR,
588 }
589}
590
591fn find_handler_for_encoding(enc: c_int) -> *mut _xmlCharEncodingHandler {
596 let enc_enum = encoding_from_int(enc);
597 if enc_enum == xmlCharEncoding::XML_CHAR_ENCODING_NONE
598 || enc_enum == xmlCharEncoding::XML_CHAR_ENCODING_UTF8
599 || enc_enum == xmlCharEncoding::XML_CHAR_ENCODING_ERROR
600 {
601 return ptr::null_mut();
602 }
603
604 if let Some(name) = encoding::encoding_name(enc_enum) {
606 let mut name_nul = name.to_vec();
608 name_nul.push(0);
609 let handler = encoding::find_encoding_handler(name_nul.as_ptr() as *const xmlChar);
610 if !handler.is_null() {
611 return handler;
612 }
613 }
614
615 ptr::null_mut()
616}
617
618fn allocate_input_buffer() -> *mut _xmlParserInputBuffer {
623 let buf =
624 unsafe { xmlMallocImpl(size_of::<_xmlParserInputBuffer>()) as *mut _xmlParserInputBuffer };
625 if buf.is_null() {
626 return ptr::null_mut();
627 }
628
629 unsafe {
630 ptr::write(
631 buf,
632 _xmlParserInputBuffer {
633 context: ptr::null_mut(),
634 readcallback: None,
635 closecallback: None,
636 encoder: ptr::null_mut(),
637 buffer: ptr::null_mut(),
638 raw: ptr::null_mut(),
639 compressed: 0,
640 error: 0,
641 rawconsumed: 0,
642 },
643 );
644 }
645
646 buf
647}
648
649pub(crate) fn input_buffer_create_mem(
654 buffer: *const c_char,
655 size: c_int,
656 enc: c_int,
657) -> *mut _xmlParserInputBuffer {
658 if buffer.is_null() || size <= 0 {
659 return ptr::null_mut();
660 }
661
662 let buf = allocate_input_buffer();
663 if buf.is_null() {
664 return ptr::null_mut();
665 }
666
667 let raw_buf = buf_create(size);
669 if raw_buf.is_null() {
670 unsafe { xmlFreeImpl(buf as *mut c_void) };
671 return ptr::null_mut();
672 }
673
674 buf_add(raw_buf, buffer as *const xmlChar, size);
676
677 let handler = find_handler_for_encoding(enc);
679 if !handler.is_null() {
680 let out_buf = buf_create((size as c_uint).saturating_mul(3).max(MIN_BUFFER_SIZE) as c_int);
683 if out_buf.is_null() {
684 buf_free(raw_buf);
685 unsafe { xmlFreeImpl(buf as *mut c_void) };
686 return ptr::null_mut();
687 }
688
689 let written = encoding::char_enc_in(handler, out_buf, raw_buf);
691 if written < 0 {
692 buf_free(raw_buf);
693 buf_free(out_buf);
694 unsafe { xmlFreeImpl(buf as *mut c_void) };
695 return ptr::null_mut();
696 }
697
698 unsafe {
699 (*buf).encoder = handler as *mut c_void;
700 (*buf).buffer = out_buf as *mut c_void;
701 (*buf).raw = raw_buf as *mut c_void;
702 }
703 } else {
704 unsafe {
706 (*buf).buffer = raw_buf as *mut c_void;
707 (*buf).raw = raw_buf as *mut c_void;
708 }
709 }
710
711 buf
712}
713
714unsafe extern "C" fn file_read_callback(
718 context: *mut c_void,
719 buffer: *mut c_char,
720 len: c_int,
721) -> c_int {
722 if context.is_null() || buffer.is_null() || len <= 0 {
723 return -1;
724 }
725
726 let fd = context as c_int;
727 let ret = libc::read(fd, buffer as *mut c_void, len as usize);
728 if ret < 0 {
729 return -1;
730 }
731 ret as c_int
732}
733
734unsafe extern "C" fn file_close_callback(context: *mut c_void) -> c_int {
736 if context.is_null() {
737 return -1;
738 }
739
740 let fd = context as c_int;
741 libc::close(fd)
742}
743
744pub(crate) fn input_buffer_create_file(
749 filename: *const c_char,
750 enc: c_int,
751) -> *mut _xmlParserInputBuffer {
752 if filename.is_null() {
753 return ptr::null_mut();
754 }
755
756 let filename_str = unsafe {
758 match CStr::from_ptr(filename).to_str() {
759 Ok(s) => s,
760 Err(_) => return ptr::null_mut(),
761 }
762 };
763
764 let fd = unsafe {
766 let path_c = std::ffi::CString::new(filename_str).unwrap_or_default();
767 libc::open(path_c.as_ptr(), libc::O_RDONLY)
768 };
769
770 if fd < 0 {
771 return ptr::null_mut();
772 }
773
774 let mut stat_buf: libc::stat = unsafe { std::mem::zeroed() };
776 let stat_ret = unsafe {
777 let path_c = std::ffi::CString::new(filename_str).unwrap_or_default();
778 libc::stat(path_c.as_ptr(), &mut stat_buf)
779 };
780
781 let file_size = if stat_ret == 0 {
782 stat_buf.st_size as usize
783 } else {
784 0
786 };
787
788 let read_size = if file_size > 0 {
790 file_size
791 } else {
792 4096 };
794
795 let mut data = vec![0u8; read_size];
796 let mut total_read: isize = 0;
797
798 loop {
799 let remaining = read_size.saturating_sub(total_read as usize);
800 if remaining == 0 {
801 let new_size = read_size.saturating_mul(2);
803 data.resize(new_size, 0u8);
804 }
805
806 let ret = unsafe {
807 libc::read(
808 fd,
809 data.as_mut_ptr().add(total_read as usize) as *mut c_void,
810 remaining,
811 )
812 };
813
814 if ret < 0 {
815 unsafe { libc::close(fd) };
817 return ptr::null_mut();
818 }
819
820 if ret == 0 {
821 break;
823 }
824
825 total_read += ret as isize;
826 }
827
828 unsafe { libc::close(fd) };
829
830 data.truncate(total_read as usize);
831
832 if data.is_empty() {
833 return ptr::null_mut();
834 }
835
836 input_buffer_create_mem(data.as_ptr() as *const c_char, data.len() as c_int, enc)
838}
839
840pub(crate) fn input_buffer_create_io(
845 ioread: Option<xmlInputReadCallback>,
846 ioclose: Option<xmlInputCloseCallback>,
847 ioctx: *mut c_void,
848 enc: c_int,
849) -> *mut _xmlParserInputBuffer {
850 let buf = allocate_input_buffer();
851 if buf.is_null() {
852 return ptr::null_mut();
853 }
854
855 let raw_buf = buf_create(DEFAULT_BUFFER_SIZE as c_int);
857 if raw_buf.is_null() {
858 unsafe { xmlFreeImpl(buf as *mut c_void) };
859 return ptr::null_mut();
860 }
861
862 unsafe {
863 (*buf).context = ioctx;
864 (*buf).readcallback = ioread;
865 (*buf).closecallback = ioclose;
866 (*buf).raw = raw_buf as *mut c_void;
867 }
868
869 let handler = find_handler_for_encoding(enc);
871 if !handler.is_null() {
872 let out_buf = buf_create(DEFAULT_BUFFER_SIZE as c_int);
873 if out_buf.is_null() {
874 buf_free(raw_buf);
875 unsafe { xmlFreeImpl(buf as *mut c_void) };
876 return ptr::null_mut();
877 }
878 unsafe {
879 (*buf).encoder = handler as *mut c_void;
880 (*buf).buffer = out_buf as *mut c_void;
881 }
882 } else {
883 unsafe {
884 (*buf).buffer = raw_buf as *mut c_void;
885 }
886 }
887
888 buf
889}
890
891pub(crate) fn input_buffer_create_fd(fd: c_int, enc: c_int) -> *mut _xmlParserInputBuffer {
895 if fd < 0 {
896 return ptr::null_mut();
897 }
898
899 input_buffer_create_io(
900 Some(file_read_callback as xmlInputReadCallback),
901 Some(file_close_callback as xmlInputCloseCallback),
902 fd as *mut c_void,
903 enc,
904 )
905}
906
907pub(crate) fn input_buffer_free(buf: *mut _xmlParserInputBuffer) {
912 if buf.is_null() {
913 return;
914 }
915
916 unsafe {
917 if let Some(close_cb) = (*buf).closecallback {
919 close_cb((*buf).context);
920 }
921
922 if !(*buf).raw.is_null() {
924 buf_free((*buf).raw as *mut _xmlBuffer);
925 }
926
927 if !(*buf).buffer.is_null() && (*buf).buffer != (*buf).raw {
929 buf_free((*buf).buffer as *mut _xmlBuffer);
930 }
931
932 xmlFreeImpl(buf as *mut c_void);
936 }
937}
938
939pub(crate) fn input_buffer_read(
948 buf: *mut _xmlParserInputBuffer,
949 buffer: *mut c_char,
950 len: c_int,
951) -> c_int {
952 if buf.is_null() || buffer.is_null() || len <= 0 {
953 return -1;
954 }
955
956 let b = unsafe { &mut *buf };
957
958 if b.error != 0 {
959 return -1;
960 }
961
962 if let Some(read_cb) = b.readcallback {
963 let raw_buf = b.raw as *mut _xmlBuffer;
966 if raw_buf.is_null() {
967 return -1;
968 }
969
970 let mut tmp = vec![0u8; len as usize];
972 let ret = unsafe { read_cb(b.context, tmp.as_mut_ptr() as *mut c_char, len) };
973
974 if ret < 0 {
975 b.error = 1;
976 return -1;
977 }
978
979 if ret == 0 {
980 return 0;
982 }
983
984 buf_add(raw_buf, tmp.as_ptr() as *const xmlChar, ret);
986
987 if !b.encoder.is_null() {
989 let out_buf = b.buffer as *mut _xmlBuffer;
990 if out_buf.is_null() {
991 return -1;
992 }
993
994 let handler = b.encoder as *mut _xmlCharEncodingHandler;
995 let conv_ret = encoding::char_enc_in(handler, out_buf, raw_buf);
996 if conv_ret < 0 {
997 b.error = 1;
998 return -1;
999 }
1000
1001 let out_b = unsafe { &*out_buf };
1003 let to_copy = (out_b.use_ as c_int).min(len);
1004 if to_copy > 0 {
1005 unsafe {
1006 ptr::copy_nonoverlapping(
1007 out_b.content,
1008 buffer as *mut xmlChar,
1009 to_copy as usize,
1010 );
1011 }
1012 buf_shrink(out_buf, to_copy as c_uint);
1014 }
1015 return to_copy;
1016 }
1017
1018 let raw_b = unsafe { &*raw_buf };
1020 let to_copy = (raw_b.use_ as c_int).min(len);
1021 if to_copy > 0 {
1022 unsafe {
1023 ptr::copy_nonoverlapping(raw_b.content, buffer as *mut xmlChar, to_copy as usize);
1024 }
1025 buf_shrink(raw_buf, to_copy as c_uint);
1026 }
1027 return to_copy;
1028 }
1029
1030 let src_buf = b.buffer as *mut _xmlBuffer;
1032 if src_buf.is_null() {
1033 return -1;
1034 }
1035
1036 let src = unsafe { &mut *src_buf };
1037 if src.content.is_null() || src.use_ == 0 {
1038 return 0;
1039 }
1040
1041 let to_copy = (src.use_ as c_int).min(len);
1042 if to_copy > 0 {
1043 unsafe {
1044 ptr::copy_nonoverlapping(src.content, buffer as *mut xmlChar, to_copy as usize);
1045 }
1046 unsafe {
1048 src.content = src.content.add(to_copy as usize);
1049 }
1050 src.use_ = src.use_.saturating_sub(to_copy as c_uint);
1051 }
1052
1053 to_copy
1054}
1055
1056pub(crate) fn input_buffer_push(
1061 buf: *mut _xmlParserInputBuffer,
1062 buffer: *const c_char,
1063 len: c_int,
1064) -> c_int {
1065 if buf.is_null() || buffer.is_null() || len <= 0 {
1066 return -1;
1067 }
1068
1069 let b = unsafe { &mut *buf };
1070
1071 if b.error != 0 {
1072 return -1;
1073 }
1074
1075 let raw_buf = b.raw as *mut _xmlBuffer;
1077 if raw_buf.is_null() {
1078 return -1;
1079 }
1080
1081 buf_add(raw_buf, buffer as *const xmlChar, len);
1082
1083 if !b.encoder.is_null() {
1085 let out_buf = b.buffer as *mut _xmlBuffer;
1086 if out_buf.is_null() {
1087 return -1;
1088 }
1089
1090 let handler = b.encoder as *mut _xmlCharEncodingHandler;
1091 let ret = encoding::char_enc_in(handler, out_buf, raw_buf);
1092 if ret < 0 {
1093 b.error = 1;
1094 return -1;
1095 }
1096 }
1097
1098 len
1099}
1100
1101pub(crate) fn input_buffer_set_encoder(
1106 buf: *mut _xmlParserInputBuffer,
1107 handler: *mut _xmlCharEncodingHandler,
1108) {
1109 if buf.is_null() {
1110 return;
1111 }
1112
1113 unsafe {
1114 (*buf).encoder = handler as *mut c_void;
1115 }
1116}
1117
1118unsafe extern "C" fn file_write_callback(
1124 context: *mut c_void,
1125 buffer: *const c_char,
1126 len: c_int,
1127) -> c_int {
1128 if context.is_null() || buffer.is_null() || len <= 0 {
1129 return -1;
1130 }
1131
1132 let fd = context as c_int;
1133 let ret = libc::write(fd, buffer as *const c_void, len as usize);
1134 if ret < 0 {
1135 return -1;
1136 }
1137 ret as c_int
1138}
1139
1140unsafe extern "C" fn file_close_output_callback(context: *mut c_void) -> c_int {
1142 if context.is_null() {
1143 return -1;
1144 }
1145
1146 let fd = context as c_int;
1147 libc::close(fd)
1148}
1149
1150unsafe extern "C" fn buffer_write_callback(
1152 context: *mut c_void,
1153 buffer: *const c_char,
1154 len: c_int,
1155) -> c_int {
1156 if context.is_null() || buffer.is_null() || len <= 0 {
1157 return -1;
1158 }
1159
1160 let target_buf = context as *mut _xmlBuffer;
1161 buf_add(target_buf, buffer as *const xmlChar, len)
1162}
1163
1164fn allocate_output_buffer() -> *mut _xmlOutputBuffer {
1168 let buf = unsafe { xmlMallocImpl(size_of::<_xmlOutputBuffer>()) as *mut _xmlOutputBuffer };
1169 if buf.is_null() {
1170 return ptr::null_mut();
1171 }
1172
1173 unsafe {
1174 ptr::write(
1175 buf,
1176 _xmlOutputBuffer {
1177 context: ptr::null_mut(),
1178 writecallback: None,
1179 closecallback: None,
1180 encoder: ptr::null_mut(),
1181 buffer: ptr::null_mut(),
1182 conv: ptr::null_mut(),
1183 written: 0,
1184 error: 0,
1185 },
1186 );
1187 }
1188
1189 buf
1190}
1191
1192pub(crate) fn output_buffer_create_filename(
1197 URI: *const c_char,
1198 encoder: *mut _xmlCharEncodingHandler,
1199 compression: c_int,
1200) -> *mut _xmlOutputBuffer {
1201 if URI.is_null() {
1202 return ptr::null_mut();
1203 }
1204
1205 let path_str = unsafe {
1206 match CStr::from_ptr(URI).to_str() {
1207 Ok(s) => s,
1208 Err(_) => return ptr::null_mut(),
1209 }
1210 };
1211
1212 let path_c = std::ffi::CString::new(path_str).unwrap_or_default();
1213
1214 let fd = unsafe {
1216 libc::open(
1217 path_c.as_ptr(),
1218 libc::O_WRONLY | libc::O_CREAT | libc::O_TRUNC,
1219 0o644,
1220 )
1221 };
1222
1223 if fd < 0 {
1224 return ptr::null_mut();
1225 }
1226
1227 let obuf = allocate_output_buffer();
1228 if obuf.is_null() {
1229 unsafe { libc::close(fd) };
1230 return ptr::null_mut();
1231 }
1232
1233 let buf = buf_create(DEFAULT_BUFFER_SIZE as c_int);
1234 if buf.is_null() {
1235 unsafe {
1236 libc::close(fd);
1237 xmlFreeImpl(obuf as *mut c_void);
1238 }
1239 return ptr::null_mut();
1240 }
1241
1242 let conv_buf = buf_create(DEFAULT_BUFFER_SIZE as c_int);
1243 if conv_buf.is_null() {
1244 unsafe {
1245 libc::close(fd);
1246 buf_free(buf);
1247 xmlFreeImpl(obuf as *mut c_void);
1248 }
1249 return ptr::null_mut();
1250 }
1251
1252 unsafe {
1253 (*obuf).context = fd as *mut c_void;
1254 (*obuf).writecallback = Some(file_write_callback as xmlOutputWriteCallback);
1255 (*obuf).closecallback = Some(file_close_output_callback as xmlOutputCloseCallback);
1256 (*obuf).encoder = encoder as *mut c_void;
1257 (*obuf).buffer = buf as *mut c_void;
1258 (*obuf).conv = conv_buf as *mut c_void;
1259 (*obuf).written = 0;
1260 (*obuf).error = 0;
1261 }
1262
1263 obuf
1264}
1265
1266pub(crate) fn output_buffer_create_fd(
1268 fd: c_int,
1269 encoder: *mut _xmlCharEncodingHandler,
1270) -> *mut _xmlOutputBuffer {
1271 if fd < 0 {
1272 return ptr::null_mut();
1273 }
1274
1275 let obuf = allocate_output_buffer();
1276 if obuf.is_null() {
1277 return ptr::null_mut();
1278 }
1279
1280 let buf = buf_create(DEFAULT_BUFFER_SIZE as c_int);
1281 if buf.is_null() {
1282 unsafe { xmlFreeImpl(obuf as *mut c_void) };
1283 return ptr::null_mut();
1284 }
1285
1286 let conv_buf = buf_create(DEFAULT_BUFFER_SIZE as c_int);
1287 if conv_buf.is_null() {
1288 unsafe {
1289 buf_free(buf);
1290 xmlFreeImpl(obuf as *mut c_void);
1291 }
1292 return ptr::null_mut();
1293 }
1294
1295 unsafe {
1296 (*obuf).context = fd as *mut c_void;
1297 (*obuf).writecallback = Some(file_write_callback as xmlOutputWriteCallback);
1298 (*obuf).closecallback = Some(file_close_output_callback as xmlOutputCloseCallback);
1299 (*obuf).encoder = encoder as *mut c_void;
1300 (*obuf).buffer = buf as *mut c_void;
1301 (*obuf).conv = conv_buf as *mut c_void;
1302 (*obuf).written = 0;
1303 (*obuf).error = 0;
1304 }
1305
1306 obuf
1307}
1308
1309pub(crate) fn output_buffer_create_io(
1311 iowrite: Option<xmlOutputWriteCallback>,
1312 ioclose: Option<xmlOutputCloseCallback>,
1313 ioctx: *mut c_void,
1314 encoder: *mut _xmlCharEncodingHandler,
1315) -> *mut _xmlOutputBuffer {
1316 let obuf = allocate_output_buffer();
1317 if obuf.is_null() {
1318 return ptr::null_mut();
1319 }
1320
1321 let buf = buf_create(DEFAULT_BUFFER_SIZE as c_int);
1322 if buf.is_null() {
1323 unsafe { xmlFreeImpl(obuf as *mut c_void) };
1324 return ptr::null_mut();
1325 }
1326
1327 let conv_buf = buf_create(DEFAULT_BUFFER_SIZE as c_int);
1328 if conv_buf.is_null() {
1329 unsafe {
1330 buf_free(buf);
1331 xmlFreeImpl(obuf as *mut c_void);
1332 }
1333 return ptr::null_mut();
1334 }
1335
1336 unsafe {
1337 (*obuf).context = ioctx;
1338 (*obuf).writecallback = iowrite;
1339 (*obuf).closecallback = ioclose;
1340 (*obuf).encoder = encoder as *mut c_void;
1341 (*obuf).buffer = buf as *mut c_void;
1342 (*obuf).conv = conv_buf as *mut c_void;
1343 (*obuf).written = 0;
1344 (*obuf).error = 0;
1345 }
1346
1347 obuf
1348}
1349
1350pub(crate) fn output_buffer_create_buffer(
1354 target_buf: *mut _xmlBuffer,
1355 encoder: *mut _xmlCharEncodingHandler,
1356) -> *mut _xmlOutputBuffer {
1357 if target_buf.is_null() {
1358 return ptr::null_mut();
1359 }
1360
1361 let obuf = allocate_output_buffer();
1362 if obuf.is_null() {
1363 return ptr::null_mut();
1364 }
1365
1366 let internal_buf = buf_create(DEFAULT_BUFFER_SIZE as c_int);
1368 if internal_buf.is_null() {
1369 unsafe { xmlFreeImpl(obuf as *mut c_void) };
1370 return ptr::null_mut();
1371 }
1372
1373 let conv_buf = buf_create(DEFAULT_BUFFER_SIZE as c_int);
1375 if conv_buf.is_null() {
1376 unsafe {
1377 buf_free(internal_buf);
1378 xmlFreeImpl(obuf as *mut c_void);
1379 }
1380 return ptr::null_mut();
1381 }
1382
1383 unsafe {
1384 (*obuf).context = target_buf as *mut c_void;
1385 (*obuf).writecallback = Some(buffer_write_callback as xmlOutputWriteCallback);
1386 (*obuf).closecallback = None;
1387 (*obuf).encoder = encoder as *mut c_void;
1388 (*obuf).buffer = internal_buf as *mut c_void;
1389 (*obuf).conv = conv_buf as *mut c_void;
1390 (*obuf).written = 0;
1391 (*obuf).error = 0;
1392 }
1393
1394 obuf
1395}
1396
1397pub(crate) fn output_buffer_flush(out: *mut _xmlOutputBuffer) -> c_int {
1404 if out.is_null() {
1405 return -1;
1406 }
1407
1408 let ob = unsafe { &mut *out };
1409
1410 if ob.error != 0 {
1411 return -1;
1412 }
1413
1414 let buf = ob.buffer as *mut _xmlBuffer;
1415 if buf.is_null() {
1416 return 0;
1417 }
1418
1419 let b = unsafe { &*buf };
1420 if b.use_ == 0 {
1421 return 0;
1422 }
1423
1424 let write_cb = match ob.writecallback {
1425 Some(cb) => cb,
1426 None => {
1427 buf_empty(buf);
1429 return 0;
1430 }
1431 };
1432
1433 let total_written = if !ob.encoder.is_null() {
1434 let handler = ob.encoder as *mut _xmlCharEncodingHandler;
1436 let conv = ob.conv as *mut _xmlBuffer;
1437
1438 buf_empty(conv);
1440
1441 let ret = encoding::char_enc_out(handler, conv, buf);
1442 if ret < 0 {
1443 ob.error = 1;
1444 return -1;
1445 }
1446
1447 let conv_b = unsafe { &*conv };
1449 if conv_b.use_ > 0 {
1450 let written = unsafe {
1451 write_cb(
1452 ob.context,
1453 conv_b.content as *const c_char,
1454 conv_b.use_ as c_int,
1455 )
1456 };
1457
1458 if written < 0 {
1459 ob.error = 1;
1460 return -1;
1461 }
1462
1463 ob.written = ob.written.saturating_add(written);
1464 buf_empty(conv);
1465 written
1466 } else {
1467 0
1468 }
1469 } else {
1470 let written = unsafe { write_cb(ob.context, b.content as *const c_char, b.use_ as c_int) };
1472
1473 if written < 0 {
1474 ob.error = 1;
1475 return -1;
1476 }
1477
1478 ob.written = ob.written.saturating_add(written);
1479 written
1480 };
1481
1482 buf_empty(buf);
1484
1485 total_written
1486}
1487
1488pub(crate) fn output_buffer_close(out: *mut _xmlOutputBuffer) -> c_int {
1493 if out.is_null() {
1494 return -1;
1495 }
1496
1497 let ob = unsafe { &mut *out };
1498
1499 let flush_ret = output_buffer_flush(out);
1501
1502 if let Some(close_cb) = ob.closecallback {
1504 unsafe {
1505 close_cb(ob.context);
1506 }
1507 }
1508
1509 if !ob.buffer.is_null() {
1511 buf_free(ob.buffer as *mut _xmlBuffer);
1512 }
1513 if !ob.conv.is_null() {
1514 buf_free(ob.conv as *mut _xmlBuffer);
1515 }
1516
1517 unsafe { xmlFreeImpl(out as *mut c_void) };
1520
1521 flush_ret
1522}
1523
1524pub(crate) fn output_buffer_write(
1539 out: *mut _xmlOutputBuffer,
1540 len: c_int,
1541 data: *const c_char,
1542) -> c_int {
1543 if out.is_null() || data.is_null() || len <= 0 {
1544 return -1;
1545 }
1546
1547 let ob = unsafe { &mut *out };
1548
1549 if ob.error != 0 {
1550 return -1;
1551 }
1552
1553 let buf = ob.buffer as *mut _xmlBuffer;
1554 if buf.is_null() {
1555 return -1;
1556 }
1557
1558 let ret = buf_add(buf, data as *const xmlChar, len);
1559 if ret < 0 {
1560 ob.error = 1;
1561 return -1;
1562 }
1563
1564 if ob.writecallback.is_none() {
1565 return len; }
1567
1568 let b = unsafe { &*buf };
1572 if b.use_ < MIN_BUFFER_SIZE {
1573 return 0;
1574 }
1575 output_buffer_flush(out)
1576}
1577
1578pub(crate) fn output_buffer_write_string(out: *mut _xmlOutputBuffer, str: *const c_char) -> c_int {
1580 if out.is_null() || str.is_null() {
1581 return -1;
1582 }
1583
1584 let len = unsafe {
1585 let mut i: c_int = 0;
1586 while *str.add(i as usize) != 0 {
1587 i += 1;
1588 }
1589 i
1590 };
1591
1592 output_buffer_write(out, len, str)
1593}
1594
1595pub(crate) fn output_buffer_write_char(out: *mut _xmlOutputBuffer, c: c_char) -> c_int {
1597 output_buffer_write(out, 1, &c as *const c_char)
1598}
1599
1600pub(crate) fn output_buffer_get_content(out: *mut _xmlOutputBuffer) -> *const xmlChar {
1604 if out.is_null() {
1605 return ptr::null();
1606 }
1607
1608 let ob = unsafe { &*out };
1609 let buf = ob.buffer as *mut _xmlBuffer;
1610 if buf.is_null() {
1611 return ptr::null();
1612 }
1613
1614 buf_content(buf)
1615}
1616
1617pub(crate) fn output_buffer_get_size(out: *mut _xmlOutputBuffer) -> c_int {
1619 if out.is_null() {
1620 return -1;
1621 }
1622 let ob = unsafe { &*out };
1623 let buf = ob.buffer as *mut _xmlBuffer;
1624 if buf.is_null() {
1625 return -1;
1626 }
1627 buf_length(buf)
1628}
1629
1630pub(crate) fn output_buffer_create(
1633 _encoder: *mut crate::abi::structs::_xmlCharEncodingHandler,
1634) -> *mut _xmlOutputBuffer {
1635 let obuf = allocate_output_buffer();
1636 if obuf.is_null() {
1637 return ptr::null_mut();
1638 }
1639 let buf = buf_create(-1);
1640 if buf.is_null() {
1641 unsafe { xmlFreeImpl(obuf as *mut c_void) };
1642 return ptr::null_mut();
1643 }
1644 unsafe {
1645 (*obuf).buffer = buf as *mut c_void;
1646 (*obuf).encoder = _encoder as *mut c_void;
1647 }
1648 obuf
1649}
1650
1651pub(crate) fn output_buffer_create_file(
1660 file: *mut libc::FILE,
1661 _encoder: *mut crate::abi::structs::_xmlCharEncodingHandler,
1662) -> *mut _xmlOutputBuffer {
1663 if file.is_null() {
1664 return ptr::null_mut();
1665 }
1666 unsafe extern "C" fn file_write(ctx: *mut c_void, buffer: *const c_char, len: c_int) -> c_int {
1667 let f = ctx as *mut libc::FILE;
1668 if f.is_null() || buffer.is_null() || len <= 0 {
1669 return 0;
1670 }
1671 let n = unsafe { libc::fwrite(buffer as *const libc::c_void, 1, len as usize, f) };
1672 n as c_int
1673 }
1674 unsafe extern "C" fn file_flush(ctx: *mut c_void) -> c_int {
1675 let f = ctx as *mut libc::FILE;
1676 if f.is_null() {
1677 return -1;
1678 }
1679 unsafe { libc::fflush(f) }
1680 }
1681 let obuf = output_buffer_create(_encoder);
1682 if obuf.is_null() {
1683 return ptr::null_mut();
1684 }
1685 unsafe {
1686 (*obuf).context = file as *mut c_void;
1687 (*obuf).writecallback = Some(file_write);
1688 (*obuf).closecallback = Some(file_flush);
1689 }
1690 obuf
1691}
1692
1693pub(crate) fn output_buffer_write_escape(
1706 out: *mut _xmlOutputBuffer,
1707 str: *const xmlChar,
1708 escaping: Option<unsafe extern "C" fn(*mut u8, *mut c_int, *const u8, *mut c_int) -> c_int>,
1709) -> c_int {
1710 if out.is_null() || str.is_null() {
1711 return -1;
1712 }
1713 if escaping.is_none() {
1714 let escaped = unsafe { escape_text(str) };
1717 if escaped.is_null() {
1718 unsafe {
1719 let ob = &mut *out;
1720 ob.error = 1;
1721 }
1722 return -1;
1723 }
1724 let len = unsafe { libc::strlen(escaped as *const libc::c_char) as c_int };
1725 let ret = output_buffer_write(out, len, escaped as *const c_char);
1726 unsafe { libc::free(escaped as *mut libc::c_void) };
1727 return ret;
1728 }
1729 let ob = unsafe { &mut *out };
1730 if ob.error != 0 {
1731 return -1;
1732 }
1733 let buf = ob.buffer as *mut _xmlBuffer;
1734 if buf.is_null() {
1735 return -1;
1736 }
1737 let mut inlen = unsafe { libc::strlen(str as *const libc::c_char) as c_int };
1738 let mut inpos = 0i32;
1739 let mut total = 0i32;
1740 while inpos < inlen {
1741 let mut outbuf = [0u8; 1024];
1742 let mut outlen = 1024i32;
1743 let chunk_in = unsafe { str.add(inpos as usize) };
1744 let mut chunk_len = inlen - inpos;
1745 let ret = unsafe {
1747 escaping.unwrap()(outbuf.as_mut_ptr(), &mut outlen, chunk_in, &mut chunk_len)
1748 };
1749 if ret < 0 || outlen < 0 {
1750 ob.error = 1;
1751 return -1;
1752 }
1753 if outlen > 0 {
1754 let r = output_buffer_write(out, outlen, outbuf.as_ptr() as *const c_char);
1755 if r < 0 {
1756 ob.error = 1;
1757 return -1;
1758 }
1759 total += r;
1760 }
1761 if chunk_len <= 0 {
1762 break; }
1764 inpos += chunk_len;
1765 if inpos > inlen {
1766 break;
1767 }
1768 }
1769 total
1770}
1771
1772unsafe fn escape_text(str: *const xmlChar) -> *mut xmlChar {
1777 if str.is_null() {
1778 return core::ptr::null_mut();
1779 }
1780 let mut out = Vec::<u8>::with_capacity(64);
1781 let mut cur = str;
1782 loop {
1783 let c = unsafe { *cur };
1784 if c == 0 {
1785 break;
1786 }
1787 match c {
1788 b'&' => out.extend_from_slice(b"&"),
1789 b'<' => out.extend_from_slice(b"<"),
1790 b'>' => out.extend_from_slice(b">"),
1791 0x0d => out.extend_from_slice(b" "),
1792 _ => {
1793 let len = utf8_seq_len(c);
1796 for _ in 0..len {
1797 let b = unsafe { *cur };
1798 if b == 0 {
1799 break;
1800 }
1801 out.push(b);
1802 cur = cur.add(1);
1803 }
1804 continue;
1805 }
1806 }
1807 cur = cur.add(1);
1808 }
1809 out.push(0);
1810 let p = libc::malloc(out.len()) as *mut xmlChar;
1811 if p.is_null() {
1812 return core::ptr::null_mut();
1813 }
1814 unsafe {
1815 libc::memcpy(
1816 p as *mut libc::c_void,
1817 out.as_ptr() as *const libc::c_void,
1818 out.len(),
1819 );
1820 }
1821 p
1822}
1823
1824fn utf8_seq_len(lead: u8) -> usize {
1826 match lead {
1827 0x00..=0x7f => 1,
1828 0xc2..=0xdf => 2,
1829 0xe0..=0xef => 3,
1830 0xf0..=0xf4 => 4,
1831 _ => 1,
1832 }
1833}
1834
1835pub(crate) fn check_file_exists(filename: *const c_char) -> c_int {
1843 if filename.is_null() {
1844 return -1;
1845 }
1846
1847 let path_str = unsafe {
1848 match CStr::from_ptr(filename).to_str() {
1849 Ok(s) => s,
1850 Err(_) => return -1,
1851 }
1852 };
1853
1854 let path_c = match std::ffi::CString::new(path_str) {
1855 Ok(c) => c,
1856 Err(_) => return -1,
1857 };
1858
1859 let mut stat_buf: libc::stat = unsafe { std::mem::zeroed() };
1860 let ret = unsafe { libc::stat(path_c.as_ptr(), &mut stat_buf) };
1861
1862 if ret == 0 {
1863 1
1864 } else {
1865 0
1866 }
1867}
1868
1869pub(crate) fn read_file_to_memory(filename: *const c_char, size: *mut c_int) -> *mut c_char {
1877 if filename.is_null() {
1878 return ptr::null_mut();
1879 }
1880
1881 let path_str = unsafe {
1882 match CStr::from_ptr(filename).to_str() {
1883 Ok(s) => s,
1884 Err(_) => return ptr::null_mut(),
1885 }
1886 };
1887
1888 let path_c = match std::ffi::CString::new(path_str) {
1889 Ok(c) => c,
1890 Err(_) => return ptr::null_mut(),
1891 };
1892
1893 let fd = unsafe { libc::open(path_c.as_ptr(), libc::O_RDONLY) };
1894 if fd < 0 {
1895 return ptr::null_mut();
1896 }
1897
1898 let mut stat_buf: libc::stat = unsafe { std::mem::zeroed() };
1900 let file_size = if unsafe { libc::stat(path_c.as_ptr(), &mut stat_buf) } == 0 {
1901 stat_buf.st_size as usize
1902 } else {
1903 0
1904 };
1905
1906 let chunk_size = 4096usize;
1908 let initial_capacity = if file_size > 0 { file_size } else { chunk_size };
1909
1910 let mut data = Vec::with_capacity(initial_capacity);
1911 let mut buf = vec![0u8; chunk_size];
1912
1913 loop {
1914 let ret = unsafe { libc::read(fd, buf.as_mut_ptr() as *mut c_void, chunk_size) };
1915
1916 if ret < 0 {
1917 unsafe { libc::close(fd) };
1918 return ptr::null_mut();
1919 }
1920
1921 if ret == 0 {
1922 break; }
1924
1925 data.extend_from_slice(&buf[..ret as usize]);
1926 }
1927
1928 unsafe { libc::close(fd) };
1929
1930 if data.is_empty() {
1931 return ptr::null_mut();
1932 }
1933
1934 let result = unsafe { xmlMallocImpl(data.len()) as *mut c_char };
1936 if result.is_null() {
1937 return ptr::null_mut();
1938 }
1939
1940 unsafe {
1941 ptr::copy_nonoverlapping(data.as_ptr(), result as *mut u8, data.len());
1942 }
1943
1944 if !size.is_null() {
1945 unsafe {
1946 *size = data.len() as c_int;
1947 }
1948 }
1949
1950 result
1951}
1952
1953pub(crate) fn write_memory_to_file(
1958 filename: *const c_char,
1959 data: *const c_char,
1960 size: c_int,
1961) -> c_int {
1962 if filename.is_null() || data.is_null() || size <= 0 {
1963 return -1;
1964 }
1965
1966 let path_str = unsafe {
1967 match CStr::from_ptr(filename).to_str() {
1968 Ok(s) => s,
1969 Err(_) => return -1,
1970 }
1971 };
1972
1973 let path_c = match std::ffi::CString::new(path_str) {
1974 Ok(c) => c,
1975 Err(_) => return -1,
1976 };
1977
1978 let fd = unsafe {
1979 libc::open(
1980 path_c.as_ptr(),
1981 libc::O_WRONLY | libc::O_CREAT | libc::O_TRUNC,
1982 0o644,
1983 )
1984 };
1985
1986 if fd < 0 {
1987 return -1;
1988 }
1989
1990 let mut remaining = size as usize;
1991 let mut offset: usize = 0;
1992
1993 while remaining > 0 {
1994 let ret = unsafe {
1995 libc::write(
1996 fd,
1997 (data as *const u8).add(offset) as *const c_void,
1998 remaining,
1999 )
2000 };
2001
2002 if ret < 0 {
2003 unsafe { libc::close(fd) };
2004 return -1;
2005 }
2006
2007 let written = ret as usize;
2008 remaining -= written;
2009 offset += written;
2010 }
2011
2012 unsafe { libc::close(fd) };
2013 0
2014}
2015
2016pub(crate) fn get_cwd() -> *mut c_char {
2021 let mut size: usize = 1024;
2023
2024 loop {
2025 let buf = unsafe { xmlMallocImpl(size) as *mut c_char };
2026 if buf.is_null() {
2027 return ptr::null_mut();
2028 }
2029
2030 let ret = unsafe { libc::getcwd(buf as *mut c_char, size) };
2031 if !ret.is_null() {
2032 return buf;
2033 }
2034
2035 unsafe { xmlFreeImpl(buf as *mut c_void) };
2036
2037 let err = std::io::Error::last_os_error();
2039 if err.raw_os_error() == Some(libc::ERANGE) {
2040 size = size.saturating_mul(2);
2041 if size > 65536 {
2042 return ptr::null_mut(); }
2044 } else {
2045 return ptr::null_mut();
2046 }
2047 }
2048}
2049
2050#[cfg(test)]
2055mod tests {
2056 use super::*;
2057 use std::ffi::CString;
2058 use std::os::raw::c_char;
2059
2060 fn c(s: &str) -> CString {
2063 CString::new(s).unwrap()
2064 }
2065
2066 unsafe fn c_bytes(bytes: &[u8]) -> CString {
2068 CString::from_vec_unchecked(bytes.to_vec())
2069 }
2070
2071 fn i8_slice(s: &[u8]) -> &[i8] {
2073 unsafe { std::slice::from_raw_parts(s.as_ptr() as *const i8, s.len()) }
2074 }
2075
2076 #[test]
2079 fn test_buf_create_free() {
2080 let buf = buf_create(100);
2081 assert!(!buf.is_null());
2082
2083 let b = unsafe { &*buf };
2084 assert!(!b.content.is_null());
2085 assert_eq!(b.use_, 0);
2086 assert!(b.size >= 100);
2087 assert_eq!(b.alloc, XML_BUFFER_ALLOC_DOUBLEIT);
2088
2089 unsafe {
2091 assert_eq!(*b.content, 0);
2092 }
2093
2094 buf_free(buf);
2095 }
2096
2097 #[test]
2098 fn test_buf_create_default_size() {
2099 let buf = buf_create(0);
2100 assert!(!buf.is_null());
2101
2102 let b = unsafe { &*buf };
2103 assert!(b.size >= MIN_BUFFER_SIZE);
2104
2105 buf_free(buf);
2106 }
2107
2108 #[test]
2109 fn test_buf_create_static() {
2110 let s: &[u8] = b"hello\0";
2111 let buf = buf_create_static(s.as_ptr() as *const xmlChar, 5);
2112 assert!(!buf.is_null());
2113
2114 let b = unsafe { &*buf };
2115 assert_eq!(b.use_, 5);
2116 assert_eq!(b.alloc, XML_BUFFER_ALLOC_IMMUTABLE);
2117
2118 unsafe {
2120 assert_eq!(*b.content.offset(0), b'h');
2121 assert_eq!(*b.content.offset(4), b'o');
2122 assert_eq!(*b.content.offset(5), 0);
2123 }
2124
2125 buf_free(buf); }
2127
2128 #[test]
2129 fn test_buf_add() {
2130 let buf = buf_create(10);
2131 assert!(!buf.is_null());
2132
2133 let s1: &[u8] = b"Hello\0";
2134 let ret = buf_add(buf, s1.as_ptr() as *const xmlChar, 5);
2135 assert_eq!(ret, 5);
2136
2137 let b = unsafe { &*buf };
2138 assert_eq!(b.use_, 5);
2139 unsafe {
2140 assert_eq!(*b.content.offset(0), b'H');
2141 assert_eq!(*b.content.offset(4), b'o');
2142 assert_eq!(*b.content.offset(5), 0); }
2144
2145 let s2: &[u8] = b" World!\0";
2147 let ret = buf_add(buf, s2.as_ptr() as *const xmlChar, 7);
2148 assert_eq!(ret, 7);
2149
2150 let b = unsafe { &*buf };
2151 assert_eq!(b.use_, 12);
2152 unsafe {
2153 assert_eq!(*b.content.offset(6), b'W');
2154 assert_eq!(*b.content.offset(11), b'!');
2155 assert_eq!(*b.content.offset(12), 0);
2156 }
2157
2158 buf_free(buf);
2159 }
2160
2161 #[test]
2162 fn test_buf_add_null() {
2163 let buf = buf_create(10);
2164 let ret = buf_add(buf, ptr::null(), 5);
2165 assert_eq!(ret, 0);
2166 buf_free(buf);
2167 }
2168
2169 #[test]
2170 fn test_buf_cat() {
2171 let buf = buf_create(10);
2172 let s: &[u8] = b"Hello\0";
2173 let ret = buf_cat(buf, s.as_ptr() as *const xmlChar);
2174 assert_eq!(ret, 5);
2175
2176 let b = unsafe { &*buf };
2177 assert_eq!(b.use_, 5);
2178
2179 buf_free(buf);
2180 }
2181
2182 #[test]
2183 fn test_buf_ccat() {
2184 let buf = buf_create(10);
2185 let ret = buf_ccat(buf, b'A' as xmlChar);
2186 assert_eq!(ret, 1);
2187
2188 let b = unsafe { &*buf };
2189 assert_eq!(b.use_, 1);
2190 unsafe {
2191 assert_eq!(*b.content, b'A');
2192 }
2193
2194 buf_free(buf);
2195 }
2196
2197 #[test]
2198 fn test_buf_empty() {
2199 let buf = buf_create(10);
2200 let s: &[u8] = b"Hello\0";
2201 buf_add(buf, s.as_ptr() as *const xmlChar, 5);
2202 assert_eq!(unsafe { &*buf }.use_, 5);
2203
2204 buf_empty(buf);
2205 let b = unsafe { &*buf };
2206 assert_eq!(b.use_, 0);
2207 unsafe {
2208 assert_eq!(*b.content, 0);
2209 }
2210
2211 buf_free(buf);
2212 }
2213
2214 #[test]
2215 fn test_buf_content() {
2216 let buf = buf_create(10);
2217 let content = buf_content(buf);
2218 assert!(!content.is_null());
2219 buf_free(buf);
2220 }
2221
2222 #[test]
2223 fn test_buf_length() {
2224 let buf = buf_create(10);
2225 assert_eq!(buf_length(buf), 0);
2226
2227 let s: &[u8] = b"Hi\0";
2228 buf_add(buf, s.as_ptr() as *const xmlChar, 2);
2229 assert_eq!(buf_length(buf), 2);
2230
2231 buf_free(buf);
2232 }
2233
2234 #[test]
2235 fn test_buf_shrink() {
2236 let buf = buf_create(10);
2237 let s: &[u8] = b"Hello World\0";
2238 buf_add(buf, s.as_ptr() as *const xmlChar, 11);
2239 assert_eq!(buf_length(buf), 11);
2240
2241 buf_shrink(buf, 5);
2242 assert_eq!(buf_length(buf), 6);
2243
2244 let b = unsafe { &*buf };
2245 unsafe {
2246 assert_eq!(*b.content.offset(6), 0); }
2248
2249 buf_shrink(buf, 100);
2251 assert_eq!(buf_length(buf), 0);
2252
2253 buf_free(buf);
2254 }
2255
2256 #[test]
2257 fn test_buf_grow() {
2258 let buf = buf_create(10);
2259 assert!(unsafe { &*buf }.size >= 10);
2260
2261 let ret = buf_grow(buf, 1000);
2262 assert_eq!(ret, 0);
2263 assert!(unsafe { &*buf }.size >= 1000);
2264
2265 buf_free(buf);
2266 }
2267
2268 #[test]
2269 fn test_buf_free_null() {
2270 buf_free(ptr::null_mut()); }
2272
2273 #[test]
2276 fn test_xml_buf_create_free() {
2277 let buf = xml_buf_create(100);
2278 assert!(!buf.is_null());
2279
2280 let b = unsafe { &*buf };
2281 assert!(!b.content.is_null());
2282 assert_eq!(b.use_, 0);
2283 assert!(b.size >= 100);
2284 assert_eq!(b.error, 0);
2285 assert_eq!(b.buffer, 0);
2286 assert_eq!(b.io, 0);
2287
2288 xml_buf_free(buf);
2289 }
2290
2291 #[test]
2292 fn test_xml_buf_add() {
2293 let buf = xml_buf_create(10);
2294 let s: &[u8] = b"Hello\0";
2295 let ret = xml_buf_add(buf, s.as_ptr() as *const xmlChar, 5);
2296 assert_eq!(ret, 5);
2297
2298 let b = unsafe { &*buf };
2299 assert_eq!(b.use_, 5);
2300
2301 xml_buf_free(buf);
2302 }
2303
2304 #[test]
2305 fn test_xml_buf_cat() {
2306 let buf = xml_buf_create(10);
2307 let s: &[u8] = b"Hello\0";
2308 let ret = xml_buf_cat(buf, s.as_ptr() as *const xmlChar);
2309 assert_eq!(ret, 5);
2310
2311 xml_buf_free(buf);
2312 }
2313
2314 #[test]
2315 fn test_xml_buf_content() {
2316 let buf = xml_buf_create(10);
2317 let content = xml_buf_content(buf);
2318 assert!(!content.is_null());
2319 xml_buf_free(buf);
2320 }
2321
2322 #[test]
2323 fn test_xml_buf_length() {
2324 let buf = xml_buf_create(10);
2325 assert_eq!(xml_buf_length(buf), 0);
2326
2327 let s: &[u8] = b"Hi\0";
2328 xml_buf_add(buf, s.as_ptr() as *const xmlChar, 2);
2329 assert_eq!(xml_buf_length(buf), 2);
2330
2331 xml_buf_free(buf);
2332 }
2333
2334 #[test]
2335 fn test_xml_buf_grow() {
2336 let buf = xml_buf_create(10);
2337 let ret = xml_buf_grow(buf, 500);
2338 assert_eq!(ret, 0);
2339 assert!(unsafe { &*buf }.size >= 500);
2340
2341 xml_buf_free(buf);
2342 }
2343
2344 #[test]
2345 fn test_xml_buf_shrink() {
2346 let buf = xml_buf_create(10);
2347 let s: &[u8] = b"Hello\0";
2348 xml_buf_add(buf, s.as_ptr() as *const xmlChar, 5);
2349 assert_eq!(xml_buf_length(buf), 5);
2350
2351 xml_buf_shrink(buf, 3);
2352 assert_eq!(xml_buf_length(buf), 2);
2353
2354 xml_buf_free(buf);
2355 }
2356
2357 #[test]
2360 fn test_input_buffer_create_mem() {
2361 let data = c("Hello XML");
2362 let buf = input_buffer_create_mem(data.as_ptr(), 9, 0); assert!(!buf.is_null());
2364
2365 let b = unsafe { &*buf };
2366 assert!(b.readcallback.is_none());
2367 assert!(!b.buffer.is_null());
2368 assert_eq!(b.error, 0);
2369
2370 let mut out = [0i8; 16];
2372 let ret = input_buffer_read(buf, out.as_mut_ptr(), 16);
2373 assert_eq!(ret, 9);
2374 assert_eq!(&out[..9], i8_slice(b"Hello XML"));
2375
2376 input_buffer_free(buf);
2377 }
2378
2379 #[test]
2380 fn test_input_buffer_create_mem_empty() {
2381 let buf = input_buffer_create_mem(ptr::null(), 0, 0);
2382 assert!(buf.is_null());
2383 }
2384
2385 #[test]
2386 fn test_input_buffer_read_partial() {
2387 let data = c("Hello XML World");
2388 let buf = input_buffer_create_mem(data.as_ptr(), 15, 0);
2389 assert!(!buf.is_null());
2390
2391 let mut out1 = [0i8; 5];
2393 let ret = input_buffer_read(buf, out1.as_mut_ptr(), 5);
2394 assert_eq!(ret, 5);
2395 assert_eq!(&out1[..5], i8_slice(b"Hello"));
2396
2397 let mut out2 = [0i8; 10];
2398 let ret = input_buffer_read(buf, out2.as_mut_ptr(), 10);
2399 assert_eq!(ret, 10);
2400 assert_eq!(&out2[..10], i8_slice(b" XML World"));
2401
2402 input_buffer_free(buf);
2403 }
2404
2405 #[test]
2406 fn test_input_buffer_push() {
2407 let buf = input_buffer_create_io(None, None, ptr::null_mut(), 0);
2408 assert!(!buf.is_null());
2409
2410 let data1 = c("<root>");
2411 let ret = input_buffer_push(buf, data1.as_ptr(), 6);
2412 assert_eq!(ret, 6);
2413
2414 let data2 = c("</root>");
2415 let ret = input_buffer_push(buf, data2.as_ptr(), 7);
2416 assert_eq!(ret, 7);
2417
2418 let mut out = [0i8; 32];
2420 let ret = input_buffer_read(buf, out.as_mut_ptr(), 32);
2421 assert_eq!(ret, 13);
2422 assert_eq!(&out[..13], i8_slice(b"<root></root>"));
2423
2424 input_buffer_free(buf);
2425 }
2426
2427 #[test]
2428 fn test_input_buffer_set_encoder() {
2429 let buf = input_buffer_create_mem(ptr::null(), 0, 0);
2430 let data = c("test");
2432 let buf = input_buffer_create_mem(data.as_ptr(), 4, 0);
2433 assert!(!buf.is_null());
2434
2435 input_buffer_set_encoder(buf, ptr::null_mut());
2437 let b = unsafe { &*buf };
2438 assert!(b.encoder.is_null());
2439
2440 input_buffer_free(buf);
2441 }
2442
2443 #[test]
2446 fn test_output_buffer_create_buffer() {
2447 let internal_buf = buf_create(100);
2448 assert!(!internal_buf.is_null());
2449
2450 let obuf = output_buffer_create_buffer(internal_buf, ptr::null_mut());
2451 assert!(!obuf.is_null());
2452
2453 let data = c("Hello Output");
2455 let ret = output_buffer_write(obuf, 12, data.as_ptr());
2459 assert_eq!(ret, 0);
2460
2461 let flushed = output_buffer_flush(obuf);
2463 assert_eq!(flushed, 12);
2464
2465 let content = output_buffer_get_content(obuf);
2467 assert!(content.is_null() || unsafe { *content } == 0);
2468
2469 let ctx = unsafe { (*obuf).context as *mut _xmlBuffer };
2471 let ctx_b = unsafe { &*ctx };
2472 assert_eq!(ctx_b.use_, 12);
2473 unsafe {
2474 assert_eq!(*ctx_b.content.offset(0), b'H' as xmlChar);
2475 }
2476
2477 output_buffer_close(obuf);
2480 }
2481
2482 #[test]
2483 fn test_output_buffer_write_string() {
2484 let internal_buf = buf_create(100);
2485 let obuf = output_buffer_create_buffer(internal_buf, ptr::null_mut());
2486 assert!(!obuf.is_null());
2487
2488 let s = c("Hello");
2489 let ret = output_buffer_write_string(obuf, s.as_ptr());
2491 assert_eq!(ret, 0);
2492
2493 output_buffer_close(obuf);
2495 }
2496
2497 #[test]
2498 fn test_output_buffer_write_char() {
2499 let internal_buf = buf_create(100);
2500 let obuf = output_buffer_create_buffer(internal_buf, ptr::null_mut());
2501 assert!(!obuf.is_null());
2502
2503 let ret = output_buffer_write_char(obuf, b'X' as c_char);
2504 assert_eq!(ret, 0);
2506
2507 output_buffer_close(obuf);
2508 }
2509
2510 #[test]
2511 fn test_output_buffer_get_content() {
2512 let internal_buf = buf_create(100);
2513 let obuf = output_buffer_create_buffer(internal_buf, ptr::null_mut());
2514 assert!(!obuf.is_null());
2515
2516 let content = output_buffer_get_content(obuf);
2517 assert!(!content.is_null());
2518
2519 output_buffer_close(obuf);
2520 }
2521
2522 #[test]
2525 fn test_check_file_exists() {
2526 let exists = check_file_exists(c("/dev/null").as_ptr());
2528 assert!(exists == 1);
2529
2530 let not_exists = check_file_exists(c("/tmp/__nonexistent_file_xyz123__").as_ptr());
2532 assert!(not_exists == 0);
2533 }
2534
2535 #[test]
2536 fn test_read_write_file() {
2537 let tmpfile = c("/tmp/libxml_rs_test_io_file.txt");
2538
2539 let data = c("Hello File I/O!");
2541 let ret = write_memory_to_file(tmpfile.as_ptr(), data.as_ptr(), 15);
2542 assert_eq!(ret, 0);
2543
2544 assert!(check_file_exists(tmpfile.as_ptr()) == 1);
2546
2547 let mut size: c_int = 0;
2549 let read_data = read_file_to_memory(tmpfile.as_ptr(), &mut size as *mut c_int);
2550 assert!(!read_data.is_null());
2551 assert_eq!(size, 15);
2552
2553 unsafe {
2554 let slice = std::slice::from_raw_parts(read_data as *const u8, size as usize);
2555 assert_eq!(slice, b"Hello File I/O!");
2556 }
2557
2558 unsafe { xmlFreeImpl(read_data as *mut c_void) };
2559
2560 std::fs::remove_file("/tmp/libxml_rs_test_io_file.txt").ok();
2562 }
2563
2564 #[test]
2565 fn test_read_file_nonexistent() {
2566 let result = read_file_to_memory(
2567 c("/tmp/__nonexistent_file_xyz456__").as_ptr(),
2568 ptr::null_mut(),
2569 );
2570 assert!(result.is_null());
2571 }
2572
2573 #[test]
2574 fn test_write_file_null() {
2575 let ret = write_memory_to_file(ptr::null(), c("data").as_ptr(), 4);
2576 assert_eq!(ret, -1);
2577 }
2578
2579 #[test]
2580 fn test_get_cwd() {
2581 let cwd = get_cwd();
2582 assert!(!cwd.is_null());
2583 unsafe {
2584 let s = CStr::from_ptr(cwd);
2585 assert!(!s.to_bytes().is_empty());
2586 xmlFreeImpl(cwd as *mut c_void);
2587 }
2588 }
2589
2590 #[test]
2593 fn test_buf_add_large_data() {
2594 let buf = buf_create(10);
2595 let mut large_data = Vec::new();
2596 large_data.resize(5000, b'X');
2597 large_data.push(0);
2598
2599 let ret = buf_add(buf, large_data.as_ptr() as *const xmlChar, 5000);
2600 assert_eq!(ret, 5000);
2601
2602 let b = unsafe { &*buf };
2603 assert_eq!(b.use_, 5000);
2604 assert!(b.size >= 5001);
2605
2606 buf_free(buf);
2607 }
2608
2609 #[test]
2610 fn test_input_buffer_free_null() {
2611 input_buffer_free(ptr::null_mut()); }
2613
2614 #[test]
2615 fn test_output_buffer_close_null() {
2616 let ret = output_buffer_close(ptr::null_mut());
2617 assert_eq!(ret, -1);
2618 }
2619
2620 #[test]
2621 fn test_buf_add_to_immutable() {
2622 let s: &[u8] = b"static\0";
2623 let buf = buf_create_static(s.as_ptr() as *const xmlChar, 6);
2624 assert!(!buf.is_null());
2625
2626 let data: &[u8] = b"more\0";
2628 let ret = buf_add(buf, data.as_ptr() as *const xmlChar, 4);
2629 assert_eq!(ret, -1); buf_free(buf);
2632 }
2633
2634 #[test]
2637 fn test_encoding_from_int() {
2638 assert_eq!(
2639 encoding_from_int(0),
2640 xmlCharEncoding::XML_CHAR_ENCODING_NONE
2641 );
2642 assert_eq!(
2643 encoding_from_int(1),
2644 xmlCharEncoding::XML_CHAR_ENCODING_UTF8
2645 );
2646 assert_eq!(
2647 encoding_from_int(10),
2648 xmlCharEncoding::XML_CHAR_ENCODING_8859_1
2649 );
2650 assert_eq!(
2651 encoding_from_int(22),
2652 xmlCharEncoding::XML_CHAR_ENCODING_ASCII
2653 );
2654 assert_eq!(
2655 encoding_from_int(999),
2656 xmlCharEncoding::XML_CHAR_ENCODING_ERROR
2657 );
2658 }
2659
2660 #[test]
2661 fn test_find_handler_for_encoding() {
2662 let handler = find_handler_for_encoding(1);
2664 assert!(handler.is_null());
2665
2666 let handler = find_handler_for_encoding(0);
2668 assert!(handler.is_null());
2669
2670 let handler = find_handler_for_encoding(-1);
2672 assert!(handler.is_null());
2673 }
2674
2675 #[test]
2676 fn test_input_buffer_with_encoding_latin1() {
2677 encoding::init_encodings();
2679
2680 let latin1_data: &[u8] = &[0x48, 0x65, 0x6C, 0x6C, 0xF6, 0x00]; let buf = input_buffer_create_mem(
2684 latin1_data.as_ptr() as *const c_char,
2685 5,
2686 10, );
2688 assert!(!buf.is_null());
2689
2690 let mut out = [0i8; 16];
2692 let ret = input_buffer_read(buf, out.as_mut_ptr(), 16);
2693 assert!(ret > 0);
2694
2695 let expected = b"Hell\xC3\xB6";
2697 assert_eq!(&out[..ret as usize], i8_slice(expected));
2698
2699 input_buffer_free(buf);
2700 }
2701
2702 #[test]
2703 fn test_output_buffer_with_encoding() {
2704 encoding::init_encodings();
2706
2707 let enc_name: &[u8] = b"ISO-8859-1\0";
2709 let handler = encoding::find_encoding_handler(enc_name.as_ptr() as *const xmlChar);
2710 assert!(!handler.is_null(), "Latin-1 handler should be available");
2711
2712 let internal_buf = buf_create(100);
2713 let obuf = output_buffer_create_buffer(internal_buf, handler);
2714 assert!(!obuf.is_null());
2715
2716 let utf8_data = unsafe { c_bytes(&[0x48, 0x65, 0x6C, 0x6C, 0xC3, 0xB6]) };
2718 let ret = output_buffer_write(obuf, 6, utf8_data.as_ptr());
2720 assert_eq!(ret, 0);
2721
2722 let flushed = output_buffer_flush(obuf);
2724 assert!(flushed > 0);
2725
2726 let ctx = unsafe { (*obuf).context as *mut _xmlBuffer };
2728 let ctx_b = unsafe { &*ctx };
2729 assert_eq!(ctx_b.use_, 5);
2731 unsafe {
2732 assert_eq!(*ctx_b.content.offset(0), 0x48); assert_eq!(*ctx_b.content.offset(4), 0xF6); }
2735
2736 output_buffer_close(obuf);
2754 buf_free(internal_buf);
2755 }
2756
2757 #[test]
2760 fn test_input_buffer_create_fd() {
2761 let fd =
2763 unsafe { libc::open(b"/dev/null\0" as *const u8 as *const c_char, libc::O_RDONLY) };
2764 assert!(fd >= 0);
2765
2766 let buf = input_buffer_create_fd(fd, 0);
2767 assert!(!buf.is_null());
2768
2769 let mut out = [0i8; 16];
2771 let ret = input_buffer_read(buf, out.as_mut_ptr(), 16);
2772 assert_eq!(ret, 0);
2773
2774 input_buffer_free(buf); }
2776
2777 #[test]
2780 fn test_input_buffer_create_io() {
2781 static mut TEST_DATA: &[u8] = b"Hello from callback!";
2783 static mut CALLED: bool = false;
2784
2785 unsafe extern "C" fn test_read(
2786 _ctx: *mut c_void,
2787 buffer: *mut c_char,
2788 len: c_int,
2789 ) -> c_int {
2790 if CALLED {
2791 return 0; }
2793 CALLED = true;
2794 let data = TEST_DATA;
2795 let to_copy = (data.len() as c_int).min(len);
2796 if to_copy > 0 {
2797 std::ptr::copy_nonoverlapping(data.as_ptr(), buffer as *mut u8, to_copy as usize);
2798 }
2799 to_copy
2800 }
2801
2802 unsafe extern "C" fn test_close(_ctx: *mut c_void) -> c_int {
2803 0
2804 }
2805
2806 let buf = input_buffer_create_io(
2807 Some(test_read as xmlInputReadCallback),
2808 Some(test_close as xmlInputCloseCallback),
2809 ptr::null_mut(),
2810 0,
2811 );
2812 assert!(!buf.is_null());
2813
2814 let mut out = [0i8; 32];
2815 let ret = input_buffer_read(buf, out.as_mut_ptr(), 32);
2816 assert!(ret > 0);
2817
2818 input_buffer_free(buf);
2819 }
2820}