OSDN Git Service

2004-06-25 Andrew Cagney <cagney@gnu.org>
[pf3gnuchains/pf3gnuchains3x.git] / newlib / libc / iconv / lib / ces_euc.c
1 /*
2  * Copyright (c) 1999,2000
3  *    Konstantin Chuguev.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  *
26  *    iconv (Charset Conversion Library) v2.0
27  */
28 #include "deps.h"
29 #include <sys/types.h>
30 #include <stddef.h>
31 #include <errno.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <assert.h>
35 #include <wchar.h>
36 #include <reent.h>
37 #include "local.h"
38
39 typedef struct {
40     int nccs;
41     struct iconv_ccs ccs[1];
42 } iconv_ces_euc_state_t;
43
44 int
45 _DEFUN(_iconv_euc_init, (rptr, data, desc_data, num),
46                         struct _reent *rptr        _AND
47                         _VOID_PTR *data            _AND
48                         _CONST _VOID_PTR desc_data _AND
49                         size_t num)
50 {
51     size_t stsz = sizeof(iconv_ces_euc_state_t) +
52                   sizeof(struct iconv_ccs) * (num - 1);
53     int i;
54     iconv_ces_euc_state_t *state = (iconv_ces_euc_state_t *)_malloc_r(rptr, stsz);
55
56     if (state == NULL)
57         return __errno_r(rptr);
58     for (i = 0; i < num; i++) {
59         int res = _iconv_ccs_init(rptr, &(state->ccs[i]),
60                            ((_CONST iconv_ces_euc_ccs_t *) desc_data)[i].name);
61         if (res) {
62             while (--i >= 0)
63                 state->ccs[i].close(rptr, &(state->ccs[i]));
64             _free_r(rptr, state);
65             return res;
66         }
67     }
68     state->nccs = num;
69     (iconv_ces_euc_state_t *)*data = state;
70     return 0;
71 }
72
73 int
74 _DEFUN(_iconv_euc_close, (rptr, data),
75                         struct _reent *rptr _AND
76                         _VOID_PTR data)
77 {
78 #define state ((iconv_ces_euc_state_t *)data)
79     int i, res = 0;
80
81     for (i = 0; i < state->nccs; i++)
82         res = state->ccs[i].close(rptr, &(state->ccs[i])) || res;
83     _free_r(rptr, data);
84     return res;
85 #undef state
86 }
87
88 #define is_7_14bit(data) ((data)->nbits & 7)
89 #define is_7bit(data) ((data)->nbits & 1)
90
91 ssize_t
92 _DEFUN(_iconv_euc_convert_from_ucs, (ces, in, outbuf, outbytesleft),
93                                     struct iconv_ces *ces  _AND
94                                     ucs_t in               _AND
95                                     unsigned char **outbuf _AND
96                                     size_t *outbytesleft)
97 {
98     iconv_ces_euc_state_t *euc_state;
99     size_t bytes;
100     int i;
101
102     if (in == UCS_CHAR_NONE)
103         return 1;    /* No state reinitialization for table charsets */
104     if (iconv_char32bit(in))
105         return -1;
106     euc_state = (iconv_ces_euc_state_t *)(ces->data);
107     for (i = 0; i < euc_state->nccs; i++) {
108         _CONST iconv_ces_euc_ccs_t *ccsattr;
109         _CONST struct iconv_ccs *ccs = &(euc_state->ccs[i]);
110         ucs_t res = ICONV_CCS_CONVERT_FROM_UCS(ccs, in);
111
112         if (res == UCS_CHAR_INVALID)
113             continue;
114         ccsattr = &(((_CONST iconv_ces_euc_ccs_t *)(ces->desc->data))[i]);
115         if (i) {
116             if (is_7_14bit(ccs))
117                 res |= is_7bit(ccs) ? 0x80 : 0x8080;
118             else if (!(res & 0x8080))
119                 continue;
120         } else if (res & 0x8080)
121             continue;
122         bytes = (res & 0xFF00 ? 2 : 1) + ccsattr->prefixlen;
123         if (*outbytesleft < bytes)
124             return 0;    /* No space in the output buffer */
125         if (ccsattr->prefixlen) {
126             memcpy(*outbuf, ccsattr->prefix, ccsattr->prefixlen);
127             (*outbuf) += ccsattr->prefixlen;
128         }
129         if (res & 0xFF00)
130             *(*outbuf)++ = (unsigned char)(res >> 8);
131         *(*outbuf)++ = (unsigned char)res;
132         *outbytesleft -= bytes;
133         return 1;
134     }
135     return -1;    /* No character in output charset */
136 }
137
138 static ucs_t
139 _DEFUN(cvt2ucs, (ccs, inbuf, inbytesleft, hi_plane, bufptr),
140                 struct iconv_ccs *ccs       _AND
141                 _CONST unsigned char *inbuf _AND
142                 size_t inbytesleft          _AND
143                 int hi_plane                _AND
144                 _CONST unsigned char **bufptr)
145 {
146     size_t bytes = ccs->nbits > 8 ? 2 : 1;
147     ucs_t ch = *(_CONST unsigned char *)inbuf++;
148
149     if (inbytesleft < bytes)
150         return UCS_CHAR_NONE;    /* Not enough bytes in the input buffer */
151     if (bytes == 2)
152         ch = (ch << 8) | *(_CONST unsigned char *)inbuf++;
153     *bufptr = inbuf;
154     if (hi_plane) {
155         if (!(ch & 0x8080))
156             return UCS_CHAR_INVALID;
157         if (is_7_14bit(ccs))
158             ch &= 0x7F7F;
159     } else if (ch & 0x8080)
160         return UCS_CHAR_INVALID;
161     return ICONV_CCS_CONVERT_TO_UCS(ccs, ch);
162 }
163
164 ucs_t
165 _DEFUN(_iconv_euc_convert_to_ucs, (ces, inbuf, inbytesleft),
166                                   struct iconv_ces *ces        _AND
167                                   _CONST unsigned char **inbuf _AND
168                                   size_t *inbytesleft)
169 {
170     iconv_ces_euc_state_t *euc_state =
171         (iconv_ces_euc_state_t *)(ces->data);
172     ucs_t res = UCS_CHAR_INVALID;
173     _CONST unsigned char *ptr;
174     int i;
175
176     if (**inbuf & 0x80) {
177         for (i = 1; i < euc_state->nccs; i++) {
178             _CONST iconv_ces_euc_ccs_t *ccsattr =
179                  &(((_CONST iconv_ces_euc_ccs_t *)
180                        (ces->desc->data))[i]);
181             if (ccsattr->prefixlen + 1 > *inbytesleft)
182                 return UCS_CHAR_NONE;
183             if (ccsattr->prefixlen &&
184                 memcmp(*inbuf, ccsattr->prefix, ccsattr->prefixlen))
185                 continue;
186             res = cvt2ucs(&(euc_state->ccs[i]),
187                           *inbuf + ccsattr->prefixlen,
188                           *inbytesleft - ccsattr->prefixlen,
189                           1, &ptr);
190             if (res != UCS_CHAR_INVALID)
191                 break;
192         }
193         if (res == UCS_CHAR_INVALID)
194             ptr = *inbuf + 1;
195     } else
196         res = cvt2ucs(euc_state->ccs, *inbuf, *inbytesleft, 0, &ptr);
197     if (res == UCS_CHAR_NONE)
198         return res;    /* Not enough bytes in the input buffer */
199     *inbytesleft -= ptr - *inbuf;
200     *inbuf = ptr;
201     return res;
202 }
203