1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
//! This crate changes text between Apple's classic Mac OS encodings and
//! Unicode.
//!
//! Apple wrote the mappings and publishes them as mapping files. The
//! generator in `tools/generate-tables` reads those files and writes the
//! tables in `src/tables.rs`. The decode and encode operations obey the WHATWG
//! [Encoding Standard](https://encoding.spec.whatwg.org/), sections 9.1 and
//! 9.2. Thus this crate and a web browser give the same result for each
//! encoding in the standard.
//!
//! ```
//! use mac_encoding::Encoding;
//!
//! // A resource type code goes through Mac OS Roman and comes back.
//! assert_eq!(Encoding::Roman.decode(b"CODE"), "CODE");
//! assert_eq!(Encoding::Roman.encode("CODE").unwrap(), b"CODE");
//!
//! // The standard calls this encoding `macintosh`.
//! assert_eq!(Encoding::from_label("X-Mac-Roman"), Some(Encoding::Roman));
//! ```
//!
//! # The encodings in the standard
//!
//! The standard gives a name to only two of these encodings. Mac OS Roman is
//! `macintosh` and Mac OS Cyrillic is `x-mac-cyrillic`. The other 19
//! encodings have no name in the standard. Use [`Encoding::from_id`] for
//! them and [`Encoding::from_label`] for the other two.
//!
//! In the standard, `x-mac-cyrillic` also has the label `x-mac-ukrainian`.
//! This agrees with Apple. The mapping file `UKRAINE.TXT` tells us that Mac
//! OS 9 put the Ukrainian characters into Mac OS Cyrillic. Thus this crate
//! has no Ukrainian encoding, because Apple supplies no mapping file for it.
//!
//! # Two conditions that the standard does not include
//!
//! Section 9.1 permits a decoder to answer an ASCII byte with the same
//! value. This is not correct for three of these encodings. Mac OS Symbol has
//! GREEK CAPITAL LETTER ALPHA at byte `0x41`. Mac OS Dingbats and Mac OS
//! Keyboard also give other characters to many bytes in that range. Thus the
//! decoder always uses the table. For the other encodings, the table gives
//! the same result as the rule in the standard.
//!
//! Section 9 also has this rule: one byte gives one code point or none.
//! Apple's tables do not obey that rule. Mac OS Thai gives a character
//! and its position as two code points. Mac OS Devanagari, Gujarati, and
//! Gurmukhi give a two-byte code to some ligatures. The decoder and the
//! encoder both use the longest match first. Thus these mappings are correct
//! in the two directions.
//!
//! # Encodings that cannot encode a byte again correctly
//!
//! Mac OS Arabic, Farsi, and Hebrew give a direction to each mapping. Thus
//! more than one byte can have the same code point. For example, byte `0x2B`
//! and byte `0xAB` are both PLUS SIGN. Only the direction is different. The
//! decoder removes the direction and the encoder gives the lowest byte. Thus
//! a byte from the right-to-left group comes back as its left-to-right
//! equivalent.
//!
//! Mac OS Keyboard has one such condition for a different reason. Byte `0x09`
//! and byte `0x61` both decode to U+2423 OPEN BOX. Apple's comment for that
//! mapping says "duplicates mapping for 0x61, hence no round-trip".
//!
//! [`Encoding::encode_is_lossy`] tells you about all four encodings.
//! [`Encoding::is_directional`] tells you about the three with directions. To
//! encode text and then to decode it is always correct. Only the opposite
//! sequence can give a different byte.
//!
//! # Control characters in Mac OS Keyboard
//!
//! Apple's mapping files do not include the bytes `0x00` to `0x1F` and the
//! byte `0x7F`. For almost all encodings, each of these bytes gives the
//! control character with the same value. Mac OS Keyboard is different. It
//! gives key symbols to 22 of these bytes. For example, byte `0x02` is U+21E5
//! LEFTWARDS ARROW TO BAR.
//!
//! That font has no byte for the control character itself. Thus
//! [`Encoding::encode`] gives an error for those 22 control characters, and
//! [`Encoding::encode_html`] writes a character reference.
//!
//! # This crate does not need `std`
//!
//! The crate is `no_std` and uses `alloc` for [`String`] and [`Vec`]. It has
//! no features and no dependencies.
extern crate alloc;
extern crate std;
pub use ;
pub use ;
use String;
use Vec;
use fmt;
/// The table for one encoding.
///
/// The generator writes these tables. They are not part of the public API.
pub