1#![allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
90
91use std::ffi::CStr;
92use std::os::raw::{c_char, c_int, c_uchar, c_uint, c_void};
93use std::ptr;
94use std::sync::atomic::{AtomicBool, Ordering};
95
96use once_cell::sync::Lazy;
97use parking_lot::RwLock;
98
99use crate::abi::allocator::{xmlFreeImpl, xmlMallocImpl, xmlReallocImpl};
100use crate::abi::callbacks::{
101 xmlCharEncConvCtxtDtor, xmlCharEncConvFunc, xmlCharEncConvImpl, xmlCharEncodingInputFunc,
102 xmlCharEncodingOutputFunc,
103};
104use crate::abi::structs::{
105 _xmlBuffer, _xmlCharEncodingHandler, EncodingInputUnion, EncodingOutputUnion,
106};
107use crate::abi::types::{xmlChar, xmlCharEncoding};
108
109#[allow(dead_code)]
113const MAX_CHAR_BYTES: usize = 6;
114
115#[allow(dead_code)]
117const UTF8_BOM: [u8; 3] = [0xEF, 0xBB, 0xBF];
118
119const UTF16LE_BOM: [u8; 2] = [0xFF, 0xFE];
121
122const UTF16BE_BOM: [u8; 2] = [0xFE, 0xFF];
124
125#[derive(Clone, Copy)]
133struct HandlerPtr(*mut _xmlCharEncodingHandler);
134
135unsafe impl Send for HandlerPtr {}
136unsafe impl Sync for HandlerPtr {}
137
138static ENCODING_HANDLERS: Lazy<RwLock<Vec<HandlerPtr>>> = Lazy::new(|| RwLock::new(Vec::new()));
145
146static ENCODING_INITIALIZED: AtomicBool = AtomicBool::new(false);
148
149static ENCODING_INIT_MUTEX: parking_lot::Mutex<()> = parking_lot::Mutex::new(());
151
152#[allow(dead_code)]
161pub(crate) fn detect_encoding_from_bom(data: &[u8]) -> xmlCharEncoding {
162 if data.len() >= 3 && data[0..3] == UTF8_BOM {
163 xmlCharEncoding::XML_CHAR_ENCODING_UTF8
164 } else if data.len() >= 2 && data[0..2] == UTF16LE_BOM {
165 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE
166 } else if data.len() >= 2 && data[0..2] == UTF16BE_BOM {
167 xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE
168 } else {
169 xmlCharEncoding::XML_CHAR_ENCODING_NONE
170 }
171}
172
173#[allow(dead_code)]
178pub(crate) fn detect_encoding_from_declaration(data: &[u8]) -> Option<Vec<u8>> {
179 let start = if data.len() >= 3 && data[0..3] == UTF8_BOM {
181 3
182 } else if data.len() >= 2 && (data[0..2] == UTF16LE_BOM || data[0..2] == UTF16BE_BOM) {
183 return None;
185 } else {
186 0
187 };
188
189 let remaining = &data[start..];
190
191 if remaining.len() < 5 || !remaining[0..5].eq_ignore_ascii_case(b"<?xml") {
193 return None;
194 }
195
196 let pi_end = remaining.windows(2).position(|w| w == b"?>")?;
198 let decl_content = &remaining[5..pi_end];
199
200 let decl_str = core::str::from_utf8(decl_content).ok()?;
202 let lower = decl_str.to_ascii_lowercase();
203
204 let enc_pos = lower.find("encoding")?;
206
207 let after_enc = &decl_content[enc_pos + 8..];
209 let after_enc_str = core::str::from_utf8(after_enc).ok()?;
210 let after_enc_trimmed = after_enc_str.trim_start();
211
212 if !after_enc_trimmed.starts_with('=') {
213 return None;
214 }
215
216 let after_eq = after_enc_trimmed[1..].trim_start();
217
218 let quote = after_eq.chars().next()?;
220 if quote != '"' && quote != '\'' {
221 return None;
222 }
223
224 let value_end = after_eq[1..].find(quote)?;
226 let encoding_value = &after_eq[1..=value_end];
227
228 Some(encoding_value.to_ascii_lowercase().as_bytes().to_vec())
229}
230
231pub(crate) fn encoding_from_name(name: &[u8]) -> xmlCharEncoding {
236 let s = core::str::from_utf8(name).unwrap_or("");
237 let s = s.trim().to_ascii_lowercase();
238
239 match s.as_str() {
240 "utf-8" | "utf8" => xmlCharEncoding::XML_CHAR_ENCODING_UTF8,
242
243 "utf-16" | "utf-16le" | "utf16le" => xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE,
245 "utf-16be" | "utf16be" => xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE,
246
247 "iso-8859-1" | "iso_8859-1" | "latin1" | "latin-1" | "l1" | "cp819" | "ibm819"
249 | "iso-ir-100" | "iso_8859-1:1987" => xmlCharEncoding::XML_CHAR_ENCODING_8859_1,
250 "iso-8859-2" | "iso_8859-2" | "latin2" | "latin-2" | "l2" => {
251 xmlCharEncoding::XML_CHAR_ENCODING_8859_2
252 }
253 "iso-8859-3" | "iso_8859-3" | "latin3" | "latin-3" | "l3" => {
254 xmlCharEncoding::XML_CHAR_ENCODING_8859_3
255 }
256 "iso-8859-4" | "iso_8859-4" | "latin4" | "latin-4" | "l4" => {
257 xmlCharEncoding::XML_CHAR_ENCODING_8859_4
258 }
259 "iso-8859-5" | "iso_8859-5" | "cyrillic" => xmlCharEncoding::XML_CHAR_ENCODING_8859_5,
260 "iso-8859-6" | "iso_8859-6" | "arabic" => xmlCharEncoding::XML_CHAR_ENCODING_8859_6,
261 "iso-8859-7" | "iso_8859-7" | "greek" => xmlCharEncoding::XML_CHAR_ENCODING_8859_7,
262 "iso-8859-8" | "iso_8859-8" | "hebrew" => xmlCharEncoding::XML_CHAR_ENCODING_8859_8,
263 "iso-8859-9" | "iso_8859-9" | "latin5" | "latin-5" | "l5" | "turkish" => {
264 xmlCharEncoding::XML_CHAR_ENCODING_8859_9
265 }
266
267 "ascii" | "us-ascii" | "us" | "ansi_x3.4-1968" | "ansi_x3.4-1986" | "iso-ir-6"
269 | "iso_646.irv:1991" | "cp367" | "ibm367" => xmlCharEncoding::XML_CHAR_ENCODING_ASCII,
270
271 "iso-2022-jp" | "iso2022-jp" => xmlCharEncoding::XML_CHAR_ENCODING_2022_JP,
273 "shift_jis" | "shift-jis" | "sjis" | "cp932" => {
274 xmlCharEncoding::XML_CHAR_ENCODING_SHIFT_JIS
275 }
276 "euc-jp" | "eucjp" => xmlCharEncoding::XML_CHAR_ENCODING_EUC_JP,
277
278 "ucs-4" | "ucs4" => xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE,
280 "ucs-4le" | "ucs4le" => xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE,
281 "ucs-4be" | "ucs4be" => xmlCharEncoding::XML_CHAR_ENCODING_UCS4BE,
282 "ucs-2" | "ucs2" => xmlCharEncoding::XML_CHAR_ENCODING_UCS2,
283
284 "ebcdic" | "cp037" | "ibm037" => xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC,
286
287 _ => xmlCharEncoding::XML_CHAR_ENCODING_ERROR,
288 }
289}
290
291pub(crate) const fn encoding_name(enc: xmlCharEncoding) -> Option<&'static [u8]> {
295 match enc {
296 xmlCharEncoding::XML_CHAR_ENCODING_UTF8 => Some(b"UTF-8" as &[u8]),
297 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE => Some(b"UTF-16LE" as &[u8]),
298 xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE => Some(b"UTF-16BE" as &[u8]),
299 xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE => Some(b"UCS-4LE" as &[u8]),
300 xmlCharEncoding::XML_CHAR_ENCODING_UCS4BE => Some(b"UCS-4BE" as &[u8]),
301 xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC => Some(b"EBCDIC" as &[u8]),
302 xmlCharEncoding::XML_CHAR_ENCODING_UCS4_2143 => Some(b"UCS-4-2143" as &[u8]),
303 xmlCharEncoding::XML_CHAR_ENCODING_UCS4_3412 => Some(b"UCS-4-3412" as &[u8]),
304 xmlCharEncoding::XML_CHAR_ENCODING_UCS2 => Some(b"UCS-2" as &[u8]),
305 xmlCharEncoding::XML_CHAR_ENCODING_8859_1 => Some(b"ISO-8859-1" as &[u8]),
306 xmlCharEncoding::XML_CHAR_ENCODING_8859_2 => Some(b"ISO-8859-2" as &[u8]),
307 xmlCharEncoding::XML_CHAR_ENCODING_8859_3 => Some(b"ISO-8859-3" as &[u8]),
308 xmlCharEncoding::XML_CHAR_ENCODING_8859_4 => Some(b"ISO-8859-4" as &[u8]),
309 xmlCharEncoding::XML_CHAR_ENCODING_8859_5 => Some(b"ISO-8859-5" as &[u8]),
310 xmlCharEncoding::XML_CHAR_ENCODING_8859_6 => Some(b"ISO-8859-6" as &[u8]),
311 xmlCharEncoding::XML_CHAR_ENCODING_8859_7 => Some(b"ISO-8859-7" as &[u8]),
312 xmlCharEncoding::XML_CHAR_ENCODING_8859_8 => Some(b"ISO-8859-8" as &[u8]),
313 xmlCharEncoding::XML_CHAR_ENCODING_8859_9 => Some(b"ISO-8859-9" as &[u8]),
314 xmlCharEncoding::XML_CHAR_ENCODING_2022_JP => Some(b"ISO-2022-JP" as &[u8]),
315 xmlCharEncoding::XML_CHAR_ENCODING_SHIFT_JIS => Some(b"SHIFT_JIS" as &[u8]),
316 xmlCharEncoding::XML_CHAR_ENCODING_EUC_JP => Some(b"EUC-JP" as &[u8]),
317 xmlCharEncoding::XML_CHAR_ENCODING_ASCII => Some(b"US-ASCII" as &[u8]),
318 _ => None,
319 }
320}
321
322#[allow(dead_code)]
330pub(crate) const fn utf8_valid(data: &[u8]) -> bool {
331 core::str::from_utf8(data).is_ok()
332}
333
334#[allow(dead_code)]
346pub(crate) const fn is_valid_xml_char(cp: u32) -> bool {
347 matches!(
348 cp,
349 0x9 | 0xA | 0xD | 0x20..=0xD7FF | 0xE000..=0xFFFD | 0x10000..=0x10FFFF
350 )
351}
352
353#[inline]
359const fn read_utf16le_unit(data: &[u8]) -> Option<u16> {
360 if data.len() < 2 {
361 return None;
362 }
363 Some(u16::from_le_bytes([data[0], data[1]]))
364}
365
366#[inline]
368const fn read_utf16be_unit(data: &[u8]) -> Option<u16> {
369 if data.len() < 2 {
370 return None;
371 }
372 Some(u16::from_be_bytes([data[0], data[1]]))
373}
374
375const fn encode_codepoint_to_utf8(cp: u32, out: &mut [u8]) -> usize {
379 if cp < 0x80 {
380 if !out.is_empty() {
381 out[0] = cp as u8;
382 }
383 1
384 } else if cp < 0x800 {
385 if out.len() < 2 {
386 return 0;
387 }
388 out[0] = 0xC0 | ((cp >> 6) as u8);
389 out[1] = 0x80 | (cp as u8 & 0x3F);
390 2
391 } else if cp < 0x10000 {
392 if out.len() < 3 {
393 return 0;
394 }
395 out[0] = 0xE0 | ((cp >> 12) as u8);
396 out[1] = 0x80 | ((cp >> 6) as u8 & 0x3F);
397 out[2] = 0x80 | (cp as u8 & 0x3F);
398 3
399 } else if cp < 0x110000 {
400 if out.len() < 4 {
401 return 0;
402 }
403 out[0] = 0xF0 | ((cp >> 18) as u8);
404 out[1] = 0x80 | ((cp >> 12) as u8 & 0x3F);
405 out[2] = 0x80 | ((cp >> 6) as u8 & 0x3F);
406 out[3] = 0x80 | (cp as u8 & 0x3F);
407 4
408 } else {
409 0
410 }
411}
412
413pub(crate) fn utf16le_to_utf8(data: &[u8]) -> Result<Vec<u8>, ()> {
418 if data.is_empty() {
419 return Ok(Vec::new());
420 }
421
422 let offset = if data.len() >= 2 && data[0..2] == UTF16LE_BOM {
424 2
425 } else {
426 0
427 };
428
429 let mut result = Vec::with_capacity(data.len() / 2 + data.len() / 4);
430 let mut i = offset;
431
432 while i < data.len() {
433 let unit = read_utf16le_unit(&data[i..]).ok_or(())?;
434 i += 2;
435
436 if (0xD800..=0xDBFF).contains(&unit) {
437 let low = read_utf16le_unit(&data[i..]).ok_or(())?;
439 i += 2;
440
441 if !(0xDC00..=0xDFFF).contains(&low) {
442 return Err(());
443 }
444
445 let cp = 0x10000 + ((unit as u32 - 0xD800) << 10) + (low as u32 - 0xDC00);
446 let mut buf = [0u8; 4];
447 let n = encode_codepoint_to_utf8(cp, &mut buf);
448 if n == 0 {
449 return Err(());
450 }
451 result.extend_from_slice(&buf[..n]);
452 } else if (0xDC00..=0xDFFF).contains(&unit) {
453 return Err(());
455 } else {
456 let cp = unit as u32;
457 let mut buf = [0u8; 4];
458 let n = encode_codepoint_to_utf8(cp, &mut buf);
459 result.extend_from_slice(&buf[..n]);
460 }
461 }
462
463 Ok(result)
464}
465
466pub(crate) fn utf16be_to_utf8(data: &[u8]) -> Result<Vec<u8>, ()> {
470 if data.is_empty() {
471 return Ok(Vec::new());
472 }
473
474 let offset = if data.len() >= 2 && data[0..2] == UTF16BE_BOM {
476 2
477 } else {
478 0
479 };
480
481 let mut result = Vec::with_capacity(data.len() / 2 + data.len() / 4);
482 let mut i = offset;
483
484 while i < data.len() {
485 let unit = read_utf16be_unit(&data[i..]).ok_or(())?;
486 i += 2;
487
488 if (0xD800..=0xDBFF).contains(&unit) {
489 let low = read_utf16be_unit(&data[i..]).ok_or(())?;
491 i += 2;
492
493 if !(0xDC00..=0xDFFF).contains(&low) {
494 return Err(());
495 }
496
497 let cp = 0x10000 + ((unit as u32 - 0xD800) << 10) + (low as u32 - 0xDC00);
498 let mut buf = [0u8; 4];
499 let n = encode_codepoint_to_utf8(cp, &mut buf);
500 if n == 0 {
501 return Err(());
502 }
503 result.extend_from_slice(&buf[..n]);
504 } else if (0xDC00..=0xDFFF).contains(&unit) {
505 return Err(());
507 } else {
508 let cp = unit as u32;
509 let mut buf = [0u8; 4];
510 let n = encode_codepoint_to_utf8(cp, &mut buf);
511 result.extend_from_slice(&buf[..n]);
512 }
513 }
514
515 Ok(result)
516}
517
518fn encode_codepoint_to_utf16le(cp: u32, out: &mut [u8]) -> usize {
522 if cp < 0x10000 {
523 if out.len() < 2 {
524 return 0;
525 }
526 let u = cp as u16;
527 out[..2].copy_from_slice(&u.to_le_bytes());
528 2
529 } else if cp < 0x110000 {
530 if out.len() < 4 {
531 return 0;
532 }
533 let cp = cp - 0x10000;
534 let high = 0xD800 | ((cp >> 10) as u16);
535 let low = 0xDC00 | (cp as u16 & 0x3FF);
536 out[..2].copy_from_slice(&high.to_le_bytes());
537 out[2..4].copy_from_slice(&low.to_le_bytes());
538 4
539 } else {
540 0
541 }
542}
543
544pub(crate) fn utf8_to_utf16le(data: &[u8]) -> Result<Vec<u8>, ()> {
548 let s = core::str::from_utf8(data).map_err(|_| ())?;
549 let mut result = Vec::with_capacity(data.len() * 2);
550
551 for ch in s.chars() {
552 let cp = ch as u32;
553 let mut buf = [0u8; 4];
554 let n = encode_codepoint_to_utf16le(cp, &mut buf);
555 if n == 0 {
556 return Err(());
557 }
558 result.extend_from_slice(&buf[..n]);
559 }
560
561 Ok(result)
562}
563
564#[allow(dead_code)]
573pub(crate) fn latin1_to_utf8(data: &[u8]) -> Vec<u8> {
574 let mut result = Vec::with_capacity(data.len() * 2);
575
576 for &byte in data {
577 let cp = byte as u32;
578 let mut buf = [0u8; 2];
579 let n = encode_codepoint_to_utf8(cp, &mut buf);
580 result.extend_from_slice(&buf[..n]);
581 }
582
583 result
584}
585
586pub(crate) fn utf8_to_latin1(data: &[u8]) -> Result<Vec<u8>, ()> {
591 let s = core::str::from_utf8(data).map_err(|_| ())?;
592 let mut result = Vec::with_capacity(data.len());
593
594 for ch in s.chars() {
595 let cp = ch as u32;
596 if cp > 0xFF {
597 return Err(());
598 }
599 result.push(cp as u8);
600 }
601
602 Ok(result)
603}
604
605pub(crate) fn init_encodings() {
620 if ENCODING_INITIALIZED.load(Ordering::SeqCst) {
621 return;
622 }
623 let _guard = ENCODING_INIT_MUTEX.lock();
629 if ENCODING_INITIALIZED.load(Ordering::SeqCst) {
630 return;
631 }
632 register_builtin_handlers();
633 ENCODING_INITIALIZED.store(true, Ordering::SeqCst);
634}
635
636fn register_builtin_handlers() {
638 register_handler(
640 b"UTF-8\0",
641 xmlCharEncoding::XML_CHAR_ENCODING_UTF8,
642 xmlCharEncoding::XML_CHAR_ENCODING_UTF8,
643 Some(utf8_input_func as xmlCharEncodingInputFunc),
644 Some(utf8_output_func as xmlCharEncodingOutputFunc),
645 );
646
647 register_handler(
649 b"UTF-16LE\0",
650 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE,
651 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE,
652 Some(utf16le_input_func as xmlCharEncodingInputFunc),
653 Some(utf16le_output_func as xmlCharEncodingOutputFunc),
654 );
655
656 register_handler(
658 b"UTF-16BE\0",
659 xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE,
660 xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE,
661 Some(utf16be_input_func as xmlCharEncodingInputFunc),
662 Some(utf16be_output_func as xmlCharEncodingOutputFunc),
663 );
664
665 register_handler(
667 b"ISO-8859-1\0",
668 xmlCharEncoding::XML_CHAR_ENCODING_8859_1,
669 xmlCharEncoding::XML_CHAR_ENCODING_8859_1,
670 Some(latin1_input_func as xmlCharEncodingInputFunc),
671 Some(latin1_output_func as xmlCharEncodingOutputFunc),
672 );
673
674 register_handler(
680 b"windows-1252\0",
681 xmlCharEncoding::XML_CHAR_ENCODING_ERROR,
682 xmlCharEncoding::XML_CHAR_ENCODING_ERROR,
683 Some(cp1252_input_func as xmlCharEncodingInputFunc),
684 Some(cp1252_output_func as xmlCharEncodingOutputFunc),
685 );
686 register_handler(
687 b"cp1252\0",
688 xmlCharEncoding::XML_CHAR_ENCODING_ERROR,
689 xmlCharEncoding::XML_CHAR_ENCODING_ERROR,
690 Some(cp1252_input_func as xmlCharEncodingInputFunc),
691 Some(cp1252_output_func as xmlCharEncodingOutputFunc),
692 );
693
694 register_handler(
699 b"US-ASCII\0",
700 xmlCharEncoding::XML_CHAR_ENCODING_ASCII,
701 xmlCharEncoding::XML_CHAR_ENCODING_ASCII,
702 Some(ascii_input_func as xmlCharEncodingInputFunc),
703 Some(ascii_output_func as xmlCharEncodingOutputFunc),
704 );
705 register_handler(
706 b"ASCII\0",
707 xmlCharEncoding::XML_CHAR_ENCODING_ASCII,
708 xmlCharEncoding::XML_CHAR_ENCODING_ASCII,
709 Some(ascii_input_func as xmlCharEncodingInputFunc),
710 Some(ascii_output_func as xmlCharEncodingOutputFunc),
711 );
712
713 register_handler(
718 b"UTF-16\0",
719 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE,
720 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE,
721 Some(utf16le_input_func as xmlCharEncodingInputFunc),
722 Some(utf16le_output_func as xmlCharEncodingOutputFunc),
723 );
724
725 register_handler(
736 b"SHIFT_JIS\0",
737 xmlCharEncoding::XML_CHAR_ENCODING_SHIFT_JIS,
738 xmlCharEncoding::XML_CHAR_ENCODING_SHIFT_JIS,
739 Some(shift_jis_input_func as xmlCharEncodingInputFunc),
740 Some(shift_jis_output_func as xmlCharEncodingOutputFunc),
741 );
742 register_handler(
743 b"SJIS\0",
744 xmlCharEncoding::XML_CHAR_ENCODING_SHIFT_JIS,
745 xmlCharEncoding::XML_CHAR_ENCODING_SHIFT_JIS,
746 Some(shift_jis_input_func as xmlCharEncodingInputFunc),
747 Some(shift_jis_output_func as xmlCharEncodingOutputFunc),
748 );
749 register_handler(
750 b"CP932\0",
751 xmlCharEncoding::XML_CHAR_ENCODING_SHIFT_JIS,
752 xmlCharEncoding::XML_CHAR_ENCODING_SHIFT_JIS,
753 Some(shift_jis_input_func as xmlCharEncodingInputFunc),
754 Some(shift_jis_output_func as xmlCharEncodingOutputFunc),
755 );
756 register_handler(
757 b"EUC-JP\0",
758 xmlCharEncoding::XML_CHAR_ENCODING_EUC_JP,
759 xmlCharEncoding::XML_CHAR_ENCODING_EUC_JP,
760 Some(euc_jp_input_func as xmlCharEncodingInputFunc),
761 Some(euc_jp_output_func as xmlCharEncodingOutputFunc),
762 );
763 register_handler(
764 b"EUCJP\0",
765 xmlCharEncoding::XML_CHAR_ENCODING_EUC_JP,
766 xmlCharEncoding::XML_CHAR_ENCODING_EUC_JP,
767 Some(euc_jp_input_func as xmlCharEncodingInputFunc),
768 Some(euc_jp_output_func as xmlCharEncodingOutputFunc),
769 );
770
771 macro_rules! register_iso8859 {
778 ($name:literal, $enc:expr, $input:ident, $output:ident) => {
779 register_handler(
780 concat!($name, "\0").as_bytes(),
781 xmlCharEncoding::XML_CHAR_ENCODING_ERROR,
782 xmlCharEncoding::XML_CHAR_ENCODING_ERROR,
783 Some($input as xmlCharEncodingInputFunc),
784 Some($output as xmlCharEncodingOutputFunc),
785 );
786 let _ = $enc; };
788 }
789 register_iso8859!(
790 "ISO-8859-2",
791 encoding_rs::ISO_8859_2,
792 iso_8859_2_input_func,
793 iso_8859_2_output_func
794 );
795 register_iso8859!(
796 "ISO-8859-3",
797 encoding_rs::ISO_8859_3,
798 iso_8859_3_input_func,
799 iso_8859_3_output_func
800 );
801 register_iso8859!(
802 "ISO-8859-4",
803 encoding_rs::ISO_8859_4,
804 iso_8859_4_input_func,
805 iso_8859_4_output_func
806 );
807 register_iso8859!(
808 "ISO-8859-5",
809 encoding_rs::ISO_8859_5,
810 iso_8859_5_input_func,
811 iso_8859_5_output_func
812 );
813 register_iso8859!(
814 "ISO-8859-6",
815 encoding_rs::ISO_8859_6,
816 iso_8859_6_input_func,
817 iso_8859_6_output_func
818 );
819 register_iso8859!(
820 "ISO-8859-7",
821 encoding_rs::ISO_8859_7,
822 iso_8859_7_input_func,
823 iso_8859_7_output_func
824 );
825 register_iso8859!(
826 "ISO-8859-8",
827 encoding_rs::ISO_8859_8,
828 iso_8859_8_input_func,
829 iso_8859_8_output_func
830 );
831 register_iso8859!(
832 "ISO-8859-9",
833 encoding_rs::WINDOWS_1254,
834 iso_8859_9_input_func,
835 iso_8859_9_output_func
836 );
837 register_iso8859!(
838 "ISO-8859-10",
839 encoding_rs::ISO_8859_10,
840 iso_8859_10_input_func,
841 iso_8859_10_output_func
842 );
843 register_iso8859!(
844 "ISO-8859-11",
845 encoding_rs::WINDOWS_874,
846 iso_8859_11_input_func,
847 iso_8859_11_output_func
848 );
849 register_iso8859!(
850 "windows-874",
851 encoding_rs::WINDOWS_874,
852 iso_8859_11_input_func,
853 iso_8859_11_output_func
854 );
855 register_iso8859!(
856 "ISO-8859-13",
857 encoding_rs::ISO_8859_13,
858 iso_8859_13_input_func,
859 iso_8859_13_output_func
860 );
861 register_iso8859!(
862 "ISO-8859-14",
863 encoding_rs::ISO_8859_14,
864 iso_8859_14_input_func,
865 iso_8859_14_output_func
866 );
867 register_iso8859!(
868 "ISO-8859-15",
869 encoding_rs::ISO_8859_15,
870 iso_8859_15_input_func,
871 iso_8859_15_output_func
872 );
873 register_iso8859!(
874 "ISO-8859-16",
875 encoding_rs::ISO_8859_16,
876 iso_8859_16_input_func,
877 iso_8859_16_output_func
878 );
879
880 register_handler(
883 b"ISO-2022-JP\0",
884 xmlCharEncoding::XML_CHAR_ENCODING_2022_JP,
885 xmlCharEncoding::XML_CHAR_ENCODING_2022_JP,
886 Some(iso_2022_jp_input_func as xmlCharEncodingInputFunc),
887 Some(iso_2022_jp_output_func as xmlCharEncodingOutputFunc),
888 );
889
890 register_handler(
893 b"UCS-2\0",
894 xmlCharEncoding::XML_CHAR_ENCODING_UCS2,
895 xmlCharEncoding::XML_CHAR_ENCODING_UCS2,
896 Some(ucs2_input_func as xmlCharEncodingInputFunc),
897 Some(ucs2_output_func as xmlCharEncodingOutputFunc),
898 );
899 register_handler(
900 b"UCS-4LE\0",
901 xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE,
902 xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE,
903 Some(ucs4le_input_func as xmlCharEncodingInputFunc),
904 Some(ucs4le_output_func as xmlCharEncodingOutputFunc),
905 );
906 register_handler(
907 b"UCS-4BE\0",
908 xmlCharEncoding::XML_CHAR_ENCODING_UCS4BE,
909 xmlCharEncoding::XML_CHAR_ENCODING_UCS4BE,
910 Some(ucs4be_input_func as xmlCharEncodingInputFunc),
911 Some(ucs4be_output_func as xmlCharEncodingOutputFunc),
912 );
913 register_handler(
914 b"UCS-4\0",
915 xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE,
916 xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE,
917 Some(ucs4le_input_func as xmlCharEncodingInputFunc),
918 Some(ucs4le_output_func as xmlCharEncodingOutputFunc),
919 );
920
921 register_handler(
924 b"IBM037\0",
925 xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC,
926 xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC,
927 Some(ebcdic_input_func as xmlCharEncodingInputFunc),
928 Some(ebcdic_output_func as xmlCharEncodingOutputFunc),
929 );
930 register_handler(
931 b"EBCDIC-US\0",
932 xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC,
933 xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC,
934 Some(ebcdic_input_func as xmlCharEncodingInputFunc),
935 Some(ebcdic_output_func as xmlCharEncodingOutputFunc),
936 );
937 register_handler(
938 b"EBCDIC\0",
939 xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC,
940 xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC,
941 Some(ebcdic_input_func as xmlCharEncodingInputFunc),
942 Some(ebcdic_output_func as xmlCharEncodingOutputFunc),
943 );
944}
945
946fn register_handler(
956 name_bytes: &[u8],
957 _input_enc: xmlCharEncoding,
958 _output_enc: xmlCharEncoding,
959 input_func: Option<xmlCharEncodingInputFunc>,
960 output_func: Option<xmlCharEncodingOutputFunc>,
961) {
962 let name_raw =
963 unsafe { crate::abi::allocator::xmlMemStrdupImpl(name_bytes.as_ptr() as *const c_char) };
964 if name_raw.is_null() {
965 return;
966 }
967
968 let handler = unsafe { xmlMallocImpl(size_of::<_xmlCharEncodingHandler>()) }
969 as *mut _xmlCharEncodingHandler;
970
971 if handler.is_null() {
972 unsafe { xmlFreeImpl(name_raw) };
973 return;
974 }
975
976 unsafe {
977 ptr::write(
978 handler,
979 _xmlCharEncodingHandler {
980 name: name_raw as *mut c_char,
981 input: EncodingInputUnion {
982 legacyFunc: input_func,
983 },
984 output: EncodingOutputUnion {
985 legacyFunc: output_func,
986 },
987 inputCtxt: ptr::null_mut(),
988 outputCtxt: ptr::null_mut(),
989 ctxtDtor: None,
990 flags: 0,
991 },
992 );
993 }
994
995 add_encoding_handler(handler);
996}
997
998pub(crate) fn cleanup_encodings() {
1009 let mut handlers = ENCODING_HANDLERS.write();
1010 for &handler in handlers.iter() {
1011 let ptr = handler.0;
1012 if !ptr.is_null() {
1013 unsafe {
1014 if !(*ptr).name.is_null() {
1015 xmlFreeImpl((*ptr).name as *mut c_void);
1016 }
1017 xmlFreeImpl(ptr as *mut c_void);
1018 }
1019 }
1020 }
1021 handlers.clear();
1022 drop(handlers);
1027 ENCODING_INITIALIZED.store(false, Ordering::SeqCst);
1028}
1029
1030pub(crate) fn find_encoding_handler(name: *const xmlChar) -> *mut _xmlCharEncodingHandler {
1042 if name.is_null() {
1043 return ptr::null_mut();
1044 }
1045
1046 init_encodings();
1050
1051 let name_str = unsafe {
1052 match CStr::from_ptr(name as *const c_char).to_bytes() {
1053 b"" => return ptr::null_mut(),
1054 s => s,
1055 }
1056 };
1057
1058 let handlers = ENCODING_HANDLERS.read();
1059 for &handler in handlers.iter() {
1060 let ptr = handler.0;
1061 if ptr.is_null() {
1062 continue;
1063 }
1064 let h_name = unsafe {
1065 if (*ptr).name.is_null() {
1066 continue;
1067 }
1068 CStr::from_ptr((*ptr).name).to_bytes()
1069 };
1070
1071 if name_str.eq_ignore_ascii_case(h_name) {
1072 return ptr;
1073 }
1074 }
1075
1076 ptr::null_mut()
1077}
1078
1079pub(crate) fn clone_encoding_handler_for_find(
1097 src: *mut _xmlCharEncodingHandler,
1098) -> *mut _xmlCharEncodingHandler {
1099 if src.is_null() {
1100 return ptr::null_mut();
1101 }
1102 let name_raw = unsafe {
1103 let nm = (*src).name;
1104 if nm.is_null() {
1105 ptr::null_mut()
1106 } else {
1107 crate::abi::allocator::xmlMemStrdupImpl(nm)
1108 }
1109 };
1110 let handler = unsafe { xmlMallocImpl(size_of::<_xmlCharEncodingHandler>()) }
1111 as *mut _xmlCharEncodingHandler;
1112 if handler.is_null() {
1113 if !name_raw.is_null() {
1114 unsafe { crate::abi::allocator::xmlFreeImpl(name_raw) };
1115 }
1116 return ptr::null_mut();
1117 }
1118 unsafe {
1119 ptr::write(
1120 handler,
1121 _xmlCharEncodingHandler {
1122 name: name_raw as *mut c_char,
1123 input: ptr::read(&(*src).input),
1124 output: ptr::read(&(*src).output),
1125 inputCtxt: (*src).inputCtxt,
1126 outputCtxt: (*src).outputCtxt,
1127 ctxtDtor: (*src).ctxtDtor,
1128 flags: (*src).flags,
1129 },
1130 );
1131 }
1132 handler
1133}
1134
1135pub(crate) const XML_HANDLER_STATIC: c_int = 0x01;
1139
1140pub(crate) fn xmlFindCharEncodingHandler_owned(
1157 name: *const xmlChar,
1158) -> *mut _xmlCharEncodingHandler {
1159 if name.is_null() {
1160 return ptr::null_mut();
1161 }
1162 let name_bytes = unsafe {
1163 let len = libc::strlen(name as *const c_char);
1164 core::slice::from_raw_parts(name as *const u8, len)
1165 };
1166
1167 if encoding_from_name(name_bytes) == xmlCharEncoding::XML_CHAR_ENCODING_UTF8 {
1169 let utf8 = find_encoding_handler(c"UTF-8".as_ptr() as *const xmlChar);
1170 if utf8.is_null() {
1171 return ptr::null_mut();
1172 }
1173 unsafe {
1175 (*utf8).flags |= XML_HANDLER_STATIC;
1176 }
1177 return utf8;
1178 }
1179
1180 let mut entry = find_encoding_handler(name as *const xmlChar);
1184 if entry.is_null() {
1185 if let Some(canon) = encoding_name(encoding_from_name(name_bytes)) {
1186 entry = find_encoding_handler(canon.as_ptr() as *const xmlChar);
1187 }
1188 }
1189 clone_encoding_handler_for_find(entry)
1192}
1193
1194pub(crate) fn add_encoding_handler(handler: *mut _xmlCharEncodingHandler) -> c_int {
1198 if handler.is_null() {
1199 return -1;
1200 }
1201
1202 let mut handlers = ENCODING_HANDLERS.write();
1203 handlers.push(HandlerPtr(handler));
1204 0
1205}
1206
1207#[allow(dead_code)]
1223pub(crate) fn char_enc_in_func(
1224 handler: *mut _xmlCharEncodingHandler,
1225 out: &mut [u8],
1226 in_data: &[u8],
1227) -> c_int {
1228 if handler.is_null() {
1229 return -1;
1230 }
1231
1232 let h = unsafe { &*handler };
1233 let input_func = unsafe { h.input.legacyFunc };
1234 let input_func = match input_func {
1235 Some(f) => f,
1236 None => return -1,
1237 };
1238
1239 let mut outlen = out.len() as c_int;
1240 let mut inlen = in_data.len() as c_int;
1241
1242 unsafe { input_func(out.as_mut_ptr(), &mut outlen, in_data.as_ptr(), &mut inlen) }
1243}
1244
1245#[allow(dead_code)]
1257pub(crate) fn char_enc_out_func(
1258 handler: *mut _xmlCharEncodingHandler,
1259 out: &mut [u8],
1260 in_data: &[u8],
1261) -> c_int {
1262 if handler.is_null() {
1263 return -1;
1264 }
1265
1266 let h = unsafe { &*handler };
1267 let output_func = unsafe { h.output.legacyFunc };
1268 let output_func = match output_func {
1269 Some(f) => f,
1270 None => return -1,
1271 };
1272
1273 let mut outlen = out.len() as c_int;
1274 let mut inlen = in_data.len() as c_int;
1275
1276 unsafe { output_func(out.as_mut_ptr(), &mut outlen, in_data.as_ptr(), &mut inlen) }
1277}
1278
1279pub(crate) fn char_enc_in(
1295 handler: *mut _xmlCharEncodingHandler,
1296 out: *mut _xmlBuffer,
1297 in_: *mut _xmlBuffer,
1298) -> c_int {
1299 if handler.is_null() || out.is_null() || in_.is_null() {
1300 return -1;
1301 }
1302
1303 let h = unsafe { &*handler };
1304 let input_func = unsafe { h.input.legacyFunc };
1305 let input_func = match input_func {
1306 Some(f) => f,
1307 None => return -1,
1308 };
1309
1310 let in_buf = unsafe { &*in_ };
1311 let out_buf = unsafe { &mut *out };
1312
1313 if in_buf.content.is_null() || in_buf.use_ == 0 {
1314 return 0;
1315 }
1316
1317 let in_data = unsafe { core::slice::from_raw_parts(in_buf.content, in_buf.use_ as usize) };
1318
1319 let out_capacity = (in_buf.use_ as usize).saturating_mul(3).max(256);
1321 let mut out_vec = vec![0u8; out_capacity];
1322 let mut out_len = out_capacity as c_int;
1323 let mut in_len = in_buf.use_ as c_int;
1324
1325 let ret = unsafe {
1326 input_func(
1327 out_vec.as_mut_ptr(),
1328 &mut out_len,
1329 in_data.as_ptr(),
1330 &mut in_len,
1331 )
1332 };
1333
1334 if ret < 0 {
1335 return -1;
1336 }
1337
1338 let written = ret as usize;
1339
1340 append_to_xml_buffer(out_buf, &out_vec[..written]);
1342
1343 written as c_int
1344}
1345
1346pub(crate) fn char_enc_out(
1362 handler: *mut _xmlCharEncodingHandler,
1363 out: *mut _xmlBuffer,
1364 in_: *mut _xmlBuffer,
1365) -> c_int {
1366 if handler.is_null() || out.is_null() || in_.is_null() {
1367 return -1;
1368 }
1369
1370 let h = unsafe { &*handler };
1371 let output_func = unsafe { h.output.legacyFunc };
1372 let output_func = match output_func {
1373 Some(f) => f,
1374 None => return -1,
1375 };
1376
1377 let in_buf = unsafe { &*in_ };
1378 let out_buf = unsafe { &mut *out };
1379
1380 if in_buf.content.is_null() || in_buf.use_ == 0 {
1381 return 0;
1382 }
1383
1384 let mut in_data = unsafe { core::slice::from_raw_parts(in_buf.content, in_buf.use_ as usize) };
1385
1386 const ENC_INPUT_ERROR: c_int = -2;
1395 let mut total_written: usize = 0;
1396 loop {
1397 let out_capacity = (in_data.len().saturating_mul(5)).max(64) + 16;
1402 let mut out_vec = vec![0u8; out_capacity];
1403 let mut out_len = out_capacity as c_int;
1404 let mut in_len = in_data.len() as c_int;
1405 let ret = unsafe {
1406 output_func(
1407 out_vec.as_mut_ptr(),
1408 &mut out_len,
1409 in_data.as_ptr(),
1410 &mut in_len,
1411 )
1412 };
1413 let written = out_len.max(0) as usize;
1414 if written > 0 {
1415 append_to_xml_buffer(out_buf, &out_vec[..written]);
1416 total_written += written;
1417 }
1418 let consumed = in_len.max(0) as usize;
1419 if ret == ENC_INPUT_ERROR && consumed < in_data.len() {
1420 let mut clen: c_int = 4;
1423 let cp = unsafe {
1424 crate::abi::exports_misc::xmlGetUTF8Char(in_data[consumed..].as_ptr(), &mut clen)
1425 };
1426 if cp <= 0 || clen <= 0 || (consumed + clen as usize) > in_data.len() {
1427 return -1;
1428 }
1429 let ref_str = format!("&#{};", cp);
1430 append_to_xml_buffer(out_buf, ref_str.as_bytes());
1431 total_written += ref_str.len();
1432 in_data = &in_data[consumed + clen as usize..];
1433 if in_data.is_empty() {
1434 break;
1435 }
1436 continue;
1437 }
1438 if ret < 0 {
1439 return -1;
1440 }
1441 break;
1442 }
1443
1444 total_written as c_int
1445}
1446
1447pub(crate) fn decode_whole_buffer_declared(name: &[u8], data: &[u8]) -> Result<Vec<u8>, ()> {
1460 if data.is_empty() {
1461 return Ok(Vec::new());
1462 }
1463 let Ok(cname) = std::ffi::CString::new(name) else {
1464 return Err(());
1465 };
1466 let mut handler = find_encoding_handler(cname.as_ptr() as *const xmlChar);
1467 if handler.is_null() {
1468 if let Some(canon) = encoding_name(encoding_from_name(name)) {
1472 if let Ok(canon_c) = std::ffi::CString::new(canon) {
1473 handler = find_encoding_handler(canon_c.as_ptr() as *const xmlChar);
1474 }
1475 }
1476 }
1477 if handler.is_null() {
1478 return Err(());
1479 }
1480 decode_bytes_with_handler(handler, data)
1481}
1482
1483pub(crate) fn decode_bytes_with_handler(
1489 handler: *mut _xmlCharEncodingHandler,
1490 data: &[u8],
1491) -> Result<Vec<u8>, ()> {
1492 if handler.is_null() || data.is_empty() {
1493 return Ok(Vec::new());
1494 }
1495 let input_func = unsafe { (*handler).input.legacyFunc };
1496 let Some(input_func) = input_func else {
1497 return Err(());
1498 };
1499 let mut out: Vec<u8> = vec![0u8; data.len().saturating_mul(3) + 16];
1500 let mut in_pos: usize = 0;
1501 let mut written_total: usize = 0;
1502 loop {
1503 let mut out_len = (out.len() - written_total) as c_int;
1504 let mut in_len = (data.len() - in_pos) as c_int;
1505 let ret = unsafe {
1509 input_func(
1510 out[written_total..].as_mut_ptr(),
1511 &mut out_len,
1512 data[in_pos..].as_ptr(),
1513 &mut in_len,
1514 )
1515 };
1516 let written = out_len.max(0) as usize;
1517 let consumed = in_len.max(0) as usize;
1518 written_total += written;
1519 in_pos += consumed;
1520 if ret < 0 {
1521 return Err(());
1522 }
1523 if in_pos >= data.len() {
1524 break;
1525 }
1526 if written == 0 {
1527 return Err(());
1529 }
1530 out.resize(out.len().saturating_mul(2).max(written_total + 64), 0);
1531 }
1532 out.truncate(written_total);
1533 Ok(out)
1534}
1535
1536fn append_to_xml_buffer(buf: &mut _xmlBuffer, data: &[u8]) {
1544 if data.is_empty() {
1545 return;
1546 }
1547
1548 let new_use = (buf.use_ as usize).saturating_add(data.len());
1549 if new_use > buf.size as usize {
1550 let new_size = (buf.size as usize).saturating_mul(2).max(new_use).max(256);
1552 let new_content =
1553 unsafe { xmlReallocImpl(buf.content as *mut c_void, new_size) as *mut xmlChar };
1554 if new_content.is_null() {
1555 return; }
1557 buf.content = new_content;
1558 buf.contentIO = new_content;
1564 buf.size = new_size as c_uint;
1565 }
1566
1567 unsafe {
1568 ptr::copy_nonoverlapping(
1569 data.as_ptr(),
1570 buf.content.add(buf.use_ as usize),
1571 data.len(),
1572 );
1573 }
1574 buf.use_ = new_use as c_uint;
1575}
1576
1577unsafe extern "C" fn utf8_input_func(
1587 out: *mut c_uchar,
1588 outlen: *mut c_int,
1589 in_: *const c_uchar,
1590 inlen: *mut c_int,
1591) -> c_int {
1592 let avail_out = *outlen as usize;
1593 let avail_in = *inlen as usize;
1594 let to_copy = avail_out.min(avail_in);
1595
1596 if to_copy > 0 {
1597 ptr::copy_nonoverlapping(in_, out, to_copy);
1598 }
1599
1600 *outlen = to_copy as c_int;
1601 *inlen = to_copy as c_int;
1602 to_copy as c_int
1603}
1604
1605unsafe extern "C" fn utf8_output_func(
1607 out: *mut c_uchar,
1608 outlen: *mut c_int,
1609 in_: *const c_uchar,
1610 inlen: *mut c_int,
1611) -> c_int {
1612 utf8_input_func(out, outlen, in_, inlen)
1613}
1614
1615unsafe extern "C" fn utf16le_input_func(
1619 out: *mut c_uchar,
1620 outlen: *mut c_int,
1621 in_: *const c_uchar,
1622 inlen: *mut c_int,
1623) -> c_int {
1624 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
1625 return -1;
1626 }
1627
1628 let avail_in = *inlen as usize;
1629 let avail_out = *outlen as usize;
1630
1631 if avail_in == 0 || avail_out == 0 {
1632 *outlen = 0;
1633 *inlen = 0;
1634 return 0;
1635 }
1636
1637 let in_data = core::slice::from_raw_parts(in_, avail_in);
1638 let _out_slice = core::slice::from_raw_parts_mut(out, avail_out);
1639
1640 let result = match utf16le_to_utf8(in_data) {
1642 Ok(v) => v,
1643 Err(()) => return -1,
1644 };
1645
1646 let written = result.len().min(avail_out);
1647 if written > 0 {
1648 ptr::copy_nonoverlapping(result.as_ptr(), out, written);
1649 }
1650
1651 *outlen = written as c_int;
1652 *inlen = avail_in as c_int; written as c_int
1654}
1655
1656unsafe extern "C" fn utf16le_output_func(
1658 out: *mut c_uchar,
1659 outlen: *mut c_int,
1660 in_: *const c_uchar,
1661 inlen: *mut c_int,
1662) -> c_int {
1663 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
1664 return -1;
1665 }
1666
1667 let avail_in = *inlen as usize;
1668 let avail_out = *outlen as usize;
1669
1670 if avail_in == 0 || avail_out == 0 {
1671 *outlen = 0;
1672 *inlen = 0;
1673 return 0;
1674 }
1675
1676 let in_data = core::slice::from_raw_parts(in_, avail_in);
1677 let _out_slice = core::slice::from_raw_parts_mut(out, avail_out);
1678
1679 let result = match utf8_to_utf16le(in_data) {
1680 Ok(v) => v,
1681 Err(()) => return -1,
1682 };
1683
1684 let written = result.len().min(avail_out);
1685 if written > 0 {
1686 ptr::copy_nonoverlapping(result.as_ptr(), out, written);
1687 }
1688
1689 *outlen = written as c_int;
1690 *inlen = avail_in as c_int;
1691 written as c_int
1692}
1693
1694unsafe extern "C" fn utf16be_input_func(
1698 out: *mut c_uchar,
1699 outlen: *mut c_int,
1700 in_: *const c_uchar,
1701 inlen: *mut c_int,
1702) -> c_int {
1703 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
1704 return -1;
1705 }
1706
1707 let avail_in = *inlen as usize;
1708 let avail_out = *outlen as usize;
1709
1710 if avail_in == 0 || avail_out == 0 {
1711 *outlen = 0;
1712 *inlen = 0;
1713 return 0;
1714 }
1715
1716 let in_data = core::slice::from_raw_parts(in_, avail_in);
1717 let _out_slice = core::slice::from_raw_parts_mut(out, avail_out);
1718
1719 let result = match utf16be_to_utf8(in_data) {
1720 Ok(v) => v,
1721 Err(()) => return -1,
1722 };
1723
1724 let written = result.len().min(avail_out);
1725 if written > 0 {
1726 ptr::copy_nonoverlapping(result.as_ptr(), out, written);
1727 }
1728
1729 *outlen = written as c_int;
1730 *inlen = avail_in as c_int;
1731 written as c_int
1732}
1733
1734unsafe extern "C" fn utf16be_output_func(
1736 out: *mut c_uchar,
1737 outlen: *mut c_int,
1738 in_: *const c_uchar,
1739 inlen: *mut c_int,
1740) -> c_int {
1741 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
1742 return -1;
1743 }
1744
1745 let avail_in = *inlen as usize;
1746 let avail_out = *outlen as usize;
1747
1748 if avail_in == 0 || avail_out == 0 {
1749 *outlen = 0;
1750 *inlen = 0;
1751 return 0;
1752 }
1753
1754 let in_data = core::slice::from_raw_parts(in_, avail_in);
1755
1756 let le_result = match utf8_to_utf16le(in_data) {
1758 Ok(v) => v,
1759 Err(()) => return -1,
1760 };
1761
1762 let mut result = le_result;
1764 for chunk in result.as_chunks_mut::<2>().0 {
1765 chunk.swap(0, 1);
1766 }
1767
1768 let written = result.len().min(avail_out);
1769 if written > 0 {
1770 ptr::copy_nonoverlapping(result.as_ptr(), out, written);
1771 }
1772
1773 *outlen = written as c_int;
1774 *inlen = avail_in as c_int;
1775 written as c_int
1776}
1777
1778unsafe extern "C" fn latin1_input_func(
1782 out: *mut c_uchar,
1783 outlen: *mut c_int,
1784 in_: *const c_uchar,
1785 inlen: *mut c_int,
1786) -> c_int {
1787 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
1788 return -1;
1789 }
1790
1791 let avail_in = *inlen as usize;
1792 let avail_out = *outlen as usize;
1793
1794 if avail_in == 0 || avail_out == 0 {
1795 *outlen = 0;
1796 *inlen = 0;
1797 return 0;
1798 }
1799
1800 let in_data = core::slice::from_raw_parts(in_, avail_in);
1801 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
1802
1803 let mut in_pos = 0;
1804 let mut out_pos = 0;
1805
1806 while in_pos < avail_in && out_pos < avail_out {
1807 let byte = in_data[in_pos];
1808 in_pos += 1;
1809
1810 if byte < 0x80 {
1811 if out_pos < avail_out {
1813 out_slice[out_pos] = byte;
1814 out_pos += 1;
1815 } else {
1816 break;
1817 }
1818 } else {
1819 if out_pos + 1 < avail_out {
1822 out_slice[out_pos] = 0xC2 | (byte >> 6);
1823 out_slice[out_pos + 1] = 0x80 | (byte & 0x3F);
1824 out_pos += 2;
1825 } else {
1826 break;
1827 }
1828 }
1829 }
1830
1831 *outlen = out_pos as c_int;
1832 *inlen = in_pos as c_int;
1833 out_pos as c_int
1834}
1835
1836unsafe extern "C" fn latin1_output_func(
1838 out: *mut c_uchar,
1839 outlen: *mut c_int,
1840 in_: *const c_uchar,
1841 inlen: *mut c_int,
1842) -> c_int {
1843 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
1844 return -1;
1845 }
1846
1847 let avail_in = *inlen as usize;
1848 let avail_out = *outlen as usize;
1849
1850 if avail_in == 0 || avail_out == 0 {
1851 *outlen = 0;
1852 *inlen = 0;
1853 return 0;
1854 }
1855
1856 let in_data = core::slice::from_raw_parts(in_, avail_in);
1857 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
1858
1859 let mut in_pos = 0;
1860 let mut out_pos = 0;
1861
1862 while in_pos < avail_in && out_pos < avail_out {
1863 let byte = in_data[in_pos];
1864 in_pos += 1;
1865
1866 if byte < 0x80 {
1867 out_slice[out_pos] = byte;
1869 out_pos += 1;
1870 } else if (0xC2..=0xC3).contains(&byte) {
1871 if in_pos < avail_in {
1873 let second = in_data[in_pos];
1874 in_pos += 1;
1875 if second & 0xC0 != 0x80 {
1876 return -1; }
1878 let cp = ((byte as u32 & 0x1F) << 6) | (second as u32 & 0x3F);
1879 if cp > 0xFF {
1880 return -1; }
1882 out_slice[out_pos] = cp as u8;
1883 out_pos += 1;
1884 } else {
1885 return -1; }
1887 } else if (0x80..=0xBF).contains(&byte) {
1888 return -1;
1890 } else {
1891 return -1;
1894 }
1895 }
1896
1897 *outlen = out_pos as c_int;
1898 *inlen = in_pos as c_int;
1899 out_pos as c_int
1900}
1901
1902const CP1252_C1: [u16; 32] = [
1913 0x20AC, 0xFFFF, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0xFFFF, 0x017D, 0xFFFF, 0xFFFF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0xFFFF, 0x017E, 0x0178, ];
1918
1919#[allow(dead_code)]
1922pub(crate) const fn cp1252_byte_to_cp(byte: u8) -> Option<u32> {
1923 match byte {
1924 0x00..=0x7F => Some(byte as u32),
1925 0x80..=0x9F => {
1926 let cp = CP1252_C1[(byte - 0x80) as usize];
1927 if cp == 0xFFFF {
1928 None
1929 } else {
1930 Some(cp as u32)
1931 }
1932 }
1933 _ => Some(byte as u32), }
1935}
1936
1937#[allow(dead_code)]
1940pub(crate) const fn cp_to_cp1252_byte(cp: u32) -> Option<u8> {
1941 if cp < 0x80 || (cp >= 0xA0 && cp <= 0xFF) {
1942 Some(cp as u8)
1943 } else if cp >= 0x80 && cp <= 0x9F {
1944 let mut i = 0;
1947 while i < 32 {
1948 if CP1252_C1[i] == cp as u16 {
1949 return Some(0x80 + i as u8);
1950 }
1951 i += 1;
1952 }
1953 None
1954 } else {
1955 None
1956 }
1957}
1958
1959fn decode_utf8_char(data: &[u8], in_pos: usize) -> Option<(u32, usize)> {
1962 let b0 = *data.get(in_pos)?;
1963 if b0 < 0x80 {
1964 return Some((u32::from(b0), 1));
1965 }
1966 let (len, cp0) = match b0 {
1967 0xC2..=0xDF => (2, u32::from(b0 & 0x1F)),
1968 0xE0..=0xEF => (3, u32::from(b0 & 0x0F)),
1969 0xF0..=0xF4 => (4, u32::from(b0 & 0x07)),
1970 _ => return None,
1971 };
1972 if in_pos + len > data.len() {
1973 return None;
1974 }
1975 let mut cp = cp0;
1976 for k in 1..len {
1977 let b = data[in_pos + k];
1978 if b & 0xC0 != 0x80 {
1979 return None;
1980 }
1981 cp = (cp << 6) | u32::from(b & 0x3F);
1982 }
1983 Some((cp, len))
1984}
1985
1986pub(crate) fn cp1252_to_utf8(data: &[u8]) -> Result<Vec<u8>, ()> {
1991 let mut result = Vec::with_capacity(data.len() * 2);
1992 for &byte in data {
1993 let cp = match cp1252_byte_to_cp(byte) {
1994 None => return Err(()),
1995 Some(cp) => cp,
1996 };
1997 let mut buf = [0u8; 4];
1998 let n = encode_codepoint_to_utf8(cp, &mut buf);
1999 result.extend_from_slice(&buf[..n]);
2000 }
2001 Ok(result)
2002}
2003
2004#[allow(dead_code)]
2008pub(crate) fn utf8_to_cp1252(data: &[u8]) -> Result<Vec<u8>, ()> {
2009 let mut result = Vec::with_capacity(data.len());
2010 let mut pos = 0;
2011 while pos < data.len() {
2012 let (cp, consumed) = match decode_utf8_char(data, pos) {
2013 None => return Err(()),
2014 Some(v) => v,
2015 };
2016 let byte = match cp_to_cp1252_byte(cp) {
2017 None => return Err(()),
2018 Some(b) => b,
2019 };
2020 result.push(byte);
2021 pos += consumed;
2022 }
2023 Ok(result)
2024}
2025
2026unsafe extern "C" fn cp1252_input_func(
2028 out: *mut c_uchar,
2029 outlen: *mut c_int,
2030 in_: *const c_uchar,
2031 inlen: *mut c_int,
2032) -> c_int {
2033 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2034 return -1;
2035 }
2036
2037 let avail_in = *inlen as usize;
2038 let avail_out = *outlen as usize;
2039
2040 if avail_in == 0 || avail_out == 0 {
2041 *outlen = 0;
2042 *inlen = 0;
2043 return 0;
2044 }
2045
2046 let in_data = core::slice::from_raw_parts(in_, avail_in);
2047 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2048
2049 let mut in_pos = 0;
2050 let mut out_pos = 0;
2051
2052 while in_pos < avail_in && out_pos < avail_out {
2053 let byte = in_data[in_pos];
2054 let cp = match cp1252_byte_to_cp(byte) {
2055 None => {
2057 *outlen = out_pos as c_int;
2058 *inlen = in_pos as c_int;
2059 return -1;
2060 }
2061 Some(cp) => cp,
2062 };
2063 let mut buf = [0u8; 4];
2064 let n = encode_codepoint_to_utf8(cp, &mut buf);
2065 if out_pos + n > avail_out {
2066 break;
2067 }
2068 out_slice[out_pos..out_pos + n].copy_from_slice(&buf[..n]);
2069 out_pos += n;
2070 in_pos += 1;
2071 }
2072
2073 *outlen = out_pos as c_int;
2074 *inlen = in_pos as c_int;
2075 out_pos as c_int
2076}
2077
2078unsafe extern "C" fn cp1252_output_func(
2080 out: *mut c_uchar,
2081 outlen: *mut c_int,
2082 in_: *const c_uchar,
2083 inlen: *mut c_int,
2084) -> c_int {
2085 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2086 return -1;
2087 }
2088
2089 let avail_in = *inlen as usize;
2090 let avail_out = *outlen as usize;
2091
2092 if avail_in == 0 || avail_out == 0 {
2093 *outlen = 0;
2094 *inlen = 0;
2095 return 0;
2096 }
2097
2098 let in_data = core::slice::from_raw_parts(in_, avail_in);
2099 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2100
2101 let mut in_pos = 0;
2102 let mut out_pos = 0;
2103
2104 while in_pos < avail_in && out_pos < avail_out {
2105 let (cp, consumed) = match decode_utf8_char(in_data, in_pos) {
2106 None => {
2107 *outlen = out_pos as c_int;
2108 *inlen = in_pos as c_int;
2109 return -1;
2110 }
2111 Some(v) => v,
2112 };
2113 let byte = match cp_to_cp1252_byte(cp) {
2114 None => {
2115 *outlen = out_pos as c_int;
2117 *inlen = in_pos as c_int;
2118 return -1;
2119 }
2120 Some(b) => b,
2121 };
2122 out_slice[out_pos] = byte;
2123 out_pos += 1;
2124 in_pos += consumed;
2125 }
2126
2127 *outlen = out_pos as c_int;
2128 *inlen = in_pos as c_int;
2129 out_pos as c_int
2130}
2131
2132unsafe extern "C" fn ascii_input_func(
2143 out: *mut c_uchar,
2144 outlen: *mut c_int,
2145 in_: *const c_uchar,
2146 inlen: *mut c_int,
2147) -> c_int {
2148 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2149 return -1;
2150 }
2151
2152 let avail_in = *inlen as usize;
2153 let avail_out = *outlen as usize;
2154
2155 if avail_in == 0 || avail_out == 0 {
2156 *outlen = 0;
2157 *inlen = 0;
2158 return 0;
2159 }
2160
2161 let in_data = core::slice::from_raw_parts(in_, avail_in);
2162 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2163
2164 let mut pos = 0;
2165 while pos < avail_in && pos < avail_out {
2166 let byte = in_data[pos];
2167 if byte > 0x7F {
2168 *outlen = pos as c_int;
2171 *inlen = pos as c_int;
2172 return -2;
2173 }
2174 out_slice[pos] = byte;
2175 pos += 1;
2176 }
2177
2178 *outlen = pos as c_int;
2179 *inlen = pos as c_int;
2180 pos as c_int
2181}
2182
2183unsafe extern "C" fn ascii_output_func(
2185 out: *mut c_uchar,
2186 outlen: *mut c_int,
2187 in_: *const c_uchar,
2188 inlen: *mut c_int,
2189) -> c_int {
2190 ascii_input_func(out, outlen, in_, inlen)
2192}
2193
2194const ENC_INPUT_ERROR: c_int = -2;
2201
2202unsafe fn enc_rs_output(
2213 target: &'static encoding_rs::Encoding,
2214 out: *mut c_uchar,
2215 outlen: *mut c_int,
2216 in_: *const c_uchar,
2217 inlen: *mut c_int,
2218) -> c_int {
2219 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2220 return -1;
2221 }
2222 let avail_in = *inlen as usize;
2223 let avail_out = *outlen as usize;
2224
2225 if avail_in == 0 || avail_out == 0 {
2226 *outlen = 0;
2227 *inlen = 0;
2228 return 0;
2229 }
2230
2231 let in_data = core::slice::from_raw_parts(in_, avail_in);
2232 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2233
2234 let (s, error_at) = match core::str::from_utf8(in_data) {
2239 Ok(s) => (s, None),
2240 Err(e) => {
2241 let valid = e.valid_up_to();
2242 if valid == 0 {
2243 *outlen = 0;
2244 *inlen = 0;
2245 return -1;
2246 }
2247 (
2250 unsafe { core::str::from_utf8_unchecked(&in_data[..valid]) },
2251 Some(valid),
2252 )
2253 }
2254 };
2255
2256 let mut encoder = target.new_encoder();
2257 let mut in_pos: usize = 0;
2258 let mut out_pos: usize = 0;
2259 while in_pos < s.len() && out_pos < avail_out {
2260 let dst = &mut out_slice[out_pos..];
2261 let (res, read, written) =
2262 encoder.encode_from_utf8_without_replacement(&s[in_pos..], dst, true);
2263 out_pos += written;
2264 in_pos += read;
2265 match res {
2266 encoding_rs::EncoderResult::InputEmpty => break,
2267 encoding_rs::EncoderResult::OutputFull => {
2268 break;
2272 }
2273 encoding_rs::EncoderResult::Unmappable(c) => {
2274 *outlen = out_pos as c_int;
2280 *inlen = (in_pos - c.len_utf8()) as c_int;
2281 return ENC_INPUT_ERROR;
2282 }
2283 }
2284 }
2285
2286 if let Some(err) = error_at {
2287 if in_pos == s.len() {
2288 *outlen = out_pos as c_int;
2292 *inlen = err as c_int;
2293 return -1;
2294 }
2295 }
2296 *outlen = out_pos as c_int;
2297 *inlen = in_pos as c_int;
2298 out_pos as c_int
2299}
2300
2301unsafe fn enc_rs_input(
2307 source: &'static encoding_rs::Encoding,
2308 out: *mut c_uchar,
2309 outlen: *mut c_int,
2310 in_: *const c_uchar,
2311 inlen: *mut c_int,
2312) -> c_int {
2313 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2314 return -1;
2315 }
2316 let avail_in = *inlen as usize;
2317 let avail_out = *outlen as usize;
2318
2319 if avail_in == 0 || avail_out == 0 {
2320 *outlen = 0;
2321 *inlen = 0;
2322 return 0;
2323 }
2324
2325 let in_data = core::slice::from_raw_parts(in_, avail_in);
2326 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2327
2328 let mut decoder = source.new_decoder_without_bom_handling();
2329 let mut in_pos: usize = 0;
2330 let mut out_pos: usize = 0;
2331 while in_pos < avail_in && out_pos < avail_out {
2332 let (res, read, written) = decoder.decode_to_utf8_without_replacement(
2333 &in_data[in_pos..],
2334 &mut out_slice[out_pos..],
2335 true,
2336 );
2337 out_pos += written;
2338 in_pos += read;
2339 match res {
2340 encoding_rs::DecoderResult::InputEmpty => break,
2341 encoding_rs::DecoderResult::OutputFull => break,
2342 encoding_rs::DecoderResult::Malformed(..) => {
2343 *outlen = out_pos as c_int;
2346 *inlen = in_pos as c_int;
2347 return -1;
2348 }
2349 }
2350 }
2351
2352 *outlen = out_pos as c_int;
2353 *inlen = in_pos as c_int;
2354 out_pos as c_int
2355}
2356
2357unsafe extern "C" fn shift_jis_input_func(
2359 out: *mut c_uchar,
2360 outlen: *mut c_int,
2361 in_: *const c_uchar,
2362 inlen: *mut c_int,
2363) -> c_int {
2364 enc_rs_input(encoding_rs::SHIFT_JIS, out, outlen, in_, inlen)
2365}
2366
2367unsafe extern "C" fn shift_jis_output_func(
2369 out: *mut c_uchar,
2370 outlen: *mut c_int,
2371 in_: *const c_uchar,
2372 inlen: *mut c_int,
2373) -> c_int {
2374 enc_rs_output(encoding_rs::SHIFT_JIS, out, outlen, in_, inlen)
2375}
2376
2377unsafe extern "C" fn euc_jp_input_func(
2379 out: *mut c_uchar,
2380 outlen: *mut c_int,
2381 in_: *const c_uchar,
2382 inlen: *mut c_int,
2383) -> c_int {
2384 enc_rs_input(encoding_rs::EUC_JP, out, outlen, in_, inlen)
2385}
2386
2387unsafe extern "C" fn euc_jp_output_func(
2389 out: *mut c_uchar,
2390 outlen: *mut c_int,
2391 in_: *const c_uchar,
2392 inlen: *mut c_int,
2393) -> c_int {
2394 enc_rs_output(encoding_rs::EUC_JP, out, outlen, in_, inlen)
2395}
2396
2397macro_rules! define_enc_rs_codec {
2402 ($input_fn:ident, $output_fn:ident, $enc:expr) => {
2403 #[allow(dead_code)]
2404 unsafe extern "C" fn $input_fn(
2405 out: *mut c_uchar,
2406 outlen: *mut c_int,
2407 in_: *const c_uchar,
2408 inlen: *mut c_int,
2409 ) -> c_int {
2410 enc_rs_input($enc, out, outlen, in_, inlen)
2411 }
2412 #[allow(dead_code)]
2413 unsafe extern "C" fn $output_fn(
2414 out: *mut c_uchar,
2415 outlen: *mut c_int,
2416 in_: *const c_uchar,
2417 inlen: *mut c_int,
2418 ) -> c_int {
2419 enc_rs_output($enc, out, outlen, in_, inlen)
2420 }
2421 };
2422}
2423
2424define_enc_rs_codec!(
2425 iso_8859_2_input_func,
2426 iso_8859_2_output_func,
2427 encoding_rs::ISO_8859_2
2428);
2429define_enc_rs_codec!(
2430 iso_8859_3_input_func,
2431 iso_8859_3_output_func,
2432 encoding_rs::ISO_8859_3
2433);
2434define_enc_rs_codec!(
2435 iso_8859_4_input_func,
2436 iso_8859_4_output_func,
2437 encoding_rs::ISO_8859_4
2438);
2439define_enc_rs_codec!(
2440 iso_8859_5_input_func,
2441 iso_8859_5_output_func,
2442 encoding_rs::ISO_8859_5
2443);
2444define_enc_rs_codec!(
2445 iso_8859_6_input_func,
2446 iso_8859_6_output_func,
2447 encoding_rs::ISO_8859_6
2448);
2449define_enc_rs_codec!(
2450 iso_8859_7_input_func,
2451 iso_8859_7_output_func,
2452 encoding_rs::ISO_8859_7
2453);
2454define_enc_rs_codec!(
2455 iso_8859_8_input_func,
2456 iso_8859_8_output_func,
2457 encoding_rs::ISO_8859_8
2458);
2459define_enc_rs_codec!(
2460 iso_8859_9_input_func,
2461 iso_8859_9_output_func,
2462 encoding_rs::WINDOWS_1254
2463);
2464define_enc_rs_codec!(
2465 iso_8859_10_input_func,
2466 iso_8859_10_output_func,
2467 encoding_rs::ISO_8859_10
2468);
2469define_enc_rs_codec!(
2470 iso_8859_11_input_func,
2471 iso_8859_11_output_func,
2472 encoding_rs::WINDOWS_874
2473);
2474define_enc_rs_codec!(
2475 iso_8859_13_input_func,
2476 iso_8859_13_output_func,
2477 encoding_rs::ISO_8859_13
2478);
2479define_enc_rs_codec!(
2480 iso_8859_14_input_func,
2481 iso_8859_14_output_func,
2482 encoding_rs::ISO_8859_14
2483);
2484define_enc_rs_codec!(
2485 iso_8859_15_input_func,
2486 iso_8859_15_output_func,
2487 encoding_rs::ISO_8859_15
2488);
2489define_enc_rs_codec!(
2490 iso_8859_16_input_func,
2491 iso_8859_16_output_func,
2492 encoding_rs::ISO_8859_16
2493);
2494define_enc_rs_codec!(
2495 iso_2022_jp_input_func,
2496 iso_2022_jp_output_func,
2497 encoding_rs::ISO_2022_JP
2498);
2499
2500unsafe fn fixed_width_input(
2509 le: bool,
2510 width: usize,
2511 out: *mut c_uchar,
2512 outlen: *mut c_int,
2513 in_: *const c_uchar,
2514 inlen: *mut c_int,
2515) -> c_int {
2516 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2517 return -1;
2518 }
2519 let avail_in = *inlen as usize;
2520 let avail_out = *outlen as usize;
2521 if avail_in == 0 || avail_out == 0 {
2522 *outlen = 0;
2523 *inlen = 0;
2524 return 0;
2525 }
2526 let in_data = core::slice::from_raw_parts(in_, avail_in);
2527 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2528 let mut in_pos = 0usize;
2529 let mut out_pos = 0usize;
2530 while in_pos + width <= avail_in {
2531 let mut unit: u32 = 0;
2532 for k in 0..width {
2533 let b = in_data[in_pos + k] as u32;
2534 unit = if le {
2535 unit | (b << (8 * k))
2536 } else {
2537 (unit << 8) | b
2538 };
2539 }
2540 if unit > 0x10FFFF || (0xD800..=0xDFFF).contains(&unit) {
2541 *outlen = out_pos as c_int;
2543 *inlen = in_pos as c_int;
2544 return -1;
2545 }
2546 let mut buf = [0u8; 4];
2547 let ch = unsafe { char::from_u32_unchecked(unit) };
2550 let n = ch.encode_utf8(&mut buf).len();
2551 if out_pos + n > avail_out {
2552 break;
2553 }
2554 out_slice[out_pos..out_pos + n].copy_from_slice(&buf[..n]);
2555 out_pos += n;
2556 in_pos += width;
2557 }
2558 *outlen = out_pos as c_int;
2559 *inlen = in_pos as c_int;
2560 out_pos as c_int
2561}
2562
2563unsafe fn fixed_width_output(
2567 le: bool,
2568 width: usize,
2569 out: *mut c_uchar,
2570 outlen: *mut c_int,
2571 in_: *const c_uchar,
2572 inlen: *mut c_int,
2573) -> c_int {
2574 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2575 return -1;
2576 }
2577 let avail_in = *inlen as usize;
2578 let avail_out = *outlen as usize;
2579 if avail_in == 0 || avail_out == 0 {
2580 *outlen = 0;
2581 *inlen = 0;
2582 return 0;
2583 }
2584 let in_data = core::slice::from_raw_parts(in_, avail_in);
2585 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2586 let mut in_pos = 0usize;
2587 let mut out_pos = 0usize;
2588 while in_pos < avail_in {
2589 let (cp, consumed) = match decode_utf8_char(in_data, in_pos) {
2590 None => {
2591 *outlen = out_pos as c_int;
2594 *inlen = in_pos as c_int;
2595 return -1;
2596 }
2597 Some(v) => v,
2598 };
2599 let max_cp = if width == 2 { 0xFFFF } else { 0x10FFFF };
2600 if cp > max_cp {
2601 *outlen = out_pos as c_int;
2604 *inlen = in_pos as c_int;
2605 return ENC_INPUT_ERROR;
2606 }
2607 if out_pos + width > avail_out {
2608 break;
2609 }
2610 for k in 0..width {
2611 let shift = 8 * if le { k } else { width - 1 - k };
2612 out_slice[out_pos + k] = ((cp >> shift) & 0xFF) as u8;
2613 }
2614 out_pos += width;
2615 in_pos += consumed;
2616 }
2617 *outlen = out_pos as c_int;
2618 *inlen = in_pos as c_int;
2619 out_pos as c_int
2620}
2621
2622unsafe extern "C" fn ucs2_input_func(
2626 out: *mut c_uchar,
2627 outlen: *mut c_int,
2628 in_: *const c_uchar,
2629 inlen: *mut c_int,
2630) -> c_int {
2631 fixed_width_input(true, 2, out, outlen, in_, inlen)
2632}
2633
2634unsafe extern "C" fn ucs2_output_func(
2636 out: *mut c_uchar,
2637 outlen: *mut c_int,
2638 in_: *const c_uchar,
2639 inlen: *mut c_int,
2640) -> c_int {
2641 fixed_width_output(true, 2, out, outlen, in_, inlen)
2642}
2643
2644unsafe extern "C" fn ucs4le_input_func(
2646 out: *mut c_uchar,
2647 outlen: *mut c_int,
2648 in_: *const c_uchar,
2649 inlen: *mut c_int,
2650) -> c_int {
2651 fixed_width_input(true, 4, out, outlen, in_, inlen)
2652}
2653
2654unsafe extern "C" fn ucs4le_output_func(
2656 out: *mut c_uchar,
2657 outlen: *mut c_int,
2658 in_: *const c_uchar,
2659 inlen: *mut c_int,
2660) -> c_int {
2661 fixed_width_output(true, 4, out, outlen, in_, inlen)
2662}
2663
2664unsafe extern "C" fn ucs4be_input_func(
2666 out: *mut c_uchar,
2667 outlen: *mut c_int,
2668 in_: *const c_uchar,
2669 inlen: *mut c_int,
2670) -> c_int {
2671 fixed_width_input(false, 4, out, outlen, in_, inlen)
2672}
2673
2674unsafe extern "C" fn ucs4be_output_func(
2676 out: *mut c_uchar,
2677 outlen: *mut c_int,
2678 in_: *const c_uchar,
2679 inlen: *mut c_int,
2680) -> c_int {
2681 fixed_width_output(false, 4, out, outlen, in_, inlen)
2682}
2683
2684const EBCDIC037_TO_UNICODE: [u16; 256] = [
2688 0x0000, 0x0001, 0x0002, 0x0003, 0x009C, 0x0009, 0x0086, 0x007F, 0x0097, 0x008D, 0x008E, 0x000B,
2689 0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x009D, 0x0085, 0x0008, 0x0087,
2690 0x0018, 0x0019, 0x0092, 0x008F, 0x001C, 0x001D, 0x001E, 0x001F, 0x0080, 0x0081, 0x0082, 0x0083,
2691 0x0084, 0x000A, 0x0017, 0x001B, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x0005, 0x0006, 0x0007,
2692 0x0090, 0x0091, 0x0016, 0x0093, 0x0094, 0x0095, 0x0096, 0x0004, 0x0098, 0x0099, 0x009A, 0x009B,
2693 0x0014, 0x0015, 0x009E, 0x001A, 0x0020, 0x00A0, 0x00E2, 0x00E4, 0x00E0, 0x00E1, 0x00E3, 0x00E5,
2694 0x00E7, 0x00F1, 0x00A2, 0x002E, 0x003C, 0x0028, 0x002B, 0x007C, 0x0026, 0x00E9, 0x00EA, 0x00EB,
2695 0x00E8, 0x00ED, 0x00EE, 0x00EF, 0x00EC, 0x00DF, 0x0021, 0x0024, 0x002A, 0x0029, 0x003B, 0x00AC,
2696 0x002D, 0x002F, 0x00C2, 0x00C4, 0x00C0, 0x00C1, 0x00C3, 0x00C5, 0x00C7, 0x00D1, 0x00A6, 0x002C,
2697 0x0025, 0x005F, 0x003E, 0x003F, 0x00F8, 0x00C9, 0x00CA, 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF,
2698 0x00CC, 0x0060, 0x003A, 0x0023, 0x0040, 0x0027, 0x003D, 0x0022, 0x00D8, 0x0061, 0x0062, 0x0063,
2699 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x00AB, 0x00BB, 0x00F0, 0x00FD, 0x00FE, 0x00B1,
2700 0x00B0, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x00AA, 0x00BA,
2701 0x00E6, 0x00B8, 0x00C6, 0x00A4, 0x00B5, 0x007E, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
2702 0x0079, 0x007A, 0x00A1, 0x00BF, 0x00D0, 0x00DD, 0x00DE, 0x00AE, 0x005E, 0x00A3, 0x00A5, 0x00B7,
2703 0x00A9, 0x00A7, 0x00B6, 0x00BC, 0x00BD, 0x00BE, 0x005B, 0x005D, 0x00AF, 0x00A8, 0x00B4, 0x00D7,
2704 0x007B, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x00AD, 0x00F4,
2705 0x00F6, 0x00F2, 0x00F3, 0x00F5, 0x007D, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
2706 0x0051, 0x0052, 0x00B9, 0x00FB, 0x00FC, 0x00F9, 0x00FA, 0x00FF, 0x005C, 0x00F7, 0x0053, 0x0054,
2707 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x00B2, 0x00D4, 0x00D6, 0x00D2, 0x00D3, 0x00D5,
2708 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x00B3, 0x00DB,
2709 0x00DC, 0x00D9, 0x00DA, 0x009F,
2710];
2711
2712const fn ebcdic037_cp_to_byte(cp: u32) -> Option<u8> {
2715 if cp > 0xFF {
2716 return None;
2717 }
2718 let mut i = 0;
2719 while i < 256 {
2720 if EBCDIC037_TO_UNICODE[i] as u32 == cp {
2721 return Some(i as u8);
2722 }
2723 i += 1;
2724 }
2725 None
2726}
2727
2728unsafe extern "C" fn ebcdic_input_func(
2730 out: *mut c_uchar,
2731 outlen: *mut c_int,
2732 in_: *const c_uchar,
2733 inlen: *mut c_int,
2734) -> c_int {
2735 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2736 return -1;
2737 }
2738 let avail_in = *inlen as usize;
2739 let avail_out = *outlen as usize;
2740 if avail_in == 0 || avail_out == 0 {
2741 *outlen = 0;
2742 *inlen = 0;
2743 return 0;
2744 }
2745 let in_data = core::slice::from_raw_parts(in_, avail_in);
2746 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2747 let mut in_pos = 0usize;
2748 let mut out_pos = 0usize;
2749 while in_pos < avail_in {
2750 let cp = u32::from(EBCDIC037_TO_UNICODE[in_data[in_pos] as usize]);
2751 let mut buf = [0u8; 2];
2752 let ch = unsafe { char::from_u32_unchecked(cp) };
2753 let n = ch.encode_utf8(&mut buf).len();
2754 if out_pos + n > avail_out {
2755 break;
2756 }
2757 out_slice[out_pos..out_pos + n].copy_from_slice(&buf[..n]);
2758 out_pos += n;
2759 in_pos += 1;
2760 }
2761 *outlen = out_pos as c_int;
2762 *inlen = in_pos as c_int;
2763 out_pos as c_int
2764}
2765
2766unsafe extern "C" fn ebcdic_output_func(
2769 out: *mut c_uchar,
2770 outlen: *mut c_int,
2771 in_: *const c_uchar,
2772 inlen: *mut c_int,
2773) -> c_int {
2774 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2775 return -1;
2776 }
2777 let avail_in = *inlen as usize;
2778 let avail_out = *outlen as usize;
2779 if avail_in == 0 || avail_out == 0 {
2780 *outlen = 0;
2781 *inlen = 0;
2782 return 0;
2783 }
2784 let in_data = core::slice::from_raw_parts(in_, avail_in);
2785 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2786 let mut in_pos = 0usize;
2787 let mut out_pos = 0usize;
2788 while in_pos < avail_in {
2789 let (cp, consumed) = match decode_utf8_char(in_data, in_pos) {
2790 None => {
2791 *outlen = out_pos as c_int;
2792 *inlen = in_pos as c_int;
2793 return -1;
2794 }
2795 Some(v) => v,
2796 };
2797 match ebcdic037_cp_to_byte(cp) {
2798 None => {
2799 *outlen = out_pos as c_int;
2800 *inlen = in_pos as c_int;
2801 return ENC_INPUT_ERROR;
2802 }
2803 Some(byte) => {
2804 if out_pos + 1 > avail_out {
2805 break;
2806 }
2807 out_slice[out_pos] = byte;
2808 out_pos += 1;
2809 }
2810 }
2811 in_pos += consumed;
2812 }
2813 *outlen = out_pos as c_int;
2814 *inlen = in_pos as c_int;
2815 out_pos as c_int
2816}
2817
2818pub(crate) fn xmlFindCharEncodingHandler(name: *const c_char) -> *mut _xmlCharEncodingHandler {
2827 if name.is_null() {
2828 return ptr::null_mut();
2829 }
2830 find_encoding_handler(name as *const xmlChar)
2831}
2832
2833pub(crate) const fn xmlGetCharEncodingName(enc: xmlCharEncoding) -> *const c_char {
2837 match enc {
2841 xmlCharEncoding::XML_CHAR_ENCODING_UTF8 => c"UTF-8".as_ptr(),
2842 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE | xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE => {
2843 c"UTF-16".as_ptr()
2844 }
2845 xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE | xmlCharEncoding::XML_CHAR_ENCODING_UCS4BE => {
2846 c"UCS-4".as_ptr()
2847 }
2848 xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC => c"IBM037".as_ptr(),
2849 xmlCharEncoding::XML_CHAR_ENCODING_UCS2 => c"UCS-2".as_ptr(),
2850 xmlCharEncoding::XML_CHAR_ENCODING_8859_1 => c"ISO-8859-1".as_ptr(),
2851 xmlCharEncoding::XML_CHAR_ENCODING_8859_2 => c"ISO-8859-2".as_ptr(),
2852 xmlCharEncoding::XML_CHAR_ENCODING_8859_3 => c"ISO-8859-3".as_ptr(),
2853 xmlCharEncoding::XML_CHAR_ENCODING_8859_4 => c"ISO-8859-4".as_ptr(),
2854 xmlCharEncoding::XML_CHAR_ENCODING_8859_5 => c"ISO-8859-5".as_ptr(),
2855 xmlCharEncoding::XML_CHAR_ENCODING_8859_6 => c"ISO-8859-6".as_ptr(),
2856 xmlCharEncoding::XML_CHAR_ENCODING_8859_7 => c"ISO-8859-7".as_ptr(),
2857 xmlCharEncoding::XML_CHAR_ENCODING_8859_8 => c"ISO-8859-8".as_ptr(),
2858 xmlCharEncoding::XML_CHAR_ENCODING_8859_9 => c"ISO-8859-9".as_ptr(),
2859 xmlCharEncoding::XML_CHAR_ENCODING_2022_JP => c"ISO-2022-JP".as_ptr(),
2860 xmlCharEncoding::XML_CHAR_ENCODING_SHIFT_JIS => c"Shift_JIS".as_ptr(),
2861 xmlCharEncoding::XML_CHAR_ENCODING_EUC_JP => c"EUC-JP".as_ptr(),
2862 xmlCharEncoding::XML_CHAR_ENCODING_ASCII => c"US-ASCII".as_ptr(),
2864 _ => ptr::null(),
2865 }
2866}
2867
2868pub(crate) fn xmlParseCharEncoding(name: *const c_char) -> c_int {
2877 if name.is_null() {
2878 return xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int;
2879 }
2880 let bytes = unsafe { CStr::from_ptr(name).to_bytes() };
2881 encoding_from_name(bytes) as c_int
2882}
2883
2884static ENCODING_ALIASES: std::sync::OnceLock<
2892 parking_lot::RwLock<std::collections::HashMap<Vec<u8>, Vec<u8>>>,
2893> = std::sync::OnceLock::new();
2894
2895fn encoding_aliases() -> &'static parking_lot::RwLock<std::collections::HashMap<Vec<u8>, Vec<u8>>> {
2896 ENCODING_ALIASES.get_or_init(|| parking_lot::RwLock::new(std::collections::HashMap::new()))
2897}
2898
2899pub(crate) fn add_encoding_alias(name: *const c_char, alias: *const c_char) -> c_int {
2907 if name.is_null() || alias.is_null() {
2908 return -1;
2909 }
2910 let n = unsafe { CStr::from_ptr(name).to_bytes().to_vec() };
2911 let a = unsafe { CStr::from_ptr(alias).to_bytes().to_vec() };
2912 encoding_aliases().write().insert(a, n);
2913 0
2914}
2915
2916pub(crate) fn del_encoding_alias(alias: *const c_char) -> c_int {
2923 if alias.is_null() {
2924 return -1;
2925 }
2926 let a = unsafe { CStr::from_ptr(alias).to_bytes().to_vec() };
2927 if encoding_aliases().write().remove(&a).is_some() {
2928 0
2929 } else {
2930 -1
2931 }
2932}
2933
2934pub(crate) fn get_encoding_alias(alias: *const c_char) -> *const c_char {
2943 if alias.is_null() {
2944 return ptr::null();
2945 }
2946 let a = unsafe { CStr::from_ptr(alias).to_bytes().to_vec() };
2947 let guard = encoding_aliases().read();
2948 match guard.get(&a) {
2949 Some(v) => {
2950 let leaked: &'static [u8] = Box::leak(v.clone().into_boxed_slice());
2953 leaked.as_ptr() as *const c_char
2954 }
2955 None => ptr::null(),
2956 }
2957}
2958
2959pub(crate) fn cleanup_encoding_aliases() {
2961 encoding_aliases().write().clear();
2962}
2963
2964pub(crate) fn xmlCharEncInFunc(
2968 handler: *mut _xmlCharEncodingHandler,
2969 out: *mut _xmlBuffer,
2970 in_: *mut _xmlBuffer,
2971) -> c_int {
2972 char_enc_in(handler, out, in_)
2973}
2974
2975pub(crate) fn xmlCharEncOutFunc(
2979 handler: *mut _xmlCharEncodingHandler,
2980 out: *mut _xmlBuffer,
2981 in_: *mut _xmlBuffer,
2982) -> c_int {
2983 char_enc_out(handler, out, in_)
2984}
2985
2986pub(crate) fn xmlNewCharEncodingHandler(
3000 name: *const c_char,
3001 input: xmlCharEncodingInputFunc,
3002 output: xmlCharEncodingOutputFunc,
3003) -> *mut _xmlCharEncodingHandler {
3004 if name.is_null() {
3005 return ptr::null_mut();
3006 }
3007
3008 let name_raw = unsafe { crate::abi::allocator::xmlMemStrdupImpl(name) };
3009 if name_raw.is_null() {
3010 return ptr::null_mut();
3011 }
3012
3013 let handler = unsafe { xmlMallocImpl(size_of::<_xmlCharEncodingHandler>()) }
3014 as *mut _xmlCharEncodingHandler;
3015
3016 if handler.is_null() {
3017 unsafe { xmlFreeImpl(name_raw) };
3018 return ptr::null_mut();
3019 }
3020
3021 unsafe {
3022 ptr::write(
3023 handler,
3024 _xmlCharEncodingHandler {
3025 name: name_raw as *mut c_char,
3026 input: EncodingInputUnion {
3027 legacyFunc: Some(input),
3028 },
3029 output: EncodingOutputUnion {
3030 legacyFunc: Some(output),
3031 },
3032 inputCtxt: ptr::null_mut(),
3033 outputCtxt: ptr::null_mut(),
3034 ctxtDtor: None,
3035 flags: 0,
3036 },
3037 );
3038 }
3039
3040 handler
3041}
3042
3043#[allow(dead_code)]
3054pub(crate) fn xmlDelEncodingHandler(handler: *mut _xmlCharEncodingHandler) {
3055 if handler.is_null() {
3056 return;
3057 }
3058
3059 {
3061 let mut handlers = ENCODING_HANDLERS.write();
3062 handlers.retain(|&h| h.0 != handler);
3063 }
3064
3065 unsafe {
3066 if !(*handler).name.is_null() {
3067 xmlFreeImpl((*handler).name as *mut c_void);
3068 }
3069 xmlFreeImpl(handler as *mut c_void);
3070 }
3071}
3072
3073pub(crate) fn xmlInitCharEncodingHandlers() {
3075 init_encodings();
3076}
3077
3078pub(crate) fn xmlCleanupCharEncodingHandlers() {
3080 cleanup_encodings();
3081}
3082
3083pub(crate) fn xmlLookupCharEncodingHandler(enc: c_int, out: *mut *mut c_void) -> c_int {
3111 if out.is_null() {
3112 return crate::abi::types::XML_ERR_ARGUMENT;
3113 }
3114 unsafe {
3115 *out = ptr::null_mut();
3116 }
3117 if enc <= 0 || enc >= 32 {
3118 return crate::abi::types::XML_ERR_UNSUPPORTED_ENCODING;
3119 }
3120 if enc == xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int {
3122 return crate::abi::types::XML_ERR_OK;
3123 }
3124 let canonical: &[u8] = match enc {
3125 2 => b"UTF-16LE\0",
3127 3 => b"UTF-16BE\0",
3129 10 => b"ISO-8859-1\0",
3131 22 => b"US-ASCII\0",
3133 23 => b"UTF-16\0",
3135 _ => return crate::abi::types::XML_ERR_UNSUPPORTED_ENCODING,
3136 };
3137 let h = find_encoding_handler(canonical.as_ptr() as *const xmlChar);
3138 if h.is_null() {
3139 return crate::abi::types::XML_ERR_UNSUPPORTED_ENCODING;
3140 }
3141 unsafe {
3142 *out = h as *mut c_void;
3143 }
3144 crate::abi::types::XML_ERR_OK
3145}
3146
3147pub(crate) fn xmlGetCharEncodingHandler(enc: c_int) -> *mut c_void {
3149 let mut ret: *mut c_void = ptr::null_mut();
3150 let _rc = xmlLookupCharEncodingHandler(enc, &mut ret);
3151 ret
3152}
3153
3154pub(crate) fn xmlCreateCharEncodingHandler(
3169 name: *const c_char,
3170 flags: c_int,
3171 impl_: Option<xmlCharEncConvImpl>,
3172 implCtxt: *mut c_void,
3173 out: *mut *mut c_void,
3174) -> c_int {
3175 if out.is_null() {
3176 return crate::abi::types::XML_ERR_ARGUMENT;
3177 }
3178 unsafe {
3179 *out = ptr::null_mut();
3180 }
3181 if name.is_null() || flags == 0 {
3182 return crate::abi::types::XML_ERR_ARGUMENT;
3183 }
3184 let norig = unsafe { CStr::from_ptr(name).to_bytes() };
3185
3186 let mut eff: &[u8] = norig;
3188 let alias = get_encoding_alias(name);
3189 if !alias.is_null() {
3190 eff = unsafe { CStr::from_ptr(alias).to_bytes() };
3191 }
3192
3193 let enc = encoding_from_name(eff);
3194
3195 if enc == xmlCharEncoding::XML_CHAR_ENCODING_UTF8 {
3197 return crate::abi::types::XML_ERR_OK;
3198 }
3199
3200 let canonical: &[u8] = match enc {
3201 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE => b"UTF-16LE\0",
3202 xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE => b"UTF-16BE\0",
3203 xmlCharEncoding::XML_CHAR_ENCODING_8859_1 => b"ISO-8859-1\0",
3204 xmlCharEncoding::XML_CHAR_ENCODING_ASCII => b"US-ASCII\0",
3205 _ => {
3206 return find_extra_handler(norig, eff, flags, impl_, implCtxt, out);
3207 }
3208 };
3209 let h = find_encoding_handler(canonical.as_ptr() as *const xmlChar);
3210 if h.is_null() {
3211 return find_extra_handler(norig, eff, flags, impl_, implCtxt, out);
3212 }
3213 unsafe {
3214 let src = &*h;
3215 let has_in = (flags & 1) == 0 || !src.input.legacyFunc.is_none();
3216 let has_out = (flags & 2) == 0 || !src.output.legacyFunc.is_none();
3217 if !has_in || !has_out {
3218 return find_extra_handler(norig, eff, flags, impl_, implCtxt, out);
3219 }
3220 let copy =
3225 xmlMallocImpl(size_of::<_xmlCharEncodingHandler>()) as *mut _xmlCharEncodingHandler;
3226 if copy.is_null() {
3227 return crate::abi::types::XML_ERR_NO_MEMORY;
3228 }
3229 let name_copy = crate::abi::allocator::xmlMemStrdupImpl(name) as *mut c_char;
3230 if name_copy.is_null() {
3231 xmlFreeImpl(copy as *mut c_void);
3232 return crate::abi::types::XML_ERR_NO_MEMORY;
3233 }
3234 ptr::write(
3235 copy,
3236 _xmlCharEncodingHandler {
3237 name: name_copy,
3238 input: EncodingInputUnion {
3239 legacyFunc: src.input.legacyFunc,
3240 },
3241 output: EncodingOutputUnion {
3242 legacyFunc: src.output.legacyFunc,
3243 },
3244 inputCtxt: src.inputCtxt,
3245 outputCtxt: src.outputCtxt,
3246 ctxtDtor: src.ctxtDtor,
3247 flags: src.flags,
3248 },
3249 );
3250 *out = copy as *mut c_void;
3251 }
3252 crate::abi::types::XML_ERR_OK
3253}
3254
3255fn find_extra_handler(
3270 norig: &[u8],
3271 name: &[u8],
3272 flags: c_int,
3273 impl_: Option<xmlCharEncConvImpl>,
3274 implCtxt: *mut c_void,
3275 out: *mut *mut c_void,
3276) -> c_int {
3277 if let Some(f) = impl_ {
3279 let mut n = norig.to_vec();
3280 n.push(0);
3281 let rc = unsafe {
3282 f(
3283 implCtxt,
3284 n.as_ptr() as *const c_char,
3285 flags,
3286 out as *mut *mut crate::abi::structs::_xmlCharEncodingHandler,
3287 )
3288 };
3289 return rc;
3290 }
3291 let mut n = name.to_vec();
3293 n.push(0);
3294 let h = find_encoding_handler(n.as_ptr() as *const xmlChar);
3295 if !h.is_null() {
3296 unsafe {
3297 let src = &*h;
3298 let has_in = (flags & 1) == 0 || !src.input.legacyFunc.is_none();
3299 let has_out = (flags & 2) == 0 || !src.output.legacyFunc.is_none();
3300 if has_in && has_out {
3301 *out = h as *mut c_void;
3302 return crate::abi::types::XML_ERR_OK;
3303 }
3304 }
3305 }
3306 crate::abi::types::XML_ERR_UNSUPPORTED_ENCODING
3307}
3308
3309pub(crate) fn xmlOpenCharEncodingHandler(
3311 name: *const c_char,
3312 output: c_int,
3313 out: *mut *mut c_void,
3314) -> c_int {
3315 let flags: c_int = if output != 0 { 2 } else { 1 };
3317 xmlCreateCharEncodingHandler(name, flags, None, ptr::null_mut(), out)
3318}
3319
3320pub(crate) fn xmlCharEncNewCustomHandler(
3335 name: *const c_char,
3336 input: xmlCharEncConvFunc,
3337 output: xmlCharEncConvFunc,
3338 ctxtDtor: Option<xmlCharEncConvCtxtDtor>,
3339 inputCtxt: *mut c_void,
3340 outputCtxt: *mut c_void,
3341 out: *mut *mut c_void,
3342) -> c_int {
3343 if out.is_null() {
3344 return crate::abi::types::XML_ERR_ARGUMENT;
3345 }
3346 let handler = unsafe { xmlMallocImpl(size_of::<_xmlCharEncodingHandler>()) }
3347 as *mut _xmlCharEncodingHandler;
3348 if handler.is_null() {
3349 unsafe {
3350 if let Some(d) = ctxtDtor {
3351 if !inputCtxt.is_null() {
3352 d(inputCtxt);
3353 }
3354 if !outputCtxt.is_null() {
3355 d(outputCtxt);
3356 }
3357 }
3358 }
3359 return crate::abi::types::XML_ERR_NO_MEMORY;
3360 }
3361 let name_copy = if name.is_null() {
3362 ptr::null_mut()
3363 } else {
3364 let nc = unsafe { crate::abi::allocator::xmlMemStrdupImpl(name) } as *mut c_char;
3365 if nc.is_null() {
3366 unsafe { xmlFreeImpl(handler as *mut c_void) };
3367 unsafe {
3368 if let Some(d) = ctxtDtor {
3369 if !inputCtxt.is_null() {
3370 d(inputCtxt);
3371 }
3372 if !outputCtxt.is_null() {
3373 d(outputCtxt);
3374 }
3375 }
3376 }
3377 return crate::abi::types::XML_ERR_NO_MEMORY;
3378 }
3379 nc
3380 };
3381 unsafe {
3382 ptr::write(
3383 handler,
3384 _xmlCharEncodingHandler {
3385 name: name_copy,
3386 input: EncodingInputUnion { func: Some(input) },
3387 output: EncodingOutputUnion { func: Some(output) },
3388 inputCtxt,
3389 outputCtxt,
3390 ctxtDtor,
3391 flags: 0,
3392 },
3393 );
3394 *out = handler as *mut c_void;
3395 }
3396 crate::abi::types::XML_ERR_OK
3397}
3398
3399#[cfg(test)]
3404mod tests {
3405 use super::*;
3406
3407 #[test]
3410 fn test_detect_bom_utf8() {
3411 let data = [0xEF, 0xBB, 0xBF, b'<', b'?', b'x', b'm', b'l'];
3412 assert_eq!(
3413 detect_encoding_from_bom(&data),
3414 xmlCharEncoding::XML_CHAR_ENCODING_UTF8
3415 );
3416 }
3417
3418 #[test]
3419 fn test_detect_bom_utf16le() {
3420 let data = [0xFF, 0xFE, 0x00, 0x01];
3421 assert_eq!(
3422 detect_encoding_from_bom(&data),
3423 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE
3424 );
3425 }
3426
3427 #[test]
3428 fn test_detect_bom_utf16be() {
3429 let data = [0xFE, 0xFF, 0x00, 0x01];
3430 assert_eq!(
3431 detect_encoding_from_bom(&data),
3432 xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE
3433 );
3434 }
3435
3436 #[test]
3437 fn test_detect_bom_none() {
3438 let data = b"<xml>";
3439 assert_eq!(
3440 detect_encoding_from_bom(data),
3441 xmlCharEncoding::XML_CHAR_ENCODING_NONE
3442 );
3443 }
3444
3445 #[test]
3446 fn test_detect_bom_empty() {
3447 assert_eq!(
3448 detect_encoding_from_bom(b""),
3449 xmlCharEncoding::XML_CHAR_ENCODING_NONE
3450 );
3451 }
3452
3453 #[test]
3456 fn test_detect_encoding_declaration_utf8() {
3457 let data = b"<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
3458 let result = detect_encoding_from_declaration(data);
3459 assert_eq!(result, Some(b"utf-8".to_vec()));
3460 }
3461
3462 #[test]
3463 fn test_detect_encoding_declaration_iso() {
3464 let data = b"<?xml version='1.0' encoding='ISO-8859-1'?>";
3465 let result = detect_encoding_from_declaration(data);
3466 assert_eq!(result, Some(b"iso-8859-1".to_vec()));
3467 }
3468
3469 #[test]
3470 fn test_detect_encoding_declaration_none() {
3471 let data = b"<?xml version=\"1.0\"?>";
3472 let result = detect_encoding_from_declaration(data);
3473 assert!(result.is_none());
3474 }
3475
3476 #[test]
3477 fn test_detect_encoding_declaration_no_xml() {
3478 let data = b"<root>";
3479 let result = detect_encoding_from_declaration(data);
3480 assert!(result.is_none());
3481 }
3482
3483 #[test]
3484 fn test_detect_encoding_declaration_with_bom() {
3485 let mut data = vec![0xEF, 0xBB, 0xBF];
3486 data.extend_from_slice(b"<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
3487 let result = detect_encoding_from_declaration(&data);
3488 assert_eq!(result, Some(b"utf-8".to_vec()));
3489 }
3490
3491 #[test]
3494 fn test_encoding_from_name_utf8() {
3495 assert_eq!(
3496 encoding_from_name(b"UTF-8"),
3497 xmlCharEncoding::XML_CHAR_ENCODING_UTF8
3498 );
3499 assert_eq!(
3500 encoding_from_name(b"utf8"),
3501 xmlCharEncoding::XML_CHAR_ENCODING_UTF8
3502 );
3503 }
3504
3505 #[test]
3506 fn test_encoding_from_name_utf16() {
3507 assert_eq!(
3508 encoding_from_name(b"UTF-16LE"),
3509 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE
3510 );
3511 assert_eq!(
3512 encoding_from_name(b"UTF-16BE"),
3513 xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE
3514 );
3515 assert_eq!(
3516 encoding_from_name(b"utf-16"),
3517 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE
3518 );
3519 }
3520
3521 #[test]
3522 fn test_encoding_from_name_latin1() {
3523 assert_eq!(
3524 encoding_from_name(b"ISO-8859-1"),
3525 xmlCharEncoding::XML_CHAR_ENCODING_8859_1
3526 );
3527 assert_eq!(
3528 encoding_from_name(b"Latin1"),
3529 xmlCharEncoding::XML_CHAR_ENCODING_8859_1
3530 );
3531 }
3532
3533 #[test]
3534 fn test_encoding_from_name_ascii() {
3535 assert_eq!(
3536 encoding_from_name(b"ASCII"),
3537 xmlCharEncoding::XML_CHAR_ENCODING_ASCII
3538 );
3539 assert_eq!(
3540 encoding_from_name(b"US-ASCII"),
3541 xmlCharEncoding::XML_CHAR_ENCODING_ASCII
3542 );
3543 }
3544
3545 #[test]
3546 fn test_encoding_from_name_error() {
3547 assert_eq!(
3548 encoding_from_name(b"invalid-encoding"),
3549 xmlCharEncoding::XML_CHAR_ENCODING_ERROR
3550 );
3551 }
3552
3553 #[test]
3554 fn test_encoding_from_name_empty() {
3555 assert_eq!(
3556 encoding_from_name(b""),
3557 xmlCharEncoding::XML_CHAR_ENCODING_ERROR
3558 );
3559 }
3560
3561 #[test]
3564 fn test_encoding_name_utf8() {
3565 assert_eq!(
3566 encoding_name(xmlCharEncoding::XML_CHAR_ENCODING_UTF8),
3567 Some(b"UTF-8" as &[u8])
3568 );
3569 }
3570
3571 #[test]
3572 fn test_encoding_name_utf16le() {
3573 assert_eq!(
3574 encoding_name(xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE),
3575 Some(b"UTF-16LE" as &[u8])
3576 );
3577 }
3578
3579 #[test]
3580 fn test_encoding_name_none() {
3581 assert!(encoding_name(xmlCharEncoding::XML_CHAR_ENCODING_NONE).is_none());
3582 }
3583
3584 #[test]
3585 fn test_encoding_name_error() {
3586 assert!(encoding_name(xmlCharEncoding::XML_CHAR_ENCODING_ERROR).is_none());
3587 }
3588
3589 #[test]
3592 fn test_utf8_valid_ascii() {
3593 assert!(utf8_valid(b"hello world"));
3594 }
3595
3596 #[test]
3597 fn test_utf8_valid_multi_byte() {
3598 assert!(utf8_valid("héllo wörld 🌍".as_bytes()));
3599 }
3600
3601 #[test]
3602 fn test_utf8_valid_empty() {
3603 assert!(utf8_valid(b""));
3604 }
3605
3606 #[test]
3607 fn test_utf8_invalid() {
3608 assert!(!utf8_valid(&[0xFF, 0xFE, 0x00]));
3609 }
3610
3611 #[test]
3614 fn test_valid_xml_chars() {
3615 assert!(is_valid_xml_char(0x9)); assert!(is_valid_xml_char(0xA)); assert!(is_valid_xml_char(0xD)); assert!(is_valid_xml_char(0x20)); assert!(is_valid_xml_char(0x41)); assert!(is_valid_xml_char(0xD7FF));
3621 assert!(is_valid_xml_char(0xE000));
3622 assert!(is_valid_xml_char(0xFFFD));
3623 assert!(is_valid_xml_char(0x10000));
3624 assert!(is_valid_xml_char(0x10FFFF));
3625 }
3626
3627 #[test]
3628 fn test_invalid_xml_chars() {
3629 assert!(!is_valid_xml_char(0x00));
3630 assert!(!is_valid_xml_char(0x08));
3631 assert!(!is_valid_xml_char(0x0B));
3632 assert!(!is_valid_xml_char(0x0C));
3633 assert!(!is_valid_xml_char(0x0E));
3634 assert!(!is_valid_xml_char(0x1F));
3635 assert!(!is_valid_xml_char(0xD800)); assert!(!is_valid_xml_char(0xDFFF)); assert!(!is_valid_xml_char(0xFFFE));
3638 assert!(!is_valid_xml_char(0xFFFF));
3639 assert!(!is_valid_xml_char(0x110000));
3640 }
3641
3642 #[test]
3645 fn test_utf16le_to_utf8_ascii() {
3646 let data = [b'A', 0x00, b'B', 0x00];
3648 let result = utf16le_to_utf8(&data).unwrap();
3649 assert_eq!(result, b"AB");
3650 }
3651
3652 #[test]
3653 fn test_utf16le_to_utf8_bom() {
3654 let mut data = vec![0xFF, 0xFE]; data.extend_from_slice(&[b'A', 0x00, b'B', 0x00]);
3656 let result = utf16le_to_utf8(&data).unwrap();
3657 assert_eq!(result, b"AB");
3658 }
3659
3660 #[test]
3661 fn test_utf16le_to_utf8_bmp() {
3662 let data = [0xE9, 0x00];
3664 let result = utf16le_to_utf8(&data).unwrap();
3665 assert_eq!(result, "é".as_bytes());
3666 }
3667
3668 #[test]
3669 fn test_utf16le_to_utf8_supplementary() {
3670 let data = [0x3D, 0xD8, 0x00, 0xDE];
3672 let result = utf16le_to_utf8(&data).unwrap();
3673 assert_eq!(result, "😀".as_bytes());
3674 }
3675
3676 #[test]
3677 fn test_utf16le_to_utf8_unpaired_surrogate() {
3678 let data = [0x00, 0xD8]; assert!(utf16le_to_utf8(&data).is_err());
3680 }
3681
3682 #[test]
3683 fn test_utf16le_to_utf8_truncated() {
3684 let data = [0x00]; assert!(utf16le_to_utf8(&data).is_err());
3686 }
3687
3688 #[test]
3689 fn test_utf16le_to_utf8_empty() {
3690 let result = utf16le_to_utf8(b"").unwrap();
3691 assert!(result.is_empty());
3692 }
3693
3694 #[test]
3697 fn test_utf16be_to_utf8_ascii() {
3698 let data = [0x00, b'A', 0x00, b'B'];
3699 let result = utf16be_to_utf8(&data).unwrap();
3700 assert_eq!(result, b"AB");
3701 }
3702
3703 #[test]
3704 fn test_utf16be_to_utf8_bom() {
3705 let mut data = vec![0xFE, 0xFF]; data.extend_from_slice(&[0x00, b'A', 0x00, b'B']);
3707 let result = utf16be_to_utf8(&data).unwrap();
3708 assert_eq!(result, b"AB");
3709 }
3710
3711 #[test]
3712 fn test_utf16be_to_utf8_supplementary() {
3713 let data = [0xD8, 0x3D, 0xDE, 0x00];
3715 let result = utf16be_to_utf8(&data).unwrap();
3716 assert_eq!(result, "😀".as_bytes());
3717 }
3718
3719 #[test]
3720 fn test_utf16be_to_utf8_empty() {
3721 let result = utf16be_to_utf8(b"").unwrap();
3722 assert!(result.is_empty());
3723 }
3724
3725 #[test]
3728 fn test_utf8_to_utf16le_ascii() {
3729 let result = utf8_to_utf16le(b"AB").unwrap();
3730 assert_eq!(result, [b'A', 0x00, b'B', 0x00]);
3731 }
3732
3733 #[test]
3734 fn test_utf8_to_utf16le_bmp() {
3735 let result = utf8_to_utf16le("é".as_bytes()).unwrap();
3736 assert_eq!(result, [0xE9, 0x00]);
3737 }
3738
3739 #[test]
3740 fn test_utf8_to_utf16le_supplementary() {
3741 let result = utf8_to_utf16le("😀".as_bytes()).unwrap();
3742 assert_eq!(result, [0x3D, 0xD8, 0x00, 0xDE]);
3743 }
3744
3745 #[test]
3746 fn test_utf8_to_utf16le_invalid_utf8() {
3747 assert!(utf8_to_utf16le(&[0xFF]).is_err());
3748 }
3749
3750 #[test]
3751 fn test_utf8_to_utf16le_empty() {
3752 let result = utf8_to_utf16le(b"").unwrap();
3753 assert!(result.is_empty());
3754 }
3755
3756 #[test]
3759 fn test_latin1_to_utf8_ascii() {
3760 let result = latin1_to_utf8(b"ABC");
3761 assert_eq!(result, b"ABC");
3762 }
3763
3764 #[test]
3765 fn test_latin1_to_utf8_accented() {
3766 let result = latin1_to_utf8(&[0xE9]);
3768 assert_eq!(result, "é".as_bytes());
3769 }
3770
3771 #[test]
3772 fn test_latin1_to_utf8_all_255() {
3773 let result = latin1_to_utf8(&[0xFF]);
3774 assert_eq!(result, [0xC3, 0xBF]);
3776 }
3777
3778 #[test]
3779 fn test_latin1_to_utf8_empty() {
3780 let result = latin1_to_utf8(b"");
3781 assert!(result.is_empty());
3782 }
3783
3784 #[test]
3785 fn test_latin1_to_utf8_mixed() {
3786 let result = latin1_to_utf8(b"caf\xE9");
3787 assert_eq!(result, "café".as_bytes());
3788 }
3789
3790 #[test]
3793 fn test_utf8_to_latin1_ascii() {
3794 let result = utf8_to_latin1(b"ABC").unwrap();
3795 assert_eq!(result, b"ABC");
3796 }
3797
3798 #[test]
3799 fn test_utf8_to_latin1_accented() {
3800 let result = utf8_to_latin1("é".as_bytes()).unwrap();
3801 assert_eq!(result, [0xE9]);
3802 }
3803
3804 #[test]
3805 fn test_utf8_to_latin1_out_of_range() {
3806 assert!(utf8_to_latin1("€".as_bytes()).is_err()); }
3808
3809 #[test]
3810 fn test_utf8_to_latin1_invalid_utf8() {
3811 assert!(utf8_to_latin1(&[0xFF]).is_err());
3812 }
3813
3814 #[test]
3815 fn test_utf8_to_latin1_empty() {
3816 let result = utf8_to_latin1(b"").unwrap();
3817 assert!(result.is_empty());
3818 }
3819
3820 #[test]
3823 fn test_init_and_find_encodings() {
3824 init_encodings();
3825
3826 let utf8_name: *const xmlChar = c"UTF-8".as_ptr() as *const xmlChar;
3827 assert!(!find_encoding_handler(utf8_name).is_null());
3828
3829 let utf16le_name: *const xmlChar = c"UTF-16LE".as_ptr() as *const xmlChar;
3830 assert!(!find_encoding_handler(utf16le_name).is_null());
3831
3832 let utf16be_name: *const xmlChar = c"UTF-16BE".as_ptr() as *const xmlChar;
3833 assert!(!find_encoding_handler(utf16be_name).is_null());
3834
3835 let latin1_name: *const xmlChar = c"ISO-8859-1".as_ptr() as *const xmlChar;
3836 assert!(!find_encoding_handler(latin1_name).is_null());
3837
3838 let ascii_name: *const xmlChar = c"ASCII".as_ptr() as *const xmlChar;
3839 assert!(!find_encoding_handler(ascii_name).is_null());
3840
3841 let lower_name: *const xmlChar = c"utf-8".as_ptr() as *const xmlChar;
3843 assert!(!find_encoding_handler(lower_name).is_null());
3844 }
3845
3846 #[test]
3860 fn test_find_owned_close_keeps_registry_intact() {
3861 init_encodings();
3862 let name: *const xmlChar = c"ISO-8859-1".as_ptr() as *const xmlChar;
3863
3864 let registry = find_encoding_handler(name);
3866 assert!(!registry.is_null());
3867 let h1 = xmlFindCharEncodingHandler_owned(name);
3869 assert!(!h1.is_null());
3870 assert_ne!(h1 as *const c_void, registry as *const c_void);
3871
3872 unsafe {
3875 if !(*h1).name.is_null() {
3876 crate::abi::allocator::xmlFreeImpl((*h1).name as *mut c_void);
3877 }
3878 xmlFreeImpl(h1 as *mut c_void);
3879 }
3880
3881 let registry2 = find_encoding_handler(name);
3886 assert_eq!(registry2 as *const c_void, registry as *const c_void);
3887 assert!(!unsafe { (*registry2).name }.is_null());
3888 let reg_name = unsafe { CStr::from_ptr((*registry2).name as *const c_char) };
3889 assert_eq!(reg_name.to_bytes(), b"ISO-8859-1");
3890
3891 let h2 = xmlFindCharEncodingHandler_owned(name);
3893 assert!(!h2.is_null());
3894 assert_ne!(h2 as *const c_void, registry as *const c_void);
3895 unsafe {
3896 if !(*h2).name.is_null() {
3897 crate::abi::allocator::xmlFreeImpl((*h2).name as *mut c_void);
3898 }
3899 xmlFreeImpl(h2 as *mut c_void);
3900 }
3901 }
3902
3903 #[test]
3909 fn test_find_owned_utf8_static_and_persistent() {
3910 init_encodings();
3911 let name: *const xmlChar = c"UTF-8".as_ptr() as *const xmlChar;
3912 let u1 = xmlFindCharEncodingHandler_owned(name);
3913 assert!(!u1.is_null());
3914 let u2 = xmlFindCharEncodingHandler_owned(c"utf8".as_ptr() as *const xmlChar);
3917 assert_eq!(u1, u2);
3918 assert_eq!(
3919 unsafe { (*u1).flags } & XML_HANDLER_STATIC,
3920 XML_HANDLER_STATIC
3921 );
3922 }
3923
3924 #[test]
3925 fn test_find_encoding_handler_not_found() {
3926 let name: *const xmlChar = c"NONEXISTENT".as_ptr() as *const xmlChar;
3927 assert!(find_encoding_handler(name).is_null());
3928 }
3929
3930 #[test]
3931 fn test_find_encoding_handler_null() {
3932 assert!(find_encoding_handler(ptr::null()).is_null());
3933 }
3934
3935 #[test]
3944 fn test_add_encoding_handler() {
3945 let handler = unsafe {
3946 xmlMallocImpl(size_of::<_xmlCharEncodingHandler>()) as *mut _xmlCharEncodingHandler
3947 };
3948 assert!(!handler.is_null());
3949
3950 let name = unsafe {
3951 crate::abi::allocator::xmlMemStrdupImpl(c"TEST-ENC".as_ptr() as *const c_char)
3952 };
3953 unsafe {
3954 ptr::write(
3955 handler,
3956 _xmlCharEncodingHandler {
3957 name: name as *mut c_char,
3958 input: EncodingInputUnion { legacyFunc: None },
3959 output: EncodingOutputUnion { legacyFunc: None },
3960 inputCtxt: ptr::null_mut(),
3961 outputCtxt: ptr::null_mut(),
3962 ctxtDtor: None,
3963 flags: 0,
3964 },
3965 );
3966 }
3967
3968 assert_eq!(add_encoding_handler(handler), 0);
3969
3970 let found = find_encoding_handler(c"TEST-ENC".as_ptr() as *const xmlChar);
3971 assert_eq!(found, handler);
3972
3973 {
3975 let mut handlers = ENCODING_HANDLERS.write();
3976 handlers.retain(|&h| h.0 != handler);
3977 }
3978
3979 unsafe {
3980 xmlFreeImpl(name as *mut c_void);
3981 xmlFreeImpl(handler as *mut c_void);
3982 }
3983 }
3984
3985 #[test]
3988 fn test_utf16le_roundtrip() {
3989 let original = b"Hello, World! UTF-16LE test: \xC3\xA9\xF0\x9F\x98\x80";
3990 let utf16 = utf8_to_utf16le(original).unwrap();
3991 let back = utf16le_to_utf8(&utf16).unwrap();
3992 assert_eq!(original.to_vec(), back);
3993 }
3994
3995 #[test]
3996 fn test_utf16be_roundtrip() {
3997 let original = b"Hello, World! UTF-16BE test: \xC3\xA9\xF0\x9F\x98\x80";
3998 let utf16le = utf8_to_utf16le(original).unwrap();
3999 let mut utf16be = utf16le.clone();
4001 for chunk in utf16be.as_chunks_mut::<2>().0 {
4002 chunk.swap(0, 1);
4003 }
4004 let back = utf16be_to_utf8(&utf16be).unwrap();
4005 assert_eq!(original.to_vec(), back);
4006 }
4007
4008 #[test]
4009 fn test_latin1_roundtrip() {
4010 let original: Vec<u8> = (0x00..=0xFF).collect();
4011 let utf8 = latin1_to_utf8(&original);
4012 let back = utf8_to_latin1(&utf8).unwrap();
4013 assert_eq!(original, back);
4014 }
4015
4016 #[test]
4026 fn test_utf8_handler_identity() {
4027 let input = b"Hello, UTF-8!";
4028 let mut output = [0u8; 64];
4029 let mut outlen = output.len() as c_int;
4030 let mut inlen = input.len() as c_int;
4031
4032 let ret = unsafe {
4033 utf8_input_func(output.as_mut_ptr(), &mut outlen, input.as_ptr(), &mut inlen)
4034 };
4035
4036 assert_eq!(ret, input.len() as c_int);
4037 assert_eq!(&output[..ret as usize], input);
4038 assert_eq!(inlen, input.len() as c_int);
4039 }
4040
4041 #[test]
4049 fn test_utf16le_handler_roundtrip() {
4050 init_encodings();
4051
4052 let original = b"Hello UTF-16LE!";
4053 let mut utf16_buf = [0u8; 128];
4054 let mut outlen = utf16_buf.len() as c_int;
4055 let mut inlen = original.len() as c_int;
4056
4057 let written = unsafe {
4058 utf16le_output_func(
4059 utf16_buf.as_mut_ptr(),
4060 &mut outlen,
4061 original.as_ptr(),
4062 &mut inlen,
4063 )
4064 };
4065 assert!(written > 0);
4066
4067 let mut decoded = [0u8; 128];
4069 let mut outlen2 = decoded.len() as c_int;
4070 let mut inlen2 = written;
4071
4072 let written2 = unsafe {
4073 utf16le_input_func(
4074 decoded.as_mut_ptr(),
4075 &mut outlen2,
4076 utf16_buf.as_ptr(),
4077 &mut inlen2,
4078 )
4079 };
4080 assert_eq!(written2 as usize, original.len());
4081 assert_eq!(&decoded[..written2 as usize], original);
4082 }
4083
4084 #[test]
4094 fn test_append_to_xml_buffer() {
4095 unsafe {
4096 let content = xmlMallocImpl(64) as *mut xmlChar;
4097 assert!(!content.is_null());
4098
4099 let mut buf = _xmlBuffer {
4100 content,
4101 use_: 0,
4102 size: 64,
4103 alloc: 0,
4104 contentIO: ptr::null_mut(),
4105 };
4106
4107 append_to_xml_buffer(&mut buf, b"Hello");
4108 assert_eq!(buf.use_, 5);
4109 let slice = core::slice::from_raw_parts(buf.content, 5);
4110 assert_eq!(slice, b"Hello");
4111
4112 append_to_xml_buffer(&mut buf, b" World");
4113 assert_eq!(buf.use_, 11);
4114 let slice = core::slice::from_raw_parts(buf.content, 11);
4115 assert_eq!(slice, b"Hello World");
4116
4117 xmlFreeImpl(buf.content as *mut c_void);
4118 }
4119 }
4120
4121 #[test]
4124 fn test_xml_parse_char_encoding() {
4125 let name = c"UTF-8".as_ptr() as *const c_char;
4126 assert_eq!(
4127 xmlParseCharEncoding(name),
4128 xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int
4129 );
4130
4131 let name = c"ISO-8859-1".as_ptr() as *const c_char;
4132 assert_eq!(
4133 xmlParseCharEncoding(name),
4134 xmlCharEncoding::XML_CHAR_ENCODING_8859_1 as c_int
4135 );
4136
4137 assert_eq!(
4138 xmlParseCharEncoding(ptr::null()),
4139 xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int
4140 );
4141 }
4142
4143 #[test]
4152 fn test_xml_new_and_del_encoding_handler() {
4153 let name = c"TestEnc".as_ptr() as *const c_char;
4154 let handler = xmlNewCharEncodingHandler(
4155 name,
4156 utf8_input_func as xmlCharEncodingInputFunc,
4157 utf8_output_func as xmlCharEncodingOutputFunc,
4158 );
4159 assert!(!handler.is_null());
4160
4161 unsafe {
4162 assert!(!(*handler).name.is_null());
4163 let cstr = CStr::from_ptr((*handler).name);
4164 assert_eq!(cstr.to_bytes(), b"TestEnc");
4165 }
4166
4167 xmlDelEncodingHandler(handler);
4168 }
4169
4170 #[test]
4171 fn test_xml_init_and_cleanup() {
4172 xmlInitCharEncodingHandlers();
4173
4174 let name: *const xmlChar = c"UTF-8".as_ptr() as *const xmlChar;
4175 assert!(!find_encoding_handler(name).is_null());
4176
4177 xmlCleanupCharEncodingHandlers();
4178 }
4180
4181 fn call_func(
4185 func: unsafe extern "C" fn(*mut c_uchar, *mut c_int, *const c_uchar, *mut c_int) -> c_int,
4186 input: &[u8],
4187 ) -> (c_int, Vec<u8>, usize) {
4188 let mut out = vec![0u8; input.len() * 6 + 64];
4189 let mut outlen = out.len() as c_int;
4190 let mut inlen = input.len() as c_int;
4191 let rc = unsafe { func(out.as_mut_ptr(), &mut outlen, input.as_ptr(), &mut inlen) };
4192 out.truncate(outlen.max(0) as usize);
4193 (rc, out, inlen.max(0) as usize)
4194 }
4195
4196 #[test]
4197 fn test_shift_jis_output_roundtrip() {
4198 let (rc, out, consumed) = call_func(shift_jis_output_func, "ぁ漢ア".as_bytes());
4201 assert!(rc >= 0);
4202 assert_eq!(out, [0x82, 0x9F, 0x8A, 0xBF, 0xB1]);
4203 assert_eq!(consumed, "ぁ漢ア".len());
4204
4205 let (rc, back, _) = call_func(shift_jis_input_func, &out);
4206 assert!(rc >= 0);
4207 assert_eq!(back, "ぁ漢ア".as_bytes());
4208 }
4209
4210 #[test]
4211 fn test_shift_jis_output_unmappable_reports_input_error() {
4212 let (rc, out, consumed) = call_func(shift_jis_output_func, "A😀B".as_bytes());
4216 assert_eq!(rc, ENC_INPUT_ERROR);
4217 assert_eq!(out, b"A");
4218 assert_eq!(consumed, 1); let handler = find_encoding_handler(c"SHIFT_JIS".as_ptr() as *const xmlChar);
4223 assert!(!handler.is_null());
4224 let in_buf = crate::xml::io::buf_create(64);
4225 let src = "A\u{1F600}B".as_bytes();
4226 assert!(
4227 crate::xml::io::buf_add(in_buf, src.as_ptr() as *const xmlChar, src.len() as c_int)
4228 >= 0
4229 );
4230 let out_buf = crate::xml::io::buf_create(64);
4231 let n = char_enc_out(handler, out_buf, in_buf);
4232 assert!(n >= 0);
4233 let bytes =
4234 unsafe { core::slice::from_raw_parts((*out_buf).content, (*out_buf).use_ as usize) };
4235 assert_eq!(bytes, b"A😀B");
4236 crate::xml::io::buf_free(in_buf);
4237 crate::xml::io::buf_free(out_buf);
4238 }
4239
4240 #[test]
4241 fn test_euc_jp_output_roundtrip() {
4242 let (rc, out, consumed) = call_func(euc_jp_output_func, "ぁ漢ア".as_bytes());
4245 assert!(rc >= 0);
4246 assert_eq!(out, [0xA4, 0xA1, 0xB4, 0xC1, 0x8E, 0xB1]);
4247 assert_eq!(consumed, "ぁ漢ア".len());
4248
4249 let (rc, back, _) = call_func(euc_jp_input_func, &out);
4250 assert!(rc >= 0);
4251 assert_eq!(back, "ぁ漢ア".as_bytes());
4252 }
4253
4254 #[test]
4255 fn test_east_asian_handlers_registered_and_findable() {
4256 for name in [
4257 c"SHIFT_JIS".as_ptr(),
4258 c"Shift_JIS".as_ptr(),
4259 c"SJIS".as_ptr(),
4260 c"CP932".as_ptr(),
4261 c"EUC-JP".as_ptr(),
4262 c"euc-jp".as_ptr(),
4263 ] {
4264 assert!(
4265 !find_encoding_handler(name as *const xmlChar).is_null(),
4266 "handler not found for {name:?}"
4267 );
4268 }
4269 }
4270
4271 #[test]
4272 fn test_shift_jis_output_invalid_utf8_errors() {
4273 let (rc, out, consumed) = call_func(shift_jis_output_func, b"A\xFFB");
4274 assert_eq!(rc, -1);
4275 assert_eq!(out, b"A");
4276 assert_eq!(consumed, 1);
4277 }
4278
4279 #[test]
4282 fn test_ucs4le_output_matches_utf32le() {
4283 let (rc, out, consumed) = call_func(ucs4le_output_func, "Aあ中".as_bytes());
4285 assert!(rc >= 0);
4286 assert_eq!(out, [0x41, 0, 0, 0, 0x42, 0x30, 0, 0, 0x2D, 0x4E, 0, 0]);
4287 assert_eq!(consumed, "Aあ中".len());
4288 let (rc, back, _) = call_func(ucs4le_input_func, &out);
4289 assert!(rc >= 0);
4290 assert_eq!(back, "Aあ中".as_bytes());
4291 }
4292
4293 #[test]
4294 fn test_ucs4be_output_matches_utf32be() {
4295 let (rc, out, _) = call_func(ucs4be_output_func, "Aあ".as_bytes());
4296 assert!(rc >= 0);
4297 assert_eq!(out, [0, 0, 0, 0x41, 0, 0, 0x30, 0x42]);
4298 let (rc, back, _) = call_func(ucs4be_input_func, &out);
4299 assert!(rc >= 0);
4300 assert_eq!(back, "Aあ".as_bytes());
4301 }
4302
4303 #[test]
4304 fn test_ucs2_output_astral_is_unmappable() {
4305 let (rc, out, consumed) = call_func(ucs2_output_func, "A😀".as_bytes());
4308 assert_eq!(rc, ENC_INPUT_ERROR);
4309 assert_eq!(out, [0x41, 0]);
4310 assert_eq!(consumed, 1);
4311 }
4312
4313 #[test]
4314 fn test_ebcdic037_bijection() {
4315 let (rc, out, _) = call_func(ebcdic_output_func, b"A 0");
4317 assert!(rc >= 0);
4318 assert_eq!(out, [0xC1, 0x40, 0xF0]);
4319 let (rc, back, _) = call_func(ebcdic_input_func, &out);
4320 assert!(rc >= 0);
4321 assert_eq!(back, b"A 0");
4322 for (b, cp) in EBCDIC037_TO_UNICODE.iter().enumerate() {
4325 assert_eq!(ebcdic037_cp_to_byte(u32::from(*cp)), Some(b as u8));
4326 }
4327 assert!(ebcdic037_cp_to_byte(0x100).is_none());
4328 }
4329
4330 #[test]
4331 fn test_iso_8859_2_output_roundtrip() {
4332 let (rc, out, _) = call_func(iso_8859_2_output_func, "Aąćę".as_bytes());
4334 assert!(rc >= 0);
4335 assert_eq!(out, [0x41, 0xB1, 0xE6, 0xEA]);
4336 let (rc, back, _) = call_func(iso_8859_2_input_func, &out);
4337 assert!(rc >= 0);
4338 assert_eq!(back, "Aąćę".as_bytes());
4339 }
4340
4341 #[test]
4342 fn test_decode_whole_buffer_declared_dispatch() {
4343 let iso2 = [0x41u8, 0xB1, 0xE6, 0xEA];
4345 assert_eq!(
4346 decode_whole_buffer_declared(b"ISO-8859-2", &iso2).unwrap(),
4347 "Aąćę".as_bytes()
4348 );
4349 assert_eq!(
4351 decode_whole_buffer_declared(b"latin2", &iso2).unwrap(),
4352 "Aąćę".as_bytes()
4353 );
4354 assert!(decode_whole_buffer_declared(b"no-such-encoding", b"abc").is_err());
4356 }
4357
4358 #[test]
4359 fn test_iso_2022_jp_output_uses_escape_sequences() {
4360 let (rc, out, consumed) = call_func(iso_2022_jp_output_func, "AあB".as_bytes());
4362 assert!(rc >= 0);
4363 assert_eq!(out, b"A\x1B$B$\"\x1B(BB");
4364 assert_eq!(consumed, "AあB".len());
4365 let (rc, back, _) = call_func(iso_2022_jp_input_func, &out);
4366 assert!(rc >= 0);
4367 assert_eq!(back, "AあB".as_bytes());
4368 }
4369}