1 /* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2
3 #if !IS_CPLUSPLUS
4 #define iconv_ostream_representation any_ostream_representation
5 #endif
6 #line 1 "iconv-ostream.oo.c"
7 /* Output stream that converts the output to another encoding.
8 Copyright (C) 2006-2007, 2010, 2019-2020 Free Software Foundation, Inc.
9 Written by Bruno Haible <bruno@clisp.org>, 2006.
10
11 This program is free software: you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <https://www.gnu.org/licenses/>. */
23
24 #include <config.h>
25
26 /* Specification. */
27 #include "iconv-ostream.h"
28
29 #if HAVE_ICONV
30
31 #include <errno.h>
32 #include <iconv.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "c-strcase.h"
37 #include "error.h"
38 #include "xalloc.h"
39 #include "gettext.h"
40
41 #define _(str) gettext (str)
42
43 #endif /* HAVE_ICONV */
44
45 #line 46 "iconv-ostream.c"
46 #include "iconv_ostream.priv.h"
47
48 const typeinfo_t iconv_ostream_typeinfo = { "iconv_ostream" };
49
50 static const typeinfo_t * const iconv_ostream_superclasses[] =
51 { iconv_ostream_SUPERCLASSES };
52
53 #define super ostream_vtable
54
55 #line 56 "iconv-ostream.oo.c"
56
57 #if HAVE_ICONV
58
59 /* Implementation of ostream_t methods. */
60
61 static void
62 iconv_ostream__write_mem (iconv_ostream_t stream, const void *data, size_t len)
63 {
64 if (len > 0)
65 {
66 #define BUFFERSIZE 256
67 char inbuffer[BUFFERSIZE];
68 size_t inbufcount;
69
70 inbufcount = stream->buflen;
71 if (inbufcount > 0)
72 memcpy (inbuffer, stream->buf, inbufcount);
73 for (;;)
74 {
75 /* At this point, inbuffer[0..inbufcount-1] is filled. */
76 {
77 /* Combine the previous rest with a chunk of new input. */
78 size_t n =
79 (len <= BUFFERSIZE - inbufcount ? len : BUFFERSIZE - inbufcount);
80
81 if (n > 0)
82 {
83 memcpy (inbuffer + inbufcount, data, n);
84 data = (const char *) data + n;
85 inbufcount += n;
86 len -= n;
87 }
88 }
89 {
90 /* Attempt to convert the combined input. */
91 char outbuffer[8*BUFFERSIZE];
92
93 const char *inptr = inbuffer;
94 size_t insize = inbufcount;
95 char *outptr = outbuffer;
96 size_t outsize = sizeof (outbuffer);
97
98 size_t res = iconv (stream->cd,
99 (ICONV_CONST char **) &inptr, &insize,
100 &outptr, &outsize);
101 #if !defined _LIBICONV_VERSION \
102 && !(defined __GLIBC__ && !defined __UCLIBC__)
103 /* Irix iconv() inserts a NUL byte if it cannot convert.
104 NetBSD iconv() inserts a question mark if it cannot convert.
105 Only GNU libiconv and GNU libc are known to prefer to fail rather
106 than doing a lossy conversion. */
107 if (res > 0)
108 {
109 errno = EILSEQ;
110 res = -1;
111 }
112 #endif
113 if (res == (size_t)(-1) && errno != EINVAL)
114 error (EXIT_FAILURE, 0, _("%s: cannot convert from %s to %s"),
115 "iconv_ostream",
116 stream->from_encoding, stream->to_encoding);
117 /* Output the converted part. */
118 if (sizeof (outbuffer) - outsize > 0)
119 ostream_write_mem (stream->destination,
120 outbuffer, sizeof (outbuffer) - outsize);
121 /* Put back the unconverted part. */
122 if (insize > BUFSIZE)
123 error (EXIT_FAILURE, 0, _("%s: shift sequence too long"),
124 "iconv_ostream");
125 if (len == 0)
126 {
127 if (insize > 0)
128 memcpy (stream->buf, inptr, insize);
129 stream->buflen = insize;
130 break;
131 }
132 if (insize > 0)
133 memmove (inbuffer, inptr, insize);
134 inbufcount = insize;
135 }
136 }
137 #undef BUFFERSIZE
138 }
139 }
140
141 static void
142 iconv_ostream__flush (iconv_ostream_t stream, ostream_flush_scope_t scope)
143 {
144 /* For scope == FLUSH_THIS_STREAM, there's nothing we can do here, since
145 stream->buf[] contains only a few bytes that don't correspond to a
146 character. */
147 if (scope != FLUSH_THIS_STREAM)
148 ostream_flush (stream->destination, scope);
149 }
150
151 static void
152 iconv_ostream__free (iconv_ostream_t stream)
153 {
154 /* Silently ignore the few bytes in stream->buf[] that don't correspond to a
155 character. */
156
157 /* Avoid glibc-2.1 bug and Solaris 2.7 bug. */
158 #if defined _LIBICONV_VERSION \
159 || !(((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) \
160 && !defined __UCLIBC__) \
161 || defined __sun)
162 {
163 char outbuffer[2048];
164 char *outptr = outbuffer;
165 size_t outsize = sizeof (outbuffer);
166 size_t res = iconv (stream->cd, NULL, NULL, &outptr, &outsize);
167 if (res == (size_t)(-1))
168 error (EXIT_FAILURE, 0, _("%s: cannot convert from %s to %s"),
169 "iconv_ostream", stream->from_encoding, stream->to_encoding);
170 /* Output the converted part. */
171 if (sizeof (outbuffer) - outsize > 0)
172 ostream_write_mem (stream->destination,
173 outbuffer, sizeof (outbuffer) - outsize);
174 }
175 #endif
176
177 iconv_close (stream->cd);
178 free (stream->from_encoding);
179 free (stream->to_encoding);
180 free (stream);
181 }
182
183 /* Constructor. */
184
185 iconv_ostream_t
186 iconv_ostream_create (const char *from_encoding, const char *to_encoding,
187 ostream_t destination)
188 {
189 iconv_ostream_t stream = XMALLOC (struct iconv_ostream_representation);
190
191 stream->base.vtable = &iconv_ostream_vtable;
192 stream->destination = destination;
193 stream->from_encoding = xstrdup (from_encoding);
194 stream->to_encoding = xstrdup (to_encoding);
195
196 /* Avoid glibc-2.1 bug with EUC-KR. */
197 #if ((__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) \
198 && !defined __UCLIBC__) \
199 && !defined _LIBICONV_VERSION
200 if (c_strcasecmp (from_encoding, "EUC-KR") == 0
201 || c_strcasecmp (to_encoding, "EUC-KR") == 0)
202 stream->cd = (iconv_t)(-1):
203 else
204 #endif
205 stream->cd = iconv_open (to_encoding, from_encoding);
206 if (stream->cd == (iconv_t)(-1))
207 {
208 if (iconv_open ("UTF-8", from_encoding) == (iconv_t)(-1))
209 error (EXIT_FAILURE, 0, _("%s does not support conversion from %s"),
210 "iconv", from_encoding);
211 else if (iconv_open (to_encoding, "UTF-8") == (iconv_t)(-1))
212 error (EXIT_FAILURE, 0, _("%s does not support conversion to %s"),
213 "iconv", to_encoding);
214 else
215 error (EXIT_FAILURE, 0,
216 _("%s does not support conversion from %s to %s"),
217 "iconv", from_encoding, to_encoding);
218 }
219
220 stream->buflen = 0;
221
222 return stream;
223 }
224
225 /* Accessors. */
226
227 static const char *
228 iconv_ostream__get_from_encoding (iconv_ostream_t stream)
229 {
230 return stream->from_encoding;
231 }
232
233 static const char *
234 iconv_ostream__get_to_encoding (iconv_ostream_t stream)
235 {
236 return stream->to_encoding;
237 }
238
239 static ostream_t
240 iconv_ostream__get_destination (iconv_ostream_t stream)
241 {
242 return stream->destination;
243 }
244
245 /* Instanceof test. */
246
247 bool
248 is_instance_of_iconv_ostream (ostream_t stream)
249 {
250 return IS_INSTANCE (stream, ostream, iconv_ostream);
251 }
252
253 #else
254
255 static void
256 iconv_ostream__write_mem (iconv_ostream_t stream, const void *data, size_t len)
257 {
258 abort ();
259 }
260
261 static void
262 iconv_ostream__flush (iconv_ostream_t stream)
263 {
264 abort ();
265 }
266
267 static void
268 iconv_ostream__free (iconv_ostream_t stream)
269 {
270 abort ();
271 }
272
273 /* Accessors. */
274
275 static const char *
276 iconv_ostream__get_from_encoding (iconv_ostream_t stream)
277 {
278 abort ();
279 }
280
281 static const char *
282 iconv_ostream__get_to_encoding (iconv_ostream_t stream)
283 {
284 abort ();
285 }
286
287 static ostream_t
288 iconv_ostream__get_destination (iconv_ostream_t stream)
289 {
290 abort ();
291 }
292
293 /* Instanceof test. */
294
295 bool
296 is_instance_of_iconv_ostream (ostream_t stream)
297 {
298 return false;
299 }
300
301 #endif /* HAVE_ICONV */
302
303 #line 304 "iconv-ostream.c"
304
305 const struct iconv_ostream_implementation iconv_ostream_vtable =
306 {
307 iconv_ostream_superclasses,
308 sizeof (iconv_ostream_superclasses) / sizeof (iconv_ostream_superclasses[0]),
309 sizeof (struct iconv_ostream_representation),
310 iconv_ostream__write_mem,
311 iconv_ostream__flush,
312 iconv_ostream__free,
313 iconv_ostream__get_from_encoding,
314 iconv_ostream__get_to_encoding,
315 iconv_ostream__get_destination,
316 };
317
318 #if !HAVE_INLINE
319
320 /* Define the functions that invoke the methods. */
321
322 void
323 iconv_ostream_write_mem (iconv_ostream_t first_arg, const void *data, size_t len)
324 {
325 const struct iconv_ostream_implementation *vtable =
326 ((struct iconv_ostream_representation_header *) (struct iconv_ostream_representation *) first_arg)->vtable;
327 vtable->write_mem (first_arg,data,len);
328 }
329
330 void
331 iconv_ostream_flush (iconv_ostream_t first_arg, ostream_flush_scope_t scope)
332 {
333 const struct iconv_ostream_implementation *vtable =
334 ((struct iconv_ostream_representation_header *) (struct iconv_ostream_representation *) first_arg)->vtable;
335 vtable->flush (first_arg,scope);
336 }
337
338 void
339 iconv_ostream_free (iconv_ostream_t first_arg)
340 {
341 const struct iconv_ostream_implementation *vtable =
342 ((struct iconv_ostream_representation_header *) (struct iconv_ostream_representation *) first_arg)->vtable;
343 vtable->free (first_arg);
344 }
345
346 const char *
347 iconv_ostream_get_from_encoding (iconv_ostream_t first_arg)
348 {
349 const struct iconv_ostream_implementation *vtable =
350 ((struct iconv_ostream_representation_header *) (struct iconv_ostream_representation *) first_arg)->vtable;
351 return vtable->get_from_encoding (first_arg);
352 }
353
354 const char *
355 iconv_ostream_get_to_encoding (iconv_ostream_t first_arg)
356 {
357 const struct iconv_ostream_implementation *vtable =
358 ((struct iconv_ostream_representation_header *) (struct iconv_ostream_representation *) first_arg)->vtable;
359 return vtable->get_to_encoding (first_arg);
360 }
361
362 ostream_t
363 iconv_ostream_get_destination (iconv_ostream_t first_arg)
364 {
365 const struct iconv_ostream_implementation *vtable =
366 ((struct iconv_ostream_representation_header *) (struct iconv_ostream_representation *) first_arg)->vtable;
367 return vtable->get_destination (first_arg);
368 }
369
370 #endif