Support for "iconv -l".
[libiconv.git] / lib / cp1258.h
blobc1bf93aa2636c0dce4045410677f165c3db2aa94
1 /*
2 * Copyright (C) 1999-2001 Free Software Foundation, Inc.
3 * This file is part of the GNU LIBICONV Library.
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.
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.
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.
22 * CP1258
25 #include "flushwc.h"
26 #include "vietcomb.h"
28 static const unsigned char cp1258_comb_table[] = {
29 0xcc, 0xec, 0xde, 0xd2, 0xf2,
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,
59 /* In the CP1258 to Unicode direction, the state contains a buffered
60 character, or 0 if none. */
62 static int
63 cp1258_mbtowc (conv_t conv, ucs4_t *pwc, const unsigned char *s, int n)
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;
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();
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;
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;
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. */
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;
137 #define cp1258_flushwc normal_flushwc
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 */
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 */
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 */
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 */
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 */
190 static int
191 cp1258_wctomb (conv_t conv, unsigned char *r, ucs4_t wc, int n)
193 unsigned char c = 0;
194 if (wc < 0x0080) {
195 *r = wc;
196 return 1;
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;
222 /* Try canonical decomposition. */
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;
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;
274 return RET_ILUNI;