xref: /haiku/src/libs/iconv/big5_2003.h (revision 17889a8c70dbb3d59c1412f6431968753c767bab)
1 /*
2  * Copyright (C) 1999-2001, 2005 Free Software Foundation, Inc.
3  * This file is part of the GNU LIBICONV Library.
4  *
5  * The GNU LIBICONV Library is free software; you can redistribute it
6  * and/or modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * The GNU LIBICONV Library is distributed in the hope that it will be
11  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with the GNU LIBICONV Library; see the file COPYING.LIB.
17  * If not, write to the Free Software Foundation, Inc., 51 Franklin Street,
18  * Fifth Floor, Boston, MA 02110-1301, USA.
19  */
20 
21 /*
22  * BIG5-2003
23  */
24 
25 /*
26  * BIG5-2003 is a slightly extended and slightly modified version of BIG5.
27  * It is actually nearer to Microsoft CP950 than to BIG5. The differences
28  * between EASTASIA/OTHER/BIG5.TXT found on ftp.unicode.org and BIG5-2003.TXT
29  * are as follows:
30  *
31  * 1. Some characters in the symbols area (0xA140..0xA2CE) are defined
32  *    differently:
33  *
34  *     code   BIG5.TXT                       BIG5-2003.TXT
35  *    0xA145  0x2022 # BULLET                0x2027 # HYPHENATION POINT
36  *    0xA14E  0xFF64 # HALFWIDTH IDEOGRAPHIC COMMA
37  *                                           0xFE51 # SMALL IDEOGRAPHIC COMMA
38  *    0xA156  0x2013 # EN DASH               0x2015 # HORIZONTAL BAR
39  *    0xA15A    ---                          0x2574 # BOX DRAWINGS LIGHT LEFT
40  *    0xA1C3    ---                          0xFFE3 # FULLWIDTH MACRON
41  *    0xA1C5    ---                          0x02CD # MODIFIER LETTER LOW MACRON
42  *    0xA1E3  0x223C # TILDE OPERATOR        0xFF5E # FULLWIDTH TILDE
43  *    0xA1F2  0x2641 # EARTH                 0x2295 # CIRCLED PLUS
44  *    0xA1F3  0x2609 # SUN                   0x2299 # CIRCLED DOT OPERATOR
45  *    0xA1FE    ---                          0xFF0F # FULLWIDTH SOLIDUS
46  *    0xA240    ---                          0xFF3C # FULLWIDTH REVERSE SOLIDUS
47  *    0xA241  0xFF0F # FULLWIDTH SOLIDUS     0x2215 # DIVISION SLASH
48  *    0xA242  0xFF3C # FULLWIDTH REVERSE SOLIDUS
49  *                                           0xFE68 # SMALL REVERSE SOLIDUS
50  *    0xA244  0x00A5 # YEN SIGN              0xFFE5 # FULLWIDTH YEN SIGN
51  *    0xA246  0x00A2 # CENT SIGN             0xFFE0 # FULLWIDTH CENT SIGN
52  *    0xA247  0x00A3 # POUND SIGN            0xFFE1 # FULLWIDTH POUND SIGN
53  *    0xA2A4  0x2550 # BOX DRAWINGS DOUBLE HORIZONTAL
54  *                                           0x2501 # BOX DRAWINGS HEAVY HORIZONTAL
55  *    0xA2A5  0x255E # BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
56  *                                           0x251D # BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY
57  *    0xA2A6  0x256A # BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
58  *                                           0x253F # BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY
59  *    0xA2A7  0x2561 # BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
60  *                                           0x2525 # BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY
61  *    0xA2CC    ---                          0x3038 # HANGZHOU NUMERAL TEN
62  *    0xA2CD  0x5344                         0x3039 # HANGZHOU NUMERAL TWENTY
63  *    0xA2CE    ---                          0x303A # HANGZHOU NUMERAL THIRTY
64  *
65  * 2. A control symbols area is added:
66  *
67  *         code
68  *    0xA3C0..0xA3E0  U+2400..U+2421
69  *
70  * 3. The Euro sign is added:
71  *
72  *     code
73  *    0xA3E1  0x20AC # EURO SIGN
74  *
75  * 4. Some characters in the main area are defined differently:
76  *
77  *     code   BIG5.TXT                       BIG5-2003.TXT
78  *    0xC255  0x5F5D                         0x5F5E
79  *
80  * 5. The area 0xC6A1..0xC7FE is organized differently:
81  *
82  *         code
83  *    0xC6A1..0xC6BE  numerals (was in BIG5.TXT at 0xC7E9..0xC7FC)
84  *    0xC6BF..0xC6D7  radicals
85  *    0xC6D8..0xC6E6  rarely used symbols
86  *    0xC6E7..0xC77A  hiragana (U+3041..U+3093, was in BIG5.TXT at 0xC6A5..0xC6F7)
87  *    0xC77B..0xC7F2  katakana (U+30A1..U+30F6, was in BIG5.TXT at 0xC6F8..0xC7B0)
88  *
89  * 6. Some characters are added at 0xF9D6..0xF9DC.
90  *
91  * 7. Box drawing characters are added at 0xF9DD..0xF9FE.
92  *
93  *    Note: 4 of these characters are mapped in a non-inversible way, because
94  *    Unicode does not yet include the corresponding characters:
95  *
96  *     code                                           Unicode approximation
97  *    0xF9FA  BOX DRAWINGS DOUBLE ARC DOWN AND RIGHT  0x2554
98  *    0xF9FB  BOX DRAWINGS DOUBLE ARC DOWN AND LEFT   0x2557
99  *    0xF9FC  BOX DRAWINGS DOUBLE ARC UP AND RIGHT    0x255A
100  *    0xF9FD  BOX DRAWINGS DOUBLE ARC UP AND LEFT     0x255D
101  *
102  * 8. Private area mappings are added:
103  *
104  *              code                 Unicode
105  *    0x{81..8D}{40..7E,A1..FE}  U+EEB8..U+F6B0
106  *    0x{8E..A0}{40..7E,A1..FE}  U+E311..U+EEB7
107  *    0x{FA..FE}{40..7E,A1..FE}  U+E000..U+E310
108  *
109  *    These mappings are not contained in the BSMI Big5-2003 standard. However,
110  *    they were contained in a draft of it.
111  */
112 
113 static const unsigned short big5_2003_2uni_pagea1[314] = {
114   /* 0xa1 */
115   0x3000, 0xff0c, 0x3001, 0x3002, 0xff0e, 0x2027, 0xff1b, 0xff1a,
116   0xff1f, 0xff01, 0xfe30, 0x2026, 0x2025, 0xfe50, 0xfe51, 0xfe52,
117   0x00b7, 0xfe54, 0xfe55, 0xfe56, 0xfe57, 0xff5c, 0x2015, 0xfe31,
118   0x2014, 0xfe33, 0x2574, 0xfe34, 0xfe4f, 0xff08, 0xff09, 0xfe35,
119   0xfe36, 0xff5b, 0xff5d, 0xfe37, 0xfe38, 0x3014, 0x3015, 0xfe39,
120   0xfe3a, 0x3010, 0x3011, 0xfe3b, 0xfe3c, 0x300a, 0x300b, 0xfe3d,
121   0xfe3e, 0x3008, 0x3009, 0xfe3f, 0xfe40, 0x300c, 0x300d, 0xfe41,
122   0xfe42, 0x300e, 0x300f, 0xfe43, 0xfe44, 0xfe59, 0xfe5a, 0xfe5b,
123   0xfe5c, 0xfe5d, 0xfe5e, 0x2018, 0x2019, 0x201c, 0x201d, 0x301d,
124   0x301e, 0x2035, 0x2032, 0xff03, 0xff06, 0xff0a, 0x203b, 0x00a7,
125   0x3003, 0x25cb, 0x25cf, 0x25b3, 0x25b2, 0x25ce, 0x2606, 0x2605,
126   0x25c7, 0x25c6, 0x25a1, 0x25a0, 0x25bd, 0x25bc, 0x32a3, 0x2105,
127   0x203e, 0xffe3, 0xff3f, 0x02cd, 0xfe49, 0xfe4a, 0xfe4d, 0xfe4e,
128   0xfe4b, 0xfe4c, 0xfe5f, 0xfe60, 0xfe61, 0xff0b, 0xff0d, 0x00d7,
129   0x00f7, 0x00b1, 0x221a, 0xff1c, 0xff1e, 0xff1d, 0x2266, 0x2267,
130   0x2260, 0x221e, 0x2252, 0x2261, 0xfe62, 0xfe63, 0xfe64, 0xfe65,
131   0xfe66, 0xff5e, 0x2229, 0x222a, 0x22a5, 0x2220, 0x221f, 0x22bf,
132   0x33d2, 0x33d1, 0x222b, 0x222e, 0x2235, 0x2234, 0x2640, 0x2642,
133   0x2295, 0x2299, 0x2191, 0x2193, 0x2190, 0x2192, 0x2196, 0x2197,
134   0x2199, 0x2198, 0x2225, 0x2223, 0xff0f,
135   /* 0xa2 */
136   0xff3c, 0x2215, 0xfe68, 0xff04, 0xffe5, 0x3012, 0xffe0, 0xffe1,
137   0xff05, 0xff20, 0x2103, 0x2109, 0xfe69, 0xfe6a, 0xfe6b, 0x33d5,
138   0x339c, 0x339d, 0x339e, 0x33ce, 0x33a1, 0x338e, 0x338f, 0x33c4,
139   0x00b0, 0x5159, 0x515b, 0x515e, 0x515d, 0x5161, 0x5163, 0x55e7,
140   0x74e9, 0x7cce, 0x2581, 0x2582, 0x2583, 0x2584, 0x2585, 0x2586,
141   0x2587, 0x2588, 0x258f, 0x258e, 0x258d, 0x258c, 0x258b, 0x258a,
142   0x2589, 0x253c, 0x2534, 0x252c, 0x2524, 0x251c, 0x2594, 0x2500,
143   0x2502, 0x2595, 0x250c, 0x2510, 0x2514, 0x2518, 0x256d, 0x256e,
144   0x2570, 0x256f, 0x2501, 0x251d, 0x253f, 0x2525, 0x25e2, 0x25e3,
145   0x25e5, 0x25e4, 0x2571, 0x2572, 0x2573, 0xff10, 0xff11, 0xff12,
146   0xff13, 0xff14, 0xff15, 0xff16, 0xff17, 0xff18, 0xff19, 0x2160,
147   0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, 0x2168,
148   0x2169, 0x3021, 0x3022, 0x3023, 0x3024, 0x3025, 0x3026, 0x3027,
149   0x3028, 0x3029, 0x3038, 0x3039, 0x303a, 0xff21, 0xff22, 0xff23,
150   0xff24, 0xff25, 0xff26, 0xff27, 0xff28, 0xff29, 0xff2a, 0xff2b,
151   0xff2c, 0xff2d, 0xff2e, 0xff2f, 0xff30, 0xff31, 0xff32, 0xff33,
152   0xff34, 0xff35, 0xff36, 0xff37, 0xff38, 0xff39, 0xff3a, 0xff41,
153   0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47, 0xff48, 0xff49,
154   0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f, 0xff50, 0xff51,
155   0xff52, 0xff53, 0xff54, 0xff55, 0xff56,
156 };
157 
158 static const unsigned short big5_2003_2uni_pagec6[70] = {
159   /* 0xc6a1 */
160   0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466, 0x2467,
161   0x2468, 0x2469, 0x2474, 0x2475, 0x2476, 0x2477, 0x2478, 0x2479,
162   0x247a, 0x247b, 0x247c, 0x247d, 0x2170, 0x2171, 0x2172, 0x2173,
163   0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x2f02, 0x2f03,
164   0x2f05, 0x2f07, 0x2f0c, 0x2f0d, 0x2f0e, 0x2f13, 0x2f16, 0x2f19,
165   0x2f1b, 0x2f22, 0x2f27, 0x2f2e, 0x2f33, 0x2f34, 0x2f35, 0x2f39,
166   0x2f3a, 0x2f41, 0x2f46, 0x2f67, 0x2f68, 0x2fa1, 0x2faa, 0x00a8,
167   0xff3e, 0x30fd, 0x30fe, 0x309d, 0x309e, 0xfffd, 0xfffd, 0x3005,
168   0x3006, 0x3007, 0x30fc, 0xff3b, 0xff3d, 0x273d,
169 };
170 
171 static const unsigned short big5_2003_2uni_pagef9[41] = {
172   /* 0xf9d6 */
173   0x7881, 0x92b9, 0x88cf, 0x58bb, 0x6052, 0x7ca7, 0x5afa,
174   /* 0xf9dd */
175   0x2554, 0x2566, 0x2557, 0x2560, 0x256c, 0x2563, 0x255a, 0x2569,
176   0x255d, 0x2552, 0x2564, 0x2555, 0x255e, 0x256a, 0x2561, 0x2558,
177   0x2567, 0x255b, 0x2553, 0x2565, 0x2556, 0x255f, 0x256b, 0x2562,
178   0x2559, 0x2568, 0x255c, 0x2551, 0x2550,
179   0x2554, 0x2557, 0x255a, 0x255d, /* not invertible */
180   0x2593,
181 };
182 
183 static int
184 big5_2003_mbtowc (conv_t conv, ucs4_t *pwc, const unsigned char *s, int n)
185 {
186   unsigned char c = *s;
187   /* Code set 0 (ASCII) */
188   if (c < 0x80)
189     return ascii_mbtowc(conv,pwc,s,n);
190   /* Code set 1 (BIG5 extended) */
191   if (c >= 0x81 && c < 0xff) {
192     if (n < 2)
193       return RET_TOOFEW(0);
194     {
195       unsigned char c2 = s[1];
196       if ((c2 >= 0x40 && c2 < 0x7f) || (c2 >= 0xa1 && c2 < 0xff)) {
197         if (c >= 0xa1) {
198           if (c < 0xa3) {
199             unsigned int i = 157 * (c - 0xa1) + (c2 - (c2 >= 0xa1 ? 0x62 : 0x40));
200             unsigned short wc = big5_2003_2uni_pagea1[i];
201             if (wc != 0xfffd) {
202               *pwc = (ucs4_t) wc;
203               return 2;
204             }
205           }
206           if (!((c == 0xc6 && c2 >= 0xa1) || c == 0xc7)) {
207             if (!(c == 0xc2 && c2 == 0x55)) {
208               int ret = big5_mbtowc(conv,pwc,s,2);
209               if (ret != RET_ILSEQ)
210                 return ret;
211               if (c == 0xa3) {
212                 if (c2 >= 0xc0 && c2 <= 0xe1) {
213                   *pwc = (c2 == 0xe1 ? 0x20ac : c2 == 0xe0 ? 0x2421 : 0x2340 + c2);
214                   return 2;
215                 }
216               } else if (c == 0xf9) {
217                 if (c2 >= 0xd6) {
218                   *pwc = big5_2003_2uni_pagef9[c2-0xd6];
219                   return 2;
220                 }
221               } else if (c >= 0xfa) {
222                 *pwc = 0xe000 + 157 * (c - 0xfa) + (c2 - (c2 >= 0xa1 ? 0x62 : 0x40));
223                 return 2;
224               }
225             } else {
226               /* c == 0xc2 && c2 == 0x55. */
227               *pwc = 0x5f5e;
228               return 2;
229             }
230           } else {
231             /* (c == 0xc6 && c2 >= 0xa1) || c == 0xc7. */
232             unsigned int i = 157 * (c - 0xc6) + (c2 - (c2 >= 0xa1 ? 0x62 : 0x40));
233             if (i < 133) {
234               /* 63 <= i < 133. */
235               unsigned short wc = big5_2003_2uni_pagec6[i-63];
236               if (wc != 0xfffd) {
237                 *pwc = (ucs4_t) wc;
238                 return 2;
239               }
240             } else if (i < 216) {
241               /* 133 <= i < 216. Hiragana. */
242               *pwc = 0x3041 - 133 + i;
243               return 2;
244             } else if (i < 302) {
245               /* 216 <= i < 302. Katakana. */
246               *pwc = 0x30a1 - 216 + i;
247               return 2;
248             }
249           }
250         } else {
251           /* 0x81 <= c < 0xa1. */
252           *pwc = (c >= 0x8e ? 0xdb18 : 0xeeb8) + 157 * (c - 0x81)
253                  + (c2 - (c2 >= 0xa1 ? 0x62 : 0x40));
254           return 2;
255         }
256       }
257     }
258   }
259   return RET_ILSEQ;
260 }
261 
262 static const unsigned char big5_2003_2charset_page25[29] = {
263   /* 0x2550 */
264   0xf9, 0xf8, 0xe6, 0xef, 0xdd, 0xe8, 0xf1, 0xdf,
265   0xec, 0xf5, 0xe3, 0xee, 0xf7, 0xe5, 0xe9, 0xf2,
266   0xe0, 0xeb, 0xf4, 0xe2, 0xe7, 0xf0, 0xde, 0xed,
267   0xf6, 0xe4, 0xea, 0xf3, 0xe1,
268 };
269 
270 static int
271 big5_2003_wctomb (conv_t conv, unsigned char *r, ucs4_t wc, int n)
272 {
273   unsigned char buf[2];
274   int ret;
275 
276   /* Code set 0 (ASCII) */
277   ret = ascii_wctomb(conv,r,wc,n);
278   if (ret != RET_ILUNI)
279     return ret;
280 
281   /* Code set 1 (BIG5 extended) */
282   switch (wc >> 8) {
283     case 0x00:
284       if (wc == 0x00a8) { buf[0] = 0xc6; buf[1] = 0xd8; ret = 2; break; }
285       if (wc == 0x00a2 || wc == 0x00a3 || wc == 0x00a5)
286         return RET_ILUNI;
287       break;
288     case 0x02:
289       if (wc == 0x02cd) { buf[0] = 0xa1; buf[1] = 0xc5; ret = 2; break; }
290       break;
291     case 0x04:
292       return RET_ILUNI;
293     case 0x20:
294       if (wc == 0x2015) { buf[0] = 0xa1; buf[1] = 0x56; ret = 2; break; }
295       if (wc == 0x2027) { buf[0] = 0xa1; buf[1] = 0x45; ret = 2; break; }
296       if (wc == 0x20ac) { buf[0] = 0xa3; buf[1] = 0xe1; ret = 2; break; }
297       if (wc == 0x2013 || wc == 0x2022)
298         return RET_ILUNI;
299       break;
300     case 0x21:
301       if (wc >= 0x2170 && wc <= 0x2179) {
302         buf[0] = 0xc6; buf[1] = wc - 0x20bb; ret = 2;
303         break;
304       }
305       break;
306     case 0x22:
307       if (wc == 0x2215) { buf[0] = 0xa2; buf[1] = 0x41; ret = 2; break; }
308       if (wc == 0x2295) { buf[0] = 0xa1; buf[1] = 0xf2; ret = 2; break; }
309       if (wc == 0x2299) { buf[0] = 0xa1; buf[1] = 0xf3; ret = 2; break; }
310       if (wc == 0x223c)
311         return RET_ILUNI;
312       break;
313     case 0x24:
314       if (wc <= 0x241f) { buf[0] = 0xa3; buf[1] = wc - 0x2340; ret = 2; break; }
315       if (wc == 0x2421) { buf[0] = 0xa3; buf[1] = 0xe0; ret = 2; break; }
316       if (wc >= 0x2460 && wc <= 0x2469) {
317         buf[0] = 0xc6; buf[1] = wc - 0x23bf; ret = 2;
318         break;
319       }
320       if (wc >= 0x2474 && wc <= 0x247d) {
321         buf[0] = 0xc6; buf[1] = wc - 0x23c9; ret = 2;
322         break;
323       }
324       break;
325     case 0x25:
326       if (wc == 0x2501) { buf[0] = 0xa2; buf[1] = 0xa4; ret = 2; break; }
327       if (wc == 0x251d) { buf[0] = 0xa2; buf[1] = 0xa5; ret = 2; break; }
328       if (wc == 0x2525) { buf[0] = 0xa2; buf[1] = 0xa7; ret = 2; break; }
329       if (wc == 0x253f) { buf[0] = 0xa2; buf[1] = 0xa6; ret = 2; break; }
330       if (wc >= 0x2550 && wc <= 0x256c) {
331         buf[0] = 0xf9; buf[1] = big5_2003_2charset_page25[wc-0x2550]; ret = 2;
332         break;
333       }
334       if (wc == 0x2574) { buf[0] = 0xa1; buf[1] = 0x5a; ret = 2; break; }
335       if (wc == 0x2593) { buf[0] = 0xf9; buf[1] = 0xfe; ret = 2; break; }
336       break;
337     case 0x26:
338       if (wc == 0x2609 || wc == 0x2641)
339         return RET_ILUNI;
340       break;
341     case 0x27:
342       if (wc == 0x273d) { buf[0] = 0xc6; buf[1] = 0xe6; ret = 2; break; }
343       break;
344     case 0x2f:
345       if (wc == 0x2f02) { buf[0] = 0xc6; buf[1] = 0xbf; ret = 2; break; }
346       if (wc == 0x2f03) { buf[0] = 0xc6; buf[1] = 0xc0; ret = 2; break; }
347       if (wc == 0x2f05) { buf[0] = 0xc6; buf[1] = 0xc1; ret = 2; break; }
348       if (wc == 0x2f07) { buf[0] = 0xc6; buf[1] = 0xc2; ret = 2; break; }
349       if (wc == 0x2f0c) { buf[0] = 0xc6; buf[1] = 0xc3; ret = 2; break; }
350       if (wc == 0x2f0d) { buf[0] = 0xc6; buf[1] = 0xc4; ret = 2; break; }
351       if (wc == 0x2f0e) { buf[0] = 0xc6; buf[1] = 0xc5; ret = 2; break; }
352       if (wc == 0x2f13) { buf[0] = 0xc6; buf[1] = 0xc6; ret = 2; break; }
353       if (wc == 0x2f16) { buf[0] = 0xc6; buf[1] = 0xc7; ret = 2; break; }
354       if (wc == 0x2f19) { buf[0] = 0xc6; buf[1] = 0xc8; ret = 2; break; }
355       if (wc == 0x2f1b) { buf[0] = 0xc6; buf[1] = 0xc9; ret = 2; break; }
356       if (wc == 0x2f22) { buf[0] = 0xc6; buf[1] = 0xca; ret = 2; break; }
357       if (wc == 0x2f27) { buf[0] = 0xc6; buf[1] = 0xcb; ret = 2; break; }
358       if (wc == 0x2f2e) { buf[0] = 0xc6; buf[1] = 0xcc; ret = 2; break; }
359       if (wc == 0x2f33) { buf[0] = 0xc6; buf[1] = 0xcd; ret = 2; break; }
360       if (wc == 0x2f34) { buf[0] = 0xc6; buf[1] = 0xce; ret = 2; break; }
361       if (wc == 0x2f35) { buf[0] = 0xc6; buf[1] = 0xcf; ret = 2; break; }
362       if (wc == 0x2f39) { buf[0] = 0xc6; buf[1] = 0xd0; ret = 2; break; }
363       if (wc == 0x2f3a) { buf[0] = 0xc6; buf[1] = 0xd1; ret = 2; break; }
364       if (wc == 0x2f41) { buf[0] = 0xc6; buf[1] = 0xd2; ret = 2; break; }
365       if (wc == 0x2f46) { buf[0] = 0xc6; buf[1] = 0xd3; ret = 2; break; }
366       if (wc == 0x2f67) { buf[0] = 0xc6; buf[1] = 0xd4; ret = 2; break; }
367       if (wc == 0x2f68) { buf[0] = 0xc6; buf[1] = 0xd5; ret = 2; break; }
368       if (wc == 0x2fa1) { buf[0] = 0xc6; buf[1] = 0xd6; ret = 2; break; }
369       if (wc == 0x2faa) { buf[0] = 0xc6; buf[1] = 0xd7; ret = 2; break; }
370       break;
371     case 0x30:
372       if (wc >= 0x3005 && wc <= 0x3007) {
373         buf[0] = 0xc6; buf[1] = wc - 0x2f25; ret = 2;
374         break;
375       }
376       if (wc >= 0x3038 && wc <= 0x303a) {
377         buf[0] = 0xa2; buf[1] = wc - 0x2f6c; ret = 2;
378         break;
379       }
380       if (wc >= 0x3041 && wc <= 0x3093) {
381         if (wc < 0x3059) {
382           buf[0] = 0xc6; buf[1] = wc - 0x2f5a;
383         } else {
384           buf[0] = 0xc7; buf[1] = wc - 0x3019;
385         }
386         ret = 2;
387         break;
388       }
389       if (wc == 0x309d) { buf[0] = 0xc6; buf[1] = 0xdc; ret = 2; break; }
390       if (wc == 0x309e) { buf[0] = 0xc6; buf[1] = 0xdd; ret = 2; break; }
391       if (wc >= 0x30a1 && wc <= 0x30f6) {
392         buf[0] = 0xc7; buf[1] = wc - (wc < 0x30a5 ? 0x3026 : 0x3004); ret = 2;
393         break;
394       }
395       if (wc == 0x30fc) { buf[0] = 0xc6; buf[1] = 0xe3; ret = 2; break; }
396       if (wc == 0x30fd) { buf[0] = 0xc6; buf[1] = 0xda; ret = 2; break; }
397       if (wc == 0x30fe) { buf[0] = 0xc6; buf[1] = 0xdb; ret = 2; break; }
398       break;
399     case 0x53:
400       if (wc == 0x5344)
401         return RET_ILUNI;
402       break;
403     case 0x58:
404       if (wc == 0x58bb) { buf[0] = 0xf9; buf[1] = 0xd9; ret = 2; break; }
405       break;
406     case 0x5a:
407       if (wc == 0x5afa) { buf[0] = 0xf9; buf[1] = 0xdc; ret = 2; break; }
408       break;
409     case 0x5f:
410       if (wc == 0x5f5e) { buf[0] = 0xc2; buf[1] = 0x55; ret = 2; break; }
411       if (wc == 0x5f5d)
412         return RET_ILUNI;
413       break;
414     case 0x60:
415       if (wc == 0x6052) { buf[0] = 0xf9; buf[1] = 0xda; ret = 2; break; }
416       break;
417     case 0x78:
418       if (wc == 0x7881) { buf[0] = 0xf9; buf[1] = 0xd6; ret = 2; break; }
419       break;
420     case 0x7c:
421       if (wc == 0x7ca7) { buf[0] = 0xf9; buf[1] = 0xdb; ret = 2; break; }
422       break;
423     case 0x88:
424       if (wc == 0x88cf) { buf[0] = 0xf9; buf[1] = 0xd8; ret = 2; break; }
425       break;
426     case 0x92:
427       if (wc == 0x92b9) { buf[0] = 0xf9; buf[1] = 0xd7; ret = 2; break; }
428       break;
429     case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5:
430     case 0xe6: case 0xe7: case 0xe8: case 0xe9: case 0xea: case 0xeb:
431     case 0xec: case 0xed: case 0xee: case 0xef: case 0xf0: case 0xf1:
432     case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6:
433       {
434         unsigned int i = wc - 0xe000;
435         if (i < 5809) {
436           unsigned int c1 = i / 157;
437           unsigned int c2 = i % 157;
438           buf[0] = c1 + (c1 < 5 ? 0xfa : c1 < 24 ? 0x89 : 0x69);
439           buf[1] = c2 + (c2 < 0x3f ? 0x40 : 0x62);
440           ret = 2;
441           break;
442         }
443       }
444       break;
445     case 0xfe:
446       if (wc == 0xfe51) { buf[0] = 0xa1; buf[1] = 0x4e; ret = 2; break; }
447       if (wc == 0xfe68) { buf[0] = 0xa2; buf[1] = 0x42; ret = 2; break; }
448       break;
449     case 0xff:
450       if (wc == 0xff0f) { buf[0] = 0xa1; buf[1] = 0xfe; ret = 2; break; }
451       if (wc == 0xff3b) { buf[0] = 0xc6; buf[1] = 0xe4; ret = 2; break; }
452       if (wc == 0xff3c) { buf[0] = 0xa2; buf[1] = 0x40; ret = 2; break; }
453       if (wc == 0xff3d) { buf[0] = 0xc6; buf[1] = 0xe5; ret = 2; break; }
454       if (wc == 0xff3e) { buf[0] = 0xc6; buf[1] = 0xd9; ret = 2; break; }
455       if (wc == 0xff5e) { buf[0] = 0xa1; buf[1] = 0xe3; ret = 2; break; }
456       if (wc == 0xffe0) { buf[0] = 0xa2; buf[1] = 0x46; ret = 2; break; }
457       if (wc == 0xffe1) { buf[0] = 0xa2; buf[1] = 0x47; ret = 2; break; }
458       if (wc == 0xffe3) { buf[0] = 0xa1; buf[1] = 0xc3; ret = 2; break; }
459       if (wc == 0xffe5) { buf[0] = 0xa2; buf[1] = 0x44; ret = 2; break; }
460       if (wc == 0xff64)
461         return RET_ILUNI;
462       break;
463   }
464   if (ret == RET_ILUNI)
465     ret = big5_wctomb(conv,buf,wc,2);
466   if (ret != RET_ILUNI) {
467     if (ret != 2) abort();
468     if (n < 2)
469       return RET_TOOSMALL;
470     r[0] = buf[0];
471     r[1] = buf[1];
472     return 2;
473   }
474 
475   return RET_ILUNI;
476 }
477