lib/util/charcnv Move iconv handle setup in common
[samba.git] / source3 / lib / 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    Copyright (C) Martin Pool 2003
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
22 */
23 #include "includes.h"
24
25 /* We can parameterize this if someone complains.... JRA. */
26
27 char lp_failed_convert_char(void)
28 {
29         return '_';
30 }
31
32 /**
33  * @file
34  *
35  * @brief Character-set conversion routines built on our iconv.
36  *
37  * @note Samba's internal character set (at least in the 3.0 series)
38  * is always the same as the one for the Unix filesystem.  It is
39  * <b>not</b> necessarily UTF-8 and may be different on machines that
40  * need i18n filenames to be compatible with Unix software.  It does
41  * have to be a superset of ASCII.  All multibyte sequences must start
42  * with a byte with the high bit set.
43  *
44  * @sa lib/iconv.c
45  */
46
47
48 static bool conv_silent; /* Should we do a debug if the conversion fails ? */
49 static bool initialized;
50
51 void lazy_initialize_conv(void)
52 {
53         if (!initialized) {
54                 load_case_tables();
55                 init_iconv();
56                 initialized = true;
57         }
58 }
59
60 /**
61  * Destroy global objects allocated by init_iconv()
62  **/
63 void gfree_charcnv(void)
64 {
65         TALLOC_FREE(global_iconv_convenience);
66         initialized = false;
67 }
68
69 /**
70  * Initialize iconv conversion descriptors.
71  *
72  * This is called the first time it is needed, and also called again
73  * every time the configuration is reloaded, because the charset or
74  * codepage might have changed.
75  **/
76 void init_iconv(void)
77 {
78         global_iconv_convenience = smb_iconv_convenience_reinit(NULL, lp_dos_charset(),
79                                                                 lp_unix_charset(), lp_display_charset(),
80                                                                 true, global_iconv_convenience);
81 }
82
83 /**
84  * Convert string from one encoding to another, making error checking etc
85  * Slow path version - uses (slow) iconv.
86  *
87  * @param src pointer to source string (multibyte or singlebyte)
88  * @param srclen length of the source string in bytes
89  * @param dest pointer to destination string (multibyte or singlebyte)
90  * @param destlen maximal length allowed for string
91  * @param allow_bad_conv determines if a "best effort" conversion is acceptable (never returns errors)
92  * @returns the number of bytes occupied in the destination
93  *
94  * Ensure the srclen contains the terminating zero.
95  *
96  **/
97
98 static size_t convert_string_internal(charset_t from, charset_t to,
99                       void const *src, size_t srclen, 
100                       void *dest, size_t destlen, bool allow_bad_conv)
101 {
102         size_t i_len, o_len;
103         size_t retval;
104         const char* inbuf = (const char*)src;
105         char* outbuf = (char*)dest;
106         smb_iconv_t descriptor;
107         struct smb_iconv_convenience *ic;
108
109         lazy_initialize_conv();
110         ic = get_iconv_convenience();
111         descriptor = get_conv_handle(ic, from, to);
112
113         if (srclen == (size_t)-1) {
114                 if (from == CH_UTF16LE || from == CH_UTF16BE) {
115                         srclen = (strlen_w((const smb_ucs2_t *)src)+1) * 2;
116                 } else {
117                         srclen = strlen((const char *)src)+1;
118                 }
119         }
120
121
122         if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
123                 if (!conv_silent)
124                         DEBUG(0,("convert_string_internal: Conversion not supported.\n"));
125                 return (size_t)-1;
126         }
127
128         i_len=srclen;
129         o_len=destlen;
130
131  again:
132
133         retval = smb_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len);
134         if(retval==(size_t)-1) {
135                 const char *reason="unknown error";
136                 switch(errno) {
137                         case EINVAL:
138                                 reason="Incomplete multibyte sequence";
139                                 if (!conv_silent)
140                                         DEBUG(3,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf));
141                                 if (allow_bad_conv)
142                                         goto use_as_is;
143                                 return (size_t)-1;
144                         case E2BIG:
145                                 reason="No more room"; 
146                                 if (!conv_silent) {
147                                         if (from == CH_UNIX) {
148                                                 DEBUG(3,("E2BIG: convert_string(%s,%s): srclen=%u destlen=%u - '%s'\n",
149                                                          charset_name(ic, from), charset_name(ic, to),
150                                                         (unsigned int)srclen, (unsigned int)destlen, (const char *)src));
151                                         } else {
152                                                 DEBUG(3,("E2BIG: convert_string(%s,%s): srclen=%u destlen=%u\n",
153                                                          charset_name(ic, from), charset_name(ic, to),
154                                                         (unsigned int)srclen, (unsigned int)destlen));
155                                         }
156                                 }
157                                 break;
158                         case EILSEQ:
159                                 reason="Illegal multibyte sequence";
160                                 if (!conv_silent)
161                                         DEBUG(3,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf));
162                                 if (allow_bad_conv)
163                                         goto use_as_is;
164                                 
165                                 return (size_t)-1;
166                         default:
167                                 if (!conv_silent)
168                                         DEBUG(0,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf));
169                                 return (size_t)-1;
170                 }
171                 /* smb_panic(reason); */
172         }
173         return destlen-o_len;
174
175  use_as_is:
176
177         /* 
178          * Conversion not supported. This is actually an error, but there are so
179          * many misconfigured iconv systems and smb.conf's out there we can't just
180          * fail. Do a very bad conversion instead.... JRA.
181          */
182
183         {
184                 if (o_len == 0 || i_len == 0)
185                         return destlen - o_len;
186
187                 if (((from == CH_UTF16LE)||(from == CH_UTF16BE)) &&
188                                 ((to != CH_UTF16LE)||(to != CH_UTF16BE))) {
189                         /* Can't convert from utf16 any endian to multibyte.
190                            Replace with the default fail char.
191                         */
192                         if (i_len < 2)
193                                 return destlen - o_len;
194                         if (i_len >= 2) {
195                                 *outbuf = lp_failed_convert_char();
196
197                                 outbuf++;
198                                 o_len--;
199
200                                 inbuf += 2;
201                                 i_len -= 2;
202                         }
203
204                         if (o_len == 0 || i_len == 0)
205                                 return destlen - o_len;
206
207                         /* Keep trying with the next char... */
208                         goto again;
209
210                 } else if (from != CH_UTF16LE && from != CH_UTF16BE && to == CH_UTF16LE) {
211                         /* Can't convert to UTF16LE - just widen by adding the
212                            default fail char then zero.
213                         */
214                         if (o_len < 2)
215                                 return destlen - o_len;
216
217                         outbuf[0] = lp_failed_convert_char();
218                         outbuf[1] = '\0';
219
220                         inbuf++;
221                         i_len--;
222
223                         outbuf += 2;
224                         o_len -= 2;
225
226                         if (o_len == 0 || i_len == 0)
227                                 return destlen - o_len;
228
229                         /* Keep trying with the next char... */
230                         goto again;
231
232                 } else if (from != CH_UTF16LE && from != CH_UTF16BE &&
233                                 to != CH_UTF16LE && to != CH_UTF16BE) {
234                         /* Failed multibyte to multibyte. Just copy the default fail char and
235                                 try again. */
236                         outbuf[0] = lp_failed_convert_char();
237
238                         inbuf++;
239                         i_len--;
240
241                         outbuf++;
242                         o_len--;
243
244                         if (o_len == 0 || i_len == 0)
245                                 return destlen - o_len;
246
247                         /* Keep trying with the next char... */
248                         goto again;
249
250                 } else {
251                         /* Keep compiler happy.... */
252                         return destlen - o_len;
253                 }
254         }
255 }
256
257 /**
258  * Convert string from one encoding to another, making error checking etc
259  * Fast path version - handles ASCII first.
260  *
261  * @param src pointer to source string (multibyte or singlebyte)
262  * @param srclen length of the source string in bytes, or -1 for nul terminated.
263  * @param dest pointer to destination string (multibyte or singlebyte)
264  * @param destlen maximal length allowed for string - *NEVER* -1.
265  * @param allow_bad_conv determines if a "best effort" conversion is acceptable (never returns errors)
266  * @returns the number of bytes occupied in the destination
267  *
268  * Ensure the srclen contains the terminating zero.
269  *
270  * This function has been hand-tuned to provide a fast path.
271  * Don't change unless you really know what you are doing. JRA.
272  **/
273
274 size_t convert_string(charset_t from, charset_t to,
275                       void const *src, size_t srclen, 
276                       void *dest, size_t destlen, bool allow_bad_conv)
277 {
278         /*
279          * NB. We deliberately don't do a strlen here if srclen == -1.
280          * This is very expensive over millions of calls and is taken
281          * care of in the slow path in convert_string_internal. JRA.
282          */
283
284 #ifdef DEVELOPER
285         SMB_ASSERT(destlen != (size_t)-1);
286 #endif
287
288         if (srclen == 0)
289                 return 0;
290
291         if (from != CH_UTF16LE && from != CH_UTF16BE && to != CH_UTF16LE && to != CH_UTF16BE) {
292                 const unsigned char *p = (const unsigned char *)src;
293                 unsigned char *q = (unsigned char *)dest;
294                 size_t slen = srclen;
295                 size_t dlen = destlen;
296                 unsigned char lastp = '\0';
297                 size_t retval = 0;
298
299                 /* If all characters are ascii, fast path here. */
300                 while (slen && dlen) {
301                         if ((lastp = *p) <= 0x7f) {
302                                 *q++ = *p++;
303                                 if (slen != (size_t)-1) {
304                                         slen--;
305                                 }
306                                 dlen--;
307                                 retval++;
308                                 if (!lastp)
309                                         break;
310                         } else {
311 #ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
312                                 goto general_case;
313 #else
314                                 size_t ret = convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv);
315                                 if (ret == (size_t)-1) {
316                                         return ret;
317                                 }
318                                 return retval + ret;
319 #endif
320                         }
321                 }
322                 if (!dlen) {
323                         /* Even if we fast path we should note if we ran out of room. */
324                         if (((slen != (size_t)-1) && slen) ||
325                                         ((slen == (size_t)-1) && lastp)) {
326                                 errno = E2BIG;
327                         }
328                 }
329                 return retval;
330         } else if (from == CH_UTF16LE && to != CH_UTF16LE) {
331                 const unsigned char *p = (const unsigned char *)src;
332                 unsigned char *q = (unsigned char *)dest;
333                 size_t retval = 0;
334                 size_t slen = srclen;
335                 size_t dlen = destlen;
336                 unsigned char lastp = '\0';
337
338                 /* If all characters are ascii, fast path here. */
339                 while (((slen == (size_t)-1) || (slen >= 2)) && dlen) {
340                         if (((lastp = *p) <= 0x7f) && (p[1] == 0)) {
341                                 *q++ = *p;
342                                 if (slen != (size_t)-1) {
343                                         slen -= 2;
344                                 }
345                                 p += 2;
346                                 dlen--;
347                                 retval++;
348                                 if (!lastp)
349                                         break;
350                         } else {
351 #ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
352                                 goto general_case;
353 #else
354                                 size_t ret = convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv);
355                                 if (ret == (size_t)-1) {
356                                         return ret;
357                                 }
358                                 return retval + ret;
359 #endif
360                         }
361                 }
362                 if (!dlen) {
363                         /* Even if we fast path we should note if we ran out of room. */
364                         if (((slen != (size_t)-1) && slen) ||
365                                         ((slen == (size_t)-1) && lastp)) {
366                                 errno = E2BIG;
367                         }
368                 }
369                 return retval;
370         } else if (from != CH_UTF16LE && from != CH_UTF16BE && to == CH_UTF16LE) {
371                 const unsigned char *p = (const unsigned char *)src;
372                 unsigned char *q = (unsigned char *)dest;
373                 size_t retval = 0;
374                 size_t slen = srclen;
375                 size_t dlen = destlen;
376                 unsigned char lastp = '\0';
377
378                 /* If all characters are ascii, fast path here. */
379                 while (slen && (dlen >= 2)) {
380                         if ((lastp = *p) <= 0x7F) {
381                                 *q++ = *p++;
382                                 *q++ = '\0';
383                                 if (slen != (size_t)-1) {
384                                         slen--;
385                                 }
386                                 dlen -= 2;
387                                 retval += 2;
388                                 if (!lastp)
389                                         break;
390                         } else {
391 #ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
392                                 goto general_case;
393 #else
394                                 size_t ret = convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv);
395                                 if (ret == (size_t)-1) {
396                                         return ret;
397                                 }
398                                 return retval + ret;
399 #endif
400                         }
401                 }
402                 if (!dlen) {
403                         /* Even if we fast path we should note if we ran out of room. */
404                         if (((slen != (size_t)-1) && slen) ||
405                                         ((slen == (size_t)-1) && lastp)) {
406                                 errno = E2BIG;
407                         }
408                 }
409                 return retval;
410         }
411
412 #ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
413   general_case:
414 #endif
415         return convert_string_internal(from, to, src, srclen, dest, destlen, allow_bad_conv);
416 }
417
418 /**
419  * Convert between character sets, allocating a new buffer using talloc for the result.
420  *
421  * @param srclen length of source buffer.
422  * @param dest always set at least to NULL
423  * @parm converted_size set to the number of bytes occupied by the string in
424  * the destination on success.
425  * @note -1 is not accepted for srclen.
426  *
427  * @return true if new buffer was correctly allocated, and string was
428  * converted.
429  *
430  * Ensure the srclen contains the terminating zero.
431  *
432  * I hate the goto's in this function. It's embarressing.....
433  * There has to be a cleaner way to do this. JRA.
434  */
435 bool convert_string_talloc(TALLOC_CTX *ctx, charset_t from, charset_t to,
436                            void const *src, size_t srclen, void *dst,
437                            size_t *converted_size, bool allow_bad_conv)
438
439 {
440         size_t i_len, o_len, destlen = (srclen * 3) / 2;
441         size_t retval;
442         const char *inbuf = (const char *)src;
443         char *outbuf = NULL, *ob = NULL;
444         smb_iconv_t descriptor;
445         void **dest = (void **)dst;
446         struct smb_iconv_convenience *ic;
447
448         *dest = NULL;
449
450         if (!converted_size) {
451                 errno = EINVAL;
452                 return false;
453         }
454
455         if (src == NULL || srclen == (size_t)-1) {
456                 errno = EINVAL;
457                 return false;
458         }
459         if (srclen == 0) {
460                 ob = talloc_strdup(ctx, "");
461                 if (ob == NULL) {
462                         errno = ENOMEM;
463                         return false;
464                 }
465                 *dest = ob;
466                 *converted_size = 0;
467                 return true;
468         }
469
470         lazy_initialize_conv();
471         ic = get_iconv_convenience();
472         descriptor = get_conv_handle(ic, from, to);
473
474         if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
475                 if (!conv_silent)
476                         DEBUG(0,("convert_string_talloc: Conversion not supported.\n"));
477                 errno = EOPNOTSUPP;
478                 return false;
479         }
480
481   convert:
482
483         /* +2 is for ucs2 null termination. */
484         if ((destlen*2)+2 < destlen) {
485                 /* wrapped ! abort. */
486                 if (!conv_silent)
487                         DEBUG(0, ("convert_string_talloc: destlen wrapped !\n"));
488                 TALLOC_FREE(outbuf);
489                 errno = EOPNOTSUPP;
490                 return false;
491         } else {
492                 destlen = destlen * 2;
493         }
494
495         /* +2 is for ucs2 null termination. */
496         ob = (char *)TALLOC_REALLOC(ctx, ob, destlen + 2);
497
498         if (!ob) {
499                 DEBUG(0, ("convert_string_talloc: realloc failed!\n"));
500                 errno = ENOMEM;
501                 return false;
502         }
503         outbuf = ob;
504         i_len = srclen;
505         o_len = destlen;
506
507  again:
508
509         retval = smb_iconv(descriptor,
510                            &inbuf, &i_len,
511                            &outbuf, &o_len);
512         if(retval == (size_t)-1)                {
513                 const char *reason="unknown error";
514                 switch(errno) {
515                         case EINVAL:
516                                 reason="Incomplete multibyte sequence";
517                                 if (!conv_silent)
518                                         DEBUG(3,("convert_string_talloc: Conversion error: %s(%s)\n",reason,inbuf));
519                                 if (allow_bad_conv)
520                                         goto use_as_is;
521                                 break;
522                         case E2BIG:
523                                 goto convert;
524                         case EILSEQ:
525                                 reason="Illegal multibyte sequence";
526                                 if (!conv_silent)
527                                         DEBUG(3,("convert_string_talloc: Conversion error: %s(%s)\n",reason,inbuf));
528                                 if (allow_bad_conv)
529                                         goto use_as_is;
530                                 break;
531                 }
532                 if (!conv_silent)
533                         DEBUG(0,("Conversion error: %s(%s)\n",reason,inbuf));
534                 /* smb_panic(reason); */
535                 TALLOC_FREE(ob);
536                 return false;
537         }
538
539   out:
540
541         destlen = destlen - o_len;
542         /* Don't shrink unless we're reclaiming a lot of
543          * space. This is in the hot codepath and these
544          * reallocs *cost*. JRA.
545          */
546         if (o_len > 1024) {
547                 /* We're shrinking here so we know the +2 is safe from wrap. */
548                 ob = (char *)TALLOC_REALLOC(ctx,ob,destlen + 2);
549         }
550
551         if (destlen && !ob) {
552                 DEBUG(0, ("convert_string_talloc: out of memory!\n"));
553                 errno = ENOMEM;
554                 return false;
555         }
556
557         *dest = ob;
558
559         /* Must ucs2 null terminate in the extra space we allocated. */
560         ob[destlen] = '\0';
561         ob[destlen+1] = '\0';
562
563         *converted_size = destlen;
564         return true;
565
566  use_as_is:
567
568         /* 
569          * Conversion not supported. This is actually an error, but there are so
570          * many misconfigured iconv systems and smb.conf's out there we can't just
571          * fail. Do a very bad conversion instead.... JRA.
572          */
573
574         {
575                 if (o_len == 0 || i_len == 0)
576                         goto out;
577
578                 if (((from == CH_UTF16LE)||(from == CH_UTF16BE)) &&
579                                 ((to != CH_UTF16LE)||(to != CH_UTF16BE))) {
580                         /* Can't convert from utf16 any endian to multibyte.
581                            Replace with the default fail char.
582                         */
583
584                         if (i_len < 2)
585                                 goto out;
586
587                         if (i_len >= 2) {
588                                 *outbuf = lp_failed_convert_char();
589
590                                 outbuf++;
591                                 o_len--;
592
593                                 inbuf += 2;
594                                 i_len -= 2;
595                         }
596
597                         if (o_len == 0 || i_len == 0)
598                                 goto out;
599
600                         /* Keep trying with the next char... */
601                         goto again;
602
603                 } else if (from != CH_UTF16LE && from != CH_UTF16BE && to == CH_UTF16LE) {
604                         /* Can't convert to UTF16LE - just widen by adding the
605                            default fail char then zero.
606                         */
607                         if (o_len < 2)
608                                 goto out;
609
610                         outbuf[0] = lp_failed_convert_char();
611                         outbuf[1] = '\0';
612
613                         inbuf++;
614                         i_len--;
615
616                         outbuf += 2;
617                         o_len -= 2;
618
619                         if (o_len == 0 || i_len == 0)
620                                 goto out;
621
622                         /* Keep trying with the next char... */
623                         goto again;
624
625                 } else if (from != CH_UTF16LE && from != CH_UTF16BE &&
626                                 to != CH_UTF16LE && to != CH_UTF16BE) {
627                         /* Failed multibyte to multibyte. Just copy the default fail char and
628                            try again. */
629                         outbuf[0] = lp_failed_convert_char();
630
631                         inbuf++;
632                         i_len--;
633
634                         outbuf++;
635                         o_len--;
636
637                         if (o_len == 0 || i_len == 0)
638                                 goto out;
639
640                         /* Keep trying with the next char... */
641                         goto again;
642
643                 } else {
644                         /* Keep compiler happy.... */
645                         goto out;
646                 }
647         }
648 }
649
650 size_t unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen)
651 {
652         size_t size;
653         smb_ucs2_t *buffer;
654
655         if (!push_ucs2_talloc(talloc_tos(), &buffer, src, &size)) {
656                 return (size_t)-1;
657         }
658
659         if (!strupper_w(buffer) && (dest == src)) {
660                 TALLOC_FREE(buffer);
661                 return srclen;
662         }
663
664         size = convert_string(CH_UTF16LE, CH_UNIX, buffer, size, dest, destlen, True);
665         TALLOC_FREE(buffer);
666         return size;
667 }
668
669 /**
670  talloc_strdup() a unix string to upper case.
671 **/
672
673 char *talloc_strdup_upper(TALLOC_CTX *ctx, const char *s)
674 {
675         char *out_buffer = talloc_strdup(ctx,s);
676         const unsigned char *p = (const unsigned char *)s;
677         unsigned char *q = (unsigned char *)out_buffer;
678
679         if (!q) {
680                 return NULL;
681         }
682
683         /* this is quite a common operation, so we want it to be
684            fast. We optimise for the ascii case, knowing that all our
685            supported multi-byte character sets are ascii-compatible
686            (ie. they match for the first 128 chars) */
687
688         while (*p) {
689                 if (*p & 0x80)
690                         break;
691                 *q++ = toupper_ascii_fast(*p);
692                 p++;
693         }
694
695         if (*p) {
696                 /* MB case. */
697                 size_t converted_size, converted_size2;
698                 smb_ucs2_t *ubuf = NULL;
699
700                 /* We're not using the ascii buffer above. */
701                 TALLOC_FREE(out_buffer);
702
703                 if (!convert_string_talloc(ctx, CH_UNIX, CH_UTF16LE, s,
704                                            strlen(s)+1, (void *)&ubuf,
705                                            &converted_size, True))
706                 {
707                         return NULL;
708                 }
709
710                 strupper_w(ubuf);
711
712                 if (!convert_string_talloc(ctx, CH_UTF16LE, CH_UNIX, ubuf,
713                                            converted_size, (void *)&out_buffer,
714                                            &converted_size2, True))
715                 {
716                         TALLOC_FREE(ubuf);
717                         return NULL;
718                 }
719
720                 /* Don't need the intermediate buffer
721                  * anymore.
722                  */
723                 TALLOC_FREE(ubuf);
724         }
725
726         return out_buffer;
727 }
728
729 char *strupper_talloc(TALLOC_CTX *ctx, const char *s) {
730         return talloc_strdup_upper(ctx, s);
731 }
732
733
734 size_t unix_strlower(const char *src, size_t srclen, char *dest, size_t destlen)
735 {
736         size_t size;
737         smb_ucs2_t *buffer = NULL;
738
739         if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_UTF16LE, src, srclen,
740                                    (void **)(void *)&buffer, &size,
741                                    True))
742         {
743                 smb_panic("failed to create UCS2 buffer");
744         }
745         if (!strlower_w(buffer) && (dest == src)) {
746                 TALLOC_FREE(buffer);
747                 return srclen;
748         }
749         size = convert_string(CH_UTF16LE, CH_UNIX, buffer, size, dest, destlen, True);
750         TALLOC_FREE(buffer);
751         return size;
752 }
753
754
755 char *talloc_strdup_lower(TALLOC_CTX *ctx, const char *s)
756 {
757         size_t converted_size;
758         smb_ucs2_t *buffer = NULL;
759         char *out_buffer;
760
761         if (!push_ucs2_talloc(ctx, &buffer, s, &converted_size)) {
762                 return NULL;
763         }
764
765         strlower_w(buffer);
766
767         if (!pull_ucs2_talloc(ctx, &out_buffer, buffer, &converted_size)) {
768                 TALLOC_FREE(buffer);
769                 return NULL;
770         }
771
772         TALLOC_FREE(buffer);
773
774         return out_buffer;
775 }
776
777 char *strlower_talloc(TALLOC_CTX *ctx, const char *s) {
778         return talloc_strdup_lower(ctx, s);
779 }
780
781 size_t ucs2_align(const void *base_ptr, const void *p, int flags)
782 {
783         if (flags & (STR_NOALIGN|STR_ASCII))
784                 return 0;
785         return PTR_DIFF(p, base_ptr) & 1;
786 }
787
788
789 /**
790  * Copy a string from a char* unix src to a dos codepage string destination.
791  *
792  * @return the number of bytes occupied by the string in the destination.
793  *
794  * @param flags can include
795  * <dl>
796  * <dt>STR_TERMINATE</dt> <dd>means include the null termination</dd>
797  * <dt>STR_UPPER</dt> <dd>means uppercase in the destination</dd>
798  * </dl>
799  *
800  * @param dest_len the maximum length in bytes allowed in the
801  * destination.
802  **/
803 size_t push_ascii(void *dest, const char *src, size_t dest_len, int flags)
804 {
805         size_t src_len = strlen(src);
806         char *tmpbuf = NULL;
807         size_t ret;
808
809         /* No longer allow a length of -1. */
810         if (dest_len == (size_t)-1) {
811                 smb_panic("push_ascii - dest_len == -1");
812         }
813
814         if (flags & STR_UPPER) {
815                 tmpbuf = SMB_STRDUP(src);
816                 if (!tmpbuf) {
817                         smb_panic("malloc fail");
818                 }
819                 strupper_m(tmpbuf);
820                 src = tmpbuf;
821         }
822
823         if (flags & (STR_TERMINATE | STR_TERMINATE_ASCII)) {
824                 src_len++;
825         }
826
827         ret = convert_string(CH_UNIX, CH_DOS, src, src_len, dest, dest_len, True);
828         if (ret == (size_t)-1 &&
829                         (flags & (STR_TERMINATE | STR_TERMINATE_ASCII))
830                         && dest_len > 0) {
831                 ((char *)dest)[0] = '\0';
832         }
833         SAFE_FREE(tmpbuf);
834         return ret;
835 }
836
837 size_t push_ascii_fstring(void *dest, const char *src)
838 {
839         return push_ascii(dest, src, sizeof(fstring), STR_TERMINATE);
840 }
841
842 /********************************************************************
843  Push an nstring - ensure null terminated. Written by
844  moriyama@miraclelinux.com (MORIYAMA Masayuki).
845 ********************************************************************/
846
847 size_t push_ascii_nstring(void *dest, const char *src)
848 {
849         size_t i, buffer_len, dest_len;
850         smb_ucs2_t *buffer;
851
852         conv_silent = True;
853         if (!push_ucs2_talloc(talloc_tos(), &buffer, src, &buffer_len)) {
854                 smb_panic("failed to create UCS2 buffer");
855         }
856
857         /* We're using buffer_len below to count ucs2 characters, not bytes. */
858         buffer_len /= sizeof(smb_ucs2_t);
859
860         dest_len = 0;
861         for (i = 0; buffer[i] != 0 && (i < buffer_len); i++) {
862                 unsigned char mb[10];
863                 /* Convert one smb_ucs2_t character at a time. */
864                 size_t mb_len = convert_string(CH_UTF16LE, CH_DOS, buffer+i, sizeof(smb_ucs2_t), mb, sizeof(mb), False);
865                 if ((mb_len != (size_t)-1) && (dest_len + mb_len <= MAX_NETBIOSNAME_LEN - 1)) {
866                         memcpy((char *)dest + dest_len, mb, mb_len);
867                         dest_len += mb_len;
868                 } else {
869                         errno = E2BIG;
870                         break;
871                 }
872         }
873         ((char *)dest)[dest_len] = '\0';
874
875         conv_silent = False;
876         TALLOC_FREE(buffer);
877         return dest_len;
878 }
879
880 /********************************************************************
881  Push and malloc an ascii string. src and dest null terminated.
882 ********************************************************************/
883
884 bool push_ascii_talloc(TALLOC_CTX *mem_ctx, char **dest, const char *src, size_t *converted_size)
885 {
886         size_t src_len = strlen(src)+1;
887
888         *dest = NULL;
889         return convert_string_talloc(mem_ctx, CH_UNIX, CH_DOS, src, src_len,
890                                      (void **)dest, converted_size, True);
891 }
892
893 /**
894  * Copy a string from a dos codepage source to a unix char* destination.
895  *
896  * The resulting string in "dest" is always null terminated.
897  *
898  * @param flags can have:
899  * <dl>
900  * <dt>STR_TERMINATE</dt>
901  * <dd>STR_TERMINATE means the string in @p src
902  * is null terminated, and src_len is ignored.</dd>
903  * </dl>
904  *
905  * @param src_len is the length of the source area in bytes.
906  * @returns the number of bytes occupied by the string in @p src.
907  **/
908 size_t pull_ascii(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
909 {
910         size_t ret;
911
912         if (dest_len == (size_t)-1) {
913                 /* No longer allow dest_len of -1. */
914                 smb_panic("pull_ascii - invalid dest_len of -1");
915         }
916
917         if (flags & STR_TERMINATE) {
918                 if (src_len == (size_t)-1) {
919                         src_len = strlen((const char *)src) + 1;
920                 } else {
921                         size_t len = strnlen((const char *)src, src_len);
922                         if (len < src_len)
923                                 len++;
924                         src_len = len;
925                 }
926         }
927
928         ret = convert_string(CH_DOS, CH_UNIX, src, src_len, dest, dest_len, True);
929         if (ret == (size_t)-1) {
930                 ret = 0;
931                 dest_len = 0;
932         }
933
934         if (dest_len && ret) {
935                 /* Did we already process the terminating zero ? */
936                 if (dest[MIN(ret-1, dest_len-1)] != 0) {
937                         dest[MIN(ret, dest_len-1)] = 0;
938                 }
939         } else  {
940                 dest[0] = 0;
941         }
942
943         return src_len;
944 }
945
946 /**
947  * Copy a string from a dos codepage source to a unix char* destination.
948  * Talloc version.
949  *
950  * The resulting string in "dest" is always null terminated.
951  *
952  * @param flags can have:
953  * <dl>
954  * <dt>STR_TERMINATE</dt>
955  * <dd>STR_TERMINATE means the string in @p src
956  * is null terminated, and src_len is ignored.</dd>
957  * </dl>
958  *
959  * @param src_len is the length of the source area in bytes.
960  * @returns the number of bytes occupied by the string in @p src.
961  **/
962
963 static size_t pull_ascii_base_talloc(TALLOC_CTX *ctx,
964                                      char **ppdest,
965                                      const void *src,
966                                      size_t src_len,
967                                      int flags)
968 {
969         char *dest = NULL;
970         size_t dest_len;
971
972         *ppdest = NULL;
973
974         if (!src_len) {
975                 return 0;
976         }
977
978         if (flags & STR_TERMINATE) {
979                 if (src_len == (size_t)-1) {
980                         src_len = strlen((const char *)src) + 1;
981                 } else {
982                         size_t len = strnlen((const char *)src, src_len);
983                         if (len < src_len)
984                                 len++;
985                         src_len = len;
986                 }
987                 /* Ensure we don't use an insane length from the client. */
988                 if (src_len >= 1024*1024) {
989                         char *msg = talloc_asprintf(ctx,
990                                         "Bad src length (%u) in "
991                                         "pull_ascii_base_talloc",
992                                         (unsigned int)src_len);
993                         smb_panic(msg);
994                 }
995         } else {
996                 /* Can't have an unlimited length
997                  * non STR_TERMINATE'd.
998                  */
999                 if (src_len == (size_t)-1) {
1000                         errno = EINVAL;
1001                         return 0;
1002                 }
1003         }
1004
1005         /* src_len != -1 here. */
1006
1007         if (!convert_string_talloc(ctx, CH_DOS, CH_UNIX, src, src_len, &dest,
1008                                      &dest_len, True)) {
1009                 dest_len = 0;
1010         }
1011
1012         if (dest_len && dest) {
1013                 /* Did we already process the terminating zero ? */
1014                 if (dest[dest_len-1] != 0) {
1015                         size_t size = talloc_get_size(dest);
1016                         /* Have we got space to append the '\0' ? */
1017                         if (size <= dest_len) {
1018                                 /* No, realloc. */
1019                                 dest = TALLOC_REALLOC_ARRAY(ctx, dest, char,
1020                                                 dest_len+1);
1021                                 if (!dest) {
1022                                         /* talloc fail. */
1023                                         dest_len = (size_t)-1;
1024                                         return 0;
1025                                 }
1026                         }
1027                         /* Yay - space ! */
1028                         dest[dest_len] = '\0';
1029                         dest_len++;
1030                 }
1031         } else if (dest) {
1032                 dest[0] = 0;
1033         }
1034
1035         *ppdest = dest;
1036         return src_len;
1037 }
1038
1039 size_t pull_ascii_fstring(char *dest, const void *src)
1040 {
1041         return pull_ascii(dest, src, sizeof(fstring), -1, STR_TERMINATE);
1042 }
1043
1044 /* When pulling an nstring it can expand into a larger size (dos cp -> utf8). Cope with this. */
1045
1046 size_t pull_ascii_nstring(char *dest, size_t dest_len, const void *src)
1047 {
1048         return pull_ascii(dest, src, dest_len, sizeof(nstring)-1, STR_TERMINATE);
1049 }
1050
1051 /**
1052  * Copy a string from a char* src to a unicode destination.
1053  *
1054  * @returns the number of bytes occupied by the string in the destination.
1055  *
1056  * @param flags can have:
1057  *
1058  * <dl>
1059  * <dt>STR_TERMINATE <dd>means include the null termination.
1060  * <dt>STR_UPPER     <dd>means uppercase in the destination.
1061  * <dt>STR_NOALIGN   <dd>means don't do alignment.
1062  * </dl>
1063  *
1064  * @param dest_len is the maximum length allowed in the
1065  * destination.
1066  **/
1067
1068 size_t push_ucs2(const void *base_ptr, void *dest, const char *src, size_t dest_len, int flags)
1069 {
1070         size_t len=0;
1071         size_t src_len;
1072         size_t ret;
1073
1074         if (dest_len == (size_t)-1) {
1075                 /* No longer allow dest_len of -1. */
1076                 smb_panic("push_ucs2 - invalid dest_len of -1");
1077         }
1078
1079         if (flags & STR_TERMINATE)
1080                 src_len = (size_t)-1;
1081         else
1082                 src_len = strlen(src);
1083
1084         if (ucs2_align(base_ptr, dest, flags)) {
1085                 *(char *)dest = 0;
1086                 dest = (void *)((char *)dest + 1);
1087                 if (dest_len)
1088                         dest_len--;
1089                 len++;
1090         }
1091
1092         /* ucs2 is always a multiple of 2 bytes */
1093         dest_len &= ~1;
1094
1095         ret =  convert_string(CH_UNIX, CH_UTF16LE, src, src_len, dest, dest_len, True);
1096         if (ret == (size_t)-1) {
1097                 if ((flags & STR_TERMINATE) &&
1098                                 dest &&
1099                                 dest_len) {
1100                         *(char *)dest = 0;
1101                 }
1102                 return len;
1103         }
1104
1105         len += ret;
1106
1107         if (flags & STR_UPPER) {
1108                 smb_ucs2_t *dest_ucs2 = (smb_ucs2_t *)dest;
1109                 size_t i;
1110
1111                 /* We check for i < (ret / 2) below as the dest string isn't null
1112                    terminated if STR_TERMINATE isn't set. */
1113
1114                 for (i = 0; i < (ret / 2) && i < (dest_len / 2) && dest_ucs2[i]; i++) {
1115                         smb_ucs2_t v = toupper_m(dest_ucs2[i]);
1116                         if (v != dest_ucs2[i]) {
1117                                 dest_ucs2[i] = v;
1118                         }
1119                 }
1120         }
1121
1122         return len;
1123 }
1124
1125
1126 /**
1127  * Copy a string from a unix char* src to a UCS2 destination,
1128  * allocating a buffer using talloc().
1129  *
1130  * @param dest always set at least to NULL 
1131  * @parm converted_size set to the number of bytes occupied by the string in
1132  * the destination on success.
1133  *
1134  * @return true if new buffer was correctly allocated, and string was
1135  * converted.
1136  **/
1137 bool push_ucs2_talloc(TALLOC_CTX *ctx, smb_ucs2_t **dest, const char *src,
1138                       size_t *converted_size)
1139 {
1140         size_t src_len = strlen(src)+1;
1141
1142         *dest = NULL;
1143         return convert_string_talloc(ctx, CH_UNIX, CH_UTF16LE, src, src_len,
1144                                      (void **)dest, converted_size, True);
1145 }
1146
1147
1148 /**
1149  Copy a string from a char* src to a UTF-8 destination.
1150  Return the number of bytes occupied by the string in the destination
1151  Flags can have:
1152   STR_TERMINATE means include the null termination
1153   STR_UPPER     means uppercase in the destination
1154  dest_len is the maximum length allowed in the destination. If dest_len
1155  is -1 then no maxiumum is used.
1156 **/
1157
1158 static size_t push_utf8(void *dest, const char *src, size_t dest_len, int flags)
1159 {
1160         size_t src_len = 0;
1161         size_t ret;
1162         char *tmpbuf = NULL;
1163
1164         if (dest_len == (size_t)-1) {
1165                 /* No longer allow dest_len of -1. */
1166                 smb_panic("push_utf8 - invalid dest_len of -1");
1167         }
1168
1169         if (flags & STR_UPPER) {
1170                 tmpbuf = strupper_talloc(talloc_tos(), src);
1171                 if (!tmpbuf) {
1172                         return (size_t)-1;
1173                 }
1174                 src = tmpbuf;
1175                 src_len = strlen(src);
1176         }
1177
1178         src_len = strlen(src);
1179         if (flags & STR_TERMINATE) {
1180                 src_len++;
1181         }
1182
1183         ret = convert_string(CH_UNIX, CH_UTF8, src, src_len, dest, dest_len, True);
1184         TALLOC_FREE(tmpbuf);
1185         return ret;
1186 }
1187
1188 size_t push_utf8_fstring(void *dest, const char *src)
1189 {
1190         return push_utf8(dest, src, sizeof(fstring), STR_TERMINATE);
1191 }
1192
1193 /**
1194  * Copy a string from a unix char* src to a UTF-8 destination, allocating a buffer using talloc
1195  *
1196  * @param dest always set at least to NULL 
1197  * @parm converted_size set to the number of bytes occupied by the string in
1198  * the destination on success.
1199  *
1200  * @return true if new buffer was correctly allocated, and string was
1201  * converted.
1202  **/
1203
1204 bool push_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src,
1205                       size_t *converted_size)
1206 {
1207         size_t src_len = strlen(src)+1;
1208
1209         *dest = NULL;
1210         return convert_string_talloc(ctx, CH_UNIX, CH_UTF8, src, src_len,
1211                                      (void**)dest, converted_size, True);
1212 }
1213
1214 /**
1215  Copy a string from a ucs2 source to a unix char* destination.
1216  Flags can have:
1217   STR_TERMINATE means the string in src is null terminated.
1218   STR_NOALIGN   means don't try to align.
1219  if STR_TERMINATE is set then src_len is ignored if it is -1.
1220  src_len is the length of the source area in bytes
1221  Return the number of bytes occupied by the string in src.
1222  The resulting string in "dest" is always null terminated.
1223 **/
1224
1225 size_t pull_ucs2(const void *base_ptr, char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
1226 {
1227         size_t ret;
1228
1229         if (dest_len == (size_t)-1) {
1230                 /* No longer allow dest_len of -1. */
1231                 smb_panic("pull_ucs2 - invalid dest_len of -1");
1232         }
1233
1234         if (!src_len) {
1235                 if (dest && dest_len > 0) {
1236                         dest[0] = '\0';
1237                 }
1238                 return 0;
1239         }
1240
1241         if (ucs2_align(base_ptr, src, flags)) {
1242                 src = (const void *)((const char *)src + 1);
1243                 if (src_len != (size_t)-1)
1244                         src_len--;
1245         }
1246
1247         if (flags & STR_TERMINATE) {
1248                 /* src_len -1 is the default for null terminated strings. */
1249                 if (src_len != (size_t)-1) {
1250                         size_t len = strnlen_w((const smb_ucs2_t *)src,
1251                                                 src_len/2);
1252                         if (len < src_len/2)
1253                                 len++;
1254                         src_len = len*2;
1255                 }
1256         }
1257
1258         /* ucs2 is always a multiple of 2 bytes */
1259         if (src_len != (size_t)-1)
1260                 src_len &= ~1;
1261
1262         ret = convert_string(CH_UTF16LE, CH_UNIX, src, src_len, dest, dest_len, True);
1263         if (ret == (size_t)-1) {
1264                 ret = 0;
1265                 dest_len = 0;
1266         }
1267
1268         if (src_len == (size_t)-1)
1269                 src_len = ret*2;
1270
1271         if (dest_len && ret) {
1272                 /* Did we already process the terminating zero ? */
1273                 if (dest[MIN(ret-1, dest_len-1)] != 0) {
1274                         dest[MIN(ret, dest_len-1)] = 0;
1275                 }
1276         } else {
1277                 dest[0] = 0;
1278         }
1279
1280         return src_len;
1281 }
1282
1283 /**
1284  Copy a string from a ucs2 source to a unix char* destination.
1285  Talloc version with a base pointer.
1286  Uses malloc if TALLOC_CTX is NULL (this is a bad interface and
1287  needs fixing. JRA).
1288  Flags can have:
1289   STR_TERMINATE means the string in src is null terminated.
1290   STR_NOALIGN   means don't try to align.
1291  if STR_TERMINATE is set then src_len is ignored if it is -1.
1292  src_len is the length of the source area in bytes
1293  Return the number of bytes occupied by the string in src.
1294  The resulting string in "dest" is always null terminated.
1295 **/
1296
1297 size_t pull_ucs2_base_talloc(TALLOC_CTX *ctx,
1298                         const void *base_ptr,
1299                         char **ppdest,
1300                         const void *src,
1301                         size_t src_len,
1302                         int flags)
1303 {
1304         char *dest;
1305         size_t dest_len;
1306
1307         *ppdest = NULL;
1308
1309 #ifdef DEVELOPER
1310         /* Ensure we never use the braindead "malloc" varient. */
1311         if (ctx == NULL) {
1312                 smb_panic("NULL talloc CTX in pull_ucs2_base_talloc\n");
1313         }
1314 #endif
1315
1316         if (!src_len) {
1317                 return 0;
1318         }
1319
1320         if (ucs2_align(base_ptr, src, flags)) {
1321                 src = (const void *)((const char *)src + 1);
1322                 if (src_len != (size_t)-1)
1323                         src_len--;
1324         }
1325
1326         if (flags & STR_TERMINATE) {
1327                 /* src_len -1 is the default for null terminated strings. */
1328                 if (src_len != (size_t)-1) {
1329                         size_t len = strnlen_w((const smb_ucs2_t *)src,
1330                                                 src_len/2);
1331                         if (len < src_len/2)
1332                                 len++;
1333                         src_len = len*2;
1334                 } else {
1335                         /*
1336                          * src_len == -1 - alloc interface won't take this
1337                          * so we must calculate.
1338                          */
1339                         src_len = (strlen_w((const smb_ucs2_t *)src)+1)*sizeof(smb_ucs2_t);
1340                 }
1341                 /* Ensure we don't use an insane length from the client. */
1342                 if (src_len >= 1024*1024) {
1343                         smb_panic("Bad src length in pull_ucs2_base_talloc\n");
1344                 }
1345         } else {
1346                 /* Can't have an unlimited length
1347                  * non STR_TERMINATE'd.
1348                  */
1349                 if (src_len == (size_t)-1) {
1350                         errno = EINVAL;
1351                         return 0;
1352                 }
1353         }
1354
1355         /* src_len != -1 here. */
1356
1357         /* ucs2 is always a multiple of 2 bytes */
1358         src_len &= ~1;
1359
1360         if (!convert_string_talloc(ctx, CH_UTF16LE, CH_UNIX, src, src_len,
1361                                    (void *)&dest, &dest_len, True)) {
1362                 dest_len = 0;
1363         }
1364
1365         if (dest_len) {
1366                 /* Did we already process the terminating zero ? */
1367                 if (dest[dest_len-1] != 0) {
1368                         size_t size = talloc_get_size(dest);
1369                         /* Have we got space to append the '\0' ? */
1370                         if (size <= dest_len) {
1371                                 /* No, realloc. */
1372                                 dest = TALLOC_REALLOC_ARRAY(ctx, dest, char,
1373                                                 dest_len+1);
1374                                 if (!dest) {
1375                                         /* talloc fail. */
1376                                         dest_len = (size_t)-1;
1377                                         return 0;
1378                                 }
1379                         }
1380                         /* Yay - space ! */
1381                         dest[dest_len] = '\0';
1382                         dest_len++;
1383                 }
1384         } else if (dest) {
1385                 dest[0] = 0;
1386         }
1387
1388         *ppdest = dest;
1389         return src_len;
1390 }
1391
1392 size_t pull_ucs2_fstring(char *dest, const void *src)
1393 {
1394         return pull_ucs2(NULL, dest, src, sizeof(fstring), -1, STR_TERMINATE);
1395 }
1396
1397 /**
1398  * Copy a string from a UCS2 src to a unix char * destination, allocating a buffer using talloc
1399  *
1400  * @param dest always set at least to NULL 
1401  * @parm converted_size set to the number of bytes occupied by the string in
1402  * the destination on success.
1403  *
1404  * @return true if new buffer was correctly allocated, and string was
1405  * converted.
1406  **/
1407
1408 bool pull_ucs2_talloc(TALLOC_CTX *ctx, char **dest, const smb_ucs2_t *src,
1409                       size_t *converted_size)
1410 {
1411         size_t src_len = (strlen_w(src)+1) * sizeof(smb_ucs2_t);
1412
1413         *dest = NULL;
1414         return convert_string_talloc(ctx, CH_UTF16LE, CH_UNIX, src, src_len,
1415                                      (void **)dest, converted_size, True);
1416 }
1417
1418 /**
1419  * Copy a string from a UTF-8 src to a unix char * destination, allocating a buffer using talloc
1420  *
1421  * @param dest always set at least to NULL 
1422  * @parm converted_size set to the number of bytes occupied by the string in
1423  * the destination on success.
1424  *
1425  * @return true if new buffer was correctly allocated, and string was
1426  * converted.
1427  **/
1428
1429 bool pull_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src,
1430                       size_t *converted_size)
1431 {
1432         size_t src_len = strlen(src)+1;
1433
1434         *dest = NULL;
1435         return convert_string_talloc(ctx, CH_UTF8, CH_UNIX, src, src_len,
1436                                      (void **)dest, converted_size, True);
1437 }
1438
1439  
1440 /**
1441  * Copy a string from a DOS src to a unix char * destination, allocating a buffer using talloc
1442  *
1443  * @param dest always set at least to NULL 
1444  * @parm converted_size set to the number of bytes occupied by the string in
1445  * the destination on success.
1446  *
1447  * @return true if new buffer was correctly allocated, and string was
1448  * converted.
1449  **/
1450
1451 bool pull_ascii_talloc(TALLOC_CTX *ctx, char **dest, const char *src,
1452                        size_t *converted_size)
1453 {
1454         size_t src_len = strlen(src)+1;
1455
1456         *dest = NULL;
1457         return convert_string_talloc(ctx, CH_DOS, CH_UNIX, src, src_len,
1458                                      (void **)dest, converted_size, True);
1459 }
1460
1461 /**
1462  Copy a string from a char* src to a unicode or ascii
1463  dos codepage destination choosing unicode or ascii based on the 
1464  flags supplied
1465  Return the number of bytes occupied by the string in the destination.
1466  flags can have:
1467   STR_TERMINATE means include the null termination.
1468   STR_UPPER     means uppercase in the destination.
1469   STR_ASCII     use ascii even with unicode packet.
1470   STR_NOALIGN   means don't do alignment.
1471  dest_len is the maximum length allowed in the destination. If dest_len
1472  is -1 then no maxiumum is used.
1473 **/
1474
1475 size_t push_string_check_fn(const char *function, unsigned int line,
1476                             void *dest, const char *src,
1477                             size_t dest_len, int flags)
1478 {
1479 #ifdef DEVELOPER
1480         /* We really need to zero fill here, not clobber
1481          * region, as we want to ensure that valgrind thinks
1482          * all of the outgoing buffer has been written to
1483          * so a send() or write() won't trap an error.
1484          * JRA.
1485          */
1486 #if 0
1487         clobber_region(function, line, dest, dest_len);
1488 #else
1489         memset(dest, '\0', dest_len);
1490 #endif
1491 #endif
1492
1493         if (!(flags & STR_ASCII) && (flags & STR_UNICODE)) {
1494                 return push_ucs2(NULL, dest, src, dest_len, flags);
1495         }
1496         return push_ascii(dest, src, dest_len, flags);
1497 }
1498
1499
1500 /**
1501  Copy a string from a char* src to a unicode or ascii
1502  dos codepage destination choosing unicode or ascii based on the 
1503  flags in the SMB buffer starting at base_ptr.
1504  Return the number of bytes occupied by the string in the destination.
1505  flags can have:
1506   STR_TERMINATE means include the null termination.
1507   STR_UPPER     means uppercase in the destination.
1508   STR_ASCII     use ascii even with unicode packet.
1509   STR_NOALIGN   means don't do alignment.
1510  dest_len is the maximum length allowed in the destination. If dest_len
1511  is -1 then no maxiumum is used.
1512 **/
1513
1514 size_t push_string_base(const char *function, unsigned int line,
1515                         const char *base, uint16 flags2, 
1516                         void *dest, const char *src,
1517                         size_t dest_len, int flags)
1518 {
1519 #ifdef DEVELOPER
1520         /* We really need to zero fill here, not clobber
1521          * region, as we want to ensure that valgrind thinks
1522          * all of the outgoing buffer has been written to
1523          * so a send() or write() won't trap an error.
1524          * JRA.
1525          */
1526 #if 0
1527         clobber_region(function, line, dest, dest_len);
1528 #else
1529         memset(dest, '\0', dest_len);
1530 #endif
1531 #endif
1532
1533         if (!(flags & STR_ASCII) && \
1534             ((flags & STR_UNICODE || \
1535               (flags2 & FLAGS2_UNICODE_STRINGS)))) {
1536                 return push_ucs2(base, dest, src, dest_len, flags);
1537         }
1538         return push_ascii(dest, src, dest_len, flags);
1539 }
1540
1541 /**
1542  Copy a string from a char* src to a unicode or ascii
1543  dos codepage destination choosing unicode or ascii based on the 
1544  flags supplied
1545  Return the number of bytes occupied by the string in the destination.
1546  flags can have:
1547   STR_TERMINATE means include the null termination.
1548   STR_UPPER     means uppercase in the destination.
1549   STR_ASCII     use ascii even with unicode packet.
1550   STR_NOALIGN   means don't do alignment.
1551  dest_len is the maximum length allowed in the destination. If dest_len
1552  is -1 then no maxiumum is used.
1553 **/
1554
1555 ssize_t push_string(void *dest, const char *src, size_t dest_len, int flags)
1556 {
1557         size_t ret;
1558 #ifdef DEVELOPER
1559         /* We really need to zero fill here, not clobber
1560          * region, as we want to ensure that valgrind thinks
1561          * all of the outgoing buffer has been written to
1562          * so a send() or write() won't trap an error.
1563          * JRA.
1564          */
1565         memset(dest, '\0', dest_len);
1566 #endif
1567
1568         if (!(flags & STR_ASCII) && \
1569             (flags & STR_UNICODE)) {
1570                 ret = push_ucs2(NULL, dest, src, dest_len, flags);
1571         } else {
1572                 ret = push_ascii(dest, src, dest_len, flags);
1573         }
1574         if (ret == (size_t)-1) {
1575                 return -1;
1576         }
1577         return ret;
1578 }
1579
1580 /**
1581  Copy a string from a unicode or ascii source (depending on
1582  the packet flags) to a char* destination.
1583  Flags can have:
1584   STR_TERMINATE means the string in src is null terminated.
1585   STR_UNICODE   means to force as unicode.
1586   STR_ASCII     use ascii even with unicode packet.
1587   STR_NOALIGN   means don't do alignment.
1588  if STR_TERMINATE is set then src_len is ignored is it is -1
1589  src_len is the length of the source area in bytes.
1590  Return the number of bytes occupied by the string in src.
1591  The resulting string in "dest" is always null terminated.
1592 **/
1593
1594 size_t pull_string_fn(const char *function,
1595                         unsigned int line,
1596                         const void *base_ptr,
1597                         uint16 smb_flags2,
1598                         char *dest,
1599                         const void *src,
1600                         size_t dest_len,
1601                         size_t src_len,
1602                         int flags)
1603 {
1604 #ifdef DEVELOPER
1605         clobber_region(function, line, dest, dest_len);
1606 #endif
1607
1608         if ((base_ptr == NULL) && ((flags & (STR_ASCII|STR_UNICODE)) == 0)) {
1609                 smb_panic("No base ptr to get flg2 and neither ASCII nor "
1610                           "UNICODE defined");
1611         }
1612
1613         if (!(flags & STR_ASCII) && \
1614             ((flags & STR_UNICODE || \
1615               (smb_flags2 & FLAGS2_UNICODE_STRINGS)))) {
1616                 return pull_ucs2(base_ptr, dest, src, dest_len, src_len, flags);
1617         }
1618         return pull_ascii(dest, src, dest_len, src_len, flags);
1619 }
1620
1621 /**
1622  Copy a string from a unicode or ascii source (depending on
1623  the packet flags) to a char* destination.
1624  Variant that uses talloc.
1625  Flags can have:
1626   STR_TERMINATE means the string in src is null terminated.
1627   STR_UNICODE   means to force as unicode.
1628   STR_ASCII     use ascii even with unicode packet.
1629   STR_NOALIGN   means don't do alignment.
1630  if STR_TERMINATE is set then src_len is ignored is it is -1
1631  src_len is the length of the source area in bytes.
1632  Return the number of bytes occupied by the string in src.
1633  The resulting string in "dest" is always null terminated.
1634 **/
1635
1636 size_t pull_string_talloc_fn(const char *function,
1637                         unsigned int line,
1638                         TALLOC_CTX *ctx,
1639                         const void *base_ptr,
1640                         uint16 smb_flags2,
1641                         char **ppdest,
1642                         const void *src,
1643                         size_t src_len,
1644                         int flags)
1645 {
1646         if ((base_ptr == NULL) && ((flags & (STR_ASCII|STR_UNICODE)) == 0)) {
1647                 smb_panic("No base ptr to get flg2 and neither ASCII nor "
1648                           "UNICODE defined");
1649         }
1650
1651         if (!(flags & STR_ASCII) && \
1652             ((flags & STR_UNICODE || \
1653               (smb_flags2 & FLAGS2_UNICODE_STRINGS)))) {
1654                 return pull_ucs2_base_talloc(ctx,
1655                                         base_ptr,
1656                                         ppdest,
1657                                         src,
1658                                         src_len,
1659                                         flags);
1660         }
1661         return pull_ascii_base_talloc(ctx,
1662                                         ppdest,
1663                                         src,
1664                                         src_len,
1665                                         flags);
1666 }
1667
1668
1669 size_t align_string(const void *base_ptr, const char *p, int flags)
1670 {
1671         if (!(flags & STR_ASCII) && \
1672             ((flags & STR_UNICODE || \
1673               (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
1674                 return ucs2_align(base_ptr, p, flags);
1675         }
1676         return 0;
1677 }
1678