1 //! Convert a string in IBM codepage 437 to UTF-8
2 
3 /// Trait to convert IBM codepage 437 to the target type
4 pub trait FromCp437 {
5     /// Target type
6     type Target;
7 
8     /// Function that does the conversion from cp437.
9     /// Gennerally allocations will be avoided if all data falls into the ASCII range.
from_cp437(self) -> Self::Target10     fn from_cp437(self) -> Self::Target;
11 }
12 
13 impl<'a> FromCp437 for &'a [u8] {
14     type Target = ::std::borrow::Cow<'a, str>;
15 
from_cp437(self) -> Self::Target16     fn from_cp437(self) -> Self::Target
17     {
18         if self.iter().all(|c| *c < 0x80) {
19             ::std::str::from_utf8(self).unwrap().into()
20         }
21         else {
22             self.iter().map(|c| to_char(*c)).collect::<String>().into()
23         }
24     }
25 }
26 
27 impl FromCp437 for Vec<u8> {
28     type Target = String;
29 
from_cp437(self) -> Self::Target30     fn from_cp437(self) -> Self::Target {
31         if self.iter().all(|c| *c < 0x80) {
32             String::from_utf8(self).unwrap()
33         }
34         else {
35             self.into_iter().map(|c| to_char(c)).collect()
36         }
37     }
38 }
39 
to_char(input: u8) -> char40 fn to_char(input: u8) -> char
41 {
42     let output = match input
43     {
44         0x00 ... 0x7f => input as u32,
45         0x80 => 0x00c7,
46         0x81 => 0x00fc,
47         0x82 => 0x00e9,
48         0x83 => 0x00e2,
49         0x84 => 0x00e4,
50         0x85 => 0x00e0,
51         0x86 => 0x00e5,
52         0x87 => 0x00e7,
53         0x88 => 0x00ea,
54         0x89 => 0x00eb,
55         0x8a => 0x00e8,
56         0x8b => 0x00ef,
57         0x8c => 0x00ee,
58         0x8d => 0x00ec,
59         0x8e => 0x00c4,
60         0x8f => 0x00c5,
61         0x90 => 0x00c9,
62         0x91 => 0x00e6,
63         0x92 => 0x00c6,
64         0x93 => 0x00f4,
65         0x94 => 0x00f6,
66         0x95 => 0x00f2,
67         0x96 => 0x00fb,
68         0x97 => 0x00f9,
69         0x98 => 0x00ff,
70         0x99 => 0x00d6,
71         0x9a => 0x00dc,
72         0x9b => 0x00a2,
73         0x9c => 0x00a3,
74         0x9d => 0x00a5,
75         0x9e => 0x20a7,
76         0x9f => 0x0192,
77         0xa0 => 0x00e1,
78         0xa1 => 0x00ed,
79         0xa2 => 0x00f3,
80         0xa3 => 0x00fa,
81         0xa4 => 0x00f1,
82         0xa5 => 0x00d1,
83         0xa6 => 0x00aa,
84         0xa7 => 0x00ba,
85         0xa8 => 0x00bf,
86         0xa9 => 0x2310,
87         0xaa => 0x00ac,
88         0xab => 0x00bd,
89         0xac => 0x00bc,
90         0xad => 0x00a1,
91         0xae => 0x00ab,
92         0xaf => 0x00bb,
93         0xb0 => 0x2591,
94         0xb1 => 0x2592,
95         0xb2 => 0x2593,
96         0xb3 => 0x2502,
97         0xb4 => 0x2524,
98         0xb5 => 0x2561,
99         0xb6 => 0x2562,
100         0xb7 => 0x2556,
101         0xb8 => 0x2555,
102         0xb9 => 0x2563,
103         0xba => 0x2551,
104         0xbb => 0x2557,
105         0xbc => 0x255d,
106         0xbd => 0x255c,
107         0xbe => 0x255b,
108         0xbf => 0x2510,
109         0xc0 => 0x2514,
110         0xc1 => 0x2534,
111         0xc2 => 0x252c,
112         0xc3 => 0x251c,
113         0xc4 => 0x2500,
114         0xc5 => 0x253c,
115         0xc6 => 0x255e,
116         0xc7 => 0x255f,
117         0xc8 => 0x255a,
118         0xc9 => 0x2554,
119         0xca => 0x2569,
120         0xcb => 0x2566,
121         0xcc => 0x2560,
122         0xcd => 0x2550,
123         0xce => 0x256c,
124         0xcf => 0x2567,
125         0xd0 => 0x2568,
126         0xd1 => 0x2564,
127         0xd2 => 0x2565,
128         0xd3 => 0x2559,
129         0xd4 => 0x2558,
130         0xd5 => 0x2552,
131         0xd6 => 0x2553,
132         0xd7 => 0x256b,
133         0xd8 => 0x256a,
134         0xd9 => 0x2518,
135         0xda => 0x250c,
136         0xdb => 0x2588,
137         0xdc => 0x2584,
138         0xdd => 0x258c,
139         0xde => 0x2590,
140         0xdf => 0x2580,
141         0xe0 => 0x03b1,
142         0xe1 => 0x00df,
143         0xe2 => 0x0393,
144         0xe3 => 0x03c0,
145         0xe4 => 0x03a3,
146         0xe5 => 0x03c3,
147         0xe6 => 0x00b5,
148         0xe7 => 0x03c4,
149         0xe8 => 0x03a6,
150         0xe9 => 0x0398,
151         0xea => 0x03a9,
152         0xeb => 0x03b4,
153         0xec => 0x221e,
154         0xed => 0x03c6,
155         0xee => 0x03b5,
156         0xef => 0x2229,
157         0xf0 => 0x2261,
158         0xf1 => 0x00b1,
159         0xf2 => 0x2265,
160         0xf3 => 0x2264,
161         0xf4 => 0x2320,
162         0xf5 => 0x2321,
163         0xf6 => 0x00f7,
164         0xf7 => 0x2248,
165         0xf8 => 0x00b0,
166         0xf9 => 0x2219,
167         0xfa => 0x00b7,
168         0xfb => 0x221a,
169         0xfc => 0x207f,
170         0xfd => 0x00b2,
171         0xfe => 0x25a0,
172         0xff => 0x00a0,
173         _ => unreachable!(),
174     };
175     ::std::char::from_u32(output).unwrap()
176 }
177 
178 #[cfg(test)]
179 mod test
180 {
181     #[test]
to_char_valid()182     fn to_char_valid()
183     {
184         for i in 0x00_u32 .. 0x100
185         {
186             super::to_char(i as u8);
187         }
188     }
189 
190     #[test]
ascii()191     fn ascii() {
192         for i in 0x00 .. 0x80 {
193             assert_eq!(super::to_char(i), i as char);
194         }
195     }
196 
197     #[test]
example_slice()198     fn example_slice() {
199         use super::FromCp437;
200         let data = b"Cura\x87ao";
201         assert!(::std::str::from_utf8(data).is_err());
202         assert_eq!(data.from_cp437(), "Curaçao");
203     }
204 
205     #[test]
example_vec()206     fn example_vec() {
207         use super::FromCp437;
208         let data = vec![0xCC, 0xCD, 0xCD, 0xB9];
209         assert!(String::from_utf8(data.clone()).is_err());
210         assert_eq!(&data.from_cp437(), "╠══╣");
211     }
212 }
213