]> git.ipfire.org Git - thirdparty/glibc.git/blob - iconv/gconv_simple.c
Update.
[thirdparty/glibc.git] / iconv / gconv_simple.c
1 /* Simple transformations functions.
2 Copyright (C) 1997 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 #include <gconv.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <wchar.h>
25 #include <sys/param.h>
26
27
28 int
29 __gconv_transform_dummy (struct gconv_step *step, struct gconv_step_data *data,
30 const char *inbuf, size_t *inlen, size_t *written,
31 int do_flush)
32 {
33 size_t do_write;
34
35 /* We have no stateful encoding. So we don't have to do anything
36 special. */
37 if (do_flush)
38 do_write = 0;
39 else
40 {
41 do_write = MIN (*inlen, data->outbufsize - data->outbufavail);
42
43 memcpy (data->outbuf, inbuf, do_write);
44
45 *inlen -= do_write;
46 data->outbufavail += do_write;
47 }
48
49 /* ### TODO Actually, this number must be devided according to the
50 size of the input charset. I.e., if the input is in UCS4 the
51 number of copied bytes must be divided by 4. */
52 if (written != NULL)
53 *written = do_write;
54
55 return GCONV_OK;
56 }
57
58
59 int
60 __gconv_transform_init_rstate (struct gconv_step *step,
61 struct gconv_step_data *data)
62 {
63 /* We have to provide the transformation function an correctly initialized
64 object of type `mbstate_t'. This must be dynamically allocated. */
65 data->data = calloc (1, sizeof (mbstate_t));
66
67 return data->data == NULL ? GCONV_NOMEM : GCONV_OK;
68 }
69
70
71 void
72 __gconv_transform_end_rstate (struct gconv_step_data *data)
73 {
74 if (data->data != NULL)
75 free (data->data);
76 }
77
78
79 int
80 __gconv_transform_ucs4_utf8 (struct gconv_step *step,
81 struct gconv_step_data *data, const char *inbuf,
82 size_t *inlen, size_t *written, int do_flush)
83 {
84 struct gconv_step *next_step = step + 1;
85 struct gconv_step_data *next_data = data + 1;
86 gconv_fct fct = next_step->fct;
87 size_t do_write;
88 int result;
89
90 /* If the function is called with no input this means we have to reset
91 to the initial state. The possibly partly converted input is
92 dropped. */
93 if (do_flush)
94 {
95 /* Clear the state. */
96 memset (data->data, '\0', sizeof (mbstate_t));
97 do_write = 0;
98
99 /* Call the steps down the chain if there are any. */
100 if (data->is_last)
101 result = GCONV_OK;
102 else
103 {
104 struct gconv_step *next_step = step + 1;
105 struct gconv_step_data *next_data = data + 1;
106
107 result = (*fct) (next_step, next_data, NULL, 0, written, 1);
108
109 /* Clear output buffer. */
110 data->outbufavail = 0;
111 }
112 }
113 else
114 {
115 do_write = 0;
116
117 do
118 {
119 const char *newinbuf = inbuf;
120 size_t actually = __wcsnrtombs (&data->outbuf[data->outbufavail],
121 (const wchar_t **) &newinbuf,
122 *inlen / sizeof (wchar_t),
123 data->outbufsize - data->outbufavail,
124 (mbstate_t *) data->data);
125
126 /* Status so far. */
127 result = GCONV_EMPTY_INPUT;
128
129 /* Remember how much we converted. */
130 do_write += newinbuf - inbuf;
131 *inlen -= (newinbuf - inbuf) * sizeof (wchar_t);
132
133 data->outbufavail += actually;
134 if (data->outbufavail > 0)
135 {
136 /* Call the functions below in the chain. */
137 size_t newavail = data->outbufavail;
138
139 result = (*fct) (next_step, next_data, data->outbuf, &newavail,
140 written, 0);
141
142 /* Correct the output buffer. */
143 if (newavail != data->outbufavail)
144 {
145 memmove (data->outbuf,
146 &data->outbuf[data->outbufavail - newavail],
147 newavail);
148 data->outbufavail = newavail;
149 }
150 }
151 }
152 while (*inlen > 0 && result == GCONV_EMPTY_INPUT);
153 }
154
155 if (written != NULL && data->is_last)
156 *written = do_write / sizeof (wchar_t);
157
158 return result;
159 }
160
161
162 int
163 __gconv_transform_utf8_ucs4 (struct gconv_step *step,
164 struct gconv_step_data *data, const char *inbuf,
165 size_t *inlen, size_t *written, int do_flush)
166 {
167 struct gconv_step *next_step = step + 1;
168 struct gconv_step_data *next_data = data + 1;
169 gconv_fct fct = next_step->fct;
170 size_t do_write;
171 int result;
172
173 /* If the function is called with no input this means we have to reset
174 to the initial state. The possibly partly converted input is
175 dropped. */
176 if (do_flush)
177 {
178 /* Clear the state. */
179 memset (data->data, '\0', sizeof (mbstate_t));
180 do_write = 0;
181
182 /* Call the steps down the chain if there are any. */
183 if (data->is_last)
184 result = GCONV_OK;
185 else
186 {
187 struct gconv_step *next_step = step + 1;
188 struct gconv_step_data *next_data = data + 1;
189
190 result = (*fct) (next_step, next_data, NULL, 0, written, 1);
191 }
192 }
193 else
194 {
195 do_write = 0;
196
197 do
198 {
199 const char *newinbuf = inbuf;
200 size_t actually = __mbsnrtowcs ((wchar_t *) &data->outbuf[data->outbufavail],
201 &newinbuf, *inlen,
202 ((data->outbufsize
203 - data->outbufavail)
204 / sizeof (wchar_t)),
205 (mbstate_t *) data->data);
206
207 /* Status so far. */
208 result = GCONV_EMPTY_INPUT;
209
210 /* Remember how much we converted. */
211 do_write += actually;
212 *inlen -= newinbuf - inbuf;
213
214 data->outbufavail += actually * sizeof (wchar_t);
215 if (data->outbufavail > 0)
216 {
217 /* Call the functions below in the chain. */
218 size_t newavail = data->outbufavail;
219
220 result = (*fct) (next_step, next_data, data->outbuf, &newavail,
221 written, 0);
222
223 /* Correct the output buffer. */
224 if (newavail != data->outbufavail)
225 {
226 memmove (data->outbuf,
227 &data->outbuf[data->outbufavail - newavail],
228 newavail);
229 data->outbufavail = newavail;
230 }
231 }
232 }
233 while (*inlen > 0 && result == GCONV_EMPTY_INPUT);
234 }
235
236 if (written != NULL && data->is_last)
237 *written = do_write;
238
239 return GCONV_OK;
240 }