LCOV - code coverage report
Current view: top level - lib/util/charset - iconv.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 410 514 79.8 %
Date: 2021-09-23 10:06:22 Functions: 17 19 89.5 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    minimal iconv implementation
       4             :    Copyright (C) Andrew Tridgell 2001
       5             :    Copyright (C) Jelmer Vernooij 2002
       6             : 
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include "replace.h"
      22             : #include "system/iconv.h"
      23             : #include "system/filesys.h"
      24             : #include "lib/util/byteorder.h"
      25             : #include "lib/util/dlinklist.h"
      26             : #include "lib/util/charset/charset.h"
      27             : #include "lib/util/charset/charset_proto.h"
      28             : 
      29             : #ifdef HAVE_ICU_I18N
      30             : #include <unicode/ustring.h>
      31             : #include <unicode/utrans.h>
      32             : #endif
      33             : 
      34             : #ifdef strcasecmp
      35             : #undef strcasecmp
      36             : #endif
      37             : 
      38             : /**
      39             :  * @file
      40             :  *
      41             :  * @brief Samba wrapper/stub for iconv character set conversion.
      42             :  *
      43             :  * iconv is the XPG2 interface for converting between character
      44             :  * encodings.  This file provides a Samba wrapper around it, and also
      45             :  * a simple reimplementation that is used if the system does not
      46             :  * implement iconv.
      47             :  *
      48             :  * Samba only works with encodings that are supersets of ASCII: ascii
      49             :  * characters like whitespace can be tested for directly, multibyte
      50             :  * sequences start with a byte with the high bit set, and strings are
      51             :  * terminated by a nul byte.
      52             :  *
      53             :  * Note that the only function provided by iconv is conversion between
      54             :  * characters.  It doesn't directly support operations like
      55             :  * uppercasing or comparison.  We have to convert to UTF-16LE and
      56             :  * compare there.
      57             :  *
      58             :  * @sa Samba Developers Guide
      59             :  **/
      60             : 
      61             : static size_t ascii_pull  (void *,const char **, size_t *, char **, size_t *);
      62             : static size_t ascii_push  (void *,const char **, size_t *, char **, size_t *);
      63             : static size_t latin1_pull(void *,const char **, size_t *, char **, size_t *);
      64             : static size_t latin1_push(void *,const char **, size_t *, char **, size_t *);
      65             : static size_t utf8_pull   (void *,const char **, size_t *, char **, size_t *);
      66             : static size_t utf8_push   (void *,const char **, size_t *, char **, size_t *);
      67             : static size_t utf16_munged_pull(void *,const char **, size_t *, char **, size_t *);
      68             : static size_t ucs2hex_pull(void *,const char **, size_t *, char **, size_t *);
      69             : static size_t ucs2hex_push(void *,const char **, size_t *, char **, size_t *);
      70             : static size_t iconv_copy  (void *,const char **, size_t *, char **, size_t *);
      71             : static size_t iconv_swab  (void *,const char **, size_t *, char **, size_t *);
      72             : 
      73             : static const struct charset_functions builtin_functions[] = {
      74             :         /* windows is closest to UTF-16 */
      75             :         {
      76             :                 .name = "UCS-2LE",
      77             :                 .pull = iconv_copy,
      78             :                 .push = iconv_copy
      79             :         },
      80             :         {
      81             :                 .name = "UTF-16LE",
      82             :                 .pull = iconv_copy,
      83             :                 .push = iconv_copy
      84             :         },
      85             :         {
      86             :                 .name = "UCS-2BE",
      87             :                 .pull = iconv_swab,
      88             :                 .push = iconv_swab
      89             :         },
      90             :         {
      91             :                 .name = "UTF-16BE",
      92             :                 .pull = iconv_swab,
      93             :                 .push = iconv_swab
      94             :         },
      95             : 
      96             :         /* we include the UTF-8 alias to cope with differing locale settings */
      97             :         {
      98             :                 .name = "UTF8",
      99             :                 .pull = utf8_pull,
     100             :                 .push = utf8_push
     101             :         },
     102             :         {
     103             :                 .name = "UTF-8",
     104             :                 .pull = utf8_pull,
     105             :                 .push = utf8_push
     106             :         },
     107             : 
     108             :         /* this handles the munging needed for String2Key */
     109             :         {
     110             :                 .name = "UTF16_MUNGED",
     111             :                 .pull = utf16_munged_pull,
     112             :                 .push = iconv_copy,
     113             :                 .samba_internal_charset = true
     114             :         },
     115             : 
     116             :         {
     117             :                 .name = "ASCII",
     118             :                 .pull = ascii_pull,
     119             :                 .push = ascii_push
     120             :         },
     121             :         {
     122             :                 .name = "646",
     123             :                 .pull = ascii_pull,
     124             :                 .push = ascii_push
     125             :         },
     126             :         {
     127             :                 .name = "ISO-8859-1",
     128             :                 .pull = latin1_pull,
     129             :                 .push = latin1_push
     130             :         },
     131             : #ifdef DEVELOPER
     132             :         {
     133             :                 .name = "WEIRD",
     134             :                 .pull = weird_pull,
     135             :                 .push = weird_push,
     136             :                 .samba_internal_charset = true
     137             :         },
     138             : #endif
     139             : #ifdef DARWINOS
     140             :         {
     141             :                 .name = "MACOSXFS",
     142             :                 .pull = macosxfs_encoding_pull,
     143             :                 .push = macosxfs_encoding_push,
     144             :                 .samba_internal_charset = true
     145             :         },
     146             : #endif
     147             :         {
     148             :                 .name = "UCS2-HEX",
     149             :                 .pull = ucs2hex_pull,
     150             :                 .push = ucs2hex_push,
     151             :                 .samba_internal_charset = true
     152             :         }
     153             : };
     154             : 
     155             : #ifdef HAVE_NATIVE_ICONV
     156             : /* if there was an error then reset the internal state,
     157             :    this ensures that we don't have a shift state remaining for
     158             :    character sets like SJIS */
     159     4742407 : static size_t sys_iconv(void *cd,
     160             :                         const char **inbuf, size_t *inbytesleft,
     161             :                         char **outbuf, size_t *outbytesleft)
     162             : {
     163     4742407 :         size_t ret = iconv((iconv_t)cd,
     164             :                            discard_const_p(char *, inbuf), inbytesleft,
     165             :                            outbuf, outbytesleft);
     166     4742407 :         if (ret == (size_t)-1) iconv(cd, NULL, NULL, NULL, NULL);
     167     4742407 :         return ret;
     168             : }
     169             : #endif
     170             : 
     171             : #ifdef HAVE_ICU_I18N
     172          72 : static size_t sys_uconv(void *cd,
     173             :                         const char **inbuf,
     174             :                         size_t *inbytesleft,
     175             :                         char **outbuf,
     176             :                         size_t *outbytesleft)
     177          72 : {
     178          72 :         UTransliterator *t = (UTransliterator *)cd;
     179          72 :         size_t bufsize = *inbytesleft * 2;
     180          72 :         UChar ustr[bufsize];
     181          72 :         UChar *up = NULL;
     182          72 :         char *p = NULL;
     183             :         int32_t ustrlen;
     184             :         int32_t limit;
     185             :         int32_t converted_len;
     186             :         size_t inbuf_consumed;
     187             :         size_t outbut_consumed;
     188             :         UErrorCode ue;
     189             : 
     190             :         /* Convert from UTF8 to UCS2 */
     191          72 :         ue = 0;
     192          72 :         up = u_strFromUTF8(ustr,           /* dst */
     193             :                            bufsize,        /* dst buflen */
     194             :                            &converted_len, /* dst written */
     195             :                            *inbuf,         /* src */
     196          58 :                            *inbytesleft,   /* src length */
     197             :                            &ue);
     198          72 :         if (up == NULL || U_FAILURE(ue)) {
     199           0 :                 return -1;
     200             :         }
     201          72 :         if (converted_len > bufsize) {
     202             :                 /*
     203             :                  * u_strFromUTF8() returns the required size in
     204             :                  * converted_len. In theory this should never overflow as the
     205             :                  * ustr[] array is allocated with a size twice as big as
     206             :                  * inbytesleft and converted_len should be equal to inbytesleft,
     207             :                  * but you never know...
     208             :                  */
     209           0 :                 errno = EOVERFLOW;
     210           0 :                 return -1;
     211             :         }
     212          72 :         inbuf_consumed = converted_len;
     213             : 
     214             :         /*
     215             :          * The following transliteration function takes two parameters, the
     216             :          * lenght of the text to be converted (converted_len) and a limit which
     217             :          * may be smaller then converted_len. We just set limit to converted_len
     218             :          * and also ignore the value returned in limit.
     219             :          */
     220          72 :         limit = converted_len;
     221             : 
     222             :         /* Inplace transliteration */
     223          72 :         utrans_transUChars(t,
     224             :                            ustr,           /* text */
     225             :                            &converted_len, /* text length */
     226             :                            bufsize,        /* text buflen */
     227             :                            0,              /* start */
     228             :                            &limit,         /* limit */
     229             :                            &ue);
     230          72 :         if (U_FAILURE(ue)) {
     231           0 :                 return -1;
     232             :         }
     233          72 :         if (converted_len > bufsize) {
     234             :                 /*
     235             :                  * In theory this should never happen as the ustr[] array is
     236             :                  * allocated with a size twice as big as inbytesleft and
     237             :                  * converted_len should be equal to inbytesleft, but you never
     238             :                  * know...
     239             :                  */
     240           0 :                 errno = EOVERFLOW;
     241           0 :                 return -1;
     242             :         }
     243          72 :         ustrlen = converted_len;
     244             : 
     245             :         /* Convert from UCS2 back to UTF8 */
     246          72 :         ue = 0;
     247         130 :         p = u_strToUTF8(*outbuf,        /* dst */
     248          72 :                         *outbytesleft,  /* dst buflen */
     249             :                         &converted_len, /* dst required length */
     250             :                         ustr,           /* src */
     251             :                         ustrlen,        /* src length */
     252             :                         &ue);
     253          72 :         if (p == NULL || U_FAILURE(ue)) {
     254           0 :                 return -1;
     255             :         }
     256             : 
     257          66 :         outbut_consumed = converted_len;
     258          66 :         if (converted_len > *outbytesleft) {
     259             :                 /*
     260             :                  * The caller's result buffer is too small...
     261             :                 */
     262           0 :                 outbut_consumed = *outbytesleft;
     263             :         }
     264             : 
     265          66 :         *inbuf += inbuf_consumed;
     266          66 :         *inbytesleft -= inbuf_consumed;
     267          66 :         *outbuf += outbut_consumed;
     268          66 :         *outbytesleft -= outbut_consumed;
     269             : 
     270          66 :         return converted_len;
     271             : }
     272             : #endif
     273             : 
     274             : /**
     275             :  * This is a simple portable iconv() implementaion.
     276             :  *
     277             :  * It only knows about a very small number of character sets - just
     278             :  * enough that Samba works on systems that don't have iconv.
     279             :  **/
     280   207838298 : _PUBLIC_ size_t smb_iconv(smb_iconv_t cd,
     281             :                  const char **inbuf, size_t *inbytesleft,
     282             :                  char **outbuf, size_t *outbytesleft)
     283             : {
     284             :         /* in many cases we can go direct */
     285   207838298 :         if (cd->direct) {
     286    34122538 :                 return cd->direct(cd->cd_direct,
     287             :                                   inbuf, inbytesleft, outbuf, outbytesleft);
     288             :         }
     289             : 
     290             :         /* otherwise we have to do it chunks at a time */
     291             :         {
     292             : #ifndef SMB_ICONV_BUFSIZE
     293             : #define SMB_ICONV_BUFSIZE 2048
     294             : #endif
     295             :                 size_t bufsize;
     296             :                 char cvtbuf[SMB_ICONV_BUFSIZE];
     297             : 
     298   492169433 :                 while (*inbytesleft > 0) {
     299   173860076 :                         char *bufp1 = cvtbuf;
     300   173860076 :                         const char *bufp2 = cvtbuf;
     301   173860076 :                         int saved_errno = errno;
     302   173860076 :                         bool pull_failed = false;
     303   173860076 :                         bufsize = SMB_ICONV_BUFSIZE;
     304             : 
     305   173860076 :                         if (cd->pull(cd->cd_pull,
     306             :                                      inbuf, inbytesleft, &bufp1, &bufsize) == -1
     307      144326 :                             && errno != E2BIG) {
     308          10 :                                 saved_errno = errno;
     309          10 :                                 pull_failed = true;
     310             :                         }
     311             : 
     312   173860076 :                         bufsize = SMB_ICONV_BUFSIZE - bufsize;
     313             : 
     314   173860076 :                         if (cd->push(cd->cd_push,
     315             :                                      &bufp2, &bufsize,
     316             :                                      outbuf, outbytesleft) == -1) {
     317        1008 :                                 return -1;
     318   173859479 :                         } else if (pull_failed) {
     319             :                                 /* We want the pull errno if possible */
     320          10 :                                 errno = saved_errno;
     321          10 :                                 return -1;
     322             :                         }
     323             :                 }
     324             :         }
     325             : 
     326   173715153 :         return 0;
     327             : }
     328             : 
     329     7234402 : static bool is_utf16(const char *name)
     330             : {
     331    14468804 :         return strcasecmp(name, "UCS-2LE") == 0 ||
     332     7234402 :                 strcasecmp(name, "UTF-16LE") == 0;
     333             : }
     334             : 
     335     4206486 : static int smb_iconv_t_destructor(smb_iconv_t hwd)
     336             : {
     337             : #ifdef HAVE_ICU_I18N
     338             :         /*
     339             :          * This has to come first, as the cd_direct member won't be an iconv
     340             :          * handle and must not be passed to iconv_close().
     341             :          */
     342     4206486 :         if (hwd->direct == sys_uconv) {
     343          48 :                 utrans_close(hwd->cd_direct);
     344          48 :                 return 0;
     345             :         }
     346             : #endif
     347             : #ifdef HAVE_NATIVE_ICONV
     348     4206438 :         if (hwd->cd_pull != NULL && hwd->cd_pull != (iconv_t)-1)
     349       22410 :                 iconv_close(hwd->cd_pull);
     350     4206438 :         if (hwd->cd_push != NULL && hwd->cd_push != (iconv_t)-1)
     351        9229 :                 iconv_close(hwd->cd_push);
     352     4206438 :         if (hwd->cd_direct != NULL && hwd->cd_direct != (iconv_t)-1)
     353     1000030 :                 iconv_close(hwd->cd_direct);
     354             : #endif
     355             : 
     356      113146 :         return 0;
     357             : }
     358             : 
     359     4310785 : _PUBLIC_ smb_iconv_t smb_iconv_open_ex(TALLOC_CTX *mem_ctx, const char *tocode, 
     360             :                               const char *fromcode, bool use_builtin_handlers)
     361             : {
     362             :         smb_iconv_t ret;
     363     4310785 :         const struct charset_functions *from=NULL, *to=NULL;
     364             :         int i;
     365             : 
     366     4310785 :         ret = (smb_iconv_t)talloc_named(mem_ctx,
     367             :                                         sizeof(*ret),
     368             :                                         "iconv(%s,%s)", tocode, fromcode);
     369     4310785 :         if (!ret) {
     370           0 :                 errno = ENOMEM;
     371           0 :                 return (smb_iconv_t)-1;
     372             :         }
     373     4310785 :         memset(ret, 0, sizeof(*ret));
     374     4310785 :         talloc_set_destructor(ret, smb_iconv_t_destructor);
     375             : 
     376             :         /* check for the simplest null conversion */
     377     4310785 :         if (strcmp(fromcode, tocode) == 0) {
     378         273 :                 ret->direct = iconv_copy;
     379         273 :                 return ret;
     380             :         }
     381             : 
     382             :         /* check if we have a builtin function for this conversion */
     383    51942160 :         for (i=0;i<ARRAY_SIZE(builtin_functions);i++) {
     384    51726144 :                 if (strcasecmp(fromcode, builtin_functions[i].name) == 0) {
     385     3767446 :                         if (use_builtin_handlers || builtin_functions[i].samba_internal_charset) {
     386     3767418 :                                 from = &builtin_functions[i];
     387             :                         }
     388             :                 }
     389    51726144 :                 if (strcasecmp(tocode, builtin_functions[i].name) == 0) {
     390     3789483 :                         if (use_builtin_handlers || builtin_functions[i].samba_internal_charset) {
     391     3789462 :                                 to = &builtin_functions[i];
     392             :                         }
     393             :                 }
     394             :         }
     395             : 
     396             : #ifdef HAVE_NATIVE_ICONV
     397             :         /* the from and to variables indicate a samba module or
     398             :          * internal conversion, ret->pull and ret->push are
     399             :          * initialised only in this block for iconv based
     400             :          * conversions */
     401             : 
     402     4310512 :         if (from == NULL) {
     403      543094 :                 ret->cd_pull = iconv_open("UTF-16LE", fromcode);
     404      543094 :                 if (ret->cd_pull == (iconv_t)-1)
     405          54 :                         ret->cd_pull = iconv_open("UCS-2LE", fromcode);
     406      543094 :                 if (ret->cd_pull != (iconv_t)-1) {
     407      543040 :                         ret->pull = sys_iconv;
     408             :                 }
     409             :         }
     410             : 
     411     4310512 :         if (to == NULL) {
     412      521050 :                 ret->cd_push = iconv_open(tocode, "UTF-16LE");
     413      521050 :                 if (ret->cd_push == (iconv_t)-1)
     414          54 :                         ret->cd_push = iconv_open(tocode, "UCS-2LE");
     415      521050 :                 if (ret->cd_push != (iconv_t)-1) {
     416      520996 :                         ret->push = sys_iconv;
     417             :                 }
     418             :         }
     419             : #endif
     420             : 
     421             : #ifdef HAVE_ICU_I18N
     422     4310538 :         if (strcasecmp(fromcode, "UTF8-NFD") == 0 &&
     423          26 :             strcasecmp(tocode, "UTF8-NFC") == 0)
     424             :         {
     425             :                 U_STRING_DECL(t, "any-nfc", 7);
     426          26 :                 UErrorCode ue = 0;
     427             : 
     428             :                 U_STRING_INIT(t, "any-nfc", 7);
     429             : 
     430          26 :                 ret->cd_direct = utrans_openU(t,
     431             :                                               strlen("any-nfc"),
     432             :                                               UTRANS_FORWARD,
     433             :                                               NULL,
     434             :                                               0,
     435             :                                               NULL,
     436             :                                               &ue);
     437          26 :                 if (U_FAILURE(ue)) {
     438           0 :                         return (smb_iconv_t)-1;
     439             :                 }
     440          26 :                 ret->direct = sys_uconv;
     441          26 :                 return ret;
     442             :         }
     443             : 
     444     4310514 :         if (strcasecmp(fromcode, "UTF8-NFC") == 0 &&
     445          28 :             strcasecmp(tocode, "UTF8-NFD") == 0)
     446             :         {
     447             :                 U_STRING_DECL(tname, "any-nfd", 7);
     448          28 :                 UErrorCode ue = 0;
     449             : 
     450             :                 U_STRING_INIT(tname, "any-nfd", 7);
     451             : 
     452          28 :                 ret->cd_direct = utrans_openU(tname,
     453             :                                               7,
     454             :                                               UTRANS_FORWARD,
     455             :                                               NULL,
     456             :                                               0,
     457             :                                               NULL,
     458             :                                               &ue);
     459          28 :                 if (U_FAILURE(ue)) {
     460           0 :                         return (smb_iconv_t)-1;
     461             :                 }
     462          28 :                 ret->direct = sys_uconv;
     463          28 :                 return ret;
     464             :         }
     465             : #endif
     466             : 
     467     4310458 :         if (ret->pull == NULL && from == NULL) {
     468           0 :                 goto failed;
     469             :         }
     470             : 
     471     4310458 :         if (ret->push == NULL && to == NULL) {
     472           0 :                 goto failed;
     473             :         }
     474             : 
     475             :         /* check for conversion to/from ucs2 */
     476     4310458 :         if (is_utf16(fromcode) && to) {
     477     1606242 :                 ret->direct = to->push;
     478     1606242 :                 return ret;
     479             :         }
     480     2704216 :         if (is_utf16(tocode) && from) {
     481     1593295 :                 ret->direct = from->pull;
     482     1593295 :                 return ret;
     483             :         }
     484             : 
     485             : #ifdef HAVE_NATIVE_ICONV
     486     1110921 :         if (is_utf16(fromcode)) {
     487      500024 :                 ret->direct = sys_iconv;
     488      500024 :                 ret->cd_direct = ret->cd_push;
     489      500024 :                 ret->cd_push = NULL;
     490      500024 :                 return ret;
     491             :         }
     492      610897 :         if (is_utf16(tocode)) {
     493      500019 :                 ret->direct = sys_iconv;
     494      500019 :                 ret->cd_direct = ret->cd_pull;
     495      500019 :                 ret->cd_pull = NULL;
     496      500019 :                 return ret;
     497             :         }
     498             : #endif
     499             : 
     500             :         /* the general case has to go via a buffer */
     501      110878 :         if (!ret->pull) ret->pull = from->pull;
     502      110878 :         if (!ret->push) ret->push = to->push;
     503      109853 :         return ret;
     504             : 
     505           0 : failed:
     506           0 :         talloc_free(ret);
     507           0 :         errno = EINVAL;
     508           0 :         return (smb_iconv_t)-1;
     509             : }
     510             : 
     511             : /*
     512             :   simple iconv_open() wrapper
     513             :  */
     514           6 : _PUBLIC_ smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode)
     515             : {
     516           6 :         return smb_iconv_open_ex(NULL, tocode, fromcode, true);
     517             : }
     518             : 
     519             : /*
     520             :   simple iconv_close() wrapper
     521             : */
     522     4206436 : _PUBLIC_ int smb_iconv_close(smb_iconv_t cd)
     523             : {
     524     4206436 :         talloc_free(cd);
     525     4206436 :         return 0;
     526             : }
     527             : 
     528             : 
     529             : /**********************************************************************
     530             :  the following functions implement the builtin character sets in Samba
     531             :  and also the "test" character sets that are designed to test
     532             :  multi-byte character set support for english users
     533             : ***********************************************************************/
     534             : 
     535             : /*
     536             :   this takes an ASCII sequence and produces a UTF16 sequence
     537             : 
     538             :   The first 127 codepoints of latin1 matches the first 127 codepoints
     539             :   of unicode, and so can be put into the first byte of UTF16LE
     540             : 
     541             :  */
     542             : 
     543           5 : static size_t ascii_pull(void *cd, const char **inbuf, size_t *inbytesleft,
     544             :                          char **outbuf, size_t *outbytesleft)
     545             : {
     546          31 :         while (*inbytesleft >= 1 && *outbytesleft >= 2) {
     547          25 :                 if (((*inbuf)[0] & 0x7F) != (*inbuf)[0]) {
     548             :                         /* If this is multi-byte, then it isn't legal ASCII */
     549           4 :                         errno = EILSEQ;
     550           4 :                         return -1;
     551             :                 }
     552          21 :                 (*outbuf)[0] = (*inbuf)[0];
     553          21 :                 (*outbuf)[1] = 0;
     554          21 :                 (*inbytesleft)  -= 1;
     555          21 :                 (*outbytesleft) -= 2;
     556          21 :                 (*inbuf)  += 1;
     557          21 :                 (*outbuf) += 2;
     558             :         }
     559             : 
     560           1 :         if (*inbytesleft > 0) {
     561           0 :                 errno = E2BIG;
     562           0 :                 return -1;
     563             :         }
     564             : 
     565           0 :         return 0;
     566             : }
     567             : 
     568             : /*
     569             :   this takes a UTF16 sequence and produces an ASCII sequence
     570             : 
     571             :   The first 127 codepoints of ASCII matches the first 127 codepoints
     572             :   of unicode, and so can be read directly from the first byte of UTF16LE
     573             : 
     574             :  */
     575           4 : static size_t ascii_push(void *cd, const char **inbuf, size_t *inbytesleft,
     576             :                          char **outbuf, size_t *outbytesleft)
     577             : {
     578           4 :         int ir_count=0;
     579             : 
     580           9 :         while (*inbytesleft >= 2 && *outbytesleft >= 1) {
     581           5 :                 if (((*inbuf)[0] & 0x7F) != (*inbuf)[0] ||
     582           1 :                         (*inbuf)[1] != 0) {
     583             :                         /* If this is multi-byte, then it isn't legal ASCII */
     584           3 :                         errno = EILSEQ;
     585           3 :                         return -1;
     586             :                 }
     587           1 :                 (*outbuf)[0] = (*inbuf)[0];
     588           1 :                 (*inbytesleft)  -= 2;
     589           1 :                 (*outbytesleft) -= 1;
     590           1 :                 (*inbuf)  += 2;
     591           1 :                 (*outbuf) += 1;
     592             :         }
     593             : 
     594           1 :         if (*inbytesleft == 1) {
     595           0 :                 errno = EINVAL;
     596           0 :                 return -1;
     597             :         }
     598             : 
     599           1 :         if (*inbytesleft > 1) {
     600           0 :                 errno = E2BIG;
     601           0 :                 return -1;
     602             :         }
     603             : 
     604           0 :         return ir_count;
     605             : }
     606             : 
     607             : /*
     608             :   this takes a latin1/ISO-8859-1 sequence and produces a UTF16 sequence
     609             : 
     610             :   The first 256 codepoints of latin1 matches the first 256 codepoints
     611             :   of unicode, and so can be put into the first byte of UTF16LE
     612             : 
     613             :  */
     614         151 : static size_t latin1_pull(void *cd, const char **inbuf, size_t *inbytesleft,
     615             :                           char **outbuf, size_t *outbytesleft)
     616             : {
     617        3081 :         while (*inbytesleft >= 1 && *outbytesleft >= 2) {
     618        2814 :                 (*outbuf)[0] = (*inbuf)[0];
     619        2814 :                 (*outbuf)[1] = 0;
     620        2814 :                 (*inbytesleft)  -= 1;
     621        2814 :                 (*outbytesleft) -= 2;
     622        2814 :                 (*inbuf)  += 1;
     623        2814 :                 (*outbuf) += 2;
     624             :         }
     625             : 
     626         151 :         if (*inbytesleft > 0) {
     627           2 :                 errno = E2BIG;
     628           2 :                 return -1;
     629             :         }
     630             : 
     631         140 :         return 0;
     632             : }
     633             : 
     634             : /*
     635             :   this takes a UTF16 sequence and produces a latin1/ISO-8859-1 sequence
     636             : 
     637             :   The first 256 codepoints of latin1 matches the first 256 codepoints
     638             :   of unicode, and so can be read directly from the first byte of UTF16LE
     639             : 
     640             :  */
     641         211 : static size_t latin1_push(void *cd, const char **inbuf, size_t *inbytesleft,
     642             :                          char **outbuf, size_t *outbytesleft)
     643             : {
     644         211 :         int ir_count=0;
     645             : 
     646        2453 :         while (*inbytesleft >= 2 && *outbytesleft >= 1) {
     647        2082 :                 (*outbuf)[0] = (*inbuf)[0];
     648        2082 :                 if ((*inbuf)[1] != 0) {
     649             :                         /* If this is multi-byte, then it isn't legal latin1 */
     650           0 :                         errno = EILSEQ;
     651           0 :                         return -1;
     652             :                 }
     653        2082 :                 (*inbytesleft)  -= 2;
     654        2082 :                 (*outbytesleft) -= 1;
     655        2082 :                 (*inbuf)  += 2;
     656        2082 :                 (*outbuf) += 1;
     657             :         }
     658             : 
     659         211 :         if (*inbytesleft == 1) {
     660           0 :                 errno = EINVAL;
     661           0 :                 return -1;
     662             :         }
     663             : 
     664         211 :         if (*inbytesleft > 1) {
     665           1 :                 errno = E2BIG;
     666           1 :                 return -1;
     667             :         }
     668             : 
     669         204 :         return ir_count;
     670             : }
     671             : 
     672           0 : static size_t ucs2hex_pull(void *cd, const char **inbuf, size_t *inbytesleft,
     673             :                          char **outbuf, size_t *outbytesleft)
     674             : {
     675           0 :         while (*inbytesleft >= 1 && *outbytesleft >= 2) {
     676           0 :                 uint8_t hi = 0, lo = 0;
     677             :                 bool ok;
     678             : 
     679           0 :                 if ((*inbuf)[0] != '@') {
     680             :                         /* seven bit ascii case */
     681           0 :                         (*outbuf)[0] = (*inbuf)[0];
     682           0 :                         (*outbuf)[1] = 0;
     683           0 :                         (*inbytesleft)  -= 1;
     684           0 :                         (*outbytesleft) -= 2;
     685           0 :                         (*inbuf)  += 1;
     686           0 :                         (*outbuf) += 2;
     687           0 :                         continue;
     688             :                 }
     689             :                 /* it's a hex character */
     690           0 :                 if (*inbytesleft < 5) {
     691           0 :                         errno = EINVAL;
     692           0 :                         return -1;
     693             :                 }
     694             : 
     695           0 :                 ok = hex_byte(&(*inbuf)[1], &hi) && hex_byte(&(*inbuf)[3], &lo);
     696           0 :                 if (!ok) {
     697           0 :                         errno = EILSEQ;
     698           0 :                         return -1;
     699             :                 }
     700             : 
     701           0 :                 (*outbuf)[0] = lo;
     702           0 :                 (*outbuf)[1] = hi;
     703           0 :                 (*inbytesleft)  -= 5;
     704           0 :                 (*outbytesleft) -= 2;
     705           0 :                 (*inbuf)  += 5;
     706           0 :                 (*outbuf) += 2;
     707             :         }
     708             : 
     709           0 :         if (*inbytesleft > 0) {
     710           0 :                 errno = E2BIG;
     711           0 :                 return -1;
     712             :         }
     713             : 
     714           0 :         return 0;
     715             : }
     716             : 
     717           0 : static size_t ucs2hex_push(void *cd, const char **inbuf, size_t *inbytesleft,
     718             :                            char **outbuf, size_t *outbytesleft)
     719             : {
     720           0 :         while (*inbytesleft >= 2 && *outbytesleft >= 1) {
     721             :                 char buf[6];
     722             : 
     723           0 :                 if ((*inbuf)[1] == 0 &&
     724           0 :                     ((*inbuf)[0] & 0x80) == 0 &&
     725           0 :                     (*inbuf)[0] != '@') {
     726           0 :                         (*outbuf)[0] = (*inbuf)[0];
     727           0 :                         (*inbytesleft)  -= 2;
     728           0 :                         (*outbytesleft) -= 1;
     729           0 :                         (*inbuf)  += 2;
     730           0 :                         (*outbuf) += 1;
     731           0 :                         continue;
     732             :                 }
     733           0 :                 if (*outbytesleft < 5) {
     734           0 :                         errno = E2BIG;
     735           0 :                         return -1;
     736             :                 }
     737           0 :                 snprintf(buf, 6, "@%04x", SVAL(*inbuf, 0));
     738           0 :                 memcpy(*outbuf, buf, 5);
     739           0 :                 (*inbytesleft)  -= 2;
     740           0 :                 (*outbytesleft) -= 5;
     741           0 :                 (*inbuf)  += 2;
     742           0 :                 (*outbuf) += 5;
     743             :         }
     744             : 
     745           0 :         if (*inbytesleft == 1) {
     746           0 :                 errno = EINVAL;
     747           0 :                 return -1;
     748             :         }
     749             : 
     750           0 :         if (*inbytesleft > 1) {
     751           0 :                 errno = E2BIG;
     752           0 :                 return -1;
     753             :         }
     754             : 
     755           0 :         return 0;
     756             : }
     757             : 
     758       69929 : static size_t iconv_swab(void *cd, const char **inbuf, size_t *inbytesleft,
     759             :                          char **outbuf, size_t *outbytesleft)
     760             : {
     761             :         int n;
     762             : 
     763       69929 :         n = MIN(*inbytesleft, *outbytesleft);
     764             : 
     765       69929 :         swab(*inbuf, *outbuf, (n&~1));
     766       69929 :         if (n&1) {
     767           0 :                 (*outbuf)[n-1] = 0;
     768             :         }
     769             : 
     770       69929 :         (*inbytesleft) -= n;
     771       69929 :         (*outbytesleft) -= n;
     772       69929 :         (*inbuf) += n;
     773       69929 :         (*outbuf) += n;
     774             : 
     775       69929 :         if (*inbytesleft > 0) {
     776         182 :                 errno = E2BIG;
     777         182 :                 return -1;
     778             :         }
     779             : 
     780       61995 :         return 0;
     781             : }
     782             : 
     783             : 
     784        4939 : static size_t iconv_copy(void *cd, const char **inbuf, size_t *inbytesleft,
     785             :                          char **outbuf, size_t *outbytesleft)
     786             : {
     787             :         int n;
     788             : 
     789        4939 :         n = MIN(*inbytesleft, *outbytesleft);
     790             : 
     791        4970 :         memmove(*outbuf, *inbuf, n);
     792             : 
     793        4939 :         (*inbytesleft) -= n;
     794        4939 :         (*outbytesleft) -= n;
     795        4939 :         (*inbuf) += n;
     796        4939 :         (*outbuf) += n;
     797             : 
     798        4939 :         if (*inbytesleft > 0) {
     799           0 :                 errno = E2BIG;
     800           0 :                 return -1;
     801             :         }
     802             : 
     803        4908 :         return 0;
     804             : }
     805             : 
     806             : /*
     807             :   this takes a UTF8 sequence and produces a UTF16 sequence
     808             :  */
     809   186988784 : static size_t utf8_pull(void *cd, const char **inbuf, size_t *inbytesleft,
     810             :                          char **outbuf, size_t *outbytesleft)
     811             : {
     812   186988784 :         size_t in_left=*inbytesleft, out_left=*outbytesleft;
     813   186988784 :         const uint8_t *c = (const uint8_t *)*inbuf;
     814   186988784 :         uint8_t *uc = (uint8_t *)*outbuf;
     815             : 
     816  3740196458 :         while (in_left >= 1 && out_left >= 2) {
     817  3396492060 :                 if ((c[0] & 0x80) == 0) {
     818  3380154879 :                         uc[0] = c[0];
     819  3380154879 :                         uc[1] = 0;
     820  3380154879 :                         c  += 1;
     821  3380154879 :                         in_left  -= 1;
     822  3380154879 :                         out_left -= 2;
     823  3380154879 :                         uc += 2;
     824  3380154879 :                         continue;
     825             :                 }
     826             : 
     827    16337181 :                 if ((c[0] & 0xe0) == 0xc0) {
     828    12093608 :                         if (in_left < 2 ||
     829     6398760 :                             (c[1] & 0xc0) != 0x80) {
     830         122 :                                 errno = EILSEQ;
     831         122 :                                 goto error;
     832             :                         }
     833     6398640 :                         uc[1] = (c[0]>>2) & 0x7;
     834     6398640 :                         uc[0] = (c[0]<<6) | (c[1]&0x3f);
     835     6398640 :                         if (uc[1] == 0 && uc[0] < 0x80) {
     836             :                                 /* this should have been a single byte */
     837           1 :                                 errno = EILSEQ;
     838           1 :                                 goto error;
     839             :                         }
     840     6398639 :                         c  += 2;
     841     6398639 :                         in_left  -= 2;
     842     6398639 :                         out_left -= 2;
     843     6398639 :                         uc += 2;
     844     6398639 :                         continue;
     845             :                 }
     846             : 
     847     9938419 :                 if ((c[0] & 0xf0) == 0xe0) {
     848             :                         unsigned int codepoint;
     849    13415691 :                         if (in_left < 3 ||
     850    13415523 :                             (c[1] & 0xc0) != 0x80 ||
     851     6981197 :                             (c[2] & 0xc0) != 0x80) {
     852         186 :                                 errno = EILSEQ;
     853         186 :                                 goto error;
     854             :                         }
     855    19849485 :                         codepoint = ((c[2] & 0x3f)        |
     856    13415341 :                                      ((c[1] & 0x3f) << 6) |
     857     6981197 :                                      ((c[0] & 0x0f) << 12));
     858             : 
     859     6981197 :                         if (codepoint < 0x800) {
     860             :                                 /* this should be a 1 or 2 byte sequence */
     861           1 :                                 errno = EILSEQ;
     862           1 :                                 goto error;
     863             :                         }
     864     6981196 :                         uc[0] = codepoint & 0xff;
     865     6981196 :                         uc[1] = codepoint >> 8;
     866     6981196 :                         c  += 3;
     867     6981196 :                         in_left  -= 3;
     868     6981196 :                         out_left -= 2;
     869     6981196 :                         uc += 2;
     870     6981196 :                         continue;
     871             :                 }
     872             : 
     873     2957036 :                 if ((c[0] & 0xf8) == 0xf0) {
     874             :                         unsigned int codepoint;
     875     5913167 :                         if (in_left < 4 ||
     876     5913167 :                             (c[1] & 0xc0) != 0x80 ||
     877     5913167 :                             (c[2] & 0xc0) != 0x80 ||
     878     2956594 :                             (c[3] & 0xc0) != 0x80) {
     879           0 :                                 errno = EILSEQ;
     880           0 :                                 goto error;
     881             :                         }
     882     2956594 :                         codepoint =
     883     5913167 :                                 (c[3]&0x3f) |
     884     5913167 :                                 ((c[2]&0x3f)<<6) |
     885     5913167 :                                 ((c[1]&0x3f)<<12) |
     886     2956594 :                                 ((c[0]&0x7)<<18);
     887     2956594 :                         if (codepoint < 0x10000) {
     888             :                                 /* reject UTF-8 characters that are not
     889             :                                    minimally packed */
     890           1 :                                 errno = EILSEQ;
     891           1 :                                 goto error;
     892             :                         }
     893             : 
     894     2956593 :                         codepoint -= 0x10000;
     895             : 
     896     2956593 :                         if (out_left < 4) {
     897      983059 :                                 errno = E2BIG;
     898      983059 :                                 goto error;
     899             :                         }
     900             : 
     901     1973534 :                         uc[0] = (codepoint>>10) & 0xFF;
     902     1973534 :                         uc[1] = (codepoint>>18) | 0xd8;
     903     1973534 :                         uc[2] = codepoint & 0xFF;
     904     1973534 :                         uc[3] = ((codepoint>>8) & 0x3) | 0xdc;
     905     1973534 :                         c  += 4;
     906     1973534 :                         in_left  -= 4;
     907     1973534 :                         out_left -= 4;
     908     1973534 :                         uc += 4;
     909     1973534 :                         continue;
     910             :                 }
     911             : 
     912             :                 /* we don't handle 5 byte sequences */
     913         442 :                 errno = EINVAL;
     914         442 :                 goto error;
     915             :         }
     916             : 
     917   186004972 :         if (in_left > 0) {
     918     2087440 :                 errno = E2BIG;
     919     2087440 :                 goto error;
     920             :         }
     921             : 
     922   183917532 :         *inbytesleft = in_left;
     923   183917532 :         *outbytesleft = out_left;
     924   183917532 :         *inbuf = (const char *)c;
     925   183917532 :         *outbuf = (char *)uc;
     926   183917532 :         return 0;
     927             : 
     928     3071252 : error:
     929     3071252 :         *inbytesleft = in_left;
     930     3071252 :         *outbytesleft = out_left;
     931     3071252 :         *inbuf = (const char *)c;
     932     3071252 :         *outbuf = (char *)uc;
     933     3071252 :         return -1;
     934             : }
     935             : 
     936             : 
     937             : /*
     938             :   this takes a UTF16 sequence and produces a UTF8 sequence
     939             :  */
     940   190022567 : static size_t utf8_push(void *cd, const char **inbuf, size_t *inbytesleft,
     941             :                         char **outbuf, size_t *outbytesleft)
     942             : {
     943   190022567 :         size_t in_left=*inbytesleft, out_left=*outbytesleft;
     944   190022567 :         uint8_t *c = (uint8_t *)*outbuf;
     945   190022567 :         const uint8_t *uc = (const uint8_t *)*inbuf;
     946             : 
     947  4444718089 :         while (in_left >= 2 && out_left >= 1) {
     948             :                 unsigned int codepoint;
     949             : 
     950  4094039619 :                 if (uc[1] == 0 && !(uc[0] & 0x80)) {
     951             :                         /* simplest case */
     952  4081798209 :                         c[0] = uc[0];
     953  4081798209 :                         in_left  -= 2;
     954  4081798209 :                         out_left -= 1;
     955  4081798209 :                         uc += 2;
     956  4081798209 :                         c  += 1;
     957  4081798209 :                         continue;
     958             :                 }
     959             : 
     960    12241410 :                 if ((uc[1]&0xf8) == 0) {
     961             :                         /* next simplest case */
     962     3988291 :                         if (out_left < 2) {
     963           4 :                                 errno = E2BIG;
     964           4 :                                 goto error;
     965             :                         }
     966     3988287 :                         c[0] = 0xc0 | (uc[0]>>6) | (uc[1]<<2);
     967     3988287 :                         c[1] = 0x80 | (uc[0] & 0x3f);
     968     3988287 :                         in_left  -= 2;
     969     3988287 :                         out_left -= 2;
     970     3988287 :                         uc += 2;
     971     3988287 :                         c  += 2;
     972     3988287 :                         continue;
     973             :                 }
     974             : 
     975     8253119 :                 if ((uc[1] & 0xfc) == 0xdc) {
     976      305631 :                         errno = EILSEQ;
     977             : #ifndef HAVE_ICONV_ERRNO_ILLEGAL_MULTIBYTE
     978             :                         if (in_left < 4) {
     979             :                                 errno = EINVAL;
     980             :                         }
     981             : #endif
     982      305631 :                         goto error;
     983             :                 }
     984             : 
     985     7947488 :                 if ((uc[1] & 0xfc) != 0xd8) {
     986     5878362 :                         codepoint = uc[0] | (uc[1]<<8);
     987     5878362 :                         if (out_left < 3) {
     988           3 :                                 errno = E2BIG;
     989           3 :                                 goto error;
     990             :                         }
     991     5878359 :                         c[0] = 0xe0 | (codepoint >> 12);
     992     5878359 :                         c[1] = 0x80 | ((codepoint >> 6) & 0x3f);
     993     5878359 :                         c[2] = 0x80 | (codepoint & 0x3f);
     994             : 
     995     5878359 :                         in_left  -= 2;
     996     5878359 :                         out_left -= 3;
     997     5878359 :                         uc  += 2;
     998     5878359 :                         c   += 3;
     999     5878359 :                         continue;
    1000             :                 }
    1001             : 
    1002             :                 /* its the first part of a 4 byte sequence */
    1003     2069126 :                 if (in_left < 4) {
    1004        3537 :                         errno = EINVAL;
    1005        3537 :                         goto error;
    1006             :                 }
    1007     2065589 :                 if ((uc[3] & 0xfc) != 0xdc) {
    1008       92055 :                         errno = EILSEQ;
    1009       92055 :                         goto error;
    1010             :                 }
    1011     5920574 :                 codepoint = 0x10000 + (uc[2] | ((uc[3] & 0x3)<<8) |
    1012     3947054 :                                        (uc[0]<<10) | ((uc[1] & 0x3)<<18));
    1013             : 
    1014     1973534 :                 if (out_left < 4) {
    1015           0 :                         errno = E2BIG;
    1016           0 :                         goto error;
    1017             :                 }
    1018     1973534 :                 c[0] = 0xf0 | (codepoint >> 18);
    1019     1973534 :                 c[1] = 0x80 | ((codepoint >> 12) & 0x3f);
    1020     1973534 :                 c[2] = 0x80 | ((codepoint >> 6) & 0x3f);
    1021     1973534 :                 c[3] = 0x80 | (codepoint & 0x3f);
    1022             : 
    1023     1973534 :                 in_left  -= 4;
    1024     1973534 :                 out_left -= 4;
    1025     1973534 :                 uc       += 4;
    1026     1973534 :                 c        += 4;
    1027             :         }
    1028             : 
    1029   189621337 :         if (in_left == 1) {
    1030       50487 :                 errno = EINVAL;
    1031       50487 :                 goto error;
    1032             :         }
    1033             : 
    1034   189570850 :         if (in_left > 1) {
    1035          15 :                 errno = E2BIG;
    1036          15 :                 goto error;
    1037             :         }
    1038             : 
    1039   189570835 :         *inbytesleft = in_left;
    1040   189570835 :         *outbytesleft = out_left;
    1041   189570835 :         *inbuf  = (const char *)uc;
    1042   189570835 :         *outbuf = (char *)c;
    1043             : 
    1044   189570835 :         return 0;
    1045             : 
    1046      451732 : error:
    1047      451732 :         *inbytesleft = in_left;
    1048      451732 :         *outbytesleft = out_left;
    1049      451732 :         *inbuf  = (const char *)uc;
    1050      451732 :         *outbuf = (char *)c;
    1051      451732 :         return -1;
    1052             : }
    1053             : 
    1054             : 
    1055             : /*
    1056             :   this takes a UTF16 munged sequence, modifies it according to the
    1057             :   string2key rules, and produces a UTF16 sequence
    1058             : 
    1059             : The rules are:
    1060             : 
    1061             :     1) any 0x0000 characters are mapped to 0x0001
    1062             : 
    1063             :     2) convert any instance of 0xD800 - 0xDBFF (high surrogate)
    1064             :        without an immediately following 0xDC00 - 0x0xDFFF (low surrogate) to
    1065             :        U+FFFD (OBJECT REPLACEMENT CHARACTER).
    1066             : 
    1067             :     3) the same for any low surrogate that was not preceded by a high surrogate.
    1068             : 
    1069             :  */
    1070       13621 : static size_t utf16_munged_pull(void *cd, const char **inbuf, size_t *inbytesleft,
    1071             :                                char **outbuf, size_t *outbytesleft)
    1072             : {
    1073       13621 :         size_t in_left=*inbytesleft, out_left=*outbytesleft;
    1074       13621 :         uint8_t *c = (uint8_t *)*outbuf;
    1075       13621 :         const uint8_t *uc = (const uint8_t *)*inbuf;
    1076             : 
    1077      514411 :         while (in_left >= 2 && out_left >= 2) {
    1078      491979 :                 unsigned int codepoint = uc[0] | (uc[1]<<8);
    1079             : 
    1080      491979 :                 if (codepoint == 0) {
    1081           4 :                         codepoint = 1;
    1082             :                 }
    1083             : 
    1084      491979 :                 if ((codepoint & 0xfc00) == 0xd800) {
    1085             :                         /* a high surrogate */
    1086             :                         unsigned int codepoint2;
    1087         937 :                         if (in_left < 4) {
    1088           4 :                                 codepoint = 0xfffd;
    1089           4 :                                 goto codepoint16;
    1090             :                         }
    1091         933 :                         codepoint2 = uc[2] | (uc[3]<<8);
    1092         933 :                         if ((codepoint2 & 0xfc00) != 0xdc00) {
    1093             :                                 /* high surrogate not followed by low
    1094             :                                    surrogate: convert to 0xfffd */
    1095         812 :                                 codepoint = 0xfffd;
    1096         812 :                                 goto codepoint16;
    1097             :                         }
    1098          19 :                         if (out_left < 4) {
    1099           0 :                                 errno = E2BIG;
    1100           0 :                                 goto error;
    1101             :                         }
    1102          19 :                         memcpy(c, uc, 4);
    1103          19 :                         in_left  -= 4;
    1104          19 :                         out_left -= 4;
    1105          19 :                         uc       += 4;
    1106          19 :                         c        += 4;
    1107          19 :                         continue;
    1108             :                 }
    1109             : 
    1110      491042 :                 if ((codepoint & 0xfc00) == 0xdc00) {
    1111             :                         /* low surrogate not preceded by high
    1112             :                            surrogate: convert to 0xfffd */
    1113         975 :                         codepoint = 0xfffd;
    1114             :                 }
    1115             : 
    1116      854184 :         codepoint16:
    1117      491960 :                 c[0] = codepoint & 0xFF;
    1118      491960 :                 c[1] = (codepoint>>8) & 0xFF;
    1119             : 
    1120      491960 :                 in_left  -= 2;
    1121      491960 :                 out_left -= 2;
    1122      491960 :                 uc  += 2;
    1123      491960 :                 c   += 2;
    1124      491960 :                 continue;
    1125             :         }
    1126             : 
    1127       13621 :         if (in_left == 1) {
    1128           0 :                 errno = EINVAL;
    1129           0 :                 goto error;
    1130             :         }
    1131             : 
    1132       13621 :         if (in_left > 1) {
    1133           0 :                 errno = E2BIG;
    1134           0 :                 goto error;
    1135             :         }
    1136             : 
    1137       13621 :         *inbytesleft = in_left;
    1138       13621 :         *outbytesleft = out_left;
    1139       13621 :         *inbuf  = (const char *)uc;
    1140       13621 :         *outbuf = (char *)c;
    1141             : 
    1142       13621 :         return 0;
    1143             : 
    1144           0 : error:
    1145           0 :         *inbytesleft = in_left;
    1146           0 :         *outbytesleft = out_left;
    1147           0 :         *inbuf  = (const char *)uc;
    1148           0 :         *outbuf = (char *)c;
    1149           0 :         return -1;
    1150             : }
    1151             : 
    1152             : 
    1153             : 

Generated by: LCOV version 1.13