Skip to main content

anyxml_encoding/
iso2022jp.rs

1use crate::{
2    DecodeError, Decoder, EncodeError, Encoder,
3    jisx::{JIS_X_0201_LATIN_DECODE_TABLE, JIS_X_0208_DECODE_TABLE, JIS_X_0208_ENCODE_TABLE},
4};
5
6/// Encoding name for ISO-2022-JP
7pub const ISO_2022_JP_NAME: &str = "ISO-2022-JP";
8
9#[derive(Clone, Copy, Default)]
10enum State {
11    /// 1B 28 42
12    #[default]
13    ISO646,
14    /// 1B 28 4A
15    JISX0201Latin,
16    /// 1B 24 42
17    JISX0208,
18    /// 1B 24 40
19    JISX0208Old,
20}
21
22const ESCSEQ_ISO646: &[u8] = b"\x1B\x28\x42";
23const ESCSEQ_JISX0201_LATIN: &[u8] = b"\x1B\x28\x4A";
24const ESCSEQ_JISX0208: &[u8] = b"\x1B\x24\x42";
25const ESCSEQ_JISX0208_OLD: &[u8] = b"\x1B\x24\x40";
26
27/// Encoder for ISO-2022-JP
28#[derive(Default)]
29pub struct ISO2022JPEncoder {
30    state: State,
31}
32
33impl Encoder for ISO2022JPEncoder {
34    fn name(&self) -> &'static str {
35        ISO_2022_JP_NAME
36    }
37
38    fn encode(
39        &mut self,
40        src: &str,
41        dst: &mut [u8],
42        finish: bool,
43    ) -> Result<(usize, usize), crate::EncodeError> {
44        if src.is_empty() {
45            return if finish {
46                Ok((0, 0))
47            } else {
48                Err(EncodeError::InputIsEmpty)
49            };
50        }
51
52        let (mut read, mut write) = (0, 0);
53        for c in src.chars() {
54            if c.is_ascii() {
55                if !matches!(self.state, State::ISO646) {
56                    if dst.len() < write + 4 {
57                        break;
58                    }
59                    dst[write..write + 3].copy_from_slice(ESCSEQ_ISO646);
60                    write += 3;
61                    self.state = State::ISO646;
62                }
63
64                if dst.len() < write + 1 {
65                    break;
66                }
67                dst[write] = c as u8;
68                write += 1;
69                read += 1;
70            } else {
71                let Ok(pos) =
72                    JIS_X_0208_ENCODE_TABLE.binary_search_by_key(&(c as u32), |v| v.0 as u32)
73                else {
74                    return Err(EncodeError::Unmappable {
75                        read: read + c.len_utf8(),
76                        write,
77                        c,
78                    });
79                };
80
81                // Since the end of the encoded data must be terminated in ISO/IEC 646, if
82                // the last character of the source data is not ASCII, the encoder must check
83                // whether there is sufficient space to store the escape sequence used to
84                // switch to ISO/IEC 646.
85                // If there is insufficient space, the encoder must not terminate the encoding
86                // by omitting the last character.
87                let close = (read + c.len_utf8() == src.len() && finish) as usize * 3;
88
89                if !matches!(self.state, State::JISX0208) {
90                    if dst.len() < write + 5 + close {
91                        break;
92                    }
93                    dst[write..write + 3].copy_from_slice(ESCSEQ_JISX0208);
94                    write += 3;
95                    self.state = State::JISX0208;
96                }
97                if dst.len() < write + 2 + close {
98                    break;
99                }
100                let d = JIS_X_0208_ENCODE_TABLE[pos].1;
101                dst[write] = (d >> 8) as u8;
102                dst[write + 1] = (d & 0xFF) as u8;
103                write += 2;
104                read += c.len_utf8();
105            }
106        }
107
108        if finish
109            && read == src.len()
110            && !matches!(self.state, State::ISO646)
111            && write + 3 <= dst.len()
112        {
113            dst[write..write + 3].copy_from_slice(ESCSEQ_ISO646);
114            self.state = State::ISO646;
115            write += 3;
116        }
117
118        Ok((read, write))
119    }
120}
121
122/// Decoder name for ISO-2022-JP
123#[derive(Default)]
124pub struct ISO2022JPDecoder {
125    state: State,
126}
127
128impl Decoder for ISO2022JPDecoder {
129    fn name(&self) -> &'static str {
130        ISO_2022_JP_NAME
131    }
132
133    fn decode(
134        &mut self,
135        src: &[u8],
136        dst: &mut String,
137        finish: bool,
138    ) -> Result<(usize, usize), crate::DecodeError> {
139        if src.is_empty() {
140            return if finish {
141                Ok((0, 0))
142            } else {
143                Err(DecodeError::InputIsEmpty)
144            };
145        }
146        let len = dst.capacity() - dst.len();
147        if len < 4 {
148            return Err(DecodeError::OutputTooShort);
149        }
150
151        macro_rules! check_capacity {
152            ($len:expr) => {
153                if dst.capacity() - dst.len() < $len {
154                    break;
155                }
156            };
157        }
158
159        let (mut read, mut write) = (0, 0);
160        while read < src.len() {
161            if src[read] >= 0x80 {
162                return Err(DecodeError::Malformed {
163                    read: read + 1,
164                    write,
165                    length: 1,
166                    offset: 0,
167                });
168            }
169
170            if src[read] == b'\x1B' {
171                if read + 3 > src.len() {
172                    break;
173                }
174
175                match &src[read..read + 3] {
176                    ESCSEQ_ISO646 => self.state = State::ISO646,
177                    ESCSEQ_JISX0201_LATIN => self.state = State::JISX0201Latin,
178                    ESCSEQ_JISX0208 => self.state = State::JISX0208,
179                    ESCSEQ_JISX0208_OLD => self.state = State::JISX0208Old,
180                    _ => {
181                        // unknown escape sequence
182                        return Err(DecodeError::Malformed {
183                            read: read + 3,
184                            write,
185                            length: 3,
186                            offset: 0,
187                        });
188                    }
189                }
190                read += 3;
191            } else {
192                match self.state {
193                    State::ISO646 => {
194                        check_capacity!(1);
195                        dst.push(src[read] as char);
196                        read += 1;
197                        write += 1;
198                    }
199                    State::JISX0201Latin => {
200                        check_capacity!(1);
201                        if src[read].is_ascii_control() {
202                            dst.push(src[read] as char);
203                        } else {
204                            dst.push(JIS_X_0201_LATIN_DECODE_TABLE[src[read] as usize - 0x20]);
205                        }
206                        read += 1;
207                        write += 1;
208                    }
209                    State::JISX0208 | State::JISX0208Old => {
210                        if read + 1 >= src.len() {
211                            break;
212                        }
213                        let mut ku = src[read] as usize - 0x20;
214                        let mut ten = src[read + 1] as usize - 0x20;
215                        if matches!(self.state, State::JISX0208Old) {
216                            // JIS X 0208:1997 附属書2(規定)RFC1468符号化表現 4.1 f)
217                            // JIS X 0208:1997 附属書2(規定)RFC1468符号化表現 表1
218                            (ku, ten) = match (ku, ten) {
219                                (15, 18) => (81, 44),
220                                (17, 8) => (81, 83),
221                                (18, 33) => (72, 57),
222                                (18, 40) => (56, 87),
223                                (18, 85) => (66, 61),
224                                (19, 34) => (61, 84),
225                                (19, 49) => (74, 60),
226                                (22, 58) => (79, 83),
227                                (24, 59) => (65, 71),
228                                (27, 40) => (72, 1),
229                                (30, 56) => (79, 54),
230                                (32, 7) => (75, 44),
231                                (35, 58) => (51, 67),
232                                (36, 54) => (65, 73),
233                                (36, 77) => (58, 76),
234                                (36, 82) => (61, 24),
235                                (37, 85) => (76, 77),
236                                (38, 71) => (73, 3),
237                                (40, 15) => (58, 55),
238                                (42, 88) => (47, 53),
239                                (43, 88) => (72, 13),
240                                (46, 21) => (67, 37),
241                                (21, 37) => (83, 0),
242                                (42, 73) => (83, 1),
243                                (44, 57) => (83, 2),
244                                (63, 85) => (83, 3),
245                                // reverse conversion
246                                (81, 44) => (15, 18),
247                                (81, 83) => (17, 8),
248                                (72, 57) => (18, 33),
249                                (56, 87) => (18, 40),
250                                (66, 61) => (18, 85),
251                                (61, 84) => (19, 34),
252                                (74, 60) => (19, 49),
253                                (79, 83) => (22, 58),
254                                (65, 71) => (24, 59),
255                                (72, 1) => (27, 40),
256                                (79, 54) => (30, 56),
257                                (75, 44) => (32, 7),
258                                (51, 67) => (35, 58),
259                                (65, 73) => (36, 54),
260                                (58, 76) => (36, 77),
261                                (61, 24) => (36, 82),
262                                (76, 77) => (37, 85),
263                                (73, 3) => (38, 71),
264                                (58, 55) => (40, 15),
265                                (47, 53) => (42, 88),
266                                (72, 13) => (43, 88),
267                                (67, 37) => (46, 21),
268                                (83, 0) => (21, 37),
269                                (83, 1) => (42, 73),
270                                (83, 2) => (44, 57),
271                                (83, 3) => (63, 85),
272                                _ => (ku, ten),
273                            };
274                        }
275                        if JIS_X_0208_DECODE_TABLE[ku].len() <= ten
276                            || JIS_X_0208_DECODE_TABLE[ku][ten] == char::REPLACEMENT_CHARACTER
277                        {
278                            return Err(DecodeError::Malformed {
279                                read: read + 2,
280                                write,
281                                length: 2,
282                                offset: 0,
283                            });
284                        }
285
286                        let c = JIS_X_0208_DECODE_TABLE[ku][ten];
287                        check_capacity!(c.len_utf8());
288                        dst.push(c);
289                        read += 2;
290                        write += c.len_utf8();
291                    }
292                }
293            }
294        }
295        Ok((read, write))
296    }
297}
298
299#[cfg(test)]
300mod tests {
301    use super::*;
302
303    #[test]
304    fn iso2022jp_tests() {
305        let src = include_bytes!("../resources/jistests/日本国憲法前文_iso2022jp.txt").as_slice();
306        let mut buf = String::with_capacity(1 << 15);
307        ISO2022JPDecoder::default()
308            .decode(src, &mut buf, true)
309            .unwrap();
310        let ucs = include_str!("../resources/jistests/日本国憲法前文_unicode.txt");
311        assert_eq!(buf, ucs);
312
313        let mut dst = vec![0; 1 << 15];
314        let (_, write) = ISO2022JPEncoder::default()
315            .encode(&buf, &mut dst, true)
316            .unwrap();
317        dst.truncate(write);
318        assert_eq!(src, dst);
319    }
320}