2 * Copyright (c) 1999,2000
3 * Konstantin Chuguev. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * iconv (Charset Conversion Library) v2.0
34 _CONST char *sequence;
37 } iconv_ces_iso2022_shift_t;
39 enum { ICONV_PREFIX_STATE = 0, ICONV_PREFIX_LINE, ICONV_PREFIX_CHAR };
41 static _CONST iconv_ces_iso2022_shift_t iso_shift[] = {
42 { "\x0f", 1, ICONV_PREFIX_STATE },
43 { "\x0e", 1, ICONV_PREFIX_LINE },
44 { "\x1bN", 2, ICONV_PREFIX_CHAR },
45 { "\x1bO", 2, ICONV_PREFIX_CHAR }
48 #define shift_num (sizeof(iso_shift) / sizeof(iconv_ces_iso2022_shift_t))
54 int shift_tab[shift_num];
55 char prefix_cache[128];
56 struct iconv_ccs ccs[1];
57 } iconv_ces_iso2022_state_t;
60 _DEFUN(_iconv_iso2022_init, (rptr, data, desc_data, num),
61 struct _reent *rptr _AND
63 _CONST _VOID_PTR desc_data _AND
66 size_t stsz = sizeof(iconv_ces_iso2022_state_t) +
67 sizeof(struct iconv_ccs) * (num - 1);
69 iconv_ces_iso2022_state_t *state
70 = (iconv_ces_iso2022_state_t *)_malloc_r(rptr, stsz);
73 return __errno_r(rptr);
74 bzero(state->prefix_cache, sizeof(state->prefix_cache));
75 for (i = 0; i < num; i++) {
76 _CONST iconv_ces_iso2022_ccs_t *ccsattr =
77 &(((_CONST iconv_ces_iso2022_ccs_t *)desc_data)[i]);
78 int res = _iconv_ccs_init(rptr, &(state->ccs[i]), ccsattr->name);
81 state->ccs[i].close(rptr, &(state->ccs[i]));
85 if (ccsattr->designatorlen)
86 state->prefix_cache[(int)ccsattr->designator[0]] = 1;
87 if (ccsattr->shift >= 0)
88 state->prefix_cache[(int)iso_shift[ccsattr->shift].sequence[0]] = 1;
91 iconv_iso2022_reset(state);
92 (iconv_ces_iso2022_state_t *)*data = state;
96 #define state ((iconv_ces_iso2022_state_t *)data)
99 _DEFUN(_iconv_iso2022_close, (rptr, data),
100 struct _reent *rptr _AND
105 for (i = 0; i < state->nccs; i++)
106 res = state->ccs[i].close(rptr, &(state->ccs[i])) || res;
112 _DEFUN(_iconv_iso2022_reset, (data), _VOID_PTR data)
116 state->shift_index = 0;
117 state->shift_tab[0] = 0;
118 for (i = 1; i < shift_num; i++)
119 state->shift_tab[i] = -1;
120 state->previous_char = UCS_CHAR_NONE;
125 #define CES_STATE(ces) ((iconv_ces_iso2022_state_t *)((ces)->data))
126 #define CES_CCSATTR(ces) ((_CONST iconv_ces_iso2022_ccs_t *) \
127 (((struct iconv_ces_desc *)((ces)->desc))->data))
130 _DEFUN(update_shift_state, (ces, ch),
131 _CONST struct iconv_ces *ces _AND
134 iconv_ces_iso2022_state_t *iso_state = CES_STATE(ces);
137 if (ch == '\n' && iso_state->previous_char == '\r') {
138 for (i = 0; i < shift_num; i ++) {
139 if (iso_shift[i].prefix_type != ICONV_PREFIX_STATE)
140 iso_state->shift_tab[i] = -1;
143 iso_state->previous_char = ch;
146 #define is_7_14bit(ccs) ((ccs)->nbits & 7)
149 _DEFUN(cvt_ucs2iso, (ces, in, outbuf, outbytesleft, cs),
150 _CONST struct iconv_ces *ces _AND
152 unsigned char **outbuf _AND
153 size_t *outbytesleft _AND
156 iconv_ces_iso2022_state_t *iso_state = CES_STATE(ces);
157 _CONST iconv_ces_iso2022_ccs_t *ccsattr;
158 _CONST struct iconv_ccs *ccs;
161 int need_designator, need_shift;
163 ccs = &(iso_state->ccs[cs]);
164 res = (in == UCS_CHAR_NONE) ?
165 in : ICONV_CCS_CONVERT_FROM_UCS(ccs, in);
166 if (in != UCS_CHAR_NONE) {
167 if (iso_shift[cs].prefix_type == ICONV_PREFIX_CHAR &&
169 if ((res & 0x8080) == 0)
172 } else if (res & 0x8080)
173 return -1; /* Invalid/missing character in the output charset */
175 ccsattr = &(CES_CCSATTR(ces)[cs]);
176 if ((need_shift = (ccsattr->shift != iso_state->shift_index)))
177 len += iso_shift[ccsattr->shift].length;
178 if ((need_designator = (cs != iso_state->shift_tab[ccsattr->shift])))
179 len += ccsattr->designatorlen;
180 if (in != UCS_CHAR_NONE)
181 len += res & 0xFF00 ? 2 : 1;
182 if (len > *outbytesleft)
183 return 0; /* No space in output buffer */
184 if (need_designator && (len = ccsattr->designatorlen)) {
185 memcpy(*outbuf, ccsattr->designator, len);
187 (*outbytesleft) -= len;
188 iso_state->shift_tab[ccsattr->shift] = cs;
190 if (need_shift && (len = iso_shift[ccsattr->shift].length)) {
191 memcpy(*outbuf, iso_shift[ccsattr->shift].sequence, len);
193 (*outbytesleft) -= len;
194 if (iso_shift[ccsattr->shift].prefix_type != ICONV_PREFIX_CHAR)
195 iso_state->shift_index = ccsattr->shift;
197 if (in == UCS_CHAR_NONE)
200 *(unsigned char *)(*outbuf) ++ = res >> 8;
203 *(unsigned char *)(*outbuf) ++ = res;
205 update_shift_state(ces, res);
210 _DEFUN(_iconv_iso2022_convert_from_ucs, (ces, in, outbuf, outbytesleft),
211 struct iconv_ces *ces _AND
213 unsigned char **outbuf _AND
214 size_t *outbytesleft)
216 iconv_ces_iso2022_state_t *iso_state = CES_STATE(ces);
220 if (in == UCS_CHAR_NONE)
221 return cvt_ucs2iso(ces, in, outbuf, outbytesleft, 0);
222 if (iconv_char32bit(in))
224 cs = iso_state->shift_tab[iso_state->shift_index];
225 if ((res = cvt_ucs2iso(ces, in, outbuf, outbytesleft, cs)) >= 0)
227 for (i = 0; i < iso_state->nccs; i++) {
230 if ((res = cvt_ucs2iso(ces, in, outbuf, outbytesleft, i)) >= 0)
235 return -1; /* No character in output charset */
239 _DEFUN(cvt_iso2ucs, (ccs, inbuf, inbytesleft, prefix_type),
240 _CONST struct iconv_ccs *ccs _AND
241 _CONST unsigned char **inbuf _AND
242 size_t *inbytesleft _AND
245 size_t bytes = ccs->nbits > 8 ? 2 : 1;
248 if (*inbytesleft < bytes)
249 return UCS_CHAR_NONE; /* Not enough bytes in the input buffer */
251 ch = (ch << 8) | *(++(*inbuf));
253 (*inbytesleft) -= bytes;
255 return UCS_CHAR_INVALID;
256 if (prefix_type == ICONV_PREFIX_CHAR && !is_7_14bit(ccs))
257 ch |= (bytes == 2) ? 0x8080 : 0x80;
258 return ICONV_CCS_CONVERT_TO_UCS(ccs, ch);
262 _DEFUN(_iconv_iso2022_convert_to_ucs, (ces, inbuf, inbytesleft),
263 struct iconv_ces *ces _AND
264 _CONST unsigned char **inbuf _AND
267 iconv_ces_iso2022_state_t *iso_state = CES_STATE(ces);
268 _CONST iconv_ces_iso2022_ccs_t *ccsattr;
270 _CONST unsigned char *ptr = *inbuf;
272 size_t len, left = *inbytesleft;
280 return UCS_CHAR_INVALID;
282 if (!iso_state->prefix_cache[byte])
284 for (i = 0; i < iso_state->nccs; i++) {
285 ccsattr = &(CES_CCSATTR(ces)[i]);
286 len = ccsattr->designatorlen;
289 return UCS_CHAR_NONE;
290 if (memcmp(ptr, ccsattr->designator, len) == 0) {
291 iso_state->shift_tab[ccsattr->shift] = i;
297 len = iso_shift[ccsattr->shift].length;
300 return UCS_CHAR_NONE;
302 iso_shift[ccsattr->shift].sequence, len) == 0) {
303 if (iso_shift[ccsattr->shift].prefix_type != ICONV_PREFIX_CHAR)
304 iso_state->shift_index = ccsattr->shift;
312 i = iso_state->shift_tab[iso_state->shift_index];
316 return UCS_CHAR_INVALID;
318 res = cvt_iso2ucs(&(iso_state->ccs[i]), &ptr, &left,
319 iso_shift[i].prefix_type);
320 if (res != UCS_CHAR_NONE) {
321 *inbuf = (_CONST char*)ptr;
323 update_shift_state(ces, res);