Initial revision
[TestXSLT.git] / libiconv / lib / tcvn.h
1 /*
2  * Copyright (C) 1999-2002 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  * TCVN-5712
23  */
24
25 #include "flushwc.h"
26 #include "vietcomb.h"
27
28 static const unsigned char tcvn_comb_table[] = {
29   0xb0, 0xb3, 0xb2, 0xb1, 0xb4,
30 };
31
32 static const unsigned short tcvn_2uni_1[24] = {
33   /* 0x00 */
34   0x0000, 0x00da, 0x1ee4, 0x0003, 0x1eea, 0x1eec, 0x1eee, 0x0007,
35   0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
36   /* 0x10 */
37   0x0010, 0x1ee8, 0x1ef0, 0x1ef2, 0x1ef6, 0x1ef8, 0x00dd, 0x1ef4,
38 };
39 static const unsigned short tcvn_2uni_2[128] = {
40   /* 0x80 */
41   0x00c0, 0x1ea2, 0x00c3, 0x00c1, 0x1ea0, 0x1eb6, 0x1eac, 0x00c8,
42   0x1eba, 0x1ebc, 0x00c9, 0x1eb8, 0x1ec6, 0x00cc, 0x1ec8, 0x0128,
43   /* 0x90 */
44   0x00cd, 0x1eca, 0x00d2, 0x1ece, 0x00d5, 0x00d3, 0x1ecc, 0x1ed8,
45   0x1edc, 0x1ede, 0x1ee0, 0x1eda, 0x1ee2, 0x00d9, 0x1ee6, 0x0168,
46   /* 0xa0 */
47   0x00a0, 0x0102, 0x00c2, 0x00ca, 0x00d4, 0x01a0, 0x01af, 0x0110,
48   0x0103, 0x00e2, 0x00ea, 0x00f4, 0x01a1, 0x01b0, 0x0111, 0x1eb0,
49   /* 0xb0 */
50   0x0300, 0x0309, 0x0303, 0x0301, 0x0323, 0x00e0, 0x1ea3, 0x00e3,
51   0x00e1, 0x1ea1, 0x1eb2, 0x1eb1, 0x1eb3, 0x1eb5, 0x1eaf, 0x1eb4,
52   /* 0xc0 */
53   0x1eae, 0x1ea6, 0x1ea8, 0x1eaa, 0x1ea4, 0x1ec0, 0x1eb7, 0x1ea7,
54   0x1ea9, 0x1eab, 0x1ea5, 0x1ead, 0x00e8, 0x1ec2, 0x1ebb, 0x1ebd,
55   /* 0xd0 */
56   0x00e9, 0x1eb9, 0x1ec1, 0x1ec3, 0x1ec5, 0x1ebf, 0x1ec7, 0x00ec,
57   0x1ec9, 0x1ec4, 0x1ebe, 0x1ed2, 0x0129, 0x00ed, 0x1ecb, 0x00f2,
58   /* 0xe0 */
59   0x1ed4, 0x1ecf, 0x00f5, 0x00f3, 0x1ecd, 0x1ed3, 0x1ed5, 0x1ed7,
60   0x1ed1, 0x1ed9, 0x1edd, 0x1edf, 0x1ee1, 0x1edb, 0x1ee3, 0x00f9,
61   /* 0xf0 */
62   0x1ed6, 0x1ee7, 0x0169, 0x00fa, 0x1ee5, 0x1eeb, 0x1eed, 0x1eef,
63   0x1ee9, 0x1ef1, 0x1ef3, 0x1ef7, 0x1ef9, 0x00fd, 0x1ef5, 0x1ed0,
64 };
65
66 /* In the TCVN to Unicode direction, the state contains a buffered
67    character, or 0 if none. */
68
69 static int
70 tcvn_mbtowc (conv_t conv, ucs4_t *pwc, const unsigned char *s, int n)
71 {
72   unsigned char c = *s;
73   unsigned short wc;
74   unsigned short last_wc;
75   if (c < 0x18)
76     wc = tcvn_2uni_1[c];
77   else if (c < 0x80)
78     wc = c;
79   else
80     wc = tcvn_2uni_2[c-0x80];
81   last_wc = conv->istate;
82   if (last_wc) {
83     if (wc >= 0x0300 && wc < 0x0340) {
84       /* See whether last_wc and wc can be combined. */
85       unsigned int k;
86       unsigned int i1, i2;
87       switch (wc) {
88         case 0x0300: k = 0; break;
89         case 0x0301: k = 1; break;
90         case 0x0303: k = 2; break;
91         case 0x0309: k = 3; break;
92         case 0x0323: k = 4; break;
93         default: abort();
94       }
95       i1 = viet_comp_table[k].idx;
96       i2 = i1 + viet_comp_table[k].len-1;
97       if (last_wc >= viet_comp_table_data[i1].base
98           && last_wc <= viet_comp_table_data[i2].base) {
99         unsigned int i;
100         for (;;) {
101           i = (i1+i2)>>1;
102           if (last_wc == viet_comp_table_data[i].base)
103             break;
104           if (last_wc < viet_comp_table_data[i].base) {
105             if (i1 == i)
106               goto not_combining;
107             i2 = i;
108           } else {
109             if (i1 != i)
110               i1 = i;
111             else {
112               i = i2;
113               if (last_wc == viet_comp_table_data[i].base)
114                 break;
115               goto not_combining;
116             }
117           }
118         }
119         last_wc = viet_comp_table_data[i].composed;
120         /* Output the combined character. */
121         conv->istate = 0;
122         *pwc = (ucs4_t) last_wc;
123         return 1;
124       }
125     }
126   not_combining:
127     /* Output the buffered character. */
128     conv->istate = 0;
129     *pwc = (ucs4_t) last_wc;
130     return 0; /* Don't advance the input pointer. */
131   }
132   if (wc >= 0x0041 && wc <= 0x01b0) {
133     /* wc is a possible match in viet_comp_table_data. Buffer it. */
134     conv->istate = wc;
135     return RET_TOOFEW(1);
136   } else {
137     /* Output wc immediately. */
138     *pwc = (ucs4_t) wc;
139     return 1;
140   }
141 }
142
143 #define tcvn_flushwc normal_flushwc
144
145 static const unsigned char tcvn_page00[96+184] = {
146   0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
147   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
148   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
149   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
150   0x80, 0x83, 0xa2, 0x82, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
151   0x87, 0x8a, 0xa3, 0x00, 0x8d, 0x90, 0x00, 0x00, /* 0xc8-0xcf */
152   0x00, 0x00, 0x92, 0x95, 0xa4, 0x94, 0x00, 0x00, /* 0xd0-0xd7 */
153   0x00, 0x9d, 0x01, 0x00, 0x00, 0x16, 0x00, 0x00, /* 0xd8-0xdf */
154   0xb5, 0xb8, 0xa9, 0xb7, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
155   0xcc, 0xd0, 0xaa, 0x00, 0xd7, 0xdd, 0x00, 0x00, /* 0xe8-0xef */
156   0x00, 0x00, 0xdf, 0xe3, 0xab, 0xe2, 0x00, 0x00, /* 0xf0-0xf7 */
157   0x00, 0xef, 0xf3, 0x00, 0x00, 0xfd, 0x00, 0x00, /* 0xf8-0xff */
158   /* 0x0100 */
159   0x00, 0x00, 0xa1, 0xa8, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
160   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
161   0xa7, 0xae, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
162   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
163   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
164   0x8f, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
165   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
166   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
167   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
168   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
169   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
170   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
171   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
172   0x9f, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
173   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
174   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
175   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
176   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
177   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
178   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
179   0xa5, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
180   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, /* 0xa8-0xaf */
181   0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
182 };
183 static const unsigned char tcvn_page03[40] = {
184   0xb0, 0xb3, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
185   0x00, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
186   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
187   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
188   0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
189 };
190 static const unsigned char tcvn_page1e[96] = {
191   0x84, 0xb9, 0x81, 0xb6, 0xc4, 0xca, 0xc1, 0xc7, /* 0xa0-0xa7 */
192   0xc2, 0xc8, 0xc3, 0xc9, 0x86, 0xcb, 0xc0, 0xbe, /* 0xa8-0xaf */
193   0xaf, 0xbb, 0xba, 0xbc, 0xbf, 0xbd, 0x85, 0xc6, /* 0xb0-0xb7 */
194   0x8b, 0xd1, 0x88, 0xce, 0x89, 0xcf, 0xda, 0xd5, /* 0xb8-0xbf */
195   0xc5, 0xd2, 0xcd, 0xd3, 0xd9, 0xd4, 0x8c, 0xd6, /* 0xc0-0xc7 */
196   0x8e, 0xd8, 0x91, 0xde, 0x96, 0xe4, 0x93, 0xe1, /* 0xc8-0xcf */
197   0xff, 0xe8, 0xdb, 0xe5, 0xe0, 0xe6, 0xf0, 0xe7, /* 0xd0-0xd7 */
198   0x97, 0xe9, 0x9b, 0xed, 0x98, 0xea, 0x99, 0xeb, /* 0xd8-0xdf */
199   0x9a, 0xec, 0x9c, 0xee, 0x02, 0xf4, 0x9e, 0xf1, /* 0xe0-0xe7 */
200   0x11, 0xf8, 0x04, 0xf5, 0x05, 0xf6, 0x06, 0xf7, /* 0xe8-0xef */
201   0x12, 0xf9, 0x13, 0xfa, 0x17, 0xfe, 0x14, 0xfb, /* 0xf0-0xf7 */
202   0x15, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
203 };
204
205 static int
206 tcvn_wctomb (conv_t conv, unsigned char *r, ucs4_t wc, int n)
207 {
208   unsigned char c = 0;
209   if (wc < 0x0080 && (wc >= 0x0020 || (0x00fe0076 & (1 << wc)) == 0)) {
210     *r = wc;
211     return 1;
212   }
213   else if (wc >= 0x00a0 && wc < 0x01b8)
214     c = tcvn_page00[wc-0x00a0];
215   else if (wc >= 0x0300 && wc < 0x0328)
216     c = tcvn_page03[wc-0x0300];
217   else if (wc >= 0x0340 && wc < 0x0342) /* deprecated Vietnamese tone marks */
218     c = tcvn_page03[wc-0x0340];
219   else if (wc >= 0x1ea0 && wc < 0x1f00)
220     c = tcvn_page1e[wc-0x1ea0];
221   if (c != 0) {
222     *r = c;
223     return 1;
224   }
225   /* Try compatibility or canonical decomposition. */
226   {
227     /* Binary search through viet_decomp_table. */
228     unsigned int i1 = 0;
229     unsigned int i2 = sizeof(viet_decomp_table)/sizeof(viet_decomp_table[0])-1;
230     if (wc >= viet_decomp_table[i1].composed
231         && wc <= viet_decomp_table[i2].composed) {
232       unsigned int i;
233       for (;;) {
234         /* Here i2 - i1 > 0. */
235         i = (i1+i2)>>1;
236         if (wc == viet_decomp_table[i].composed)
237           break;
238         if (wc < viet_decomp_table[i].composed) {
239           if (i1 == i)
240             return RET_ILUNI;
241           /* Here i1 < i < i2. */
242           i2 = i;
243         } else {
244           /* Here i1 <= i < i2. */
245           if (i1 != i)
246             i1 = i;
247           else {
248             /* Here i2 - i1 = 1. */
249             i = i2;
250             if (wc == viet_decomp_table[i].composed)
251               break;
252             else
253               return RET_ILUNI;
254           }
255         }
256       }
257       /* Found a compatibility or canonical decomposition. */
258       wc = viet_decomp_table[i].base;
259       /* wc is one of 0x0020, 0x0041..0x005a, 0x0061..0x007a, 0x00a5, 0x00a8,
260          0x00c2, 0x00c5..0x00c7, 0x00ca, 0x00cf, 0x00d3, 0x00d4, 0x00d6,
261          0x00d8, 0x00da, 0x00dc, 0x00e2, 0x00e5..0x00e7, 0x00ea, 0x00ef,
262          0x00f3, 0x00f4, 0x00f6, 0x00f8, 0x00fc, 0x0102, 0x0103, 0x01a0,
263          0x01a1, 0x01af, 0x01b0. */
264       if (wc < 0x0080)
265         c = wc;
266       else {
267         c = tcvn_page00[wc-0x00a0];
268         if (c == 0)
269           return RET_ILUNI;
270       }
271       if (n < 2)
272         return RET_TOOSMALL;
273       r[0] = c;
274       r[1] = tcvn_comb_table[viet_decomp_table[i].comb1];
275       return 2;
276     }
277   }
278   return RET_ILUNI;
279 }