Skip to main content

anyxml_encoding/
euc.rs

1use crate::{
2    DecodeError, Decoder, EncodeError, Encoder,
3    gb2312::{GB2312_TO_UCS, UCS_TO_GB2312},
4    jisx, ksx,
5};
6
7pub struct EUCDecoder {
8    // G0 implicitly designate ASCII.
9    // Each buffer is assumed to be either 94, 96, 94^n, or 96^n.
10
11    // G1 buffer
12    g1: &'static [&'static [char]],
13    // G2 buffer
14    g2: &'static [&'static [char]],
15    // G3 buffer
16    g3: &'static [&'static [char]],
17}
18
19impl EUCDecoder {
20    /// If no error occurs, return `Ok((read_bytes, write_bytes))`.
21    pub(crate) fn decode(
22        &mut self,
23        src: &[u8],
24        dst: &mut String,
25        finish: bool,
26    ) -> Result<(usize, usize), DecodeError> {
27        if src.is_empty() {
28            return if finish {
29                Ok((0, 0))
30            } else {
31                Err(DecodeError::InputIsEmpty)
32            };
33        }
34        let len = dst.capacity() - dst.len();
35        if len < 4 {
36            return Err(DecodeError::OutputTooShort);
37        }
38
39        let (mut read, mut write) = (0, 0);
40        macro_rules! malformed {
41            ( $length:expr ) => {
42                Err(DecodeError::Malformed {
43                    read,
44                    write,
45                    length: $length,
46                    offset: 0,
47                })
48            };
49        }
50
51        while read < src.len() {
52            match src[read..] {
53                [0x8E, ..] | [0x8F, ..] => {
54                    // SS2/SS3
55                    let g = if src[read] == 0x8E {
56                        &self.g2
57                    } else {
58                        &self.g3
59                    };
60
61                    read += 1;
62                    if read >= src.len() {
63                        if finish {
64                            return malformed!(1);
65                        }
66                        break;
67                    }
68
69                    if src[read] < 0xA0 {
70                        read += 1;
71                        return malformed!(1);
72                    }
73                    let s = src[read] as usize - 0xA0;
74                    read += 1;
75                    if g.len() == 1 {
76                        let c = g[0][s];
77                        if g[0].len() <= s || g[0][s] == char::REPLACEMENT_CHARACTER {
78                            return malformed!(2);
79                        }
80                        dst.push(c);
81                        write += c.len_utf8();
82                    } else {
83                        if read >= src.len() {
84                            if finish {
85                                return malformed!(2);
86                            }
87                            break;
88                        }
89                        if src[read] < 0xA0 {
90                            read += 1;
91                            return malformed!(3);
92                        }
93                        let t = src[read] as usize - 0xA0;
94                        read += 1;
95                        if g.len() <= s || g[s].len() <= t || g[s][t] == char::REPLACEMENT_CHARACTER
96                        {
97                            return malformed!(3);
98                        }
99                        let c = g[s][t];
100                        dst.push(c);
101                        write += c.len_utf8();
102                    }
103                }
104                _ => {
105                    if src[read] < 0xA0 {
106                        // GL (G0, ASCII) and CR
107                        // I'm not sure if this is the correct way to handle CR...
108                        // uconv seems to return the original value for EUC-JP/CN/KR.
109                        // However, iconv appears to return the original value for EUC-JP/KR,
110                        // but returns an error for EUC-CN.
111                        let c = src[read] as char;
112                        dst.push(c);
113                        read += 1;
114                        write += c.len_utf8();
115                    } else {
116                        // GR (G1)
117                        if self.g1.len() > 1 {
118                            // multibyte character
119                            if read + 1 == src.len() {
120                                // The second byte of multibyte characters cannot be read.
121                                if finish {
122                                    read += 1;
123                                    return malformed!(1);
124                                }
125                                break;
126                            }
127                            let s = src[read] as usize - 0xA0;
128                            if src[read + 1] < 0xA0 {
129                                read += 2;
130                                return malformed!(2);
131                            }
132                            let t = src[read + 1] as usize - 0xA0;
133                            read += 2;
134                            if self.g1.len() <= s
135                                || self.g1[s].len() <= t
136                                || self.g1[s][t] == char::REPLACEMENT_CHARACTER
137                            {
138                                return malformed!(2);
139                            }
140                            let c = self.g1[s][t];
141                            dst.push(c);
142                            write += c.len_utf8();
143                        } else {
144                            // singlebyte character
145                            let c = self.g1[0][src[read] as usize - 0xA0];
146                            read += 1;
147                            if c == char::REPLACEMENT_CHARACTER {
148                                return malformed!(1);
149                            } else {
150                                dst.push(c);
151                                write += c.len_utf8();
152                            }
153                        }
154                    }
155                }
156            }
157
158            if dst.capacity() - dst.len() < 4 {
159                break;
160            }
161        }
162
163        Ok((read, write))
164    }
165}
166
167pub struct EUCEncoder<
168    G1From,
169    G1To,
170    G2From,
171    G2To,
172    G3From,
173    G3To,
174    const G1DIM: u8,
175    const G2DIM: u8,
176    const G3DIM: u8,
177> where
178    G1From: Into<u32> + 'static,
179    G1To: Into<u32> + 'static,
180    G2From: Into<u32> + 'static,
181    G2To: Into<u32> + 'static,
182    G3From: Into<u32> + 'static,
183    G3To: Into<u32> + 'static,
184{
185    // G0 implicitly designate ASCII.
186
187    // G1 buffer
188    g1: &'static [(G1From, G1To)],
189    // G2 buffer
190    g2: &'static [(G2From, G2To)],
191    // G3 buffer
192    g3: &'static [(G3From, G3To)],
193}
194
195impl<G1From, G1To, G2From, G2To, G3From, G3To, const G1DIM: u8, const G2DIM: u8, const G3DIM: u8>
196    EUCEncoder<G1From, G1To, G2From, G2To, G3From, G3To, G1DIM, G2DIM, G3DIM>
197where
198    G1From: Into<u32> + Copy,
199    G1To: Into<u32> + Copy,
200    G2From: Into<u32> + Copy,
201    G2To: Into<u32> + Copy,
202    G3From: Into<u32> + Copy,
203    G3To: Into<u32> + Copy,
204{
205    /// If no error occurs, return `Ok((read_bytes, write_bytes))`.
206    pub(crate) fn encode(
207        &mut self,
208        src: &str,
209        dst: &mut [u8],
210        finish: bool,
211    ) -> Result<(usize, usize), EncodeError> {
212        assert!(0 < G1DIM && G1DIM <= 2 && 0 < G2DIM && G2DIM <= 2 && 0 < G3DIM && G3DIM <= 2);
213        if src.is_empty() {
214            return if finish {
215                Ok((0, 0))
216            } else {
217                Err(EncodeError::InputIsEmpty)
218            };
219        }
220
221        if dst.len() < 3 {
222            return Err(EncodeError::OutputTooShort);
223        }
224
225        let (mut read, mut write) = (0, 0);
226        macro_rules! write_buffer {
227            ( $dim:expr, $to:expr ) => {
228                if $dim == 1 {
229                    assert!($to < u8::MAX as u32);
230                    dst[write] = $to as u8 + 0xA0;
231                    write += 1;
232                } else if $dim == 2 {
233                    let to = $to + 0x8080;
234                    dst[write] = (to >> 8) as u8;
235                    dst[write + 1] = (to & 0xFF) as u8;
236                    write += 2;
237                } else {
238                    unreachable!();
239                }
240            };
241        }
242        for c in src.chars() {
243            read += c.len_utf8();
244            if c.is_ascii() || ((..'\u{A0}').contains(&c) && c != '\u{8E}' && c != '\u{8F}') {
245                dst[write] = c as u8;
246                write += 1;
247            } else if let Ok(pos) = self.g1.binary_search_by_key(&(c as u32), |e| e.0.into()) {
248                let to: u32 = self.g1[pos].1.into();
249                write_buffer!(G1DIM, to);
250            } else if let Ok(pos) = self.g2.binary_search_by_key(&(c as u32), |e| e.0.into()) {
251                dst[write] = 0x8E;
252                write += 1;
253                let to: u32 = self.g2[pos].1.into();
254                write_buffer!(G2DIM, to);
255            } else if let Ok(pos) = self.g3.binary_search_by_key(&(c as u32), |e| e.0.into()) {
256                dst[write] = 0x8F;
257                write += 1;
258                let to: u32 = self.g3[pos].1.into();
259                write_buffer!(G3DIM, to);
260            } else {
261                return Err(EncodeError::Unmappable { read, write, c });
262            }
263
264            if dst[write..].len() < 3 {
265                break;
266            }
267        }
268
269        Ok((read, write))
270    }
271}
272
273/// Encoding name for EUC-JP.
274pub const EUCJP_NAME: &str = "EUC-JP";
275/// Decoder for EUC-JP.
276pub struct EUCJPDecoder {
277    decoder: EUCDecoder,
278}
279
280pub(crate) fn eucjp_decoder_factory() -> Box<dyn Decoder> {
281    static G2: &[&[char]] = &[jisx::JIS_X_0201_KATAKANA_DECODE_TABLE];
282    Box::new(EUCJPDecoder {
283        decoder: EUCDecoder {
284            g1: &jisx::JIS_X_0208_DECODE_TABLE,
285            g2: G2,
286            g3: &jisx::JIS_X_0212_DECODE_TABLE,
287        },
288    })
289}
290
291impl Decoder for EUCJPDecoder {
292    fn name(&self) -> &'static str {
293        EUCJP_NAME
294    }
295
296    fn decode(
297        &mut self,
298        src: &[u8],
299        dst: &mut String,
300        finish: bool,
301    ) -> Result<(usize, usize), DecodeError> {
302        self.decoder.decode(src, dst, finish)
303    }
304}
305
306/// Encoder for EUC-JP.
307pub struct EUCJPEncoder {
308    encoder: EUCEncoder<u16, u16, u16, u8, u16, u16, 2, 1, 2>,
309}
310
311pub(crate) fn eucjp_encoder_factory() -> Box<dyn Encoder> {
312    Box::new(EUCJPEncoder {
313        encoder: EUCEncoder {
314            g1: jisx::JIS_X_0208_ENCODE_TABLE,
315            g2: jisx::JIS_X_0201_KATAKANA_ENCODE_TABLE,
316            g3: jisx::JIS_X_0212_ENCODE_TABLE,
317        },
318    })
319}
320
321impl Encoder for EUCJPEncoder {
322    fn name(&self) -> &'static str {
323        EUCJP_NAME
324    }
325
326    fn encode(
327        &mut self,
328        src: &str,
329        dst: &mut [u8],
330        finish: bool,
331    ) -> Result<(usize, usize), EncodeError> {
332        self.encoder.encode(src, dst, finish)
333    }
334}
335
336/// Encoding name for EUC-KR.
337pub const EUCKR_NAME: &str = "EUC-KR";
338/// Decoder for EUC-KR.
339pub struct EUCKRDecoder {
340    decoder: EUCDecoder,
341}
342
343pub(crate) fn euckr_decoder_factory() -> Box<dyn Decoder> {
344    Box::new(EUCKRDecoder {
345        decoder: EUCDecoder {
346            g1: &ksx::KS_X_1001_DECODE_TABLE,
347            g2: &[&[]],
348            g3: &[&[]],
349        },
350    })
351}
352
353impl Decoder for EUCKRDecoder {
354    fn name(&self) -> &'static str {
355        EUCKR_NAME
356    }
357
358    fn decode(
359        &mut self,
360        src: &[u8],
361        dst: &mut String,
362        finish: bool,
363    ) -> Result<(usize, usize), DecodeError> {
364        self.decoder.decode(src, dst, finish)
365    }
366}
367
368/// Encoder for EUC-KR.
369pub struct EUCKREncoder {
370    encoder: EUCEncoder<u16, u16, u8, u8, u8, u8, 2, 1, 1>,
371}
372
373pub(crate) fn euckr_encoder_factory() -> Box<dyn Encoder> {
374    Box::new(EUCKREncoder {
375        encoder: EUCEncoder {
376            g1: ksx::KS_X_1001_ENCODE_TABLE,
377            g2: &[],
378            g3: &[],
379        },
380    })
381}
382
383impl Encoder for EUCKREncoder {
384    fn name(&self) -> &'static str {
385        EUCKR_NAME
386    }
387
388    fn encode(
389        &mut self,
390        src: &str,
391        dst: &mut [u8],
392        finish: bool,
393    ) -> Result<(usize, usize), EncodeError> {
394        self.encoder.encode(src, dst, finish)
395    }
396}
397
398/// Encoding name for GB2312.
399pub const GB2312_NAME: &str = "GB2312";
400
401/// Encoder for GB2312.
402pub struct GB2312Encoder {
403    encoder: EUCEncoder<u16, u16, u8, u8, u8, u8, 2, 1, 1>,
404}
405
406impl Encoder for GB2312Encoder {
407    fn name(&self) -> &'static str {
408        GB2312_NAME
409    }
410
411    fn encode(
412        &mut self,
413        src: &str,
414        dst: &mut [u8],
415        finish: bool,
416    ) -> Result<(usize, usize), crate::EncodeError> {
417        self.encoder.encode(src, dst, finish)
418    }
419}
420
421pub(crate) fn gb2312_encoder_factory() -> Box<dyn Encoder> {
422    Box::new(GB2312Encoder {
423        encoder: EUCEncoder {
424            g1: UCS_TO_GB2312,
425            g2: &[],
426            g3: &[],
427        },
428    })
429}
430
431/// Decoder for GB2312.
432pub struct GB2312Decoder {
433    decoder: EUCDecoder,
434}
435
436impl Decoder for GB2312Decoder {
437    fn name(&self) -> &'static str {
438        GB2312_NAME
439    }
440
441    fn decode(
442        &mut self,
443        src: &[u8],
444        dst: &mut String,
445        finish: bool,
446    ) -> Result<(usize, usize), crate::DecodeError> {
447        self.decoder.decode(src, dst, finish)
448    }
449}
450
451pub(crate) fn gb2312_decoder_factory() -> Box<dyn Decoder> {
452    Box::new(GB2312Decoder {
453        decoder: EUCDecoder {
454            g1: &GB2312_TO_UCS,
455            g2: &[&[]],
456            g3: &[&[]],
457        },
458    })
459}
460
461#[cfg(test)]
462mod tests {
463    use super::*;
464
465    #[test]
466    fn eucjp_katakana_tests() {
467        let bytes = &[
468            0x8e, 0xb1, 0x8e, 0xb2, 0x8e, 0xb3, 0x8e, 0xb4, 0x8e, 0xb5, 0x8e, 0xb6, 0x8e, 0xb7,
469            0x8e, 0xb8, 0x8e, 0xb9, 0x8e, 0xba, 0x8e, 0xbb, 0x8e, 0xbc, 0x8e, 0xbd, 0x8e, 0xbe,
470            0x8e, 0xbf, 0x8e, 0xc0, 0x8e, 0xc1, 0x8e, 0xc2, 0x8e, 0xc3, 0x8e, 0xc4, 0x8e, 0xc5,
471            0x8e, 0xc6, 0x8e, 0xc7, 0x8e, 0xc8, 0x8e, 0xc9, 0x8e, 0xca, 0x8e, 0xcb, 0x8e, 0xcc,
472            0x8e, 0xcd, 0x8e, 0xce, 0x8e, 0xcf, 0x8e, 0xd0, 0x8e, 0xd1, 0x8e, 0xd2, 0x8e, 0xd3,
473            0x8e, 0xd4, 0x8e, 0xd5, 0x8e, 0xd6, 0x8e, 0xd7, 0x8e, 0xd8, 0x8e, 0xd9, 0x8e, 0xda,
474            0x8e, 0xdb, 0x8e, 0xdc, 0x8e, 0xa6, 0x8e, 0xdd,
475        ];
476        let mut buf = String::with_capacity(512);
477        eucjp_decoder_factory()
478            .decode(bytes, &mut buf, true)
479            .unwrap();
480        assert_eq!(buf, "アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン");
481    }
482
483    #[test]
484    fn eucjp_kanji_tests() {
485        let bytes = &[
486            0xc4, 0xbf, 0xb9, 0xf1, 0xb2, 0xc8, 0xa5, 0xce, 0xce, 0xb4, 0xbe, 0xbb, 0xa5, 0xc8,
487            0xbf, 0xc3, 0xcc, 0xb1, 0xa5, 0xce, 0xb7, 0xc4, 0xca, 0xa1, 0xa5, 0xc8, 0xa5, 0xf2,
488            0xb0, 0xca, 0xa5, 0xc6, 0xc3, 0xe6, 0xbf, 0xb4, 0xa5, 0xce, 0xb6, 0xd5, 0xb1, 0xc9,
489            0xa5, 0xc8, 0xa5, 0xb7, 0xc4, 0xbf, 0xa5, 0xab, 0xc1, 0xc4, 0xbd, 0xa1, 0xa5, 0xcb,
490            0xbe, 0xb5, 0xa5, 0xaf, 0xa5, 0xeb, 0xa5, 0xce, 0xc2, 0xe7, 0xb8, 0xa2, 0xa5, 0xcb,
491            0xb0, 0xcd, 0xa5, 0xea, 0xb8, 0xbd, 0xba, 0xdf, 0xb5, 0xda, 0xbe, 0xad, 0xcd, 0xe8,
492            0xa5, 0xce, 0xbf, 0xc3, 0xcc, 0xb1, 0xa5, 0xcb, 0xc2, 0xd0, 0xa5, 0xb7, 0xba, 0xa1,
493            0xa5, 0xce, 0xc9, 0xd4, 0xcb, 0xe1, 0xa5, 0xce, 0xc2, 0xe7, 0xc5, 0xb5, 0xa5, 0xf2,
494            0xc0, 0xeb, 0xc9, 0xdb, 0xa5, 0xb9, 0x0a, 0xb0, 0xd4, 0xa5, 0xd5, 0xa5, 0xcb, 0xb2,
495            0xe6, 0xa5, 0xab, 0xc1, 0xc4, 0xb2, 0xe6, 0xa5, 0xab, 0xbd, 0xa1, 0xa5, 0xcf, 0xb2,
496            0xe6, 0xa5, 0xab, 0xbf, 0xc3, 0xcc, 0xb1, 0xc1, 0xc4, 0xc0, 0xe8, 0xa5, 0xce, 0xb6,
497            0xa8, 0xce, 0xcf, 0xca, 0xe5, 0xcd, 0xe3, 0xa5, 0xcb, 0xd0, 0xe1, 0xa5, 0xea, 0xb2,
498            0xe6, 0xa5, 0xab, 0xc4, 0xeb, 0xb9, 0xf1, 0xa5, 0xf2, 0xc8, 0xa5, 0xc2, 0xa4, 0xa5,
499            0xb7, 0xb0, 0xca, 0xa5, 0xc6, 0xcc, 0xb5, 0xb5, 0xe7, 0xa5, 0xcb, 0xbf, 0xe2, 0xa5,
500            0xec, 0xa5, 0xbf, 0xa5, 0xea, 0xba, 0xa1, 0xa5, 0xec, 0xb2, 0xe6, 0xa5, 0xab, 0xbf,
501            0xc0, 0xc0, 0xbb, 0xa5, 0xca, 0xa5, 0xeb, 0xc1, 0xc4, 0xbd, 0xa1, 0xa5, 0xce, 0xb0,
502            0xd2, 0xc6, 0xc1, 0xa5, 0xc8, 0xca, 0xc2, 0xa5, 0xcb, 0xbf, 0xc3, 0xcc, 0xb1, 0xa5,
503            0xce, 0xc3, 0xe9, 0xbc, 0xc2, 0xcd, 0xa6, 0xc9, 0xf0, 0xa5, 0xcb, 0xa5, 0xb7, 0xa5,
504            0xc6, 0xb9, 0xf1, 0xa5, 0xf2, 0xb0, 0xa6, 0xa5, 0xb7, 0xb8, 0xf8, 0xa5, 0xcb, 0xbd,
505            0xde, 0xa5, 0xd2, 0xb0, 0xca, 0xa5, 0xc6, 0xba, 0xa1, 0xa5, 0xce, 0xb8, 0xf7, 0xb5,
506            0xb1, 0xa5, 0xa2, 0xa5, 0xeb, 0xb9, 0xf1, 0xbb, 0xcb, 0xa5, 0xce, 0xc0, 0xae, 0xc0,
507            0xd7, 0xa5, 0xf2, 0xec, 0xc6, 0xa5, 0xb7, 0xa5, 0xbf, 0xa5, 0xeb, 0xa5, 0xca, 0xa5,
508            0xea, 0xc4, 0xbf, 0xb2, 0xe6, 0xa5, 0xab, 0xbf, 0xc3, 0xcc, 0xb1, 0xa5, 0xcf, 0xc2,
509            0xa8, 0xa5, 0xc1, 0xc1, 0xc4, 0xbd, 0xa1, 0xa5, 0xce, 0xc3, 0xe9, 0xce, 0xc9, 0xa5,
510            0xca, 0xa5, 0xeb, 0xbf, 0xc3, 0xcc, 0xb1, 0xa5, 0xce, 0xbb, 0xd2, 0xc2, 0xb9, 0xa5,
511            0xca, 0xa5, 0xeb, 0xa5, 0xf2, 0xb2, 0xf3, 0xc1, 0xdb, 0xa5, 0xb7, 0xc2, 0xb6, 0xa5,
512            0xce, 0xc4, 0xbf, 0xa5, 0xab, 0xb0, 0xd5, 0xa5, 0xf2, 0xca, 0xf4, 0xc2, 0xce, 0xa5,
513            0xb7, 0xc4, 0xbf, 0xa5, 0xab, 0xbb, 0xf6, 0xa5, 0xf2, 0xbe, 0xa9, 0xbd, 0xe7, 0xa5,
514            0xb7, 0xc1, 0xea, 0xcd, 0xbf, 0xa5, 0xcb, 0xcf, 0xc2, 0xc3, 0xef, 0xb6, 0xa8, 0xc6,
515            0xb1, 0xa5, 0xb7, 0xb1, 0xd7, 0xa1, 0xb9, 0xb2, 0xe6, 0xa5, 0xab, 0xc4, 0xeb, 0xb9,
516            0xf1, 0xa5, 0xce, 0xb8, 0xf7, 0xb1, 0xc9, 0xa5, 0xf2, 0xc3, 0xe6, 0xb3, 0xb0, 0xa5,
517            0xcb, 0xc0, 0xeb, 0xcd, 0xc8, 0xa5, 0xb7, 0xc1, 0xc4, 0xbd, 0xa1, 0xa5, 0xce, 0xb0,
518            0xe4, 0xb6, 0xc8, 0xa5, 0xf2, 0xb1, 0xca, 0xb5, 0xd7, 0xa5, 0xcb, 0xf0, 0xdf, 0xb8,
519            0xc7, 0xa5, 0xca, 0xa5, 0xe9, 0xa5, 0xb7, 0xa5, 0xe0, 0xa5, 0xeb, 0xa5, 0xce, 0xb4,
520            0xf5, 0xcb, 0xbe, 0xa5, 0xf2, 0xc6, 0xb1, 0xa5, 0xaf, 0xa5, 0xb7, 0xba, 0xa1, 0xa5,
521            0xce, 0xc9, 0xe9, 0xc3, 0xb4, 0xa5, 0xf2, 0xca, 0xac, 0xa5, 0xc4, 0xa5, 0xcb, 0xb4,
522            0xae, 0xa5, 0xd5, 0xa5, 0xeb, 0xa5, 0xb3, 0xa5, 0xc8, 0xa5, 0xf2, 0xb5, 0xbf, 0xa5,
523            0xcf, 0xa5, 0xb5, 0xa5, 0xeb, 0xa5, 0xca, 0xa5, 0xea,
524        ];
525
526        let mut buf = String::with_capacity(1024);
527        let (read, _) = eucjp_decoder_factory()
528            .decode(bytes, &mut buf, true)
529            .unwrap();
530        assert_eq!(read, bytes.len());
531        assert_eq!(
532            buf,
533            "朕国家ノ隆昌ト臣民ノ慶福トヲ以テ中心ノ欣栄トシ朕カ祖宗ニ承クルノ大権ニ依リ現在及将来ノ臣民ニ対シ此ノ不磨ノ大典ヲ宣布ス\n惟フニ我カ祖我カ宗ハ我カ臣民祖先ノ協力輔翼ニ倚リ我カ帝国ヲ肇造シ以テ無窮ニ垂レタリ此レ我カ神聖ナル祖宗ノ威徳ト並ニ臣民ノ忠実勇武ニシテ国ヲ愛シ公ニ殉ヒ以テ此ノ光輝アル国史ノ成跡ヲ貽シタルナリ朕我カ臣民ハ即チ祖宗ノ忠良ナル臣民ノ子孫ナルヲ回想シ其ノ朕カ意ヲ奉体シ朕カ事ヲ奨順シ相与ニ和衷協同シ益々我カ帝国ノ光栄ヲ中外ニ宣揚シ祖宗ノ遺業ヲ永久ニ鞏固ナラシムルノ希望ヲ同クシ此ノ負担ヲ分ツニ堪フルコトヲ疑ハサルナリ"
534        );
535    }
536
537    #[test]
538    fn euckr_kanji_hangul_tests() {
539        let bytes = &[
540            0xea, 0xed, 0xce, 0xf9, 0xc7, 0xd1, 0x20, 0xd5, 0xf6, 0xde, 0xc8, 0xbf, 0xcd, 0x20,
541            0xee, 0xee, 0xf7, 0xd6, 0xbf, 0xa1, 0x20, 0xba, 0xfb, 0xb3, 0xaa, 0xb4, 0xc2, 0x20,
542            0xbf, 0xec, 0xb8, 0xae, 0x20, 0xd3, 0xde, 0xf9, 0xdb, 0xcf, 0xd0, 0xda, 0xc5, 0xc0,
543            0xba, 0x20, 0x33, 0xa1, 0xa4, 0x31, 0x20, 0xea, 0xa1, 0xd4, 0xd1, 0xc0, 0xb8, 0xb7,
544            0xce, 0x20, 0xcb, 0xef, 0xd8, 0xa1, 0xb5, 0xc8, 0x20, 0xd3, 0xde, 0xf9, 0xdb, 0xda,
545            0xc5, 0xcf, 0xd0, 0xd7, 0xfc, 0xe3, 0xc1, 0xef, 0xd9, 0xdd, 0xa4, 0xc0, 0xc7, 0x20,
546            0xdb, 0xf6, 0xf7, 0xd6, 0xb0, 0xfa, 0x20, 0xdc, 0xf4, 0xeb, 0xf9, 0xbf, 0xa1, 0x20,
547            0xf9, 0xf7, 0xcb, 0xde, 0xc7, 0xd1, 0x20, 0x34, 0xa1, 0xa4, 0x31, 0x39, 0x20, 0xda,
548            0xc5, 0xf1, 0xab, 0xd7, 0xe2, 0xd2, 0xb7, 0xc0, 0xbb, 0x20, 0xcd, 0xa9, 0xe3, 0xaf,
549            0xc7, 0xcf, 0xb0, 0xed, 0x2c, 0x20, 0xf0, 0xd3, 0xcf, 0xd0, 0xc0, 0xc7, 0x20, 0xda,
550            0xc5, 0xf1, 0xab, 0xcb, 0xc7, 0xfa, 0xd4, 0xb0, 0xfa, 0x20, 0xf8, 0xc1, 0xfb, 0xfa,
551            0xee, 0xdc, 0xf7, 0xd6, 0xec, 0xe9, 0xc0, 0xc7, 0x20, 0xde, 0xc5, 0xd9, 0xa4, 0xbf,
552            0xa1, 0x20, 0xd8, 0xa1, 0xca, 0xc5, 0xc7, 0xcf, 0xbf, 0xa9, 0x20, 0xef, 0xe1, 0xeb,
553            0xf9, 0xa1, 0xa4, 0xec, 0xd1, 0xd4, 0xb3, 0xbf, 0xcd, 0x20, 0xd4, 0xd2, 0xf8, 0xe0,
554            0xe4, 0xf1, 0xb7, 0xce, 0xbd, 0xe1, 0x20, 0xda, 0xc5, 0xf0, 0xe9, 0xc0, 0xc7, 0x20,
555            0xd3, 0xa5, 0xcc, 0xbf, 0xc0, 0xbb, 0x20, 0xcd, 0xf9, 0xcd, 0xb3, 0xc8, 0xf7, 0x20,
556            0xc7, 0xcf, 0xb0, 0xed, 0x2c, 0x20, 0xb8, 0xf0, 0xb5, 0xe7, 0x20, 0xde, 0xe4, 0xfc,
557            0xe5, 0xee, 0xdc, 0xf8, 0xc9, 0xe3, 0xa7, 0xb0, 0xfa, 0x20, 0xdc, 0xf4, 0xeb, 0xf9,
558            0xb8, 0xa6, 0x20, 0xf6, 0xe8, 0xf7, 0xf2, 0xc7, 0xcf, 0xb8, 0xe7, 0x2c, 0x20, 0xed,
559            0xbb, 0xd7, 0xc8, 0xb0, 0xfa, 0x20, 0xf0, 0xe0, 0xfb, 0xfa, 0xb8, 0xa6, 0x20, 0xb9,
560            0xd9, 0xc5, 0xc1, 0xc0, 0xb8, 0xb7, 0xce, 0x20, 0xed, 0xbb, 0xeb, 0xa6, 0xda, 0xc5,
561            0xf1, 0xab, 0xee, 0xdc, 0xd0, 0xf1, 0xdc, 0xe2, 0xf2, 0xf1, 0xdf, 0xed, 0xb8, 0xa6,
562            0x20, 0xb4, 0xf5, 0xbf, 0xed, 0x20, 0xfc, 0xac, 0xcd, 0xb3, 0xc8, 0xf7, 0x20, 0xc7,
563            0xcf, 0xbf, 0xa9, 0x20, 0xef, 0xd9, 0xf6, 0xbd, 0xa1, 0xa4, 0xcc, 0xe8, 0xf0, 0xad,
564            0xa1, 0xa4, 0xde, 0xe4, 0xfc, 0xe5, 0xa1, 0xa4, 0xd9, 0xfe, 0xfb, 0xf9, 0xc0, 0xc7,
565            0x20, 0xb8, 0xf0, 0xb5, 0xe7, 0x20, 0xd6, 0xc5, 0xe6, 0xb4, 0xbf, 0xa1, 0x20, 0xc0,
566            0xd6, 0xbe, 0xee, 0xbc, 0xad, 0x20, 0xca, 0xc0, 0xec, 0xd1, 0xc0, 0xc7, 0x20, 0xd1,
567            0xa6, 0xfc, 0xe5, 0xb8, 0xa6, 0x20, 0xd0, 0xb3, 0xd4, 0xf5, 0xc8, 0xf7, 0x20, 0xc7,
568            0xcf, 0xb0, 0xed, 0x2c, 0x20, 0xd2, 0xf6, 0xd5, 0xf4, 0xc0, 0xbb, 0x20, 0xf5, 0xcc,
569            0xcd, 0xd4, 0xd3, 0xf8, 0xb7, 0xce, 0x20, 0xdb, 0xa1, 0xfd, 0xc6, 0xc7, 0xcf, 0xb0,
570            0xd4, 0x20, 0xc7, 0xcf, 0xb8, 0xe7, 0x2c, 0x20, 0xed, 0xbb, 0xeb, 0xa6, 0xbf, 0xcd,
571            0x20, 0xcf, 0xed, 0xd7, 0xd7, 0xbf, 0xa1, 0x20, 0xb5, 0xfb, 0xb8, 0xa3, 0xb4, 0xc2,
572            0x20, 0xf4, 0xa1, 0xec, 0xf2, 0xb0, 0xfa, 0x20, 0xeb, 0xf9, 0xd9, 0xe2, 0xb8, 0xa6,
573            0x20, 0xe8, 0xc7, 0xe2, 0xc4, 0xc7, 0xcf, 0xb0, 0xd4, 0x20, 0xc7, 0xcf, 0xbf, 0xa9,
574            0x2c, 0x20, 0xbe, 0xc8, 0xc0, 0xb8, 0xb7, 0xce, 0xb4, 0xc2, 0x20, 0xcf, 0xd0, 0xda,
575            0xc5, 0xdf, 0xe6, 0xfc, 0xc0, 0xc0, 0xc7, 0x20, 0xd0, 0xb3, 0xd4, 0xf5, 0xc7, 0xd1,
576            0x20, 0xfa, 0xbe, 0xdf, 0xbe, 0xc0, 0xbb, 0x20, 0xd1, 0xa2, 0xc7, 0xcf, 0xb0, 0xed,
577            0x20, 0xb9, 0xdb, 0xc0, 0xb8, 0xb7, 0xce, 0xb4, 0xc2, 0x20, 0xf9, 0xf6, 0xce, 0xf9,
578            0xee, 0xdc, 0xc0, 0xce, 0x20, 0xe1, 0xa6, 0xcd, 0xa3, 0xf8, 0xc1, 0xfb, 0xfa, 0xbf,
579            0xcd, 0x20, 0xec, 0xd1, 0xd7, 0xbe, 0xcd, 0xec, 0xe7, 0xb4, 0xbf, 0xa1, 0x20, 0xc0,
580            0xcc, 0xb9, 0xd9, 0xc1, 0xf6, 0xc7, 0xd4, 0xc0, 0xb8, 0xb7, 0xce, 0xbd, 0xe1, 0x20,
581            0xbf, 0xec, 0xb8, 0xae, 0xb5, 0xe9, 0xb0, 0xfa, 0x20, 0xbf, 0xec, 0xb8, 0xae, 0xb5,
582            0xe9, 0xc0, 0xc7, 0x20, 0xed, 0xad, 0xe1, 0xdd, 0xc0, 0xc7, 0x20, 0xe4, 0xcc, 0xee,
583            0xef, 0xb0, 0xfa, 0x20, 0xed, 0xbb, 0xeb, 0xa6, 0xbf, 0xcd, 0x20, 0xfa, 0xb9, 0xdc,
584            0xd8, 0xc0, 0xbb, 0x20, 0xe7, 0xb5, 0xea, 0xc0, 0xc8, 0xf7, 0x20, 0xfc, 0xac, 0xdc,
585            0xc1, 0xc7, 0xd2, 0x20, 0xb0, 0xcd, 0xc0, 0xbb, 0x20, 0xb4, 0xd9, 0xc1, 0xfc, 0xc7,
586            0xcf, 0xb8, 0xe9, 0xbc, 0xad, 0x20, 0x31, 0x39, 0x34, 0x38, 0xd2, 0xb4, 0x20, 0x37,
587            0xea, 0xc5, 0x20, 0x31, 0x32, 0xec, 0xed, 0xbf, 0xa1, 0x20, 0xf0, 0xa4, 0xef, 0xd2,
588            0xb5, 0xc7, 0xb0, 0xed, 0x20, 0x38, 0xf3, 0xad, 0xbf, 0xa1, 0x20, 0xb0, 0xc9, 0xc3,
589            0xc4, 0x20, 0xcb, 0xc7, 0xef, 0xe1, 0xb5, 0xc8, 0x20, 0xfa, 0xca, 0xdb, 0xf6, 0xc0,
590            0xbb, 0x20, 0xc0, 0xcc, 0xc1, 0xa6, 0x20, 0xcf, 0xd0, 0xfc, 0xe5, 0xc0, 0xc7, 0x20,
591            0xec, 0xa1, 0xcc, 0xbd, 0xc0, 0xbb, 0x20, 0xb0, 0xc5, 0xc3, 0xc4, 0x20, 0xcf, 0xd0,
592            0xda, 0xc5, 0xf7, 0xe1, 0xf8, 0xf9, 0xbf, 0xa1, 0x20, 0xeb, 0xee, 0xc7, 0xcf, 0xbf,
593            0xa9, 0x20, 0xcb, 0xc7, 0xef, 0xe1, 0xc7, 0xd1, 0xb4, 0xd9, 0x2e,
594        ];
595
596        let mut buf = String::with_capacity(2048);
597        let (read, _) = euckr_decoder_factory()
598            .decode(bytes, &mut buf, true)
599            .unwrap();
600        assert_eq!(read, bytes.len());
601        assert_eq!(
602            buf,
603            "悠久한 歷史와 傳統에 빛나는 우리 大韓國民은 3·1 運動으로 建立된 大韓民國臨時政府의 法統과 不義에 抗拒한 4·19 民主理念을 繼承하고, 祖國의 民主改革과 平和的統一의 使命에 立脚하여 正義·人道와 同胞愛로써 民族의 團結을 鞏固히 하고, 모든 社會的弊習과 不義를 打破하며, 自律과 調和를 바탕으로 自由民主的基本秩序를 더욱 確固히 하여 政治·經濟·社會·文化의 모든 領域에 있어서 各人의 機會를 均等히 하고, 能力을 最高度로 發揮하게 하며, 自由와 權利에 따르는 責任과 義務를 完遂하게 하여, 안으로는 國民生活의 均等한 向上을 期하고 밖으로는 恒久的인 世界平和와 人類共榮에 이바지함으로써 우리들과 우리들의 子孫의 安全과 自由와 幸福을 永遠히 確保할 것을 다짐하면서 1948年 7月 12日에 制定되고 8次에 걸쳐 改正된 憲法을 이제 國會의 議決을 거쳐 國民投票에 依하여 改正한다."
604        );
605    }
606
607    #[test]
608    fn gb2312_tests() {
609        let src = include_str!("../resources/gb2312tests/邓小平南巡讲话_unicode.txt");
610        let mut buf = vec![0; 1 << 15];
611        let (_, write) = gb2312_encoder_factory()
612            .encode(src, &mut buf, true)
613            .unwrap();
614        assert!(buf.len() >= write);
615        buf.truncate(write);
616
617        let bytes = include_bytes!("../resources/gb2312tests/邓小平南巡讲话_GB2312.txt").as_slice();
618        assert_eq!(buf.as_slice(), bytes);
619
620        let mut unicode = String::with_capacity(src.len() * 2);
621        gb2312_decoder_factory()
622            .decode(&buf, &mut unicode, true)
623            .unwrap();
624        assert_eq!(src, unicode);
625    }
626}