r25456: Avoid externs for charsets for now - it breaks openchange.
[kai/samba.git] / source / lib / charset / charcnv.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Character set conversion Extensions
4    Copyright (C) Igor Vergeichik <iverg@mail.ru> 2001
5    Copyright (C) Andrew Tridgell 2001
6    Copyright (C) Simo Sorce 2001
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
21 */
22 #include "includes.h"
23 #include "system/iconv.h"
24 #include "param/param.h"
25
26 /**
27  * @file
28  *
29  * @brief Character-set conversion routines built on our iconv.
30  * 
31  * @note Samba's internal character set (at least in the 3.0 series)
32  * is always the same as the one for the Unix filesystem.  It is
33  * <b>not</b> necessarily UTF-8 and may be different on machines that
34  * need i18n filenames to be compatible with Unix software.  It does
35  * have to be a superset of ASCII.  All multibyte sequences must start
36  * with a byte with the high bit set.
37  *
38  * @sa lib/iconv.c
39  */
40
41 /**
42  * Return the name of a charset to give to iconv().
43  **/
44 static const char *charset_name(struct loadparm_context *lp_ctx, charset_t ch)
45 {
46         switch (ch) {
47         case CH_UTF16: return "UTF-16LE";
48         case CH_UNIX: return lp_unix_charset(lp_ctx);
49         case CH_DOS: return lp_dos_charset(lp_ctx);
50         case CH_DISPLAY: return lp_display_charset(lp_ctx);
51         case CH_UTF8: return "UTF8";
52         case CH_UTF16BE: return "UTF-16BE";
53         default:
54         return "ASCII";
55         }
56 }
57
58 static smb_iconv_t conv_handles[NUM_CHARSETS][NUM_CHARSETS];
59
60 /**
61  re-initialize iconv conversion descriptors
62 **/
63 _PUBLIC_ void init_iconv(void)
64 {
65         unsigned c1, c2;
66         for (c1=0;c1<NUM_CHARSETS;c1++) {
67                 for (c2=0;c2<NUM_CHARSETS;c2++) {
68                         if (conv_handles[c1][c2] != NULL) {
69                                 if (conv_handles[c1][c2] != (smb_iconv_t)-1) {
70                                         smb_iconv_close(conv_handles[c1][c2]);
71                                 }
72                                 conv_handles[c1][c2] = NULL;
73                         }
74                 }
75         }
76
77 }
78
79 /*
80   on-demand initialisation of conversion handles
81 */
82 static smb_iconv_t get_conv_handle(charset_t from, charset_t to)
83 {
84         const char *n1, *n2;
85         static int initialised;
86         /* auto-free iconv memory on exit so valgrind reports are easier
87            to look at */
88         if (initialised == 0) {
89                 initialised = 1;
90                 
91 #ifdef LC_ALL
92                 /* we set back the locale to C to get ASCII-compatible
93                    toupper/lower functions.  For now we do not need
94                    any other POSIX localisations anyway. When we
95                    should really need localized string functions one
96                    day we need to write our own ascii_tolower etc.
97                 */
98                 setlocale(LC_ALL, "C");
99 #endif
100
101                 atexit(init_iconv);
102         }
103
104         if (conv_handles[from][to]) {
105                 return conv_handles[from][to];
106         }
107
108         n1 = charset_name(global_loadparm, from);
109         n2 = charset_name(global_loadparm, to);
110
111         conv_handles[from][to] = smb_iconv_open(n2,n1);
112         
113         if (conv_handles[from][to] == (smb_iconv_t)-1) {
114                 if ((from == CH_DOS || to == CH_DOS) &&
115                     strcasecmp(charset_name(global_loadparm, CH_DOS), "ASCII") != 0) {
116                         DEBUG(0,("dos charset '%s' unavailable - using ASCII\n",
117                                  charset_name(global_loadparm, CH_DOS)));
118                         lp_set_cmdline(global_loadparm, "dos charset", "ASCII");
119
120                         n1 = charset_name(global_loadparm, from);
121                         n2 = charset_name(global_loadparm, to);
122                         
123                         conv_handles[from][to] = smb_iconv_open(n2,n1);
124                 }
125         }
126
127         return conv_handles[from][to];
128 }
129
130
131 /**
132  * Convert string from one encoding to another, making error checking etc
133  *
134  * @param src pointer to source string (multibyte or singlebyte)
135  * @param srclen length of the source string in bytes
136  * @param dest pointer to destination string (multibyte or singlebyte)
137  * @param destlen maximal length allowed for string
138  * @returns the number of bytes occupied in the destination
139  **/
140 _PUBLIC_ ssize_t convert_string(charset_t from, charset_t to,
141                       void const *src, size_t srclen, 
142                       void *dest, size_t destlen)
143 {
144         size_t i_len, o_len;
145         size_t retval;
146         const char* inbuf = (const char*)src;
147         char* outbuf = (char*)dest;
148         smb_iconv_t descriptor;
149
150         if (srclen == (size_t)-1)
151                 srclen = strlen(inbuf)+1;
152
153         descriptor = get_conv_handle(from, to);
154
155         if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
156                 /* conversion not supported, use as is */
157                 size_t len = MIN(srclen,destlen);
158                 memcpy(dest,src,len);
159                 return len;
160         }
161
162         i_len=srclen;
163         o_len=destlen;
164         retval = smb_iconv(descriptor,  &inbuf, &i_len, &outbuf, &o_len);
165         if(retval==(size_t)-1) {
166                 const char *reason;
167                 switch(errno) {
168                         case EINVAL:
169                                 reason="Incomplete multibyte sequence";
170                                 return -1;
171                         case E2BIG:
172                                 reason="No more room"; 
173                                 if (from == CH_UNIX) {
174                                         DEBUG(0,("E2BIG: convert_string(%s,%s): srclen=%d destlen=%d - '%s'\n",
175                                                  charset_name(global_loadparm, from), charset_name(global_loadparm, to),
176                                                  (int)srclen, (int)destlen, 
177                                                  (const char *)src));
178                                 } else {
179                                         DEBUG(0,("E2BIG: convert_string(%s,%s): srclen=%d destlen=%d\n",
180                                                  charset_name(global_loadparm, from), charset_name(global_loadparm, to),
181                                                  (int)srclen, (int)destlen));
182                                 }
183                                return -1;
184                         case EILSEQ:
185                                reason="Illegal multibyte sequence";
186                                return -1;
187                 }
188                 /* smb_panic(reason); */
189         }
190         return destlen-o_len;
191 }
192
193 /**
194  * Convert between character sets, allocating a new buffer using talloc for the result.
195  *
196  * @param srclen length of source buffer.
197  * @param dest always set at least to NULL
198  * @note -1 is not accepted for srclen.
199  *
200  * @returns Size in bytes of the converted string; or -1 in case of error.
201  **/
202
203 _PUBLIC_ ssize_t convert_string_talloc(TALLOC_CTX *ctx, charset_t from, charset_t to,
204                               void const *src, size_t srclen, void **dest)
205 {
206         size_t i_len, o_len, destlen;
207         size_t retval;
208         const char *inbuf = (const char *)src;
209         char *outbuf, *ob;
210         smb_iconv_t descriptor;
211
212         *dest = NULL;
213
214         if (src == NULL || srclen == (size_t)-1 || srclen == 0)
215                 return (size_t)-1;
216
217         descriptor = get_conv_handle(from, to);
218
219         if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
220                 /* conversion not supported, return -1*/
221                 DEBUG(3, ("convert_string_talloc: conversion from %s to %s not supported!\n",
222                           charset_name(global_loadparm, from), charset_name(global_loadparm, to)));
223                 return -1;
224         }
225
226         /* it is _very_ rare that a conversion increases the size by
227            more than 3x */
228         destlen = srclen;
229         outbuf = NULL;
230 convert:
231         destlen = 2 + (destlen*3);
232         ob = talloc_realloc(ctx, outbuf, char, destlen);
233         if (!ob) {
234                 DEBUG(0, ("convert_string_talloc: realloc failed!\n"));
235                 talloc_free(outbuf);
236                 return (size_t)-1;
237         } else {
238                 outbuf = ob;
239         }
240
241         /* we give iconv 2 less bytes to allow us to terminate at the
242            end */
243         i_len = srclen;
244         o_len = destlen-2;
245         retval = smb_iconv(descriptor,
246                            &inbuf, &i_len,
247                            &outbuf, &o_len);
248         if(retval == (size_t)-1)                {
249                 const char *reason="unknown error";
250                 switch(errno) {
251                         case EINVAL:
252                                 reason="Incomplete multibyte sequence";
253                                 break;
254                         case E2BIG:
255                                 goto convert;           
256                         case EILSEQ:
257                                 reason="Illegal multibyte sequence";
258                                 break;
259                 }
260                 DEBUG(0,("Conversion error: %s(%s)\n",reason,inbuf));
261                 talloc_free(ob);
262                 return (size_t)-1;
263         }
264         
265         destlen = (destlen-2) - o_len;
266
267         /* guarantee null termination in all charsets */
268         SSVAL(ob, destlen, 0);
269
270         *dest = ob;
271
272         return destlen;
273 }
274
275 /**
276  * Copy a string from a char* unix src to a dos codepage string destination.
277  *
278  * @return the number of bytes occupied by the string in the destination.
279  *
280  * @param flags can include
281  * <dl>
282  * <dt>STR_TERMINATE</dt> <dd>means include the null termination</dd>
283  * <dt>STR_UPPER</dt> <dd>means uppercase in the destination</dd>
284  * </dl>
285  *
286  * @param dest_len the maximum length in bytes allowed in the
287  * destination.  If @p dest_len is -1 then no maximum is used.
288  **/
289 static ssize_t push_ascii(void *dest, const char *src, size_t dest_len, int flags)
290 {
291         size_t src_len;
292         ssize_t ret;
293
294         if (flags & STR_UPPER) {
295                 char *tmpbuf = strupper_talloc(NULL, src);
296                 if (tmpbuf == NULL) {
297                         return -1;
298                 }
299                 ret = push_ascii(dest, tmpbuf, dest_len, flags & ~STR_UPPER);
300                 talloc_free(tmpbuf);
301                 return ret;
302         }
303
304         src_len = strlen(src);
305
306         if (flags & (STR_TERMINATE | STR_TERMINATE_ASCII))
307                 src_len++;
308
309         return convert_string(CH_UNIX, CH_DOS, src, src_len, dest, dest_len);
310 }
311
312 /**
313  * Copy a string from a unix char* src to an ASCII destination,
314  * allocating a buffer using talloc().
315  *
316  * @param dest always set at least to NULL 
317  *
318  * @returns The number of bytes occupied by the string in the destination
319  *         or -1 in case of error.
320  **/
321 _PUBLIC_ ssize_t push_ascii_talloc(TALLOC_CTX *ctx, char **dest, const char *src)
322 {
323         size_t src_len = strlen(src)+1;
324         *dest = NULL;
325         return convert_string_talloc(ctx, CH_UNIX, CH_DOS, src, src_len, (void **)dest);
326 }
327
328
329 /**
330  * Copy a string from a dos codepage source to a unix char* destination.
331  *
332  * The resulting string in "dest" is always null terminated.
333  *
334  * @param flags can have:
335  * <dl>
336  * <dt>STR_TERMINATE</dt>
337  * <dd>STR_TERMINATE means the string in @p src
338  * is null terminated, and src_len is ignored.</dd>
339  * </dl>
340  *
341  * @param src_len is the length of the source area in bytes.
342  * @returns the number of bytes occupied by the string in @p src.
343  **/
344 static ssize_t pull_ascii(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
345 {
346         size_t ret;
347
348         if (flags & (STR_TERMINATE | STR_TERMINATE_ASCII)) {
349                 if (src_len == (size_t)-1) {
350                         src_len = strlen((const char *)src) + 1;
351                 } else {
352                         size_t len = strnlen((const char *)src, src_len);
353                         if (len < src_len)
354                                 len++;
355                         src_len = len;
356                 }
357         }
358
359         ret = convert_string(CH_DOS, CH_UNIX, src, src_len, dest, dest_len);
360
361         if (dest_len)
362                 dest[MIN(ret, dest_len-1)] = 0;
363
364         return src_len;
365 }
366
367 /**
368  * Copy a string from a char* src to a unicode destination.
369  *
370  * @returns the number of bytes occupied by the string in the destination.
371  *
372  * @param flags can have:
373  *
374  * <dl>
375  * <dt>STR_TERMINATE <dd>means include the null termination.
376  * <dt>STR_UPPER     <dd>means uppercase in the destination.
377  * <dt>STR_NOALIGN   <dd>means don't do alignment.
378  * </dl>
379  *
380  * @param dest_len is the maximum length allowed in the
381  * destination. If dest_len is -1 then no maxiumum is used.
382  **/
383 static ssize_t push_ucs2(void *dest, const char *src, size_t dest_len, int flags)
384 {
385         size_t len=0;
386         size_t src_len = strlen(src);
387         size_t ret;
388
389         if (flags & STR_UPPER) {
390                 char *tmpbuf = strupper_talloc(NULL, src);
391                 if (tmpbuf == NULL) {
392                         return -1;
393                 }
394                 ret = push_ucs2(dest, tmpbuf, dest_len, flags & ~STR_UPPER);
395                 talloc_free(tmpbuf);
396                 return ret;
397         }
398
399         if (flags & STR_TERMINATE)
400                 src_len++;
401
402         if (ucs2_align(NULL, dest, flags)) {
403                 *(char *)dest = 0;
404                 dest = (void *)((char *)dest + 1);
405                 if (dest_len) dest_len--;
406                 len++;
407         }
408
409         /* ucs2 is always a multiple of 2 bytes */
410         dest_len &= ~1;
411
412         ret = convert_string(CH_UNIX, CH_UTF16, src, src_len, dest, dest_len);
413         if (ret == (size_t)-1) {
414                 return 0;
415         }
416
417         len += ret;
418
419         return len;
420 }
421
422
423 /**
424  * Copy a string from a unix char* src to a UCS2 destination,
425  * allocating a buffer using talloc().
426  *
427  * @param dest always set at least to NULL 
428  *
429  * @returns The number of bytes occupied by the string in the destination
430  *         or -1 in case of error.
431  **/
432 _PUBLIC_ ssize_t push_ucs2_talloc(TALLOC_CTX *ctx, void **dest, const char *src)
433 {
434         size_t src_len = strlen(src)+1;
435         *dest = NULL;
436         return convert_string_talloc(ctx, CH_UNIX, CH_UTF16, src, src_len, dest);
437 }
438
439
440 /**
441  * Copy a string from a unix char* src to a UTF-8 destination, allocating a buffer using talloc
442  *
443  * @param dest always set at least to NULL 
444  *
445  * @returns The number of bytes occupied by the string in the destination
446  **/
447
448 _PUBLIC_ ssize_t push_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src)
449 {
450         size_t src_len = strlen(src)+1;
451         *dest = NULL;
452         return convert_string_talloc(ctx, CH_UNIX, CH_UTF8, src, src_len, (void **)dest);
453 }
454
455 /**
456  Copy a string from a ucs2 source to a unix char* destination.
457  Flags can have:
458   STR_TERMINATE means the string in src is null terminated.
459   STR_NOALIGN   means don't try to align.
460  if STR_TERMINATE is set then src_len is ignored if it is -1.
461  src_len is the length of the source area in bytes
462  Return the number of bytes occupied by the string in src.
463  The resulting string in "dest" is always null terminated.
464 **/
465
466 static size_t pull_ucs2(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
467 {
468         size_t ret;
469
470         if (ucs2_align(NULL, src, flags)) {
471                 src = (const void *)((const char *)src + 1);
472                 if (src_len > 0)
473                         src_len--;
474         }
475
476         if (flags & STR_TERMINATE) {
477                 if (src_len == (size_t)-1) {
478                         src_len = utf16_len(src);
479                 } else {
480                         src_len = utf16_len_n(src, src_len);
481                 }
482         }
483
484         /* ucs2 is always a multiple of 2 bytes */
485         if (src_len != (size_t)-1)
486                 src_len &= ~1;
487         
488         ret = convert_string(CH_UTF16, CH_UNIX, src, src_len, dest, dest_len);
489         if (dest_len)
490                 dest[MIN(ret, dest_len-1)] = 0;
491
492         return src_len;
493 }
494
495 /**
496  * Copy a string from a ASCII src to a unix char * destination, allocating a buffer using talloc
497  *
498  * @param dest always set at least to NULL 
499  *
500  * @returns The number of bytes occupied by the string in the destination
501  **/
502
503 _PUBLIC_ ssize_t pull_ascii_talloc(TALLOC_CTX *ctx, char **dest, const char *src)
504 {
505         size_t src_len = strlen(src)+1;
506         *dest = NULL;
507         return convert_string_talloc(ctx, CH_DOS, CH_UNIX, src, src_len, (void **)dest);
508 }
509
510 /**
511  * Copy a string from a UCS2 src to a unix char * destination, allocating a buffer using talloc
512  *
513  * @param dest always set at least to NULL 
514  *
515  * @returns The number of bytes occupied by the string in the destination
516  **/
517
518 _PUBLIC_ ssize_t pull_ucs2_talloc(TALLOC_CTX *ctx, char **dest, const void *src)
519 {
520         size_t src_len = utf16_len(src);
521         *dest = NULL;
522         return convert_string_talloc(ctx, CH_UTF16, CH_UNIX, src, src_len, (void **)dest);
523 }
524
525 /**
526  * Copy a string from a UTF-8 src to a unix char * destination, allocating a buffer using talloc
527  *
528  * @param dest always set at least to NULL 
529  *
530  * @returns The number of bytes occupied by the string in the destination
531  **/
532
533 _PUBLIC_ ssize_t pull_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src)
534 {
535         size_t src_len = strlen(src)+1;
536         *dest = NULL;
537         return convert_string_talloc(ctx, CH_UTF8, CH_UNIX, src, src_len, (void **)dest);
538 }
539
540 /**
541  Copy a string from a char* src to a unicode or ascii
542  dos codepage destination choosing unicode or ascii based on the 
543  flags in the SMB buffer starting at base_ptr.
544  Return the number of bytes occupied by the string in the destination.
545  flags can have:
546   STR_TERMINATE means include the null termination.
547   STR_UPPER     means uppercase in the destination.
548   STR_ASCII     use ascii even with unicode packet.
549   STR_NOALIGN   means don't do alignment.
550  dest_len is the maximum length allowed in the destination. If dest_len
551  is -1 then no maxiumum is used.
552 **/
553
554 _PUBLIC_ ssize_t push_string(void *dest, const char *src, size_t dest_len, int flags)
555 {
556         if (flags & STR_ASCII) {
557                 return push_ascii(dest, src, dest_len, flags);
558         } else if (flags & STR_UNICODE) {
559                 return push_ucs2(dest, src, dest_len, flags);
560         } else {
561                 smb_panic("push_string requires either STR_ASCII or STR_UNICODE flag to be set");
562                 return -1;
563         }
564 }
565
566
567 /**
568  Copy a string from a unicode or ascii source (depending on
569  the packet flags) to a char* destination.
570  Flags can have:
571   STR_TERMINATE means the string in src is null terminated.
572   STR_UNICODE   means to force as unicode.
573   STR_ASCII     use ascii even with unicode packet.
574   STR_NOALIGN   means don't do alignment.
575  if STR_TERMINATE is set then src_len is ignored is it is -1
576  src_len is the length of the source area in bytes.
577  Return the number of bytes occupied by the string in src.
578  The resulting string in "dest" is always null terminated.
579 **/
580
581 _PUBLIC_ ssize_t pull_string(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
582 {
583         if (flags & STR_ASCII) {
584                 return pull_ascii(dest, src, dest_len, src_len, flags);
585         } else if (flags & STR_UNICODE) {
586                 return pull_ucs2(dest, src, dest_len, src_len, flags);
587         } else {
588                 smb_panic("pull_string requires either STR_ASCII or STR_UNICODE flag to be set");
589                 return -1;
590         }
591 }
592
593
594 /*
595   return the unicode codepoint for the next multi-byte CH_UNIX character
596   in the string
597
598   also return the number of bytes consumed (which tells the caller
599   how many bytes to skip to get to the next CH_UNIX character)
600
601   return INVALID_CODEPOINT if the next character cannot be converted
602 */
603 _PUBLIC_ codepoint_t next_codepoint(const char *str, size_t *size)
604 {
605         /* it cannot occupy more than 4 bytes in UTF16 format */
606         uint8_t buf[4];
607         smb_iconv_t descriptor;
608         size_t ilen_orig;
609         size_t ilen;
610         size_t olen;
611         char *outbuf;
612
613         if ((str[0] & 0x80) == 0) {
614                 *size = 1;
615                 return (codepoint_t)str[0];
616         }
617
618         /* we assume that no multi-byte character can take
619            more than 5 bytes. This is OK as we only
620            support codepoints up to 1M */
621         ilen_orig = strnlen(str, 5);
622         ilen = ilen_orig;
623
624         descriptor = get_conv_handle(CH_UNIX, CH_UTF16);
625         if (descriptor == (smb_iconv_t)-1) {
626                 *size = 1;
627                 return INVALID_CODEPOINT;
628         }
629
630         /* this looks a little strange, but it is needed to cope
631            with codepoints above 64k */
632         olen = 2;
633         outbuf = (char *)buf;
634         smb_iconv(descriptor,  &str, &ilen, &outbuf, &olen);
635         if (olen == 2) {
636                 olen = 4;
637                 outbuf = (char *)buf;
638                 smb_iconv(descriptor,  &str, &ilen, &outbuf, &olen);
639                 if (olen == 4) {
640                         /* we didn't convert any bytes */
641                         *size = 1;
642                         return INVALID_CODEPOINT;
643                 }
644                 olen = 4 - olen;
645         } else {
646                 olen = 2 - olen;
647         }
648
649         *size = ilen_orig - ilen;
650
651         if (olen == 2) {
652                 return (codepoint_t)SVAL(buf, 0);
653         }
654         if (olen == 4) {
655                 /* decode a 4 byte UTF16 character manually */
656                 return (codepoint_t)0x10000 + 
657                         (buf[2] | ((buf[3] & 0x3)<<8) | 
658                          (buf[0]<<10) | ((buf[1] & 0x3)<<18));
659         }
660
661         /* no other length is valid */
662         return INVALID_CODEPOINT;
663 }
664
665 /*
666   push a single codepoint into a CH_UNIX string the target string must
667   be able to hold the full character, which is guaranteed if it is at
668   least 5 bytes in size. The caller may pass less than 5 bytes if they
669   are sure the character will fit (for example, you can assume that
670   uppercase/lowercase of a character will not add more than 1 byte)
671
672   return the number of bytes occupied by the CH_UNIX character, or
673   -1 on failure
674 */
675 _PUBLIC_ ssize_t push_codepoint(char *str, codepoint_t c)
676 {
677         smb_iconv_t descriptor;
678         uint8_t buf[4];
679         size_t ilen, olen;
680         const char *inbuf;
681         
682         if (c < 128) {
683                 *str = c;
684                 return 1;
685         }
686
687         descriptor = get_conv_handle(CH_UTF16, CH_UNIX);
688         if (descriptor == (smb_iconv_t)-1) {
689                 return -1;
690         }
691
692         if (c < 0x10000) {
693                 ilen = 2;
694                 olen = 5;
695                 inbuf = (char *)buf;
696                 SSVAL(buf, 0, c);
697                 smb_iconv(descriptor, &inbuf, &ilen, &str, &olen);
698                 if (ilen != 0) {
699                         return -1;
700                 }
701                 return 5 - olen;
702         }
703
704         c -= 0x10000;
705
706         buf[0] = (c>>10) & 0xFF;
707         buf[1] = (c>>18) | 0xd8;
708         buf[2] = c & 0xFF;
709         buf[3] = ((c>>8) & 0x3) | 0xdc;
710
711         ilen = 4;
712         olen = 5;
713         inbuf = (char *)buf;
714
715         smb_iconv(descriptor, &inbuf, &ilen, &str, &olen);
716         if (ilen != 0) {
717                 return -1;
718         }
719         return 5 - olen;
720 }