Skip to main content

anyxml_encoding/
euc.rs

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