LCOV - code coverage report
Current view: top level - lib/util/charset - iconv.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 282 514 54.9 %
Date: 2024-06-13 04:01:37 Functions: 11 19 57.9 %

          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     1208962 : static size_t sys_iconv(void *cd,
     160             :                         const char **inbuf, size_t *inbytesleft,
     161             :                         char **outbuf, size_t *outbytesleft)
     162             : {
     163     1208962 :         size_t ret = iconv((iconv_t)cd,
     164             :                            discard_const_p(char *, inbuf), inbytesleft,
     165             :                            outbuf, outbytesleft);
     166     1208962 :         if (ret == (size_t)-1) iconv(cd, NULL, NULL, NULL, NULL);
     167     1208962 :         return ret;
     168             : }
     169             : #endif
     170             : 
     171             : #ifdef HAVE_ICU_I18N
     172           0 : static size_t sys_uconv(void *cd,
     173             :                         const char **inbuf,
     174             :                         size_t *inbytesleft,
     175             :                         char **outbuf,
     176             :                         size_t *outbytesleft)
     177           0 : {
     178           0 :         UTransliterator *t = (UTransliterator *)cd;
     179           0 :         size_t bufsize = *inbytesleft * 2;
     180           0 :         UChar ustr[bufsize];
     181           0 :         UChar *up = NULL;
     182           0 :         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           0 :         ue = 0;
     192           0 :         up = u_strFromUTF8(ustr,           /* dst */
     193             :                            bufsize,        /* dst buflen */
     194             :                            &converted_len, /* dst written */
     195             :                            *inbuf,         /* src */
     196           0 :                            *inbytesleft,   /* src length */
     197             :                            &ue);
     198           0 :         if (up == NULL || U_FAILURE(ue)) {
     199           0 :                 return -1;
     200             :         }
     201           0 :         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           0 :         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           0 :         limit = converted_len;
     221             : 
     222             :         /* Inplace transliteration */
     223           0 :         utrans_transUChars(t,
     224             :                            ustr,           /* text */
     225             :                            &converted_len, /* text length */
     226             :                            bufsize,        /* text buflen */
     227             :                            0,              /* start */
     228             :                            &limit,         /* limit */
     229             :                            &ue);
     230           0 :         if (U_FAILURE(ue)) {
     231           0 :                 return -1;
     232             :         }
     233           0 :         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           0 :         ustrlen = converted_len;
     244             : 
     245             :         /* Convert from UCS2 back to UTF8 */
     246           0 :         ue = 0;
     247           0 :         p = u_strToUTF8(*outbuf,        /* dst */
     248           0 :                         *outbytesleft,  /* dst buflen */
     249             :                         &converted_len, /* dst required length */
     250             :                         ustr,           /* src */
     251             :                         ustrlen,        /* src length */
     252             :                         &ue);
     253           0 :         if (p == NULL || U_FAILURE(ue)) {
     254           0 :                 return -1;
     255             :         }
     256             : 
     257           0 :         outbut_consumed = converted_len;
     258           0 :         if (converted_len > *outbytesleft) {
     259             :                 /*
     260             :                  * The caller's result buffer is too small...
     261             :                 */
     262           0 :                 outbut_consumed = *outbytesleft;
     263             :         }
     264             : 
     265           0 :         *inbuf += inbuf_consumed;
     266           0 :         *inbytesleft -= inbuf_consumed;
     267           0 :         *outbuf += outbut_consumed;
     268           0 :         *outbytesleft -= outbut_consumed;
     269             : 
     270           0 :         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    21306752 : _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    21306752 :         if (cd->direct) {
     286    18158316 :                 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     9251588 :                 while (*inbytesleft > 0) {
     299     3234992 :                         char *bufp1 = cvtbuf;
     300     3234992 :                         const char *bufp2 = cvtbuf;
     301     3234992 :                         int saved_errno = errno;
     302     3234992 :                         bool pull_failed = false;
     303     3234992 :                         bufsize = SMB_ICONV_BUFSIZE;
     304             : 
     305     3234992 :                         if (cd->pull(cd->cd_pull,
     306             :                                      inbuf, inbytesleft, &bufp1, &bufsize) == -1
     307       86556 :                             && errno != E2BIG) {
     308           0 :                                 saved_errno = errno;
     309           0 :                                 pull_failed = true;
     310             :                         }
     311             : 
     312     3234992 :                         bufsize = SMB_ICONV_BUFSIZE - bufsize;
     313             : 
     314     3234992 :                         if (cd->push(cd->cd_push,
     315             :                                      &bufp2, &bufsize,
     316             :                                      outbuf, outbytesleft) == -1) {
     317           8 :                                 return -1;
     318     3234988 :                         } else if (pull_failed) {
     319             :                                 /* We want the pull errno if possible */
     320           0 :                                 errno = saved_errno;
     321           0 :                                 return -1;
     322             :                         }
     323             :                 }
     324             :         }
     325             : 
     326     3148432 :         return 0;
     327             : }
     328             : 
     329      171006 : static bool is_utf16(const char *name)
     330             : {
     331      342012 :         return strcasecmp(name, "UCS-2LE") == 0 ||
     332      171006 :                 strcasecmp(name, "UTF-16LE") == 0;
     333             : }
     334             : 
     335       42474 : 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       42474 :         if (hwd->direct == sys_uconv) {
     343           0 :                 utrans_close(hwd->cd_direct);
     344           0 :                 return 0;
     345             :         }
     346             : #endif
     347             : #ifdef HAVE_NATIVE_ICONV
     348       42474 :         if (hwd->cd_pull != NULL && hwd->cd_pull != (iconv_t)-1)
     349        5076 :                 iconv_close(hwd->cd_pull);
     350       42474 :         if (hwd->cd_push != NULL && hwd->cd_push != (iconv_t)-1)
     351        1129 :                 iconv_close(hwd->cd_push);
     352       42474 :         if (hwd->cd_direct != NULL && hwd->cd_direct != (iconv_t)-1)
     353           0 :                 iconv_close(hwd->cd_direct);
     354             : #endif
     355             : 
     356       42474 :         return 0;
     357             : }
     358             : 
     359       69410 : _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       69410 :         const struct charset_functions *from=NULL, *to=NULL;
     364             :         int i;
     365             : 
     366       69410 :         ret = (smb_iconv_t)talloc_named(mem_ctx,
     367             :                                         sizeof(*ret),
     368             :                                         "iconv(%s,%s)", tocode, fromcode);
     369       69410 :         if (!ret) {
     370           0 :                 errno = ENOMEM;
     371           0 :                 return (smb_iconv_t)-1;
     372             :         }
     373       69410 :         memset(ret, 0, sizeof(*ret));
     374       69410 :         talloc_set_destructor(ret, smb_iconv_t_destructor);
     375             : 
     376             :         /* check for the simplest null conversion */
     377       69410 :         if (strcmp(fromcode, tocode) == 0) {
     378         234 :                 ret->direct = iconv_copy;
     379         234 :                 return ret;
     380             :         }
     381             : 
     382             :         /* check if we have a builtin function for this conversion */
     383      899288 :         for (i=0;i<ARRAY_SIZE(builtin_functions);i++) {
     384      830112 :                 if (strcasecmp(fromcode, builtin_functions[i].name) == 0) {
     385       57959 :                         if (use_builtin_handlers || builtin_functions[i].samba_internal_charset) {
     386       57959 :                                 from = &builtin_functions[i];
     387             :                         }
     388             :                 }
     389      830112 :                 if (strcasecmp(tocode, builtin_functions[i].name) == 0) {
     390       66205 :                         if (use_builtin_handlers || builtin_functions[i].samba_internal_charset) {
     391       66205 :                                 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       69176 :         if (from == NULL) {
     403       11217 :                 ret->cd_pull = iconv_open("UTF-16LE", fromcode);
     404       11217 :                 if (ret->cd_pull == (iconv_t)-1)
     405           0 :                         ret->cd_pull = iconv_open("UCS-2LE", fromcode);
     406       11217 :                 if (ret->cd_pull != (iconv_t)-1) {
     407       11217 :                         ret->pull = sys_iconv;
     408             :                 }
     409             :         }
     410             : 
     411       69176 :         if (to == NULL) {
     412        2971 :                 ret->cd_push = iconv_open(tocode, "UTF-16LE");
     413        2971 :                 if (ret->cd_push == (iconv_t)-1)
     414           0 :                         ret->cd_push = iconv_open(tocode, "UCS-2LE");
     415        2971 :                 if (ret->cd_push != (iconv_t)-1) {
     416        2971 :                         ret->push = sys_iconv;
     417             :                 }
     418             :         }
     419             : #endif
     420             : 
     421             : #ifdef HAVE_ICU_I18N
     422       69176 :         if (strcasecmp(fromcode, "UTF8-NFD") == 0 &&
     423           0 :             strcasecmp(tocode, "UTF8-NFC") == 0)
     424             :         {
     425             :                 U_STRING_DECL(t, "any-nfc", 7);
     426           0 :                 UErrorCode ue = 0;
     427             : 
     428             :                 U_STRING_INIT(t, "any-nfc", 7);
     429             : 
     430           0 :                 ret->cd_direct = utrans_openU(t,
     431             :                                               strlen("any-nfc"),
     432             :                                               UTRANS_FORWARD,
     433             :                                               NULL,
     434             :                                               0,
     435             :                                               NULL,
     436             :                                               &ue);
     437           0 :                 if (U_FAILURE(ue)) {
     438           0 :                         return (smb_iconv_t)-1;
     439             :                 }
     440           0 :                 ret->direct = sys_uconv;
     441           0 :                 return ret;
     442             :         }
     443             : 
     444       69176 :         if (strcasecmp(fromcode, "UTF8-NFC") == 0 &&
     445           0 :             strcasecmp(tocode, "UTF8-NFD") == 0)
     446             :         {
     447             :                 U_STRING_DECL(tname, "any-nfd", 7);
     448           0 :                 UErrorCode ue = 0;
     449             : 
     450             :                 U_STRING_INIT(tname, "any-nfd", 7);
     451             : 
     452           0 :                 ret->cd_direct = utrans_openU(tname,
     453             :                                               7,
     454             :                                               UTRANS_FORWARD,
     455             :                                               NULL,
     456             :                                               0,
     457             :                                               NULL,
     458             :                                               &ue);
     459           0 :                 if (U_FAILURE(ue)) {
     460           0 :                         return (smb_iconv_t)-1;
     461             :                 }
     462           0 :                 ret->direct = sys_uconv;
     463           0 :                 return ret;
     464             :         }
     465             : #endif
     466             : 
     467       69176 :         if (ret->pull == NULL && from == NULL) {
     468           0 :                 goto failed;
     469             :         }
     470             : 
     471       69176 :         if (ret->push == NULL && to == NULL) {
     472           0 :                 goto failed;
     473             :         }
     474             : 
     475             :         /* check for conversion to/from ucs2 */
     476       69176 :         if (is_utf16(fromcode) && to) {
     477       23598 :                 ret->direct = to->push;
     478       23598 :                 return ret;
     479             :         }
     480       45578 :         if (is_utf16(tocode) && from) {
     481       17452 :                 ret->direct = from->pull;
     482       17452 :                 return ret;
     483             :         }
     484             : 
     485             : #ifdef HAVE_NATIVE_ICONV
     486       28126 :         if (is_utf16(fromcode)) {
     487           0 :                 ret->direct = sys_iconv;
     488           0 :                 ret->cd_direct = ret->cd_push;
     489           0 :                 ret->cd_push = NULL;
     490           0 :                 return ret;
     491             :         }
     492       28126 :         if (is_utf16(tocode)) {
     493           0 :                 ret->direct = sys_iconv;
     494           0 :                 ret->cd_direct = ret->cd_pull;
     495           0 :                 ret->cd_pull = NULL;
     496           0 :                 return ret;
     497             :         }
     498             : #endif
     499             : 
     500             :         /* the general case has to go via a buffer */
     501       28126 :         if (!ret->pull) ret->pull = from->pull;
     502       28126 :         if (!ret->push) ret->push = to->push;
     503       28126 :         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           0 : _PUBLIC_ smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode)
     515             : {
     516           0 :         return smb_iconv_open_ex(NULL, tocode, fromcode, true);
     517             : }
     518             : 
     519             : /*
     520             :   simple iconv_close() wrapper
     521             : */
     522       42474 : _PUBLIC_ int smb_iconv_close(smb_iconv_t cd)
     523             : {
     524       42474 :         talloc_free(cd);
     525       42474 :         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           0 : static size_t ascii_pull(void *cd, const char **inbuf, size_t *inbytesleft,
     544             :                          char **outbuf, size_t *outbytesleft)
     545             : {
     546           0 :         while (*inbytesleft >= 1 && *outbytesleft >= 2) {
     547           0 :                 if (((*inbuf)[0] & 0x7F) != (*inbuf)[0]) {
     548             :                         /* If this is multi-byte, then it isn't legal ASCII */
     549           0 :                         errno = EILSEQ;
     550           0 :                         return -1;
     551             :                 }
     552           0 :                 (*outbuf)[0] = (*inbuf)[0];
     553           0 :                 (*outbuf)[1] = 0;
     554           0 :                 (*inbytesleft)  -= 1;
     555           0 :                 (*outbytesleft) -= 2;
     556           0 :                 (*inbuf)  += 1;
     557           0 :                 (*outbuf) += 2;
     558             :         }
     559             : 
     560           0 :         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           0 : static size_t ascii_push(void *cd, const char **inbuf, size_t *inbytesleft,
     576             :                          char **outbuf, size_t *outbytesleft)
     577             : {
     578           0 :         int ir_count=0;
     579             : 
     580           0 :         while (*inbytesleft >= 2 && *outbytesleft >= 1) {
     581           0 :                 if (((*inbuf)[0] & 0x7F) != (*inbuf)[0] ||
     582           0 :                         (*inbuf)[1] != 0) {
     583             :                         /* If this is multi-byte, then it isn't legal ASCII */
     584           0 :                         errno = EILSEQ;
     585           0 :                         return -1;
     586             :                 }
     587           0 :                 (*outbuf)[0] = (*inbuf)[0];
     588           0 :                 (*inbytesleft)  -= 2;
     589           0 :                 (*outbytesleft) -= 1;
     590           0 :                 (*inbuf)  += 2;
     591           0 :                 (*outbuf) += 1;
     592             :         }
     593             : 
     594           0 :         if (*inbytesleft == 1) {
     595           0 :                 errno = EINVAL;
     596           0 :                 return -1;
     597             :         }
     598             : 
     599           0 :         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           0 : static size_t latin1_pull(void *cd, const char **inbuf, size_t *inbytesleft,
     615             :                           char **outbuf, size_t *outbytesleft)
     616             : {
     617           0 :         while (*inbytesleft >= 1 && *outbytesleft >= 2) {
     618           0 :                 (*outbuf)[0] = (*inbuf)[0];
     619           0 :                 (*outbuf)[1] = 0;
     620           0 :                 (*inbytesleft)  -= 1;
     621           0 :                 (*outbytesleft) -= 2;
     622           0 :                 (*inbuf)  += 1;
     623           0 :                 (*outbuf) += 2;
     624             :         }
     625             : 
     626           0 :         if (*inbytesleft > 0) {
     627           0 :                 errno = E2BIG;
     628           0 :                 return -1;
     629             :         }
     630             : 
     631           0 :         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           0 : static size_t latin1_push(void *cd, const char **inbuf, size_t *inbytesleft,
     642             :                          char **outbuf, size_t *outbytesleft)
     643             : {
     644           0 :         int ir_count=0;
     645             : 
     646           0 :         while (*inbytesleft >= 2 && *outbytesleft >= 1) {
     647           0 :                 (*outbuf)[0] = (*inbuf)[0];
     648           0 :                 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           0 :                 (*inbytesleft)  -= 2;
     654           0 :                 (*outbytesleft) -= 1;
     655           0 :                 (*inbuf)  += 2;
     656           0 :                 (*outbuf) += 1;
     657             :         }
     658             : 
     659           0 :         if (*inbytesleft == 1) {
     660           0 :                 errno = EINVAL;
     661           0 :                 return -1;
     662             :         }
     663             : 
     664           0 :         if (*inbytesleft > 1) {
     665           0 :                 errno = E2BIG;
     666           0 :                 return -1;
     667             :         }
     668             : 
     669           0 :         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       45579 : 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       45579 :         n = MIN(*inbytesleft, *outbytesleft);
     764             : 
     765       45579 :         swab(*inbuf, *outbuf, (n&~1));
     766       45579 :         if (n&1) {
     767           0 :                 (*outbuf)[n-1] = 0;
     768             :         }
     769             : 
     770       45579 :         (*inbytesleft) -= n;
     771       45579 :         (*outbytesleft) -= n;
     772       45579 :         (*inbuf) += n;
     773       45579 :         (*outbuf) += n;
     774             : 
     775       45579 :         if (*inbytesleft > 0) {
     776         182 :                 errno = E2BIG;
     777         182 :                 return -1;
     778             :         }
     779             : 
     780       45397 :         return 0;
     781             : }
     782             : 
     783             : 
     784        2578 : 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        2578 :         n = MIN(*inbytesleft, *outbytesleft);
     790             : 
     791        2578 :         memmove(*outbuf, *inbuf, n);
     792             : 
     793        2578 :         (*inbytesleft) -= n;
     794        2578 :         (*outbytesleft) -= n;
     795        2578 :         (*inbuf) += n;
     796        2578 :         (*outbuf) += n;
     797             : 
     798        2578 :         if (*inbytesleft > 0) {
     799           0 :                 errno = E2BIG;
     800           0 :                 return -1;
     801             :         }
     802             : 
     803        2578 :         return 0;
     804             : }
     805             : 
     806             : /*
     807             :   this takes a UTF8 sequence and produces a UTF16 sequence
     808             :  */
     809    10414160 : static size_t utf8_pull(void *cd, const char **inbuf, size_t *inbytesleft,
     810             :                          char **outbuf, size_t *outbytesleft)
     811             : {
     812    10414160 :         size_t in_left=*inbytesleft, out_left=*outbytesleft;
     813    10414160 :         const uint8_t *c = (const uint8_t *)*inbuf;
     814    10414160 :         uint8_t *uc = (uint8_t *)*outbuf;
     815             : 
     816   310948960 :         while (in_left >= 1 && out_left >= 2) {
     817   291075236 :                 if ((c[0] & 0x80) == 0) {
     818   283961581 :                         uc[0] = c[0];
     819   283961581 :                         uc[1] = 0;
     820   283961581 :                         c  += 1;
     821   283961581 :                         in_left  -= 1;
     822   283961581 :                         out_left -= 2;
     823   283961581 :                         uc += 2;
     824   283961581 :                         continue;
     825             :                 }
     826             : 
     827     7113655 :                 if ((c[0] & 0xe0) == 0xc0) {
     828     9572968 :                         if (in_left < 2 ||
     829     4979750 :                             (c[1] & 0xc0) != 0x80) {
     830          48 :                                 errno = EILSEQ;
     831          48 :                                 goto error;
     832             :                         }
     833     4979702 :                         uc[1] = (c[0]>>2) & 0x7;
     834     4979702 :                         uc[0] = (c[0]<<6) | (c[1]&0x3f);
     835     4979702 :                         if (uc[1] == 0 && uc[0] < 0x80) {
     836             :                                 /* this should have been a single byte */
     837           0 :                                 errno = EILSEQ;
     838           0 :                                 goto error;
     839             :                         }
     840     4979702 :                         c  += 2;
     841     4979702 :                         in_left  -= 2;
     842     4979702 :                         out_left -= 2;
     843     4979702 :                         uc += 2;
     844     4979702 :                         continue;
     845             :                 }
     846             : 
     847     2133905 :                 if ((c[0] & 0xf0) == 0xe0) {
     848             :                         unsigned int codepoint;
     849     4121870 :                         if (in_left < 3 ||
     850     4121834 :                             (c[1] & 0xc0) != 0x80 ||
     851     2133611 :                             (c[2] & 0xc0) != 0x80) {
     852          72 :                                 errno = EILSEQ;
     853          72 :                                 goto error;
     854             :                         }
     855     6109913 :                         codepoint = ((c[2] & 0x3f)        |
     856     4121762 :                                      ((c[1] & 0x3f) << 6) |
     857     2133611 :                                      ((c[0] & 0x0f) << 12));
     858             : 
     859     2133611 :                         if (codepoint < 0x800) {
     860             :                                 /* this should be a 1 or 2 byte sequence */
     861           0 :                                 errno = EILSEQ;
     862           0 :                                 goto error;
     863             :                         }
     864     2133611 :                         uc[0] = codepoint & 0xff;
     865     2133611 :                         uc[1] = codepoint >> 8;
     866     2133611 :                         c  += 3;
     867     2133611 :                         in_left  -= 3;
     868     2133611 :                         out_left -= 2;
     869     2133611 :                         uc += 2;
     870     2133611 :                         continue;
     871             :                 }
     872             : 
     873         222 :                 if ((c[0] & 0xf8) == 0xf0) {
     874             :                         unsigned int codepoint;
     875          52 :                         if (in_left < 4 ||
     876          52 :                             (c[1] & 0xc0) != 0x80 ||
     877          52 :                             (c[2] & 0xc0) != 0x80 ||
     878          26 :                             (c[3] & 0xc0) != 0x80) {
     879           0 :                                 errno = EILSEQ;
     880           0 :                                 goto error;
     881             :                         }
     882          26 :                         codepoint =
     883          52 :                                 (c[3]&0x3f) |
     884          52 :                                 ((c[2]&0x3f)<<6) |
     885          52 :                                 ((c[1]&0x3f)<<12) |
     886          26 :                                 ((c[0]&0x7)<<18);
     887          26 :                         if (codepoint < 0x10000) {
     888             :                                 /* reject UTF-8 characters that are not
     889             :                                    minimally packed */
     890           0 :                                 errno = EILSEQ;
     891           0 :                                 goto error;
     892             :                         }
     893             : 
     894          26 :                         codepoint -= 0x10000;
     895             : 
     896          26 :                         if (out_left < 4) {
     897          12 :                                 errno = E2BIG;
     898          12 :                                 goto error;
     899             :                         }
     900             : 
     901          14 :                         uc[0] = (codepoint>>10) & 0xFF;
     902          14 :                         uc[1] = (codepoint>>18) | 0xd8;
     903          14 :                         uc[2] = codepoint & 0xFF;
     904          14 :                         uc[3] = ((codepoint>>8) & 0x3) | 0xdc;
     905          14 :                         c  += 4;
     906          14 :                         in_left  -= 4;
     907          14 :                         out_left -= 4;
     908          14 :                         uc += 4;
     909          14 :                         continue;
     910             :                 }
     911             : 
     912             :                 /* we don't handle 5 byte sequences */
     913         196 :                 errno = EINVAL;
     914         196 :                 goto error;
     915             :         }
     916             : 
     917    10413832 :         if (in_left > 0) {
     918      481079 :                 errno = E2BIG;
     919      481079 :                 goto error;
     920             :         }
     921             : 
     922     9932753 :         *inbytesleft = in_left;
     923     9932753 :         *outbytesleft = out_left;
     924     9932753 :         *inbuf = (const char *)c;
     925     9932753 :         *outbuf = (char *)uc;
     926     9932753 :         return 0;
     927             : 
     928      481407 : error:
     929      481407 :         *inbytesleft = in_left;
     930      481407 :         *outbytesleft = out_left;
     931      481407 :         *inbuf = (const char *)c;
     932      481407 :         *outbuf = (char *)uc;
     933      481407 :         return -1;
     934             : }
     935             : 
     936             : 
     937             : /*
     938             :   this takes a UTF16 sequence and produces a UTF8 sequence
     939             :  */
     940    12942500 : static size_t utf8_push(void *cd, const char **inbuf, size_t *inbytesleft,
     941             :                         char **outbuf, size_t *outbytesleft)
     942             : {
     943    12942500 :         size_t in_left=*inbytesleft, out_left=*outbytesleft;
     944    12942500 :         uint8_t *c = (uint8_t *)*outbuf;
     945    12942500 :         const uint8_t *uc = (const uint8_t *)*inbuf;
     946             : 
     947   895311112 :         while (in_left >= 2 && out_left >= 1) {
     948             :                 unsigned int codepoint;
     949             : 
     950   870048312 :                 if (uc[1] == 0 && !(uc[0] & 0x80)) {
     951             :                         /* simplest case */
     952   864856948 :                         c[0] = uc[0];
     953   864856948 :                         in_left  -= 2;
     954   864856948 :                         out_left -= 1;
     955   864856948 :                         uc += 2;
     956   864856948 :                         c  += 1;
     957   864856948 :                         continue;
     958             :                 }
     959             : 
     960     5191364 :                 if ((uc[1]&0xf8) == 0) {
     961             :                         /* next simplest case */
     962     3456290 :                         if (out_left < 2) {
     963           0 :                                 errno = E2BIG;
     964           0 :                                 goto error;
     965             :                         }
     966     3456290 :                         c[0] = 0xc0 | (uc[0]>>6) | (uc[1]<<2);
     967     3456290 :                         c[1] = 0x80 | (uc[0] & 0x3f);
     968     3456290 :                         in_left  -= 2;
     969     3456290 :                         out_left -= 2;
     970     3456290 :                         uc += 2;
     971     3456290 :                         c  += 2;
     972     3456290 :                         continue;
     973             :                 }
     974             : 
     975     1735074 :                 if ((uc[1] & 0xfc) == 0xdc) {
     976           6 :                         errno = EILSEQ;
     977             : #ifndef HAVE_ICONV_ERRNO_ILLEGAL_MULTIBYTE
     978             :                         if (in_left < 4) {
     979             :                                 errno = EINVAL;
     980             :                         }
     981             : #endif
     982           6 :                         goto error;
     983             :                 }
     984             : 
     985     1735068 :                 if ((uc[1] & 0xfc) != 0xd8) {
     986     1735046 :                         codepoint = uc[0] | (uc[1]<<8);
     987     1735046 :                         if (out_left < 3) {
     988           0 :                                 errno = E2BIG;
     989           0 :                                 goto error;
     990             :                         }
     991     1735046 :                         c[0] = 0xe0 | (codepoint >> 12);
     992     1735046 :                         c[1] = 0x80 | ((codepoint >> 6) & 0x3f);
     993     1735046 :                         c[2] = 0x80 | (codepoint & 0x3f);
     994             : 
     995     1735046 :                         in_left  -= 2;
     996     1735046 :                         out_left -= 3;
     997     1735046 :                         uc  += 2;
     998     1735046 :                         c   += 3;
     999     1735046 :                         continue;
    1000             :                 }
    1001             : 
    1002             :                 /* its the first part of a 4 byte sequence */
    1003          22 :                 if (in_left < 4) {
    1004           0 :                         errno = EINVAL;
    1005           0 :                         goto error;
    1006             :                 }
    1007          22 :                 if ((uc[3] & 0xfc) != 0xdc) {
    1008           2 :                         errno = EILSEQ;
    1009           2 :                         goto error;
    1010             :                 }
    1011          56 :                 codepoint = 0x10000 + (uc[2] | ((uc[3] & 0x3)<<8) |
    1012          38 :                                        (uc[0]<<10) | ((uc[1] & 0x3)<<18));
    1013             : 
    1014          20 :                 if (out_left < 4) {
    1015           0 :                         errno = E2BIG;
    1016           0 :                         goto error;
    1017             :                 }
    1018          20 :                 c[0] = 0xf0 | (codepoint >> 18);
    1019          20 :                 c[1] = 0x80 | ((codepoint >> 12) & 0x3f);
    1020          20 :                 c[2] = 0x80 | ((codepoint >> 6) & 0x3f);
    1021          20 :                 c[3] = 0x80 | (codepoint & 0x3f);
    1022             : 
    1023          20 :                 in_left  -= 4;
    1024          20 :                 out_left -= 4;
    1025          20 :                 uc       += 4;
    1026          20 :                 c        += 4;
    1027             :         }
    1028             : 
    1029    12942492 :         if (in_left == 1) {
    1030           0 :                 errno = EINVAL;
    1031           0 :                 goto error;
    1032             :         }
    1033             : 
    1034    12942492 :         if (in_left > 1) {
    1035           0 :                 errno = E2BIG;
    1036           0 :                 goto error;
    1037             :         }
    1038             : 
    1039    12942492 :         *inbytesleft = in_left;
    1040    12942492 :         *outbytesleft = out_left;
    1041    12942492 :         *inbuf  = (const char *)uc;
    1042    12942492 :         *outbuf = (char *)c;
    1043             : 
    1044    12942492 :         return 0;
    1045             : 
    1046           8 : error:
    1047           8 :         *inbytesleft = in_left;
    1048           8 :         *outbytesleft = out_left;
    1049           8 :         *inbuf  = (const char *)uc;
    1050           8 :         *outbuf = (char *)c;
    1051           8 :         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       14521 : static size_t utf16_munged_pull(void *cd, const char **inbuf, size_t *inbytesleft,
    1071             :                                char **outbuf, size_t *outbytesleft)
    1072             : {
    1073       14521 :         size_t in_left=*inbytesleft, out_left=*outbytesleft;
    1074       14521 :         uint8_t *c = (uint8_t *)*outbuf;
    1075       14521 :         const uint8_t *uc = (const uint8_t *)*inbuf;
    1076             : 
    1077      422043 :         while (in_left >= 2 && out_left >= 2) {
    1078      397374 :                 unsigned int codepoint = uc[0] | (uc[1]<<8);
    1079             : 
    1080      397374 :                 if (codepoint == 0) {
    1081           3 :                         codepoint = 1;
    1082             :                 }
    1083             : 
    1084      397374 :                 if ((codepoint & 0xfc00) == 0xd800) {
    1085             :                         /* a high surrogate */
    1086             :                         unsigned int codepoint2;
    1087         796 :                         if (in_left < 4) {
    1088           6 :                                 codepoint = 0xfffd;
    1089           6 :                                 goto codepoint16;
    1090             :                         }
    1091         790 :                         codepoint2 = uc[2] | (uc[3]<<8);
    1092         790 :                         if ((codepoint2 & 0xfc00) != 0xdc00) {
    1093             :                                 /* high surrogate not followed by low
    1094             :                                    surrogate: convert to 0xfffd */
    1095         782 :                                 codepoint = 0xfffd;
    1096         782 :                                 goto codepoint16;
    1097             :                         }
    1098           8 :                         if (out_left < 4) {
    1099           0 :                                 errno = E2BIG;
    1100           0 :                                 goto error;
    1101             :                         }
    1102           8 :                         memcpy(c, uc, 4);
    1103           8 :                         in_left  -= 4;
    1104           8 :                         out_left -= 4;
    1105           8 :                         uc       += 4;
    1106           8 :                         c        += 4;
    1107           8 :                         continue;
    1108             :                 }
    1109             : 
    1110      396578 :                 if ((codepoint & 0xfc00) == 0xdc00) {
    1111             :                         /* low surrogate not preceded by high
    1112             :                            surrogate: convert to 0xfffd */
    1113         784 :                         codepoint = 0xfffd;
    1114             :                 }
    1115             : 
    1116      711642 :         codepoint16:
    1117      397366 :                 c[0] = codepoint & 0xFF;
    1118      397366 :                 c[1] = (codepoint>>8) & 0xFF;
    1119             : 
    1120      397366 :                 in_left  -= 2;
    1121      397366 :                 out_left -= 2;
    1122      397366 :                 uc  += 2;
    1123      397366 :                 c   += 2;
    1124      397366 :                 continue;
    1125             :         }
    1126             : 
    1127       14521 :         if (in_left == 1) {
    1128           0 :                 errno = EINVAL;
    1129           0 :                 goto error;
    1130             :         }
    1131             : 
    1132       14521 :         if (in_left > 1) {
    1133           0 :                 errno = E2BIG;
    1134           0 :                 goto error;
    1135             :         }
    1136             : 
    1137       14521 :         *inbytesleft = in_left;
    1138       14521 :         *outbytesleft = out_left;
    1139       14521 :         *inbuf  = (const char *)uc;
    1140       14521 :         *outbuf = (char *)c;
    1141             : 
    1142       14521 :         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