lib/util/charcnv Move iconv handle setup in common
[samba.git] / lib / util / charset / util_unistr.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Samba utility functions
4    Copyright (C) Andrew Tridgell 1992-2001
5    Copyright (C) Simo Sorce 2001
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 "includes.h"
22 #include "system/locale.h"
23
24 /**
25  Case insensitive string compararison
26 **/
27 _PUBLIC_ int strcasecmp_m(const char *s1, const char *s2)
28 {
29         codepoint_t c1=0, c2=0;
30         size_t size1, size2;
31         struct smb_iconv_convenience *iconv_convenience = get_iconv_convenience();
32
33         /* handle null ptr comparisons to simplify the use in qsort */
34         if (s1 == s2) return 0;
35         if (s1 == NULL) return -1;
36         if (s2 == NULL) return 1;
37
38         while (*s1 && *s2) {
39                 c1 = next_codepoint_convenience(iconv_convenience, s1, &size1);
40                 c2 = next_codepoint_convenience(iconv_convenience, s2, &size2);
41
42                 s1 += size1;
43                 s2 += size2;
44
45                 if (c1 == c2) {
46                         continue;
47                 }
48
49                 if (c1 == INVALID_CODEPOINT ||
50                     c2 == INVALID_CODEPOINT) {
51                         /* what else can we do?? */
52                         return strcasecmp(s1, s2);
53                 }
54
55                 if (toupper_m(c1) != toupper_m(c2)) {
56                         return c1 - c2;
57                 }
58         }
59
60         return *s1 - *s2;
61 }
62
63 /**
64  * Get the next token from a string, return False if none found.
65  * Handles double-quotes.
66  * 
67  * Based on a routine by GJC@VILLAGE.COM. 
68  * Extensively modified by Andrew.Tridgell@anu.edu.au
69  **/
70 _PUBLIC_ bool next_token(const char **ptr,char *buff, const char *sep, size_t bufsize)
71 {
72         const char *s;
73         bool quoted;
74         size_t len=1;
75
76         if (!ptr)
77                 return false;
78
79         s = *ptr;
80
81         /* default to simple separators */
82         if (!sep)
83                 sep = " \t\n\r";
84
85         /* find the first non sep char */
86         while (*s && strchr_m(sep,*s))
87                 s++;
88         
89         /* nothing left? */
90         if (!*s)
91                 return false;
92         
93         /* copy over the token */
94         for (quoted = false; len < bufsize && *s && (quoted || !strchr_m(sep,*s)); s++) {
95                 if (*s == '\"') {
96                         quoted = !quoted;
97                 } else {
98                         len++;
99                         *buff++ = *s;
100                 }
101         }
102         
103         *ptr = (*s) ? s+1 : s;  
104         *buff = 0;
105         
106         return true;
107 }
108
109 /**
110  Case insensitive string compararison, length limited
111 **/
112 _PUBLIC_ int strncasecmp_m(const char *s1, const char *s2, size_t n)
113 {
114         codepoint_t c1=0, c2=0;
115         size_t size1, size2;
116         struct smb_iconv_convenience *iconv_convenience = get_iconv_convenience();
117
118         /* handle null ptr comparisons to simplify the use in qsort */
119         if (s1 == s2) return 0;
120         if (s1 == NULL) return -1;
121         if (s2 == NULL) return 1;
122
123         while (*s1 && *s2 && n) {
124                 n--;
125
126                 c1 = next_codepoint_convenience(iconv_convenience, s1, &size1);
127                 c2 = next_codepoint_convenience(iconv_convenience, s2, &size2);
128
129                 s1 += size1;
130                 s2 += size2;
131
132                 if (c1 == c2) {
133                         continue;
134                 }
135
136                 if (c1 == INVALID_CODEPOINT ||
137                     c2 == INVALID_CODEPOINT) {
138                         /* what else can we do?? */
139                         return strcasecmp(s1, s2);
140                 }
141
142                 if (toupper_m(c1) != toupper_m(c2)) {
143                         return c1 - c2;
144                 }
145         }
146
147         if (n == 0) {
148                 return 0;
149         }
150
151         return *s1 - *s2;
152 }
153
154 /**
155  * Compare 2 strings.
156  *
157  * @note The comparison is case-insensitive.
158  **/
159 _PUBLIC_ bool strequal_m(const char *s1, const char *s2)
160 {
161         return strcasecmp_m(s1,s2) == 0;
162 }
163
164 /**
165  Compare 2 strings (case sensitive).
166 **/
167 _PUBLIC_ bool strcsequal_m(const char *s1,const char *s2)
168 {
169         if (s1 == s2)
170                 return true;
171         if (!s1 || !s2)
172                 return false;
173         
174         return strcmp(s1,s2) == 0;
175 }
176
177
178 /**
179  String replace.
180  NOTE: oldc and newc must be 7 bit characters
181 **/
182 _PUBLIC_ void string_replace_m(char *s, char oldc, char newc)
183 {
184         struct smb_iconv_convenience *ic = get_iconv_convenience();
185         while (s && *s) {
186                 size_t size;
187                 codepoint_t c = next_codepoint_convenience(ic, s, &size);
188                 if (c == oldc) {
189                         *s = newc;
190                 }
191                 s += size;
192         }
193 }
194
195 /**
196  Paranoid strcpy into a buffer of given length (includes terminating
197  zero. Strips out all but 'a-Z0-9' and the character in other_safe_chars
198  and replaces with '_'. Deliberately does *NOT* check for multibyte
199  characters. Don't change it !
200 **/
201
202 _PUBLIC_ char *alpha_strcpy(char *dest, const char *src, const char *other_safe_chars, size_t maxlength)
203 {
204         size_t len, i;
205
206         if (maxlength == 0) {
207                 /* can't fit any bytes at all! */
208                 return NULL;
209         }
210
211         if (!dest) {
212                 DEBUG(0,("ERROR: NULL dest in alpha_strcpy\n"));
213                 return NULL;
214         }
215
216         if (!src) {
217                 *dest = 0;
218                 return dest;
219         }  
220
221         len = strlen(src);
222         if (len >= maxlength)
223                 len = maxlength - 1;
224
225         if (!other_safe_chars)
226                 other_safe_chars = "";
227
228         for(i = 0; i < len; i++) {
229                 int val = (src[i] & 0xff);
230                 if (isupper(val) || islower(val) || isdigit(val) || strchr_m(other_safe_chars, val))
231                         dest[i] = src[i];
232                 else
233                         dest[i] = '_';
234         }
235
236         dest[i] = '\0';
237
238         return dest;
239 }
240
241 /**
242  * Calculate the number of units (8 or 16-bit, depending on the
243  * destination charset), that would be needed to convert the input
244  * string which is expected to be in in src_charset encoding to the
245  * destination charset (which should be a unicode charset).
246  */
247 _PUBLIC_ size_t strlen_m_ext(const char *s, charset_t src_charset, charset_t dst_charset)
248 {
249         size_t count = 0;
250         struct smb_iconv_convenience *ic = get_iconv_convenience();
251
252         if (!s) {
253                 return 0;
254         }
255
256         while (*s && !(((uint8_t)*s) & 0x80)) {
257                 s++;
258                 count++;
259         }
260
261         if (!*s) {
262                 return count;
263         }
264
265         while (*s) {
266                 size_t c_size;
267                 codepoint_t c = next_codepoint_convenience_ext(ic, s, src_charset, &c_size);
268                 s += c_size;
269
270                 switch (dst_charset) {
271                 case CH_UTF16LE:
272                 case CH_UTF16BE:
273                 case CH_UTF16MUNGED:
274                         if (c < 0x10000) {
275                                 count += 1;
276                         } else {
277                                 count += 2;
278                         }
279                         break;
280                 case CH_UTF8:
281                         /*
282                          * this only checks ranges, and does not
283                          * check for invalid codepoints
284                          */
285                         if (c < 0x80) {
286                                 count += 1;
287                         } else if (c < 0x800) {
288                                 count += 2;
289                         } else if (c < 0x1000) {
290                                 count += 3;
291                         } else {
292                                 count += 4;
293                         }
294                         break;
295                 default:
296                         /*
297                          * non-unicode encoding:
298                          * assume that each codepoint fits into
299                          * one unit in the destination encoding.
300                          */
301                         count += 1;
302                 }
303         }
304
305         return count;
306 }
307
308 _PUBLIC_ size_t strlen_m_ext_term(const char *s, const charset_t src_charset,
309                                   const charset_t dst_charset)
310 {
311         if (!s) {
312                 return 0;
313         }
314         return strlen_m_ext(s, src_charset, dst_charset) + 1;
315 }
316
317 /**
318  * Calculate the number of 16-bit units that would be needed to convert
319  * the input string which is expected to be in CH_UNIX encoding to UTF16.
320  *
321  * This will be the same as the number of bytes in a string for single
322  * byte strings, but will be different for multibyte.
323  */
324 _PUBLIC_ size_t strlen_m(const char *s)
325 {
326         return strlen_m_ext(s, CH_UNIX, CH_UTF16LE);
327 }
328
329 /**
330    Work out the number of multibyte chars in a string, including the NULL
331    terminator.
332 **/
333 _PUBLIC_ size_t strlen_m_term(const char *s)
334 {
335         if (!s) {
336                 return 0;
337         }
338
339         return strlen_m(s) + 1;
340 }
341
342 /*
343  * Weird helper routine for the winreg pipe: If nothing is around, return 0,
344  * if a string is there, include the terminator.
345  */
346
347 _PUBLIC_ size_t strlen_m_term_null(const char *s)
348 {
349         size_t len;
350         if (!s) {
351                 return 0;
352         }
353         len = strlen_m(s);
354         if (len == 0) {
355                 return 0;
356         }
357
358         return len+1;
359 }
360
361 /**
362  Strchr and strrchr_m are a bit complex on general multi-byte strings. 
363 **/
364 _PUBLIC_ char *strchr_m(const char *s, char c)
365 {
366         struct smb_iconv_convenience *ic = get_iconv_convenience();
367         if (s == NULL) {
368                 return NULL;
369         }
370         /* characters below 0x3F are guaranteed to not appear in
371            non-initial position in multi-byte charsets */
372         if ((c & 0xC0) == 0) {
373                 return strchr(s, c);
374         }
375
376         while (*s) {
377                 size_t size;
378                 codepoint_t c2 = next_codepoint_convenience(ic, s, &size);
379                 if (c2 == c) {
380                         return discard_const_p(char, s);
381                 }
382                 s += size;
383         }
384
385         return NULL;
386 }
387
388 /**
389  * Multibyte-character version of strrchr
390  */
391 _PUBLIC_ char *strrchr_m(const char *s, char c)
392 {
393         struct smb_iconv_convenience *ic = get_iconv_convenience();
394         char *ret = NULL;
395
396         if (s == NULL) {
397                 return NULL;
398         }
399
400         /* characters below 0x3F are guaranteed to not appear in
401            non-initial position in multi-byte charsets */
402         if ((c & 0xC0) == 0) {
403                 return strrchr(s, c);
404         }
405
406         while (*s) {
407                 size_t size;
408                 codepoint_t c2 = next_codepoint_convenience(ic, s, &size);
409                 if (c2 == c) {
410                         ret = discard_const_p(char, s);
411                 }
412                 s += size;
413         }
414
415         return ret;
416 }
417
418 /**
419   return True if any (multi-byte) character is lower case
420 */
421 _PUBLIC_ bool strhaslower(const char *string)
422 {
423         struct smb_iconv_convenience *ic = get_iconv_convenience();
424         while (*string) {
425                 size_t c_size;
426                 codepoint_t s;
427                 codepoint_t t;
428
429                 s = next_codepoint_convenience(ic, string, &c_size);
430                 string += c_size;
431
432                 t = toupper_m(s);
433
434                 if (s != t) {
435                         return true; /* that means it has lower case chars */
436                 }
437         }
438
439         return false;
440
441
442 /**
443   return True if any (multi-byte) character is upper case
444 */
445 _PUBLIC_ bool strhasupper(const char *string)
446 {
447         struct smb_iconv_convenience *ic = get_iconv_convenience();
448         while (*string) {
449                 size_t c_size;
450                 codepoint_t s;
451                 codepoint_t t;
452
453                 s = next_codepoint_convenience(ic, string, &c_size);
454                 string += c_size;
455
456                 t = tolower_m(s);
457
458                 if (s != t) {
459                         return true; /* that means it has upper case chars */
460                 }
461         }
462
463         return false;
464
465
466 /**
467  Convert a string to lower case, allocated with talloc
468 **/
469 _PUBLIC_ char *strlower_talloc(TALLOC_CTX *ctx, const char *src)
470 {
471         size_t size=0;
472         char *dest;
473         struct smb_iconv_convenience *iconv_convenience = get_iconv_convenience();
474
475         if(src == NULL) {
476                 return NULL;
477         }
478
479         /* this takes advantage of the fact that upper/lower can't
480            change the length of a character by more than 1 byte */
481         dest = talloc_array(ctx, char, 2*(strlen(src))+1);
482         if (dest == NULL) {
483                 return NULL;
484         }
485
486         while (*src) {
487                 size_t c_size;
488                 codepoint_t c = next_codepoint_convenience(iconv_convenience, src, &c_size);
489                 src += c_size;
490
491                 c = tolower_m(c);
492
493                 c_size = push_codepoint_convenience(iconv_convenience, dest+size, c);
494                 if (c_size == -1) {
495                         talloc_free(dest);
496                         return NULL;
497                 }
498                 size += c_size;
499         }
500
501         dest[size] = 0;
502
503         /* trim it so talloc_append_string() works */
504         dest = talloc_realloc(ctx, dest, char, size+1);
505
506         talloc_set_name_const(dest, dest);
507
508         return dest;
509 }
510
511 /**
512  Convert a string to UPPER case, allocated with talloc
513  source length limited to n bytes
514 **/
515 _PUBLIC_ char *strupper_talloc_n(TALLOC_CTX *ctx, const char *src, size_t n)
516 {
517         size_t size=0;
518         char *dest;
519         struct smb_iconv_convenience *iconv_convenience = get_iconv_convenience();
520         
521         if (!src) {
522                 return NULL;
523         }
524
525         /* this takes advantage of the fact that upper/lower can't
526            change the length of a character by more than 1 byte */
527         dest = talloc_array(ctx, char, 2*(n+1));
528         if (dest == NULL) {
529                 return NULL;
530         }
531
532         while (n-- && *src) {
533                 size_t c_size;
534                 codepoint_t c = next_codepoint_convenience(iconv_convenience, src, &c_size);
535                 src += c_size;
536
537                 c = toupper_m(c);
538
539                 c_size = push_codepoint_convenience(iconv_convenience, dest+size, c);
540                 if (c_size == -1) {
541                         talloc_free(dest);
542                         return NULL;
543                 }
544                 size += c_size;
545         }
546
547         dest[size] = 0;
548
549         /* trim it so talloc_append_string() works */
550         dest = talloc_realloc(ctx, dest, char, size+1);
551
552         talloc_set_name_const(dest, dest);
553
554         return dest;
555 }
556
557 /**
558  Convert a string to UPPER case, allocated with talloc
559 **/
560 _PUBLIC_ char *strupper_talloc(TALLOC_CTX *ctx, const char *src)
561 {
562         return strupper_talloc_n(ctx, src, src?strlen(src):0);
563 }
564
565 /**
566  talloc_strdup() a unix string to upper case.
567 **/
568 _PUBLIC_ char *talloc_strdup_upper(TALLOC_CTX *ctx, const char *src)
569 {
570         return strupper_talloc(ctx, src);
571 }
572
573 /**
574  Convert a string to lower case.
575 **/
576 _PUBLIC_ void strlower_m(char *s)
577 {
578         char *d;
579         struct smb_iconv_convenience *iconv_convenience;
580
581         /* this is quite a common operation, so we want it to be
582            fast. We optimise for the ascii case, knowing that all our
583            supported multi-byte character sets are ascii-compatible
584            (ie. they match for the first 128 chars) */
585         while (*s && !(((uint8_t)*s) & 0x80)) {
586                 *s = tolower((uint8_t)*s);
587                 s++;
588         }
589
590         if (!*s)
591                 return;
592
593         iconv_convenience = get_iconv_convenience();
594
595         d = s;
596
597         while (*s) {
598                 size_t c_size, c_size2;
599                 codepoint_t c = next_codepoint_convenience(iconv_convenience, s, &c_size);
600                 c_size2 = push_codepoint_convenience(iconv_convenience, d, tolower_m(c));
601                 if (c_size2 > c_size) {
602                         DEBUG(0,("FATAL: codepoint 0x%x (0x%x) expanded from %d to %d bytes in strlower_m\n",
603                                  c, tolower_m(c), (int)c_size, (int)c_size2));
604                         smb_panic("codepoint expansion in strlower_m\n");
605                 }
606                 s += c_size;
607                 d += c_size2;
608         }
609         *d = 0;
610 }
611
612 /**
613  Convert a string to UPPER case.
614 **/
615 _PUBLIC_ void strupper_m(char *s)
616 {
617         char *d;
618         struct smb_iconv_convenience *iconv_convenience;
619
620         /* this is quite a common operation, so we want it to be
621            fast. We optimise for the ascii case, knowing that all our
622            supported multi-byte character sets are ascii-compatible
623            (ie. they match for the first 128 chars) */
624         while (*s && !(((uint8_t)*s) & 0x80)) {
625                 *s = toupper((uint8_t)*s);
626                 s++;
627         }
628
629         if (!*s)
630                 return;
631
632         iconv_convenience = get_iconv_convenience();
633
634         d = s;
635
636         while (*s) {
637                 size_t c_size, c_size2;
638                 codepoint_t c = next_codepoint_convenience(iconv_convenience, s, &c_size);
639                 c_size2 = push_codepoint_convenience(iconv_convenience, d, toupper_m(c));
640                 if (c_size2 > c_size) {
641                         DEBUG(0,("FATAL: codepoint 0x%x (0x%x) expanded from %d to %d bytes in strupper_m\n",
642                                  c, toupper_m(c), (int)c_size, (int)c_size2));
643                         smb_panic("codepoint expansion in strupper_m\n");
644                 }
645                 s += c_size;
646                 d += c_size2;
647         }
648         *d = 0;
649 }
650
651
652 /**
653  Find the number of 'c' chars in a string
654 **/
655 _PUBLIC_ size_t count_chars_m(const char *s, char c)
656 {
657         struct smb_iconv_convenience *ic = get_iconv_convenience();
658         size_t count = 0;
659
660         while (*s) {
661                 size_t size;
662                 codepoint_t c2 = next_codepoint_convenience(ic, s, &size);
663                 if (c2 == c) count++;
664                 s += size;
665         }
666
667         return count;
668 }
669
670
671 /**
672  * Copy a string from a char* unix src to a dos codepage string destination.
673  *
674  * @return the number of bytes occupied by the string in the destination.
675  *
676  * @param flags can include
677  * <dl>
678  * <dt>STR_TERMINATE</dt> <dd>means include the null termination</dd>
679  * <dt>STR_UPPER</dt> <dd>means uppercase in the destination</dd>
680  * </dl>
681  *
682  * @param dest_len the maximum length in bytes allowed in the
683  * destination.  If @p dest_len is -1 then no maximum is used.
684  **/
685 static ssize_t push_ascii(void *dest, const char *src, size_t dest_len, int flags)
686 {
687         size_t src_len;
688         ssize_t ret;
689
690         if (flags & STR_UPPER) {
691                 char *tmpbuf = strupper_talloc(NULL, src);
692                 if (tmpbuf == NULL) {
693                         return -1;
694                 }
695                 ret = push_ascii(dest, tmpbuf, dest_len, flags & ~STR_UPPER);
696                 talloc_free(tmpbuf);
697                 return ret;
698         }
699
700         src_len = strlen(src);
701
702         if (flags & (STR_TERMINATE | STR_TERMINATE_ASCII))
703                 src_len++;
704
705         return convert_string(CH_UNIX, CH_DOS, src, src_len, dest, dest_len, false);
706 }
707
708 /**
709  * Copy a string from a unix char* src to an ASCII destination,
710  * allocating a buffer using talloc().
711  *
712  * @param dest always set at least to NULL 
713  *
714  * @returns The number of bytes occupied by the string in the destination
715  *         or -1 in case of error.
716  **/
717 _PUBLIC_ bool push_ascii_talloc(TALLOC_CTX *ctx, char **dest, const char *src, size_t *converted_size)
718 {
719         size_t src_len = strlen(src)+1;
720         *dest = NULL;
721         return convert_string_talloc(ctx, CH_UNIX, CH_DOS, src, src_len, (void **)dest, converted_size, false);
722 }
723
724
725 /**
726  * Copy a string from a dos codepage source to a unix char* destination.
727  *
728  * The resulting string in "dest" is always null terminated.
729  *
730  * @param flags can have:
731  * <dl>
732  * <dt>STR_TERMINATE</dt>
733  * <dd>STR_TERMINATE means the string in @p src
734  * is null terminated, and src_len is ignored.</dd>
735  * </dl>
736  *
737  * @param src_len is the length of the source area in bytes.
738  * @returns the number of bytes occupied by the string in @p src.
739  **/
740 static ssize_t pull_ascii(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
741 {
742         size_t ret;
743
744         if (flags & (STR_TERMINATE | STR_TERMINATE_ASCII)) {
745                 if (src_len == (size_t)-1) {
746                         src_len = strlen((const char *)src) + 1;
747                 } else {
748                         size_t len = strnlen((const char *)src, src_len);
749                         if (len < src_len)
750                                 len++;
751                         src_len = len;
752                 }
753         }
754
755         ret = convert_string(CH_DOS, CH_UNIX, src, src_len, dest, dest_len, false);
756
757         if (dest_len)
758                 dest[MIN(ret, dest_len-1)] = 0;
759
760         return src_len;
761 }
762
763 /**
764  * Copy a string from a char* src to a unicode destination.
765  *
766  * @returns the number of bytes occupied by the string in the destination.
767  *
768  * @param flags can have:
769  *
770  * <dl>
771  * <dt>STR_TERMINATE <dd>means include the null termination.
772  * <dt>STR_UPPER     <dd>means uppercase in the destination.
773  * <dt>STR_NOALIGN   <dd>means don't do alignment.
774  * </dl>
775  *
776  * @param dest_len is the maximum length allowed in the
777  * destination. If dest_len is -1 then no maxiumum is used.
778  **/
779 static ssize_t push_ucs2(void *dest, const char *src, size_t dest_len, int flags)
780 {
781         size_t len=0;
782         size_t src_len = strlen(src);
783         size_t ret;
784
785         if (flags & STR_UPPER) {
786                 char *tmpbuf = strupper_talloc(NULL, src);
787                 if (tmpbuf == NULL) {
788                         return -1;
789                 }
790                 ret = push_ucs2(dest, tmpbuf, dest_len, flags & ~STR_UPPER);
791                 talloc_free(tmpbuf);
792                 return ret;
793         }
794
795         if (flags & STR_TERMINATE)
796                 src_len++;
797
798         if (ucs2_align(NULL, dest, flags)) {
799                 *(char *)dest = 0;
800                 dest = (void *)((char *)dest + 1);
801                 if (dest_len) dest_len--;
802                 len++;
803         }
804
805         /* ucs2 is always a multiple of 2 bytes */
806         dest_len &= ~1;
807
808         ret = convert_string(CH_UNIX, CH_UTF16, src, src_len, dest, dest_len, false);
809         if (ret == (size_t)-1) {
810                 return 0;
811         }
812
813         len += ret;
814
815         return len;
816 }
817
818
819 /**
820  * Copy a string from a unix char* src to a UCS2 destination,
821  * allocating a buffer using talloc().
822  *
823  * @param dest always set at least to NULL 
824  *
825  * @returns The number of bytes occupied by the string in the destination
826  *         or -1 in case of error.
827  **/
828 _PUBLIC_ bool push_ucs2_talloc(TALLOC_CTX *ctx, smb_ucs2_t **dest, const char *src, size_t *converted_size)
829 {
830         size_t src_len = strlen(src)+1;
831         *dest = NULL;
832         return convert_string_talloc(ctx, CH_UNIX, CH_UTF16, src, src_len, (void **)dest, converted_size, false);
833 }
834
835
836 /**
837  * Copy a string from a unix char* src to a UTF-8 destination, allocating a buffer using talloc
838  *
839  * @param dest always set at least to NULL 
840  *
841  * @returns The number of bytes occupied by the string in the destination
842  **/
843
844 _PUBLIC_ bool push_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src, size_t *converted_size)
845 {
846         size_t src_len = strlen(src)+1;
847         *dest = NULL;
848         return convert_string_talloc(ctx, CH_UNIX, CH_UTF8, src, src_len, (void **)dest, converted_size, false);
849 }
850
851 /**
852  Copy a string from a ucs2 source to a unix char* destination.
853  Flags can have:
854   STR_TERMINATE means the string in src is null terminated.
855   STR_NOALIGN   means don't try to align.
856  if STR_TERMINATE is set then src_len is ignored if it is -1.
857  src_len is the length of the source area in bytes
858  Return the number of bytes occupied by the string in src.
859  The resulting string in "dest" is always null terminated.
860 **/
861
862 static size_t pull_ucs2(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
863 {
864         size_t ret;
865
866         if (ucs2_align(NULL, src, flags)) {
867                 src = (const void *)((const char *)src + 1);
868                 if (src_len > 0)
869                         src_len--;
870         }
871
872         if (flags & STR_TERMINATE) {
873                 if (src_len == (size_t)-1) {
874                         src_len = utf16_len(src);
875                 } else {
876                         src_len = utf16_len_n(src, src_len);
877                 }
878         }
879
880         /* ucs2 is always a multiple of 2 bytes */
881         if (src_len != (size_t)-1)
882                 src_len &= ~1;
883         
884         ret = convert_string(CH_UTF16, CH_UNIX, src, src_len, dest, dest_len, false);
885         if (dest_len)
886                 dest[MIN(ret, dest_len-1)] = 0;
887
888         return src_len;
889 }
890
891 /**
892  * Copy a string from a ASCII src to a unix char * destination, allocating a buffer using talloc
893  *
894  * @param dest always set at least to NULL 
895  *
896  * @returns The number of bytes occupied by the string in the destination
897  **/
898
899 _PUBLIC_ bool pull_ascii_talloc(TALLOC_CTX *ctx, char **dest, const char *src, size_t *converted_size)
900 {
901         size_t src_len = strlen(src)+1;
902         *dest = NULL;
903         return convert_string_talloc(ctx, CH_DOS, CH_UNIX, src, src_len, (void **)dest, converted_size, false);
904 }
905
906 /**
907  * Copy a string from a UCS2 src to a unix char * destination, allocating a buffer using talloc
908  *
909  * @param dest always set at least to NULL 
910  *
911  * @returns The number of bytes occupied by the string in the destination
912  **/
913
914 _PUBLIC_ bool pull_ucs2_talloc(TALLOC_CTX *ctx, char **dest, const smb_ucs2_t *src, size_t *converted_size)
915 {
916         size_t src_len = utf16_len(src);
917         *dest = NULL;
918         return convert_string_talloc(ctx, CH_UTF16, CH_UNIX, src, src_len, (void **)dest, converted_size, false);
919 }
920
921 /**
922  * Copy a string from a UTF-8 src to a unix char * destination, allocating a buffer using talloc
923  *
924  * @param dest always set at least to NULL 
925  *
926  * @returns The number of bytes occupied by the string in the destination
927  **/
928
929 _PUBLIC_ bool pull_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src, size_t *converted_size)
930 {
931         size_t src_len = strlen(src)+1;
932         *dest = NULL;
933         return convert_string_talloc(ctx, CH_UTF8, CH_UNIX, src, src_len, (void **)dest, converted_size, false);
934 }
935
936 /**
937  Copy a string from a char* src to a unicode or ascii
938  dos codepage destination choosing unicode or ascii based on the 
939  flags in the SMB buffer starting at base_ptr.
940  Return the number of bytes occupied by the string in the destination.
941  flags can have:
942   STR_TERMINATE means include the null termination.
943   STR_UPPER     means uppercase in the destination.
944   STR_ASCII     use ascii even with unicode packet.
945   STR_NOALIGN   means don't do alignment.
946  dest_len is the maximum length allowed in the destination. If dest_len
947  is -1 then no maxiumum is used.
948 **/
949
950 _PUBLIC_ ssize_t push_string(void *dest, const char *src, size_t dest_len, int flags)
951 {
952         if (flags & STR_ASCII) {
953                 return push_ascii(dest, src, dest_len, flags);
954         } else if (flags & STR_UNICODE) {
955                 return push_ucs2(dest, src, dest_len, flags);
956         } else {
957                 smb_panic("push_string requires either STR_ASCII or STR_UNICODE flag to be set");
958                 return -1;
959         }
960 }
961
962
963 /**
964  Copy a string from a unicode or ascii source (depending on
965  the packet flags) to a char* destination.
966  Flags can have:
967   STR_TERMINATE means the string in src is null terminated.
968   STR_UNICODE   means to force as unicode.
969   STR_ASCII     use ascii even with unicode packet.
970   STR_NOALIGN   means don't do alignment.
971  if STR_TERMINATE is set then src_len is ignored is it is -1
972  src_len is the length of the source area in bytes.
973  Return the number of bytes occupied by the string in src.
974  The resulting string in "dest" is always null terminated.
975 **/
976
977 _PUBLIC_ ssize_t pull_string(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
978 {
979         if (flags & STR_ASCII) {
980                 return pull_ascii(dest, src, dest_len, src_len, flags);
981         } else if (flags & STR_UNICODE) {
982                 return pull_ucs2(dest, src, dest_len, src_len, flags);
983         } else {
984                 smb_panic("pull_string requires either STR_ASCII or STR_UNICODE flag to be set");
985                 return -1;
986         }
987 }
988
989
990 /**
991  * Convert string from one encoding to another, making error checking etc
992  *
993  * @param src pointer to source string (multibyte or singlebyte)
994  * @param srclen length of the source string in bytes
995  * @param dest pointer to destination string (multibyte or singlebyte)
996  * @param destlen maximal length allowed for string
997  * @returns the number of bytes occupied in the destination
998  **/
999 _PUBLIC_ size_t convert_string(charset_t from, charset_t to,
1000                                 void const *src, size_t srclen, 
1001                                 void *dest, size_t destlen, 
1002                                 bool allow_badcharcnv)
1003 {
1004         size_t ret;
1005         if (!convert_string_convenience(get_iconv_convenience(), from, to, 
1006                                                                           src, srclen,
1007                                                                           dest, destlen, &ret,
1008                                                                           allow_badcharcnv))
1009                 return -1;
1010         return ret;
1011 }
1012
1013 /**
1014  * Convert between character sets, allocating a new buffer using talloc for the result.
1015  *
1016  * @param srclen length of source buffer.
1017  * @param dest always set at least to NULL
1018  * @param converted_size Size in bytes of the converted string
1019  * @note -1 is not accepted for srclen.
1020  *
1021  * @returns boolean indication whether the conversion succeeded
1022  **/
1023
1024 _PUBLIC_ bool convert_string_talloc(TALLOC_CTX *ctx, 
1025                                        charset_t from, charset_t to, 
1026                                        void const *src, size_t srclen, 
1027                                        void *dest, size_t *converted_size, 
1028                                            bool allow_badcharcnv)
1029 {
1030         return convert_string_talloc_convenience(ctx, get_iconv_convenience(),
1031                                                                                          from, to, src, srclen, dest,
1032                                                                                          converted_size, 
1033                                                                                          allow_badcharcnv);
1034 }
1035