Skip to main content

anyxml_encoding/
lib.rs

1//! Provide a unified interface for encoders and decoders,
2//! and a default implementation for some encodings.
3//!
4//! If it is necessary to provide a custom decoder for XML processor, a type implementing
5//! the [`Decoder`] trait can be registered using the [`register_decoder`] function.
6//!
7//! By default, the encoding name provided to the [`register_encoder`] or [`register_decoder`]
8//! function is used to search for encoders and decoders.  \
9//! If it is necessary to assign multiple names to a single encoder or decoder,
10//! it is possible to set aliases for encoding names using [`register_encoding_alias`].
11//!
12//! The default encoding names and aliases are based on
13//! [IANA registrations](https://www.iana.org/assignments/character-sets/character-sets.xhtml).
14
15mod big5;
16mod ebcdic;
17mod euc;
18mod iso_8859;
19mod jisx;
20mod ksx;
21mod shift_jis;
22mod ucs4;
23mod us_ascii;
24mod utf16;
25mod utf8;
26
27use std::{
28    borrow::Cow,
29    collections::BTreeMap,
30    sync::{LazyLock, RwLock},
31};
32
33pub use big5::*;
34pub use ebcdic::*;
35pub use euc::*;
36pub use iso_8859::*;
37pub use shift_jis::*;
38pub use ucs4::*;
39pub use us_ascii::*;
40pub use utf8::*;
41pub use utf16::*;
42
43/// Encode error.
44#[derive(Debug, Clone)]
45pub enum EncodeError {
46    /// Input buffer is empty.
47    InputIsEmpty,
48    /// The length of the output buffer is too short.  \
49    /// If this error is returned, it is guaranteed that the encoder is consuming the input buffer.
50    OutputTooShort,
51    /// A UTF-8 character `c` cannot map any codepoints of the target encoding.
52    ///
53    /// The input and output buffer have consumed `read` and `write` bytes respectively.  \
54    /// `read` includes the length of `c`. Thus, the correctly read length is `read - c.len_utf8()`.  \
55    /// `write` does not include the length of `c` because encoder cannot write unmapped characters.
56    Unmappable { read: usize, write: usize, c: char },
57    /// Other errors.
58    Other { msg: Cow<'static, str> },
59}
60
61impl std::fmt::Display for EncodeError {
62    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63        write!(f, "{self:?}")
64    }
65}
66
67impl std::error::Error for EncodeError {}
68
69pub trait Encoder {
70    fn name(&self) -> &'static str;
71    /// If no error occurs, return `Ok((read_bytes, write_bytes))`.
72    fn encode(
73        &mut self,
74        src: &str,
75        dst: &mut [u8],
76        finish: bool,
77    ) -> Result<(usize, usize), EncodeError>;
78}
79
80/// Decode error.
81#[derive(Debug, Clone)]
82pub enum DecodeError {
83    /// Input buffer is empty.
84    InputIsEmpty,
85    /// The length of the output buffer is too short.  \
86    /// If this error is returned, it is guaranteed that the decoder is consuming the input buffer.
87    OutputTooShort,
88    /// Malformed byte sequence is found.
89    ///
90    /// The input and output buffer have consumed `read` and `write` bytes respectively.  \
91    /// Malformed sequence occurs `input[read-length-offset..read-offset]`.
92    Malformed {
93        read: usize,
94        write: usize,
95        length: usize,
96        offset: usize,
97    },
98    /// Other errors.
99    Other { msg: Cow<'static, str> },
100}
101
102impl std::fmt::Display for DecodeError {
103    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104        write!(f, "{self:?}")
105    }
106}
107
108impl std::error::Error for DecodeError {}
109
110pub trait Decoder {
111    fn name(&self) -> &'static str;
112    /// If no error occurs, return `Ok((read_bytes, write_bytes))`.
113    fn decode(
114        &mut self,
115        src: &[u8],
116        dst: &mut String,
117        finish: bool,
118    ) -> Result<(usize, usize), DecodeError>;
119}
120
121/// Supported encodings.
122///
123/// Encoding names are listed in lexical order.
124pub const DEFAULT_SUPPORTED_ENCODINGS: &[&str] = {
125    const NAMES: &[&str] = &[
126        BIG5_NAME,
127        EUCJP_NAME,
128        EUCKR_NAME,
129        IBM037,
130        IBM1026,
131        IBM273,
132        IBM274,
133        IBM275,
134        IBM277,
135        IBM278,
136        IBM280,
137        IBM284,
138        IBM285,
139        IBM290,
140        IBM297,
141        IBM420,
142        IBM423,
143        IBM424,
144        IBM437,
145        IBM500,
146        IBM850,
147        IBM851,
148        IBM852,
149        IBM855,
150        IBM857,
151        IBM860,
152        IBM861,
153        IBM862,
154        IBM863,
155        IBM864,
156        IBM865,
157        IBM868,
158        IBM869,
159        IBM870,
160        IBM871,
161        IBM880,
162        IBM891,
163        IBM903,
164        IBM904,
165        IBM905,
166        IBM918,
167        ISO_8859_10_NAME,
168        ISO_8859_13_NAME,
169        ISO_8859_14_NAME,
170        ISO_8859_15_NAME,
171        ISO_8859_16_NAME,
172        ISO_8859_1_NAME,
173        ISO_8859_2_NAME,
174        ISO_8859_3_NAME,
175        ISO_8859_4_NAME,
176        ISO_8859_5_NAME,
177        ISO_8859_6_NAME,
178        ISO_8859_7_NAME,
179        ISO_8859_8_NAME,
180        ISO_8859_9_NAME,
181        SHIFT_JIS_NAME,
182        ISO_8859_11_NAME,
183        US_ASCII_NAME,
184        UTF16_NAME,
185        UTF16BE_NAME,
186        UTF16LE_NAME,
187        UTF32_NAME,
188        UTF32BE_NAME,
189        UTF32LE_NAME,
190        UTF8_NAME,
191    ];
192    let len = NAMES.len();
193    let mut i = 0;
194    while i + 1 < len {
195        let x = NAMES[i].as_bytes();
196        let y = NAMES[i + 1].as_bytes();
197        let mut j = 0;
198        while j < x.len() {
199            assert!(x[j] <= y[j]);
200            if x[j] < y[j] {
201                break;
202            }
203            j += 1;
204            if j == x.len() {
205                break;
206            }
207            assert!(j < y.len());
208        }
209        i += 1;
210    }
211    NAMES
212};
213/// Manage aliases for encoding names.
214pub static ENCODING_ALIASES: LazyLock<RwLock<BTreeMap<Cow<'static, str>, &'static str>>> =
215    LazyLock::new(|| {
216        // To perform case-insensitive comparisons, capitalize all aliases.
217        RwLock::new(BTreeMap::from([
218            ("UTF8".into(), UTF8_NAME),
219            ("UTF16".into(), UTF16_NAME),
220            ("UTF16BE".into(), UTF16BE_NAME),
221            ("UTF16LE".into(), UTF16LE_NAME),
222            ("ISO-IR-100".into(), ISO_8859_1_NAME),
223            ("ISO_8859-1".into(), ISO_8859_1_NAME),
224            ("ISO-8859-1".into(), ISO_8859_1_NAME),
225            ("LATIN1".into(), ISO_8859_1_NAME),
226            ("L1".into(), ISO_8859_1_NAME),
227            ("IBM819".into(), ISO_8859_1_NAME),
228            ("CP819".into(), ISO_8859_1_NAME),
229            ("ISOLATIN1".into(), ISO_8859_1_NAME),
230            ("ISO-IR-101".into(), ISO_8859_2_NAME),
231            ("ISO_8859-2".into(), ISO_8859_2_NAME),
232            ("ISO-8859-2".into(), ISO_8859_2_NAME),
233            ("LATIN2".into(), ISO_8859_2_NAME),
234            ("L2".into(), ISO_8859_2_NAME),
235            ("ISOLATIN2".into(), ISO_8859_2_NAME),
236            ("ISO-IR-109".into(), ISO_8859_3_NAME),
237            ("ISO_8859-3".into(), ISO_8859_3_NAME),
238            ("ISO-8859-3".into(), ISO_8859_3_NAME),
239            ("LATIN3".into(), ISO_8859_3_NAME),
240            ("L3".into(), ISO_8859_3_NAME),
241            ("ISOLATIN3".into(), ISO_8859_3_NAME),
242            ("ISO-IR-110".into(), ISO_8859_4_NAME),
243            ("ISO_8859-4".into(), ISO_8859_4_NAME),
244            ("ISO-8859-4".into(), ISO_8859_4_NAME),
245            ("LATIN4".into(), ISO_8859_4_NAME),
246            ("L4".into(), ISO_8859_4_NAME),
247            ("ISOLATIN4".into(), ISO_8859_4_NAME),
248            ("ISO-IR-144".into(), ISO_8859_5_NAME),
249            ("ISO_8859-5".into(), ISO_8859_5_NAME),
250            ("ISO-8859-5".into(), ISO_8859_5_NAME),
251            ("CYRILLIC".into(), ISO_8859_5_NAME),
252            ("ISOLATINCYRILLIC".into(), ISO_8859_5_NAME),
253            ("ISO-IR-127".into(), ISO_8859_6_NAME),
254            ("ISO_8859-6".into(), ISO_8859_6_NAME),
255            ("ISO-8859-6".into(), ISO_8859_6_NAME),
256            ("ECMA-114".into(), ISO_8859_6_NAME),
257            ("ASMO-708".into(), ISO_8859_6_NAME),
258            ("ARABIC".into(), ISO_8859_6_NAME),
259            ("ISOLATINARABIC".into(), ISO_8859_6_NAME),
260            ("ISO-IR-126".into(), ISO_8859_7_NAME),
261            ("ISO_8859-7".into(), ISO_8859_7_NAME),
262            ("ISO-8859-7".into(), ISO_8859_7_NAME),
263            ("ELOT_928".into(), ISO_8859_7_NAME),
264            ("ECMA-118".into(), ISO_8859_7_NAME),
265            ("GREEK".into(), ISO_8859_7_NAME),
266            ("GREEK8".into(), ISO_8859_7_NAME),
267            ("ISOLATINGREEK".into(), ISO_8859_7_NAME),
268            ("ISO-IR-138".into(), ISO_8859_8_NAME),
269            ("ISO_8859-8".into(), ISO_8859_8_NAME),
270            ("ISO-8859-8".into(), ISO_8859_8_NAME),
271            ("HEBREW".into(), ISO_8859_8_NAME),
272            ("ISOLATINHEBREW".into(), ISO_8859_8_NAME),
273            ("ISO-IR-148".into(), ISO_8859_9_NAME),
274            ("ISO_8859-9".into(), ISO_8859_9_NAME),
275            ("ISO-8859-9".into(), ISO_8859_9_NAME),
276            ("LATIN5".into(), ISO_8859_9_NAME),
277            ("L5".into(), ISO_8859_9_NAME),
278            ("ISOLATIN5".into(), ISO_8859_9_NAME),
279            ("ISO-IR-157".into(), ISO_8859_10_NAME),
280            ("L6".into(), ISO_8859_10_NAME),
281            ("ISO_8859-10:1992".into(), ISO_8859_10_NAME),
282            ("ISOLATIN6".into(), ISO_8859_10_NAME),
283            ("LATIN6".into(), ISO_8859_10_NAME),
284            ("TIS620".into(), ISO_8859_11_NAME),
285            ("ISO-8859-11".into(), ISO_8859_11_NAME),
286            ("ISO885913".into(), ISO_8859_13_NAME),
287            ("ISO-IR-199".into(), ISO_8859_14_NAME),
288            ("ISO_8859-14:1998".into(), ISO_8859_14_NAME),
289            ("ISO_8859-14".into(), ISO_8859_14_NAME),
290            ("LATIN8".into(), ISO_8859_14_NAME),
291            ("ISO-CELTIC".into(), ISO_8859_14_NAME),
292            ("L8".into(), ISO_8859_14_NAME),
293            ("ISO885914".into(), ISO_8859_14_NAME),
294            ("ISO_8859-15".into(), ISO_8859_15_NAME),
295            ("LATIN-9".into(), ISO_8859_15_NAME),
296            ("ISO885915".into(), ISO_8859_15_NAME),
297            ("ISO-IR-226".into(), ISO_8859_16_NAME),
298            ("ISO_8859-16:2001".into(), ISO_8859_16_NAME),
299            ("ISO_8859-16".into(), ISO_8859_16_NAME),
300            ("LATIN10".into(), ISO_8859_16_NAME),
301            ("L10".into(), ISO_8859_16_NAME),
302            ("ISO885916".into(), ISO_8859_16_NAME),
303            ("UTF32".into(), UTF32_NAME),
304            ("UTF32BE".into(), UTF32BE_NAME),
305            ("UTF32LE".into(), UTF32LE_NAME),
306            ("MS_KANJI".into(), SHIFT_JIS_NAME),
307            ("SHIFTJIS".into(), SHIFT_JIS_NAME),
308            ("ISO-IR-6".into(), US_ASCII_NAME),
309            ("ANSI_X3.4-1968".into(), US_ASCII_NAME),
310            ("ANSI_X3.4-1986".into(), US_ASCII_NAME),
311            ("ISO_646.IRV:1991".into(), US_ASCII_NAME),
312            ("ISO646-US".into(), US_ASCII_NAME),
313            ("US-ASCII".into(), US_ASCII_NAME),
314            ("US".into(), US_ASCII_NAME),
315            ("IBM367".into(), US_ASCII_NAME),
316            ("CP367".into(), US_ASCII_NAME),
317            ("ASCII".into(), US_ASCII_NAME),
318            ("CP037".into(), IBM037),
319            ("EBCDIC-CP-US".into(), IBM037),
320            ("EBCDIC-CP-CA".into(), IBM037),
321            ("EBCDIC-CP-WT".into(), IBM037),
322            ("EBCDIC-CP-NL".into(), IBM037),
323            ("CP273".into(), IBM273),
324            ("EBCDIC-BE".into(), IBM274),
325            ("CP274".into(), IBM274),
326            ("EBCDIC-BR".into(), IBM275),
327            ("CP275".into(), IBM275),
328            ("EBCDIC-CP-DK".into(), IBM277),
329            ("EBCDIC-CP-NO".into(), IBM277),
330            ("CP278".into(), IBM278),
331            ("EBCDIC-CP-FI".into(), IBM278),
332            ("EBCDIC-CP-SE".into(), IBM278),
333            ("CP280".into(), IBM280),
334            ("EBCDIC-CP-IT".into(), IBM280),
335            ("CP284".into(), IBM284),
336            ("EBCDIC-CP-ES".into(), IBM284),
337            ("CP285".into(), IBM285),
338            ("EBCDIC-CP-GB".into(), IBM285),
339            ("CP290".into(), IBM290),
340            ("EBCDIC-JP-KANA".into(), IBM290),
341            ("CP297".into(), IBM297),
342            ("EBCDIC-CP-FR".into(), IBM297),
343            ("CP420".into(), IBM420),
344            ("EBCDIC-CP-AR1".into(), IBM420),
345            ("CP423".into(), IBM423),
346            ("EBCDIC-CP-GR".into(), IBM423),
347            ("CP424".into(), IBM424),
348            ("EBCDIC-CP-HE".into(), IBM424),
349            ("CP437".into(), IBM437),
350            ("437".into(), IBM437),
351            ("PC8CODEPAGE437".into(), IBM437),
352            ("CP500".into(), IBM500),
353            ("EBCDIC-CP-BE".into(), IBM500),
354            ("EBCDIC-CP-CH".into(), IBM500),
355            ("CP851".into(), IBM851),
356            ("851".into(), IBM851),
357            ("CP852".into(), IBM852),
358            ("852".into(), IBM852),
359            ("PCP852".into(), IBM852),
360            ("CP855".into(), IBM855),
361            ("855".into(), IBM855),
362            ("CP857".into(), IBM857),
363            ("857".into(), IBM857),
364            ("CP860".into(), IBM860),
365            ("860".into(), IBM860),
366            ("CP861".into(), IBM861),
367            ("861".into(), IBM861),
368            ("CP-IS".into(), IBM861),
369            ("CP863".into(), IBM863),
370            ("863".into(), IBM863),
371            ("CP864".into(), IBM864),
372            ("CP865".into(), IBM865),
373            ("865".into(), IBM865),
374            ("CP868".into(), IBM868),
375            ("CP-AR".into(), IBM868),
376            ("CP869".into(), IBM869),
377            ("869".into(), IBM869),
378            ("CP-GR".into(), IBM869),
379            ("CP870".into(), IBM870),
380            ("EBCDIC-CP-ROECE".into(), IBM870),
381            ("EBCDIC-CP-YU".into(), IBM870),
382            ("CP871".into(), IBM871),
383            ("EBCDIC-CP-IS".into(), IBM871),
384            ("CP880".into(), IBM880),
385            ("EBCDIC-CYRILLIC".into(), IBM880),
386            ("CP891".into(), IBM891),
387            ("CP903".into(), IBM903),
388            ("CP904".into(), IBM904),
389            ("904".into(), IBM904),
390            // is this correct ????
391            // But since it really says "IBBM", I'll just list it for now...
392            ("IBBM904".into(), IBM904),
393            ("CP905".into(), IBM905),
394            ("EBCDIC-CP-TR".into(), IBM905),
395            ("CP918".into(), IBM918),
396            ("EBCDIC-CP-AR2".into(), IBM918),
397            ("CP1026".into(), IBM1026),
398            ("EUCPKDFMTJAPANESE".into(), EUCJP_NAME),
399            ("EUCKR".into(), EUCKR_NAME),
400        ]))
401    });
402/// Register `alias` as an alias for the encoding name `real`.  \
403/// If `alias` is already an alias for another encoding name, overwrite it and return
404/// the encoding name before the overwrite.
405///
406/// It is assumed that real names and aliases will be linked based on the IANA list,
407/// but this is not required.  \
408/// However, since aliases do not redirect multiple times, `real` must be the name registered
409/// with the encoder/decoder.
410///
411/// If an encoding name becomes both a real name and an alias, searches may not work properly.
412///
413/// Reference: [Charcter sets registered by IANA](https://www.iana.org/assignments/character-sets/character-sets.xhtml)
414pub fn register_encoding_alias(alias: &'static str, real: &'static str) -> Option<&'static str> {
415    let mut table = ENCODING_ALIASES.write().unwrap();
416    if alias.chars().all(|c| c.is_ascii_uppercase()) {
417        table.insert(alias.into(), real)
418    } else {
419        table.insert(alias.to_ascii_uppercase().into(), real)
420    }
421}
422/// Unregister `alias` if it is registerd as an alias for an encoding name.  \
423/// If successfully removed, return the real name.
424pub fn unregister_encoding_alias(alias: &'static str) -> Option<&'static str> {
425    ENCODING_ALIASES
426        .write()
427        .unwrap()
428        .remove(alias.to_ascii_uppercase().as_str())
429}
430/// Retrieve the encoding name from `alias`, which is an alias for a certain encoding name.  \
431/// If retrieval fails, returns [`None`].
432///
433/// Alias comparisons are case-insensitive.
434pub fn resolve_encoding_alias(alias: &str) -> Option<&'static str> {
435    let aliases = ENCODING_ALIASES.read().unwrap();
436    aliases
437        .get(alias)
438        .or_else(|| aliases.get(alias.to_ascii_uppercase().as_str()))
439        .copied()
440}
441
442pub type EncoderFactory = fn() -> Box<dyn Encoder>;
443pub static ENCODER_TABLE: LazyLock<RwLock<BTreeMap<&'static str, EncoderFactory>>> =
444    LazyLock::new(|| {
445        let mut map = BTreeMap::<&'static str, EncoderFactory>::new();
446        map.insert(UTF8_NAME, || Box::new(UTF8Encoder));
447        map.insert(UTF16_NAME, || Box::new(UTF16Encoder::default()));
448        map.insert(UTF16BE_NAME, || Box::new(UTF16BEEncoder));
449        map.insert(UTF16LE_NAME, || Box::new(UTF16LEEncoder));
450        map.insert(ISO_8859_1_NAME, || Box::new(ISO8859_1Encoder));
451        map.insert(ISO_8859_2_NAME, || Box::new(ISO8859_2Encoder));
452        map.insert(ISO_8859_3_NAME, || Box::new(ISO8859_3Encoder));
453        map.insert(ISO_8859_4_NAME, || Box::new(ISO8859_4Encoder));
454        map.insert(ISO_8859_5_NAME, || Box::new(ISO8859_5Encoder));
455        map.insert(ISO_8859_6_NAME, || Box::new(ISO8859_6Encoder));
456        map.insert(ISO_8859_7_NAME, || Box::new(ISO8859_7Encoder));
457        map.insert(ISO_8859_8_NAME, || Box::new(ISO8859_8Encoder));
458        map.insert(ISO_8859_9_NAME, || Box::new(ISO8859_9Encoder));
459        map.insert(ISO_8859_10_NAME, || Box::new(ISO8859_10Encoder));
460        map.insert(ISO_8859_11_NAME, || Box::new(ISO8859_11Encoder));
461        map.insert(ISO_8859_13_NAME, || Box::new(ISO8859_13Encoder));
462        map.insert(ISO_8859_14_NAME, || Box::new(ISO8859_14Encoder));
463        map.insert(ISO_8859_15_NAME, || Box::new(ISO8859_15Encoder));
464        map.insert(ISO_8859_16_NAME, || Box::new(ISO8859_16Encoder));
465        map.insert(UTF32_NAME, || Box::new(UTF32Encoder::default()));
466        map.insert(UTF32BE_NAME, || Box::new(UTF32BEEncoder));
467        map.insert(UTF32LE_NAME, || Box::new(UTF32LEEncoder));
468        map.insert(SHIFT_JIS_NAME, || Box::new(ShiftJISEncoder));
469        map.insert(US_ASCII_NAME, || Box::new(USASCIIEncoder));
470        map.insert(IBM037, || Box::new(IBM037Encoder));
471        map.insert(IBM273, || Box::new(IBM273Encoder));
472        map.insert(IBM274, || Box::new(IBM274Encoder));
473        map.insert(IBM275, || Box::new(IBM275Encoder));
474        map.insert(IBM277, || Box::new(IBM277Encoder));
475        map.insert(IBM278, || Box::new(IBM278Encoder));
476        map.insert(IBM280, || Box::new(IBM280Encoder));
477        map.insert(IBM284, || Box::new(IBM284Encoder));
478        map.insert(IBM285, || Box::new(IBM285Encoder));
479        map.insert(IBM290, || Box::new(IBM290Encoder));
480        map.insert(IBM297, || Box::new(IBM297Encoder));
481        map.insert(IBM420, || Box::new(IBM420Encoder));
482        map.insert(IBM423, || Box::new(IBM423Encoder));
483        map.insert(IBM424, || Box::new(IBM424Encoder));
484        map.insert(IBM437, || Box::new(IBM437Encoder));
485        map.insert(IBM500, || Box::new(IBM500Encoder));
486        map.insert(IBM850, || Box::new(IBM850Encoder));
487        map.insert(IBM851, || Box::new(IBM851Encoder));
488        map.insert(IBM852, || Box::new(IBM852Encoder));
489        map.insert(IBM855, || Box::new(IBM855Encoder));
490        map.insert(IBM857, || Box::new(IBM857Encoder));
491        map.insert(IBM860, || Box::new(IBM860Encoder));
492        map.insert(IBM861, || Box::new(IBM861Encoder));
493        map.insert(IBM862, || Box::new(IBM862Encoder));
494        map.insert(IBM863, || Box::new(IBM863Encoder));
495        map.insert(IBM864, || Box::new(IBM864Encoder));
496        map.insert(IBM865, || Box::new(IBM865Encoder));
497        map.insert(IBM868, || Box::new(IBM868Encoder));
498        map.insert(IBM869, || Box::new(IBM869Encoder));
499        map.insert(IBM870, || Box::new(IBM870Encoder));
500        map.insert(IBM871, || Box::new(IBM871Encoder));
501        map.insert(IBM880, || Box::new(IBM880Encoder));
502        map.insert(IBM891, || Box::new(IBM891Encoder));
503        map.insert(IBM903, || Box::new(IBM903Encoder));
504        map.insert(IBM904, || Box::new(IBM904Encoder));
505        map.insert(IBM905, || Box::new(IBM905Encoder));
506        map.insert(IBM918, || Box::new(IBM918Encoder));
507        map.insert(IBM1026, || Box::new(IBM1026Encoder));
508        map.insert(EUCJP_NAME, eucjp_encoder_factory);
509        map.insert(EUCKR_NAME, euckr_encoder_factory);
510        map.insert(BIG5_NAME, || Box::new(Big5Encoder));
511        RwLock::new(map)
512    });
513pub fn find_encoder(encoding_name: &str) -> Option<Box<dyn Encoder>> {
514    let table = ENCODER_TABLE.read().unwrap();
515    if let Some(factory) = table.get(encoding_name) {
516        return Some(factory());
517    }
518    if let Some(factory) = table.get(encoding_name.to_ascii_uppercase().as_str()) {
519        return Some(factory());
520    }
521
522    let alias = resolve_encoding_alias(encoding_name)?;
523    table.get(alias).map(|f| f())
524}
525pub fn register_encoder(
526    encoding_name: &'static str,
527    factory: EncoderFactory,
528) -> Option<EncoderFactory> {
529    ENCODER_TABLE
530        .write()
531        .unwrap()
532        .insert(encoding_name, factory)
533}
534pub fn unregister_encoder(encoding_name: &str) -> Option<EncoderFactory> {
535    ENCODER_TABLE.write().unwrap().remove(encoding_name)
536}
537
538pub type DecoderFactory = fn() -> Box<dyn Decoder>;
539pub static DECODER_TABLE: LazyLock<RwLock<BTreeMap<&'static str, DecoderFactory>>> =
540    LazyLock::new(|| {
541        let mut map = BTreeMap::<&'static str, DecoderFactory>::new();
542        map.insert(UTF8_NAME, || Box::new(UTF8Decoder));
543        map.insert(UTF16_NAME, || Box::new(UTF16Decoder::default()));
544        map.insert(UTF16BE_NAME, || Box::new(UTF16BEDecoder));
545        map.insert(UTF16LE_NAME, || Box::new(UTF16LEDecoder));
546        map.insert(ISO_8859_1_NAME, || Box::new(ISO8859_1Decoder));
547        map.insert(ISO_8859_2_NAME, || Box::new(ISO8859_2Decoder));
548        map.insert(ISO_8859_3_NAME, || Box::new(ISO8859_3Decoder));
549        map.insert(ISO_8859_4_NAME, || Box::new(ISO8859_4Decoder));
550        map.insert(ISO_8859_5_NAME, || Box::new(ISO8859_5Decoder));
551        map.insert(ISO_8859_6_NAME, || Box::new(ISO8859_6Decoder));
552        map.insert(ISO_8859_7_NAME, || Box::new(ISO8859_7Decoder));
553        map.insert(ISO_8859_8_NAME, || Box::new(ISO8859_8Decoder));
554        map.insert(ISO_8859_9_NAME, || Box::new(ISO8859_9Decoder));
555        map.insert(ISO_8859_10_NAME, || Box::new(ISO8859_10Decoder));
556        map.insert(ISO_8859_11_NAME, || Box::new(ISO8859_11Decoder));
557        map.insert(ISO_8859_13_NAME, || Box::new(ISO8859_13Decoder));
558        map.insert(ISO_8859_14_NAME, || Box::new(ISO8859_14Decoder));
559        map.insert(ISO_8859_15_NAME, || Box::new(ISO8859_15Decoder));
560        map.insert(ISO_8859_16_NAME, || Box::new(ISO8859_16Decoder));
561        map.insert(UTF32_NAME, || Box::new(UTF32Decoder::default()));
562        map.insert(UTF32BE_NAME, || Box::new(UTF32BEDecoder));
563        map.insert(UTF32LE_NAME, || Box::new(UTF32LEDecoder));
564        map.insert(SHIFT_JIS_NAME, || Box::new(ShiftJISDecoder));
565        map.insert(US_ASCII_NAME, || Box::new(USASCIIDecoder));
566        map.insert(IBM037, || Box::new(IBM037Decoder));
567        map.insert(IBM273, || Box::new(IBM273Decoder));
568        map.insert(IBM274, || Box::new(IBM274Decoder));
569        map.insert(IBM275, || Box::new(IBM275Decoder));
570        map.insert(IBM277, || Box::new(IBM277Decoder));
571        map.insert(IBM278, || Box::new(IBM278Decoder));
572        map.insert(IBM280, || Box::new(IBM280Decoder));
573        map.insert(IBM284, || Box::new(IBM284Decoder));
574        map.insert(IBM285, || Box::new(IBM285Decoder));
575        map.insert(IBM290, || Box::new(IBM290Decoder));
576        map.insert(IBM297, || Box::new(IBM297Decoder));
577        map.insert(IBM420, || Box::new(IBM420Decoder));
578        map.insert(IBM423, || Box::new(IBM423Decoder));
579        map.insert(IBM424, || Box::new(IBM424Decoder));
580        map.insert(IBM437, || Box::new(IBM437Decoder));
581        map.insert(IBM500, || Box::new(IBM500Decoder));
582        map.insert(IBM850, || Box::new(IBM850Decoder));
583        map.insert(IBM851, || Box::new(IBM851Decoder));
584        map.insert(IBM852, || Box::new(IBM852Decoder));
585        map.insert(IBM855, || Box::new(IBM855Decoder));
586        map.insert(IBM857, || Box::new(IBM857Decoder));
587        map.insert(IBM860, || Box::new(IBM860Decoder));
588        map.insert(IBM861, || Box::new(IBM861Decoder));
589        map.insert(IBM862, || Box::new(IBM862Decoder));
590        map.insert(IBM863, || Box::new(IBM863Decoder));
591        map.insert(IBM864, || Box::new(IBM864Decoder));
592        map.insert(IBM865, || Box::new(IBM865Decoder));
593        map.insert(IBM868, || Box::new(IBM868Decoder));
594        map.insert(IBM869, || Box::new(IBM869Decoder));
595        map.insert(IBM870, || Box::new(IBM870Decoder));
596        map.insert(IBM871, || Box::new(IBM871Decoder));
597        map.insert(IBM880, || Box::new(IBM880Decoder));
598        map.insert(IBM891, || Box::new(IBM891Decoder));
599        map.insert(IBM903, || Box::new(IBM903Decoder));
600        map.insert(IBM904, || Box::new(IBM904Decoder));
601        map.insert(IBM905, || Box::new(IBM905Decoder));
602        map.insert(IBM918, || Box::new(IBM918Decoder));
603        map.insert(IBM1026, || Box::new(IBM1026Decoder));
604        map.insert(EUCJP_NAME, eucjp_decoder_factory);
605        map.insert(EUCKR_NAME, euckr_decoder_factory);
606        map.insert(BIG5_NAME, || Box::new(Big5Decoder));
607        RwLock::new(map)
608    });
609pub fn find_decoder(encoding_name: &str) -> Option<Box<dyn Decoder>> {
610    let table = DECODER_TABLE.read().unwrap();
611    if let Some(factory) = table.get(encoding_name) {
612        return Some(factory());
613    }
614    if let Some(factory) = table.get(encoding_name.to_ascii_uppercase().as_str()) {
615        return Some(factory());
616    }
617
618    let alias = resolve_encoding_alias(encoding_name)?;
619    table.get(alias).map(|f| f())
620}
621pub fn register_decoder(
622    encoding_name: &'static str,
623    factory: DecoderFactory,
624) -> Option<DecoderFactory> {
625    DECODER_TABLE
626        .write()
627        .unwrap()
628        .insert(encoding_name, factory)
629}
630pub fn unregister_decoder(encoding_name: &str) -> Option<DecoderFactory> {
631    DECODER_TABLE.write().unwrap().remove(encoding_name)
632}