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];
124const UTF32LE_BOM: [u8; 4] = [0xFF, 0xFE, 0x00, 0x00];
125const UTF32BE_BOM: [u8; 4] = [0x00, 0x00, 0xFE, 0xFF];
126
127#[derive(Clone, Copy)]
135struct HandlerPtr(*mut _xmlCharEncodingHandler);
136
137unsafe impl Send for HandlerPtr {}
138unsafe impl Sync for HandlerPtr {}
139
140static ENCODING_HANDLERS: Lazy<RwLock<Vec<HandlerPtr>>> = Lazy::new(|| RwLock::new(Vec::new()));
147
148static ENCODING_INITIALIZED: AtomicBool = AtomicBool::new(false);
150
151static ENCODING_INIT_MUTEX: parking_lot::Mutex<()> = parking_lot::Mutex::new(());
153
154#[allow(dead_code)]
163pub(crate) fn detect_encoding_from_bom(data: &[u8]) -> xmlCharEncoding {
164 if data.len() >= 3 && data[0..3] == UTF8_BOM {
165 xmlCharEncoding::XML_CHAR_ENCODING_UTF8
166 } else if data.len() >= 2 && data[0..2] == UTF16LE_BOM {
167 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE
168 } else if data.len() >= 2 && data[0..2] == UTF16BE_BOM {
169 xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE
170 } else {
171 xmlCharEncoding::XML_CHAR_ENCODING_NONE
172 }
173}
174
175#[allow(dead_code)]
180pub(crate) fn detect_encoding_from_declaration(data: &[u8]) -> Option<Vec<u8>> {
181 let start = if data.len() >= 3 && data[0..3] == UTF8_BOM {
183 3
184 } else if data.len() >= 2 && (data[0..2] == UTF16LE_BOM || data[0..2] == UTF16BE_BOM) {
185 return None;
187 } else {
188 0
189 };
190
191 let remaining = &data[start..];
192
193 if remaining.len() < 5 || !remaining[0..5].eq_ignore_ascii_case(b"<?xml") {
195 return None;
196 }
197
198 let pi_end = remaining.windows(2).position(|w| w == b"?>")?;
200 let decl_content = &remaining[5..pi_end];
201
202 let decl_str = core::str::from_utf8(decl_content).ok()?;
204 let lower = decl_str.to_ascii_lowercase();
205
206 let enc_pos = lower.find("encoding")?;
208
209 let after_enc = &decl_content[enc_pos + 8..];
211 let after_enc_str = core::str::from_utf8(after_enc).ok()?;
212 let after_enc_trimmed = after_enc_str.trim_start();
213
214 if !after_enc_trimmed.starts_with('=') {
215 return None;
216 }
217
218 let after_eq = after_enc_trimmed[1..].trim_start();
219
220 let quote = after_eq.chars().next()?;
222 if quote != '"' && quote != '\'' {
223 return None;
224 }
225
226 let value_end = after_eq[1..].find(quote)?;
228 let encoding_value = &after_eq[1..=value_end];
229
230 Some(encoding_value.to_ascii_lowercase().as_bytes().to_vec())
231}
232
233pub(crate) fn encoding_from_name(name: &[u8]) -> xmlCharEncoding {
238 let s = core::str::from_utf8(name).unwrap_or("");
239 let s = s.trim().to_ascii_lowercase();
240
241 match s.as_str() {
242 "utf-8" | "utf8" => xmlCharEncoding::XML_CHAR_ENCODING_UTF8,
244
245 "utf-16" | "utf-16le" | "utf16le" => xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE,
247 "utf-16be" | "utf16be" => xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE,
248
249 "utf-32" | "utf-32le" | "utf32le" => xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE,
252 "utf-32be" | "utf32be" => xmlCharEncoding::XML_CHAR_ENCODING_UCS4BE,
253
254 "iso-8859-1" | "iso_8859-1" | "latin1" | "latin-1" | "l1" | "cp819" | "ibm819"
256 | "iso-ir-100" | "iso_8859-1:1987" => xmlCharEncoding::XML_CHAR_ENCODING_8859_1,
257 "iso-8859-2" | "iso_8859-2" | "latin2" | "latin-2" | "l2" => {
258 xmlCharEncoding::XML_CHAR_ENCODING_8859_2
259 }
260 "iso-8859-3" | "iso_8859-3" | "latin3" | "latin-3" | "l3" => {
261 xmlCharEncoding::XML_CHAR_ENCODING_8859_3
262 }
263 "iso-8859-4" | "iso_8859-4" | "latin4" | "latin-4" | "l4" => {
264 xmlCharEncoding::XML_CHAR_ENCODING_8859_4
265 }
266 "iso-8859-5" | "iso_8859-5" | "cyrillic" => xmlCharEncoding::XML_CHAR_ENCODING_8859_5,
267 "iso-8859-6" | "iso_8859-6" | "arabic" => xmlCharEncoding::XML_CHAR_ENCODING_8859_6,
268 "iso-8859-7" | "iso_8859-7" | "greek" => xmlCharEncoding::XML_CHAR_ENCODING_8859_7,
269 "iso-8859-8" | "iso_8859-8" | "hebrew" => xmlCharEncoding::XML_CHAR_ENCODING_8859_8,
270 "iso-8859-9" | "iso_8859-9" | "latin5" | "latin-5" | "l5" | "turkish" => {
271 xmlCharEncoding::XML_CHAR_ENCODING_8859_9
272 }
273
274 "ascii" | "us-ascii" | "us" | "ansi_x3.4-1968" | "ansi_x3.4-1986" | "iso-ir-6"
276 | "iso_646.irv:1991" | "cp367" | "ibm367" => xmlCharEncoding::XML_CHAR_ENCODING_ASCII,
277
278 "iso-2022-jp" | "iso2022-jp" => xmlCharEncoding::XML_CHAR_ENCODING_2022_JP,
280 "shift_jis" | "shift-jis" | "sjis" | "cp932" => {
281 xmlCharEncoding::XML_CHAR_ENCODING_SHIFT_JIS
282 }
283 "euc-jp" | "eucjp" => xmlCharEncoding::XML_CHAR_ENCODING_EUC_JP,
284
285 "ucs-4" | "ucs4" => xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE,
287 "ucs-4le" | "ucs4le" => xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE,
288 "ucs-4be" | "ucs4be" => xmlCharEncoding::XML_CHAR_ENCODING_UCS4BE,
289 "ucs-2" | "ucs2" => xmlCharEncoding::XML_CHAR_ENCODING_UCS2,
290
291 "ebcdic" | "cp037" | "ibm037" => xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC,
293
294 _ => xmlCharEncoding::XML_CHAR_ENCODING_ERROR,
295 }
296}
297
298pub(crate) const fn encoding_name(enc: xmlCharEncoding) -> Option<&'static [u8]> {
302 match enc {
303 xmlCharEncoding::XML_CHAR_ENCODING_UTF8 => Some(b"UTF-8" as &[u8]),
304 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE => Some(b"UTF-16LE" as &[u8]),
305 xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE => Some(b"UTF-16BE" as &[u8]),
306 xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE => Some(b"UCS-4LE" as &[u8]),
307 xmlCharEncoding::XML_CHAR_ENCODING_UCS4BE => Some(b"UCS-4BE" as &[u8]),
308 xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC => Some(b"EBCDIC" as &[u8]),
309 xmlCharEncoding::XML_CHAR_ENCODING_UCS4_2143 => Some(b"UCS-4-2143" as &[u8]),
310 xmlCharEncoding::XML_CHAR_ENCODING_UCS4_3412 => Some(b"UCS-4-3412" as &[u8]),
311 xmlCharEncoding::XML_CHAR_ENCODING_UCS2 => Some(b"UCS-2" as &[u8]),
312 xmlCharEncoding::XML_CHAR_ENCODING_8859_1 => Some(b"ISO-8859-1" as &[u8]),
313 xmlCharEncoding::XML_CHAR_ENCODING_8859_2 => Some(b"ISO-8859-2" as &[u8]),
314 xmlCharEncoding::XML_CHAR_ENCODING_8859_3 => Some(b"ISO-8859-3" as &[u8]),
315 xmlCharEncoding::XML_CHAR_ENCODING_8859_4 => Some(b"ISO-8859-4" as &[u8]),
316 xmlCharEncoding::XML_CHAR_ENCODING_8859_5 => Some(b"ISO-8859-5" as &[u8]),
317 xmlCharEncoding::XML_CHAR_ENCODING_8859_6 => Some(b"ISO-8859-6" as &[u8]),
318 xmlCharEncoding::XML_CHAR_ENCODING_8859_7 => Some(b"ISO-8859-7" as &[u8]),
319 xmlCharEncoding::XML_CHAR_ENCODING_8859_8 => Some(b"ISO-8859-8" as &[u8]),
320 xmlCharEncoding::XML_CHAR_ENCODING_8859_9 => Some(b"ISO-8859-9" as &[u8]),
321 xmlCharEncoding::XML_CHAR_ENCODING_2022_JP => Some(b"ISO-2022-JP" as &[u8]),
322 xmlCharEncoding::XML_CHAR_ENCODING_SHIFT_JIS => Some(b"SHIFT_JIS" as &[u8]),
323 xmlCharEncoding::XML_CHAR_ENCODING_EUC_JP => Some(b"EUC-JP" as &[u8]),
324 xmlCharEncoding::XML_CHAR_ENCODING_ASCII => Some(b"US-ASCII" as &[u8]),
325 _ => None,
326 }
327}
328
329#[allow(dead_code)]
337pub(crate) const fn utf8_valid(data: &[u8]) -> bool {
338 core::str::from_utf8(data).is_ok()
339}
340
341#[allow(dead_code)]
353pub(crate) const fn is_valid_xml_char(cp: u32) -> bool {
354 matches!(
355 cp,
356 0x9 | 0xA | 0xD | 0x20..=0xD7FF | 0xE000..=0xFFFD | 0x10000..=0x10FFFF
357 )
358}
359
360#[inline]
366const fn read_utf16le_unit(data: &[u8]) -> Option<u16> {
367 if data.len() < 2 {
368 return None;
369 }
370 Some(u16::from_le_bytes([data[0], data[1]]))
371}
372
373#[inline]
375const fn read_utf16be_unit(data: &[u8]) -> Option<u16> {
376 if data.len() < 2 {
377 return None;
378 }
379 Some(u16::from_be_bytes([data[0], data[1]]))
380}
381
382const fn encode_codepoint_to_utf8(cp: u32, out: &mut [u8]) -> usize {
386 if cp < 0x80 {
387 if !out.is_empty() {
388 out[0] = cp as u8;
389 }
390 1
391 } else if cp < 0x800 {
392 if out.len() < 2 {
393 return 0;
394 }
395 out[0] = 0xC0 | ((cp >> 6) as u8);
396 out[1] = 0x80 | (cp as u8 & 0x3F);
397 2
398 } else if cp < 0x10000 {
399 if out.len() < 3 {
400 return 0;
401 }
402 out[0] = 0xE0 | ((cp >> 12) as u8);
403 out[1] = 0x80 | ((cp >> 6) as u8 & 0x3F);
404 out[2] = 0x80 | (cp as u8 & 0x3F);
405 3
406 } else if cp < 0x110000 {
407 if out.len() < 4 {
408 return 0;
409 }
410 out[0] = 0xF0 | ((cp >> 18) as u8);
411 out[1] = 0x80 | ((cp >> 12) as u8 & 0x3F);
412 out[2] = 0x80 | ((cp >> 6) as u8 & 0x3F);
413 out[3] = 0x80 | (cp as u8 & 0x3F);
414 4
415 } else {
416 0
417 }
418}
419
420pub(crate) fn utf16le_to_utf8(data: &[u8]) -> Result<Vec<u8>, ()> {
425 if data.is_empty() {
426 return Ok(Vec::new());
427 }
428
429 let offset = if data.len() >= 2 && data[0..2] == UTF16LE_BOM {
431 2
432 } else {
433 0
434 };
435
436 let mut result = Vec::with_capacity(data.len() / 2 + data.len() / 4);
437 let mut i = offset;
438
439 while i < data.len() {
440 let unit = read_utf16le_unit(&data[i..]).ok_or(())?;
441 i += 2;
442
443 if (0xD800..=0xDBFF).contains(&unit) {
444 let low = read_utf16le_unit(&data[i..]).ok_or(())?;
446 i += 2;
447
448 if !(0xDC00..=0xDFFF).contains(&low) {
449 return Err(());
450 }
451
452 let cp = 0x10000 + ((unit as u32 - 0xD800) << 10) + (low as u32 - 0xDC00);
453 let mut buf = [0u8; 4];
454 let n = encode_codepoint_to_utf8(cp, &mut buf);
455 if n == 0 {
456 return Err(());
457 }
458 result.extend_from_slice(&buf[..n]);
459 } else if (0xDC00..=0xDFFF).contains(&unit) {
460 return Err(());
462 } else {
463 let cp = unit as u32;
464 let mut buf = [0u8; 4];
465 let n = encode_codepoint_to_utf8(cp, &mut buf);
466 result.extend_from_slice(&buf[..n]);
467 }
468 }
469
470 Ok(result)
471}
472
473pub(crate) fn utf16be_to_utf8(data: &[u8]) -> Result<Vec<u8>, ()> {
477 if data.is_empty() {
478 return Ok(Vec::new());
479 }
480
481 let offset = if data.len() >= 2 && data[0..2] == UTF16BE_BOM {
483 2
484 } else {
485 0
486 };
487
488 let mut result = Vec::with_capacity(data.len() / 2 + data.len() / 4);
489 let mut i = offset;
490
491 while i < data.len() {
492 let unit = read_utf16be_unit(&data[i..]).ok_or(())?;
493 i += 2;
494
495 if (0xD800..=0xDBFF).contains(&unit) {
496 let low = read_utf16be_unit(&data[i..]).ok_or(())?;
498 i += 2;
499
500 if !(0xDC00..=0xDFFF).contains(&low) {
501 return Err(());
502 }
503
504 let cp = 0x10000 + ((unit as u32 - 0xD800) << 10) + (low as u32 - 0xDC00);
505 let mut buf = [0u8; 4];
506 let n = encode_codepoint_to_utf8(cp, &mut buf);
507 if n == 0 {
508 return Err(());
509 }
510 result.extend_from_slice(&buf[..n]);
511 } else if (0xDC00..=0xDFFF).contains(&unit) {
512 return Err(());
514 } else {
515 let cp = unit as u32;
516 let mut buf = [0u8; 4];
517 let n = encode_codepoint_to_utf8(cp, &mut buf);
518 result.extend_from_slice(&buf[..n]);
519 }
520 }
521
522 Ok(result)
523}
524
525pub(crate) fn ucs4le_to_utf8(data: &[u8]) -> Result<Vec<u8>, ()> {
531 fixed_width_to_utf8(data, true, UTF32LE_BOM)
532}
533
534pub(crate) fn ucs4be_to_utf8(data: &[u8]) -> Result<Vec<u8>, ()> {
540 fixed_width_to_utf8(data, false, UTF32BE_BOM)
541}
542
543fn fixed_width_to_utf8(data: &[u8], little_endian: bool, bom: [u8; 4]) -> Result<Vec<u8>, ()> {
545 if data.is_empty() {
546 return Ok(Vec::new());
547 }
548 let offset = if data.len() >= 4 && data[0..4] == bom {
549 4
550 } else {
551 0
552 };
553 let mut result = Vec::with_capacity(data.len() / 2);
554 let mut i = offset;
555 while i + 4 <= data.len() {
556 let raw = [data[i], data[i + 1], data[i + 2], data[i + 3]];
557 i += 4;
558 let cp = if little_endian {
559 u32::from_le_bytes(raw)
560 } else {
561 u32::from_be_bytes(raw)
562 };
563 if cp > 0x10FFFF || (0xD800..=0xDFFF).contains(&cp) {
566 return Err(());
567 }
568 let mut buf = [0u8; 4];
569 let n = encode_codepoint_to_utf8(cp, &mut buf);
570 if n == 0 {
571 return Err(());
572 }
573 result.extend_from_slice(&buf[..n]);
574 }
575 if i != data.len() {
577 return Err(());
578 }
579 Ok(result)
580}
581
582fn encode_codepoint_to_utf16le(cp: u32, out: &mut [u8]) -> usize {
586 if cp < 0x10000 {
587 if out.len() < 2 {
588 return 0;
589 }
590 let u = cp as u16;
591 out[..2].copy_from_slice(&u.to_le_bytes());
592 2
593 } else if cp < 0x110000 {
594 if out.len() < 4 {
595 return 0;
596 }
597 let cp = cp - 0x10000;
598 let high = 0xD800 | ((cp >> 10) as u16);
599 let low = 0xDC00 | (cp as u16 & 0x3FF);
600 out[..2].copy_from_slice(&high.to_le_bytes());
601 out[2..4].copy_from_slice(&low.to_le_bytes());
602 4
603 } else {
604 0
605 }
606}
607
608pub(crate) fn utf8_to_utf16le(data: &[u8]) -> Result<Vec<u8>, ()> {
612 let s = core::str::from_utf8(data).map_err(|_| ())?;
613 let mut result = Vec::with_capacity(data.len() * 2);
614
615 for ch in s.chars() {
616 let cp = ch as u32;
617 let mut buf = [0u8; 4];
618 let n = encode_codepoint_to_utf16le(cp, &mut buf);
619 if n == 0 {
620 return Err(());
621 }
622 result.extend_from_slice(&buf[..n]);
623 }
624
625 Ok(result)
626}
627
628#[allow(dead_code)]
637pub(crate) fn latin1_to_utf8(data: &[u8]) -> Vec<u8> {
638 let mut result = Vec::with_capacity(data.len() * 2);
639
640 for &byte in data {
641 let cp = byte as u32;
642 let mut buf = [0u8; 2];
643 let n = encode_codepoint_to_utf8(cp, &mut buf);
644 result.extend_from_slice(&buf[..n]);
645 }
646
647 result
648}
649
650pub(crate) fn utf8_to_latin1(data: &[u8]) -> Result<Vec<u8>, ()> {
655 let s = core::str::from_utf8(data).map_err(|_| ())?;
656 let mut result = Vec::with_capacity(data.len());
657
658 for ch in s.chars() {
659 let cp = ch as u32;
660 if cp > 0xFF {
661 return Err(());
662 }
663 result.push(cp as u8);
664 }
665
666 Ok(result)
667}
668
669pub(crate) fn init_encodings() {
684 if ENCODING_INITIALIZED.load(Ordering::SeqCst) {
685 return;
686 }
687 let _guard = ENCODING_INIT_MUTEX.lock();
693 if ENCODING_INITIALIZED.load(Ordering::SeqCst) {
694 return;
695 }
696 register_builtin_handlers();
697 ENCODING_INITIALIZED.store(true, Ordering::SeqCst);
698}
699
700fn register_builtin_handlers() {
702 register_handler(
704 b"UTF-8\0",
705 xmlCharEncoding::XML_CHAR_ENCODING_UTF8,
706 xmlCharEncoding::XML_CHAR_ENCODING_UTF8,
707 Some(utf8_input_func as xmlCharEncodingInputFunc),
708 Some(utf8_output_func as xmlCharEncodingOutputFunc),
709 );
710
711 register_handler(
713 b"UTF-16LE\0",
714 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE,
715 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE,
716 Some(utf16le_input_func as xmlCharEncodingInputFunc),
717 Some(utf16le_output_func as xmlCharEncodingOutputFunc),
718 );
719
720 register_handler(
722 b"UTF-16BE\0",
723 xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE,
724 xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE,
725 Some(utf16be_input_func as xmlCharEncodingInputFunc),
726 Some(utf16be_output_func as xmlCharEncodingOutputFunc),
727 );
728
729 register_handler(
735 b"UCS-4LE\0",
736 xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE,
737 xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE,
738 Some(ucs4le_input_func as xmlCharEncodingInputFunc),
739 Some(ucs4le_output_func as xmlCharEncodingOutputFunc),
740 );
741
742 register_handler(
744 b"UCS-4BE\0",
745 xmlCharEncoding::XML_CHAR_ENCODING_UCS4BE,
746 xmlCharEncoding::XML_CHAR_ENCODING_UCS4BE,
747 Some(ucs4be_input_func as xmlCharEncodingInputFunc),
748 Some(ucs4be_output_func as xmlCharEncodingOutputFunc),
749 );
750
751 register_handler(
753 b"ISO-8859-1\0",
754 xmlCharEncoding::XML_CHAR_ENCODING_8859_1,
755 xmlCharEncoding::XML_CHAR_ENCODING_8859_1,
756 Some(latin1_input_func as xmlCharEncodingInputFunc),
757 Some(latin1_output_func as xmlCharEncodingOutputFunc),
758 );
759
760 register_handler(
766 b"windows-1252\0",
767 xmlCharEncoding::XML_CHAR_ENCODING_ERROR,
768 xmlCharEncoding::XML_CHAR_ENCODING_ERROR,
769 Some(cp1252_input_func as xmlCharEncodingInputFunc),
770 Some(cp1252_output_func as xmlCharEncodingOutputFunc),
771 );
772 register_handler(
773 b"cp1252\0",
774 xmlCharEncoding::XML_CHAR_ENCODING_ERROR,
775 xmlCharEncoding::XML_CHAR_ENCODING_ERROR,
776 Some(cp1252_input_func as xmlCharEncodingInputFunc),
777 Some(cp1252_output_func as xmlCharEncodingOutputFunc),
778 );
779
780 register_handler(
785 b"US-ASCII\0",
786 xmlCharEncoding::XML_CHAR_ENCODING_ASCII,
787 xmlCharEncoding::XML_CHAR_ENCODING_ASCII,
788 Some(ascii_input_func as xmlCharEncodingInputFunc),
789 Some(ascii_output_func as xmlCharEncodingOutputFunc),
790 );
791 register_handler(
792 b"ASCII\0",
793 xmlCharEncoding::XML_CHAR_ENCODING_ASCII,
794 xmlCharEncoding::XML_CHAR_ENCODING_ASCII,
795 Some(ascii_input_func as xmlCharEncodingInputFunc),
796 Some(ascii_output_func as xmlCharEncodingOutputFunc),
797 );
798
799 register_handler(
804 b"UTF-16\0",
805 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE,
806 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE,
807 Some(utf16le_input_func as xmlCharEncodingInputFunc),
808 Some(utf16le_output_func as xmlCharEncodingOutputFunc),
809 );
810
811 register_handler(
822 b"SHIFT_JIS\0",
823 xmlCharEncoding::XML_CHAR_ENCODING_SHIFT_JIS,
824 xmlCharEncoding::XML_CHAR_ENCODING_SHIFT_JIS,
825 Some(shift_jis_input_func as xmlCharEncodingInputFunc),
826 Some(shift_jis_output_func as xmlCharEncodingOutputFunc),
827 );
828 register_handler(
829 b"SJIS\0",
830 xmlCharEncoding::XML_CHAR_ENCODING_SHIFT_JIS,
831 xmlCharEncoding::XML_CHAR_ENCODING_SHIFT_JIS,
832 Some(shift_jis_input_func as xmlCharEncodingInputFunc),
833 Some(shift_jis_output_func as xmlCharEncodingOutputFunc),
834 );
835 register_handler(
836 b"CP932\0",
837 xmlCharEncoding::XML_CHAR_ENCODING_SHIFT_JIS,
838 xmlCharEncoding::XML_CHAR_ENCODING_SHIFT_JIS,
839 Some(shift_jis_input_func as xmlCharEncodingInputFunc),
840 Some(shift_jis_output_func as xmlCharEncodingOutputFunc),
841 );
842 register_handler(
843 b"EUC-JP\0",
844 xmlCharEncoding::XML_CHAR_ENCODING_EUC_JP,
845 xmlCharEncoding::XML_CHAR_ENCODING_EUC_JP,
846 Some(euc_jp_input_func as xmlCharEncodingInputFunc),
847 Some(euc_jp_output_func as xmlCharEncodingOutputFunc),
848 );
849 register_handler(
850 b"EUCJP\0",
851 xmlCharEncoding::XML_CHAR_ENCODING_EUC_JP,
852 xmlCharEncoding::XML_CHAR_ENCODING_EUC_JP,
853 Some(euc_jp_input_func as xmlCharEncodingInputFunc),
854 Some(euc_jp_output_func as xmlCharEncodingOutputFunc),
855 );
856
857 macro_rules! register_iso8859 {
864 ($name:literal, $enc:expr, $input:ident, $output:ident) => {
865 register_handler(
866 concat!($name, "\0").as_bytes(),
867 xmlCharEncoding::XML_CHAR_ENCODING_ERROR,
868 xmlCharEncoding::XML_CHAR_ENCODING_ERROR,
869 Some($input as xmlCharEncodingInputFunc),
870 Some($output as xmlCharEncodingOutputFunc),
871 );
872 let _ = $enc; };
874 }
875 register_iso8859!(
876 "ISO-8859-2",
877 encoding_rs::ISO_8859_2,
878 iso_8859_2_input_func,
879 iso_8859_2_output_func
880 );
881 register_iso8859!(
882 "ISO-8859-3",
883 encoding_rs::ISO_8859_3,
884 iso_8859_3_input_func,
885 iso_8859_3_output_func
886 );
887 register_iso8859!(
888 "ISO-8859-4",
889 encoding_rs::ISO_8859_4,
890 iso_8859_4_input_func,
891 iso_8859_4_output_func
892 );
893 register_iso8859!(
894 "ISO-8859-5",
895 encoding_rs::ISO_8859_5,
896 iso_8859_5_input_func,
897 iso_8859_5_output_func
898 );
899 register_iso8859!(
900 "ISO-8859-6",
901 encoding_rs::ISO_8859_6,
902 iso_8859_6_input_func,
903 iso_8859_6_output_func
904 );
905 register_iso8859!(
906 "ISO-8859-7",
907 encoding_rs::ISO_8859_7,
908 iso_8859_7_input_func,
909 iso_8859_7_output_func
910 );
911 register_iso8859!(
912 "ISO-8859-8",
913 encoding_rs::ISO_8859_8,
914 iso_8859_8_input_func,
915 iso_8859_8_output_func
916 );
917 register_iso8859!(
918 "ISO-8859-9",
919 encoding_rs::WINDOWS_1254,
920 iso_8859_9_input_func,
921 iso_8859_9_output_func
922 );
923 register_iso8859!(
924 "ISO-8859-10",
925 encoding_rs::ISO_8859_10,
926 iso_8859_10_input_func,
927 iso_8859_10_output_func
928 );
929 register_iso8859!(
930 "ISO-8859-11",
931 encoding_rs::WINDOWS_874,
932 iso_8859_11_input_func,
933 iso_8859_11_output_func
934 );
935 register_iso8859!(
936 "windows-874",
937 encoding_rs::WINDOWS_874,
938 iso_8859_11_input_func,
939 iso_8859_11_output_func
940 );
941 register_iso8859!(
942 "ISO-8859-13",
943 encoding_rs::ISO_8859_13,
944 iso_8859_13_input_func,
945 iso_8859_13_output_func
946 );
947 register_iso8859!(
948 "ISO-8859-14",
949 encoding_rs::ISO_8859_14,
950 iso_8859_14_input_func,
951 iso_8859_14_output_func
952 );
953 register_iso8859!(
954 "ISO-8859-15",
955 encoding_rs::ISO_8859_15,
956 iso_8859_15_input_func,
957 iso_8859_15_output_func
958 );
959 register_iso8859!(
960 "ISO-8859-16",
961 encoding_rs::ISO_8859_16,
962 iso_8859_16_input_func,
963 iso_8859_16_output_func
964 );
965
966 register_handler(
969 b"ISO-2022-JP\0",
970 xmlCharEncoding::XML_CHAR_ENCODING_2022_JP,
971 xmlCharEncoding::XML_CHAR_ENCODING_2022_JP,
972 Some(iso_2022_jp_input_func as xmlCharEncodingInputFunc),
973 Some(iso_2022_jp_output_func as xmlCharEncodingOutputFunc),
974 );
975
976 register_handler(
979 b"UCS-2\0",
980 xmlCharEncoding::XML_CHAR_ENCODING_UCS2,
981 xmlCharEncoding::XML_CHAR_ENCODING_UCS2,
982 Some(ucs2_input_func as xmlCharEncodingInputFunc),
983 Some(ucs2_output_func as xmlCharEncodingOutputFunc),
984 );
985 register_handler(
986 b"UCS-4LE\0",
987 xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE,
988 xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE,
989 Some(ucs4le_input_func as xmlCharEncodingInputFunc),
990 Some(ucs4le_output_func as xmlCharEncodingOutputFunc),
991 );
992 register_handler(
993 b"UCS-4BE\0",
994 xmlCharEncoding::XML_CHAR_ENCODING_UCS4BE,
995 xmlCharEncoding::XML_CHAR_ENCODING_UCS4BE,
996 Some(ucs4be_input_func as xmlCharEncodingInputFunc),
997 Some(ucs4be_output_func as xmlCharEncodingOutputFunc),
998 );
999 register_handler(
1000 b"UCS-4\0",
1001 xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE,
1002 xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE,
1003 Some(ucs4le_input_func as xmlCharEncodingInputFunc),
1004 Some(ucs4le_output_func as xmlCharEncodingOutputFunc),
1005 );
1006
1007 register_handler(
1010 b"IBM037\0",
1011 xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC,
1012 xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC,
1013 Some(ebcdic_input_func as xmlCharEncodingInputFunc),
1014 Some(ebcdic_output_func as xmlCharEncodingOutputFunc),
1015 );
1016 register_handler(
1017 b"EBCDIC-US\0",
1018 xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC,
1019 xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC,
1020 Some(ebcdic_input_func as xmlCharEncodingInputFunc),
1021 Some(ebcdic_output_func as xmlCharEncodingOutputFunc),
1022 );
1023 register_handler(
1024 b"EBCDIC\0",
1025 xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC,
1026 xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC,
1027 Some(ebcdic_input_func as xmlCharEncodingInputFunc),
1028 Some(ebcdic_output_func as xmlCharEncodingOutputFunc),
1029 );
1030}
1031
1032fn register_handler(
1042 name_bytes: &[u8],
1043 _input_enc: xmlCharEncoding,
1044 _output_enc: xmlCharEncoding,
1045 input_func: Option<xmlCharEncodingInputFunc>,
1046 output_func: Option<xmlCharEncodingOutputFunc>,
1047) {
1048 let name_raw =
1049 unsafe { crate::abi::allocator::xmlMemStrdupImpl(name_bytes.as_ptr() as *const c_char) };
1050 if name_raw.is_null() {
1051 return;
1052 }
1053
1054 let handler = unsafe { xmlMallocImpl(size_of::<_xmlCharEncodingHandler>()) }
1055 as *mut _xmlCharEncodingHandler;
1056
1057 if handler.is_null() {
1058 unsafe { xmlFreeImpl(name_raw) };
1059 return;
1060 }
1061
1062 unsafe {
1063 ptr::write(
1064 handler,
1065 _xmlCharEncodingHandler {
1066 name: name_raw as *mut c_char,
1067 input: EncodingInputUnion {
1068 legacyFunc: input_func,
1069 },
1070 output: EncodingOutputUnion {
1071 legacyFunc: output_func,
1072 },
1073 inputCtxt: ptr::null_mut(),
1074 outputCtxt: ptr::null_mut(),
1075 ctxtDtor: None,
1076 flags: 0,
1077 },
1078 );
1079 }
1080
1081 add_encoding_handler(handler);
1082}
1083
1084pub(crate) fn cleanup_encodings() {
1095 let mut handlers = ENCODING_HANDLERS.write();
1096 for &handler in handlers.iter() {
1097 let ptr = handler.0;
1098 if !ptr.is_null() {
1099 unsafe {
1100 if !(*ptr).name.is_null() {
1101 xmlFreeImpl((*ptr).name as *mut c_void);
1102 }
1103 xmlFreeImpl(ptr as *mut c_void);
1104 }
1105 }
1106 }
1107 handlers.clear();
1108 drop(handlers);
1113 ENCODING_INITIALIZED.store(false, Ordering::SeqCst);
1114}
1115
1116pub(crate) fn find_encoding_handler(name: *const xmlChar) -> *mut _xmlCharEncodingHandler {
1128 if name.is_null() {
1129 return ptr::null_mut();
1130 }
1131
1132 init_encodings();
1136
1137 let name_str = unsafe {
1138 match CStr::from_ptr(name as *const c_char).to_bytes() {
1139 b"" => return ptr::null_mut(),
1140 s => s,
1141 }
1142 };
1143
1144 let handlers = ENCODING_HANDLERS.read();
1145 for &handler in handlers.iter() {
1146 let ptr = handler.0;
1147 if ptr.is_null() {
1148 continue;
1149 }
1150 let h_name = unsafe {
1151 if (*ptr).name.is_null() {
1152 continue;
1153 }
1154 CStr::from_ptr((*ptr).name).to_bytes()
1155 };
1156
1157 if name_str.eq_ignore_ascii_case(h_name) {
1158 return ptr;
1159 }
1160 }
1161 drop(handlers);
1162
1163 if let Some(canon) = encoding_name(encoding_from_name(name_str)) {
1169 if let Ok(canon_c) = std::ffi::CString::new(canon) {
1170 let handlers = ENCODING_HANDLERS.read();
1171 for &handler in handlers.iter() {
1172 let ptr = handler.0;
1173 if ptr.is_null() {
1174 continue;
1175 }
1176 let h_name = unsafe {
1177 if (*ptr).name.is_null() {
1178 continue;
1179 }
1180 CStr::from_ptr((*ptr).name).to_bytes()
1181 };
1182 if canon.eq_ignore_ascii_case(h_name) {
1183 return ptr;
1184 }
1185 }
1186 }
1187 }
1188
1189 ptr::null_mut()
1190}
1191
1192pub(crate) fn clone_encoding_handler_for_find(
1210 src: *mut _xmlCharEncodingHandler,
1211) -> *mut _xmlCharEncodingHandler {
1212 if src.is_null() {
1213 return ptr::null_mut();
1214 }
1215 let name_raw = unsafe {
1216 let nm = (*src).name;
1217 if nm.is_null() {
1218 ptr::null_mut()
1219 } else {
1220 crate::abi::allocator::xmlMemStrdupImpl(nm)
1221 }
1222 };
1223 let handler = unsafe { xmlMallocImpl(size_of::<_xmlCharEncodingHandler>()) }
1224 as *mut _xmlCharEncodingHandler;
1225 if handler.is_null() {
1226 if !name_raw.is_null() {
1227 unsafe { crate::abi::allocator::xmlFreeImpl(name_raw) };
1228 }
1229 return ptr::null_mut();
1230 }
1231 unsafe {
1232 ptr::write(
1233 handler,
1234 _xmlCharEncodingHandler {
1235 name: name_raw as *mut c_char,
1236 input: ptr::read(&(*src).input),
1237 output: ptr::read(&(*src).output),
1238 inputCtxt: (*src).inputCtxt,
1239 outputCtxt: (*src).outputCtxt,
1240 ctxtDtor: (*src).ctxtDtor,
1241 flags: (*src).flags,
1242 },
1243 );
1244 }
1245 handler
1246}
1247
1248pub(crate) const XML_HANDLER_STATIC: c_int = 0x01;
1252
1253pub(crate) fn xmlFindCharEncodingHandler_owned(
1270 name: *const xmlChar,
1271) -> *mut _xmlCharEncodingHandler {
1272 if name.is_null() {
1273 return ptr::null_mut();
1274 }
1275 let name_bytes = unsafe {
1276 let len = libc::strlen(name as *const c_char);
1277 core::slice::from_raw_parts(name as *const u8, len)
1278 };
1279
1280 if encoding_from_name(name_bytes) == xmlCharEncoding::XML_CHAR_ENCODING_UTF8 {
1282 let utf8 = find_encoding_handler(c"UTF-8".as_ptr() as *const xmlChar);
1283 if utf8.is_null() {
1284 return ptr::null_mut();
1285 }
1286 unsafe {
1288 (*utf8).flags |= XML_HANDLER_STATIC;
1289 }
1290 return utf8;
1291 }
1292
1293 let mut entry = find_encoding_handler(name as *const xmlChar);
1297 if entry.is_null() {
1298 if let Some(canon) = encoding_name(encoding_from_name(name_bytes)) {
1299 entry = find_encoding_handler(canon.as_ptr() as *const xmlChar);
1300 }
1301 }
1302 clone_encoding_handler_for_find(entry)
1305}
1306
1307pub(crate) fn add_encoding_handler(handler: *mut _xmlCharEncodingHandler) -> c_int {
1311 if handler.is_null() {
1312 return -1;
1313 }
1314
1315 let mut handlers = ENCODING_HANDLERS.write();
1316 handlers.push(HandlerPtr(handler));
1317 0
1318}
1319
1320#[allow(dead_code)]
1336pub(crate) fn char_enc_in_func(
1337 handler: *mut _xmlCharEncodingHandler,
1338 out: &mut [u8],
1339 in_data: &[u8],
1340) -> c_int {
1341 if handler.is_null() {
1342 return -1;
1343 }
1344
1345 let h = unsafe { &*handler };
1346 let input_func = unsafe { h.input.legacyFunc };
1347 let input_func = match input_func {
1348 Some(f) => f,
1349 None => return -1,
1350 };
1351
1352 let mut outlen = out.len() as c_int;
1353 let mut inlen = in_data.len() as c_int;
1354
1355 unsafe { input_func(out.as_mut_ptr(), &mut outlen, in_data.as_ptr(), &mut inlen) }
1356}
1357
1358#[allow(dead_code)]
1370pub(crate) fn char_enc_out_func(
1371 handler: *mut _xmlCharEncodingHandler,
1372 out: &mut [u8],
1373 in_data: &[u8],
1374) -> c_int {
1375 if handler.is_null() {
1376 return -1;
1377 }
1378
1379 let h = unsafe { &*handler };
1380 let output_func = unsafe { h.output.legacyFunc };
1381 let output_func = match output_func {
1382 Some(f) => f,
1383 None => return -1,
1384 };
1385
1386 let mut outlen = out.len() as c_int;
1387 let mut inlen = in_data.len() as c_int;
1388
1389 unsafe { output_func(out.as_mut_ptr(), &mut outlen, in_data.as_ptr(), &mut inlen) }
1390}
1391
1392pub(crate) fn char_enc_in(
1408 handler: *mut _xmlCharEncodingHandler,
1409 out: *mut _xmlBuffer,
1410 in_: *mut _xmlBuffer,
1411) -> c_int {
1412 if handler.is_null() || out.is_null() || in_.is_null() {
1413 return -1;
1414 }
1415
1416 let h = unsafe { &*handler };
1417 let input_func = unsafe { h.input.legacyFunc };
1418 let input_func = match input_func {
1419 Some(f) => f,
1420 None => return -1,
1421 };
1422
1423 let in_buf = unsafe { &*in_ };
1424 let out_buf = unsafe { &mut *out };
1425
1426 if in_buf.content.is_null() || in_buf.use_ == 0 {
1427 return 0;
1428 }
1429
1430 let in_data = unsafe { core::slice::from_raw_parts(in_buf.content, in_buf.use_ as usize) };
1431
1432 let out_capacity = (in_buf.use_ as usize).saturating_mul(3).max(256);
1434 let mut out_vec = vec![0u8; out_capacity];
1435 let mut out_len = out_capacity as c_int;
1436 let mut in_len = in_buf.use_ as c_int;
1437
1438 let ret = unsafe {
1439 input_func(
1440 out_vec.as_mut_ptr(),
1441 &mut out_len,
1442 in_data.as_ptr(),
1443 &mut in_len,
1444 )
1445 };
1446
1447 if ret < 0 {
1448 return -1;
1449 }
1450
1451 let written = ret as usize;
1452
1453 append_to_xml_buffer(out_buf, &out_vec[..written]);
1455
1456 written as c_int
1457}
1458
1459pub(crate) fn char_enc_out(
1475 handler: *mut _xmlCharEncodingHandler,
1476 out: *mut _xmlBuffer,
1477 in_: *mut _xmlBuffer,
1478) -> c_int {
1479 if handler.is_null() || out.is_null() || in_.is_null() {
1480 return -1;
1481 }
1482
1483 let h = unsafe { &*handler };
1484 let output_func = unsafe { h.output.legacyFunc };
1485 let output_func = match output_func {
1486 Some(f) => f,
1487 None => return -1,
1488 };
1489
1490 let in_buf = unsafe { &*in_ };
1491 let out_buf = unsafe { &mut *out };
1492
1493 if in_buf.content.is_null() || in_buf.use_ == 0 {
1494 return 0;
1495 }
1496
1497 let mut in_data = unsafe { core::slice::from_raw_parts(in_buf.content, in_buf.use_ as usize) };
1498
1499 const ENC_INPUT_ERROR: c_int = -2;
1508 let mut total_written: usize = 0;
1509 loop {
1510 let out_capacity = (in_data.len().saturating_mul(5)).max(64) + 16;
1515 let mut out_vec = vec![0u8; out_capacity];
1516 let mut out_len = out_capacity as c_int;
1517 let mut in_len = in_data.len() as c_int;
1518 let ret = unsafe {
1519 output_func(
1520 out_vec.as_mut_ptr(),
1521 &mut out_len,
1522 in_data.as_ptr(),
1523 &mut in_len,
1524 )
1525 };
1526 let written = out_len.max(0) as usize;
1527 if written > 0 {
1528 append_to_xml_buffer(out_buf, &out_vec[..written]);
1529 total_written += written;
1530 }
1531 let consumed = in_len.max(0) as usize;
1532 if ret == ENC_INPUT_ERROR && consumed < in_data.len() {
1533 let mut clen: c_int = 4;
1536 let cp = unsafe {
1537 crate::abi::exports_misc::xmlGetUTF8Char(in_data[consumed..].as_ptr(), &mut clen)
1538 };
1539 if cp <= 0 || clen <= 0 || (consumed + clen as usize) > in_data.len() {
1540 return -1;
1541 }
1542 let ref_str = format!("&#{};", cp);
1543 append_to_xml_buffer(out_buf, ref_str.as_bytes());
1544 total_written += ref_str.len();
1545 in_data = &in_data[consumed + clen as usize..];
1546 if in_data.is_empty() {
1547 break;
1548 }
1549 continue;
1550 }
1551 if ret < 0 {
1552 return -1;
1553 }
1554 break;
1555 }
1556
1557 total_written as c_int
1558}
1559
1560pub(crate) fn decode_whole_buffer_declared(name: &[u8], data: &[u8]) -> Result<Vec<u8>, ()> {
1573 if data.is_empty() {
1574 return Ok(Vec::new());
1575 }
1576 let Ok(cname) = std::ffi::CString::new(name) else {
1577 return Err(());
1578 };
1579 let mut handler = find_encoding_handler(cname.as_ptr() as *const xmlChar);
1580 if handler.is_null() {
1581 if let Some(canon) = encoding_name(encoding_from_name(name)) {
1585 if let Ok(canon_c) = std::ffi::CString::new(canon) {
1586 handler = find_encoding_handler(canon_c.as_ptr() as *const xmlChar);
1587 }
1588 }
1589 }
1590 if handler.is_null() {
1591 return Err(());
1592 }
1593 decode_bytes_with_handler(handler, data)
1594}
1595
1596pub(crate) fn decode_bytes_with_handler(
1602 handler: *mut _xmlCharEncodingHandler,
1603 data: &[u8],
1604) -> Result<Vec<u8>, ()> {
1605 if handler.is_null() || data.is_empty() {
1606 return Ok(Vec::new());
1607 }
1608 let input_func = unsafe { (*handler).input.legacyFunc };
1609 let Some(input_func) = input_func else {
1610 return Err(());
1611 };
1612 let mut out: Vec<u8> = vec![0u8; data.len().saturating_mul(3) + 16];
1613 let mut in_pos: usize = 0;
1614 let mut written_total: usize = 0;
1615 loop {
1616 let mut out_len = (out.len() - written_total) as c_int;
1617 let mut in_len = (data.len() - in_pos) as c_int;
1618 let ret = unsafe {
1622 input_func(
1623 out[written_total..].as_mut_ptr(),
1624 &mut out_len,
1625 data[in_pos..].as_ptr(),
1626 &mut in_len,
1627 )
1628 };
1629 let written = out_len.max(0) as usize;
1630 let consumed = in_len.max(0) as usize;
1631 written_total += written;
1632 in_pos += consumed;
1633 if ret < 0 {
1634 return Err(());
1635 }
1636 if in_pos >= data.len() {
1637 break;
1638 }
1639 if written == 0 {
1640 return Err(());
1642 }
1643 out.resize(out.len().saturating_mul(2).max(written_total + 64), 0);
1644 }
1645 out.truncate(written_total);
1646 Ok(out)
1647}
1648
1649fn append_to_xml_buffer(buf: &mut _xmlBuffer, data: &[u8]) {
1657 if data.is_empty() {
1658 return;
1659 }
1660
1661 let new_use = (buf.use_ as usize).saturating_add(data.len());
1662 if new_use > buf.size as usize {
1663 let new_size = (buf.size as usize).saturating_mul(2).max(new_use).max(256);
1665 let new_content =
1666 unsafe { xmlReallocImpl(buf.content as *mut c_void, new_size) as *mut xmlChar };
1667 if new_content.is_null() {
1668 return; }
1670 buf.content = new_content;
1671 buf.contentIO = new_content;
1677 buf.size = new_size as c_uint;
1678 }
1679
1680 unsafe {
1681 ptr::copy_nonoverlapping(
1682 data.as_ptr(),
1683 buf.content.add(buf.use_ as usize),
1684 data.len(),
1685 );
1686 }
1687 buf.use_ = new_use as c_uint;
1688}
1689
1690unsafe extern "C" fn utf8_input_func(
1700 out: *mut c_uchar,
1701 outlen: *mut c_int,
1702 in_: *const c_uchar,
1703 inlen: *mut c_int,
1704) -> c_int {
1705 let avail_out = *outlen as usize;
1706 let avail_in = *inlen as usize;
1707 let to_copy = avail_out.min(avail_in);
1708
1709 if to_copy > 0 {
1710 ptr::copy_nonoverlapping(in_, out, to_copy);
1711 }
1712
1713 *outlen = to_copy as c_int;
1714 *inlen = to_copy as c_int;
1715 to_copy as c_int
1716}
1717
1718unsafe extern "C" fn utf8_output_func(
1720 out: *mut c_uchar,
1721 outlen: *mut c_int,
1722 in_: *const c_uchar,
1723 inlen: *mut c_int,
1724) -> c_int {
1725 utf8_input_func(out, outlen, in_, inlen)
1726}
1727
1728unsafe extern "C" fn utf16le_input_func(
1732 out: *mut c_uchar,
1733 outlen: *mut c_int,
1734 in_: *const c_uchar,
1735 inlen: *mut c_int,
1736) -> c_int {
1737 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
1738 return -1;
1739 }
1740
1741 let avail_in = *inlen as usize;
1742 let avail_out = *outlen as usize;
1743
1744 if avail_in == 0 || avail_out == 0 {
1745 *outlen = 0;
1746 *inlen = 0;
1747 return 0;
1748 }
1749
1750 let in_data = core::slice::from_raw_parts(in_, avail_in);
1751 let _out_slice = core::slice::from_raw_parts_mut(out, avail_out);
1752
1753 let result = match utf16le_to_utf8(in_data) {
1755 Ok(v) => v,
1756 Err(()) => return -1,
1757 };
1758
1759 let written = result.len().min(avail_out);
1760 if written > 0 {
1761 ptr::copy_nonoverlapping(result.as_ptr(), out, written);
1762 }
1763
1764 *outlen = written as c_int;
1765 *inlen = avail_in as c_int; written as c_int
1767}
1768
1769unsafe extern "C" fn utf16le_output_func(
1771 out: *mut c_uchar,
1772 outlen: *mut c_int,
1773 in_: *const c_uchar,
1774 inlen: *mut c_int,
1775) -> c_int {
1776 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
1777 return -1;
1778 }
1779
1780 let avail_in = *inlen as usize;
1781 let avail_out = *outlen as usize;
1782
1783 if avail_in == 0 || avail_out == 0 {
1784 *outlen = 0;
1785 *inlen = 0;
1786 return 0;
1787 }
1788
1789 let in_data = core::slice::from_raw_parts(in_, avail_in);
1790 let _out_slice = core::slice::from_raw_parts_mut(out, avail_out);
1791
1792 let result = match utf8_to_utf16le(in_data) {
1793 Ok(v) => v,
1794 Err(()) => return -1,
1795 };
1796
1797 let written = result.len().min(avail_out);
1798 if written > 0 {
1799 ptr::copy_nonoverlapping(result.as_ptr(), out, written);
1800 }
1801
1802 *outlen = written as c_int;
1803 *inlen = avail_in as c_int;
1804 written as c_int
1805}
1806
1807unsafe extern "C" fn utf16be_input_func(
1811 out: *mut c_uchar,
1812 outlen: *mut c_int,
1813 in_: *const c_uchar,
1814 inlen: *mut c_int,
1815) -> c_int {
1816 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
1817 return -1;
1818 }
1819
1820 let avail_in = *inlen as usize;
1821 let avail_out = *outlen as usize;
1822
1823 if avail_in == 0 || avail_out == 0 {
1824 *outlen = 0;
1825 *inlen = 0;
1826 return 0;
1827 }
1828
1829 let in_data = core::slice::from_raw_parts(in_, avail_in);
1830 let _out_slice = core::slice::from_raw_parts_mut(out, avail_out);
1831
1832 let result = match utf16be_to_utf8(in_data) {
1833 Ok(v) => v,
1834 Err(()) => return -1,
1835 };
1836
1837 let written = result.len().min(avail_out);
1838 if written > 0 {
1839 ptr::copy_nonoverlapping(result.as_ptr(), out, written);
1840 }
1841
1842 *outlen = written as c_int;
1843 *inlen = avail_in as c_int;
1844 written as c_int
1845}
1846
1847unsafe extern "C" fn utf16be_output_func(
1849 out: *mut c_uchar,
1850 outlen: *mut c_int,
1851 in_: *const c_uchar,
1852 inlen: *mut c_int,
1853) -> c_int {
1854 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
1855 return -1;
1856 }
1857
1858 let avail_in = *inlen as usize;
1859 let avail_out = *outlen as usize;
1860
1861 if avail_in == 0 || avail_out == 0 {
1862 *outlen = 0;
1863 *inlen = 0;
1864 return 0;
1865 }
1866
1867 let in_data = core::slice::from_raw_parts(in_, avail_in);
1868
1869 let le_result = match utf8_to_utf16le(in_data) {
1871 Ok(v) => v,
1872 Err(()) => return -1,
1873 };
1874
1875 let mut result = le_result;
1877 for chunk in result.as_chunks_mut::<2>().0 {
1878 chunk.swap(0, 1);
1879 }
1880
1881 let written = result.len().min(avail_out);
1882 if written > 0 {
1883 ptr::copy_nonoverlapping(result.as_ptr(), out, written);
1884 }
1885
1886 *outlen = written as c_int;
1887 *inlen = avail_in as c_int;
1888 written as c_int
1889}
1890
1891unsafe extern "C" fn latin1_input_func(
1895 out: *mut c_uchar,
1896 outlen: *mut c_int,
1897 in_: *const c_uchar,
1898 inlen: *mut c_int,
1899) -> c_int {
1900 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
1901 return -1;
1902 }
1903
1904 let avail_in = *inlen as usize;
1905 let avail_out = *outlen as usize;
1906
1907 if avail_in == 0 || avail_out == 0 {
1908 *outlen = 0;
1909 *inlen = 0;
1910 return 0;
1911 }
1912
1913 let in_data = core::slice::from_raw_parts(in_, avail_in);
1914 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
1915
1916 let mut in_pos = 0;
1917 let mut out_pos = 0;
1918
1919 while in_pos < avail_in && out_pos < avail_out {
1920 let byte = in_data[in_pos];
1921 in_pos += 1;
1922
1923 if byte < 0x80 {
1924 if out_pos < avail_out {
1926 out_slice[out_pos] = byte;
1927 out_pos += 1;
1928 } else {
1929 break;
1930 }
1931 } else {
1932 if out_pos + 1 < avail_out {
1935 out_slice[out_pos] = 0xC2 | (byte >> 6);
1936 out_slice[out_pos + 1] = 0x80 | (byte & 0x3F);
1937 out_pos += 2;
1938 } else {
1939 break;
1940 }
1941 }
1942 }
1943
1944 *outlen = out_pos as c_int;
1945 *inlen = in_pos as c_int;
1946 out_pos as c_int
1947}
1948
1949unsafe extern "C" fn latin1_output_func(
1951 out: *mut c_uchar,
1952 outlen: *mut c_int,
1953 in_: *const c_uchar,
1954 inlen: *mut c_int,
1955) -> c_int {
1956 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
1957 return -1;
1958 }
1959
1960 let avail_in = *inlen as usize;
1961 let avail_out = *outlen as usize;
1962
1963 if avail_in == 0 || avail_out == 0 {
1964 *outlen = 0;
1965 *inlen = 0;
1966 return 0;
1967 }
1968
1969 let in_data = core::slice::from_raw_parts(in_, avail_in);
1970 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
1971
1972 let mut in_pos = 0;
1973 let mut out_pos = 0;
1974
1975 while in_pos < avail_in && out_pos < avail_out {
1976 let byte = in_data[in_pos];
1977 in_pos += 1;
1978
1979 if byte < 0x80 {
1980 out_slice[out_pos] = byte;
1982 out_pos += 1;
1983 } else if (0xC2..=0xC3).contains(&byte) {
1984 if in_pos < avail_in {
1986 let second = in_data[in_pos];
1987 in_pos += 1;
1988 if second & 0xC0 != 0x80 {
1989 return -1; }
1991 let cp = ((byte as u32 & 0x1F) << 6) | (second as u32 & 0x3F);
1992 if cp > 0xFF {
1993 return -1; }
1995 out_slice[out_pos] = cp as u8;
1996 out_pos += 1;
1997 } else {
1998 return -1; }
2000 } else if (0x80..=0xBF).contains(&byte) {
2001 return -1;
2003 } else {
2004 return -1;
2007 }
2008 }
2009
2010 *outlen = out_pos as c_int;
2011 *inlen = in_pos as c_int;
2012 out_pos as c_int
2013}
2014
2015const CP1252_C1: [u16; 32] = [
2026 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, ];
2031
2032#[allow(dead_code)]
2035pub(crate) const fn cp1252_byte_to_cp(byte: u8) -> Option<u32> {
2036 match byte {
2037 0x00..=0x7F => Some(byte as u32),
2038 0x80..=0x9F => {
2039 let cp = CP1252_C1[(byte - 0x80) as usize];
2040 if cp == 0xFFFF {
2041 None
2042 } else {
2043 Some(cp as u32)
2044 }
2045 }
2046 _ => Some(byte as u32), }
2048}
2049
2050#[allow(dead_code)]
2053pub(crate) const fn cp_to_cp1252_byte(cp: u32) -> Option<u8> {
2054 if cp < 0x80 || (cp >= 0xA0 && cp <= 0xFF) {
2055 Some(cp as u8)
2056 } else if cp >= 0x80 && cp <= 0x9F {
2057 let mut i = 0;
2060 while i < 32 {
2061 if CP1252_C1[i] == cp as u16 {
2062 return Some(0x80 + i as u8);
2063 }
2064 i += 1;
2065 }
2066 None
2067 } else {
2068 None
2069 }
2070}
2071
2072fn decode_utf8_char(data: &[u8], in_pos: usize) -> Option<(u32, usize)> {
2075 let b0 = *data.get(in_pos)?;
2076 if b0 < 0x80 {
2077 return Some((u32::from(b0), 1));
2078 }
2079 let (len, cp0) = match b0 {
2080 0xC2..=0xDF => (2, u32::from(b0 & 0x1F)),
2081 0xE0..=0xEF => (3, u32::from(b0 & 0x0F)),
2082 0xF0..=0xF4 => (4, u32::from(b0 & 0x07)),
2083 _ => return None,
2084 };
2085 if in_pos + len > data.len() {
2086 return None;
2087 }
2088 let mut cp = cp0;
2089 for k in 1..len {
2090 let b = data[in_pos + k];
2091 if b & 0xC0 != 0x80 {
2092 return None;
2093 }
2094 cp = (cp << 6) | u32::from(b & 0x3F);
2095 }
2096 Some((cp, len))
2097}
2098
2099pub(crate) fn cp1252_to_utf8(data: &[u8]) -> Result<Vec<u8>, ()> {
2104 let mut result = Vec::with_capacity(data.len() * 2);
2105 for &byte in data {
2106 let cp = match cp1252_byte_to_cp(byte) {
2107 None => return Err(()),
2108 Some(cp) => cp,
2109 };
2110 let mut buf = [0u8; 4];
2111 let n = encode_codepoint_to_utf8(cp, &mut buf);
2112 result.extend_from_slice(&buf[..n]);
2113 }
2114 Ok(result)
2115}
2116
2117#[allow(dead_code)]
2121pub(crate) fn utf8_to_cp1252(data: &[u8]) -> Result<Vec<u8>, ()> {
2122 let mut result = Vec::with_capacity(data.len());
2123 let mut pos = 0;
2124 while pos < data.len() {
2125 let (cp, consumed) = match decode_utf8_char(data, pos) {
2126 None => return Err(()),
2127 Some(v) => v,
2128 };
2129 let byte = match cp_to_cp1252_byte(cp) {
2130 None => return Err(()),
2131 Some(b) => b,
2132 };
2133 result.push(byte);
2134 pos += consumed;
2135 }
2136 Ok(result)
2137}
2138
2139unsafe extern "C" fn cp1252_input_func(
2141 out: *mut c_uchar,
2142 outlen: *mut c_int,
2143 in_: *const c_uchar,
2144 inlen: *mut c_int,
2145) -> c_int {
2146 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2147 return -1;
2148 }
2149
2150 let avail_in = *inlen as usize;
2151 let avail_out = *outlen as usize;
2152
2153 if avail_in == 0 || avail_out == 0 {
2154 *outlen = 0;
2155 *inlen = 0;
2156 return 0;
2157 }
2158
2159 let in_data = core::slice::from_raw_parts(in_, avail_in);
2160 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2161
2162 let mut in_pos = 0;
2163 let mut out_pos = 0;
2164
2165 while in_pos < avail_in && out_pos < avail_out {
2166 let byte = in_data[in_pos];
2167 let cp = match cp1252_byte_to_cp(byte) {
2168 None => {
2170 *outlen = out_pos as c_int;
2171 *inlen = in_pos as c_int;
2172 return -1;
2173 }
2174 Some(cp) => cp,
2175 };
2176 let mut buf = [0u8; 4];
2177 let n = encode_codepoint_to_utf8(cp, &mut buf);
2178 if out_pos + n > avail_out {
2179 break;
2180 }
2181 out_slice[out_pos..out_pos + n].copy_from_slice(&buf[..n]);
2182 out_pos += n;
2183 in_pos += 1;
2184 }
2185
2186 *outlen = out_pos as c_int;
2187 *inlen = in_pos as c_int;
2188 out_pos as c_int
2189}
2190
2191unsafe extern "C" fn cp1252_output_func(
2193 out: *mut c_uchar,
2194 outlen: *mut c_int,
2195 in_: *const c_uchar,
2196 inlen: *mut c_int,
2197) -> c_int {
2198 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2199 return -1;
2200 }
2201
2202 let avail_in = *inlen as usize;
2203 let avail_out = *outlen as usize;
2204
2205 if avail_in == 0 || avail_out == 0 {
2206 *outlen = 0;
2207 *inlen = 0;
2208 return 0;
2209 }
2210
2211 let in_data = core::slice::from_raw_parts(in_, avail_in);
2212 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2213
2214 let mut in_pos = 0;
2215 let mut out_pos = 0;
2216
2217 while in_pos < avail_in && out_pos < avail_out {
2218 let (cp, consumed) = match decode_utf8_char(in_data, in_pos) {
2219 None => {
2220 *outlen = out_pos as c_int;
2221 *inlen = in_pos as c_int;
2222 return -1;
2223 }
2224 Some(v) => v,
2225 };
2226 let byte = match cp_to_cp1252_byte(cp) {
2227 None => {
2228 *outlen = out_pos as c_int;
2230 *inlen = in_pos as c_int;
2231 return -1;
2232 }
2233 Some(b) => b,
2234 };
2235 out_slice[out_pos] = byte;
2236 out_pos += 1;
2237 in_pos += consumed;
2238 }
2239
2240 *outlen = out_pos as c_int;
2241 *inlen = in_pos as c_int;
2242 out_pos as c_int
2243}
2244
2245unsafe extern "C" fn ascii_input_func(
2256 out: *mut c_uchar,
2257 outlen: *mut c_int,
2258 in_: *const c_uchar,
2259 inlen: *mut c_int,
2260) -> c_int {
2261 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2262 return -1;
2263 }
2264
2265 let avail_in = *inlen as usize;
2266 let avail_out = *outlen as usize;
2267
2268 if avail_in == 0 || avail_out == 0 {
2269 *outlen = 0;
2270 *inlen = 0;
2271 return 0;
2272 }
2273
2274 let in_data = core::slice::from_raw_parts(in_, avail_in);
2275 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2276
2277 let mut pos = 0;
2278 while pos < avail_in && pos < avail_out {
2279 let byte = in_data[pos];
2280 if byte > 0x7F {
2281 *outlen = pos as c_int;
2284 *inlen = pos as c_int;
2285 return -2;
2286 }
2287 out_slice[pos] = byte;
2288 pos += 1;
2289 }
2290
2291 *outlen = pos as c_int;
2292 *inlen = pos as c_int;
2293 pos as c_int
2294}
2295
2296unsafe extern "C" fn ascii_output_func(
2298 out: *mut c_uchar,
2299 outlen: *mut c_int,
2300 in_: *const c_uchar,
2301 inlen: *mut c_int,
2302) -> c_int {
2303 ascii_input_func(out, outlen, in_, inlen)
2305}
2306
2307const ENC_INPUT_ERROR: c_int = -2;
2314
2315unsafe fn enc_rs_output(
2326 target: &'static encoding_rs::Encoding,
2327 out: *mut c_uchar,
2328 outlen: *mut c_int,
2329 in_: *const c_uchar,
2330 inlen: *mut c_int,
2331) -> c_int {
2332 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2333 return -1;
2334 }
2335 let avail_in = *inlen as usize;
2336 let avail_out = *outlen as usize;
2337
2338 if avail_in == 0 || avail_out == 0 {
2339 *outlen = 0;
2340 *inlen = 0;
2341 return 0;
2342 }
2343
2344 let in_data = core::slice::from_raw_parts(in_, avail_in);
2345 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2346
2347 let (s, error_at) = match core::str::from_utf8(in_data) {
2352 Ok(s) => (s, None),
2353 Err(e) => {
2354 let valid = e.valid_up_to();
2355 if valid == 0 {
2356 *outlen = 0;
2357 *inlen = 0;
2358 return -1;
2359 }
2360 (
2363 unsafe { core::str::from_utf8_unchecked(&in_data[..valid]) },
2364 Some(valid),
2365 )
2366 }
2367 };
2368
2369 let mut encoder = target.new_encoder();
2370 let mut in_pos: usize = 0;
2371 let mut out_pos: usize = 0;
2372 while in_pos < s.len() && out_pos < avail_out {
2373 let dst = &mut out_slice[out_pos..];
2374 let (res, read, written) =
2375 encoder.encode_from_utf8_without_replacement(&s[in_pos..], dst, true);
2376 out_pos += written;
2377 in_pos += read;
2378 match res {
2379 encoding_rs::EncoderResult::InputEmpty => break,
2380 encoding_rs::EncoderResult::OutputFull => {
2381 break;
2385 }
2386 encoding_rs::EncoderResult::Unmappable(c) => {
2387 *outlen = out_pos as c_int;
2393 *inlen = (in_pos - c.len_utf8()) as c_int;
2394 return ENC_INPUT_ERROR;
2395 }
2396 }
2397 }
2398
2399 if let Some(err) = error_at {
2400 if in_pos == s.len() {
2401 *outlen = out_pos as c_int;
2405 *inlen = err as c_int;
2406 return -1;
2407 }
2408 }
2409 *outlen = out_pos as c_int;
2410 *inlen = in_pos as c_int;
2411 out_pos as c_int
2412}
2413
2414unsafe fn enc_rs_input(
2420 source: &'static encoding_rs::Encoding,
2421 out: *mut c_uchar,
2422 outlen: *mut c_int,
2423 in_: *const c_uchar,
2424 inlen: *mut c_int,
2425) -> c_int {
2426 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2427 return -1;
2428 }
2429 let avail_in = *inlen as usize;
2430 let avail_out = *outlen as usize;
2431
2432 if avail_in == 0 || avail_out == 0 {
2433 *outlen = 0;
2434 *inlen = 0;
2435 return 0;
2436 }
2437
2438 let in_data = core::slice::from_raw_parts(in_, avail_in);
2439 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2440
2441 let mut decoder = source.new_decoder_without_bom_handling();
2442 let mut in_pos: usize = 0;
2443 let mut out_pos: usize = 0;
2444 while in_pos < avail_in && out_pos < avail_out {
2445 let (res, read, written) = decoder.decode_to_utf8_without_replacement(
2446 &in_data[in_pos..],
2447 &mut out_slice[out_pos..],
2448 true,
2449 );
2450 out_pos += written;
2451 in_pos += read;
2452 match res {
2453 encoding_rs::DecoderResult::InputEmpty => break,
2454 encoding_rs::DecoderResult::OutputFull => break,
2455 encoding_rs::DecoderResult::Malformed(..) => {
2456 *outlen = out_pos as c_int;
2459 *inlen = in_pos as c_int;
2460 return -1;
2461 }
2462 }
2463 }
2464
2465 *outlen = out_pos as c_int;
2466 *inlen = in_pos as c_int;
2467 out_pos as c_int
2468}
2469
2470unsafe extern "C" fn shift_jis_input_func(
2472 out: *mut c_uchar,
2473 outlen: *mut c_int,
2474 in_: *const c_uchar,
2475 inlen: *mut c_int,
2476) -> c_int {
2477 enc_rs_input(encoding_rs::SHIFT_JIS, out, outlen, in_, inlen)
2478}
2479
2480unsafe extern "C" fn shift_jis_output_func(
2482 out: *mut c_uchar,
2483 outlen: *mut c_int,
2484 in_: *const c_uchar,
2485 inlen: *mut c_int,
2486) -> c_int {
2487 enc_rs_output(encoding_rs::SHIFT_JIS, out, outlen, in_, inlen)
2488}
2489
2490unsafe extern "C" fn euc_jp_input_func(
2492 out: *mut c_uchar,
2493 outlen: *mut c_int,
2494 in_: *const c_uchar,
2495 inlen: *mut c_int,
2496) -> c_int {
2497 enc_rs_input(encoding_rs::EUC_JP, out, outlen, in_, inlen)
2498}
2499
2500unsafe extern "C" fn euc_jp_output_func(
2502 out: *mut c_uchar,
2503 outlen: *mut c_int,
2504 in_: *const c_uchar,
2505 inlen: *mut c_int,
2506) -> c_int {
2507 enc_rs_output(encoding_rs::EUC_JP, out, outlen, in_, inlen)
2508}
2509
2510macro_rules! define_enc_rs_codec {
2515 ($input_fn:ident, $output_fn:ident, $enc:expr) => {
2516 #[allow(dead_code)]
2517 unsafe extern "C" fn $input_fn(
2518 out: *mut c_uchar,
2519 outlen: *mut c_int,
2520 in_: *const c_uchar,
2521 inlen: *mut c_int,
2522 ) -> c_int {
2523 enc_rs_input($enc, out, outlen, in_, inlen)
2524 }
2525 #[allow(dead_code)]
2526 unsafe extern "C" fn $output_fn(
2527 out: *mut c_uchar,
2528 outlen: *mut c_int,
2529 in_: *const c_uchar,
2530 inlen: *mut c_int,
2531 ) -> c_int {
2532 enc_rs_output($enc, out, outlen, in_, inlen)
2533 }
2534 };
2535}
2536
2537define_enc_rs_codec!(
2538 iso_8859_2_input_func,
2539 iso_8859_2_output_func,
2540 encoding_rs::ISO_8859_2
2541);
2542define_enc_rs_codec!(
2543 iso_8859_3_input_func,
2544 iso_8859_3_output_func,
2545 encoding_rs::ISO_8859_3
2546);
2547define_enc_rs_codec!(
2548 iso_8859_4_input_func,
2549 iso_8859_4_output_func,
2550 encoding_rs::ISO_8859_4
2551);
2552define_enc_rs_codec!(
2553 iso_8859_5_input_func,
2554 iso_8859_5_output_func,
2555 encoding_rs::ISO_8859_5
2556);
2557define_enc_rs_codec!(
2558 iso_8859_6_input_func,
2559 iso_8859_6_output_func,
2560 encoding_rs::ISO_8859_6
2561);
2562define_enc_rs_codec!(
2563 iso_8859_7_input_func,
2564 iso_8859_7_output_func,
2565 encoding_rs::ISO_8859_7
2566);
2567define_enc_rs_codec!(
2568 iso_8859_8_input_func,
2569 iso_8859_8_output_func,
2570 encoding_rs::ISO_8859_8
2571);
2572define_enc_rs_codec!(
2573 iso_8859_9_input_func,
2574 iso_8859_9_output_func,
2575 encoding_rs::WINDOWS_1254
2576);
2577define_enc_rs_codec!(
2578 iso_8859_10_input_func,
2579 iso_8859_10_output_func,
2580 encoding_rs::ISO_8859_10
2581);
2582define_enc_rs_codec!(
2583 iso_8859_11_input_func,
2584 iso_8859_11_output_func,
2585 encoding_rs::WINDOWS_874
2586);
2587define_enc_rs_codec!(
2588 iso_8859_13_input_func,
2589 iso_8859_13_output_func,
2590 encoding_rs::ISO_8859_13
2591);
2592define_enc_rs_codec!(
2593 iso_8859_14_input_func,
2594 iso_8859_14_output_func,
2595 encoding_rs::ISO_8859_14
2596);
2597define_enc_rs_codec!(
2598 iso_8859_15_input_func,
2599 iso_8859_15_output_func,
2600 encoding_rs::ISO_8859_15
2601);
2602define_enc_rs_codec!(
2603 iso_8859_16_input_func,
2604 iso_8859_16_output_func,
2605 encoding_rs::ISO_8859_16
2606);
2607define_enc_rs_codec!(
2608 iso_2022_jp_input_func,
2609 iso_2022_jp_output_func,
2610 encoding_rs::ISO_2022_JP
2611);
2612
2613unsafe fn fixed_width_input(
2622 le: bool,
2623 width: usize,
2624 out: *mut c_uchar,
2625 outlen: *mut c_int,
2626 in_: *const c_uchar,
2627 inlen: *mut c_int,
2628) -> c_int {
2629 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2630 return -1;
2631 }
2632 let avail_in = *inlen as usize;
2633 let avail_out = *outlen as usize;
2634 if avail_in == 0 || avail_out == 0 {
2635 *outlen = 0;
2636 *inlen = 0;
2637 return 0;
2638 }
2639 let in_data = core::slice::from_raw_parts(in_, avail_in);
2640 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2641 let mut in_pos = 0usize;
2642 let mut out_pos = 0usize;
2643 if avail_in >= width {
2648 let mut first: u32 = 0;
2649 for k in 0..width {
2650 let b = in_data[k] as u32;
2651 first = if le {
2652 first | (b << (8 * k))
2653 } else {
2654 (first << 8) | b
2655 };
2656 }
2657 if first == 0x0000_FEFF {
2658 in_pos = width;
2659 }
2660 }
2661 while in_pos + width <= avail_in {
2662 let mut unit: u32 = 0;
2663 for k in 0..width {
2664 let b = in_data[in_pos + k] as u32;
2665 unit = if le {
2666 unit | (b << (8 * k))
2667 } else {
2668 (unit << 8) | b
2669 };
2670 }
2671 if unit > 0x10FFFF || (0xD800..=0xDFFF).contains(&unit) {
2672 *outlen = out_pos as c_int;
2674 *inlen = in_pos as c_int;
2675 return -1;
2676 }
2677 let mut buf = [0u8; 4];
2678 let ch = unsafe { char::from_u32_unchecked(unit) };
2681 let n = ch.encode_utf8(&mut buf).len();
2682 if out_pos + n > avail_out {
2683 break;
2684 }
2685 out_slice[out_pos..out_pos + n].copy_from_slice(&buf[..n]);
2686 out_pos += n;
2687 in_pos += width;
2688 }
2689 *outlen = out_pos as c_int;
2690 *inlen = in_pos as c_int;
2691 out_pos as c_int
2692}
2693
2694unsafe fn fixed_width_output(
2698 le: bool,
2699 width: usize,
2700 out: *mut c_uchar,
2701 outlen: *mut c_int,
2702 in_: *const c_uchar,
2703 inlen: *mut c_int,
2704) -> c_int {
2705 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2706 return -1;
2707 }
2708 let avail_in = *inlen as usize;
2709 let avail_out = *outlen as usize;
2710 if avail_in == 0 || avail_out == 0 {
2711 *outlen = 0;
2712 *inlen = 0;
2713 return 0;
2714 }
2715 let in_data = core::slice::from_raw_parts(in_, avail_in);
2716 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2717 let mut in_pos = 0usize;
2718 let mut out_pos = 0usize;
2719 while in_pos < avail_in {
2720 let (cp, consumed) = match decode_utf8_char(in_data, in_pos) {
2721 None => {
2722 *outlen = out_pos as c_int;
2725 *inlen = in_pos as c_int;
2726 return -1;
2727 }
2728 Some(v) => v,
2729 };
2730 let max_cp = if width == 2 { 0xFFFF } else { 0x10FFFF };
2731 if cp > max_cp {
2732 *outlen = out_pos as c_int;
2735 *inlen = in_pos as c_int;
2736 return ENC_INPUT_ERROR;
2737 }
2738 if out_pos + width > avail_out {
2739 break;
2740 }
2741 for k in 0..width {
2742 let shift = 8 * if le { k } else { width - 1 - k };
2743 out_slice[out_pos + k] = ((cp >> shift) & 0xFF) as u8;
2744 }
2745 out_pos += width;
2746 in_pos += consumed;
2747 }
2748 *outlen = out_pos as c_int;
2749 *inlen = in_pos as c_int;
2750 out_pos as c_int
2751}
2752
2753unsafe extern "C" fn ucs2_input_func(
2757 out: *mut c_uchar,
2758 outlen: *mut c_int,
2759 in_: *const c_uchar,
2760 inlen: *mut c_int,
2761) -> c_int {
2762 fixed_width_input(true, 2, out, outlen, in_, inlen)
2763}
2764
2765unsafe extern "C" fn ucs2_output_func(
2767 out: *mut c_uchar,
2768 outlen: *mut c_int,
2769 in_: *const c_uchar,
2770 inlen: *mut c_int,
2771) -> c_int {
2772 fixed_width_output(true, 2, out, outlen, in_, inlen)
2773}
2774
2775unsafe extern "C" fn ucs4le_input_func(
2777 out: *mut c_uchar,
2778 outlen: *mut c_int,
2779 in_: *const c_uchar,
2780 inlen: *mut c_int,
2781) -> c_int {
2782 fixed_width_input(true, 4, out, outlen, in_, inlen)
2783}
2784
2785unsafe extern "C" fn ucs4le_output_func(
2787 out: *mut c_uchar,
2788 outlen: *mut c_int,
2789 in_: *const c_uchar,
2790 inlen: *mut c_int,
2791) -> c_int {
2792 fixed_width_output(true, 4, out, outlen, in_, inlen)
2793}
2794
2795unsafe extern "C" fn ucs4be_input_func(
2797 out: *mut c_uchar,
2798 outlen: *mut c_int,
2799 in_: *const c_uchar,
2800 inlen: *mut c_int,
2801) -> c_int {
2802 fixed_width_input(false, 4, out, outlen, in_, inlen)
2803}
2804
2805unsafe extern "C" fn ucs4be_output_func(
2807 out: *mut c_uchar,
2808 outlen: *mut c_int,
2809 in_: *const c_uchar,
2810 inlen: *mut c_int,
2811) -> c_int {
2812 fixed_width_output(false, 4, out, outlen, in_, inlen)
2813}
2814
2815const EBCDIC037_TO_UNICODE: [u16; 256] = [
2819 0x0000, 0x0001, 0x0002, 0x0003, 0x009C, 0x0009, 0x0086, 0x007F, 0x0097, 0x008D, 0x008E, 0x000B,
2820 0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x009D, 0x0085, 0x0008, 0x0087,
2821 0x0018, 0x0019, 0x0092, 0x008F, 0x001C, 0x001D, 0x001E, 0x001F, 0x0080, 0x0081, 0x0082, 0x0083,
2822 0x0084, 0x000A, 0x0017, 0x001B, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x0005, 0x0006, 0x0007,
2823 0x0090, 0x0091, 0x0016, 0x0093, 0x0094, 0x0095, 0x0096, 0x0004, 0x0098, 0x0099, 0x009A, 0x009B,
2824 0x0014, 0x0015, 0x009E, 0x001A, 0x0020, 0x00A0, 0x00E2, 0x00E4, 0x00E0, 0x00E1, 0x00E3, 0x00E5,
2825 0x00E7, 0x00F1, 0x00A2, 0x002E, 0x003C, 0x0028, 0x002B, 0x007C, 0x0026, 0x00E9, 0x00EA, 0x00EB,
2826 0x00E8, 0x00ED, 0x00EE, 0x00EF, 0x00EC, 0x00DF, 0x0021, 0x0024, 0x002A, 0x0029, 0x003B, 0x00AC,
2827 0x002D, 0x002F, 0x00C2, 0x00C4, 0x00C0, 0x00C1, 0x00C3, 0x00C5, 0x00C7, 0x00D1, 0x00A6, 0x002C,
2828 0x0025, 0x005F, 0x003E, 0x003F, 0x00F8, 0x00C9, 0x00CA, 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF,
2829 0x00CC, 0x0060, 0x003A, 0x0023, 0x0040, 0x0027, 0x003D, 0x0022, 0x00D8, 0x0061, 0x0062, 0x0063,
2830 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x00AB, 0x00BB, 0x00F0, 0x00FD, 0x00FE, 0x00B1,
2831 0x00B0, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x00AA, 0x00BA,
2832 0x00E6, 0x00B8, 0x00C6, 0x00A4, 0x00B5, 0x007E, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
2833 0x0079, 0x007A, 0x00A1, 0x00BF, 0x00D0, 0x00DD, 0x00DE, 0x00AE, 0x005E, 0x00A3, 0x00A5, 0x00B7,
2834 0x00A9, 0x00A7, 0x00B6, 0x00BC, 0x00BD, 0x00BE, 0x005B, 0x005D, 0x00AF, 0x00A8, 0x00B4, 0x00D7,
2835 0x007B, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x00AD, 0x00F4,
2836 0x00F6, 0x00F2, 0x00F3, 0x00F5, 0x007D, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
2837 0x0051, 0x0052, 0x00B9, 0x00FB, 0x00FC, 0x00F9, 0x00FA, 0x00FF, 0x005C, 0x00F7, 0x0053, 0x0054,
2838 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x00B2, 0x00D4, 0x00D6, 0x00D2, 0x00D3, 0x00D5,
2839 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x00B3, 0x00DB,
2840 0x00DC, 0x00D9, 0x00DA, 0x009F,
2841];
2842
2843const fn ebcdic037_cp_to_byte(cp: u32) -> Option<u8> {
2846 if cp > 0xFF {
2847 return None;
2848 }
2849 let mut i = 0;
2850 while i < 256 {
2851 if EBCDIC037_TO_UNICODE[i] as u32 == cp {
2852 return Some(i as u8);
2853 }
2854 i += 1;
2855 }
2856 None
2857}
2858
2859unsafe extern "C" fn ebcdic_input_func(
2861 out: *mut c_uchar,
2862 outlen: *mut c_int,
2863 in_: *const c_uchar,
2864 inlen: *mut c_int,
2865) -> c_int {
2866 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2867 return -1;
2868 }
2869 let avail_in = *inlen as usize;
2870 let avail_out = *outlen as usize;
2871 if avail_in == 0 || avail_out == 0 {
2872 *outlen = 0;
2873 *inlen = 0;
2874 return 0;
2875 }
2876 let in_data = core::slice::from_raw_parts(in_, avail_in);
2877 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2878 let mut in_pos = 0usize;
2879 let mut out_pos = 0usize;
2880 while in_pos < avail_in {
2881 let cp = u32::from(EBCDIC037_TO_UNICODE[in_data[in_pos] as usize]);
2882 let mut buf = [0u8; 2];
2883 let ch = unsafe { char::from_u32_unchecked(cp) };
2884 let n = ch.encode_utf8(&mut buf).len();
2885 if out_pos + n > avail_out {
2886 break;
2887 }
2888 out_slice[out_pos..out_pos + n].copy_from_slice(&buf[..n]);
2889 out_pos += n;
2890 in_pos += 1;
2891 }
2892 *outlen = out_pos as c_int;
2893 *inlen = in_pos as c_int;
2894 out_pos as c_int
2895}
2896
2897unsafe extern "C" fn ebcdic_output_func(
2900 out: *mut c_uchar,
2901 outlen: *mut c_int,
2902 in_: *const c_uchar,
2903 inlen: *mut c_int,
2904) -> c_int {
2905 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2906 return -1;
2907 }
2908 let avail_in = *inlen as usize;
2909 let avail_out = *outlen as usize;
2910 if avail_in == 0 || avail_out == 0 {
2911 *outlen = 0;
2912 *inlen = 0;
2913 return 0;
2914 }
2915 let in_data = core::slice::from_raw_parts(in_, avail_in);
2916 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2917 let mut in_pos = 0usize;
2918 let mut out_pos = 0usize;
2919 while in_pos < avail_in {
2920 let (cp, consumed) = match decode_utf8_char(in_data, in_pos) {
2921 None => {
2922 *outlen = out_pos as c_int;
2923 *inlen = in_pos as c_int;
2924 return -1;
2925 }
2926 Some(v) => v,
2927 };
2928 match ebcdic037_cp_to_byte(cp) {
2929 None => {
2930 *outlen = out_pos as c_int;
2931 *inlen = in_pos as c_int;
2932 return ENC_INPUT_ERROR;
2933 }
2934 Some(byte) => {
2935 if out_pos + 1 > avail_out {
2936 break;
2937 }
2938 out_slice[out_pos] = byte;
2939 out_pos += 1;
2940 }
2941 }
2942 in_pos += consumed;
2943 }
2944 *outlen = out_pos as c_int;
2945 *inlen = in_pos as c_int;
2946 out_pos as c_int
2947}
2948
2949pub(crate) fn xmlFindCharEncodingHandler(name: *const c_char) -> *mut _xmlCharEncodingHandler {
2958 if name.is_null() {
2959 return ptr::null_mut();
2960 }
2961 find_encoding_handler(name as *const xmlChar)
2962}
2963
2964pub(crate) const fn xmlGetCharEncodingName(enc: xmlCharEncoding) -> *const c_char {
2968 match enc {
2972 xmlCharEncoding::XML_CHAR_ENCODING_UTF8 => c"UTF-8".as_ptr(),
2973 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE | xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE => {
2974 c"UTF-16".as_ptr()
2975 }
2976 xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE | xmlCharEncoding::XML_CHAR_ENCODING_UCS4BE => {
2977 c"UCS-4".as_ptr()
2978 }
2979 xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC => c"IBM037".as_ptr(),
2980 xmlCharEncoding::XML_CHAR_ENCODING_UCS2 => c"UCS-2".as_ptr(),
2981 xmlCharEncoding::XML_CHAR_ENCODING_8859_1 => c"ISO-8859-1".as_ptr(),
2982 xmlCharEncoding::XML_CHAR_ENCODING_8859_2 => c"ISO-8859-2".as_ptr(),
2983 xmlCharEncoding::XML_CHAR_ENCODING_8859_3 => c"ISO-8859-3".as_ptr(),
2984 xmlCharEncoding::XML_CHAR_ENCODING_8859_4 => c"ISO-8859-4".as_ptr(),
2985 xmlCharEncoding::XML_CHAR_ENCODING_8859_5 => c"ISO-8859-5".as_ptr(),
2986 xmlCharEncoding::XML_CHAR_ENCODING_8859_6 => c"ISO-8859-6".as_ptr(),
2987 xmlCharEncoding::XML_CHAR_ENCODING_8859_7 => c"ISO-8859-7".as_ptr(),
2988 xmlCharEncoding::XML_CHAR_ENCODING_8859_8 => c"ISO-8859-8".as_ptr(),
2989 xmlCharEncoding::XML_CHAR_ENCODING_8859_9 => c"ISO-8859-9".as_ptr(),
2990 xmlCharEncoding::XML_CHAR_ENCODING_2022_JP => c"ISO-2022-JP".as_ptr(),
2991 xmlCharEncoding::XML_CHAR_ENCODING_SHIFT_JIS => c"Shift_JIS".as_ptr(),
2992 xmlCharEncoding::XML_CHAR_ENCODING_EUC_JP => c"EUC-JP".as_ptr(),
2993 xmlCharEncoding::XML_CHAR_ENCODING_ASCII => c"US-ASCII".as_ptr(),
2995 _ => ptr::null(),
2996 }
2997}
2998
2999pub(crate) fn xmlParseCharEncoding(name: *const c_char) -> c_int {
3008 if name.is_null() {
3009 return xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int;
3010 }
3011 let bytes = unsafe { CStr::from_ptr(name).to_bytes() };
3012 encoding_from_name(bytes) as c_int
3013}
3014
3015static ENCODING_ALIASES: std::sync::OnceLock<
3023 parking_lot::RwLock<std::collections::HashMap<Vec<u8>, Vec<u8>>>,
3024> = std::sync::OnceLock::new();
3025
3026fn encoding_aliases() -> &'static parking_lot::RwLock<std::collections::HashMap<Vec<u8>, Vec<u8>>> {
3027 ENCODING_ALIASES.get_or_init(|| parking_lot::RwLock::new(std::collections::HashMap::new()))
3028}
3029
3030pub(crate) fn add_encoding_alias(name: *const c_char, alias: *const c_char) -> c_int {
3038 if name.is_null() || alias.is_null() {
3039 return -1;
3040 }
3041 let n = unsafe { CStr::from_ptr(name).to_bytes().to_vec() };
3042 let a = unsafe { CStr::from_ptr(alias).to_bytes().to_vec() };
3043 encoding_aliases().write().insert(a, n);
3044 0
3045}
3046
3047pub(crate) fn del_encoding_alias(alias: *const c_char) -> c_int {
3054 if alias.is_null() {
3055 return -1;
3056 }
3057 let a = unsafe { CStr::from_ptr(alias).to_bytes().to_vec() };
3058 if encoding_aliases().write().remove(&a).is_some() {
3059 0
3060 } else {
3061 -1
3062 }
3063}
3064
3065pub(crate) fn get_encoding_alias(alias: *const c_char) -> *const c_char {
3074 if alias.is_null() {
3075 return ptr::null();
3076 }
3077 let a = unsafe { CStr::from_ptr(alias).to_bytes().to_vec() };
3078 let guard = encoding_aliases().read();
3079 match guard.get(&a) {
3080 Some(v) => {
3081 let leaked: &'static [u8] = Box::leak(v.clone().into_boxed_slice());
3084 leaked.as_ptr() as *const c_char
3085 }
3086 None => ptr::null(),
3087 }
3088}
3089
3090pub(crate) fn cleanup_encoding_aliases() {
3092 encoding_aliases().write().clear();
3093}
3094
3095pub(crate) fn xmlCharEncInFunc(
3099 handler: *mut _xmlCharEncodingHandler,
3100 out: *mut _xmlBuffer,
3101 in_: *mut _xmlBuffer,
3102) -> c_int {
3103 char_enc_in(handler, out, in_)
3104}
3105
3106pub(crate) fn xmlCharEncOutFunc(
3110 handler: *mut _xmlCharEncodingHandler,
3111 out: *mut _xmlBuffer,
3112 in_: *mut _xmlBuffer,
3113) -> c_int {
3114 char_enc_out(handler, out, in_)
3115}
3116
3117pub(crate) fn xmlNewCharEncodingHandler(
3131 name: *const c_char,
3132 input: xmlCharEncodingInputFunc,
3133 output: xmlCharEncodingOutputFunc,
3134) -> *mut _xmlCharEncodingHandler {
3135 if name.is_null() {
3136 return ptr::null_mut();
3137 }
3138
3139 let name_raw = unsafe { crate::abi::allocator::xmlMemStrdupImpl(name) };
3140 if name_raw.is_null() {
3141 return ptr::null_mut();
3142 }
3143
3144 let handler = unsafe { xmlMallocImpl(size_of::<_xmlCharEncodingHandler>()) }
3145 as *mut _xmlCharEncodingHandler;
3146
3147 if handler.is_null() {
3148 unsafe { xmlFreeImpl(name_raw) };
3149 return ptr::null_mut();
3150 }
3151
3152 unsafe {
3153 ptr::write(
3154 handler,
3155 _xmlCharEncodingHandler {
3156 name: name_raw as *mut c_char,
3157 input: EncodingInputUnion {
3158 legacyFunc: Some(input),
3159 },
3160 output: EncodingOutputUnion {
3161 legacyFunc: Some(output),
3162 },
3163 inputCtxt: ptr::null_mut(),
3164 outputCtxt: ptr::null_mut(),
3165 ctxtDtor: None,
3166 flags: 0,
3167 },
3168 );
3169 }
3170
3171 handler
3172}
3173
3174#[allow(dead_code)]
3185pub(crate) fn xmlDelEncodingHandler(handler: *mut _xmlCharEncodingHandler) {
3186 if handler.is_null() {
3187 return;
3188 }
3189
3190 {
3192 let mut handlers = ENCODING_HANDLERS.write();
3193 handlers.retain(|&h| h.0 != handler);
3194 }
3195
3196 unsafe {
3197 if !(*handler).name.is_null() {
3198 xmlFreeImpl((*handler).name as *mut c_void);
3199 }
3200 xmlFreeImpl(handler as *mut c_void);
3201 }
3202}
3203
3204pub(crate) fn xmlInitCharEncodingHandlers() {
3206 init_encodings();
3207}
3208
3209pub(crate) fn xmlCleanupCharEncodingHandlers() {
3211 cleanup_encodings();
3212}
3213
3214pub(crate) fn xmlLookupCharEncodingHandler(enc: c_int, out: *mut *mut c_void) -> c_int {
3242 if out.is_null() {
3243 return crate::abi::types::XML_ERR_ARGUMENT;
3244 }
3245 unsafe {
3246 *out = ptr::null_mut();
3247 }
3248 if enc <= 0 || enc >= 32 {
3249 return crate::abi::types::XML_ERR_UNSUPPORTED_ENCODING;
3250 }
3251 if enc == xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int {
3253 return crate::abi::types::XML_ERR_OK;
3254 }
3255 let canonical: &[u8] = match enc {
3256 2 => b"UTF-16LE\0",
3258 3 => b"UTF-16BE\0",
3260 10 => b"ISO-8859-1\0",
3262 22 => b"US-ASCII\0",
3264 23 => b"UTF-16\0",
3266 _ => return crate::abi::types::XML_ERR_UNSUPPORTED_ENCODING,
3267 };
3268 let h = find_encoding_handler(canonical.as_ptr() as *const xmlChar);
3269 if h.is_null() {
3270 return crate::abi::types::XML_ERR_UNSUPPORTED_ENCODING;
3271 }
3272 unsafe {
3273 *out = h as *mut c_void;
3274 }
3275 crate::abi::types::XML_ERR_OK
3276}
3277
3278pub(crate) fn xmlGetCharEncodingHandler(enc: c_int) -> *mut c_void {
3280 let mut ret: *mut c_void = ptr::null_mut();
3281 let _rc = xmlLookupCharEncodingHandler(enc, &mut ret);
3282 ret
3283}
3284
3285pub(crate) fn xmlCreateCharEncodingHandler(
3300 name: *const c_char,
3301 flags: c_int,
3302 impl_: Option<xmlCharEncConvImpl>,
3303 implCtxt: *mut c_void,
3304 out: *mut *mut c_void,
3305) -> c_int {
3306 if out.is_null() {
3307 return crate::abi::types::XML_ERR_ARGUMENT;
3308 }
3309 unsafe {
3310 *out = ptr::null_mut();
3311 }
3312 if name.is_null() || flags == 0 {
3313 return crate::abi::types::XML_ERR_ARGUMENT;
3314 }
3315 let norig = unsafe { CStr::from_ptr(name).to_bytes() };
3316
3317 let mut eff: &[u8] = norig;
3319 let alias = get_encoding_alias(name);
3320 if !alias.is_null() {
3321 eff = unsafe { CStr::from_ptr(alias).to_bytes() };
3322 }
3323
3324 let enc = encoding_from_name(eff);
3325
3326 if enc == xmlCharEncoding::XML_CHAR_ENCODING_UTF8 {
3328 return crate::abi::types::XML_ERR_OK;
3329 }
3330
3331 let canonical: &[u8] = match enc {
3332 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE => b"UTF-16LE\0",
3333 xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE => b"UTF-16BE\0",
3334 xmlCharEncoding::XML_CHAR_ENCODING_8859_1 => b"ISO-8859-1\0",
3335 xmlCharEncoding::XML_CHAR_ENCODING_ASCII => b"US-ASCII\0",
3336 _ => {
3337 return find_extra_handler(norig, eff, flags, impl_, implCtxt, out);
3338 }
3339 };
3340 let h = find_encoding_handler(canonical.as_ptr() as *const xmlChar);
3341 if h.is_null() {
3342 return find_extra_handler(norig, eff, flags, impl_, implCtxt, out);
3343 }
3344 unsafe {
3345 let src = &*h;
3346 let has_in = (flags & 1) == 0 || !src.input.legacyFunc.is_none();
3347 let has_out = (flags & 2) == 0 || !src.output.legacyFunc.is_none();
3348 if !has_in || !has_out {
3349 return find_extra_handler(norig, eff, flags, impl_, implCtxt, out);
3350 }
3351 let copy =
3356 xmlMallocImpl(size_of::<_xmlCharEncodingHandler>()) as *mut _xmlCharEncodingHandler;
3357 if copy.is_null() {
3358 return crate::abi::types::XML_ERR_NO_MEMORY;
3359 }
3360 let name_copy = crate::abi::allocator::xmlMemStrdupImpl(name) as *mut c_char;
3361 if name_copy.is_null() {
3362 xmlFreeImpl(copy as *mut c_void);
3363 return crate::abi::types::XML_ERR_NO_MEMORY;
3364 }
3365 ptr::write(
3366 copy,
3367 _xmlCharEncodingHandler {
3368 name: name_copy,
3369 input: EncodingInputUnion {
3370 legacyFunc: src.input.legacyFunc,
3371 },
3372 output: EncodingOutputUnion {
3373 legacyFunc: src.output.legacyFunc,
3374 },
3375 inputCtxt: src.inputCtxt,
3376 outputCtxt: src.outputCtxt,
3377 ctxtDtor: src.ctxtDtor,
3378 flags: src.flags,
3379 },
3380 );
3381 *out = copy as *mut c_void;
3382 }
3383 crate::abi::types::XML_ERR_OK
3384}
3385
3386fn find_extra_handler(
3401 norig: &[u8],
3402 name: &[u8],
3403 flags: c_int,
3404 impl_: Option<xmlCharEncConvImpl>,
3405 implCtxt: *mut c_void,
3406 out: *mut *mut c_void,
3407) -> c_int {
3408 if let Some(f) = impl_ {
3410 let mut n = norig.to_vec();
3411 n.push(0);
3412 let rc = unsafe {
3413 f(
3414 implCtxt,
3415 n.as_ptr() as *const c_char,
3416 flags,
3417 out as *mut *mut crate::abi::structs::_xmlCharEncodingHandler,
3418 )
3419 };
3420 return rc;
3421 }
3422 let mut n = name.to_vec();
3424 n.push(0);
3425 let h = find_encoding_handler(n.as_ptr() as *const xmlChar);
3426 if !h.is_null() {
3427 unsafe {
3428 let src = &*h;
3429 let has_in = (flags & 1) == 0 || !src.input.legacyFunc.is_none();
3430 let has_out = (flags & 2) == 0 || !src.output.legacyFunc.is_none();
3431 if has_in && has_out {
3432 *out = h as *mut c_void;
3433 return crate::abi::types::XML_ERR_OK;
3434 }
3435 }
3436 }
3437 crate::abi::types::XML_ERR_UNSUPPORTED_ENCODING
3438}
3439
3440pub(crate) fn xmlOpenCharEncodingHandler(
3442 name: *const c_char,
3443 output: c_int,
3444 out: *mut *mut c_void,
3445) -> c_int {
3446 let flags: c_int = if output != 0 { 2 } else { 1 };
3448 xmlCreateCharEncodingHandler(name, flags, None, ptr::null_mut(), out)
3449}
3450
3451pub(crate) fn xmlCharEncNewCustomHandler(
3466 name: *const c_char,
3467 input: xmlCharEncConvFunc,
3468 output: xmlCharEncConvFunc,
3469 ctxtDtor: Option<xmlCharEncConvCtxtDtor>,
3470 inputCtxt: *mut c_void,
3471 outputCtxt: *mut c_void,
3472 out: *mut *mut c_void,
3473) -> c_int {
3474 if out.is_null() {
3475 return crate::abi::types::XML_ERR_ARGUMENT;
3476 }
3477 let handler = unsafe { xmlMallocImpl(size_of::<_xmlCharEncodingHandler>()) }
3478 as *mut _xmlCharEncodingHandler;
3479 if handler.is_null() {
3480 unsafe {
3481 if let Some(d) = ctxtDtor {
3482 if !inputCtxt.is_null() {
3483 d(inputCtxt);
3484 }
3485 if !outputCtxt.is_null() {
3486 d(outputCtxt);
3487 }
3488 }
3489 }
3490 return crate::abi::types::XML_ERR_NO_MEMORY;
3491 }
3492 let name_copy = if name.is_null() {
3493 ptr::null_mut()
3494 } else {
3495 let nc = unsafe { crate::abi::allocator::xmlMemStrdupImpl(name) } as *mut c_char;
3496 if nc.is_null() {
3497 unsafe { xmlFreeImpl(handler as *mut c_void) };
3498 unsafe {
3499 if let Some(d) = ctxtDtor {
3500 if !inputCtxt.is_null() {
3501 d(inputCtxt);
3502 }
3503 if !outputCtxt.is_null() {
3504 d(outputCtxt);
3505 }
3506 }
3507 }
3508 return crate::abi::types::XML_ERR_NO_MEMORY;
3509 }
3510 nc
3511 };
3512 unsafe {
3513 ptr::write(
3514 handler,
3515 _xmlCharEncodingHandler {
3516 name: name_copy,
3517 input: EncodingInputUnion { func: Some(input) },
3518 output: EncodingOutputUnion { func: Some(output) },
3519 inputCtxt,
3520 outputCtxt,
3521 ctxtDtor,
3522 flags: 0,
3523 },
3524 );
3525 *out = handler as *mut c_void;
3526 }
3527 crate::abi::types::XML_ERR_OK
3528}
3529
3530#[cfg(test)]
3535mod tests {
3536 use super::*;
3537
3538 #[test]
3541 fn test_detect_bom_utf8() {
3542 let data = [0xEF, 0xBB, 0xBF, b'<', b'?', b'x', b'm', b'l'];
3543 assert_eq!(
3544 detect_encoding_from_bom(&data),
3545 xmlCharEncoding::XML_CHAR_ENCODING_UTF8
3546 );
3547 }
3548
3549 #[test]
3550 fn test_detect_bom_utf16le() {
3551 let data = [0xFF, 0xFE, 0x00, 0x01];
3552 assert_eq!(
3553 detect_encoding_from_bom(&data),
3554 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE
3555 );
3556 }
3557
3558 #[test]
3559 fn test_detect_bom_utf16be() {
3560 let data = [0xFE, 0xFF, 0x00, 0x01];
3561 assert_eq!(
3562 detect_encoding_from_bom(&data),
3563 xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE
3564 );
3565 }
3566
3567 #[test]
3568 fn test_detect_bom_none() {
3569 let data = b"<xml>";
3570 assert_eq!(
3571 detect_encoding_from_bom(data),
3572 xmlCharEncoding::XML_CHAR_ENCODING_NONE
3573 );
3574 }
3575
3576 #[test]
3577 fn test_detect_bom_empty() {
3578 assert_eq!(
3579 detect_encoding_from_bom(b""),
3580 xmlCharEncoding::XML_CHAR_ENCODING_NONE
3581 );
3582 }
3583
3584 #[test]
3587 fn test_detect_encoding_declaration_utf8() {
3588 let data = b"<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
3589 let result = detect_encoding_from_declaration(data);
3590 assert_eq!(result, Some(b"utf-8".to_vec()));
3591 }
3592
3593 #[test]
3594 fn test_detect_encoding_declaration_iso() {
3595 let data = b"<?xml version='1.0' encoding='ISO-8859-1'?>";
3596 let result = detect_encoding_from_declaration(data);
3597 assert_eq!(result, Some(b"iso-8859-1".to_vec()));
3598 }
3599
3600 #[test]
3601 fn test_detect_encoding_declaration_none() {
3602 let data = b"<?xml version=\"1.0\"?>";
3603 let result = detect_encoding_from_declaration(data);
3604 assert!(result.is_none());
3605 }
3606
3607 #[test]
3608 fn test_detect_encoding_declaration_no_xml() {
3609 let data = b"<root>";
3610 let result = detect_encoding_from_declaration(data);
3611 assert!(result.is_none());
3612 }
3613
3614 #[test]
3615 fn test_detect_encoding_declaration_with_bom() {
3616 let mut data = vec![0xEF, 0xBB, 0xBF];
3617 data.extend_from_slice(b"<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
3618 let result = detect_encoding_from_declaration(&data);
3619 assert_eq!(result, Some(b"utf-8".to_vec()));
3620 }
3621
3622 #[test]
3625 fn test_encoding_from_name_utf8() {
3626 assert_eq!(
3627 encoding_from_name(b"UTF-8"),
3628 xmlCharEncoding::XML_CHAR_ENCODING_UTF8
3629 );
3630 assert_eq!(
3631 encoding_from_name(b"utf8"),
3632 xmlCharEncoding::XML_CHAR_ENCODING_UTF8
3633 );
3634 }
3635
3636 #[test]
3637 fn test_encoding_from_name_utf16() {
3638 assert_eq!(
3639 encoding_from_name(b"UTF-16LE"),
3640 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE
3641 );
3642 assert_eq!(
3643 encoding_from_name(b"UTF-16BE"),
3644 xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE
3645 );
3646 assert_eq!(
3647 encoding_from_name(b"utf-16"),
3648 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE
3649 );
3650 }
3651
3652 #[test]
3653 fn test_encoding_from_name_latin1() {
3654 assert_eq!(
3655 encoding_from_name(b"ISO-8859-1"),
3656 xmlCharEncoding::XML_CHAR_ENCODING_8859_1
3657 );
3658 assert_eq!(
3659 encoding_from_name(b"Latin1"),
3660 xmlCharEncoding::XML_CHAR_ENCODING_8859_1
3661 );
3662 }
3663
3664 #[test]
3665 fn test_encoding_from_name_ascii() {
3666 assert_eq!(
3667 encoding_from_name(b"ASCII"),
3668 xmlCharEncoding::XML_CHAR_ENCODING_ASCII
3669 );
3670 assert_eq!(
3671 encoding_from_name(b"US-ASCII"),
3672 xmlCharEncoding::XML_CHAR_ENCODING_ASCII
3673 );
3674 }
3675
3676 #[test]
3677 fn test_encoding_from_name_error() {
3678 assert_eq!(
3679 encoding_from_name(b"invalid-encoding"),
3680 xmlCharEncoding::XML_CHAR_ENCODING_ERROR
3681 );
3682 }
3683
3684 #[test]
3685 fn test_encoding_from_name_empty() {
3686 assert_eq!(
3687 encoding_from_name(b""),
3688 xmlCharEncoding::XML_CHAR_ENCODING_ERROR
3689 );
3690 }
3691
3692 #[test]
3695 fn test_encoding_name_utf8() {
3696 assert_eq!(
3697 encoding_name(xmlCharEncoding::XML_CHAR_ENCODING_UTF8),
3698 Some(b"UTF-8" as &[u8])
3699 );
3700 }
3701
3702 #[test]
3703 fn test_encoding_name_utf16le() {
3704 assert_eq!(
3705 encoding_name(xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE),
3706 Some(b"UTF-16LE" as &[u8])
3707 );
3708 }
3709
3710 #[test]
3711 fn test_encoding_name_none() {
3712 assert!(encoding_name(xmlCharEncoding::XML_CHAR_ENCODING_NONE).is_none());
3713 }
3714
3715 #[test]
3716 fn test_encoding_name_error() {
3717 assert!(encoding_name(xmlCharEncoding::XML_CHAR_ENCODING_ERROR).is_none());
3718 }
3719
3720 #[test]
3723 fn test_utf8_valid_ascii() {
3724 assert!(utf8_valid(b"hello world"));
3725 }
3726
3727 #[test]
3728 fn test_utf8_valid_multi_byte() {
3729 assert!(utf8_valid("héllo wörld 🌍".as_bytes()));
3730 }
3731
3732 #[test]
3733 fn test_utf8_valid_empty() {
3734 assert!(utf8_valid(b""));
3735 }
3736
3737 #[test]
3738 fn test_utf8_invalid() {
3739 assert!(!utf8_valid(&[0xFF, 0xFE, 0x00]));
3740 }
3741
3742 #[test]
3745 fn test_valid_xml_chars() {
3746 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));
3752 assert!(is_valid_xml_char(0xE000));
3753 assert!(is_valid_xml_char(0xFFFD));
3754 assert!(is_valid_xml_char(0x10000));
3755 assert!(is_valid_xml_char(0x10FFFF));
3756 }
3757
3758 #[test]
3759 fn test_invalid_xml_chars() {
3760 assert!(!is_valid_xml_char(0x00));
3761 assert!(!is_valid_xml_char(0x08));
3762 assert!(!is_valid_xml_char(0x0B));
3763 assert!(!is_valid_xml_char(0x0C));
3764 assert!(!is_valid_xml_char(0x0E));
3765 assert!(!is_valid_xml_char(0x1F));
3766 assert!(!is_valid_xml_char(0xD800)); assert!(!is_valid_xml_char(0xDFFF)); assert!(!is_valid_xml_char(0xFFFE));
3769 assert!(!is_valid_xml_char(0xFFFF));
3770 assert!(!is_valid_xml_char(0x110000));
3771 }
3772
3773 #[test]
3776 fn test_utf16le_to_utf8_ascii() {
3777 let data = [b'A', 0x00, b'B', 0x00];
3779 let result = utf16le_to_utf8(&data).unwrap();
3780 assert_eq!(result, b"AB");
3781 }
3782
3783 #[test]
3784 fn test_utf16le_to_utf8_bom() {
3785 let mut data = vec![0xFF, 0xFE]; data.extend_from_slice(&[b'A', 0x00, b'B', 0x00]);
3787 let result = utf16le_to_utf8(&data).unwrap();
3788 assert_eq!(result, b"AB");
3789 }
3790
3791 #[test]
3792 fn test_utf16le_to_utf8_bmp() {
3793 let data = [0xE9, 0x00];
3795 let result = utf16le_to_utf8(&data).unwrap();
3796 assert_eq!(result, "é".as_bytes());
3797 }
3798
3799 #[test]
3800 fn test_utf16le_to_utf8_supplementary() {
3801 let data = [0x3D, 0xD8, 0x00, 0xDE];
3803 let result = utf16le_to_utf8(&data).unwrap();
3804 assert_eq!(result, "😀".as_bytes());
3805 }
3806
3807 #[test]
3808 fn test_utf16le_to_utf8_unpaired_surrogate() {
3809 let data = [0x00, 0xD8]; assert!(utf16le_to_utf8(&data).is_err());
3811 }
3812
3813 #[test]
3814 fn test_utf16le_to_utf8_truncated() {
3815 let data = [0x00]; assert!(utf16le_to_utf8(&data).is_err());
3817 }
3818
3819 #[test]
3820 fn test_utf16le_to_utf8_empty() {
3821 let result = utf16le_to_utf8(b"").unwrap();
3822 assert!(result.is_empty());
3823 }
3824
3825 #[test]
3828 fn test_utf16be_to_utf8_ascii() {
3829 let data = [0x00, b'A', 0x00, b'B'];
3830 let result = utf16be_to_utf8(&data).unwrap();
3831 assert_eq!(result, b"AB");
3832 }
3833
3834 #[test]
3835 fn test_utf16be_to_utf8_bom() {
3836 let mut data = vec![0xFE, 0xFF]; data.extend_from_slice(&[0x00, b'A', 0x00, b'B']);
3838 let result = utf16be_to_utf8(&data).unwrap();
3839 assert_eq!(result, b"AB");
3840 }
3841
3842 #[test]
3843 fn test_utf16be_to_utf8_supplementary() {
3844 let data = [0xD8, 0x3D, 0xDE, 0x00];
3846 let result = utf16be_to_utf8(&data).unwrap();
3847 assert_eq!(result, "😀".as_bytes());
3848 }
3849
3850 #[test]
3851 fn test_utf16be_to_utf8_empty() {
3852 let result = utf16be_to_utf8(b"").unwrap();
3853 assert!(result.is_empty());
3854 }
3855
3856 #[test]
3859 fn test_utf8_to_utf16le_ascii() {
3860 let result = utf8_to_utf16le(b"AB").unwrap();
3861 assert_eq!(result, [b'A', 0x00, b'B', 0x00]);
3862 }
3863
3864 #[test]
3865 fn test_utf8_to_utf16le_bmp() {
3866 let result = utf8_to_utf16le("é".as_bytes()).unwrap();
3867 assert_eq!(result, [0xE9, 0x00]);
3868 }
3869
3870 #[test]
3871 fn test_utf8_to_utf16le_supplementary() {
3872 let result = utf8_to_utf16le("😀".as_bytes()).unwrap();
3873 assert_eq!(result, [0x3D, 0xD8, 0x00, 0xDE]);
3874 }
3875
3876 #[test]
3877 fn test_utf8_to_utf16le_invalid_utf8() {
3878 assert!(utf8_to_utf16le(&[0xFF]).is_err());
3879 }
3880
3881 #[test]
3882 fn test_utf8_to_utf16le_empty() {
3883 let result = utf8_to_utf16le(b"").unwrap();
3884 assert!(result.is_empty());
3885 }
3886
3887 #[test]
3890 fn test_latin1_to_utf8_ascii() {
3891 let result = latin1_to_utf8(b"ABC");
3892 assert_eq!(result, b"ABC");
3893 }
3894
3895 #[test]
3896 fn test_latin1_to_utf8_accented() {
3897 let result = latin1_to_utf8(&[0xE9]);
3899 assert_eq!(result, "é".as_bytes());
3900 }
3901
3902 #[test]
3903 fn test_latin1_to_utf8_all_255() {
3904 let result = latin1_to_utf8(&[0xFF]);
3905 assert_eq!(result, [0xC3, 0xBF]);
3907 }
3908
3909 #[test]
3910 fn test_latin1_to_utf8_empty() {
3911 let result = latin1_to_utf8(b"");
3912 assert!(result.is_empty());
3913 }
3914
3915 #[test]
3916 fn test_latin1_to_utf8_mixed() {
3917 let result = latin1_to_utf8(b"caf\xE9");
3918 assert_eq!(result, "café".as_bytes());
3919 }
3920
3921 #[test]
3924 fn test_utf8_to_latin1_ascii() {
3925 let result = utf8_to_latin1(b"ABC").unwrap();
3926 assert_eq!(result, b"ABC");
3927 }
3928
3929 #[test]
3930 fn test_utf8_to_latin1_accented() {
3931 let result = utf8_to_latin1("é".as_bytes()).unwrap();
3932 assert_eq!(result, [0xE9]);
3933 }
3934
3935 #[test]
3936 fn test_utf8_to_latin1_out_of_range() {
3937 assert!(utf8_to_latin1("€".as_bytes()).is_err()); }
3939
3940 #[test]
3941 fn test_utf8_to_latin1_invalid_utf8() {
3942 assert!(utf8_to_latin1(&[0xFF]).is_err());
3943 }
3944
3945 #[test]
3946 fn test_utf8_to_latin1_empty() {
3947 let result = utf8_to_latin1(b"").unwrap();
3948 assert!(result.is_empty());
3949 }
3950
3951 #[test]
3954 fn test_init_and_find_encodings() {
3955 init_encodings();
3956
3957 let utf8_name: *const xmlChar = c"UTF-8".as_ptr() as *const xmlChar;
3958 assert!(!find_encoding_handler(utf8_name).is_null());
3959
3960 let utf16le_name: *const xmlChar = c"UTF-16LE".as_ptr() as *const xmlChar;
3961 assert!(!find_encoding_handler(utf16le_name).is_null());
3962
3963 let utf16be_name: *const xmlChar = c"UTF-16BE".as_ptr() as *const xmlChar;
3964 assert!(!find_encoding_handler(utf16be_name).is_null());
3965
3966 let latin1_name: *const xmlChar = c"ISO-8859-1".as_ptr() as *const xmlChar;
3967 assert!(!find_encoding_handler(latin1_name).is_null());
3968
3969 let ascii_name: *const xmlChar = c"ASCII".as_ptr() as *const xmlChar;
3970 assert!(!find_encoding_handler(ascii_name).is_null());
3971
3972 let lower_name: *const xmlChar = c"utf-8".as_ptr() as *const xmlChar;
3974 assert!(!find_encoding_handler(lower_name).is_null());
3975 }
3976
3977 #[test]
3991 fn test_find_owned_close_keeps_registry_intact() {
3992 init_encodings();
3993 let name: *const xmlChar = c"ISO-8859-1".as_ptr() as *const xmlChar;
3994
3995 let registry = find_encoding_handler(name);
3997 assert!(!registry.is_null());
3998 let h1 = xmlFindCharEncodingHandler_owned(name);
4000 assert!(!h1.is_null());
4001 assert_ne!(h1 as *const c_void, registry as *const c_void);
4002
4003 unsafe {
4006 if !(*h1).name.is_null() {
4007 crate::abi::allocator::xmlFreeImpl((*h1).name as *mut c_void);
4008 }
4009 xmlFreeImpl(h1 as *mut c_void);
4010 }
4011
4012 let registry2 = find_encoding_handler(name);
4017 assert_eq!(registry2 as *const c_void, registry as *const c_void);
4018 assert!(!unsafe { (*registry2).name }.is_null());
4019 let reg_name = unsafe { CStr::from_ptr((*registry2).name as *const c_char) };
4020 assert_eq!(reg_name.to_bytes(), b"ISO-8859-1");
4021
4022 let h2 = xmlFindCharEncodingHandler_owned(name);
4024 assert!(!h2.is_null());
4025 assert_ne!(h2 as *const c_void, registry as *const c_void);
4026 unsafe {
4027 if !(*h2).name.is_null() {
4028 crate::abi::allocator::xmlFreeImpl((*h2).name as *mut c_void);
4029 }
4030 xmlFreeImpl(h2 as *mut c_void);
4031 }
4032 }
4033
4034 #[test]
4040 fn test_find_owned_utf8_static_and_persistent() {
4041 init_encodings();
4042 let name: *const xmlChar = c"UTF-8".as_ptr() as *const xmlChar;
4043 let u1 = xmlFindCharEncodingHandler_owned(name);
4044 assert!(!u1.is_null());
4045 let u2 = xmlFindCharEncodingHandler_owned(c"utf8".as_ptr() as *const xmlChar);
4048 assert_eq!(u1, u2);
4049 assert_eq!(
4050 unsafe { (*u1).flags } & XML_HANDLER_STATIC,
4051 XML_HANDLER_STATIC
4052 );
4053 }
4054
4055 #[test]
4056 fn test_find_encoding_handler_not_found() {
4057 let name: *const xmlChar = c"NONEXISTENT".as_ptr() as *const xmlChar;
4058 assert!(find_encoding_handler(name).is_null());
4059 }
4060
4061 #[test]
4062 fn test_find_encoding_handler_null() {
4063 assert!(find_encoding_handler(ptr::null()).is_null());
4064 }
4065
4066 #[test]
4075 fn test_add_encoding_handler() {
4076 let handler = unsafe {
4077 xmlMallocImpl(size_of::<_xmlCharEncodingHandler>()) as *mut _xmlCharEncodingHandler
4078 };
4079 assert!(!handler.is_null());
4080
4081 let name = unsafe {
4082 crate::abi::allocator::xmlMemStrdupImpl(c"TEST-ENC".as_ptr() as *const c_char)
4083 };
4084 unsafe {
4085 ptr::write(
4086 handler,
4087 _xmlCharEncodingHandler {
4088 name: name as *mut c_char,
4089 input: EncodingInputUnion { legacyFunc: None },
4090 output: EncodingOutputUnion { legacyFunc: None },
4091 inputCtxt: ptr::null_mut(),
4092 outputCtxt: ptr::null_mut(),
4093 ctxtDtor: None,
4094 flags: 0,
4095 },
4096 );
4097 }
4098
4099 assert_eq!(add_encoding_handler(handler), 0);
4100
4101 let found = find_encoding_handler(c"TEST-ENC".as_ptr() as *const xmlChar);
4102 assert_eq!(found, handler);
4103
4104 {
4106 let mut handlers = ENCODING_HANDLERS.write();
4107 handlers.retain(|&h| h.0 != handler);
4108 }
4109
4110 unsafe {
4111 xmlFreeImpl(name as *mut c_void);
4112 xmlFreeImpl(handler as *mut c_void);
4113 }
4114 }
4115
4116 #[test]
4119 fn test_utf16le_roundtrip() {
4120 let original = b"Hello, World! UTF-16LE test: \xC3\xA9\xF0\x9F\x98\x80";
4121 let utf16 = utf8_to_utf16le(original).unwrap();
4122 let back = utf16le_to_utf8(&utf16).unwrap();
4123 assert_eq!(original.to_vec(), back);
4124 }
4125
4126 #[test]
4127 fn test_utf16be_roundtrip() {
4128 let original = b"Hello, World! UTF-16BE test: \xC3\xA9\xF0\x9F\x98\x80";
4129 let utf16le = utf8_to_utf16le(original).unwrap();
4130 let mut utf16be = utf16le.clone();
4132 for chunk in utf16be.as_chunks_mut::<2>().0 {
4133 chunk.swap(0, 1);
4134 }
4135 let back = utf16be_to_utf8(&utf16be).unwrap();
4136 assert_eq!(original.to_vec(), back);
4137 }
4138
4139 #[test]
4140 fn test_latin1_roundtrip() {
4141 let original: Vec<u8> = (0x00..=0xFF).collect();
4142 let utf8 = latin1_to_utf8(&original);
4143 let back = utf8_to_latin1(&utf8).unwrap();
4144 assert_eq!(original, back);
4145 }
4146
4147 #[test]
4157 fn test_utf8_handler_identity() {
4158 let input = b"Hello, UTF-8!";
4159 let mut output = [0u8; 64];
4160 let mut outlen = output.len() as c_int;
4161 let mut inlen = input.len() as c_int;
4162
4163 let ret = unsafe {
4164 utf8_input_func(output.as_mut_ptr(), &mut outlen, input.as_ptr(), &mut inlen)
4165 };
4166
4167 assert_eq!(ret, input.len() as c_int);
4168 assert_eq!(&output[..ret as usize], input);
4169 assert_eq!(inlen, input.len() as c_int);
4170 }
4171
4172 #[test]
4180 fn test_utf16le_handler_roundtrip() {
4181 init_encodings();
4182
4183 let original = b"Hello UTF-16LE!";
4184 let mut utf16_buf = [0u8; 128];
4185 let mut outlen = utf16_buf.len() as c_int;
4186 let mut inlen = original.len() as c_int;
4187
4188 let written = unsafe {
4189 utf16le_output_func(
4190 utf16_buf.as_mut_ptr(),
4191 &mut outlen,
4192 original.as_ptr(),
4193 &mut inlen,
4194 )
4195 };
4196 assert!(written > 0);
4197
4198 let mut decoded = [0u8; 128];
4200 let mut outlen2 = decoded.len() as c_int;
4201 let mut inlen2 = written;
4202
4203 let written2 = unsafe {
4204 utf16le_input_func(
4205 decoded.as_mut_ptr(),
4206 &mut outlen2,
4207 utf16_buf.as_ptr(),
4208 &mut inlen2,
4209 )
4210 };
4211 assert_eq!(written2 as usize, original.len());
4212 assert_eq!(&decoded[..written2 as usize], original);
4213 }
4214
4215 #[test]
4225 fn test_append_to_xml_buffer() {
4226 unsafe {
4227 let content = xmlMallocImpl(64) as *mut xmlChar;
4228 assert!(!content.is_null());
4229
4230 let mut buf = _xmlBuffer {
4231 content,
4232 use_: 0,
4233 size: 64,
4234 alloc: 0,
4235 contentIO: ptr::null_mut(),
4236 };
4237
4238 append_to_xml_buffer(&mut buf, b"Hello");
4239 assert_eq!(buf.use_, 5);
4240 let slice = core::slice::from_raw_parts(buf.content, 5);
4241 assert_eq!(slice, b"Hello");
4242
4243 append_to_xml_buffer(&mut buf, b" World");
4244 assert_eq!(buf.use_, 11);
4245 let slice = core::slice::from_raw_parts(buf.content, 11);
4246 assert_eq!(slice, b"Hello World");
4247
4248 xmlFreeImpl(buf.content as *mut c_void);
4249 }
4250 }
4251
4252 #[test]
4255 fn test_xml_parse_char_encoding() {
4256 let name = c"UTF-8".as_ptr() as *const c_char;
4257 assert_eq!(
4258 xmlParseCharEncoding(name),
4259 xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int
4260 );
4261
4262 let name = c"ISO-8859-1".as_ptr() as *const c_char;
4263 assert_eq!(
4264 xmlParseCharEncoding(name),
4265 xmlCharEncoding::XML_CHAR_ENCODING_8859_1 as c_int
4266 );
4267
4268 assert_eq!(
4269 xmlParseCharEncoding(ptr::null()),
4270 xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int
4271 );
4272 }
4273
4274 #[test]
4283 fn test_xml_new_and_del_encoding_handler() {
4284 let name = c"TestEnc".as_ptr() as *const c_char;
4285 let handler = xmlNewCharEncodingHandler(
4286 name,
4287 utf8_input_func as xmlCharEncodingInputFunc,
4288 utf8_output_func as xmlCharEncodingOutputFunc,
4289 );
4290 assert!(!handler.is_null());
4291
4292 unsafe {
4293 assert!(!(*handler).name.is_null());
4294 let cstr = CStr::from_ptr((*handler).name);
4295 assert_eq!(cstr.to_bytes(), b"TestEnc");
4296 }
4297
4298 xmlDelEncodingHandler(handler);
4299 }
4300
4301 #[test]
4302 fn test_xml_init_and_cleanup() {
4303 xmlInitCharEncodingHandlers();
4304
4305 let name: *const xmlChar = c"UTF-8".as_ptr() as *const xmlChar;
4306 assert!(!find_encoding_handler(name).is_null());
4307
4308 xmlCleanupCharEncodingHandlers();
4309 }
4311
4312 fn call_func(
4316 func: unsafe extern "C" fn(*mut c_uchar, *mut c_int, *const c_uchar, *mut c_int) -> c_int,
4317 input: &[u8],
4318 ) -> (c_int, Vec<u8>, usize) {
4319 let mut out = vec![0u8; input.len() * 6 + 64];
4320 let mut outlen = out.len() as c_int;
4321 let mut inlen = input.len() as c_int;
4322 let rc = unsafe { func(out.as_mut_ptr(), &mut outlen, input.as_ptr(), &mut inlen) };
4323 out.truncate(outlen.max(0) as usize);
4324 (rc, out, inlen.max(0) as usize)
4325 }
4326
4327 #[test]
4328 fn test_shift_jis_output_roundtrip() {
4329 let (rc, out, consumed) = call_func(shift_jis_output_func, "ぁ漢ア".as_bytes());
4332 assert!(rc >= 0);
4333 assert_eq!(out, [0x82, 0x9F, 0x8A, 0xBF, 0xB1]);
4334 assert_eq!(consumed, "ぁ漢ア".len());
4335
4336 let (rc, back, _) = call_func(shift_jis_input_func, &out);
4337 assert!(rc >= 0);
4338 assert_eq!(back, "ぁ漢ア".as_bytes());
4339 }
4340
4341 #[test]
4342 fn test_shift_jis_output_unmappable_reports_input_error() {
4343 let (rc, out, consumed) = call_func(shift_jis_output_func, "A😀B".as_bytes());
4347 assert_eq!(rc, ENC_INPUT_ERROR);
4348 assert_eq!(out, b"A");
4349 assert_eq!(consumed, 1); let handler = find_encoding_handler(c"SHIFT_JIS".as_ptr() as *const xmlChar);
4354 assert!(!handler.is_null());
4355 let in_buf = crate::xml::io::buf_create(64);
4356 let src = "A\u{1F600}B".as_bytes();
4357 assert!(
4358 crate::xml::io::buf_add(in_buf, src.as_ptr() as *const xmlChar, src.len() as c_int)
4359 >= 0
4360 );
4361 let out_buf = crate::xml::io::buf_create(64);
4362 let n = char_enc_out(handler, out_buf, in_buf);
4363 assert!(n >= 0);
4364 let bytes =
4365 unsafe { core::slice::from_raw_parts((*out_buf).content, (*out_buf).use_ as usize) };
4366 assert_eq!(bytes, b"A😀B");
4367 crate::xml::io::buf_free(in_buf);
4368 crate::xml::io::buf_free(out_buf);
4369 }
4370
4371 #[test]
4372 fn test_euc_jp_output_roundtrip() {
4373 let (rc, out, consumed) = call_func(euc_jp_output_func, "ぁ漢ア".as_bytes());
4376 assert!(rc >= 0);
4377 assert_eq!(out, [0xA4, 0xA1, 0xB4, 0xC1, 0x8E, 0xB1]);
4378 assert_eq!(consumed, "ぁ漢ア".len());
4379
4380 let (rc, back, _) = call_func(euc_jp_input_func, &out);
4381 assert!(rc >= 0);
4382 assert_eq!(back, "ぁ漢ア".as_bytes());
4383 }
4384
4385 #[test]
4386 fn test_east_asian_handlers_registered_and_findable() {
4387 for name in [
4388 c"SHIFT_JIS".as_ptr(),
4389 c"Shift_JIS".as_ptr(),
4390 c"SJIS".as_ptr(),
4391 c"CP932".as_ptr(),
4392 c"EUC-JP".as_ptr(),
4393 c"euc-jp".as_ptr(),
4394 ] {
4395 assert!(
4396 !find_encoding_handler(name as *const xmlChar).is_null(),
4397 "handler not found for {name:?}"
4398 );
4399 }
4400 }
4401
4402 #[test]
4403 fn test_shift_jis_output_invalid_utf8_errors() {
4404 let (rc, out, consumed) = call_func(shift_jis_output_func, b"A\xFFB");
4405 assert_eq!(rc, -1);
4406 assert_eq!(out, b"A");
4407 assert_eq!(consumed, 1);
4408 }
4409
4410 #[test]
4413 fn test_ucs4le_output_matches_utf32le() {
4414 let (rc, out, consumed) = call_func(ucs4le_output_func, "Aあ中".as_bytes());
4416 assert!(rc >= 0);
4417 assert_eq!(out, [0x41, 0, 0, 0, 0x42, 0x30, 0, 0, 0x2D, 0x4E, 0, 0]);
4418 assert_eq!(consumed, "Aあ中".len());
4419 let (rc, back, _) = call_func(ucs4le_input_func, &out);
4420 assert!(rc >= 0);
4421 assert_eq!(back, "Aあ中".as_bytes());
4422 }
4423
4424 #[test]
4425 fn test_ucs4be_output_matches_utf32be() {
4426 let (rc, out, _) = call_func(ucs4be_output_func, "Aあ".as_bytes());
4427 assert!(rc >= 0);
4428 assert_eq!(out, [0, 0, 0, 0x41, 0, 0, 0x30, 0x42]);
4429 let (rc, back, _) = call_func(ucs4be_input_func, &out);
4430 assert!(rc >= 0);
4431 assert_eq!(back, "Aあ".as_bytes());
4432 }
4433
4434 #[test]
4435 fn test_ucs2_output_astral_is_unmappable() {
4436 let (rc, out, consumed) = call_func(ucs2_output_func, "A😀".as_bytes());
4439 assert_eq!(rc, ENC_INPUT_ERROR);
4440 assert_eq!(out, [0x41, 0]);
4441 assert_eq!(consumed, 1);
4442 }
4443
4444 #[test]
4445 fn test_ebcdic037_bijection() {
4446 let (rc, out, _) = call_func(ebcdic_output_func, b"A 0");
4448 assert!(rc >= 0);
4449 assert_eq!(out, [0xC1, 0x40, 0xF0]);
4450 let (rc, back, _) = call_func(ebcdic_input_func, &out);
4451 assert!(rc >= 0);
4452 assert_eq!(back, b"A 0");
4453 for (b, cp) in EBCDIC037_TO_UNICODE.iter().enumerate() {
4456 assert_eq!(ebcdic037_cp_to_byte(u32::from(*cp)), Some(b as u8));
4457 }
4458 assert!(ebcdic037_cp_to_byte(0x100).is_none());
4459 }
4460
4461 #[test]
4462 fn test_iso_8859_2_output_roundtrip() {
4463 let (rc, out, _) = call_func(iso_8859_2_output_func, "Aąćę".as_bytes());
4465 assert!(rc >= 0);
4466 assert_eq!(out, [0x41, 0xB1, 0xE6, 0xEA]);
4467 let (rc, back, _) = call_func(iso_8859_2_input_func, &out);
4468 assert!(rc >= 0);
4469 assert_eq!(back, "Aąćę".as_bytes());
4470 }
4471
4472 #[test]
4473 fn test_decode_whole_buffer_declared_dispatch() {
4474 let iso2 = [0x41u8, 0xB1, 0xE6, 0xEA];
4476 assert_eq!(
4477 decode_whole_buffer_declared(b"ISO-8859-2", &iso2).unwrap(),
4478 "Aąćę".as_bytes()
4479 );
4480 assert_eq!(
4482 decode_whole_buffer_declared(b"latin2", &iso2).unwrap(),
4483 "Aąćę".as_bytes()
4484 );
4485 assert!(decode_whole_buffer_declared(b"no-such-encoding", b"abc").is_err());
4487 }
4488
4489 #[test]
4490 fn test_iso_2022_jp_output_uses_escape_sequences() {
4491 let (rc, out, consumed) = call_func(iso_2022_jp_output_func, "AあB".as_bytes());
4493 assert!(rc >= 0);
4494 assert_eq!(out, b"A\x1B$B$\"\x1B(BB");
4495 assert_eq!(consumed, "AあB".len());
4496 let (rc, back, _) = call_func(iso_2022_jp_input_func, &out);
4497 assert!(rc >= 0);
4498 assert_eq!(back, "AあB".as_bytes());
4499 }
4500}