iconv sync 10/x: FreeBSD SVN 258316 + 283406 + 283418
authorJohn Marino <draco@marino.st>
Sat, 4 Jul 2015 07:15:01 +0000 (09:15 +0200)
committerJohn Marino <draco@marino.st>
Sat, 4 Jul 2015 08:19:06 +0000 (10:19 +0200)
SVN 258316: Bug fixes in iconv(3) UTF-7 support.

- Add ' to the list of directly encoded characters and * to the list of
  optionally directly encoded characters as per RFC 2152.

- In _citrus_UTF7_mbtoutf16 on end of input when the next output character
  has only been partially decoded, save a copy of the buffer of input
  characters (not just its length).  On the next call with more input
  characters this buffer is reprocessed together with the new input to
  form a fully decoded output character.

- At the end of a base64 encoded sequence fully discard '-' (BASE64_OUT)
  by decrementing psenc->chlen and i.  This is needed to make room in
  psenc->ch (input buffer) in case the next input character starts a new
  base64 encoded sequence.  And also, if this is the end of input and no
  output character can be returned, this brings the encoder in the initial
  state as indicated by _citrus_UTF7_stdenc_get_state_desc_generic which
  is used by the caller to distinguish between no output and partial
  output.

- In _citrus_UTF7_mbrtowc_priv pass the s parameter (input pointer)
  directly to _citrus_UTF7_mbtoutf16 instead of a copy (s0).  This way s
  is updated correctly in case of errors.

- In _citrus_UTF7_mbrtowc_priv when called with psenc->surrogate set
  (previous call did not have enough input), retrieve the previously
  decoded UTF-16 character fr

SVN 283406: Fix decoding of UTF-7 when a base64 encoded chunk appears at
            the end of the input buffer.

_citrus_UTF7_mbtoutf16 stored the decoder state at the beginning so it
could restore this state on an incomplete character such that the next
call would restart the decoding.  The problem was that "-" (end of base64
mode) at the end of a string was also treated as an incomplete character
but was also removed from the state buffer.  So the initial state would be
restored (with base64 mode) and the next call would no longer see the "-"
so it continued in base64 mode.

This state saving/restoring isn't needed here.  It's already handled
elsewhere (citrus_iconv_std.c:_citrus_iconv_std_iconv_convert) so just
remove it.

Also initialise *nresult.

SVN 283418: (continued)

When only 2 bytes can be read from a 4 byte UTF-16 character in a base64
encoded chunk of a UTF-7 string, treat that as an incomplete character and
return an error instead of a shift sequence and no error.

Also check that the low 2 bytes have a valid value.

lib/i18n_module/UTF7/citrus_utf7.c

index 8929426..c82da3b 100644 (file)
@@ -1,4 +1,4 @@
-/* $FreeBSD: head/lib/libiconv_modules/UTF7/citrus_utf7.c 252583 2013-07-03 18:27:45Z peter $ */
+/* $FreeBSD: head/lib/libiconv_modules/UTF7/citrus_utf7.c 283418 2015-05-24 15:47:06Z tijl $ */
 /*     $NetBSD: citrus_utf7.c,v 1.5 2006/08/23 12:57:24 tnozaki Exp $  */
 
 /*-
@@ -62,8 +62,7 @@ typedef struct {
        unsigned int
                mode: 1,        /* whether base64 mode */
                bits: 4,        /* need to hold 0 - 15 */
-               cache: 22,      /* 22 = BASE64_BIT + UTF16_BIT */
-               surrogate: 1;   /* whether surrogate pair or not */
+               cache: 22;      /* 22 = BASE64_BIT + UTF16_BIT */
        int chlen;
        char ch[4]; /* BASE64_IN, 3 * 6 = 18, most closed to UTF16_BIT */
 } _UTF7State;
@@ -115,9 +114,9 @@ static const char base64[] =
 static const char direct[] =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz"
-       "0123456789(),-./:?";
+       "0123456789'(),-./:?";
 
-static const char option[] = "!\"#$%&';<=>@[]^_`{|}";
+static const char option[] = "!\"#$%&*;<=>@[]^_`{|}";
 static const char spaces[] = " \t\r\n";
 
 #define        BASE64_BIT      6
@@ -154,20 +153,17 @@ _citrus_UTF7_mbtoutf16(_UTF7EncodingInfo * __restrict ei,
     uint16_t * __restrict u16, char ** __restrict s, size_t n,
     _UTF7State * __restrict psenc, size_t * __restrict nresult)
 {
-       _UTF7State sv;
        char *s0;
        int done, i, len;
 
+       *nresult = 0;
        s0 = *s;
-       sv = *psenc;
 
        for (i = 0, done = 0; done == 0; i++) {
                if (i == psenc->chlen) {
                        if (n-- < 1) {
                                *nresult = (size_t)-2;
                                *s = s0;
-                               sv.chlen = psenc->chlen;
-                               *psenc = sv;
                                return (0);
                        }
                        psenc->ch[psenc->chlen++] = *s0++;
@@ -204,6 +200,9 @@ _citrus_UTF7_mbtoutf16(_UTF7EncodingInfo * __restrict ei,
                                                goto ilseq;
                                        *u16 = (uint16_t)psenc->ch[i];
                                        done = 1;
+                               } else {
+                                       psenc->chlen--;
+                                       i--;
                                }
                        } else {
                                psenc->cache =
@@ -243,7 +242,6 @@ _citrus_UTF7_mbrtowc_priv(_UTF7EncodingInfo * __restrict ei,
     wchar_t * __restrict pwc, char ** __restrict s, size_t n,
     _UTF7State * __restrict psenc, size_t * __restrict nresult)
 {
-       char *s0;
        uint32_t u32;
        uint16_t hi, lo;
        size_t nr, siz;
@@ -254,41 +252,36 @@ _citrus_UTF7_mbrtowc_priv(_UTF7EncodingInfo * __restrict ei,
                *nresult = (size_t)_ENCODING_IS_STATE_DEPENDENT;
                return (0);
        }
-       s0 = *s;
-       if (psenc->surrogate) {
-               hi = (psenc->cache >> 2) & UTF16_MAX;
-               if (hi < HISRG_MIN || hi > HISRG_MAX)
-                       return (EINVAL);
-               siz = 0;
-       } else {
-               err = _citrus_UTF7_mbtoutf16(ei, &hi, &s0, n, psenc, &nr);
-               if (nr == (size_t)-1 || nr == (size_t)-2) {
-                       *nresult = nr;
-                       return (err);
-               }
-               if (err != 0)
-                       return (err);
-               n -= nr;
-               siz = nr;
-               if (hi < HISRG_MIN || hi > HISRG_MAX) {
-                       u32 = (uint32_t)hi;
-                       goto done;
-               }
-               psenc->surrogate = 1;
+       err = _citrus_UTF7_mbtoutf16(ei, &hi, s, n, psenc, &nr);
+       if (nr == (size_t)-1 || nr == (size_t)-2) {
+               *nresult = nr;
+               return (err);
        }
-       err = _citrus_UTF7_mbtoutf16(ei, &lo, &s0, n, psenc, &nr);
+       if (err != 0)
+               return (err);
+       n -= nr;
+       siz = nr;
+       if (hi < HISRG_MIN || hi > HISRG_MAX) {
+               u32 = (uint32_t)hi;
+               goto done;
+       }
+       err = _citrus_UTF7_mbtoutf16(ei, &lo, s, n, psenc, &nr);
        if (nr == (size_t)-1 || nr == (size_t)-2) {
+               psenc->chlen = 1; /* make get_state_desc return incomplete */
                *nresult = nr;
                return (err);
        }
        if (err != 0)
                return (err);
+       if (lo < LOSRG_MIN || lo > LOSRG_MAX) {
+               *nresult = (size_t)-1;
+               return (EILSEQ);
+       }
        hi -= HISRG_MIN;
        lo -= LOSRG_MIN;
        u32 = (hi << 10 | lo) + SRG_BASE;
        siz += nr;
 done:
-       *s = s0;
        if (pwc != NULL)
                *pwc = (wchar_t)u32;
        if (u32 == (uint32_t)0) {
@@ -296,7 +289,6 @@ done:
                _citrus_UTF7_init_state(ei, psenc);
        } else {
                *nresult = siz;
-               psenc->surrogate = 0;
        }
        return (err);
 }
@@ -395,7 +387,7 @@ _citrus_UTF7_put_state_reset(_UTF7EncodingInfo * __restrict ei __unused,
 {
        int bits, pos;
 
-       if (psenc->chlen != 0 || psenc->bits > BASE64_BIT || psenc->surrogate)
+       if (psenc->chlen != 0 || psenc->bits > BASE64_BIT)
                return (EINVAL);
 
        if (psenc->mode) {