textcode/
iso8859.rs

1use std::io::Write;
2
3use crate::{
4    ENCODE_FALLBACK,
5    Textcode,
6    write_ascii,
7    write_utf8,
8};
9
10fn decode_inner<W: Write>(src: &[u8], dst: &mut W, map: &[u16]) -> std::io::Result<usize> {
11    let mut written = 0;
12
13    for &c in src {
14        if c <= 0x7F {
15            written += write_ascii(dst, c)?;
16        } else if c >= 0xA0 {
17            let offset = c as usize - 0xA0;
18            let u = map[offset] as u32;
19            written += write_utf8(dst, u)?;
20        }
21    }
22
23    Ok(written)
24}
25
26fn encode_inner<W: Write>(
27    src: &str,
28    dst: &mut W,
29    hi_map: &[usize],
30    map: &[u8],
31) -> std::io::Result<usize> {
32    let mut written = 0;
33
34    for ch in src.chars() {
35        let u = u32::from(ch) as u16;
36        let c;
37
38        if u <= 0x7F {
39            c = u as u8;
40        } else if u >= 0xA0 {
41            let hi = usize::from(u >> 8);
42            let lo = usize::from(u & 0xFF);
43
44            let pos = hi_map[hi] * 0x100 + lo;
45            let code = map[pos];
46
47            if code != 0x0000 {
48                c = code;
49            } else {
50                c = ENCODE_FALLBACK;
51            }
52        } else {
53            c = ENCODE_FALLBACK;
54        }
55
56        dst.write_all(&[c])?;
57        written += 1;
58    }
59
60    Ok(written)
61}
62
63macro_rules! iso8859 {
64    ( $($struct_name: ident, $decode_map: ident, $hi_map: ident, $encode_map: ident),* ) => {
65        $(
66            /// ISO-8859 encoding implementation.
67            pub struct $struct_name;
68
69            impl Textcode for $struct_name {
70                fn decode<W: Write, R: AsRef<[u8]>>(src: R, dst: &mut W) -> std::io::Result<usize> {
71                    decode_inner(src.as_ref(), dst, &crate::data::$decode_map)
72                }
73
74                fn encode<W: Write, R: AsRef<str>>(src: R, dst: &mut W) -> std::io::Result<usize> {
75                    encode_inner(src.as_ref(), dst, &crate::data::$hi_map, &crate::data::$encode_map)
76                }
77            }
78        )*
79    }
80}
81
82iso8859!(
83    // Western European
84    Iso8859_1,
85    DECODE_MAP_1,
86    HI_MAP_1,
87    ENCODE_MAP_1,
88    // Central European
89    Iso8859_2,
90    DECODE_MAP_2,
91    HI_MAP_2,
92    ENCODE_MAP_2,
93    // South European
94    Iso8859_3,
95    DECODE_MAP_3,
96    HI_MAP_3,
97    ENCODE_MAP_3,
98    // North European
99    Iso8859_4,
100    DECODE_MAP_4,
101    HI_MAP_4,
102    ENCODE_MAP_4,
103    // Cyrillic
104    Iso8859_5,
105    DECODE_MAP_5,
106    HI_MAP_5,
107    ENCODE_MAP_5,
108    // Arabic
109    Iso8859_6,
110    DECODE_MAP_6,
111    HI_MAP_6,
112    ENCODE_MAP_6,
113    // Greek
114    Iso8859_7,
115    DECODE_MAP_7,
116    HI_MAP_7,
117    ENCODE_MAP_7,
118    // Hebrew
119    Iso8859_8,
120    DECODE_MAP_8,
121    HI_MAP_8,
122    ENCODE_MAP_8,
123    // Turkish
124    Iso8859_9,
125    DECODE_MAP_9,
126    HI_MAP_9,
127    ENCODE_MAP_9,
128    // Nordic
129    Iso8859_10,
130    DECODE_MAP_10,
131    HI_MAP_10,
132    ENCODE_MAP_10,
133    // Thai
134    Iso8859_11,
135    DECODE_MAP_11,
136    HI_MAP_11,
137    ENCODE_MAP_11,
138    // Baltic Rim
139    Iso8859_13,
140    DECODE_MAP_13,
141    HI_MAP_13,
142    ENCODE_MAP_13,
143    // Celtic
144    Iso8859_14,
145    DECODE_MAP_14,
146    HI_MAP_14,
147    ENCODE_MAP_14,
148    // Western European
149    Iso8859_15,
150    DECODE_MAP_15,
151    HI_MAP_15,
152    ENCODE_MAP_15,
153    // South-Eastern European
154    Iso8859_16,
155    DECODE_MAP_16,
156    HI_MAP_16,
157    ENCODE_MAP_16
158);