Back to index

glibc  2.9
utf-7.c
Go to the documentation of this file.
00001 /* Conversion module for UTF-7.
00002    Copyright (C) 2000-2002, 2003, 2004 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Bruno Haible <haible@clisp.cons.org>, 2000.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 /* UTF-7 is a legacy encoding used for transmitting Unicode within the
00022    ASCII character set, used primarily by mail agents.  New programs
00023    are encouraged to use UTF-8 instead.
00024 
00025    UTF-7 is specified in RFC 2152 (and old RFC 1641, RFC 1642).  The
00026    original Base64 encoding is defined in RFC 2045.  */
00027 
00028 #include <dlfcn.h>
00029 #include <gconv.h>
00030 #include <stdint.h>
00031 #include <stdlib.h>
00032 
00033 
00034 /* Define this to 1 if you want the so-called "optional direct" characters
00035       ! " # $ % & * ; < = > @ [ ] ^ _ ` { | }
00036    to be encoded. Define to 0 if you want them to be passed straight
00037    through, like the so-called "direct" characters.
00038    We set this to 1 because it's safer.
00039  */
00040 #define UTF7_ENCODE_OPTIONAL_CHARS 1
00041 
00042 
00043 /* The set of "direct characters":
00044    A-Z a-z 0-9 ' ( ) , - . / : ? space tab lf cr
00045 */
00046 
00047 static const unsigned char direct_tab[128 / 8] =
00048   {
00049     0x00, 0x26, 0x00, 0x00, 0x81, 0xf3, 0xff, 0x87,
00050     0xfe, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0x07
00051   };
00052 
00053 static int
00054 isdirect (uint32_t ch)
00055 {
00056   return (ch < 128 && ((direct_tab[ch >> 3] >> (ch & 7)) & 1));
00057 }
00058 
00059 
00060 /* The set of "direct and optional direct characters":
00061    A-Z a-z 0-9 ' ( ) , - . / : ? space tab lf cr
00062    ! " # $ % & * ; < = > @ [ ] ^ _ ` { | }
00063 */
00064 
00065 static const unsigned char xdirect_tab[128 / 8] =
00066   {
00067     0x00, 0x26, 0x00, 0x00, 0xff, 0xf7, 0xff, 0xff,
00068     0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0x3f
00069   };
00070 
00071 static int
00072 isxdirect (uint32_t ch)
00073 {
00074   return (ch < 128 && ((xdirect_tab[ch >> 3] >> (ch & 7)) & 1));
00075 }
00076 
00077 
00078 /* The set of "extended base64 characters":
00079    A-Z a-z 0-9 + / -
00080 */
00081 
00082 static const unsigned char xbase64_tab[128 / 8] =
00083   {
00084     0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0xff, 0x03,
00085     0xfe, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0x07
00086   };
00087 
00088 static int
00089 isxbase64 (uint32_t ch)
00090 {
00091   return (ch < 128 && ((xbase64_tab[ch >> 3] >> (ch & 7)) & 1));
00092 }
00093 
00094 
00095 /* Converts a value in the range 0..63 to a base64 encoded char.  */
00096 static unsigned char
00097 base64 (unsigned int i)
00098 {
00099   if (i < 26)
00100     return i + 'A';
00101   else if (i < 52)
00102     return i - 26 + 'a';
00103   else if (i < 62)
00104     return i - 52 + '0';
00105   else if (i == 62)
00106     return '+';
00107   else if (i == 63)
00108     return '/';
00109   else
00110     abort ();
00111 }
00112 
00113 
00114 /* Definitions used in the body of the `gconv' function.  */
00115 #define CHARSET_NAME        "UTF-7//"
00116 #define DEFINE_INIT         1
00117 #define DEFINE_FINI         1
00118 #define FROM_LOOP           from_utf7_loop
00119 #define TO_LOOP                    to_utf7_loop
00120 #define MIN_NEEDED_FROM            1
00121 #define MAX_NEEDED_FROM            6
00122 #define MIN_NEEDED_TO              4
00123 #define MAX_NEEDED_TO              4
00124 #define PREPARE_LOOP \
00125   mbstate_t saved_state;                                             \
00126   mbstate_t *statep = data->__statep;
00127 #define EXTRA_LOOP_ARGS            , statep
00128 
00129 
00130 /* Since we might have to reset input pointer we must be able to save
00131    and restore the state.  */
00132 #define SAVE_RESET_STATE(Save) \
00133   if (Save)                                                          \
00134     saved_state = *statep;                                           \
00135   else                                                               \
00136     *statep = saved_state
00137 
00138 
00139 /* First define the conversion function from UTF-7 to UCS4.
00140    The state is structured as follows:
00141      __count bit 2..0: zero
00142      __count bit 8..3: shift
00143      __wch: data
00144    Precise meaning:
00145      shift      data
00146        0         --          not inside base64 encoding
00147      1..32  XX..XX00..00     inside base64, (32 - shift) bits pending
00148    This state layout is simpler than relying on STORE_REST/UNPACK_BYTES.
00149 
00150    When shift = 0, __wch needs to store at most one lookahead byte (see
00151    __GCONV_INCOMPLETE_INPUT below).
00152 */
00153 #define MIN_NEEDED_INPUT    MIN_NEEDED_FROM
00154 #define MAX_NEEDED_INPUT    MAX_NEEDED_FROM
00155 #define MIN_NEEDED_OUTPUT   MIN_NEEDED_TO
00156 #define MAX_NEEDED_OUTPUT   MAX_NEEDED_TO
00157 #define LOOPFCT                    FROM_LOOP
00158 #define BODY \
00159   {                                                                  \
00160     uint_fast8_t ch = *inptr;                                               \
00161                                                                      \
00162     if ((statep->__count >> 3) == 0)                                        \
00163       {                                                                     \
00164        /* base64 encoding inactive.  */                              \
00165        if (isxdirect (ch))                                           \
00166          {                                                           \
00167            inptr++;                                                  \
00168            put32 (outptr, ch);                                              \
00169            outptr += 4;                                              \
00170          }                                                           \
00171        else if (__builtin_expect (ch == '+', 1))                     \
00172          {                                                           \
00173            if (__builtin_expect (inptr + 2 > inend, 0))              \
00174              {                                                              \
00175               /* Not enough input available.  */                     \
00176               result = __GCONV_INCOMPLETE_INPUT;                     \
00177               break;                                                 \
00178              }                                                              \
00179            if (inptr[1] == '-')                                      \
00180              {                                                              \
00181               inptr += 2;                                            \
00182               put32 (outptr, ch);                                    \
00183               outptr += 4;                                           \
00184              }                                                              \
00185            else                                                      \
00186              {                                                              \
00187               /* Switch into base64 mode.  */                               \
00188               inptr++;                                               \
00189               statep->__count = (32 << 3);                                  \
00190               statep->__value.__wch = 0;                             \
00191              }                                                              \
00192          }                                                           \
00193        else                                                          \
00194          {                                                           \
00195            /* The input is invalid.  */                              \
00196            STANDARD_FROM_LOOP_ERR_HANDLER (1);                              \
00197          }                                                           \
00198       }                                                                     \
00199     else                                                             \
00200       {                                                                     \
00201        /* base64 encoding active.  */                                       \
00202        uint32_t i;                                                   \
00203        int shift;                                                    \
00204                                                                      \
00205        if (ch >= 'A' && ch <= 'Z')                                   \
00206          i = ch - 'A';                                                      \
00207        else if (ch >= 'a' && ch <= 'z')                              \
00208          i = ch - 'a' + 26;                                          \
00209        else if (ch >= '0' && ch <= '9')                              \
00210          i = ch - '0' + 52;                                          \
00211        else if (ch == '+')                                           \
00212          i = 62;                                                     \
00213        else if (ch == '/')                                           \
00214          i = 63;                                                     \
00215        else                                                          \
00216          {                                                           \
00217            /* Terminate base64 encoding.  */                                \
00218                                                                      \
00219            /* If accumulated data is nonzero, the input is invalid.  */      \
00220            /* Also, partial UTF-16 characters are invalid.  */              \
00221            if (__builtin_expect (statep->__value.__wch != 0, 0)             \
00222               || __builtin_expect ((statep->__count >> 3) <= 26, 0))        \
00223              {                                                              \
00224               STANDARD_FROM_LOOP_ERR_HANDLER ((statep->__count = 0, 1));    \
00225              }                                                              \
00226                                                                      \
00227            if (ch == '-')                                            \
00228              inptr++;                                                       \
00229                                                                      \
00230            statep->__count = 0;                                      \
00231            continue;                                                 \
00232          }                                                           \
00233                                                                      \
00234        /* Concatenate the base64 integer i to the accumulator.  */          \
00235        shift = (statep->__count >> 3);                                      \
00236        if (shift > 6)                                                       \
00237          {                                                           \
00238            uint32_t wch;                                             \
00239                                                                      \
00240            shift -= 6;                                                      \
00241            wch = statep->__value.__wch | (i << shift);                      \
00242                                                                      \
00243            if (shift <= 16 && shift > 10)                            \
00244              {                                                              \
00245               /* An UTF-16 character has just been completed.  */           \
00246               uint32_t wc1 = wch >> 16;                              \
00247                                                                      \
00248               /* UTF-16: When we see a High Surrogate, we must also decode  \
00249                  the following Low Surrogate. */                     \
00250               if (!(wc1 >= 0xd800 && wc1 < 0xdc00))                         \
00251                 {                                                    \
00252                   wch = wch << 16;                                   \
00253                   shift += 16;                                       \
00254                   put32 (outptr, wc1);                               \
00255                   outptr += 4;                                       \
00256                 }                                                    \
00257              }                                                              \
00258            else if (shift <= 10 && shift > 4)                               \
00259              {                                                              \
00260               /* After a High Surrogate, verify that the next 16 bit        \
00261                  indeed form a Low Surrogate.  */                           \
00262               uint32_t wc2 = wch & 0xffff;                                  \
00263                                                                      \
00264               if (! __builtin_expect (wc2 >= 0xdc00 && wc2 < 0xe000, 1))    \
00265                 {                                                    \
00266                   STANDARD_FROM_LOOP_ERR_HANDLER ((statep->__count = 0, 1));\
00267                 }                                                    \
00268              }                                                              \
00269                                                                      \
00270            statep->__value.__wch = wch;                              \
00271          }                                                           \
00272        else                                                          \
00273          {                                                           \
00274            /* An UTF-16 surrogate pair has just been completed.  */         \
00275            uint32_t wc1 = (uint32_t) statep->__value.__wch >> 16;           \
00276            uint32_t wc2 = ((uint32_t) statep->__value.__wch & 0xffff)       \
00277                         | (i >> (6 - shift));                        \
00278                                                                      \
00279            statep->__value.__wch = (i << shift) << 26;                      \
00280            shift += 26;                                              \
00281                                                                      \
00282            assert (wc1 >= 0xd800 && wc1 < 0xdc00);                          \
00283            assert (wc2 >= 0xdc00 && wc2 < 0xe000);                          \
00284            put32 (outptr,                                            \
00285                  0x10000 + ((wc1 - 0xd800) << 10) + (wc2 - 0xdc00));        \
00286            outptr += 4;                                              \
00287          }                                                           \
00288                                                                      \
00289        statep->__count = shift << 3;                                        \
00290                                                                      \
00291        /* Now that we digested the input increment the input pointer.  */    \
00292        inptr++;                                                      \
00293       }                                                                     \
00294   }
00295 #define LOOP_NEED_FLAGS
00296 #define EXTRA_LOOP_DECLS    , mbstate_t *statep
00297 #include <iconv/loop.c>
00298 
00299 
00300 /* Next, define the conversion from UCS4 to UTF-7.
00301    The state is structured as follows:
00302      __count bit 2..0: zero
00303      __count bit 4..3: shift
00304      __count bit 8..5: data
00305    Precise meaning:
00306      shift      data
00307        0         0           not inside base64 encoding
00308        1         0           inside base64, no pending bits
00309        2       XX00          inside base64, 2 bits known for next byte
00310        3       XXXX          inside base64, 4 bits known for next byte
00311 
00312    __count bit 2..0 and __wch are always zero, because this direction
00313    never returns __GCONV_INCOMPLETE_INPUT.
00314 */
00315 #define MIN_NEEDED_INPUT    MIN_NEEDED_TO
00316 #define MAX_NEEDED_INPUT    MAX_NEEDED_TO
00317 #define MIN_NEEDED_OUTPUT   MIN_NEEDED_FROM
00318 #define MAX_NEEDED_OUTPUT   MAX_NEEDED_FROM
00319 #define LOOPFCT                    TO_LOOP
00320 #define BODY \
00321   {                                                                  \
00322     uint32_t ch = get32 (inptr);                                     \
00323                                                                      \
00324     if ((statep->__count & 0x18) == 0)                                      \
00325       {                                                                     \
00326        /* base64 encoding inactive */                                       \
00327        if (UTF7_ENCODE_OPTIONAL_CHARS ? isdirect (ch) : isxdirect (ch))      \
00328          {                                                           \
00329            *outptr++ = (unsigned char) ch;                                  \
00330          }                                                           \
00331        else                                                          \
00332          {                                                           \
00333            size_t count;                                             \
00334                                                                      \
00335            if (ch == '+')                                            \
00336              count = 2;                                              \
00337            else if (ch < 0x10000)                                    \
00338              count = 3;                                              \
00339            else if (ch < 0x110000)                                   \
00340              count = 6;                                              \
00341            else                                                      \
00342              STANDARD_TO_LOOP_ERR_HANDLER (4);                              \
00343                                                                      \
00344            if (__builtin_expect (outptr + count > outend, 0))               \
00345              {                                                              \
00346               result = __GCONV_FULL_OUTPUT;                                 \
00347               break;                                                 \
00348              }                                                              \
00349                                                                      \
00350            *outptr++ = '+';                                          \
00351            if (ch == '+')                                            \
00352              *outptr++ = '-';                                               \
00353            else if (ch < 0x10000)                                    \
00354              {                                                              \
00355               *outptr++ = base64 (ch >> 10);                                \
00356               *outptr++ = base64 ((ch >> 4) & 0x3f);                        \
00357               statep->__count = ((ch & 15) << 5) | (3 << 3);                \
00358              }                                                              \
00359            else if (ch < 0x110000)                                   \
00360              {                                                              \
00361               uint32_t ch1 = 0xd800 + ((ch - 0x10000) >> 10);               \
00362               uint32_t ch2 = 0xdc00 + ((ch - 0x10000) & 0x3ff);             \
00363                                                                      \
00364               ch = (ch1 << 16) | ch2;                                       \
00365               *outptr++ = base64 (ch >> 26);                                \
00366               *outptr++ = base64 ((ch >> 20) & 0x3f);                       \
00367               *outptr++ = base64 ((ch >> 14) & 0x3f);                       \
00368               *outptr++ = base64 ((ch >> 8) & 0x3f);                        \
00369               *outptr++ = base64 ((ch >> 2) & 0x3f);                        \
00370               statep->__count = ((ch & 3) << 7) | (2 << 3);                 \
00371              }                                                              \
00372            else                                                      \
00373              abort ();                                                      \
00374          }                                                           \
00375       }                                                                     \
00376     else                                                             \
00377       {                                                                     \
00378        /* base64 encoding active */                                         \
00379        if (UTF7_ENCODE_OPTIONAL_CHARS ? isdirect (ch) : isxdirect (ch))      \
00380          {                                                           \
00381            /* deactivate base64 encoding */                                 \
00382            size_t count;                                             \
00383                                                                      \
00384            count = ((statep->__count & 0x18) >= 0x10) + isxbase64 (ch) + 1;  \
00385            if (__builtin_expect (outptr + count > outend, 0))               \
00386              {                                                              \
00387               result = __GCONV_FULL_OUTPUT;                                 \
00388               break;                                                 \
00389              }                                                              \
00390                                                                      \
00391            if ((statep->__count & 0x18) >= 0x10)                     \
00392              *outptr++ = base64 ((statep->__count >> 3) & ~3);              \
00393            if (isxbase64 (ch))                                              \
00394              *outptr++ = '-';                                               \
00395            *outptr++ = (unsigned char) ch;                                  \
00396            statep->__count = 0;                                      \
00397          }                                                           \
00398        else                                                          \
00399          {                                                           \
00400            size_t count;                                             \
00401                                                                      \
00402            if (ch < 0x10000)                                                \
00403              count = ((statep->__count & 0x18) >= 0x10 ? 3 : 2);            \
00404            else if (ch < 0x110000)                                   \
00405              count = ((statep->__count & 0x18) >= 0x18 ? 6 : 5);            \
00406            else                                                      \
00407              STANDARD_TO_LOOP_ERR_HANDLER (4);                              \
00408                                                                      \
00409            if (__builtin_expect (outptr + count > outend, 0))               \
00410              {                                                              \
00411               result = __GCONV_FULL_OUTPUT;                                 \
00412               break;                                                 \
00413              }                                                              \
00414                                                                      \
00415            if (ch < 0x10000)                                                \
00416              {                                                              \
00417               switch ((statep->__count >> 3) & 3)                           \
00418                 {                                                    \
00419                 case 1:                                              \
00420                   *outptr++ = base64 (ch >> 10);                     \
00421                   *outptr++ = base64 ((ch >> 4) & 0x3f);                    \
00422                   statep->__count = ((ch & 15) << 5) | (3 << 3);            \
00423                   break;                                             \
00424                 case 2:                                              \
00425                   *outptr++ =                                               \
00426                     base64 (((statep->__count >> 3) & ~3) | (ch >> 12));    \
00427                   *outptr++ = base64 ((ch >> 6) & 0x3f);                    \
00428                   *outptr++ = base64 (ch & 0x3f);                           \
00429                   statep->__count = (1 << 3);                               \
00430                   break;                                             \
00431                 case 3:                                              \
00432                   *outptr++ =                                               \
00433                     base64 (((statep->__count >> 3) & ~3) | (ch >> 14));    \
00434                   *outptr++ = base64 ((ch >> 8) & 0x3f);                    \
00435                   *outptr++ = base64 ((ch >> 2) & 0x3f);                    \
00436                   statep->__count = ((ch & 3) << 7) | (2 << 3);             \
00437                   break;                                             \
00438                 default:                                             \
00439                   abort ();                                          \
00440                 }                                                    \
00441              }                                                              \
00442            else if (ch < 0x110000)                                   \
00443              {                                                              \
00444               uint32_t ch1 = 0xd800 + ((ch - 0x10000) >> 10);               \
00445               uint32_t ch2 = 0xdc00 + ((ch - 0x10000) & 0x3ff);             \
00446                                                                      \
00447               ch = (ch1 << 16) | ch2;                                       \
00448               switch ((statep->__count >> 3) & 3)                           \
00449                 {                                                    \
00450                 case 1:                                              \
00451                   *outptr++ = base64 (ch >> 26);                     \
00452                   *outptr++ = base64 ((ch >> 20) & 0x3f);                   \
00453                   *outptr++ = base64 ((ch >> 14) & 0x3f);                   \
00454                   *outptr++ = base64 ((ch >> 8) & 0x3f);                    \
00455                   *outptr++ = base64 ((ch >> 2) & 0x3f);                    \
00456                   statep->__count = ((ch & 3) << 7) | (2 << 3);             \
00457                   break;                                             \
00458                 case 2:                                              \
00459                   *outptr++ =                                               \
00460                     base64 (((statep->__count >> 3) & ~3) | (ch >> 28));    \
00461                   *outptr++ = base64 ((ch >> 22) & 0x3f);                   \
00462                   *outptr++ = base64 ((ch >> 16) & 0x3f);                   \
00463                   *outptr++ = base64 ((ch >> 10) & 0x3f);                   \
00464                   *outptr++ = base64 ((ch >> 4) & 0x3f);                    \
00465                   statep->__count = ((ch & 15) << 5) | (3 << 3);            \
00466                   break;                                             \
00467                 case 3:                                              \
00468                   *outptr++ =                                               \
00469                     base64 (((statep->__count >> 3) & ~3) | (ch >> 30));    \
00470                   *outptr++ = base64 ((ch >> 24) & 0x3f);                   \
00471                   *outptr++ = base64 ((ch >> 18) & 0x3f);                   \
00472                   *outptr++ = base64 ((ch >> 12) & 0x3f);                   \
00473                   *outptr++ = base64 ((ch >> 6) & 0x3f);                    \
00474                   *outptr++ = base64 (ch & 0x3f);                           \
00475                   statep->__count = (1 << 3);                               \
00476                   break;                                             \
00477                 default:                                             \
00478                   abort ();                                          \
00479                 }                                                    \
00480              }                                                              \
00481            else                                                      \
00482              abort ();                                                      \
00483          }                                                           \
00484       }                                                                     \
00485                                                                      \
00486     /* Now that we wrote the output increment the input pointer.  */        \
00487     inptr += 4;                                                             \
00488   }
00489 #define LOOP_NEED_FLAGS
00490 #define EXTRA_LOOP_DECLS    , mbstate_t *statep
00491 #include <iconv/loop.c>
00492 
00493 
00494 /* Since this is a stateful encoding we have to provide code which resets
00495    the output state to the initial state.  This has to be done during the
00496    flushing.  */
00497 #define EMIT_SHIFT_TO_INIT \
00498   if (FROM_DIRECTION)                                                       \
00499     /* Nothing to emit.  */                                          \
00500     memset (data->__statep, '\0', sizeof (mbstate_t));                      \
00501   else                                                               \
00502     {                                                                \
00503       /* The "to UTF-7" direction.  Flush the remaining bits and terminate    \
00504         with a '-' byte.  This will guarantee correct decoding if more             \
00505         UTF-7 encoded text is added afterwards.  */                         \
00506       int state = data->__statep->__count;                                  \
00507                                                                      \
00508       if (state & 0x18)                                                     \
00509        {                                                             \
00510          /* Deactivate base64 encoding.  */                                 \
00511          size_t count = ((state & 0x18) >= 0x10) + 1;                       \
00512                                                                      \
00513          if (__builtin_expect (outbuf + count > outend, 0))                 \
00514            /* We don't have enough room in the output buffer.  */           \
00515            status = __GCONV_FULL_OUTPUT;                             \
00516          else                                                        \
00517            {                                                         \
00518              /* Write out the shift sequence.  */                           \
00519              if ((state & 0x18) >= 0x10)                             \
00520               *outbuf++ = base64 ((state >> 3) & ~3);                       \
00521              *outbuf++ = '-';                                               \
00522                                                                      \
00523              data->__statep->__count = 0;                            \
00524            }                                                         \
00525        }                                                             \
00526       else                                                           \
00527        data->__statep->__count = 0;                                         \
00528     }
00529 
00530 
00531 /* Now define the toplevel functions.  */
00532 #include <iconv/skeleton.c>