textcode/
iso6937.rs

1//! Latin superset of ISO/IEC 6937 with addition of the Euro symbol
2
3use std::io::Write;
4
5use crate::{
6    ENCODE_FALLBACK,
7    Textcode,
8    data::{
9        DECODE_MAP_ISO6937,
10        ENCODE_MAP_ISO6937,
11        HI_MAP_ISO6937,
12    },
13    write_ascii,
14    write_decode_fallback,
15    write_utf8,
16};
17
18/// Latin superset of ISO/IEC 6937 with addition of the Euro symbol.
19pub struct Iso6937;
20
21impl Textcode for Iso6937 {
22    fn decode<W: Write, R: AsRef<[u8]>>(src: R, dst: &mut W) -> std::io::Result<usize> {
23        let src = src.as_ref();
24        let mut skip = 0;
25        let size = src.len();
26        let mut written = 0;
27
28        while skip < size {
29            let c = src[skip];
30
31            if c <= 0x7F {
32                written += write_ascii(dst, c)?;
33            } else if (0xC1 ..= 0xCF).contains(&c) {
34                // diactrics
35                skip += 1;
36
37                if skip >= size {
38                    written += write_decode_fallback(dst)?;
39                    break;
40                }
41
42                let map_skip =
43                    usize::from(c - 0xC1) * usize::from(b'z' - b'A' + 1) + (0x0100 - 0x00A0);
44                let c = src[skip];
45
46                if (b'A' ..= b'z').contains(&c) {
47                    let offset = map_skip + usize::from(c - b'A');
48                    let u = DECODE_MAP_ISO6937[offset] as u32;
49                    written += write_utf8(dst, u)?;
50                } else {
51                    written += write_decode_fallback(dst)?;
52                }
53            } else if c >= 0xA0 {
54                let offset = usize::from(c) - 0xA0;
55                let u = DECODE_MAP_ISO6937[offset] as u32;
56                written += write_utf8(dst, u)?;
57            } else {
58                written += write_decode_fallback(dst)?;
59            }
60
61            skip += 1;
62        }
63
64        Ok(written)
65    }
66
67    fn encode<W: Write, R: AsRef<str>>(src: R, dst: &mut W) -> std::io::Result<usize> {
68        let src = src.as_ref();
69        let mut written = 0;
70
71        for ch in src.chars() {
72            let u = ch as u32;
73            let mut buf = [0u8; 2];
74            let n: usize;
75
76            if u <= 0x7F {
77                buf[0] = u as u8;
78                n = 1;
79            } else if u >= 0x00A0 && u <= 0xFFFF {
80                let c = u as u16;
81                let hi = (c >> 8) as usize;
82                let lo = (c & 0xFF) as usize;
83
84                let pos = HI_MAP_ISO6937[hi] * 0x100 + lo;
85                let code = ENCODE_MAP_ISO6937[pos];
86
87                if code > 0xFF {
88                    buf[0] = (code >> 8) as u8;
89                    buf[1] = (code & 0xFF) as u8;
90                    n = 2;
91                } else if code > 0 {
92                    buf[0] = code as u8;
93                    n = 1;
94                } else {
95                    buf[0] = ENCODE_FALLBACK;
96                    n = 1;
97                }
98            } else {
99                buf[0] = ENCODE_FALLBACK;
100                n = 1;
101            }
102
103            dst.write_all(&buf[.. n])?;
104            written += n;
105        }
106
107        Ok(written)
108    }
109}