1 /* Conversion module for UTF-7.
2 Copyright (C) 2000 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Bruno Haible <haible@clisp.cons.org>, 2000.
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. */
21 /* UTF-7 is a legacy encoding used for transmitting Unicode within the
22 ASCII character set, used primarily by mail agents. New programs
23 are encouraged to use UTF-8 instead.
25 UTF-7 is specified in RFC 2152 (and old RFC 1641, RFC 1642). The
26 original Base64 encoding is defined in RFC 2045. */
34 /* Define this to 1 if you want the so-called "optional direct" characters
35 ! " # $ % & * ; < = > @ [ ] ^ _ ` { | }
36 to be encoded. Define to 0 if you want them to be passed straight
37 through, like the so-called "direct" characters.
38 We set this to 1 because it's safer.
40 #define UTF7_ENCODE_OPTIONAL_CHARS 1
43 /* The set of "direct characters":
44 A-Z a-z 0-9 ' ( ) , - . / : ? space tab lf cr
47 static const unsigned char direct_tab
[128/8] =
49 0x00, 0x26, 0x00, 0x00, 0x81, 0xf3, 0xff, 0x87,
50 0xfe, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0x07
54 isdirect (uint32_t ch
)
56 return (ch
< 128 && ((direct_tab
[ch
>> 3] >> (ch
& 7)) & 1));
60 /* The set of "direct and optional direct characters":
61 A-Z a-z 0-9 ' ( ) , - . / : ? space tab lf cr
62 ! " # $ % & * ; < = > @ [ ] ^ _ ` { | }
65 static const unsigned char xdirect_tab
[128/8] =
67 0x00, 0x26, 0x00, 0x00, 0xff, 0xf7, 0xff, 0xff,
68 0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0x3f
72 isxdirect (uint32_t ch
)
74 return (ch
< 128 && ((xdirect_tab
[ch
>> 3] >> (ch
& 7)) & 1));
78 /* The set of "extended base64 characters":
82 static const unsigned char xbase64_tab
[128/8] =
84 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0xff, 0x03,
85 0xfe, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0x07
89 isxbase64 (uint32_t ch
)
91 return (ch
< 128 && ((xbase64_tab
[ch
>> 3] >> (ch
& 7)) & 1));
95 /* Converts a value in the range 0..63 to a base64 encoded char. */
96 static inline unsigned char
97 base64 (unsigned int i
)
114 /* Definitions used in the body of the `gconv' function. */
115 #define CHARSET_NAME "UTF-7//"
116 #define DEFINE_INIT 1
117 #define DEFINE_FINI 1
118 #define FROM_LOOP from_utf7_loop
119 #define TO_LOOP to_utf7_loop
120 #define MIN_NEEDED_FROM 1
121 #define MAX_NEEDED_FROM 6
122 #define MIN_NEEDED_TO 4
123 #define MAX_NEEDED_TO 4
124 #define PREPARE_LOOP \
125 mbstate_t saved_state; \
126 mbstate_t *statep = data->__statep;
127 #define EXTRA_LOOP_ARGS , statep
130 /* Since we might have to reset input pointer we must be able to save
131 and restore the state. */
132 #define SAVE_RESET_STATE(Save) \
134 saved_state = *statep; \
136 *statep = saved_state
139 /* First define the conversion function from UTF-7 to UCS4.
140 The state is structured as follows:
141 __count bit 2..0: zero
142 __count bit 8..3: shift
146 0 -- not inside base64 encoding
147 1..32 XX..XX00..00 inside base64, (32 - shift) bits pending
148 This state layout is simpler than relying on STORE_REST/UNPACK_BYTES.
150 When shift = 0, __wch needs to store at most one lookahead byte (see
151 __GCONV_INCOMPLETE_INPUT below).
153 #define MIN_NEEDED_INPUT MIN_NEEDED_FROM
154 #define MAX_NEEDED_INPUT MAX_NEEDED_FROM
155 #define MIN_NEEDED_OUTPUT MIN_NEEDED_TO
156 #define MAX_NEEDED_OUTPUT MAX_NEEDED_TO
157 #define LOOPFCT FROM_LOOP
160 uint_fast8_t ch = *inptr; \
162 if ((statep->__count >> 3) == 0) \
164 /* base64 encoding inactive. */ \
165 if (isxdirect (ch)) \
168 put32 (outptr, ch); \
171 else if (__builtin_expect (ch == '+', 1)) \
173 if (__builtin_expect (inptr + 2 >= inend, 0)) \
175 /* Not enough input available. */ \
176 result = __GCONV_INCOMPLETE_INPUT; \
179 if (inptr[1] == '-') \
182 put32 (outptr, ch); \
187 /* Switch into base64 mode. */ \
189 statep->__count = (32 << 3); \
190 statep->__value.__wch = 0; \
195 /* The input is invalid. */ \
196 if (! ignore_errors_p ()) \
198 result = __GCONV_ILLEGAL_INPUT; \
208 /* base64 encoding active. */ \
212 if (ch >= 'A' && ch <= 'Z') \
214 else if (ch >= 'a' && ch <= 'z') \
216 else if (ch >= '0' && ch <= '9') \
218 else if (ch == '+') \
220 else if (ch == '/') \
224 /* Terminate base64 encoding. */ \
226 /* If accumulated data is nonzero, the input is invalid. */ \
227 /* Also, partial UTF-16 characters are invalid. */ \
228 if (__builtin_expect (statep->__value.__wch != 0, 0) \
229 || __builtin_expect ((statep->__count >> 3) <= 26, 0)) \
231 if (! ignore_errors_p ()) \
233 result = __GCONV_ILLEGAL_INPUT; \
239 statep->__count = 0; \
246 statep->__count = 0; \
250 /* Concatenate the base64 integer i to the accumulator. */ \
251 shift = (statep->__count >> 3); \
257 wch = statep->__value.__wch | (i << shift); \
259 if (shift <= 16 && shift > 10) \
261 /* An UTF-16 character has just been completed. */ \
262 uint32_t wc1 = wch >> 16; \
264 /* UTF-16: When we see a High Surrogate, we must also decode \
265 the following Low Surrogate. */ \
266 if (!(wc1 >= 0xd800 && wc1 < 0xdc00)) \
270 put32 (outptr, wc1); \
274 else if (shift <= 10 && shift > 4) \
276 /* After a High Surrogate, verify that the next 16 bit \
277 indeed form a Low Surrogate. */ \
278 uint32_t wc2 = wch & 0xffff; \
280 if (! __builtin_expect (wc2 >= 0xdc00 && wc2 < 0xe000, 1)) \
282 if (! ignore_errors_p ()) \
284 result = __GCONV_ILLEGAL_INPUT; \
290 statep->__count = 0; \
295 statep->__value.__wch = wch; \
299 /* An UTF-16 surrogate pair has just been completed. */ \
300 uint32_t wc1 = (uint32_t) statep->__value.__wch >> 16; \
301 uint32_t wc2 = ((uint32_t) statep->__value.__wch & 0xffff) \
302 | (i >> (6 - shift)); \
304 statep->__value.__wch = (i << shift) << 26; \
307 assert (wc1 >= 0xd800 && wc1 < 0xdc00); \
308 assert (wc2 >= 0xdc00 && wc2 < 0xe000); \
310 0x10000 + ((wc1 - 0xd800) << 10) + (wc2 - 0xdc00)); \
314 statep->__count = shift << 3; \
316 /* Now that we digested the input increment the input pointer. */ \
320 #define LOOP_NEED_FLAGS
321 #define EXTRA_LOOP_DECLS , mbstate_t *statep
322 #include <iconv/loop.c>
325 /* Next, define the conversion from UCS4 to UTF-7.
326 The state is structured as follows:
327 __count bit 2..0: zero
328 __count bit 4..3: shift
329 __count bit 8..5: data
332 0 0 not inside base64 encoding
333 1 0 inside base64, no pending bits
334 2 XX00 inside base64, 2 bits known for next byte
335 3 XXXX inside base64, 4 bits known for next byte
337 __count bit 2..0 and __wch are always zero, because this direction
338 never returns __GCONV_INCOMPLETE_INPUT.
340 #define MIN_NEEDED_INPUT MIN_NEEDED_TO
341 #define MAX_NEEDED_INPUT MAX_NEEDED_TO
342 #define MIN_NEEDED_OUTPUT MIN_NEEDED_FROM
343 #define MAX_NEEDED_OUTPUT MAX_NEEDED_FROM
344 #define LOOPFCT TO_LOOP
347 uint32_t ch = get32 (inptr); \
349 if ((statep->__count & 0x18) == 0) \
351 /* base64 encoding inactive */ \
352 if (UTF7_ENCODE_OPTIONAL_CHARS ? isdirect (ch) : isxdirect (ch)) \
354 *outptr++ = (unsigned char) ch; \
362 else if (ch < 0x10000) \
364 else if (ch < 0x110000) \
367 STANDARD_ERR_HANDLER (4); \
369 if (__builtin_expect (outptr + count > outend, 0)) \
371 result = __GCONV_FULL_OUTPUT; \
378 else if (ch < 0x10000) \
380 *outptr++ = base64 (ch >> 10); \
381 *outptr++ = base64 ((ch >> 4) & 0x3f); \
382 statep->__count = ((ch & 15) << 5) | (3 << 3); \
384 else if (ch < 0x110000) \
386 uint32_t ch1 = 0xd800 + ((ch - 0x10000) >> 10); \
387 uint32_t ch2 = 0xdc00 + ((ch - 0x10000) & 0x3ff); \
389 ch = (ch1 << 16) | ch2; \
390 *outptr++ = base64 (ch >> 26); \
391 *outptr++ = base64 ((ch >> 20) & 0x3f); \
392 *outptr++ = base64 ((ch >> 14) & 0x3f); \
393 *outptr++ = base64 ((ch >> 8) & 0x3f); \
394 *outptr++ = base64 ((ch >> 2) & 0x3f); \
395 statep->__count = ((ch & 3) << 7) | (2 << 3); \
403 /* base64 encoding active */ \
404 if (UTF7_ENCODE_OPTIONAL_CHARS ? isdirect (ch) : isxdirect (ch)) \
406 /* deactivate base64 encoding */ \
409 count = ((statep->__count & 0x18) >= 0x10) + isxbase64 (ch) + 1; \
410 if (__builtin_expect (outptr + count > outend, 0)) \
412 result = __GCONV_FULL_OUTPUT; \
416 if ((statep->__count & 0x18) >= 0x10) \
417 *outptr++ = base64 ((statep->__count >> 3) & ~3); \
418 if (isxbase64 (ch)) \
420 *outptr++ = (unsigned char) ch; \
421 statep->__count = 0; \
428 count = ((statep->__count & 0x18) >= 0x10 ? 3 : 2); \
429 else if (ch < 0x110000) \
430 count = ((statep->__count & 0x18) >= 0x18 ? 6 : 5); \
432 STANDARD_ERR_HANDLER (4); \
434 if (__builtin_expect (outptr + count > outend, 0)) \
436 result = __GCONV_FULL_OUTPUT; \
442 switch ((statep->__count >> 3) & 3) \
445 *outptr++ = base64 (ch >> 10); \
446 *outptr++ = base64 ((ch >> 4) & 0x3f); \
447 statep->__count = ((ch & 15) << 5) | (3 << 3); \
451 base64 (((statep->__count >> 3) & ~3) | (ch >> 12)); \
452 *outptr++ = base64 ((ch >> 6) & 0x3f); \
453 *outptr++ = base64 (ch & 0x3f); \
454 statep->__count = (1 << 3); \
458 base64 (((statep->__count >> 3) & ~3) | (ch >> 14)); \
459 *outptr++ = base64 ((ch >> 8) & 0x3f); \
460 *outptr++ = base64 ((ch >> 2) & 0x3f); \
461 statep->__count = ((ch & 3) << 7) | (2 << 3); \
467 else if (ch < 0x110000) \
469 uint32_t ch1 = 0xd800 + ((ch - 0x10000) >> 10); \
470 uint32_t ch2 = 0xdc00 + ((ch - 0x10000) & 0x3ff); \
472 ch = (ch1 << 16) | ch2; \
473 switch ((statep->__count >> 3) & 3) \
476 *outptr++ = base64 (ch >> 26); \
477 *outptr++ = base64 ((ch >> 20) & 0x3f); \
478 *outptr++ = base64 ((ch >> 14) & 0x3f); \
479 *outptr++ = base64 ((ch >> 8) & 0x3f); \
480 *outptr++ = base64 ((ch >> 2) & 0x3f); \
481 statep->__count = ((ch & 3) << 7) | (2 << 3); \
485 base64 (((statep->__count >> 3) & ~3) | (ch >> 28)); \
486 *outptr++ = base64 ((ch >> 22) & 0x3f); \
487 *outptr++ = base64 ((ch >> 16) & 0x3f); \
488 *outptr++ = base64 ((ch >> 10) & 0x3f); \
489 *outptr++ = base64 ((ch >> 4) & 0x3f); \
490 statep->__count = ((ch & 15) << 5) | (3 << 3); \
494 base64 (((statep->__count >> 3) & ~3) | (ch >> 30)); \
495 *outptr++ = base64 ((ch >> 24) & 0x3f); \
496 *outptr++ = base64 ((ch >> 18) & 0x3f); \
497 *outptr++ = base64 ((ch >> 12) & 0x3f); \
498 *outptr++ = base64 ((ch >> 6) & 0x3f); \
499 *outptr++ = base64 (ch & 0x3f); \
500 statep->__count = (1 << 3); \
511 /* Now that we wrote the output increment the input pointer. */ \
514 #define LOOP_NEED_FLAGS
515 #define EXTRA_LOOP_DECLS , mbstate_t *statep
516 #include <iconv/loop.c>
519 /* Since this is a stateful encoding we have to provide code which resets
520 the output state to the initial state. This has to be done during the
522 #define EMIT_SHIFT_TO_INIT \
523 if (FROM_DIRECTION) \
524 /* Nothing to emit. */ \
525 memset (data->__statep, '\0', sizeof (mbstate_t)); \
528 /* The "to UTF-7" direction. Flush the remaining bits and terminate \
529 with a '-' byte. This will guarantee correct decoding if more \
530 UTF-7 encoded text is added afterwards. */ \
531 int state = data->__statep->__count; \
535 /* Deactivate base64 encoding. */ \
536 unsigned char *outbuf = data->__outbuf; \
537 size_t count = ((state & 0x18) >= 0x10) + 1; \
539 if (__builtin_expect (outbuf + count > data->__outbufend, 0)) \
540 /* We don't have enough room in the output buffer. */ \
541 status = __GCONV_FULL_OUTPUT; \
544 /* Write out the shift sequence. */ \
545 if ((state & 0x18) >= 0x10) \
546 *outbuf++ = base64 ((state >> 3) & ~3); \
549 data->__outbuf = outbuf; \
550 data->__statep->__count = 0; \
554 data->__statep->__count = 0; \
558 /* Now define the toplevel functions. */
559 #include <iconv/skeleton.c>