1use 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
18pub 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 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}