2 Unix SMB/CIFS implementation.
3 minimal iconv implementation
4 Copyright (C) Andrew Tridgell 2001
5 Copyright (C) Jelmer Vernooij 2002
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.
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.
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/>.
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"
30 #include <unicode/ustring.h>
31 #include <unicode/utrans.h>
41 * @brief Samba wrapper/stub for iconv character set conversion.
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
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.
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
58 * @sa Samba Developers Guide
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 *);
73 static const struct charset_functions builtin_functions[] = {
74 /* windows is closest to UTF-16 */
96 /* we include the UTF-8 alias to cope with differing locale settings */
108 /* this handles the munging needed for String2Key */
110 .name = "UTF16_MUNGED",
111 .pull = utf16_munged_pull,
113 .samba_internal_charset = true
127 .name = "ISO-8859-1",
136 .samba_internal_charset = true
142 .pull = macosxfs_encoding_pull,
143 .push = macosxfs_encoding_push,
144 .samba_internal_charset = true
149 .pull = ucs2hex_pull,
150 .push = ucs2hex_push,
151 .samba_internal_charset = true
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 static size_t sys_iconv(void *cd,
160 const char **inbuf, size_t *inbytesleft,
161 char **outbuf, size_t *outbytesleft)
163 size_t ret = iconv((iconv_t)cd,
164 discard_const_p(char *, inbuf), inbytesleft,
165 outbuf, outbytesleft);
166 if (ret == (size_t)-1) iconv(cd, NULL, NULL, NULL, NULL);
172 static size_t sys_uconv(void *cd,
176 size_t *outbytesleft)
178 UTransliterator *t = (UTransliterator *)cd;
179 size_t bufsize = *inbytesleft * 2;
185 int32_t converted_len;
186 size_t inbuf_consumed;
187 size_t outbut_consumed;
190 /* Convert from UTF8 to UCS2 */
192 up = u_strFromUTF8(ustr, /* dst */
193 bufsize, /* dst buflen */
194 &converted_len, /* dst written */
196 *inbytesleft, /* src length */
198 if (up == NULL || U_FAILURE(ue)) {
201 if (converted_len > bufsize) {
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...
212 inbuf_consumed = converted_len;
215 * The following transliteration function takes two parameters, the
216 * length 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.
220 limit = converted_len;
222 /* Inplace transliteration */
223 utrans_transUChars(t,
225 &converted_len, /* text length */
226 bufsize, /* text buflen */
233 if (converted_len > bufsize) {
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
243 ustrlen = converted_len;
245 /* Convert from UCS2 back to UTF8 */
247 p = u_strToUTF8(*outbuf, /* dst */
248 *outbytesleft, /* dst buflen */
249 &converted_len, /* dst required length */
251 ustrlen, /* src length */
253 if (p == NULL || U_FAILURE(ue)) {
257 outbut_consumed = converted_len;
258 if (converted_len > *outbytesleft) {
260 * The caller's result buffer is too small...
262 outbut_consumed = *outbytesleft;
265 *inbuf += inbuf_consumed;
266 *inbytesleft -= inbuf_consumed;
267 *outbuf += outbut_consumed;
268 *outbytesleft -= outbut_consumed;
270 return converted_len;
275 * This is a simple portable iconv() implementation.
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.
280 _PUBLIC_ size_t smb_iconv(smb_iconv_t cd,
281 const char **inbuf, size_t *inbytesleft,
282 char **outbuf, size_t *outbytesleft)
284 /* in many cases we can go direct */
286 return cd->direct(cd->cd_direct,
287 inbuf, inbytesleft, outbuf, outbytesleft);
290 /* otherwise we have to do it chunks at a time */
292 #ifndef SMB_ICONV_BUFSIZE
293 #define SMB_ICONV_BUFSIZE 2048
296 char cvtbuf[SMB_ICONV_BUFSIZE];
298 while (*inbytesleft > 0) {
299 char *bufp1 = cvtbuf;
300 const char *bufp2 = cvtbuf;
301 int saved_errno = errno;
302 bool pull_failed = false;
303 bufsize = SMB_ICONV_BUFSIZE;
305 if (cd->pull(cd->cd_pull,
306 inbuf, inbytesleft, &bufp1, &bufsize) == -1
312 bufsize = SMB_ICONV_BUFSIZE - bufsize;
314 if (cd->push(cd->cd_push,
316 outbuf, outbytesleft) == -1) {
318 } else if (pull_failed) {
319 /* We want the pull errno if possible */
329 static bool is_utf16(const char *name)
331 return strcasecmp(name, "UCS-2LE") == 0 ||
332 strcasecmp(name, "UTF-16LE") == 0;
335 static int smb_iconv_t_destructor(smb_iconv_t hwd)
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().
342 if (hwd->direct == sys_uconv) {
343 utrans_close(hwd->cd_direct);
347 #ifdef HAVE_NATIVE_ICONV
348 if (hwd->cd_pull != NULL && hwd->cd_pull != (iconv_t)-1)
349 iconv_close(hwd->cd_pull);
350 if (hwd->cd_push != NULL && hwd->cd_push != (iconv_t)-1)
351 iconv_close(hwd->cd_push);
352 if (hwd->cd_direct != NULL && hwd->cd_direct != (iconv_t)-1)
353 iconv_close(hwd->cd_direct);
359 _PUBLIC_ smb_iconv_t smb_iconv_open_ex(TALLOC_CTX *mem_ctx, const char *tocode,
360 const char *fromcode, bool use_builtin_handlers)
363 const struct charset_functions *from=NULL, *to=NULL;
366 ret = (smb_iconv_t)talloc_named(mem_ctx,
368 "iconv(%s,%s)", tocode, fromcode);
371 return (smb_iconv_t)-1;
373 memset(ret, 0, sizeof(*ret));
374 talloc_set_destructor(ret, smb_iconv_t_destructor);
376 /* check for the simplest null conversion */
377 if (strcmp(fromcode, tocode) == 0) {
378 ret->direct = iconv_copy;
382 /* check if we have a builtin function for this conversion */
383 for (i=0;i<ARRAY_SIZE(builtin_functions);i++) {
384 if (strcasecmp(fromcode, builtin_functions[i].name) == 0) {
385 if (use_builtin_handlers || builtin_functions[i].samba_internal_charset) {
386 from = &builtin_functions[i];
389 if (strcasecmp(tocode, builtin_functions[i].name) == 0) {
390 if (use_builtin_handlers || builtin_functions[i].samba_internal_charset) {
391 to = &builtin_functions[i];
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
403 ret->cd_pull = iconv_open("UTF-16LE", fromcode);
404 if (ret->cd_pull == (iconv_t)-1)
405 ret->cd_pull = iconv_open("UCS-2LE", fromcode);
406 if (ret->cd_pull != (iconv_t)-1) {
407 ret->pull = sys_iconv;
412 ret->cd_push = iconv_open(tocode, "UTF-16LE");
413 if (ret->cd_push == (iconv_t)-1)
414 ret->cd_push = iconv_open(tocode, "UCS-2LE");
415 if (ret->cd_push != (iconv_t)-1) {
416 ret->push = sys_iconv;
422 if (strcasecmp(fromcode, "UTF8-NFD") == 0 &&
423 strcasecmp(tocode, "UTF8-NFC") == 0)
425 U_STRING_DECL(t, "any-nfc", 7);
428 U_STRING_INIT(t, "any-nfc", 7);
430 ret->cd_direct = utrans_openU(t,
438 return (smb_iconv_t)-1;
440 ret->direct = sys_uconv;
444 if (strcasecmp(fromcode, "UTF8-NFC") == 0 &&
445 strcasecmp(tocode, "UTF8-NFD") == 0)
447 U_STRING_DECL(tname, "any-nfd", 7);
450 U_STRING_INIT(tname, "any-nfd", 7);
452 ret->cd_direct = utrans_openU(tname,
460 return (smb_iconv_t)-1;
462 ret->direct = sys_uconv;
467 if (ret->pull == NULL && from == NULL) {
471 if (ret->push == NULL && to == NULL) {
475 /* check for conversion to/from ucs2 */
476 if (is_utf16(fromcode) && to) {
477 ret->direct = to->push;
480 if (is_utf16(tocode) && from) {
481 ret->direct = from->pull;
485 #ifdef HAVE_NATIVE_ICONV
486 if (is_utf16(fromcode)) {
487 ret->direct = sys_iconv;
488 ret->cd_direct = ret->cd_push;
492 if (is_utf16(tocode)) {
493 ret->direct = sys_iconv;
494 ret->cd_direct = ret->cd_pull;
500 /* the general case has to go via a buffer */
501 if (!ret->pull) ret->pull = from->pull;
502 if (!ret->push) ret->push = to->push;
508 return (smb_iconv_t)-1;
512 simple iconv_open() wrapper
514 _PUBLIC_ smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode)
516 return smb_iconv_open_ex(NULL, tocode, fromcode, true);
520 simple iconv_close() wrapper
522 _PUBLIC_ int smb_iconv_close(smb_iconv_t cd)
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 ***********************************************************************/
536 this takes an ASCII sequence and produces a UTF16 sequence
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
543 static size_t ascii_pull(void *cd, const char **inbuf, size_t *inbytesleft,
544 char **outbuf, size_t *outbytesleft)
546 while (*inbytesleft >= 1 && *outbytesleft >= 2) {
547 if (((*inbuf)[0] & 0x7F) != (*inbuf)[0]) {
548 /* If this is multi-byte, then it isn't legal ASCII */
552 (*outbuf)[0] = (*inbuf)[0];
555 (*outbytesleft) -= 2;
560 if (*inbytesleft > 0) {
569 this takes a UTF16 sequence and produces an ASCII sequence
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
575 static size_t ascii_push(void *cd, const char **inbuf, size_t *inbytesleft,
576 char **outbuf, size_t *outbytesleft)
580 while (*inbytesleft >= 2 && *outbytesleft >= 1) {
581 if (((*inbuf)[0] & 0x7F) != (*inbuf)[0] ||
583 /* If this is multi-byte, then it isn't legal ASCII */
587 (*outbuf)[0] = (*inbuf)[0];
589 (*outbytesleft) -= 1;
594 if (*inbytesleft == 1) {
599 if (*inbytesleft > 1) {
608 this takes a latin1/ISO-8859-1 sequence and produces a UTF16 sequence
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
614 static size_t latin1_pull(void *cd, const char **inbuf, size_t *inbytesleft,
615 char **outbuf, size_t *outbytesleft)
617 while (*inbytesleft >= 1 && *outbytesleft >= 2) {
618 (*outbuf)[0] = (*inbuf)[0];
621 (*outbytesleft) -= 2;
626 if (*inbytesleft > 0) {
635 this takes a UTF16 sequence and produces a latin1/ISO-8859-1 sequence
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
641 static size_t latin1_push(void *cd, const char **inbuf, size_t *inbytesleft,
642 char **outbuf, size_t *outbytesleft)
646 while (*inbytesleft >= 2 && *outbytesleft >= 1) {
647 (*outbuf)[0] = (*inbuf)[0];
648 if ((*inbuf)[1] != 0) {
649 /* If this is multi-byte, then it isn't legal latin1 */
654 (*outbytesleft) -= 1;
659 if (*inbytesleft == 1) {
664 if (*inbytesleft > 1) {
672 static size_t ucs2hex_pull(void *cd, const char **inbuf, size_t *inbytesleft,
673 char **outbuf, size_t *outbytesleft)
675 while (*inbytesleft >= 1 && *outbytesleft >= 2) {
676 uint8_t hi = 0, lo = 0;
679 if ((*inbuf)[0] != '@') {
680 /* seven bit ascii case */
681 (*outbuf)[0] = (*inbuf)[0];
684 (*outbytesleft) -= 2;
689 /* it's a hex character */
690 if (*inbytesleft < 5) {
695 ok = hex_byte(&(*inbuf)[1], &hi) && hex_byte(&(*inbuf)[3], &lo);
704 (*outbytesleft) -= 2;
709 if (*inbytesleft > 0) {
717 static size_t ucs2hex_push(void *cd, const char **inbuf, size_t *inbytesleft,
718 char **outbuf, size_t *outbytesleft)
720 while (*inbytesleft >= 2 && *outbytesleft >= 1) {
723 if ((*inbuf)[1] == 0 &&
724 ((*inbuf)[0] & 0x80) == 0 &&
725 (*inbuf)[0] != '@') {
726 (*outbuf)[0] = (*inbuf)[0];
728 (*outbytesleft) -= 1;
733 if (*outbytesleft < 5) {
737 snprintf(buf, 6, "@%04x", SVAL(*inbuf, 0));
738 memcpy(*outbuf, buf, 5);
740 (*outbytesleft) -= 5;
745 if (*inbytesleft == 1) {
750 if (*inbytesleft > 1) {
758 static size_t iconv_swab(void *cd, const char **inbuf, size_t *inbytesleft,
759 char **outbuf, size_t *outbytesleft)
763 n = MIN(*inbytesleft, *outbytesleft);
765 swab(*inbuf, *outbuf, (n&~1));
771 (*outbytesleft) -= n;
775 if (*inbytesleft > 0) {
784 static size_t iconv_copy(void *cd, const char **inbuf, size_t *inbytesleft,
785 char **outbuf, size_t *outbytesleft)
789 n = MIN(*inbytesleft, *outbytesleft);
791 memmove(*outbuf, *inbuf, n);
794 (*outbytesleft) -= n;
798 if (*inbytesleft > 0) {
807 this takes a UTF8 sequence and produces a UTF16 sequence
809 static size_t utf8_pull(void *cd, const char **inbuf, size_t *inbytesleft,
810 char **outbuf, size_t *outbytesleft)
812 size_t in_left=*inbytesleft, out_left=*outbytesleft;
813 const uint8_t *c = (const uint8_t *)*inbuf;
814 uint8_t *uc = (uint8_t *)*outbuf;
816 while (in_left >= 1 && out_left >= 2) {
817 if ((c[0] & 0x80) == 0) {
827 if ((c[0] & 0xe0) == 0xc0) {
829 (c[1] & 0xc0) != 0x80) {
833 uc[1] = (c[0]>>2) & 0x7;
834 uc[0] = (c[0]<<6) | (c[1]&0x3f);
835 if (uc[1] == 0 && uc[0] < 0x80) {
836 /* this should have been a single byte */
847 if ((c[0] & 0xf0) == 0xe0) {
848 unsigned int codepoint;
850 (c[1] & 0xc0) != 0x80 ||
851 (c[2] & 0xc0) != 0x80) {
855 codepoint = ((c[2] & 0x3f) |
856 ((c[1] & 0x3f) << 6) |
857 ((c[0] & 0x0f) << 12));
859 if (codepoint < 0x800) {
860 /* this should be a 1 or 2 byte sequence */
864 if (codepoint >= 0xd800 && codepoint <= 0xdfff) {
866 * This is an invalid codepoint, per
867 * RFC3629, as it encodes part of a
868 * UTF-16 surrogate pair for a
869 * character over U+10000, which ought
870 * to have been encoded as a four byte
873 * Prior to Vista, Windows might
874 * sometimes produce invalid strings
875 * where a utf-16 sequence containing
876 * surrogate pairs was converted
877 * "verbatim" into utf-8, instead of
878 * encoding the actual codepoint. This
879 * format is sometimes called "WTF-8".
881 * If we were to support that, we'd
882 * have a branch here for the case
883 * where the codepoint is between
884 * 0xd800 and 0xdbff (a "high
885 * surrogate"), and read a *six*
886 * character sequence from there which
887 * would include a low surrogate. But
888 * that would undermine the
889 * hard-learnt principle that each
890 * character should only have one
897 uc[0] = codepoint & 0xff;
898 uc[1] = codepoint >> 8;
906 if ((c[0] & 0xf8) == 0xf0) {
907 unsigned int codepoint;
909 (c[1] & 0xc0) != 0x80 ||
910 (c[2] & 0xc0) != 0x80 ||
911 (c[3] & 0xc0) != 0x80) {
920 if (codepoint < 0x10000) {
921 /* reject UTF-8 characters that are not
926 if (codepoint > 0x10ffff) {
928 * Unicode stops at 0x10ffff, and if
929 * we ignore that, we'll end up
930 * encoding the wrong characters in
931 * the surrogate pair.
937 codepoint -= 0x10000;
944 uc[0] = (codepoint>>10) & 0xFF;
945 uc[1] = (codepoint>>18) | 0xd8;
946 uc[2] = codepoint & 0xFF;
947 uc[3] = ((codepoint>>8) & 0x3) | 0xdc;
955 /* we don't handle 5 byte sequences */
965 *inbytesleft = in_left;
966 *outbytesleft = out_left;
967 *inbuf = (const char *)c;
968 *outbuf = (char *)uc;
972 *inbytesleft = in_left;
973 *outbytesleft = out_left;
974 *inbuf = (const char *)c;
975 *outbuf = (char *)uc;
981 this takes a UTF16 sequence and produces a UTF8 sequence
983 static size_t utf8_push(void *cd, const char **inbuf, size_t *inbytesleft,
984 char **outbuf, size_t *outbytesleft)
986 size_t in_left=*inbytesleft, out_left=*outbytesleft;
987 uint8_t *c = (uint8_t *)*outbuf;
988 const uint8_t *uc = (const uint8_t *)*inbuf;
990 while (in_left >= 2 && out_left >= 1) {
991 unsigned int codepoint;
993 if (uc[1] == 0 && !(uc[0] & 0x80)) {
1003 if ((uc[1]&0xf8) == 0) {
1004 /* next simplest case */
1009 c[0] = 0xc0 | (uc[0]>>6) | (uc[1]<<2);
1010 c[1] = 0x80 | (uc[0] & 0x3f);
1018 if ((uc[1] & 0xfc) == 0xdc) {
1020 #ifndef HAVE_ICONV_ERRNO_ILLEGAL_MULTIBYTE
1028 if ((uc[1] & 0xfc) != 0xd8) {
1029 codepoint = uc[0] | (uc[1]<<8);
1034 c[0] = 0xe0 | (codepoint >> 12);
1035 c[1] = 0x80 | ((codepoint >> 6) & 0x3f);
1036 c[2] = 0x80 | (codepoint & 0x3f);
1045 /* its the first part of a 4 byte sequence */
1050 if ((uc[3] & 0xfc) != 0xdc) {
1054 codepoint = 0x10000 + (uc[2] | ((uc[3] & 0x3)<<8) |
1055 (uc[0]<<10) | ((uc[1] & 0x3)<<18));
1061 c[0] = 0xf0 | (codepoint >> 18);
1062 c[1] = 0x80 | ((codepoint >> 12) & 0x3f);
1063 c[2] = 0x80 | ((codepoint >> 6) & 0x3f);
1064 c[3] = 0x80 | (codepoint & 0x3f);
1082 *inbytesleft = in_left;
1083 *outbytesleft = out_left;
1084 *inbuf = (const char *)uc;
1085 *outbuf = (char *)c;
1090 *inbytesleft = in_left;
1091 *outbytesleft = out_left;
1092 *inbuf = (const char *)uc;
1093 *outbuf = (char *)c;
1099 this takes a UTF16 munged sequence, modifies it according to the
1100 string2key rules, and produces a UTF16 sequence
1104 1) any 0x0000 characters are mapped to 0x0001
1106 2) convert any instance of 0xD800 - 0xDBFF (high surrogate)
1107 without an immediately following 0xDC00 - 0x0xDFFF (low surrogate) to
1108 U+FFFD (OBJECT REPLACEMENT CHARACTER).
1110 3) the same for any low surrogate that was not preceded by a high surrogate.
1113 static size_t utf16_munged_pull(void *cd, const char **inbuf, size_t *inbytesleft,
1114 char **outbuf, size_t *outbytesleft)
1116 size_t in_left=*inbytesleft, out_left=*outbytesleft;
1117 uint8_t *c = (uint8_t *)*outbuf;
1118 const uint8_t *uc = (const uint8_t *)*inbuf;
1120 while (in_left >= 2 && out_left >= 2) {
1121 unsigned int codepoint = uc[0] | (uc[1]<<8);
1123 if (codepoint == 0) {
1127 if ((codepoint & 0xfc00) == 0xd800) {
1128 /* a high surrogate */
1129 unsigned int codepoint2;
1134 codepoint2 = uc[2] | (uc[3]<<8);
1135 if ((codepoint2 & 0xfc00) != 0xdc00) {
1136 /* high surrogate not followed by low
1137 surrogate: convert to 0xfffd */
1153 if ((codepoint & 0xfc00) == 0xdc00) {
1154 /* low surrogate not preceded by high
1155 surrogate: convert to 0xfffd */
1160 c[0] = codepoint & 0xFF;
1161 c[1] = (codepoint>>8) & 0xFF;
1180 *inbytesleft = in_left;
1181 *outbytesleft = out_left;
1182 *inbuf = (const char *)uc;
1183 *outbuf = (char *)c;
1188 *inbytesleft = in_left;
1189 *outbytesleft = out_left;
1190 *inbuf = (const char *)uc;
1191 *outbuf = (char *)c;