]> git.saurik.com Git - apple/xnu.git/blame - bsd/hfs/hfs_encodings.c
xnu-792.17.14.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_encodings.c
CommitLineData
1c79356b 1/*
5d5c5d0d
A
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
3 *
8f6c56a5 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
8f6c56a5
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
8ad349bb 24 * limitations under the License.
8f6c56a5
A
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28
29#include <sys/param.h>
30#include <sys/systm.h>
31#include <sys/kernel.h>
1c79356b
A
32#include <sys/malloc.h>
33#include <sys/queue.h>
34#include <sys/utfconv.h>
35
36#include "hfs.h"
37
38
91447636
A
39lck_grp_t * encodinglst_lck_grp;
40lck_grp_attr_t * encodinglst_lck_grp_attr;
41lck_attr_t * encodinglst_lck_attr;
42
43
1c79356b
A
44/* hfs encoding converter list */
45SLIST_HEAD(encodinglst, hfs_encoding) hfs_encoding_list = {0};
91447636
A
46
47lck_mtx_t encodinglst_mutex;
48
1c79356b
A
49
50
51/* hfs encoding converter entry */
52struct hfs_encoding {
53 SLIST_ENTRY(hfs_encoding) link;
54 int refcount;
55 int kmod_id;
56 UInt32 encoding;
57 hfs_to_unicode_func_t get_unicode_func;
58 unicode_to_hfs_func_t get_hfsname_func;
59};
60
61/* XXX We should use an "official" interface! */
62extern kern_return_t kmod_destroy(host_priv_t host_priv, kmod_t id);
63extern struct host realhost;
64
65#define MAX_HFS_UNICODE_CHARS (15*5)
66
55e303ae 67int mac_roman_to_unicode(const Str31 hfs_str, UniChar *uni_str, UInt32 maxCharLen, UInt32 *usedCharLen);
1c79356b
A
68
69static int unicode_to_mac_roman(UniChar *uni_str, UInt32 unicodeChars, Str31 hfs_str);
70
71
72void
73hfs_converterinit(void)
74{
75 SLIST_INIT(&hfs_encoding_list);
91447636
A
76
77 encodinglst_lck_grp_attr= lck_grp_attr_alloc_init();
8f6c56a5 78 lck_grp_attr_setstat(encodinglst_lck_grp_attr);
91447636 79 encodinglst_lck_grp = lck_grp_alloc_init("cnode_hash", encodinglst_lck_grp_attr);
8f6c56a5 80
91447636 81 encodinglst_lck_attr = lck_attr_alloc_init();
8f6c56a5 82 //lck_attr_setdebug(encodinglst_lck_attr);
91447636
A
83
84 lck_mtx_init(&encodinglst_mutex, encodinglst_lck_grp, encodinglst_lck_attr);
1c79356b
A
85
86 /*
87 * add resident MacRoman converter and take a reference
88 * since its always "loaded".
89 */
90 hfs_addconverter(0, kTextEncodingMacRoman, mac_roman_to_unicode, unicode_to_mac_roman);
91 SLIST_FIRST(&hfs_encoding_list)->refcount++;
92}
93
94
95/*
96 * hfs_addconverter - add an HFS encoding converter
97 *
98 * This is called exclusivly by kernel loadable modules
99 * (like HFS_Japanese.kmod) to register hfs encoding
100 * conversion routines.
101 *
102 */
103int
104hfs_addconverter(int id, UInt32 encoding, hfs_to_unicode_func_t get_unicode, unicode_to_hfs_func_t get_hfsname)
105{
106 struct hfs_encoding *encp;
107
108 MALLOC(encp, struct hfs_encoding *, sizeof(struct hfs_encoding), M_TEMP, M_WAITOK);
109
91447636 110 lck_mtx_lock(&encodinglst_mutex);
1c79356b
A
111
112 encp->link.sle_next = NULL;
113 encp->refcount = 0;
114 encp->encoding = encoding;
115 encp->get_unicode_func = get_unicode;
116 encp->get_hfsname_func = get_hfsname;
117 encp->kmod_id = id;
118 SLIST_INSERT_HEAD(&hfs_encoding_list, encp, link);
119
91447636 120 lck_mtx_unlock(&encodinglst_mutex);
1c79356b
A
121 return (0);
122}
123
124
125/*
126 * hfs_remconverter - remove an HFS encoding converter
127 *
128 * Can be called by a kernel loadable module's finalize
129 * routine to remove an encoding converter so that the
130 * module (i.e. the code) can be unloaded.
131 *
132 * However, in the normal case, the removing and unloading
133 * of these converters is done in hfs_relconverter.
134 * The call is initiated from within the kernel during the unmounting of an hfs voulume.
135 */
136int
137hfs_remconverter(int id, UInt32 encoding)
138{
139 struct hfs_encoding *encp;
1c79356b 140
91447636 141 lck_mtx_lock(&encodinglst_mutex);
1c79356b
A
142 SLIST_FOREACH(encp, &hfs_encoding_list, link) {
143 if (encp->encoding == encoding && encp->kmod_id == id) {
144 encp->refcount--;
145
146 /* if converter is no longer in use, release it */
147 if (encp->refcount <= 0 && encp->kmod_id != 0) {
148 SLIST_REMOVE(&hfs_encoding_list, encp, hfs_encoding, link);
91447636 149 lck_mtx_unlock(&encodinglst_mutex);
1c79356b 150 FREE(encp, M_TEMP);
91447636 151 return (0);
1c79356b 152 } else {
91447636
A
153 lck_mtx_unlock(&encodinglst_mutex);
154 return (1); /* busy */
1c79356b
A
155 }
156 break;
157 }
158 }
91447636 159 lck_mtx_unlock(&encodinglst_mutex);
1c79356b 160
91447636 161 return (0);
1c79356b
A
162}
163
164
165/*
166 * hfs_getconverter - get HFS encoding converters
167 *
168 * Normally called during the mounting of an hfs voulume.
169 */
170int
171hfs_getconverter(UInt32 encoding, hfs_to_unicode_func_t *get_unicode, unicode_to_hfs_func_t *get_hfsname)
172{
173 struct hfs_encoding *encp;
174 int found = 0;
175
91447636 176 lck_mtx_lock(&encodinglst_mutex);
1c79356b
A
177 SLIST_FOREACH(encp, &hfs_encoding_list, link) {
178 if (encp->encoding == encoding) {
179 found = 1;
180 *get_unicode = encp->get_unicode_func;
181 *get_hfsname = encp->get_hfsname_func;
182 ++encp->refcount;
183 break;
184 }
185 }
91447636 186 lck_mtx_unlock(&encodinglst_mutex);
1c79356b
A
187
188 if (!found) {
189 *get_unicode = NULL;
190 *get_hfsname = NULL;
191 return (EINVAL);
192 }
193
194 return (0);
195}
196
197
198/*
199 * hfs_relconverter - release interest in an HFS encoding converter
200 *
201 * Normally called during the unmounting of an hfs voulume.
202 */
203int
204hfs_relconverter(UInt32 encoding)
205{
206 struct hfs_encoding *encp;
1c79356b 207
91447636 208 lck_mtx_lock(&encodinglst_mutex);
1c79356b
A
209 SLIST_FOREACH(encp, &hfs_encoding_list, link) {
210 if (encp->encoding == encoding) {
1c79356b
A
211 encp->refcount--;
212
213 /* if converter is no longer in use, release it */
214 if (encp->refcount <= 0 && encp->kmod_id != 0) {
215 int id = encp->kmod_id;
216
217 SLIST_REMOVE(&hfs_encoding_list, encp, hfs_encoding, link);
91447636
A
218 lck_mtx_unlock(&encodinglst_mutex);
219
220 FREE(encp, M_TEMP);
221 kmod_destroy((host_priv_t) host_priv_self(), id);
222 return (0);
1c79356b 223 }
91447636
A
224 lck_mtx_unlock(&encodinglst_mutex);
225 return (0);
1c79356b
A
226 }
227 }
91447636 228 lck_mtx_unlock(&encodinglst_mutex);
1c79356b 229
91447636 230 return (EINVAL);
1c79356b
A
231}
232
233
234/*
235 * Convert HFS encoded string into UTF-8
236 *
237 * Unicode output is fully decomposed
238 * '/' chars are converted to ':'
239 */
240int
241hfs_to_utf8(ExtendedVCB *vcb, Str31 hfs_str, ByteCount maxDstLen, ByteCount *actualDstLen, unsigned char* dstStr)
242{
243 int error;
244 UniChar uniStr[MAX_HFS_UNICODE_CHARS];
245 ItemCount uniCount;
246 size_t utf8len;
247 hfs_to_unicode_func_t hfs_get_unicode = VCBTOHFS(vcb)->hfs_get_unicode;
248
249 error = hfs_get_unicode(hfs_str, uniStr, MAX_HFS_UNICODE_CHARS, &uniCount);
250
251 if (uniCount == 0)
252 error = EINVAL;
253
254 if (error == 0) {
255 error = utf8_encodestr(uniStr, uniCount * sizeof(UniChar), dstStr, &utf8len, maxDstLen , ':', 0);
256 if (error == ENAMETOOLONG)
257 *actualDstLen = utf8_encodelen(uniStr, uniCount * sizeof(UniChar), ':', 0);
258 else
259 *actualDstLen = utf8len;
260 }
261
262 return error;
263}
264
265
266/*
267 * When an HFS name cannot be encoded with the current
268 * volume encoding then MacRoman is used as a fallback.
269 */
270int
271mac_roman_to_utf8(Str31 hfs_str, ByteCount maxDstLen, ByteCount *actualDstLen, unsigned char* dstStr)
272{
273 int error;
274 UniChar uniStr[MAX_HFS_UNICODE_CHARS];
275 ItemCount uniCount;
276 size_t utf8len;
277
278 error = mac_roman_to_unicode(hfs_str, uniStr, MAX_HFS_UNICODE_CHARS, &uniCount);
279
280 if (uniCount == 0)
281 error = EINVAL;
282
283 if (error == 0) {
284 error = utf8_encodestr(uniStr, uniCount * sizeof(UniChar), dstStr, &utf8len, maxDstLen , ':', 0);
285 if (error == ENAMETOOLONG)
286 *actualDstLen = utf8_encodelen(uniStr, uniCount * sizeof(UniChar), ':', 0);
287 else
288 *actualDstLen = utf8len;
289 }
290
291 return error;
292}
293
294
9bccf70c
A
295/*
296 * Convert Unicode string into HFS encoding
297 *
298 * ':' chars are converted to '/'
299 * Assumes input represents fully decomposed Unicode
300 */
301int
302unicode_to_hfs(ExtendedVCB *vcb, ByteCount srcLen, u_int16_t* srcStr, Str31 dstStr, int retry)
303{
304 int error;
305 unicode_to_hfs_func_t hfs_get_hfsname = VCBTOHFS(vcb)->hfs_get_hfsname;
306
307 error = hfs_get_hfsname(srcStr, srcLen/sizeof(UniChar), dstStr);
308 if (error && retry) {
309 error = unicode_to_mac_roman(srcStr, srcLen/sizeof(UniChar), dstStr);
310 }
311 return error;
312}
313
1c79356b
A
314/*
315 * Convert UTF-8 string into HFS encoding
316 *
317 * ':' chars are converted to '/'
318 * Assumes input represents fully decomposed Unicode
319 */
320int
9bccf70c 321utf8_to_hfs(ExtendedVCB *vcb, ByteCount srcLen, const unsigned char* srcStr, Str31 dstStr/*, int retry*/)
1c79356b
A
322{
323 int error;
324 UniChar uniStr[MAX_HFS_UNICODE_CHARS];
325 size_t ucslen;
1c79356b
A
326
327 error = utf8_decodestr(srcStr, srcLen, uniStr, &ucslen, sizeof(uniStr), ':', 0);
328 if (error == 0)
9bccf70c 329 error = unicode_to_hfs(vcb, ucslen, uniStr, dstStr, 1);
1c79356b
A
330
331 return error;
332}
333
334int
335utf8_to_mac_roman(ByteCount srcLen, const unsigned char* srcStr, Str31 dstStr)
336{
337 int error;
338 UniChar uniStr[MAX_HFS_UNICODE_CHARS];
339 size_t ucslen;
340
341 error = utf8_decodestr(srcStr, srcLen, uniStr, &ucslen, sizeof(uniStr), ':', 0);
342 if (error == 0)
343 error = unicode_to_mac_roman(uniStr, ucslen/sizeof(UniChar), dstStr);
344
345 return error;
346}
347
348/*
349 * HFS MacRoman to/from Unicode conversions are built into the kernel
350 * All others hfs encodings are loadable.
351 */
352
353/* 0x00A0 - 0x00FF = Latin 1 Supplement (30 total) */
354static UInt8 gLatin1Table[] = {
355 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
356 /* 0x00A0 */ 0xCA, 0xC1, 0xA2, 0xA3, 0xDB, 0xB4, '?', 0xA4, 0xAC, 0xA9, 0xBB, 0xC7, 0xC2, '?', 0xA8, 0xF8,
357 /* 0x00B0 */ 0xA1, 0XB1, '?', '?', 0xAB, 0xB5, 0xA6, 0xe1, 0xFC, '?', 0xBC, 0xC8, '?', '?', '?', 0xC0,
358 /* 0x00C0 */ '?', '?', '?', '?', '?', '?', 0xAE, '?', '?', '?', '?', '?', '?', '?', '?', '?',
359 /* 0x00D0 */ '?', '?', '?', '?', '?', '?', '?', '?', 0xAF, '?', '?', '?', '?', '?', '?', 0xA7,
360 /* 0x00E0 */ '?', '?', '?', '?', '?', '?', 0xBE, '?', '?', '?', '?', '?', '?', '?', '?', '?',
361 /* 0x00F0 */ '?', '?', '?', '?', '?', '?', '?', 0xD6, 0xBF, '?', '?', '?', '?', '?', '?', '?'
362};
363
364/* 0x02C0 - 0x02DF = Spacing Modifiers (8 total) */
365static UInt8 gSpaceModsTable[] = {
366 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
367 /* 0x02C0 */ '?', '?', '?', '?', '?', '?', 0xF6, 0xFF, '?', '?', '?', '?', '?', '?', '?', '?',
368 /* 0x02D0 */ '?', '?', '?', '?', '?', '?', '?', '?', 0xF9, 0xFA, 0xFB, 0xFE, 0xF7, 0xFD, '?', '?'
369};
370
371/* 0x2010 - 0x20AF = General Punctuation (17 total) */
372static UInt8 gPunctTable[] = {
373 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
374 /* 0x2010 */ '?', '?', '?', 0xd0, 0xd1, '?', '?', '?', 0xd4, 0xd5, 0xe2, '?', 0xd2, 0xd3, 0xe3, '?',
375 /* 0x2020 */ 0xa0, 0xe0, 0xa5, '?', '?', '?', 0xc9, '?', '?', '?', '?', '?', '?', '?', '?', '?',
376 /* 0x2030 */ 0xe4, '?', '?', '?', '?', '?', '?', '?', '?', 0xdc, 0xdd, '?', '?', '?', '?', '?',
377 /* 0x2040 */ '?', '?', '?', '?', 0xda, '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?',
378 /* 0x2050 */ '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?',
379 /* 0x2060 */ '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?',
380 /* 0x2070 */ '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?',
381 /* 0x2080 */ '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?',
382 /* 0x2090 */ '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?',
383 /* 0x20A0 */ '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', 0xdb, '?', '?', '?'
384};
385
386/* 0x22xx = Mathematical Operators (11 total) */
387static UInt8 gMathTable[] = {
388 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
389 /* 0x2200 */ '?', '?', 0xb6, '?', '?', '?', 0xc6, '?', '?', '?', '?', '?', '?', '?', '?', 0xb8,
390 /* 0x2210 */ '?', 0xb7, '?', '?', '?', '?', '?', '?', '?', '?', 0xc3, '?', '?', '?', 0xb0, '?',
391 /* 0x2220 */ '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', 0xba, '?', '?', '?', '?',
392 /* 0x2230 */ '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?',
393 /* 0x2240 */ '?', '?', '?', '?', '?', '?', '?', '?', 0xc5, '?', '?', '?', '?', '?', '?', '?',
394 /* 0x2250 */ '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?',
395 /* 0x2260 */ 0xad, '?', '?', '?', 0xb2, 0xb3, '?', '?'
396};
397
398/* */
399static UInt8 gReverseCombTable[] = {
400 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
401 /* 0x40 */ 0xDA, 0x40, 0xDA, 0xDA, 0xDA, 0x56, 0xDA, 0xDA, 0xDA, 0x6C, 0xDA, 0xDA, 0xDA, 0xDA, 0x82, 0x98,
402 /* 0x50 */ 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xAE, 0xDA, 0xDA, 0xDA, 0xC4, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA,
403 /* 0x60 */ 0xDA, 0x4B, 0xDA, 0xDA, 0xDA, 0x61, 0xDA, 0xDA, 0xDA, 0x77, 0xDA, 0xDA, 0xDA, 0xDA, 0x8D, 0xA3,
404 /* 0x70 */ 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xB9, 0xDA, 0xDA, 0xDA, 0xCF, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA,
405
406 /* Combining Diacritical Marks (0x0300 - 0x030A) */
407 /* 0 1 2 3 4 5 6 7 8 9 A */
408 /* 'A' */
409 /* 0x0300 */ 0xCB, 0xE7, 0xE5, 0xCC, '?', '?', '?', '?', 0x80, '?', 0x81,
410
411 /* 'a' */
412 /* 0x0300 */ 0x88, 0x87, 0x89, 0x8B, '?', '?', '?', '?', 0x8A, '?', 0x8C,
413
414 /* 'E' */
415 /* 0x0300 */ 0xE9, 0x83, 0xE6, '?', '?', '?', '?', '?', 0xE8, '?', '?',
416
417 /* 'e' */
418 /* 0x0300 */ 0x8F, 0x8E, 0x90, '?', '?', '?', '?', '?', 0x91, '?', '?',
419
420 /* 'I' */
421 /* 0x0300 */ 0xED, 0xEA, 0xEB, '?', '?', '?', '?', '?', 0xEC, '?', '?',
422
423 /* 'i' */
424 /* 0x0300 */ 0x93, 0x92, 0x94, '?', '?', '?', '?', '?', 0x95, '?', '?',
425
426 /* 'N' */
427 /* 0x0300 */ '?', '?', '?', 0x84, '?', '?', '?', '?', '?', '?', '?',
428
429 /* 'n' */
430 /* 0x0300 */ '?', '?', '?', 0x96, '?', '?', '?', '?', '?', '?', '?',
431
432 /* 'O' */
433 /* 0x0300 */ 0xF1, 0xEE, 0xEF, 0xCD, '?', '?', '?', '?', 0x85, '?', '?',
434
435 /* 'o' */
436 /* 0x0300 */ 0x98, 0x97, 0x99, 0x9B, '?', '?', '?', '?', 0x9A, '?', '?',
437
438 /* 'U' */
439 /* 0x0300 */ 0xF4, 0xF2, 0xF3, '?', '?', '?', '?', '?', 0x86, '?', '?',
440
441 /* 'u' */
442 /* 0x0300 */ 0x9D, 0x9C, 0x9E, '?', '?', '?', '?', '?', 0x9F, '?', '?',
443
444 /* 'Y' */
445 /* 0x0300 */ '?', '?', '?', '?', '?', '?', '?', '?', 0xD9, '?', '?',
446
447 /* 'y' */
448 /* 0x0300 */ '?', '?', '?', '?', '?', '?', '?', '?', 0xD8, '?', '?',
449
450 /* else */
451 /* 0x0300 */ '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?'
452};
453
454
455/*
456 * Convert Unicode string into HFS MacRoman encoding
457 *
458 * Assumes Unicode input is fully decomposed
459 */
460static int unicode_to_mac_roman(UniChar *uni_str, UInt32 unicodeChars, Str31 hfs_str)
461{
462 UInt8 *p;
463 const UniChar *u;
464 UniChar c;
465 UniChar mask;
466 UInt16 inputChars;
467 UInt16 pascalChars;
468 OSErr result = noErr;
469 UInt8 lsb;
470 UInt8 prevChar;
471 UInt8 mc;
472
473 mask = (UniChar) 0xFF80;
474 p = &hfs_str[1];
475 u = uni_str;
476 inputChars = unicodeChars;
477 pascalChars = prevChar = 0;
478
479 while (inputChars) {
480 c = *(u++);
481 lsb = (UInt8) c;
482
483 /*
484 * If its not 7-bit ascii, then we need to map it
485 */
486 if ( c & mask ) {
487 mc = '?';
488 switch (c & 0xFF00) {
489 case 0x0000:
490 if (lsb >= 0xA0)
491 mc = gLatin1Table[lsb - 0xA0];
492 break;
493
494 case 0x0200:
495 if (lsb >= 0xC0 && lsb <= 0xDF)
496 mc = gSpaceModsTable[lsb - 0xC0];
497 break;
498
499 case 0x2000:
500 if (lsb >= 0x10 && lsb <= 0xAF)
501 mc = gPunctTable[lsb- 0x10];
502 break;
503
504 case 0x2200:
505 if (lsb <= 0x68)
506 mc = gMathTable[lsb];
507 break;
508
509 case 0x0300:
510 if (c <= 0x030A) {
511 if (prevChar >= 'A' && prevChar < 'z') {
512 mc = gReverseCombTable[gReverseCombTable[prevChar - 0x40] + lsb];
513 --p; /* backup over base char */
514 --pascalChars;
515 }
516 } else {
517 switch (c) {
518 case 0x0327: /* combining cedilla */
519 if (prevChar == 'C')
520 mc = 0x82;
521 else if (prevChar == 'c')
522 mc = 0x8D;
523 else
524 break;
525 --p; /* backup over base char */
526 --pascalChars;
527 break;
528
529 case 0x03A9: mc = 0xBD; break; /* omega */
530
531 case 0x03C0: mc = 0xB9; break; /* pi */
532 }
533 }
534 break;
535
536 default:
537 switch (c) {
538 case 0x0131: mc = 0xf5; break; /* dotless i */
539
540 case 0x0152: mc = 0xce; break; /* OE */
541
542 case 0x0153: mc = 0xcf; break; /* oe */
543
544