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