Initial revision
[TestXSLT.git] / libiconv / lib / cp1258.h
1 /*
2  * Copyright (C) 1999-2001 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., 59 Temple Place -
18  * Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * CP1258
23  */
24
25 #include "flushwc.h"
26 #include "vietcomb.h"
27
28 static const unsigned char cp1258_comb_table[] = {
29   0xcc, 0xec, 0xde, 0xd2, 0xf2,
30 };
31
32 static const unsigned short cp1258_2uni[128] = {
33   /* 0x80 */
34   0x20ac, 0xfffd, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
35   0x02c6, 0x2030, 0xfffd, 0x2039, 0x0152, 0xfffd, 0xfffd, 0xfffd,
36   /* 0x90 */
37   0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
38   0x02dc, 0x2122, 0xfffd, 0x203a, 0x0153, 0xfffd, 0xfffd, 0x0178,
39   /* 0xa0 */
40   0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
41   0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
42   /* 0xb0 */
43   0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
44   0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
45   /* 0xc0 */
46   0x00c0, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
47   0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x0300, 0x00cd, 0x00ce, 0x00cf,
48   /* 0xd0 */
49   0x0110, 0x00d1, 0x0309, 0x00d3, 0x00d4, 0x01a0, 0x00d6, 0x00d7,
50   0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x01af, 0x0303, 0x00df,
51   /* 0xe0 */
52   0x00e0, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
53   0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x0301, 0x00ed, 0x00ee, 0x00ef,
54   /* 0xf0 */
55   0x0111, 0x00f1, 0x0323, 0x00f3, 0x00f4, 0x01a1, 0x00f6, 0x00f7,
56   0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x01b0, 0x20ab, 0x00ff,
57 };
58
59 /* In the CP1258 to Unicode direction, the state contains a buffered
60    character, or 0 if none. */
61
62 static int
63 cp1258_mbtowc (conv_t conv, ucs4_t *pwc, const unsigned char *s, int n)
64 {
65   unsigned char c = *s;
66   unsigned short wc;
67   unsigned short last_wc;
68   if (c < 0x80) {
69     wc = c;
70   } else {
71     wc = cp1258_2uni[c-0x80];
72     if (wc == 0xfffd)
73       return RET_ILSEQ;
74   }
75   last_wc = conv->istate;
76   if (last_wc) {
77     if (wc >= 0x0300 && wc < 0x0340) {
78       /* See whether last_wc and wc can be combined. */
79       unsigned int k;
80       unsigned int i1, i2;
81       switch (wc) {
82         case 0x0300: k = 0; break;
83         case 0x0301: k = 1; break;
84         case 0x0303: k = 2; break;
85         case 0x0309: k = 3; break;
86         case 0x0323: k = 4; break;
87         default: abort();
88       }
89       i1 = viet_comp_table[k].idx;
90       i2 = i1 + viet_comp_table[k].len-1;
91       if (last_wc >= viet_comp_table_data[i1].base
92           && last_wc <= viet_comp_table_data[i2].base) {
93         unsigned int i;
94         for (;;) {
95           i = (i1+i2)>>1;
96           if (last_wc == viet_comp_table_data[i].base)
97             break;
98           if (last_wc < viet_comp_table_data[i].base) {
99             if (i1 == i)
100               goto not_combining;
101             i2 = i;
102           } else {
103             if (i1 != i)
104               i1 = i;
105             else {
106               i = i2;
107               if (last_wc == viet_comp_table_data[i].base)
108                 break;
109               goto not_combining;
110             }
111           }
112         }
113         last_wc = viet_comp_table_data[i].composed;
114         /* Output the combined character. */
115         conv->istate = 0;
116         *pwc = (ucs4_t) last_wc;
117         return 1;
118       }
119     }
120   not_combining:
121     /* Output the buffered character. */
122     conv->istate = 0;
123     *pwc = (ucs4_t) last_wc;
124     return 0; /* Don't advance the input pointer. */
125   }
126   if (wc >= 0x0041 && wc <= 0x01b0) {
127     /* wc is a possible match in viet_comp_table_data. Buffer it. */
128     conv->istate = wc;
129     return RET_TOOFEW(1);
130   } else {
131     /* Output wc immediately. */
132     *pwc = (ucs4_t) wc;
133     return 1;
134   }
135 }
136
137 #define cp1258_flushwc normal_flushwc
138
139 static const unsigned char cp1258_page00[88] = {
140   0xc0, 0xc1, 0xc2, 0x00, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
141   0xc8, 0xc9, 0xca, 0xcb, 0x00, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
142   0x00, 0xd1, 0x00, 0xd3, 0xd4, 0x00, 0xd6, 0xd7, /* 0xd0-0xd7 */
143   0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */
144   0xe0, 0xe1, 0xe2, 0x00, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
145   0xe8, 0xe9, 0xea, 0xeb, 0x00, 0xed, 0xee, 0xef, /* 0xe8-0xef */
146   0x00, 0xf1, 0x00, 0xf3, 0xf4, 0x00, 0xf6, 0xf7, /* 0xf0-0xf7 */
147   0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0x00, 0x00, 0xff, /* 0xf8-0xff */
148   /* 0x0100 */
149   0x00, 0x00, 0xc3, 0xe3, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
150   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
151   0xd0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
152 };
153 static const unsigned char cp1258_page01[104] = {
154   0x00, 0x00, 0x8c, 0x9c, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
155   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
156   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
157   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
158   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
159   0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
160   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
161   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
162   0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
163   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
164   0xd5, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
165   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, /* 0xa8-0xaf */
166   0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
167 };
168 static const unsigned char cp1258_page02[32] = {
169   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, /* 0xc0-0xc7 */
170   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
171   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
172   0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
173 };
174 static const unsigned char cp1258_page03[40] = {
175   0xcc, 0xec, 0x00, 0xde, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
176   0x00, 0xd2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
177   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
178   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
179   0x00, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
180 };
181 static const unsigned char cp1258_page20[48] = {
182   0x00, 0x00, 0x00, 0x96, 0x97, 0x00, 0x00, 0x00, /* 0x10-0x17 */
183   0x91, 0x92, 0x82, 0x00, 0x93, 0x94, 0x84, 0x00, /* 0x18-0x1f */
184   0x86, 0x87, 0x95, 0x00, 0x00, 0x00, 0x85, 0x00, /* 0x20-0x27 */
185   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
186   0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
187   0x00, 0x8b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
188 };
189
190 static int
191 cp1258_wctomb (conv_t conv, unsigned char *r, ucs4_t wc, int n)
192 {
193   unsigned char c = 0;
194   if (wc < 0x0080) {
195     *r = wc;
196     return 1;
197   }
198   else if (wc >= 0x00a0 && wc < 0x00c0)
199     c = wc;
200   else if (wc >= 0x00c0 && wc < 0x0118)
201     c = cp1258_page00[wc-0x00c0];
202   else if (wc >= 0x0150 && wc < 0x01b8)
203     c = cp1258_page01[wc-0x0150];
204   else if (wc >= 0x02c0 && wc < 0x02e0)
205     c = cp1258_page02[wc-0x02c0];
206   else if (wc >= 0x0300 && wc < 0x0328)
207     c = cp1258_page03[wc-0x0300];
208   else if (wc >= 0x0340 && wc < 0x0342) /* deprecated Vietnamese tone marks */
209     c = cp1258_page03[wc-0x0340];
210   else if (wc >= 0x2010 && wc < 0x2040)
211     c = cp1258_page20[wc-0x2010];
212   else if (wc == 0x20ab)
213     c = 0xfe;
214   else if (wc == 0x20ac)
215     c = 0x80;
216   else if (wc == 0x2122)
217     c = 0x99;
218   if (c != 0) {
219     *r = c;
220     return 1;
221   }
222   /* Try canonical decomposition. */
223   {
224     /* Binary search through viet_decomp_table. */
225     unsigned int i1 = 0;
226     unsigned int i2 = sizeof(viet_decomp_table)/sizeof(viet_decomp_table[0])-1;
227     if (wc >= viet_decomp_table[i1].composed
228         && wc <= viet_decomp_table[i2].composed) {
229       unsigned int i;
230       for (;;) {
231         /* Here i2 - i1 > 0. */
232         i = (i1+i2)>>1;
233         if (wc == viet_decomp_table[i].composed)
234           break;
235         if (wc < viet_decomp_table[i].composed) {
236           if (i1 == i)
237             return RET_ILUNI;
238           /* Here i1 < i < i2. */
239           i2 = i;
240         } else {
241           /* Here i1 <= i < i2. */
242           if (i1 != i)
243             i1 = i;
244           else {
245             /* Here i2 - i1 = 1. */
246             i = i2;
247             if (wc == viet_decomp_table[i].composed)
248               break;
249             else
250               return RET_ILUNI;
251           }
252         }
253       }
254       /* Found a canonical decomposition. */
255       wc = viet_decomp_table[i].base;
256       /* wc is one of 0x0020, 0x0041..0x005a, 0x0061..0x007a, 0x00a5, 0x00a8,
257          0x00c2, 0x00c5..0x00c7, 0x00ca, 0x00cf, 0x00d3, 0x00d4, 0x00d6,
258          0x00d8, 0x00da, 0x00dc, 0x00e2, 0x00e5..0x00e7, 0x00ea, 0x00ef,
259          0x00f3, 0x00f4, 0x00f6, 0x00f8, 0x00fc, 0x0102, 0x0103, 0x01a0,
260          0x01a1, 0x01af, 0x01b0. */
261       if (wc < 0x0100)
262         c = wc;
263       else if (wc < 0x0118)
264         c = cp1258_page00[wc-0x00c0];
265       else
266         c = cp1258_page01[wc-0x0150];
267       if (n < 2)
268         return RET_TOOSMALL;
269       r[0] = c;
270       r[1] = cp1258_comb_table[viet_decomp_table[i].comb1];
271       return 2;
272     }
273   }
274   return RET_ILUNI;
275 }