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