1 /* Simple transformations functions.
2 Copyright (C) 1997, 1998 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
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.
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.
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. */
29 #include <sys/param.h>
32 # define EILSEQ EINVAL
36 /* These are definitions used by some of the functions for handling
37 UTF-8 encoding below. */
38 static const uint32_t encoding_mask
[] =
40 ~0x7ff, ~0xffff, ~0x1fffff, ~0x3ffffff
43 static const unsigned char encoding_byte
[] =
45 0xc0, 0xe0, 0xf0, 0xf8, 0xfc
51 __gconv_transform_dummy (struct gconv_step
*step
, struct gconv_step_data
*data
,
52 const char **inbuf
, const char *inbufend
,
53 size_t *written
, int do_flush
)
57 /* We have no stateful encoding. So we don't have to do anything
63 do_write
= MIN (inbufend
- *inbuf
, data
->outbufend
- data
->outbuf
);
65 memcpy (data
->outbuf
, inbuf
, do_write
);
68 *data
->outbuf
+= do_write
;
71 /* ### TODO Actually, this number must be devided according to the
72 size of the input charset. I.e., if the input is in UCS4 the
73 number of copied bytes must be divided by 4. */
81 /* Transform from the internal, UCS4-like format, to UCS4. The
82 difference between the internal ucs4 format and the real UCS4
83 format is, if any, the endianess. The Unicode/ISO 10646 says that
84 unless some higher protocol specifies it differently, the byte
85 order is big endian.*/
88 #define MIN_NEEDED_FROM 4
89 #define MIN_NEEDED_TO 4
90 #define FROM_DIRECTION 1
91 #define FROM_LOOP internal_ucs4_loop
92 #define TO_LOOP internal_ucs4_loop /* This is not used. */
93 #define FUNCTION_NAME __gconv_transform_internal_ucs4
97 internal_ucs4_loop (const unsigned char **inptrp
, const unsigned char *inend
,
98 unsigned char **outptrp
, unsigned char *outend
,
99 mbstate_t *state
, void *data
, size_t *converted
)
101 const unsigned char *inptr
= *inptrp
;
102 unsigned char *outptr
= *outptrp
;
103 size_t n_convert
= MIN (inend
- inptr
, outend
- outptr
) / 4;
106 #if __BYTE_ORDER == __LITTLE_ENDIAN
107 /* Sigh, we have to do some real work. */
110 for (cnt
= 0; cnt
< n_convert
; ++cnt
, inptr
+= 4)
111 *((uint32_t *) outptr
)++ = bswap_32 (*(uint32_t *) inptr
);
115 #elif __BYTE_ORDER == __BIG_ENDIAN
116 /* Simply copy the data. */
117 *inptrp
= inptr
+ n_convert
* 4;
118 *outptrp
= __mempcpy (outptr
, inptr
, n_convert
* 4);
120 # error "This endianess is not supported."
123 /* Determine the status. */
124 if (*outptrp
== outend
)
125 result
= GCONV_FULL_OUTPUT
;
126 else if (*inptrp
== inend
)
127 result
= GCONV_EMPTY_INPUT
;
129 result
= GCONV_INCOMPLETE_INPUT
;
131 if (converted
!= NULL
)
132 converted
+= n_convert
;
137 #include <iconv/skeleton.c>
140 /* Convert from ISO 646-IRV to the internal (UCS4-like) format. */
141 #define DEFINE_INIT 0
142 #define DEFINE_FINI 0
143 #define MIN_NEEDED_FROM 1
144 #define MIN_NEEDED_TO 4
145 #define FROM_DIRECTION 1
146 #define FROM_LOOP ascii_internal_loop
147 #define TO_LOOP ascii_internal_loop /* This is not used. */
148 #define FUNCTION_NAME __gconv_transform_ascii_internal
150 #define MIN_NEEDED_INPUT MIN_NEEDED_FROM
151 #define MIN_NEEDED_OUTPUT MIN_NEEDED_TO
152 #define LOOPFCT FROM_LOOP
155 if (*inptr > '\x7f') \
157 /* This is no correct ANSI_X3.4-1968 character. */ \
158 result = GCONV_ILLEGAL_INPUT; \
162 /* It's an one byte sequence. */ \
163 *((uint32_t *) outptr)++ = *inptr++; \
165 #include <iconv/loop.c>
166 #include <iconv/skeleton.c>
169 /* Convert from the internal (UCS4-like) format to ISO 646-IRV. */
170 #define DEFINE_INIT 0
171 #define DEFINE_FINI 0
172 #define MIN_NEEDED_FROM 4
173 #define MIN_NEEDED_TO 1
174 #define FROM_DIRECTION 1
175 #define FROM_LOOP internal_ascii_loop
176 #define TO_LOOP internal_ascii_loop /* This is not used. */
177 #define FUNCTION_NAME __gconv_transform_internal_ascii
179 #define MIN_NEEDED_INPUT MIN_NEEDED_FROM
180 #define MIN_NEEDED_OUTPUT MIN_NEEDED_TO
181 #define LOOPFCT FROM_LOOP
184 if (*((uint32_t *) inptr) > 0x7f) \
186 /* This is no correct ANSI_X3.4-1968 character. */ \
187 result = GCONV_ILLEGAL_INPUT; \
191 /* It's an one byte sequence. */ \
192 *outptr++ = *((uint32_t *) inptr)++; \
194 #include <iconv/loop.c>
195 #include <iconv/skeleton.c>
198 /* Convert from the internal (UCS4-like) format to UTF-8. */
199 #define DEFINE_INIT 0
200 #define DEFINE_FINI 0
201 #define MIN_NEEDED_FROM 4
202 #define MIN_NEEDED_TO 1
203 #define MAX_NEEDED_TO 6
204 #define FROM_DIRECTION 1
205 #define FROM_LOOP internal_utf8_loop
206 #define TO_LOOP internal_utf8_loop /* This is not used. */
207 #define FUNCTION_NAME __gconv_transform_internal_utf8
209 #define MIN_NEEDED_INPUT MIN_NEEDED_FROM
210 #define MIN_NEEDED_OUTPUT MIN_NEEDED_TO
211 #define MAX_NEEDED_OUTPUT MAX_NEEDED_TO
212 #define LOOPFCT FROM_LOOP
215 uint32_t wc = *((uint32_t *) inptr); \
217 /* Since we control every character we read this cannot happen. */ \
218 assert (wc <= 0x7fffffff); \
221 /* It's an one byte sequence. */ \
222 *outptr++ = (unsigned char) wc; \
228 for (step = 2; step < 6; ++step) \
229 if ((wc & encoding_mask[step - 2]) == 0) \
232 if (outptr + step >= outend) \
235 result = GCONV_FULL_OUTPUT; \
240 *outptr = encoding_byte[step - 2]; \
245 start[step] = 0x80 | (wc & 0x3f); \
248 while (--step > 0); \
254 #include <iconv/loop.c>
255 #include <iconv/skeleton.c>
258 /* Convert from UTF-8 to the internal (UCS4-like) format. */
259 #define DEFINE_INIT 0
260 #define DEFINE_FINI 0
261 #define MIN_NEEDED_FROM 1
262 #define MAX_NEEDED_FROM 6
263 #define MIN_NEEDED_TO 4
264 #define FROM_DIRECTION 1
265 #define FROM_LOOP utf8_internal_loop
266 #define TO_LOOP utf8_internal_loop /* This is not used. */
267 #define FUNCTION_NAME __gconv_transform_utf8_internal
269 #define MIN_NEEDED_INPUT MIN_NEEDED_FROM
270 #define MAX_NEEDED_INPUT MAX_NEEDED_FROM
271 #define MIN_NEEDED_OUTPUT MIN_NEEDED_TO
272 #define LOOPFCT FROM_LOOP
279 /* Next input byte. */ \
284 /* One byte sequence. */ \
290 if ((ch & 0xe0) == 0xc0) \
295 else if ((ch & 0xf0) == 0xe0) \
297 /* We expect three bytes. */ \
301 else if ((ch & 0xf8) == 0xf0) \
303 /* We expect four bytes. */ \
307 else if ((ch & 0xfc) == 0xf8) \
309 /* We expect five bytes. */ \
313 else if ((ch & 0xfe) == 0xfc) \
315 /* We expect six bytes. */ \
321 /* This is an illegal encoding. */ \
322 result = GCONV_ILLEGAL_INPUT; \
326 if (NEED_LENGTH_TEST && inptr + cnt > inend) \
328 /* We don't have enough input. */ \
329 result = GCONV_INCOMPLETE_INPUT; \
333 /* Read the possible remaining bytes. */ \
334 for (i = 1; i < cnt; ++i) \
336 uint32_t byte = inptr[i]; \
338 if ((byte & 0xc0) != 0x80) \
340 /* This is an illegal encoding. */ \
341 result = GCONV_ILLEGAL_INPUT; \
351 /* Now adjust the pointers and store the result. */ \
352 *((uint32_t *) outptr)++ = ch; \
354 #include <iconv/loop.c>
355 #include <iconv/skeleton.c>
358 /* Convert from UCS2 to the internal (UCS4-like) format. */
359 #define DEFINE_INIT 0
360 #define DEFINE_FINI 0
361 #define MIN_NEEDED_FROM 2
362 #define MIN_NEEDED_TO 4
363 #define FROM_DIRECTION 1
364 #define FROM_LOOP ucs2_internal_loop
365 #define TO_LOOP ucs2_internal_loop /* This is not used. */
366 #define FUNCTION_NAME __gconv_transform_ucs2_internal
368 #define MIN_NEEDED_INPUT MIN_NEEDED_FROM
369 #define MIN_NEEDED_OUTPUT MIN_NEEDED_TO
370 #define LOOPFCT FROM_LOOP
371 #if __BYTE_ORDER == __LITTLE_ENDIAN
373 *((uint32_t *) outptr)++ = bswap_16 (*(uint16_t *) inptr); \
377 *((uint32_t *) outptr)++ = *((uint16_t *) inptr)++;
379 #include <iconv/loop.c>
380 #include <iconv/skeleton.c>
383 /* Convert from the internal (UCS4-like) format to UCS2. */
384 #define DEFINE_INIT 0
385 #define DEFINE_FINI 0
386 #define MIN_NEEDED_FROM 4
387 #define MIN_NEEDED_TO 2
388 #define FROM_DIRECTION 1
389 #define FROM_LOOP internal_ucs2_loop
390 #define TO_LOOP internal_ucs2_loop /* This is not used. */
391 #define FUNCTION_NAME __gconv_transform_internal_ucs2
393 #define MIN_NEEDED_INPUT MIN_NEEDED_FROM
394 #define MIN_NEEDED_OUTPUT MIN_NEEDED_TO
395 #define LOOPFCT FROM_LOOP
396 #if __BYTE_ORDER == __LITTLE_ENDIAN
399 if (*((uint32_t *) inptr) >= 0x10000) \
401 result = GCONV_ILLEGAL_INPUT; \
404 /* Please note that we use the `uint32_t' from-pointer as an `uint16_t' \
405 pointer which works since we are on a little endian machine. */ \
406 *((uint16_t *) outptr)++ = bswap_16 (*((uint16_t *) inptr)); \
412 if (*((uint32_t *) inptr) >= 0x10000) \
414 result = GCONV_ILLEGAL_INPUT; \
417 *((uint16_t *) outptr)++ = *((uint32_t *) inptr)++; \
420 #include <iconv/loop.c>
421 #include <iconv/skeleton.c>
424 /* Convert from UCS2 in little endian to the internal (UCS4-like) format. */
425 #define DEFINE_INIT 0
426 #define DEFINE_FINI 0
427 #define MIN_NEEDED_FROM 2
428 #define MIN_NEEDED_TO 4
429 #define FROM_DIRECTION 1
430 #define FROM_LOOP ucs2little_internal_loop
431 #define TO_LOOP ucs2little_internal_loop /* This is not used.*/
432 #define FUNCTION_NAME __gconv_transform_ucs2little_internal
434 #define MIN_NEEDED_INPUT MIN_NEEDED_FROM
435 #define MIN_NEEDED_OUTPUT MIN_NEEDED_TO
436 #define LOOPFCT FROM_LOOP
437 #if __BYTE_ORDER == __LITTLE_ENDIAN
439 *((uint32_t *) outptr)++ = *((uint16_t *) inptr)++;
442 *((uint32_t *) outptr)++ = bswap_16 (*(uint16_t *) inptr); \
445 #include <iconv/loop.c>
446 #include <iconv/skeleton.c>
449 /* Convert from the internal (UCS4-like) format to UCS2 in little endian. */
450 #define DEFINE_INIT 0
451 #define DEFINE_FINI 0
452 #define MIN_NEEDED_FROM 4
453 #define MIN_NEEDED_TO 2
454 #define FROM_DIRECTION 1
455 #define FROM_LOOP internal_ucs2little_loop
456 #define TO_LOOP internal_ucs2little_loop /* This is not used.*/
457 #define FUNCTION_NAME __gconv_transform_internal_ucs2little
459 #define MIN_NEEDED_INPUT MIN_NEEDED_FROM
460 #define MIN_NEEDED_OUTPUT MIN_NEEDED_TO
461 #define LOOPFCT FROM_LOOP
462 #if __BYTE_ORDER == __LITTLE_ENDIAN
465 if (*((uint32_t *) inptr) >= 0x10000) \
467 result = GCONV_ILLEGAL_INPUT; \
470 *((uint16_t *) outptr)++ = *((uint32_t *) inptr)++; \
475 if (*((uint32_t *) inptr) >= 0x10000) \
477 result = GCONV_ILLEGAL_INPUT; \
480 *((uint16_t *) outptr)++ = bswap_16 (((uint16_t *) inptr)[1]); \
484 #include <iconv/loop.c>
485 #include <iconv/skeleton.c>