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 registered_handler_names() -> Vec<String> {
1135 init_encodings();
1136 let handlers = ENCODING_HANDLERS.read();
1137 let mut out = Vec::new();
1138 for &handler in handlers.iter() {
1139 let ptr = handler.0;
1140 if ptr.is_null() {
1141 continue;
1142 }
1143 let name = unsafe {
1146 if (*ptr).name.is_null() {
1147 continue;
1148 }
1149 CStr::from_ptr((*ptr).name).to_string_lossy().into_owned()
1150 };
1151 out.push(name);
1152 }
1153 out.sort();
1154 out.dedup();
1155 out
1156}
1157
1158pub(crate) fn find_encoding_handler(name: *const xmlChar) -> *mut _xmlCharEncodingHandler {
1159 if name.is_null() {
1160 return ptr::null_mut();
1161 }
1162
1163 init_encodings();
1167
1168 let name_str = unsafe {
1169 match CStr::from_ptr(name as *const c_char).to_bytes() {
1170 b"" => return ptr::null_mut(),
1171 s => s,
1172 }
1173 };
1174
1175 let handlers = ENCODING_HANDLERS.read();
1176 for &handler in handlers.iter() {
1177 let ptr = handler.0;
1178 if ptr.is_null() {
1179 continue;
1180 }
1181 let h_name = unsafe {
1182 if (*ptr).name.is_null() {
1183 continue;
1184 }
1185 CStr::from_ptr((*ptr).name).to_bytes()
1186 };
1187
1188 if name_str.eq_ignore_ascii_case(h_name) {
1189 return ptr;
1190 }
1191 }
1192 drop(handlers);
1193
1194 if let Some(canon) = encoding_name(encoding_from_name(name_str)) {
1200 if let Ok(canon_c) = std::ffi::CString::new(canon) {
1201 let handlers = ENCODING_HANDLERS.read();
1202 for &handler in handlers.iter() {
1203 let ptr = handler.0;
1204 if ptr.is_null() {
1205 continue;
1206 }
1207 let h_name = unsafe {
1208 if (*ptr).name.is_null() {
1209 continue;
1210 }
1211 CStr::from_ptr((*ptr).name).to_bytes()
1212 };
1213 if canon.eq_ignore_ascii_case(h_name) {
1214 return ptr;
1215 }
1216 }
1217 }
1218 }
1219
1220 ptr::null_mut()
1221}
1222
1223pub(crate) fn clone_encoding_handler_for_find(
1241 src: *mut _xmlCharEncodingHandler,
1242) -> *mut _xmlCharEncodingHandler {
1243 if src.is_null() {
1244 return ptr::null_mut();
1245 }
1246 let name_raw = unsafe {
1247 let nm = (*src).name;
1248 if nm.is_null() {
1249 ptr::null_mut()
1250 } else {
1251 crate::abi::allocator::xmlMemStrdupImpl(nm)
1252 }
1253 };
1254 let handler = unsafe { xmlMallocImpl(size_of::<_xmlCharEncodingHandler>()) }
1255 as *mut _xmlCharEncodingHandler;
1256 if handler.is_null() {
1257 if !name_raw.is_null() {
1258 unsafe { crate::abi::allocator::xmlFreeImpl(name_raw) };
1259 }
1260 return ptr::null_mut();
1261 }
1262 unsafe {
1263 ptr::write(
1264 handler,
1265 _xmlCharEncodingHandler {
1266 name: name_raw as *mut c_char,
1267 input: ptr::read(&(*src).input),
1268 output: ptr::read(&(*src).output),
1269 inputCtxt: (*src).inputCtxt,
1270 outputCtxt: (*src).outputCtxt,
1271 ctxtDtor: (*src).ctxtDtor,
1272 flags: (*src).flags,
1273 },
1274 );
1275 }
1276 handler
1277}
1278
1279pub(crate) const XML_HANDLER_STATIC: c_int = 0x01;
1283
1284pub(crate) fn xmlFindCharEncodingHandler_owned(
1301 name: *const xmlChar,
1302) -> *mut _xmlCharEncodingHandler {
1303 if name.is_null() {
1304 return ptr::null_mut();
1305 }
1306 let name_bytes = unsafe {
1307 let len = libc::strlen(name as *const c_char);
1308 core::slice::from_raw_parts(name as *const u8, len)
1309 };
1310
1311 if encoding_from_name(name_bytes) == xmlCharEncoding::XML_CHAR_ENCODING_UTF8 {
1313 let utf8 = find_encoding_handler(c"UTF-8".as_ptr() as *const xmlChar);
1314 if utf8.is_null() {
1315 return ptr::null_mut();
1316 }
1317 unsafe {
1319 (*utf8).flags |= XML_HANDLER_STATIC;
1320 }
1321 return utf8;
1322 }
1323
1324 let mut entry = find_encoding_handler(name as *const xmlChar);
1328 if entry.is_null() {
1329 if let Some(canon) = encoding_name(encoding_from_name(name_bytes)) {
1330 entry = find_encoding_handler(canon.as_ptr() as *const xmlChar);
1331 }
1332 }
1333 clone_encoding_handler_for_find(entry)
1336}
1337
1338pub(crate) fn add_encoding_handler(handler: *mut _xmlCharEncodingHandler) -> c_int {
1342 if handler.is_null() {
1343 return -1;
1344 }
1345
1346 let mut handlers = ENCODING_HANDLERS.write();
1347 handlers.push(HandlerPtr(handler));
1348 0
1349}
1350
1351#[allow(dead_code)]
1367pub(crate) fn char_enc_in_func(
1368 handler: *mut _xmlCharEncodingHandler,
1369 out: &mut [u8],
1370 in_data: &[u8],
1371) -> c_int {
1372 if handler.is_null() {
1373 return -1;
1374 }
1375
1376 let h = unsafe { &*handler };
1377 let input_func = unsafe { h.input.legacyFunc };
1378 let input_func = match input_func {
1379 Some(f) => f,
1380 None => return -1,
1381 };
1382
1383 let mut outlen = out.len() as c_int;
1384 let mut inlen = in_data.len() as c_int;
1385
1386 unsafe { input_func(out.as_mut_ptr(), &mut outlen, in_data.as_ptr(), &mut inlen) }
1387}
1388
1389#[allow(dead_code)]
1401pub(crate) fn char_enc_out_func(
1402 handler: *mut _xmlCharEncodingHandler,
1403 out: &mut [u8],
1404 in_data: &[u8],
1405) -> c_int {
1406 if handler.is_null() {
1407 return -1;
1408 }
1409
1410 let h = unsafe { &*handler };
1411 let output_func = unsafe { h.output.legacyFunc };
1412 let output_func = match output_func {
1413 Some(f) => f,
1414 None => return -1,
1415 };
1416
1417 let mut outlen = out.len() as c_int;
1418 let mut inlen = in_data.len() as c_int;
1419
1420 unsafe { output_func(out.as_mut_ptr(), &mut outlen, in_data.as_ptr(), &mut inlen) }
1421}
1422
1423pub(crate) fn char_enc_in(
1439 handler: *mut _xmlCharEncodingHandler,
1440 out: *mut _xmlBuffer,
1441 in_: *mut _xmlBuffer,
1442) -> c_int {
1443 if handler.is_null() || out.is_null() || in_.is_null() {
1444 return -1;
1445 }
1446
1447 let h = unsafe { &*handler };
1448 let input_func = unsafe { h.input.legacyFunc };
1449 let input_func = match input_func {
1450 Some(f) => f,
1451 None => return -1,
1452 };
1453
1454 let in_buf = unsafe { &*in_ };
1455 let out_buf = unsafe { &mut *out };
1456
1457 if in_buf.content.is_null() || in_buf.use_ == 0 {
1458 return 0;
1459 }
1460
1461 let in_data = unsafe { core::slice::from_raw_parts(in_buf.content, in_buf.use_ as usize) };
1462
1463 let out_capacity = (in_buf.use_ as usize).saturating_mul(3).max(256);
1465 let mut out_vec = vec![0u8; out_capacity];
1466 let mut out_len = out_capacity as c_int;
1467 let mut in_len = in_buf.use_ as c_int;
1468
1469 let ret = unsafe {
1470 input_func(
1471 out_vec.as_mut_ptr(),
1472 &mut out_len,
1473 in_data.as_ptr(),
1474 &mut in_len,
1475 )
1476 };
1477
1478 if ret < 0 {
1479 return -1;
1480 }
1481
1482 let written = ret as usize;
1483
1484 append_to_xml_buffer(out_buf, &out_vec[..written]);
1486
1487 written as c_int
1488}
1489
1490pub(crate) fn char_enc_out(
1506 handler: *mut _xmlCharEncodingHandler,
1507 out: *mut _xmlBuffer,
1508 in_: *mut _xmlBuffer,
1509) -> c_int {
1510 if handler.is_null() || out.is_null() || in_.is_null() {
1511 return -1;
1512 }
1513
1514 let h = unsafe { &*handler };
1515 let output_func = unsafe { h.output.legacyFunc };
1516 let output_func = match output_func {
1517 Some(f) => f,
1518 None => return -1,
1519 };
1520
1521 let in_buf = unsafe { &*in_ };
1522 let out_buf = unsafe { &mut *out };
1523
1524 if in_buf.content.is_null() || in_buf.use_ == 0 {
1525 return 0;
1526 }
1527
1528 let mut in_data = unsafe { core::slice::from_raw_parts(in_buf.content, in_buf.use_ as usize) };
1529
1530 const ENC_INPUT_ERROR: c_int = -2;
1539 let mut total_written: usize = 0;
1540 loop {
1541 let out_capacity = (in_data.len().saturating_mul(5)).max(64) + 16;
1546 let mut out_vec = vec![0u8; out_capacity];
1547 let mut out_len = out_capacity as c_int;
1548 let mut in_len = in_data.len() as c_int;
1549 let ret = unsafe {
1550 output_func(
1551 out_vec.as_mut_ptr(),
1552 &mut out_len,
1553 in_data.as_ptr(),
1554 &mut in_len,
1555 )
1556 };
1557 let written = out_len.max(0) as usize;
1558 if written > 0 {
1559 append_to_xml_buffer(out_buf, &out_vec[..written]);
1560 total_written += written;
1561 }
1562 let consumed = in_len.max(0) as usize;
1563 if ret == ENC_INPUT_ERROR && consumed < in_data.len() {
1564 let mut clen: c_int = 4;
1567 let cp = unsafe {
1568 crate::abi::exports_misc::xmlGetUTF8Char(in_data[consumed..].as_ptr(), &mut clen)
1569 };
1570 if cp <= 0 || clen <= 0 || (consumed + clen as usize) > in_data.len() {
1571 return -1;
1572 }
1573 let ref_str = format!("&#{};", cp);
1574 append_to_xml_buffer(out_buf, ref_str.as_bytes());
1575 total_written += ref_str.len();
1576 in_data = &in_data[consumed + clen as usize..];
1577 if in_data.is_empty() {
1578 break;
1579 }
1580 continue;
1581 }
1582 if ret < 0 {
1583 return -1;
1584 }
1585 break;
1586 }
1587
1588 total_written as c_int
1589}
1590
1591pub(crate) fn decode_whole_buffer_declared(name: &[u8], data: &[u8]) -> Result<Vec<u8>, ()> {
1604 if data.is_empty() {
1605 return Ok(Vec::new());
1606 }
1607 let Ok(cname) = std::ffi::CString::new(name) else {
1608 return Err(());
1609 };
1610 let mut handler = find_encoding_handler(cname.as_ptr() as *const xmlChar);
1611 if handler.is_null() {
1612 if let Some(canon) = encoding_name(encoding_from_name(name)) {
1616 if let Ok(canon_c) = std::ffi::CString::new(canon) {
1617 handler = find_encoding_handler(canon_c.as_ptr() as *const xmlChar);
1618 }
1619 }
1620 }
1621 if handler.is_null() {
1622 return Err(());
1623 }
1624 decode_bytes_with_handler(handler, data)
1625}
1626
1627pub(crate) fn decode_bytes_with_handler(
1633 handler: *mut _xmlCharEncodingHandler,
1634 data: &[u8],
1635) -> Result<Vec<u8>, ()> {
1636 if handler.is_null() || data.is_empty() {
1637 return Ok(Vec::new());
1638 }
1639 let input_func = unsafe { (*handler).input.legacyFunc };
1640 let Some(input_func) = input_func else {
1641 return Err(());
1642 };
1643 let mut out: Vec<u8> = vec![0u8; data.len().saturating_mul(3) + 16];
1644 let mut in_pos: usize = 0;
1645 let mut written_total: usize = 0;
1646 loop {
1647 let mut out_len = (out.len() - written_total) as c_int;
1648 let mut in_len = (data.len() - in_pos) as c_int;
1649 let ret = unsafe {
1653 input_func(
1654 out[written_total..].as_mut_ptr(),
1655 &mut out_len,
1656 data[in_pos..].as_ptr(),
1657 &mut in_len,
1658 )
1659 };
1660 let written = out_len.max(0) as usize;
1661 let consumed = in_len.max(0) as usize;
1662 written_total += written;
1663 in_pos += consumed;
1664 if ret < 0 {
1665 return Err(());
1666 }
1667 if in_pos >= data.len() {
1668 break;
1669 }
1670 if written == 0 {
1671 return Err(());
1673 }
1674 out.resize(out.len().saturating_mul(2).max(written_total + 64), 0);
1675 }
1676 out.truncate(written_total);
1677 Ok(out)
1678}
1679
1680fn append_to_xml_buffer(buf: &mut _xmlBuffer, data: &[u8]) {
1688 if data.is_empty() {
1689 return;
1690 }
1691
1692 let new_use = (buf.use_ as usize).saturating_add(data.len());
1693 if new_use > buf.size as usize {
1694 let new_size = (buf.size as usize).saturating_mul(2).max(new_use).max(256);
1696 let new_content =
1697 unsafe { xmlReallocImpl(buf.content as *mut c_void, new_size) as *mut xmlChar };
1698 if new_content.is_null() {
1699 return; }
1701 buf.content = new_content;
1702 buf.contentIO = new_content;
1708 buf.size = new_size as c_uint;
1709 }
1710
1711 unsafe {
1712 ptr::copy_nonoverlapping(
1713 data.as_ptr(),
1714 buf.content.add(buf.use_ as usize),
1715 data.len(),
1716 );
1717 }
1718 buf.use_ = new_use as c_uint;
1719}
1720
1721unsafe extern "C" fn utf8_input_func(
1731 out: *mut c_uchar,
1732 outlen: *mut c_int,
1733 in_: *const c_uchar,
1734 inlen: *mut c_int,
1735) -> c_int {
1736 let avail_out = *outlen as usize;
1737 let avail_in = *inlen as usize;
1738 let to_copy = avail_out.min(avail_in);
1739
1740 if to_copy > 0 {
1741 ptr::copy_nonoverlapping(in_, out, to_copy);
1742 }
1743
1744 *outlen = to_copy as c_int;
1745 *inlen = to_copy as c_int;
1746 to_copy as c_int
1747}
1748
1749unsafe extern "C" fn utf8_output_func(
1751 out: *mut c_uchar,
1752 outlen: *mut c_int,
1753 in_: *const c_uchar,
1754 inlen: *mut c_int,
1755) -> c_int {
1756 utf8_input_func(out, outlen, in_, inlen)
1757}
1758
1759unsafe extern "C" fn utf16le_input_func(
1763 out: *mut c_uchar,
1764 outlen: *mut c_int,
1765 in_: *const c_uchar,
1766 inlen: *mut c_int,
1767) -> c_int {
1768 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
1769 return -1;
1770 }
1771
1772 let avail_in = *inlen as usize;
1773 let avail_out = *outlen as usize;
1774
1775 if avail_in == 0 || avail_out == 0 {
1776 *outlen = 0;
1777 *inlen = 0;
1778 return 0;
1779 }
1780
1781 let in_data = core::slice::from_raw_parts(in_, avail_in);
1782 let _out_slice = core::slice::from_raw_parts_mut(out, avail_out);
1783
1784 let result = match utf16le_to_utf8(in_data) {
1786 Ok(v) => v,
1787 Err(()) => return -1,
1788 };
1789
1790 let written = result.len().min(avail_out);
1791 if written > 0 {
1792 ptr::copy_nonoverlapping(result.as_ptr(), out, written);
1793 }
1794
1795 *outlen = written as c_int;
1796 *inlen = avail_in as c_int; written as c_int
1798}
1799
1800unsafe extern "C" fn utf16le_output_func(
1802 out: *mut c_uchar,
1803 outlen: *mut c_int,
1804 in_: *const c_uchar,
1805 inlen: *mut c_int,
1806) -> c_int {
1807 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
1808 return -1;
1809 }
1810
1811 let avail_in = *inlen as usize;
1812 let avail_out = *outlen as usize;
1813
1814 if avail_in == 0 || avail_out == 0 {
1815 *outlen = 0;
1816 *inlen = 0;
1817 return 0;
1818 }
1819
1820 let in_data = core::slice::from_raw_parts(in_, avail_in);
1821 let _out_slice = core::slice::from_raw_parts_mut(out, avail_out);
1822
1823 let result = match utf8_to_utf16le(in_data) {
1824 Ok(v) => v,
1825 Err(()) => return -1,
1826 };
1827
1828 let written = result.len().min(avail_out);
1829 if written > 0 {
1830 ptr::copy_nonoverlapping(result.as_ptr(), out, written);
1831 }
1832
1833 *outlen = written as c_int;
1834 *inlen = avail_in as c_int;
1835 written as c_int
1836}
1837
1838unsafe extern "C" fn utf16be_input_func(
1842 out: *mut c_uchar,
1843 outlen: *mut c_int,
1844 in_: *const c_uchar,
1845 inlen: *mut c_int,
1846) -> c_int {
1847 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
1848 return -1;
1849 }
1850
1851 let avail_in = *inlen as usize;
1852 let avail_out = *outlen as usize;
1853
1854 if avail_in == 0 || avail_out == 0 {
1855 *outlen = 0;
1856 *inlen = 0;
1857 return 0;
1858 }
1859
1860 let in_data = core::slice::from_raw_parts(in_, avail_in);
1861 let _out_slice = core::slice::from_raw_parts_mut(out, avail_out);
1862
1863 let result = match utf16be_to_utf8(in_data) {
1864 Ok(v) => v,
1865 Err(()) => return -1,
1866 };
1867
1868 let written = result.len().min(avail_out);
1869 if written > 0 {
1870 ptr::copy_nonoverlapping(result.as_ptr(), out, written);
1871 }
1872
1873 *outlen = written as c_int;
1874 *inlen = avail_in as c_int;
1875 written as c_int
1876}
1877
1878unsafe extern "C" fn utf16be_output_func(
1880 out: *mut c_uchar,
1881 outlen: *mut c_int,
1882 in_: *const c_uchar,
1883 inlen: *mut c_int,
1884) -> c_int {
1885 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
1886 return -1;
1887 }
1888
1889 let avail_in = *inlen as usize;
1890 let avail_out = *outlen as usize;
1891
1892 if avail_in == 0 || avail_out == 0 {
1893 *outlen = 0;
1894 *inlen = 0;
1895 return 0;
1896 }
1897
1898 let in_data = core::slice::from_raw_parts(in_, avail_in);
1899
1900 let le_result = match utf8_to_utf16le(in_data) {
1902 Ok(v) => v,
1903 Err(()) => return -1,
1904 };
1905
1906 let mut result = le_result;
1908 for chunk in result.as_chunks_mut::<2>().0 {
1909 chunk.swap(0, 1);
1910 }
1911
1912 let written = result.len().min(avail_out);
1913 if written > 0 {
1914 ptr::copy_nonoverlapping(result.as_ptr(), out, written);
1915 }
1916
1917 *outlen = written as c_int;
1918 *inlen = avail_in as c_int;
1919 written as c_int
1920}
1921
1922unsafe extern "C" fn latin1_input_func(
1926 out: *mut c_uchar,
1927 outlen: *mut c_int,
1928 in_: *const c_uchar,
1929 inlen: *mut c_int,
1930) -> c_int {
1931 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
1932 return -1;
1933 }
1934
1935 let avail_in = *inlen as usize;
1936 let avail_out = *outlen as usize;
1937
1938 if avail_in == 0 || avail_out == 0 {
1939 *outlen = 0;
1940 *inlen = 0;
1941 return 0;
1942 }
1943
1944 let in_data = core::slice::from_raw_parts(in_, avail_in);
1945 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
1946
1947 let mut in_pos = 0;
1948 let mut out_pos = 0;
1949
1950 while in_pos < avail_in && out_pos < avail_out {
1951 let byte = in_data[in_pos];
1952 in_pos += 1;
1953
1954 if byte < 0x80 {
1955 if out_pos < avail_out {
1957 out_slice[out_pos] = byte;
1958 out_pos += 1;
1959 } else {
1960 break;
1961 }
1962 } else {
1963 if out_pos + 1 < avail_out {
1966 out_slice[out_pos] = 0xC2 | (byte >> 6);
1967 out_slice[out_pos + 1] = 0x80 | (byte & 0x3F);
1968 out_pos += 2;
1969 } else {
1970 break;
1971 }
1972 }
1973 }
1974
1975 *outlen = out_pos as c_int;
1976 *inlen = in_pos as c_int;
1977 out_pos as c_int
1978}
1979
1980unsafe extern "C" fn latin1_output_func(
1982 out: *mut c_uchar,
1983 outlen: *mut c_int,
1984 in_: *const c_uchar,
1985 inlen: *mut c_int,
1986) -> c_int {
1987 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
1988 return -1;
1989 }
1990
1991 let avail_in = *inlen as usize;
1992 let avail_out = *outlen as usize;
1993
1994 if avail_in == 0 || avail_out == 0 {
1995 *outlen = 0;
1996 *inlen = 0;
1997 return 0;
1998 }
1999
2000 let in_data = core::slice::from_raw_parts(in_, avail_in);
2001 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2002
2003 let mut in_pos = 0;
2004 let mut out_pos = 0;
2005
2006 while in_pos < avail_in && out_pos < avail_out {
2007 let byte = in_data[in_pos];
2008 in_pos += 1;
2009
2010 if byte < 0x80 {
2011 out_slice[out_pos] = byte;
2013 out_pos += 1;
2014 } else if (0xC2..=0xC3).contains(&byte) {
2015 if in_pos < avail_in {
2017 let second = in_data[in_pos];
2018 in_pos += 1;
2019 if second & 0xC0 != 0x80 {
2020 return -1; }
2022 let cp = ((byte as u32 & 0x1F) << 6) | (second as u32 & 0x3F);
2023 if cp > 0xFF {
2024 return -1; }
2026 out_slice[out_pos] = cp as u8;
2027 out_pos += 1;
2028 } else {
2029 return -1; }
2031 } else if (0x80..=0xBF).contains(&byte) {
2032 return -1;
2034 } else {
2035 return -1;
2038 }
2039 }
2040
2041 *outlen = out_pos as c_int;
2042 *inlen = in_pos as c_int;
2043 out_pos as c_int
2044}
2045
2046const CP1252_C1: [u16; 32] = [
2057 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, ];
2062
2063#[allow(dead_code)]
2066pub(crate) const fn cp1252_byte_to_cp(byte: u8) -> Option<u32> {
2067 match byte {
2068 0x00..=0x7F => Some(byte as u32),
2069 0x80..=0x9F => {
2070 let cp = CP1252_C1[(byte - 0x80) as usize];
2071 if cp == 0xFFFF {
2072 None
2073 } else {
2074 Some(cp as u32)
2075 }
2076 }
2077 _ => Some(byte as u32), }
2079}
2080
2081#[allow(dead_code)]
2084pub(crate) const fn cp_to_cp1252_byte(cp: u32) -> Option<u8> {
2085 if cp < 0x80 || (cp >= 0xA0 && cp <= 0xFF) {
2086 Some(cp as u8)
2087 } else if cp >= 0x80 && cp <= 0x9F {
2088 let mut i = 0;
2091 while i < 32 {
2092 if CP1252_C1[i] == cp as u16 {
2093 return Some(0x80 + i as u8);
2094 }
2095 i += 1;
2096 }
2097 None
2098 } else {
2099 None
2100 }
2101}
2102
2103fn decode_utf8_char(data: &[u8], in_pos: usize) -> Option<(u32, usize)> {
2106 let b0 = *data.get(in_pos)?;
2107 if b0 < 0x80 {
2108 return Some((u32::from(b0), 1));
2109 }
2110 let (len, cp0) = match b0 {
2111 0xC2..=0xDF => (2, u32::from(b0 & 0x1F)),
2112 0xE0..=0xEF => (3, u32::from(b0 & 0x0F)),
2113 0xF0..=0xF4 => (4, u32::from(b0 & 0x07)),
2114 _ => return None,
2115 };
2116 if in_pos + len > data.len() {
2117 return None;
2118 }
2119 let mut cp = cp0;
2120 for k in 1..len {
2121 let b = data[in_pos + k];
2122 if b & 0xC0 != 0x80 {
2123 return None;
2124 }
2125 cp = (cp << 6) | u32::from(b & 0x3F);
2126 }
2127 Some((cp, len))
2128}
2129
2130pub(crate) fn cp1252_to_utf8(data: &[u8]) -> Result<Vec<u8>, ()> {
2135 let mut result = Vec::with_capacity(data.len() * 2);
2136 for &byte in data {
2137 let cp = match cp1252_byte_to_cp(byte) {
2138 None => return Err(()),
2139 Some(cp) => cp,
2140 };
2141 let mut buf = [0u8; 4];
2142 let n = encode_codepoint_to_utf8(cp, &mut buf);
2143 result.extend_from_slice(&buf[..n]);
2144 }
2145 Ok(result)
2146}
2147
2148#[allow(dead_code)]
2152pub(crate) fn utf8_to_cp1252(data: &[u8]) -> Result<Vec<u8>, ()> {
2153 let mut result = Vec::with_capacity(data.len());
2154 let mut pos = 0;
2155 while pos < data.len() {
2156 let (cp, consumed) = match decode_utf8_char(data, pos) {
2157 None => return Err(()),
2158 Some(v) => v,
2159 };
2160 let byte = match cp_to_cp1252_byte(cp) {
2161 None => return Err(()),
2162 Some(b) => b,
2163 };
2164 result.push(byte);
2165 pos += consumed;
2166 }
2167 Ok(result)
2168}
2169
2170unsafe extern "C" fn cp1252_input_func(
2172 out: *mut c_uchar,
2173 outlen: *mut c_int,
2174 in_: *const c_uchar,
2175 inlen: *mut c_int,
2176) -> c_int {
2177 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2178 return -1;
2179 }
2180
2181 let avail_in = *inlen as usize;
2182 let avail_out = *outlen as usize;
2183
2184 if avail_in == 0 || avail_out == 0 {
2185 *outlen = 0;
2186 *inlen = 0;
2187 return 0;
2188 }
2189
2190 let in_data = core::slice::from_raw_parts(in_, avail_in);
2191 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2192
2193 let mut in_pos = 0;
2194 let mut out_pos = 0;
2195
2196 while in_pos < avail_in && out_pos < avail_out {
2197 let byte = in_data[in_pos];
2198 let cp = match cp1252_byte_to_cp(byte) {
2199 None => {
2201 *outlen = out_pos as c_int;
2202 *inlen = in_pos as c_int;
2203 return -1;
2204 }
2205 Some(cp) => cp,
2206 };
2207 let mut buf = [0u8; 4];
2208 let n = encode_codepoint_to_utf8(cp, &mut buf);
2209 if out_pos + n > avail_out {
2210 break;
2211 }
2212 out_slice[out_pos..out_pos + n].copy_from_slice(&buf[..n]);
2213 out_pos += n;
2214 in_pos += 1;
2215 }
2216
2217 *outlen = out_pos as c_int;
2218 *inlen = in_pos as c_int;
2219 out_pos as c_int
2220}
2221
2222unsafe extern "C" fn cp1252_output_func(
2224 out: *mut c_uchar,
2225 outlen: *mut c_int,
2226 in_: *const c_uchar,
2227 inlen: *mut c_int,
2228) -> c_int {
2229 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2230 return -1;
2231 }
2232
2233 let avail_in = *inlen as usize;
2234 let avail_out = *outlen as usize;
2235
2236 if avail_in == 0 || avail_out == 0 {
2237 *outlen = 0;
2238 *inlen = 0;
2239 return 0;
2240 }
2241
2242 let in_data = core::slice::from_raw_parts(in_, avail_in);
2243 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2244
2245 let mut in_pos = 0;
2246 let mut out_pos = 0;
2247
2248 while in_pos < avail_in && out_pos < avail_out {
2249 let (cp, consumed) = match decode_utf8_char(in_data, in_pos) {
2250 None => {
2251 *outlen = out_pos as c_int;
2252 *inlen = in_pos as c_int;
2253 return -1;
2254 }
2255 Some(v) => v,
2256 };
2257 let byte = match cp_to_cp1252_byte(cp) {
2258 None => {
2259 *outlen = out_pos as c_int;
2261 *inlen = in_pos as c_int;
2262 return -1;
2263 }
2264 Some(b) => b,
2265 };
2266 out_slice[out_pos] = byte;
2267 out_pos += 1;
2268 in_pos += consumed;
2269 }
2270
2271 *outlen = out_pos as c_int;
2272 *inlen = in_pos as c_int;
2273 out_pos as c_int
2274}
2275
2276unsafe extern "C" fn ascii_input_func(
2287 out: *mut c_uchar,
2288 outlen: *mut c_int,
2289 in_: *const c_uchar,
2290 inlen: *mut c_int,
2291) -> c_int {
2292 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2293 return -1;
2294 }
2295
2296 let avail_in = *inlen as usize;
2297 let avail_out = *outlen as usize;
2298
2299 if avail_in == 0 || avail_out == 0 {
2300 *outlen = 0;
2301 *inlen = 0;
2302 return 0;
2303 }
2304
2305 let in_data = core::slice::from_raw_parts(in_, avail_in);
2306 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2307
2308 let mut pos = 0;
2309 while pos < avail_in && pos < avail_out {
2310 let byte = in_data[pos];
2311 if byte > 0x7F {
2312 *outlen = pos as c_int;
2315 *inlen = pos as c_int;
2316 return -2;
2317 }
2318 out_slice[pos] = byte;
2319 pos += 1;
2320 }
2321
2322 *outlen = pos as c_int;
2323 *inlen = pos as c_int;
2324 pos as c_int
2325}
2326
2327unsafe extern "C" fn ascii_output_func(
2329 out: *mut c_uchar,
2330 outlen: *mut c_int,
2331 in_: *const c_uchar,
2332 inlen: *mut c_int,
2333) -> c_int {
2334 ascii_input_func(out, outlen, in_, inlen)
2336}
2337
2338const ENC_INPUT_ERROR: c_int = -2;
2345
2346unsafe fn enc_rs_output(
2357 target: &'static encoding_rs::Encoding,
2358 out: *mut c_uchar,
2359 outlen: *mut c_int,
2360 in_: *const c_uchar,
2361 inlen: *mut c_int,
2362) -> c_int {
2363 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2364 return -1;
2365 }
2366 let avail_in = *inlen as usize;
2367 let avail_out = *outlen as usize;
2368
2369 if avail_in == 0 || avail_out == 0 {
2370 *outlen = 0;
2371 *inlen = 0;
2372 return 0;
2373 }
2374
2375 let in_data = core::slice::from_raw_parts(in_, avail_in);
2376 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2377
2378 let (s, error_at) = match core::str::from_utf8(in_data) {
2383 Ok(s) => (s, None),
2384 Err(e) => {
2385 let valid = e.valid_up_to();
2386 if valid == 0 {
2387 *outlen = 0;
2388 *inlen = 0;
2389 return -1;
2390 }
2391 (
2394 unsafe { core::str::from_utf8_unchecked(&in_data[..valid]) },
2395 Some(valid),
2396 )
2397 }
2398 };
2399
2400 let mut encoder = target.new_encoder();
2401 let mut in_pos: usize = 0;
2402 let mut out_pos: usize = 0;
2403 while in_pos < s.len() && out_pos < avail_out {
2404 let dst = &mut out_slice[out_pos..];
2405 let (res, read, written) =
2406 encoder.encode_from_utf8_without_replacement(&s[in_pos..], dst, true);
2407 out_pos += written;
2408 in_pos += read;
2409 match res {
2410 encoding_rs::EncoderResult::InputEmpty => break,
2411 encoding_rs::EncoderResult::OutputFull => {
2412 break;
2416 }
2417 encoding_rs::EncoderResult::Unmappable(c) => {
2418 *outlen = out_pos as c_int;
2424 *inlen = (in_pos - c.len_utf8()) as c_int;
2425 return ENC_INPUT_ERROR;
2426 }
2427 }
2428 }
2429
2430 if let Some(err) = error_at {
2431 if in_pos == s.len() {
2432 *outlen = out_pos as c_int;
2436 *inlen = err as c_int;
2437 return -1;
2438 }
2439 }
2440 *outlen = out_pos as c_int;
2441 *inlen = in_pos as c_int;
2442 out_pos as c_int
2443}
2444
2445unsafe fn enc_rs_input(
2451 source: &'static encoding_rs::Encoding,
2452 out: *mut c_uchar,
2453 outlen: *mut c_int,
2454 in_: *const c_uchar,
2455 inlen: *mut c_int,
2456) -> c_int {
2457 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2458 return -1;
2459 }
2460 let avail_in = *inlen as usize;
2461 let avail_out = *outlen as usize;
2462
2463 if avail_in == 0 || avail_out == 0 {
2464 *outlen = 0;
2465 *inlen = 0;
2466 return 0;
2467 }
2468
2469 let in_data = core::slice::from_raw_parts(in_, avail_in);
2470 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2471
2472 let mut decoder = source.new_decoder_without_bom_handling();
2473 let mut in_pos: usize = 0;
2474 let mut out_pos: usize = 0;
2475 while in_pos < avail_in && out_pos < avail_out {
2476 let (res, read, written) = decoder.decode_to_utf8_without_replacement(
2477 &in_data[in_pos..],
2478 &mut out_slice[out_pos..],
2479 true,
2480 );
2481 out_pos += written;
2482 in_pos += read;
2483 match res {
2484 encoding_rs::DecoderResult::InputEmpty => break,
2485 encoding_rs::DecoderResult::OutputFull => break,
2486 encoding_rs::DecoderResult::Malformed(..) => {
2487 *outlen = out_pos as c_int;
2490 *inlen = in_pos as c_int;
2491 return -1;
2492 }
2493 }
2494 }
2495
2496 *outlen = out_pos as c_int;
2497 *inlen = in_pos as c_int;
2498 out_pos as c_int
2499}
2500
2501unsafe extern "C" fn shift_jis_input_func(
2503 out: *mut c_uchar,
2504 outlen: *mut c_int,
2505 in_: *const c_uchar,
2506 inlen: *mut c_int,
2507) -> c_int {
2508 enc_rs_input(encoding_rs::SHIFT_JIS, out, outlen, in_, inlen)
2509}
2510
2511unsafe extern "C" fn shift_jis_output_func(
2513 out: *mut c_uchar,
2514 outlen: *mut c_int,
2515 in_: *const c_uchar,
2516 inlen: *mut c_int,
2517) -> c_int {
2518 enc_rs_output(encoding_rs::SHIFT_JIS, out, outlen, in_, inlen)
2519}
2520
2521unsafe extern "C" fn euc_jp_input_func(
2523 out: *mut c_uchar,
2524 outlen: *mut c_int,
2525 in_: *const c_uchar,
2526 inlen: *mut c_int,
2527) -> c_int {
2528 enc_rs_input(encoding_rs::EUC_JP, out, outlen, in_, inlen)
2529}
2530
2531unsafe extern "C" fn euc_jp_output_func(
2533 out: *mut c_uchar,
2534 outlen: *mut c_int,
2535 in_: *const c_uchar,
2536 inlen: *mut c_int,
2537) -> c_int {
2538 enc_rs_output(encoding_rs::EUC_JP, out, outlen, in_, inlen)
2539}
2540
2541macro_rules! define_enc_rs_codec {
2546 ($input_fn:ident, $output_fn:ident, $enc:expr) => {
2547 #[allow(dead_code)]
2548 unsafe extern "C" fn $input_fn(
2549 out: *mut c_uchar,
2550 outlen: *mut c_int,
2551 in_: *const c_uchar,
2552 inlen: *mut c_int,
2553 ) -> c_int {
2554 enc_rs_input($enc, out, outlen, in_, inlen)
2555 }
2556 #[allow(dead_code)]
2557 unsafe extern "C" fn $output_fn(
2558 out: *mut c_uchar,
2559 outlen: *mut c_int,
2560 in_: *const c_uchar,
2561 inlen: *mut c_int,
2562 ) -> c_int {
2563 enc_rs_output($enc, out, outlen, in_, inlen)
2564 }
2565 };
2566}
2567
2568define_enc_rs_codec!(
2569 iso_8859_2_input_func,
2570 iso_8859_2_output_func,
2571 encoding_rs::ISO_8859_2
2572);
2573define_enc_rs_codec!(
2574 iso_8859_3_input_func,
2575 iso_8859_3_output_func,
2576 encoding_rs::ISO_8859_3
2577);
2578define_enc_rs_codec!(
2579 iso_8859_4_input_func,
2580 iso_8859_4_output_func,
2581 encoding_rs::ISO_8859_4
2582);
2583define_enc_rs_codec!(
2584 iso_8859_5_input_func,
2585 iso_8859_5_output_func,
2586 encoding_rs::ISO_8859_5
2587);
2588define_enc_rs_codec!(
2589 iso_8859_6_input_func,
2590 iso_8859_6_output_func,
2591 encoding_rs::ISO_8859_6
2592);
2593define_enc_rs_codec!(
2594 iso_8859_7_input_func,
2595 iso_8859_7_output_func,
2596 encoding_rs::ISO_8859_7
2597);
2598define_enc_rs_codec!(
2599 iso_8859_8_input_func,
2600 iso_8859_8_output_func,
2601 encoding_rs::ISO_8859_8
2602);
2603define_enc_rs_codec!(
2604 iso_8859_9_input_func,
2605 iso_8859_9_output_func,
2606 encoding_rs::WINDOWS_1254
2607);
2608define_enc_rs_codec!(
2609 iso_8859_10_input_func,
2610 iso_8859_10_output_func,
2611 encoding_rs::ISO_8859_10
2612);
2613define_enc_rs_codec!(
2614 iso_8859_11_input_func,
2615 iso_8859_11_output_func,
2616 encoding_rs::WINDOWS_874
2617);
2618define_enc_rs_codec!(
2619 iso_8859_13_input_func,
2620 iso_8859_13_output_func,
2621 encoding_rs::ISO_8859_13
2622);
2623define_enc_rs_codec!(
2624 iso_8859_14_input_func,
2625 iso_8859_14_output_func,
2626 encoding_rs::ISO_8859_14
2627);
2628define_enc_rs_codec!(
2629 iso_8859_15_input_func,
2630 iso_8859_15_output_func,
2631 encoding_rs::ISO_8859_15
2632);
2633define_enc_rs_codec!(
2634 iso_8859_16_input_func,
2635 iso_8859_16_output_func,
2636 encoding_rs::ISO_8859_16
2637);
2638define_enc_rs_codec!(
2639 iso_2022_jp_input_func,
2640 iso_2022_jp_output_func,
2641 encoding_rs::ISO_2022_JP
2642);
2643
2644unsafe fn fixed_width_input(
2653 le: bool,
2654 width: usize,
2655 out: *mut c_uchar,
2656 outlen: *mut c_int,
2657 in_: *const c_uchar,
2658 inlen: *mut c_int,
2659) -> c_int {
2660 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2661 return -1;
2662 }
2663 let avail_in = *inlen as usize;
2664 let avail_out = *outlen as usize;
2665 if avail_in == 0 || avail_out == 0 {
2666 *outlen = 0;
2667 *inlen = 0;
2668 return 0;
2669 }
2670 let in_data = core::slice::from_raw_parts(in_, avail_in);
2671 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2672 let mut in_pos = 0usize;
2673 let mut out_pos = 0usize;
2674 if avail_in >= width {
2679 let mut first: u32 = 0;
2680 for k in 0..width {
2681 let b = in_data[k] as u32;
2682 first = if le {
2683 first | (b << (8 * k))
2684 } else {
2685 (first << 8) | b
2686 };
2687 }
2688 if first == 0x0000_FEFF {
2689 in_pos = width;
2690 }
2691 }
2692 while in_pos + width <= avail_in {
2693 let mut unit: u32 = 0;
2694 for k in 0..width {
2695 let b = in_data[in_pos + k] as u32;
2696 unit = if le {
2697 unit | (b << (8 * k))
2698 } else {
2699 (unit << 8) | b
2700 };
2701 }
2702 if unit > 0x10FFFF || (0xD800..=0xDFFF).contains(&unit) {
2703 *outlen = out_pos as c_int;
2705 *inlen = in_pos as c_int;
2706 return -1;
2707 }
2708 let mut buf = [0u8; 4];
2709 let ch = unsafe { char::from_u32_unchecked(unit) };
2712 let n = ch.encode_utf8(&mut buf).len();
2713 if out_pos + n > avail_out {
2714 break;
2715 }
2716 out_slice[out_pos..out_pos + n].copy_from_slice(&buf[..n]);
2717 out_pos += n;
2718 in_pos += width;
2719 }
2720 *outlen = out_pos as c_int;
2721 *inlen = in_pos as c_int;
2722 out_pos as c_int
2723}
2724
2725unsafe fn fixed_width_output(
2729 le: bool,
2730 width: usize,
2731 out: *mut c_uchar,
2732 outlen: *mut c_int,
2733 in_: *const c_uchar,
2734 inlen: *mut c_int,
2735) -> c_int {
2736 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2737 return -1;
2738 }
2739 let avail_in = *inlen as usize;
2740 let avail_out = *outlen as usize;
2741 if avail_in == 0 || avail_out == 0 {
2742 *outlen = 0;
2743 *inlen = 0;
2744 return 0;
2745 }
2746 let in_data = core::slice::from_raw_parts(in_, avail_in);
2747 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2748 let mut in_pos = 0usize;
2749 let mut out_pos = 0usize;
2750 while in_pos < avail_in {
2751 let (cp, consumed) = match decode_utf8_char(in_data, in_pos) {
2752 None => {
2753 *outlen = out_pos as c_int;
2756 *inlen = in_pos as c_int;
2757 return -1;
2758 }
2759 Some(v) => v,
2760 };
2761 let max_cp = if width == 2 { 0xFFFF } else { 0x10FFFF };
2762 if cp > max_cp {
2763 *outlen = out_pos as c_int;
2766 *inlen = in_pos as c_int;
2767 return ENC_INPUT_ERROR;
2768 }
2769 if out_pos + width > avail_out {
2770 break;
2771 }
2772 for k in 0..width {
2773 let shift = 8 * if le { k } else { width - 1 - k };
2774 out_slice[out_pos + k] = ((cp >> shift) & 0xFF) as u8;
2775 }
2776 out_pos += width;
2777 in_pos += consumed;
2778 }
2779 *outlen = out_pos as c_int;
2780 *inlen = in_pos as c_int;
2781 out_pos as c_int
2782}
2783
2784unsafe extern "C" fn ucs2_input_func(
2788 out: *mut c_uchar,
2789 outlen: *mut c_int,
2790 in_: *const c_uchar,
2791 inlen: *mut c_int,
2792) -> c_int {
2793 fixed_width_input(true, 2, out, outlen, in_, inlen)
2794}
2795
2796unsafe extern "C" fn ucs2_output_func(
2798 out: *mut c_uchar,
2799 outlen: *mut c_int,
2800 in_: *const c_uchar,
2801 inlen: *mut c_int,
2802) -> c_int {
2803 fixed_width_output(true, 2, out, outlen, in_, inlen)
2804}
2805
2806unsafe extern "C" fn ucs4le_input_func(
2808 out: *mut c_uchar,
2809 outlen: *mut c_int,
2810 in_: *const c_uchar,
2811 inlen: *mut c_int,
2812) -> c_int {
2813 fixed_width_input(true, 4, out, outlen, in_, inlen)
2814}
2815
2816unsafe extern "C" fn ucs4le_output_func(
2818 out: *mut c_uchar,
2819 outlen: *mut c_int,
2820 in_: *const c_uchar,
2821 inlen: *mut c_int,
2822) -> c_int {
2823 fixed_width_output(true, 4, out, outlen, in_, inlen)
2824}
2825
2826unsafe extern "C" fn ucs4be_input_func(
2828 out: *mut c_uchar,
2829 outlen: *mut c_int,
2830 in_: *const c_uchar,
2831 inlen: *mut c_int,
2832) -> c_int {
2833 fixed_width_input(false, 4, out, outlen, in_, inlen)
2834}
2835
2836unsafe extern "C" fn ucs4be_output_func(
2838 out: *mut c_uchar,
2839 outlen: *mut c_int,
2840 in_: *const c_uchar,
2841 inlen: *mut c_int,
2842) -> c_int {
2843 fixed_width_output(false, 4, out, outlen, in_, inlen)
2844}
2845
2846const EBCDIC037_TO_UNICODE: [u16; 256] = [
2850 0x0000, 0x0001, 0x0002, 0x0003, 0x009C, 0x0009, 0x0086, 0x007F, 0x0097, 0x008D, 0x008E, 0x000B,
2851 0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x009D, 0x0085, 0x0008, 0x0087,
2852 0x0018, 0x0019, 0x0092, 0x008F, 0x001C, 0x001D, 0x001E, 0x001F, 0x0080, 0x0081, 0x0082, 0x0083,
2853 0x0084, 0x000A, 0x0017, 0x001B, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x0005, 0x0006, 0x0007,
2854 0x0090, 0x0091, 0x0016, 0x0093, 0x0094, 0x0095, 0x0096, 0x0004, 0x0098, 0x0099, 0x009A, 0x009B,
2855 0x0014, 0x0015, 0x009E, 0x001A, 0x0020, 0x00A0, 0x00E2, 0x00E4, 0x00E0, 0x00E1, 0x00E3, 0x00E5,
2856 0x00E7, 0x00F1, 0x00A2, 0x002E, 0x003C, 0x0028, 0x002B, 0x007C, 0x0026, 0x00E9, 0x00EA, 0x00EB,
2857 0x00E8, 0x00ED, 0x00EE, 0x00EF, 0x00EC, 0x00DF, 0x0021, 0x0024, 0x002A, 0x0029, 0x003B, 0x00AC,
2858 0x002D, 0x002F, 0x00C2, 0x00C4, 0x00C0, 0x00C1, 0x00C3, 0x00C5, 0x00C7, 0x00D1, 0x00A6, 0x002C,
2859 0x0025, 0x005F, 0x003E, 0x003F, 0x00F8, 0x00C9, 0x00CA, 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF,
2860 0x00CC, 0x0060, 0x003A, 0x0023, 0x0040, 0x0027, 0x003D, 0x0022, 0x00D8, 0x0061, 0x0062, 0x0063,
2861 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x00AB, 0x00BB, 0x00F0, 0x00FD, 0x00FE, 0x00B1,
2862 0x00B0, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x00AA, 0x00BA,
2863 0x00E6, 0x00B8, 0x00C6, 0x00A4, 0x00B5, 0x007E, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078,
2864 0x0079, 0x007A, 0x00A1, 0x00BF, 0x00D0, 0x00DD, 0x00DE, 0x00AE, 0x005E, 0x00A3, 0x00A5, 0x00B7,
2865 0x00A9, 0x00A7, 0x00B6, 0x00BC, 0x00BD, 0x00BE, 0x005B, 0x005D, 0x00AF, 0x00A8, 0x00B4, 0x00D7,
2866 0x007B, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x00AD, 0x00F4,
2867 0x00F6, 0x00F2, 0x00F3, 0x00F5, 0x007D, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050,
2868 0x0051, 0x0052, 0x00B9, 0x00FB, 0x00FC, 0x00F9, 0x00FA, 0x00FF, 0x005C, 0x00F7, 0x0053, 0x0054,
2869 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x00B2, 0x00D4, 0x00D6, 0x00D2, 0x00D3, 0x00D5,
2870 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x00B3, 0x00DB,
2871 0x00DC, 0x00D9, 0x00DA, 0x009F,
2872];
2873
2874const fn ebcdic037_cp_to_byte(cp: u32) -> Option<u8> {
2877 if cp > 0xFF {
2878 return None;
2879 }
2880 let mut i = 0;
2881 while i < 256 {
2882 if EBCDIC037_TO_UNICODE[i] as u32 == cp {
2883 return Some(i as u8);
2884 }
2885 i += 1;
2886 }
2887 None
2888}
2889
2890unsafe extern "C" fn ebcdic_input_func(
2892 out: *mut c_uchar,
2893 outlen: *mut c_int,
2894 in_: *const c_uchar,
2895 inlen: *mut c_int,
2896) -> c_int {
2897 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2898 return -1;
2899 }
2900 let avail_in = *inlen as usize;
2901 let avail_out = *outlen as usize;
2902 if avail_in == 0 || avail_out == 0 {
2903 *outlen = 0;
2904 *inlen = 0;
2905 return 0;
2906 }
2907 let in_data = core::slice::from_raw_parts(in_, avail_in);
2908 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2909 let mut in_pos = 0usize;
2910 let mut out_pos = 0usize;
2911 while in_pos < avail_in {
2912 let cp = u32::from(EBCDIC037_TO_UNICODE[in_data[in_pos] as usize]);
2913 let mut buf = [0u8; 2];
2914 let ch = unsafe { char::from_u32_unchecked(cp) };
2915 let n = ch.encode_utf8(&mut buf).len();
2916 if out_pos + n > avail_out {
2917 break;
2918 }
2919 out_slice[out_pos..out_pos + n].copy_from_slice(&buf[..n]);
2920 out_pos += n;
2921 in_pos += 1;
2922 }
2923 *outlen = out_pos as c_int;
2924 *inlen = in_pos as c_int;
2925 out_pos as c_int
2926}
2927
2928unsafe extern "C" fn ebcdic_output_func(
2931 out: *mut c_uchar,
2932 outlen: *mut c_int,
2933 in_: *const c_uchar,
2934 inlen: *mut c_int,
2935) -> c_int {
2936 if out.is_null() || outlen.is_null() || in_.is_null() || inlen.is_null() {
2937 return -1;
2938 }
2939 let avail_in = *inlen as usize;
2940 let avail_out = *outlen as usize;
2941 if avail_in == 0 || avail_out == 0 {
2942 *outlen = 0;
2943 *inlen = 0;
2944 return 0;
2945 }
2946 let in_data = core::slice::from_raw_parts(in_, avail_in);
2947 let out_slice = core::slice::from_raw_parts_mut(out, avail_out);
2948 let mut in_pos = 0usize;
2949 let mut out_pos = 0usize;
2950 while in_pos < avail_in {
2951 let (cp, consumed) = match decode_utf8_char(in_data, in_pos) {
2952 None => {
2953 *outlen = out_pos as c_int;
2954 *inlen = in_pos as c_int;
2955 return -1;
2956 }
2957 Some(v) => v,
2958 };
2959 match ebcdic037_cp_to_byte(cp) {
2960 None => {
2961 *outlen = out_pos as c_int;
2962 *inlen = in_pos as c_int;
2963 return ENC_INPUT_ERROR;
2964 }
2965 Some(byte) => {
2966 if out_pos + 1 > avail_out {
2967 break;
2968 }
2969 out_slice[out_pos] = byte;
2970 out_pos += 1;
2971 }
2972 }
2973 in_pos += consumed;
2974 }
2975 *outlen = out_pos as c_int;
2976 *inlen = in_pos as c_int;
2977 out_pos as c_int
2978}
2979
2980pub(crate) fn xmlFindCharEncodingHandler(name: *const c_char) -> *mut _xmlCharEncodingHandler {
2989 if name.is_null() {
2990 return ptr::null_mut();
2991 }
2992 find_encoding_handler(name as *const xmlChar)
2993}
2994
2995pub(crate) const fn xmlGetCharEncodingName(enc: xmlCharEncoding) -> *const c_char {
2999 match enc {
3003 xmlCharEncoding::XML_CHAR_ENCODING_UTF8 => c"UTF-8".as_ptr(),
3004 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE | xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE => {
3005 c"UTF-16".as_ptr()
3006 }
3007 xmlCharEncoding::XML_CHAR_ENCODING_UCS4LE | xmlCharEncoding::XML_CHAR_ENCODING_UCS4BE => {
3008 c"UCS-4".as_ptr()
3009 }
3010 xmlCharEncoding::XML_CHAR_ENCODING_EBCDIC => c"IBM037".as_ptr(),
3011 xmlCharEncoding::XML_CHAR_ENCODING_UCS2 => c"UCS-2".as_ptr(),
3012 xmlCharEncoding::XML_CHAR_ENCODING_8859_1 => c"ISO-8859-1".as_ptr(),
3013 xmlCharEncoding::XML_CHAR_ENCODING_8859_2 => c"ISO-8859-2".as_ptr(),
3014 xmlCharEncoding::XML_CHAR_ENCODING_8859_3 => c"ISO-8859-3".as_ptr(),
3015 xmlCharEncoding::XML_CHAR_ENCODING_8859_4 => c"ISO-8859-4".as_ptr(),
3016 xmlCharEncoding::XML_CHAR_ENCODING_8859_5 => c"ISO-8859-5".as_ptr(),
3017 xmlCharEncoding::XML_CHAR_ENCODING_8859_6 => c"ISO-8859-6".as_ptr(),
3018 xmlCharEncoding::XML_CHAR_ENCODING_8859_7 => c"ISO-8859-7".as_ptr(),
3019 xmlCharEncoding::XML_CHAR_ENCODING_8859_8 => c"ISO-8859-8".as_ptr(),
3020 xmlCharEncoding::XML_CHAR_ENCODING_8859_9 => c"ISO-8859-9".as_ptr(),
3021 xmlCharEncoding::XML_CHAR_ENCODING_2022_JP => c"ISO-2022-JP".as_ptr(),
3022 xmlCharEncoding::XML_CHAR_ENCODING_SHIFT_JIS => c"Shift_JIS".as_ptr(),
3023 xmlCharEncoding::XML_CHAR_ENCODING_EUC_JP => c"EUC-JP".as_ptr(),
3024 xmlCharEncoding::XML_CHAR_ENCODING_ASCII => c"US-ASCII".as_ptr(),
3026 _ => ptr::null(),
3027 }
3028}
3029
3030pub(crate) fn xmlParseCharEncoding(name: *const c_char) -> c_int {
3039 if name.is_null() {
3040 return xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int;
3041 }
3042 let bytes = unsafe { CStr::from_ptr(name).to_bytes() };
3043 encoding_from_name(bytes) as c_int
3044}
3045
3046static ENCODING_ALIASES: std::sync::OnceLock<
3054 parking_lot::RwLock<std::collections::HashMap<Vec<u8>, Vec<u8>>>,
3055> = std::sync::OnceLock::new();
3056
3057fn encoding_aliases() -> &'static parking_lot::RwLock<std::collections::HashMap<Vec<u8>, Vec<u8>>> {
3058 ENCODING_ALIASES.get_or_init(|| parking_lot::RwLock::new(std::collections::HashMap::new()))
3059}
3060
3061pub(crate) fn add_encoding_alias(name: *const c_char, alias: *const c_char) -> c_int {
3069 if name.is_null() || alias.is_null() {
3070 return -1;
3071 }
3072 let n = unsafe { CStr::from_ptr(name).to_bytes().to_vec() };
3073 let a = unsafe { CStr::from_ptr(alias).to_bytes().to_vec() };
3074 encoding_aliases().write().insert(a, n);
3075 0
3076}
3077
3078pub(crate) fn del_encoding_alias(alias: *const c_char) -> c_int {
3085 if alias.is_null() {
3086 return -1;
3087 }
3088 let a = unsafe { CStr::from_ptr(alias).to_bytes().to_vec() };
3089 if encoding_aliases().write().remove(&a).is_some() {
3090 0
3091 } else {
3092 -1
3093 }
3094}
3095
3096pub(crate) fn get_encoding_alias(alias: *const c_char) -> *const c_char {
3105 if alias.is_null() {
3106 return ptr::null();
3107 }
3108 let a = unsafe { CStr::from_ptr(alias).to_bytes().to_vec() };
3109 let guard = encoding_aliases().read();
3110 match guard.get(&a) {
3111 Some(v) => {
3112 let leaked: &'static [u8] = Box::leak(v.clone().into_boxed_slice());
3115 leaked.as_ptr() as *const c_char
3116 }
3117 None => ptr::null(),
3118 }
3119}
3120
3121pub(crate) fn cleanup_encoding_aliases() {
3123 encoding_aliases().write().clear();
3124}
3125
3126pub(crate) fn xmlCharEncInFunc(
3130 handler: *mut _xmlCharEncodingHandler,
3131 out: *mut _xmlBuffer,
3132 in_: *mut _xmlBuffer,
3133) -> c_int {
3134 char_enc_in(handler, out, in_)
3135}
3136
3137pub(crate) fn xmlCharEncOutFunc(
3141 handler: *mut _xmlCharEncodingHandler,
3142 out: *mut _xmlBuffer,
3143 in_: *mut _xmlBuffer,
3144) -> c_int {
3145 char_enc_out(handler, out, in_)
3146}
3147
3148pub(crate) fn xmlNewCharEncodingHandler(
3162 name: *const c_char,
3163 input: xmlCharEncodingInputFunc,
3164 output: xmlCharEncodingOutputFunc,
3165) -> *mut _xmlCharEncodingHandler {
3166 if name.is_null() {
3167 return ptr::null_mut();
3168 }
3169
3170 let name_raw = unsafe { crate::abi::allocator::xmlMemStrdupImpl(name) };
3171 if name_raw.is_null() {
3172 return ptr::null_mut();
3173 }
3174
3175 let handler = unsafe { xmlMallocImpl(size_of::<_xmlCharEncodingHandler>()) }
3176 as *mut _xmlCharEncodingHandler;
3177
3178 if handler.is_null() {
3179 unsafe { xmlFreeImpl(name_raw) };
3180 return ptr::null_mut();
3181 }
3182
3183 unsafe {
3184 ptr::write(
3185 handler,
3186 _xmlCharEncodingHandler {
3187 name: name_raw as *mut c_char,
3188 input: EncodingInputUnion {
3189 legacyFunc: Some(input),
3190 },
3191 output: EncodingOutputUnion {
3192 legacyFunc: Some(output),
3193 },
3194 inputCtxt: ptr::null_mut(),
3195 outputCtxt: ptr::null_mut(),
3196 ctxtDtor: None,
3197 flags: 0,
3198 },
3199 );
3200 }
3201
3202 handler
3203}
3204
3205#[allow(dead_code)]
3216pub(crate) fn xmlDelEncodingHandler(handler: *mut _xmlCharEncodingHandler) {
3217 if handler.is_null() {
3218 return;
3219 }
3220
3221 {
3223 let mut handlers = ENCODING_HANDLERS.write();
3224 handlers.retain(|&h| h.0 != handler);
3225 }
3226
3227 unsafe {
3228 if !(*handler).name.is_null() {
3229 xmlFreeImpl((*handler).name as *mut c_void);
3230 }
3231 xmlFreeImpl(handler as *mut c_void);
3232 }
3233}
3234
3235pub(crate) fn xmlInitCharEncodingHandlers() {
3237 init_encodings();
3238}
3239
3240pub(crate) fn xmlCleanupCharEncodingHandlers() {
3242 cleanup_encodings();
3243}
3244
3245pub(crate) fn xmlLookupCharEncodingHandler(enc: c_int, out: *mut *mut c_void) -> c_int {
3273 if out.is_null() {
3274 return crate::abi::types::XML_ERR_ARGUMENT;
3275 }
3276 unsafe {
3277 *out = ptr::null_mut();
3278 }
3279 if enc <= 0 || enc >= 32 {
3280 return crate::abi::types::XML_ERR_UNSUPPORTED_ENCODING;
3281 }
3282 if enc == xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int {
3284 return crate::abi::types::XML_ERR_OK;
3285 }
3286 let canonical: &[u8] = match enc {
3287 2 => b"UTF-16LE\0",
3289 3 => b"UTF-16BE\0",
3291 10 => b"ISO-8859-1\0",
3293 22 => b"US-ASCII\0",
3295 23 => b"UTF-16\0",
3297 _ => return crate::abi::types::XML_ERR_UNSUPPORTED_ENCODING,
3298 };
3299 let h = find_encoding_handler(canonical.as_ptr() as *const xmlChar);
3300 if h.is_null() {
3301 return crate::abi::types::XML_ERR_UNSUPPORTED_ENCODING;
3302 }
3303 unsafe {
3304 *out = h as *mut c_void;
3305 }
3306 crate::abi::types::XML_ERR_OK
3307}
3308
3309pub(crate) fn xmlGetCharEncodingHandler(enc: c_int) -> *mut c_void {
3311 let mut ret: *mut c_void = ptr::null_mut();
3312 let _rc = xmlLookupCharEncodingHandler(enc, &mut ret);
3313 ret
3314}
3315
3316pub(crate) fn xmlCreateCharEncodingHandler(
3331 name: *const c_char,
3332 flags: c_int,
3333 impl_: Option<xmlCharEncConvImpl>,
3334 implCtxt: *mut c_void,
3335 out: *mut *mut c_void,
3336) -> c_int {
3337 if out.is_null() {
3338 return crate::abi::types::XML_ERR_ARGUMENT;
3339 }
3340 unsafe {
3341 *out = ptr::null_mut();
3342 }
3343 if name.is_null() || flags == 0 {
3344 return crate::abi::types::XML_ERR_ARGUMENT;
3345 }
3346 let norig = unsafe { CStr::from_ptr(name).to_bytes() };
3347
3348 let mut eff: &[u8] = norig;
3350 let alias = get_encoding_alias(name);
3351 if !alias.is_null() {
3352 eff = unsafe { CStr::from_ptr(alias).to_bytes() };
3353 }
3354
3355 let enc = encoding_from_name(eff);
3356
3357 if enc == xmlCharEncoding::XML_CHAR_ENCODING_UTF8 {
3359 return crate::abi::types::XML_ERR_OK;
3360 }
3361
3362 let canonical: &[u8] = match enc {
3363 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE => b"UTF-16LE\0",
3364 xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE => b"UTF-16BE\0",
3365 xmlCharEncoding::XML_CHAR_ENCODING_8859_1 => b"ISO-8859-1\0",
3366 xmlCharEncoding::XML_CHAR_ENCODING_ASCII => b"US-ASCII\0",
3367 _ => {
3368 return find_extra_handler(norig, eff, flags, impl_, implCtxt, out);
3369 }
3370 };
3371 let h = find_encoding_handler(canonical.as_ptr() as *const xmlChar);
3372 if h.is_null() {
3373 return find_extra_handler(norig, eff, flags, impl_, implCtxt, out);
3374 }
3375 unsafe {
3376 let src = &*h;
3377 let has_in = (flags & 1) == 0 || !src.input.legacyFunc.is_none();
3378 let has_out = (flags & 2) == 0 || !src.output.legacyFunc.is_none();
3379 if !has_in || !has_out {
3380 return find_extra_handler(norig, eff, flags, impl_, implCtxt, out);
3381 }
3382 let copy =
3387 xmlMallocImpl(size_of::<_xmlCharEncodingHandler>()) as *mut _xmlCharEncodingHandler;
3388 if copy.is_null() {
3389 return crate::abi::types::XML_ERR_NO_MEMORY;
3390 }
3391 let name_copy = crate::abi::allocator::xmlMemStrdupImpl(name) as *mut c_char;
3392 if name_copy.is_null() {
3393 xmlFreeImpl(copy as *mut c_void);
3394 return crate::abi::types::XML_ERR_NO_MEMORY;
3395 }
3396 ptr::write(
3397 copy,
3398 _xmlCharEncodingHandler {
3399 name: name_copy,
3400 input: EncodingInputUnion {
3401 legacyFunc: src.input.legacyFunc,
3402 },
3403 output: EncodingOutputUnion {
3404 legacyFunc: src.output.legacyFunc,
3405 },
3406 inputCtxt: src.inputCtxt,
3407 outputCtxt: src.outputCtxt,
3408 ctxtDtor: src.ctxtDtor,
3409 flags: src.flags,
3410 },
3411 );
3412 *out = copy as *mut c_void;
3413 }
3414 crate::abi::types::XML_ERR_OK
3415}
3416
3417fn find_extra_handler(
3432 norig: &[u8],
3433 name: &[u8],
3434 flags: c_int,
3435 impl_: Option<xmlCharEncConvImpl>,
3436 implCtxt: *mut c_void,
3437 out: *mut *mut c_void,
3438) -> c_int {
3439 if let Some(f) = impl_ {
3441 let mut n = norig.to_vec();
3442 n.push(0);
3443 let rc = unsafe {
3444 f(
3445 implCtxt,
3446 n.as_ptr() as *const c_char,
3447 flags,
3448 out as *mut *mut crate::abi::structs::_xmlCharEncodingHandler,
3449 )
3450 };
3451 return rc;
3452 }
3453 let mut n = name.to_vec();
3455 n.push(0);
3456 let h = find_encoding_handler(n.as_ptr() as *const xmlChar);
3457 if !h.is_null() {
3458 unsafe {
3459 let src = &*h;
3460 let has_in = (flags & 1) == 0 || !src.input.legacyFunc.is_none();
3461 let has_out = (flags & 2) == 0 || !src.output.legacyFunc.is_none();
3462 if has_in && has_out {
3463 *out = h as *mut c_void;
3464 return crate::abi::types::XML_ERR_OK;
3465 }
3466 }
3467 }
3468 crate::abi::types::XML_ERR_UNSUPPORTED_ENCODING
3469}
3470
3471pub(crate) fn xmlOpenCharEncodingHandler(
3473 name: *const c_char,
3474 output: c_int,
3475 out: *mut *mut c_void,
3476) -> c_int {
3477 let flags: c_int = if output != 0 { 2 } else { 1 };
3479 xmlCreateCharEncodingHandler(name, flags, None, ptr::null_mut(), out)
3480}
3481
3482pub(crate) fn xmlCharEncNewCustomHandler(
3497 name: *const c_char,
3498 input: xmlCharEncConvFunc,
3499 output: xmlCharEncConvFunc,
3500 ctxtDtor: Option<xmlCharEncConvCtxtDtor>,
3501 inputCtxt: *mut c_void,
3502 outputCtxt: *mut c_void,
3503 out: *mut *mut c_void,
3504) -> c_int {
3505 if out.is_null() {
3506 return crate::abi::types::XML_ERR_ARGUMENT;
3507 }
3508 let handler = unsafe { xmlMallocImpl(size_of::<_xmlCharEncodingHandler>()) }
3509 as *mut _xmlCharEncodingHandler;
3510 if handler.is_null() {
3511 unsafe {
3512 if let Some(d) = ctxtDtor {
3513 if !inputCtxt.is_null() {
3514 d(inputCtxt);
3515 }
3516 if !outputCtxt.is_null() {
3517 d(outputCtxt);
3518 }
3519 }
3520 }
3521 return crate::abi::types::XML_ERR_NO_MEMORY;
3522 }
3523 let name_copy = if name.is_null() {
3524 ptr::null_mut()
3525 } else {
3526 let nc = unsafe { crate::abi::allocator::xmlMemStrdupImpl(name) } as *mut c_char;
3527 if nc.is_null() {
3528 unsafe { xmlFreeImpl(handler as *mut c_void) };
3529 unsafe {
3530 if let Some(d) = ctxtDtor {
3531 if !inputCtxt.is_null() {
3532 d(inputCtxt);
3533 }
3534 if !outputCtxt.is_null() {
3535 d(outputCtxt);
3536 }
3537 }
3538 }
3539 return crate::abi::types::XML_ERR_NO_MEMORY;
3540 }
3541 nc
3542 };
3543 unsafe {
3544 ptr::write(
3545 handler,
3546 _xmlCharEncodingHandler {
3547 name: name_copy,
3548 input: EncodingInputUnion { func: Some(input) },
3549 output: EncodingOutputUnion { func: Some(output) },
3550 inputCtxt,
3551 outputCtxt,
3552 ctxtDtor,
3553 flags: 0,
3554 },
3555 );
3556 *out = handler as *mut c_void;
3557 }
3558 crate::abi::types::XML_ERR_OK
3559}
3560
3561#[cfg(test)]
3566mod tests {
3567 use super::*;
3568
3569 #[test]
3572 fn test_detect_bom_utf8() {
3573 let data = [0xEF, 0xBB, 0xBF, b'<', b'?', b'x', b'm', b'l'];
3574 assert_eq!(
3575 detect_encoding_from_bom(&data),
3576 xmlCharEncoding::XML_CHAR_ENCODING_UTF8
3577 );
3578 }
3579
3580 #[test]
3581 fn test_detect_bom_utf16le() {
3582 let data = [0xFF, 0xFE, 0x00, 0x01];
3583 assert_eq!(
3584 detect_encoding_from_bom(&data),
3585 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE
3586 );
3587 }
3588
3589 #[test]
3590 fn test_detect_bom_utf16be() {
3591 let data = [0xFE, 0xFF, 0x00, 0x01];
3592 assert_eq!(
3593 detect_encoding_from_bom(&data),
3594 xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE
3595 );
3596 }
3597
3598 #[test]
3599 fn test_detect_bom_none() {
3600 let data = b"<xml>";
3601 assert_eq!(
3602 detect_encoding_from_bom(data),
3603 xmlCharEncoding::XML_CHAR_ENCODING_NONE
3604 );
3605 }
3606
3607 #[test]
3608 fn test_detect_bom_empty() {
3609 assert_eq!(
3610 detect_encoding_from_bom(b""),
3611 xmlCharEncoding::XML_CHAR_ENCODING_NONE
3612 );
3613 }
3614
3615 #[test]
3618 fn test_detect_encoding_declaration_utf8() {
3619 let data = b"<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
3620 let result = detect_encoding_from_declaration(data);
3621 assert_eq!(result, Some(b"utf-8".to_vec()));
3622 }
3623
3624 #[test]
3625 fn test_detect_encoding_declaration_iso() {
3626 let data = b"<?xml version='1.0' encoding='ISO-8859-1'?>";
3627 let result = detect_encoding_from_declaration(data);
3628 assert_eq!(result, Some(b"iso-8859-1".to_vec()));
3629 }
3630
3631 #[test]
3632 fn test_detect_encoding_declaration_none() {
3633 let data = b"<?xml version=\"1.0\"?>";
3634 let result = detect_encoding_from_declaration(data);
3635 assert!(result.is_none());
3636 }
3637
3638 #[test]
3639 fn test_detect_encoding_declaration_no_xml() {
3640 let data = b"<root>";
3641 let result = detect_encoding_from_declaration(data);
3642 assert!(result.is_none());
3643 }
3644
3645 #[test]
3646 fn test_detect_encoding_declaration_with_bom() {
3647 let mut data = vec![0xEF, 0xBB, 0xBF];
3648 data.extend_from_slice(b"<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
3649 let result = detect_encoding_from_declaration(&data);
3650 assert_eq!(result, Some(b"utf-8".to_vec()));
3651 }
3652
3653 #[test]
3656 fn test_encoding_from_name_utf8() {
3657 assert_eq!(
3658 encoding_from_name(b"UTF-8"),
3659 xmlCharEncoding::XML_CHAR_ENCODING_UTF8
3660 );
3661 assert_eq!(
3662 encoding_from_name(b"utf8"),
3663 xmlCharEncoding::XML_CHAR_ENCODING_UTF8
3664 );
3665 }
3666
3667 #[test]
3668 fn test_encoding_from_name_utf16() {
3669 assert_eq!(
3670 encoding_from_name(b"UTF-16LE"),
3671 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE
3672 );
3673 assert_eq!(
3674 encoding_from_name(b"UTF-16BE"),
3675 xmlCharEncoding::XML_CHAR_ENCODING_UTF16BE
3676 );
3677 assert_eq!(
3678 encoding_from_name(b"utf-16"),
3679 xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE
3680 );
3681 }
3682
3683 #[test]
3684 fn test_encoding_from_name_latin1() {
3685 assert_eq!(
3686 encoding_from_name(b"ISO-8859-1"),
3687 xmlCharEncoding::XML_CHAR_ENCODING_8859_1
3688 );
3689 assert_eq!(
3690 encoding_from_name(b"Latin1"),
3691 xmlCharEncoding::XML_CHAR_ENCODING_8859_1
3692 );
3693 }
3694
3695 #[test]
3696 fn test_encoding_from_name_ascii() {
3697 assert_eq!(
3698 encoding_from_name(b"ASCII"),
3699 xmlCharEncoding::XML_CHAR_ENCODING_ASCII
3700 );
3701 assert_eq!(
3702 encoding_from_name(b"US-ASCII"),
3703 xmlCharEncoding::XML_CHAR_ENCODING_ASCII
3704 );
3705 }
3706
3707 #[test]
3708 fn test_encoding_from_name_error() {
3709 assert_eq!(
3710 encoding_from_name(b"invalid-encoding"),
3711 xmlCharEncoding::XML_CHAR_ENCODING_ERROR
3712 );
3713 }
3714
3715 #[test]
3716 fn test_encoding_from_name_empty() {
3717 assert_eq!(
3718 encoding_from_name(b""),
3719 xmlCharEncoding::XML_CHAR_ENCODING_ERROR
3720 );
3721 }
3722
3723 #[test]
3726 fn test_encoding_name_utf8() {
3727 assert_eq!(
3728 encoding_name(xmlCharEncoding::XML_CHAR_ENCODING_UTF8),
3729 Some(b"UTF-8" as &[u8])
3730 );
3731 }
3732
3733 #[test]
3734 fn test_encoding_name_utf16le() {
3735 assert_eq!(
3736 encoding_name(xmlCharEncoding::XML_CHAR_ENCODING_UTF16LE),
3737 Some(b"UTF-16LE" as &[u8])
3738 );
3739 }
3740
3741 #[test]
3742 fn test_encoding_name_none() {
3743 assert!(encoding_name(xmlCharEncoding::XML_CHAR_ENCODING_NONE).is_none());
3744 }
3745
3746 #[test]
3747 fn test_encoding_name_error() {
3748 assert!(encoding_name(xmlCharEncoding::XML_CHAR_ENCODING_ERROR).is_none());
3749 }
3750
3751 #[test]
3754 fn test_utf8_valid_ascii() {
3755 assert!(utf8_valid(b"hello world"));
3756 }
3757
3758 #[test]
3759 fn test_utf8_valid_multi_byte() {
3760 assert!(utf8_valid("héllo wörld 🌍".as_bytes()));
3761 }
3762
3763 #[test]
3764 fn test_utf8_valid_empty() {
3765 assert!(utf8_valid(b""));
3766 }
3767
3768 #[test]
3769 fn test_utf8_invalid() {
3770 assert!(!utf8_valid(&[0xFF, 0xFE, 0x00]));
3771 }
3772
3773 #[test]
3776 fn test_valid_xml_chars() {
3777 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));
3783 assert!(is_valid_xml_char(0xE000));
3784 assert!(is_valid_xml_char(0xFFFD));
3785 assert!(is_valid_xml_char(0x10000));
3786 assert!(is_valid_xml_char(0x10FFFF));
3787 }
3788
3789 #[test]
3790 fn test_invalid_xml_chars() {
3791 assert!(!is_valid_xml_char(0x00));
3792 assert!(!is_valid_xml_char(0x08));
3793 assert!(!is_valid_xml_char(0x0B));
3794 assert!(!is_valid_xml_char(0x0C));
3795 assert!(!is_valid_xml_char(0x0E));
3796 assert!(!is_valid_xml_char(0x1F));
3797 assert!(!is_valid_xml_char(0xD800)); assert!(!is_valid_xml_char(0xDFFF)); assert!(!is_valid_xml_char(0xFFFE));
3800 assert!(!is_valid_xml_char(0xFFFF));
3801 assert!(!is_valid_xml_char(0x110000));
3802 }
3803
3804 #[test]
3807 fn test_utf16le_to_utf8_ascii() {
3808 let data = [b'A', 0x00, b'B', 0x00];
3810 let result = utf16le_to_utf8(&data).unwrap();
3811 assert_eq!(result, b"AB");
3812 }
3813
3814 #[test]
3815 fn test_utf16le_to_utf8_bom() {
3816 let mut data = vec![0xFF, 0xFE]; data.extend_from_slice(&[b'A', 0x00, b'B', 0x00]);
3818 let result = utf16le_to_utf8(&data).unwrap();
3819 assert_eq!(result, b"AB");
3820 }
3821
3822 #[test]
3823 fn test_utf16le_to_utf8_bmp() {
3824 let data = [0xE9, 0x00];
3826 let result = utf16le_to_utf8(&data).unwrap();
3827 assert_eq!(result, "é".as_bytes());
3828 }
3829
3830 #[test]
3831 fn test_utf16le_to_utf8_supplementary() {
3832 let data = [0x3D, 0xD8, 0x00, 0xDE];
3834 let result = utf16le_to_utf8(&data).unwrap();
3835 assert_eq!(result, "😀".as_bytes());
3836 }
3837
3838 #[test]
3839 fn test_utf16le_to_utf8_unpaired_surrogate() {
3840 let data = [0x00, 0xD8]; assert!(utf16le_to_utf8(&data).is_err());
3842 }
3843
3844 #[test]
3845 fn test_utf16le_to_utf8_truncated() {
3846 let data = [0x00]; assert!(utf16le_to_utf8(&data).is_err());
3848 }
3849
3850 #[test]
3851 fn test_utf16le_to_utf8_empty() {
3852 let result = utf16le_to_utf8(b"").unwrap();
3853 assert!(result.is_empty());
3854 }
3855
3856 #[test]
3859 fn test_utf16be_to_utf8_ascii() {
3860 let data = [0x00, b'A', 0x00, b'B'];
3861 let result = utf16be_to_utf8(&data).unwrap();
3862 assert_eq!(result, b"AB");
3863 }
3864
3865 #[test]
3866 fn test_utf16be_to_utf8_bom() {
3867 let mut data = vec![0xFE, 0xFF]; data.extend_from_slice(&[0x00, b'A', 0x00, b'B']);
3869 let result = utf16be_to_utf8(&data).unwrap();
3870 assert_eq!(result, b"AB");
3871 }
3872
3873 #[test]
3874 fn test_utf16be_to_utf8_supplementary() {
3875 let data = [0xD8, 0x3D, 0xDE, 0x00];
3877 let result = utf16be_to_utf8(&data).unwrap();
3878 assert_eq!(result, "😀".as_bytes());
3879 }
3880
3881 #[test]
3882 fn test_utf16be_to_utf8_empty() {
3883 let result = utf16be_to_utf8(b"").unwrap();
3884 assert!(result.is_empty());
3885 }
3886
3887 #[test]
3890 fn test_utf8_to_utf16le_ascii() {
3891 let result = utf8_to_utf16le(b"AB").unwrap();
3892 assert_eq!(result, [b'A', 0x00, b'B', 0x00]);
3893 }
3894
3895 #[test]
3896 fn test_utf8_to_utf16le_bmp() {
3897 let result = utf8_to_utf16le("é".as_bytes()).unwrap();
3898 assert_eq!(result, [0xE9, 0x00]);
3899 }
3900
3901 #[test]
3902 fn test_utf8_to_utf16le_supplementary() {
3903 let result = utf8_to_utf16le("😀".as_bytes()).unwrap();
3904 assert_eq!(result, [0x3D, 0xD8, 0x00, 0xDE]);
3905 }
3906
3907 #[test]
3908 fn test_utf8_to_utf16le_invalid_utf8() {
3909 assert!(utf8_to_utf16le(&[0xFF]).is_err());
3910 }
3911
3912 #[test]
3913 fn test_utf8_to_utf16le_empty() {
3914 let result = utf8_to_utf16le(b"").unwrap();
3915 assert!(result.is_empty());
3916 }
3917
3918 #[test]
3921 fn test_latin1_to_utf8_ascii() {
3922 let result = latin1_to_utf8(b"ABC");
3923 assert_eq!(result, b"ABC");
3924 }
3925
3926 #[test]
3927 fn test_latin1_to_utf8_accented() {
3928 let result = latin1_to_utf8(&[0xE9]);
3930 assert_eq!(result, "é".as_bytes());
3931 }
3932
3933 #[test]
3934 fn test_latin1_to_utf8_all_255() {
3935 let result = latin1_to_utf8(&[0xFF]);
3936 assert_eq!(result, [0xC3, 0xBF]);
3938 }
3939
3940 #[test]
3941 fn test_latin1_to_utf8_empty() {
3942 let result = latin1_to_utf8(b"");
3943 assert!(result.is_empty());
3944 }
3945
3946 #[test]
3947 fn test_latin1_to_utf8_mixed() {
3948 let result = latin1_to_utf8(b"caf\xE9");
3949 assert_eq!(result, "café".as_bytes());
3950 }
3951
3952 #[test]
3955 fn test_utf8_to_latin1_ascii() {
3956 let result = utf8_to_latin1(b"ABC").unwrap();
3957 assert_eq!(result, b"ABC");
3958 }
3959
3960 #[test]
3961 fn test_utf8_to_latin1_accented() {
3962 let result = utf8_to_latin1("é".as_bytes()).unwrap();
3963 assert_eq!(result, [0xE9]);
3964 }
3965
3966 #[test]
3967 fn test_utf8_to_latin1_out_of_range() {
3968 assert!(utf8_to_latin1("€".as_bytes()).is_err()); }
3970
3971 #[test]
3972 fn test_utf8_to_latin1_invalid_utf8() {
3973 assert!(utf8_to_latin1(&[0xFF]).is_err());
3974 }
3975
3976 #[test]
3977 fn test_utf8_to_latin1_empty() {
3978 let result = utf8_to_latin1(b"").unwrap();
3979 assert!(result.is_empty());
3980 }
3981
3982 #[test]
3985 fn test_init_and_find_encodings() {
3986 init_encodings();
3987
3988 let utf8_name: *const xmlChar = c"UTF-8".as_ptr() as *const xmlChar;
3989 assert!(!find_encoding_handler(utf8_name).is_null());
3990
3991 let utf16le_name: *const xmlChar = c"UTF-16LE".as_ptr() as *const xmlChar;
3992 assert!(!find_encoding_handler(utf16le_name).is_null());
3993
3994 let utf16be_name: *const xmlChar = c"UTF-16BE".as_ptr() as *const xmlChar;
3995 assert!(!find_encoding_handler(utf16be_name).is_null());
3996
3997 let latin1_name: *const xmlChar = c"ISO-8859-1".as_ptr() as *const xmlChar;
3998 assert!(!find_encoding_handler(latin1_name).is_null());
3999
4000 let ascii_name: *const xmlChar = c"ASCII".as_ptr() as *const xmlChar;
4001 assert!(!find_encoding_handler(ascii_name).is_null());
4002
4003 let lower_name: *const xmlChar = c"utf-8".as_ptr() as *const xmlChar;
4005 assert!(!find_encoding_handler(lower_name).is_null());
4006 }
4007
4008 #[test]
4022 fn test_find_owned_close_keeps_registry_intact() {
4023 init_encodings();
4024 let name: *const xmlChar = c"ISO-8859-1".as_ptr() as *const xmlChar;
4025
4026 let registry = find_encoding_handler(name);
4028 assert!(!registry.is_null());
4029 let h1 = xmlFindCharEncodingHandler_owned(name);
4031 assert!(!h1.is_null());
4032 assert_ne!(h1 as *const c_void, registry as *const c_void);
4033
4034 unsafe {
4037 if !(*h1).name.is_null() {
4038 crate::abi::allocator::xmlFreeImpl((*h1).name as *mut c_void);
4039 }
4040 xmlFreeImpl(h1 as *mut c_void);
4041 }
4042
4043 let registry2 = find_encoding_handler(name);
4048 assert_eq!(registry2 as *const c_void, registry as *const c_void);
4049 assert!(!unsafe { (*registry2).name }.is_null());
4050 let reg_name = unsafe { CStr::from_ptr((*registry2).name as *const c_char) };
4051 assert_eq!(reg_name.to_bytes(), b"ISO-8859-1");
4052
4053 let h2 = xmlFindCharEncodingHandler_owned(name);
4055 assert!(!h2.is_null());
4056 assert_ne!(h2 as *const c_void, registry as *const c_void);
4057 unsafe {
4058 if !(*h2).name.is_null() {
4059 crate::abi::allocator::xmlFreeImpl((*h2).name as *mut c_void);
4060 }
4061 xmlFreeImpl(h2 as *mut c_void);
4062 }
4063 }
4064
4065 #[test]
4071 fn test_find_owned_utf8_static_and_persistent() {
4072 init_encodings();
4073 let name: *const xmlChar = c"UTF-8".as_ptr() as *const xmlChar;
4074 let u1 = xmlFindCharEncodingHandler_owned(name);
4075 assert!(!u1.is_null());
4076 let u2 = xmlFindCharEncodingHandler_owned(c"utf8".as_ptr() as *const xmlChar);
4079 assert_eq!(u1, u2);
4080 assert_eq!(
4081 unsafe { (*u1).flags } & XML_HANDLER_STATIC,
4082 XML_HANDLER_STATIC
4083 );
4084 }
4085
4086 #[test]
4087 fn test_find_encoding_handler_not_found() {
4088 let name: *const xmlChar = c"NONEXISTENT".as_ptr() as *const xmlChar;
4089 assert!(find_encoding_handler(name).is_null());
4090 }
4091
4092 #[test]
4093 fn test_find_encoding_handler_null() {
4094 assert!(find_encoding_handler(ptr::null()).is_null());
4095 }
4096
4097 #[test]
4106 fn test_add_encoding_handler() {
4107 let handler = unsafe {
4108 xmlMallocImpl(size_of::<_xmlCharEncodingHandler>()) as *mut _xmlCharEncodingHandler
4109 };
4110 assert!(!handler.is_null());
4111
4112 let name = unsafe {
4113 crate::abi::allocator::xmlMemStrdupImpl(c"TEST-ENC".as_ptr() as *const c_char)
4114 };
4115 unsafe {
4116 ptr::write(
4117 handler,
4118 _xmlCharEncodingHandler {
4119 name: name as *mut c_char,
4120 input: EncodingInputUnion { legacyFunc: None },
4121 output: EncodingOutputUnion { legacyFunc: None },
4122 inputCtxt: ptr::null_mut(),
4123 outputCtxt: ptr::null_mut(),
4124 ctxtDtor: None,
4125 flags: 0,
4126 },
4127 );
4128 }
4129
4130 assert_eq!(add_encoding_handler(handler), 0);
4131
4132 let found = find_encoding_handler(c"TEST-ENC".as_ptr() as *const xmlChar);
4133 assert_eq!(found, handler);
4134
4135 {
4137 let mut handlers = ENCODING_HANDLERS.write();
4138 handlers.retain(|&h| h.0 != handler);
4139 }
4140
4141 unsafe {
4142 xmlFreeImpl(name as *mut c_void);
4143 xmlFreeImpl(handler as *mut c_void);
4144 }
4145 }
4146
4147 #[test]
4150 fn test_utf16le_roundtrip() {
4151 let original = b"Hello, World! UTF-16LE test: \xC3\xA9\xF0\x9F\x98\x80";
4152 let utf16 = utf8_to_utf16le(original).unwrap();
4153 let back = utf16le_to_utf8(&utf16).unwrap();
4154 assert_eq!(original.to_vec(), back);
4155 }
4156
4157 #[test]
4158 fn test_utf16be_roundtrip() {
4159 let original = b"Hello, World! UTF-16BE test: \xC3\xA9\xF0\x9F\x98\x80";
4160 let utf16le = utf8_to_utf16le(original).unwrap();
4161 let mut utf16be = utf16le.clone();
4163 for chunk in utf16be.as_chunks_mut::<2>().0 {
4164 chunk.swap(0, 1);
4165 }
4166 let back = utf16be_to_utf8(&utf16be).unwrap();
4167 assert_eq!(original.to_vec(), back);
4168 }
4169
4170 #[test]
4171 fn test_latin1_roundtrip() {
4172 let original: Vec<u8> = (0x00..=0xFF).collect();
4173 let utf8 = latin1_to_utf8(&original);
4174 let back = utf8_to_latin1(&utf8).unwrap();
4175 assert_eq!(original, back);
4176 }
4177
4178 #[test]
4188 fn test_utf8_handler_identity() {
4189 let input = b"Hello, UTF-8!";
4190 let mut output = [0u8; 64];
4191 let mut outlen = output.len() as c_int;
4192 let mut inlen = input.len() as c_int;
4193
4194 let ret = unsafe {
4195 utf8_input_func(output.as_mut_ptr(), &mut outlen, input.as_ptr(), &mut inlen)
4196 };
4197
4198 assert_eq!(ret, input.len() as c_int);
4199 assert_eq!(&output[..ret as usize], input);
4200 assert_eq!(inlen, input.len() as c_int);
4201 }
4202
4203 #[test]
4211 fn test_utf16le_handler_roundtrip() {
4212 init_encodings();
4213
4214 let original = b"Hello UTF-16LE!";
4215 let mut utf16_buf = [0u8; 128];
4216 let mut outlen = utf16_buf.len() as c_int;
4217 let mut inlen = original.len() as c_int;
4218
4219 let written = unsafe {
4220 utf16le_output_func(
4221 utf16_buf.as_mut_ptr(),
4222 &mut outlen,
4223 original.as_ptr(),
4224 &mut inlen,
4225 )
4226 };
4227 assert!(written > 0);
4228
4229 let mut decoded = [0u8; 128];
4231 let mut outlen2 = decoded.len() as c_int;
4232 let mut inlen2 = written;
4233
4234 let written2 = unsafe {
4235 utf16le_input_func(
4236 decoded.as_mut_ptr(),
4237 &mut outlen2,
4238 utf16_buf.as_ptr(),
4239 &mut inlen2,
4240 )
4241 };
4242 assert_eq!(written2 as usize, original.len());
4243 assert_eq!(&decoded[..written2 as usize], original);
4244 }
4245
4246 #[test]
4256 fn test_append_to_xml_buffer() {
4257 unsafe {
4258 let content = xmlMallocImpl(64) as *mut xmlChar;
4259 assert!(!content.is_null());
4260
4261 let mut buf = _xmlBuffer {
4262 content,
4263 use_: 0,
4264 size: 64,
4265 alloc: 0,
4266 contentIO: ptr::null_mut(),
4267 };
4268
4269 append_to_xml_buffer(&mut buf, b"Hello");
4270 assert_eq!(buf.use_, 5);
4271 let slice = core::slice::from_raw_parts(buf.content, 5);
4272 assert_eq!(slice, b"Hello");
4273
4274 append_to_xml_buffer(&mut buf, b" World");
4275 assert_eq!(buf.use_, 11);
4276 let slice = core::slice::from_raw_parts(buf.content, 11);
4277 assert_eq!(slice, b"Hello World");
4278
4279 xmlFreeImpl(buf.content as *mut c_void);
4280 }
4281 }
4282
4283 #[test]
4286 fn test_xml_parse_char_encoding() {
4287 let name = c"UTF-8".as_ptr() as *const c_char;
4288 assert_eq!(
4289 xmlParseCharEncoding(name),
4290 xmlCharEncoding::XML_CHAR_ENCODING_UTF8 as c_int
4291 );
4292
4293 let name = c"ISO-8859-1".as_ptr() as *const c_char;
4294 assert_eq!(
4295 xmlParseCharEncoding(name),
4296 xmlCharEncoding::XML_CHAR_ENCODING_8859_1 as c_int
4297 );
4298
4299 assert_eq!(
4300 xmlParseCharEncoding(ptr::null()),
4301 xmlCharEncoding::XML_CHAR_ENCODING_NONE as c_int
4302 );
4303 }
4304
4305 #[test]
4314 fn test_xml_new_and_del_encoding_handler() {
4315 let name = c"TestEnc".as_ptr() as *const c_char;
4316 let handler = xmlNewCharEncodingHandler(
4317 name,
4318 utf8_input_func as xmlCharEncodingInputFunc,
4319 utf8_output_func as xmlCharEncodingOutputFunc,
4320 );
4321 assert!(!handler.is_null());
4322
4323 unsafe {
4324 assert!(!(*handler).name.is_null());
4325 let cstr = CStr::from_ptr((*handler).name);
4326 assert_eq!(cstr.to_bytes(), b"TestEnc");
4327 }
4328
4329 xmlDelEncodingHandler(handler);
4330 }
4331
4332 #[test]
4333 fn test_xml_init_and_cleanup() {
4334 xmlInitCharEncodingHandlers();
4335
4336 let name: *const xmlChar = c"UTF-8".as_ptr() as *const xmlChar;
4337 assert!(!find_encoding_handler(name).is_null());
4338
4339 xmlCleanupCharEncodingHandlers();
4340 }
4342
4343 fn call_func(
4347 func: unsafe extern "C" fn(*mut c_uchar, *mut c_int, *const c_uchar, *mut c_int) -> c_int,
4348 input: &[u8],
4349 ) -> (c_int, Vec<u8>, usize) {
4350 let mut out = vec![0u8; input.len() * 6 + 64];
4351 let mut outlen = out.len() as c_int;
4352 let mut inlen = input.len() as c_int;
4353 let rc = unsafe { func(out.as_mut_ptr(), &mut outlen, input.as_ptr(), &mut inlen) };
4354 out.truncate(outlen.max(0) as usize);
4355 (rc, out, inlen.max(0) as usize)
4356 }
4357
4358 #[test]
4359 fn test_shift_jis_output_roundtrip() {
4360 let (rc, out, consumed) = call_func(shift_jis_output_func, "ぁ漢ア".as_bytes());
4363 assert!(rc >= 0);
4364 assert_eq!(out, [0x82, 0x9F, 0x8A, 0xBF, 0xB1]);
4365 assert_eq!(consumed, "ぁ漢ア".len());
4366
4367 let (rc, back, _) = call_func(shift_jis_input_func, &out);
4368 assert!(rc >= 0);
4369 assert_eq!(back, "ぁ漢ア".as_bytes());
4370 }
4371
4372 #[test]
4373 fn test_shift_jis_output_unmappable_reports_input_error() {
4374 let (rc, out, consumed) = call_func(shift_jis_output_func, "A😀B".as_bytes());
4378 assert_eq!(rc, ENC_INPUT_ERROR);
4379 assert_eq!(out, b"A");
4380 assert_eq!(consumed, 1); let handler = find_encoding_handler(c"SHIFT_JIS".as_ptr() as *const xmlChar);
4385 assert!(!handler.is_null());
4386 let in_buf = crate::xml::io::buf_create(64);
4387 let src = "A\u{1F600}B".as_bytes();
4388 assert!(
4389 crate::xml::io::buf_add(in_buf, src.as_ptr() as *const xmlChar, src.len() as c_int)
4390 >= 0
4391 );
4392 let out_buf = crate::xml::io::buf_create(64);
4393 let n = char_enc_out(handler, out_buf, in_buf);
4394 assert!(n >= 0);
4395 let bytes =
4396 unsafe { core::slice::from_raw_parts((*out_buf).content, (*out_buf).use_ as usize) };
4397 assert_eq!(bytes, b"A😀B");
4398 crate::xml::io::buf_free(in_buf);
4399 crate::xml::io::buf_free(out_buf);
4400 }
4401
4402 #[test]
4403 fn test_euc_jp_output_roundtrip() {
4404 let (rc, out, consumed) = call_func(euc_jp_output_func, "ぁ漢ア".as_bytes());
4407 assert!(rc >= 0);
4408 assert_eq!(out, [0xA4, 0xA1, 0xB4, 0xC1, 0x8E, 0xB1]);
4409 assert_eq!(consumed, "ぁ漢ア".len());
4410
4411 let (rc, back, _) = call_func(euc_jp_input_func, &out);
4412 assert!(rc >= 0);
4413 assert_eq!(back, "ぁ漢ア".as_bytes());
4414 }
4415
4416 #[test]
4417 fn test_east_asian_handlers_registered_and_findable() {
4418 for name in [
4419 c"SHIFT_JIS".as_ptr(),
4420 c"Shift_JIS".as_ptr(),
4421 c"SJIS".as_ptr(),
4422 c"CP932".as_ptr(),
4423 c"EUC-JP".as_ptr(),
4424 c"euc-jp".as_ptr(),
4425 ] {
4426 assert!(
4427 !find_encoding_handler(name as *const xmlChar).is_null(),
4428 "handler not found for {name:?}"
4429 );
4430 }
4431 }
4432
4433 #[test]
4434 fn test_shift_jis_output_invalid_utf8_errors() {
4435 let (rc, out, consumed) = call_func(shift_jis_output_func, b"A\xFFB");
4436 assert_eq!(rc, -1);
4437 assert_eq!(out, b"A");
4438 assert_eq!(consumed, 1);
4439 }
4440
4441 #[test]
4444 fn test_ucs4le_output_matches_utf32le() {
4445 let (rc, out, consumed) = call_func(ucs4le_output_func, "Aあ中".as_bytes());
4447 assert!(rc >= 0);
4448 assert_eq!(out, [0x41, 0, 0, 0, 0x42, 0x30, 0, 0, 0x2D, 0x4E, 0, 0]);
4449 assert_eq!(consumed, "Aあ中".len());
4450 let (rc, back, _) = call_func(ucs4le_input_func, &out);
4451 assert!(rc >= 0);
4452 assert_eq!(back, "Aあ中".as_bytes());
4453 }
4454
4455 #[test]
4456 fn test_ucs4be_output_matches_utf32be() {
4457 let (rc, out, _) = call_func(ucs4be_output_func, "Aあ".as_bytes());
4458 assert!(rc >= 0);
4459 assert_eq!(out, [0, 0, 0, 0x41, 0, 0, 0x30, 0x42]);
4460 let (rc, back, _) = call_func(ucs4be_input_func, &out);
4461 assert!(rc >= 0);
4462 assert_eq!(back, "Aあ".as_bytes());
4463 }
4464
4465 #[test]
4466 fn test_ucs2_output_astral_is_unmappable() {
4467 let (rc, out, consumed) = call_func(ucs2_output_func, "A😀".as_bytes());
4470 assert_eq!(rc, ENC_INPUT_ERROR);
4471 assert_eq!(out, [0x41, 0]);
4472 assert_eq!(consumed, 1);
4473 }
4474
4475 #[test]
4476 fn test_ebcdic037_bijection() {
4477 let (rc, out, _) = call_func(ebcdic_output_func, b"A 0");
4479 assert!(rc >= 0);
4480 assert_eq!(out, [0xC1, 0x40, 0xF0]);
4481 let (rc, back, _) = call_func(ebcdic_input_func, &out);
4482 assert!(rc >= 0);
4483 assert_eq!(back, b"A 0");
4484 for (b, cp) in EBCDIC037_TO_UNICODE.iter().enumerate() {
4487 assert_eq!(ebcdic037_cp_to_byte(u32::from(*cp)), Some(b as u8));
4488 }
4489 assert!(ebcdic037_cp_to_byte(0x100).is_none());
4490 }
4491
4492 #[test]
4493 fn test_iso_8859_2_output_roundtrip() {
4494 let (rc, out, _) = call_func(iso_8859_2_output_func, "Aąćę".as_bytes());
4496 assert!(rc >= 0);
4497 assert_eq!(out, [0x41, 0xB1, 0xE6, 0xEA]);
4498 let (rc, back, _) = call_func(iso_8859_2_input_func, &out);
4499 assert!(rc >= 0);
4500 assert_eq!(back, "Aąćę".as_bytes());
4501 }
4502
4503 #[test]
4504 fn test_decode_whole_buffer_declared_dispatch() {
4505 let iso2 = [0x41u8, 0xB1, 0xE6, 0xEA];
4507 assert_eq!(
4508 decode_whole_buffer_declared(b"ISO-8859-2", &iso2).unwrap(),
4509 "Aąćę".as_bytes()
4510 );
4511 assert_eq!(
4513 decode_whole_buffer_declared(b"latin2", &iso2).unwrap(),
4514 "Aąćę".as_bytes()
4515 );
4516 assert!(decode_whole_buffer_declared(b"no-such-encoding", b"abc").is_err());
4518 }
4519
4520 #[test]
4521 fn test_iso_2022_jp_output_uses_escape_sequences() {
4522 let (rc, out, consumed) = call_func(iso_2022_jp_output_func, "AあB".as_bytes());
4524 assert!(rc >= 0);
4525 assert_eq!(out, b"A\x1B$B$\"\x1B(BB");
4526 assert_eq!(consumed, "AあB".len());
4527 let (rc, back, _) = call_func(iso_2022_jp_input_func, &out);
4528 assert!(rc >= 0);
4529 assert_eq!(back, "AあB".as_bytes());
4530 }
4531}