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