Remove convert_string_internal completely from fast path when processing
[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 2 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, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
23 */
24 #include "includes.h"
25
26 /**
27  * @file
28  *
29  * @brief Character-set conversion routines built on our iconv.
30  * 
31  * @note Samba's internal character set (at least in the 3.0 series)
32  * is always the same as the one for the Unix filesystem.  It is
33  * <b>not</b> necessarily UTF-8 and may be different on machines that
34  * need i18n filenames to be compatible with Unix software.  It does
35  * have to be a superset of ASCII.  All multibyte sequences must start
36  * with a byte with the high bit set.
37  *
38  * @sa lib/iconv.c
39  */
40
41
42 static smb_iconv_t conv_handles[NUM_CHARSETS][NUM_CHARSETS];
43 static BOOL conv_silent; /* Should we do a debug if the conversion fails ? */
44
45 /**
46  * Return the name of a charset to give to iconv().
47  **/
48 static const char *charset_name(charset_t ch)
49 {
50         const char *ret = NULL;
51
52         if (ch == CH_UCS2) ret = "UCS-2LE";
53         else if (ch == CH_UNIX) ret = lp_unix_charset();
54         else if (ch == CH_DOS) ret = lp_dos_charset();
55         else if (ch == CH_DISPLAY) ret = lp_display_charset();
56         else if (ch == CH_UTF8) ret = "UTF8";
57
58 #if defined(HAVE_NL_LANGINFO) && defined(CODESET)
59         if (ret && strcasecmp(ret, "LOCALE") == 0) {
60                 const char *ln = NULL;
61
62 #ifdef HAVE_SETLOCALE
63                 setlocale(LC_ALL, "");
64 #endif
65                 ln = nl_langinfo(CODESET);
66                 if (ln) {
67                         /* Check whether the charset name is supported
68                            by iconv */
69                         smb_iconv_t handle = smb_iconv_open(ln,"UCS-2LE");
70                         if (handle == (smb_iconv_t) -1) {
71                                 DEBUG(5,("Locale charset '%s' unsupported, using ASCII instead\n", ln));
72                                 ln = NULL;
73                         } else {
74                                 DEBUG(5,("Substituting charset '%s' for LOCALE\n", ln));
75                                 smb_iconv_close(handle);
76                         }
77                 }
78                 ret = ln;
79         }
80 #endif
81
82         if (!ret || !*ret) ret = "ASCII";
83         return ret;
84 }
85
86 void lazy_initialize_conv(void)
87 {
88         static int initialized = False;
89
90         if (!initialized) {
91                 initialized = True;
92                 load_case_tables();
93                 init_iconv();
94         }
95 }
96
97 /**
98  * Initialize iconv conversion descriptors.
99  *
100  * This is called the first time it is needed, and also called again
101  * every time the configuration is reloaded, because the charset or
102  * codepage might have changed.
103  **/
104 void init_iconv(void)
105 {
106         int c1, c2;
107         BOOL did_reload = False;
108
109         /* so that charset_name() works we need to get the UNIX<->UCS2 going
110            first */
111         if (!conv_handles[CH_UNIX][CH_UCS2])
112                 conv_handles[CH_UNIX][CH_UCS2] = smb_iconv_open("UCS-2LE", "ASCII");
113
114         if (!conv_handles[CH_UCS2][CH_UNIX])
115                 conv_handles[CH_UCS2][CH_UNIX] = smb_iconv_open("ASCII", "UCS-2LE");
116
117         for (c1=0;c1<NUM_CHARSETS;c1++) {
118                 for (c2=0;c2<NUM_CHARSETS;c2++) {
119                         const char *n1 = charset_name((charset_t)c1);
120                         const char *n2 = charset_name((charset_t)c2);
121                         if (conv_handles[c1][c2] &&
122                             strcmp(n1, conv_handles[c1][c2]->from_name) == 0 &&
123                             strcmp(n2, conv_handles[c1][c2]->to_name) == 0)
124                                 continue;
125
126                         did_reload = True;
127
128                         if (conv_handles[c1][c2])
129                                 smb_iconv_close(conv_handles[c1][c2]);
130
131                         conv_handles[c1][c2] = smb_iconv_open(n2,n1);
132                         if (conv_handles[c1][c2] == (smb_iconv_t)-1) {
133                                 DEBUG(0,("Conversion from %s to %s not supported\n",
134                                          charset_name((charset_t)c1), charset_name((charset_t)c2)));
135                                 conv_handles[c1][c2] = NULL;
136                         }
137                 }
138         }
139
140         if (did_reload) {
141                 /* XXX: Does this really get called every time the dos
142                  * codepage changes? */
143                 /* XXX: Is the did_reload test too strict? */
144                 conv_silent = True;
145                 init_doschar_table();
146                 init_valid_table();
147                 conv_silent = False;
148         }
149 }
150
151 /**
152  * Convert string from one encoding to another, making error checking etc
153  * Slow path version - uses (slow) iconv.
154  *
155  * @param src pointer to source string (multibyte or singlebyte)
156  * @param srclen length of the source string in bytes
157  * @param dest pointer to destination string (multibyte or singlebyte)
158  * @param destlen maximal length allowed for string
159  * @returns the number of bytes occupied in the destination
160  *
161  * Ensure the srclen contains the terminating zero.
162  *
163  **/
164
165 static size_t convert_string_internal(charset_t from, charset_t to,
166                       void const *src, size_t srclen, 
167                       void *dest, size_t destlen)
168 {
169         size_t i_len, o_len;
170         size_t retval;
171         const char* inbuf = (const char*)src;
172         char* outbuf = (char*)dest;
173         smb_iconv_t descriptor;
174
175         lazy_initialize_conv();
176
177         descriptor = conv_handles[from][to];
178
179         if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
180                 if (!conv_silent)
181                         DEBUG(0,("convert_string_internal: Conversion not supported.\n"));
182                 goto use_as_is;
183         }
184
185         i_len=srclen;
186         o_len=destlen;
187         retval = smb_iconv(descriptor,  &inbuf, &i_len, &outbuf, &o_len);
188         if(retval==(size_t)-1) {
189                 const char *reason="unknown error";
190                 switch(errno) {
191                         case EINVAL:
192                                 reason="Incomplete multibyte sequence";
193                                 if (!conv_silent)
194                                         DEBUG(3,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf));
195                                 goto use_as_is;
196                         case E2BIG:
197                                 reason="No more room"; 
198                                 if (!conv_silent)
199                                         DEBUG(3, ("convert_string_internal: Required %lu, available %lu\n",
200                                                 (unsigned long)srclen, (unsigned long)destlen));
201                                 /* we are not sure we need srclen bytes,
202                                   may be more, may be less.
203                                   We only know we need more than destlen
204                                   bytes ---simo */
205                                break;
206                         case EILSEQ:
207                                 reason="Illegal multibyte sequence";
208                                 if (!conv_silent)
209                                         DEBUG(3,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf));
210                                 goto use_as_is;
211                         default:
212                                 if (!conv_silent)
213                                         DEBUG(0,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf));
214                                 break;
215                 }
216                 /* smb_panic(reason); */
217         }
218         return destlen-o_len;
219
220  use_as_is:
221
222         /* conversion not supported, use as is */
223         {
224                 size_t len = MIN(srclen,destlen);
225                 if (len)
226                         memcpy(dest,src,len);
227                 return len;
228         }
229 }
230
231 /**
232  * Convert string from one encoding to another, making error checking etc
233  * Fast path version - handles ASCII first.
234  *
235  * @param src pointer to source string (multibyte or singlebyte)
236  * @param srclen length of the source string in bytes
237  * @param dest pointer to destination string (multibyte or singlebyte)
238  * @param destlen maximal length allowed for string
239  * @returns the number of bytes occupied in the destination
240  *
241  * Ensure the srclen contains the terminating zero.
242  *
243  **/
244
245 size_t convert_string(charset_t from, charset_t to,
246                       void const *src, size_t srclen, 
247                       void *dest, size_t destlen)
248 {
249         if (srclen == (size_t)-1) {
250                 if (from == CH_UCS2)
251                         srclen = strlen_w(src)+2;
252                 else
253                         srclen = strlen(src)+1;
254         }
255         if (srclen == 0)
256                 return 0;
257
258         if (from != CH_UCS2 && to != CH_UCS2) {
259                 const unsigned char *p = (const unsigned char *)src;
260                 unsigned char *q = (unsigned char *)dest;
261                 unsigned char lastp;
262                 size_t retval = 0;
263
264                 /* If all characters are ascii, fast path here. */
265                 while (srclen && destlen) {
266                         if ((lastp = *p) <= 0x7f) {
267                                 *q++ = *p++;
268                                 srclen--;
269                                 destlen--;
270                                 retval++;
271                                 if (!lastp)
272                                         break;
273                         } else {
274                                 return retval + convert_string_internal(from, to, p, srclen, q, destlen);
275                         }
276                 }
277                 return retval;
278         } else if (from == CH_UCS2 && to != CH_UCS2) {
279                 const unsigned char *p = (const unsigned char *)src;
280                 unsigned char *q = (unsigned char *)dest;
281                 size_t retval = 0;
282                 unsigned char lastp;
283
284                 /* If all characters are ascii, fast path here. */
285                 while ((srclen >= 2) && destlen) {
286                         if ((lastp = *p) <= 0x7f && p[1] == 0) {
287                                 *q++ = *p;
288                                 srclen -= 2;
289                                 p += 2;
290                                 destlen--;
291                                 retval++;
292                                 if (!lastp)
293                                         break;
294                         } else {
295                                 return retval + convert_string_internal(from, to, p, srclen, q, destlen);
296                         }
297                 }
298                 return retval;
299         } else if (from != CH_UCS2 && to == CH_UCS2) {
300                 const unsigned char *p = (const unsigned char *)src;
301                 unsigned char *q = (unsigned char *)dest;
302                 size_t retval = 0;
303                 unsigned char lastp;
304
305                 /* If all characters are ascii, fast path here. */
306                 while (srclen && (destlen >= 2)) {
307                         if ((lastp = *p) <= 0x7F) {
308                                 *q++ = *p++;
309                                 *q++ = '\0';
310                                 srclen--;
311                                 destlen -= 2;
312                                 retval += 2;
313                                 if (!lastp)
314                                         break;
315                         } else {
316                                 return retval + convert_string_internal(from, to, p, srclen, q, destlen);
317                         }
318                 }
319                 return retval;
320         }
321         return convert_string_internal(from, to, src, srclen, dest, destlen);
322 }
323
324 /**
325  * Convert between character sets, allocating a new buffer for the result.
326  *
327  * @param ctx TALLOC_CTX to use to allocate with. If NULL use malloc.
328  * @param srclen length of source buffer.
329  * @param dest always set at least to NULL
330  * @note -1 is not accepted for srclen.
331  *
332  * @returns Size in bytes of the converted string; or -1 in case of error.
333  *
334  * Ensure the srclen contains the terminating zero.
335  **/
336
337 size_t convert_string_allocate(TALLOC_CTX *ctx, charset_t from, charset_t to,
338                                void const *src, size_t srclen, void **dest)
339 {
340         size_t i_len, o_len, destlen = MAX(srclen, 512);
341         size_t retval;
342         const char *inbuf = (const char *)src;
343         char *outbuf = NULL, *ob = NULL;
344         smb_iconv_t descriptor;
345
346         *dest = NULL;
347
348         if (src == NULL || srclen == (size_t)-1)
349                 return (size_t)-1;
350         if (srclen == 0)
351                 return 0;
352
353         lazy_initialize_conv();
354
355         descriptor = conv_handles[from][to];
356
357         if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
358                 if (!conv_silent)
359                         DEBUG(0,("convert_string_allocate: Conversion not supported.\n"));
360                 goto use_as_is;
361         }
362
363 convert:
364         if ((destlen*2) < destlen) {
365                 /* wrapped ! abort. */
366                 if (!conv_silent)
367                         DEBUG(0, ("convert_string_allocate: destlen wrapped !\n"));
368                 if (!ctx)
369                         SAFE_FREE(outbuf);
370                 return (size_t)-1;
371         } else {
372                 destlen = destlen * 2;
373         }
374
375         if (ctx)
376                 ob = (char *)talloc_realloc(ctx, ob, destlen);
377         else
378                 ob = (char *)Realloc(ob, destlen);
379
380         if (!ob) {
381                 DEBUG(0, ("convert_string_allocate: realloc failed!\n"));
382                 if (!ctx)
383                         SAFE_FREE(outbuf);
384                 return (size_t)-1;
385         } else {
386                 outbuf = ob;
387         }
388         i_len = srclen;
389         o_len = destlen;
390         retval = smb_iconv(descriptor,
391                            &inbuf, &i_len,
392                            &outbuf, &o_len);
393         if(retval == (size_t)-1)                {
394                 const char *reason="unknown error";
395                 switch(errno) {
396                         case EINVAL:
397                                 reason="Incomplete multibyte sequence";
398                                 if (!conv_silent)
399                                         DEBUG(3,("convert_string_allocate: Conversion error: %s(%s)\n",reason,inbuf));
400                                 goto use_as_is;
401                         case E2BIG:
402                                 goto convert;           
403                         case EILSEQ:
404                                 reason="Illegal multibyte sequence";
405                                 if (!conv_silent)
406                                         DEBUG(3,("convert_string_allocate: Conversion error: %s(%s)\n",reason,inbuf));
407                                 goto use_as_is;
408                 }
409                 if (!conv_silent)
410                         DEBUG(0,("Conversion error: %s(%s)\n",reason,inbuf));
411                 /* smb_panic(reason); */
412                 return (size_t)-1;
413         }
414         
415         destlen = destlen - o_len;
416         if (ctx)
417                 *dest = (char *)talloc_realloc(ctx,ob,destlen);
418         else
419                 *dest = (char *)Realloc(ob,destlen);
420         if (destlen && !*dest) {
421                 DEBUG(0, ("convert_string_allocate: out of memory!\n"));
422                 if (!ctx)
423                         SAFE_FREE(ob);
424                 return (size_t)-1;
425         }
426
427         return destlen;
428
429   use_as_is:
430
431         /* conversion not supported, use as is */
432         {
433                 if (srclen && (destlen != srclen)) {
434                         destlen = srclen;
435                         if (ctx)
436                                 ob = (char *)talloc_realloc(ctx, ob, destlen);
437                         else
438                                 ob = (char *)Realloc(ob, destlen);
439                         if (!ob) {
440                                 DEBUG(0, ("convert_string_allocate: realloc failed!\n"));
441                                 if (!ctx)
442                                         SAFE_FREE(outbuf);
443                                 return (size_t)-1;
444                         }
445                 }
446                 if (srclen && ob)
447                         memcpy(ob,(const char *)src,srclen);
448                 *dest = (char *)ob;
449                 return srclen;
450         }
451 }
452
453
454 /**
455  * Convert between character sets, allocating a new buffer using talloc for the result.
456  *
457  * @param srclen length of source buffer.
458  * @param dest always set at least to NULL 
459  * @note -1 is not accepted for srclen.
460  *
461  * @returns Size in bytes of the converted string; or -1 in case of error.
462  **/
463 static size_t convert_string_talloc(TALLOC_CTX *ctx, charset_t from, charset_t to,
464                                 void const *src, size_t srclen, void **dest)
465 {
466         size_t dest_len;
467
468         *dest = NULL;
469         dest_len=convert_string_allocate(ctx, from, to, src, srclen, dest);
470         if (dest_len == (size_t)-1)
471                 return (size_t)-1;
472         if (*dest == NULL)
473                 return (size_t)-1;
474         return dest_len;
475 }
476
477 size_t unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen)
478 {
479         size_t size;
480         smb_ucs2_t *buffer;
481         
482         size = push_ucs2_allocate(&buffer, src);
483         if (size == -1) {
484                 smb_panic("failed to create UCS2 buffer");
485         }
486         if (!strupper_w(buffer) && (dest == src)) {
487                 free(buffer);
488                 return srclen;
489         }
490         
491         size = convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen);
492         free(buffer);
493         return size;
494 }
495
496 /**
497  strdup() a unix string to upper case.
498  Max size is pstring.
499 **/
500
501 char *strdup_upper(const char *s)
502 {
503         size_t size;
504         wpstring buffer;
505         pstring out_buffer;
506         
507         size = convert_string(CH_UNIX, CH_UCS2, s, -1, buffer, sizeof(buffer));
508         if (size == -1) {
509                 return NULL;
510         }
511
512         strupper_w(buffer);
513         
514         size = convert_string(CH_UCS2, CH_UNIX, buffer, sizeof(buffer), out_buffer, sizeof(out_buffer));
515         if (size == -1) {
516                 return NULL;
517         }
518         
519         return strdup(out_buffer);
520 }
521
522 size_t unix_strlower(const char *src, size_t srclen, char *dest, size_t destlen)
523 {
524         size_t size;
525         smb_ucs2_t *buffer;
526         
527         size = convert_string_allocate(NULL, CH_UNIX, CH_UCS2, src, srclen,
528                                        (void **) &buffer);
529         if (size == -1) {
530                 smb_panic("failed to create UCS2 buffer");
531         }
532         if (!strlower_w(buffer) && (dest == src)) {
533                 free(buffer);
534                 return srclen;
535         }
536         size = convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen);
537         free(buffer);
538         return size;
539 }
540
541 /**
542  strdup() a unix string to lower case.
543 **/
544
545 char *strdup_lower(const char *s)
546 {
547         size_t size;
548         smb_ucs2_t *buffer;
549         char *out_buffer;
550         
551         size = push_ucs2_allocate(&buffer, s);
552         if (size == -1) {
553                 return NULL;
554         }
555
556         strlower_w(buffer);
557         
558         size = pull_ucs2_allocate(&out_buffer, buffer);
559         SAFE_FREE(buffer);
560
561         if (size == -1) {
562                 return NULL;
563         }
564         
565         return out_buffer;
566 }
567
568 static size_t ucs2_align(const void *base_ptr, const void *p, int flags)
569 {
570         if (flags & (STR_NOALIGN|STR_ASCII))
571                 return 0;
572         return PTR_DIFF(p, base_ptr) & 1;
573 }
574
575
576 /**
577  * Copy a string from a char* unix src to a dos codepage string destination.
578  *
579  * @return the number of bytes occupied by the string in the destination.
580  *
581  * @param flags can include
582  * <dl>
583  * <dt>STR_TERMINATE</dt> <dd>means include the null termination</dd>
584  * <dt>STR_UPPER</dt> <dd>means uppercase in the destination</dd>
585  * </dl>
586  *
587  * @param dest_len the maximum length in bytes allowed in the
588  * destination.  If @p dest_len is -1 then no maximum is used.
589  **/
590 size_t push_ascii(void *dest, const char *src, size_t dest_len, int flags)
591 {
592         size_t src_len = strlen(src);
593         pstring tmpbuf;
594
595         /* treat a pstring as "unlimited" length */
596         if (dest_len == (size_t)-1)
597                 dest_len = sizeof(pstring);
598
599         if (flags & STR_UPPER) {
600                 pstrcpy(tmpbuf, src);
601                 strupper_m(tmpbuf);
602                 src = tmpbuf;
603         }
604
605         if (flags & (STR_TERMINATE | STR_TERMINATE_ASCII))
606                 src_len++;
607
608         return convert_string(CH_UNIX, CH_DOS, src, src_len, dest, dest_len);
609 }
610
611 size_t push_ascii_fstring(void *dest, const char *src)
612 {
613         return push_ascii(dest, src, sizeof(fstring), STR_TERMINATE);
614 }
615
616 size_t push_ascii_pstring(void *dest, const char *src)
617 {
618         return push_ascii(dest, src, sizeof(pstring), STR_TERMINATE);
619 }
620
621 size_t push_ascii_nstring(void *dest, const char *src)
622 {
623         return push_ascii(dest, src, sizeof(nstring), STR_TERMINATE);
624 }
625
626 /**
627  * Copy a string from a dos codepage source to a unix char* destination.
628  *
629  * The resulting string in "dest" is always null terminated.
630  *
631  * @param flags can have:
632  * <dl>
633  * <dt>STR_TERMINATE</dt>
634  * <dd>STR_TERMINATE means the string in @p src
635  * is null terminated, and src_len is ignored.</dd>
636  * </dl>
637  *
638  * @param src_len is the length of the source area in bytes.
639  * @returns the number of bytes occupied by the string in @p src.
640  **/
641 size_t pull_ascii(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
642 {
643         size_t ret;
644
645         if (dest_len == (size_t)-1)
646                 dest_len = sizeof(pstring);
647
648         if (flags & STR_TERMINATE) {
649                 if (src_len == (size_t)-1) {
650                         src_len = strlen(src) + 1;
651                 } else {
652                         size_t len = strnlen(src, src_len);
653                         if (len < src_len)
654                                 len++;
655                         src_len = len;
656                 }
657         }
658
659         ret = convert_string(CH_DOS, CH_UNIX, src, src_len, dest, dest_len);
660
661         if (dest_len)
662                 dest[MIN(ret, dest_len-1)] = 0;
663         else 
664                 dest[0] = 0;
665
666         return src_len;
667 }
668
669 size_t pull_ascii_pstring(char *dest, const void *src)
670 {
671         return pull_ascii(dest, src, sizeof(pstring), -1, STR_TERMINATE);
672 }
673
674 size_t pull_ascii_fstring(char *dest, const void *src)
675 {
676         return pull_ascii(dest, src, sizeof(fstring), -1, STR_TERMINATE);
677 }
678
679 size_t pull_ascii_nstring(char *dest, const void *src)
680 {
681         return pull_ascii(dest, src, sizeof(nstring), sizeof(nstring), STR_TERMINATE);
682 }
683
684 /**
685  * Copy a string from a char* src to a unicode destination.
686  *
687  * @returns the number of bytes occupied by the string in the destination.
688  *
689  * @param flags can have:
690  *
691  * <dl>
692  * <dt>STR_TERMINATE <dd>means include the null termination.
693  * <dt>STR_UPPER     <dd>means uppercase in the destination.
694  * <dt>STR_NOALIGN   <dd>means don't do alignment.
695  * </dl>
696  *
697  * @param dest_len is the maximum length allowed in the
698  * destination. If dest_len is -1 then no maxiumum is used.
699  **/
700 size_t push_ucs2(const void *base_ptr, void *dest, const char *src, size_t dest_len, int flags)
701 {
702         size_t len=0;
703         size_t src_len = strlen(src);
704
705         /* treat a pstring as "unlimited" length */
706         if (dest_len == (size_t)-1)
707                 dest_len = sizeof(pstring);
708
709         if (flags & STR_TERMINATE)
710                 src_len++;
711
712         if (ucs2_align(base_ptr, dest, flags)) {
713                 *(char *)dest = 0;
714                 dest = (void *)((char *)dest + 1);
715                 if (dest_len) dest_len--;
716                 len++;
717         }
718
719         /* ucs2 is always a multiple of 2 bytes */
720         dest_len &= ~1;
721
722         len += convert_string(CH_UNIX, CH_UCS2, src, src_len, dest, dest_len);
723
724         if (flags & STR_UPPER) {
725                 smb_ucs2_t *dest_ucs2 = dest;
726                 size_t i;
727                 for (i = 0; i < (dest_len / 2) && dest_ucs2[i]; i++) {
728                         smb_ucs2_t v = toupper_w(dest_ucs2[i]);
729                         if (v != dest_ucs2[i]) {
730                                 dest_ucs2[i] = v;
731                         }
732                 }
733         }
734
735         return len;
736 }
737
738
739 /**
740  * Copy a string from a unix char* src to a UCS2 destination,
741  * allocating a buffer using talloc().
742  *
743  * @param dest always set at least to NULL 
744  *
745  * @returns The number of bytes occupied by the string in the destination
746  *         or -1 in case of error.
747  **/
748 size_t push_ucs2_talloc(TALLOC_CTX *ctx, smb_ucs2_t **dest, const char *src)
749 {
750         size_t src_len = strlen(src)+1;
751
752         *dest = NULL;
753         return convert_string_talloc(ctx, CH_UNIX, CH_UCS2, src, src_len, (void **)dest);
754 }
755
756
757 /**
758  * Copy a string from a unix char* src to a UCS2 destination, allocating a buffer
759  *
760  * @param dest always set at least to NULL 
761  *
762  * @returns The number of bytes occupied by the string in the destination
763  *         or -1 in case of error.
764  **/
765
766 size_t push_ucs2_allocate(smb_ucs2_t **dest, const char *src)
767 {
768         size_t src_len = strlen(src)+1;
769
770         *dest = NULL;
771         return convert_string_allocate(NULL, CH_UNIX, CH_UCS2, src, src_len, (void **)dest);    
772 }
773
774 /**
775  Copy a string from a char* src to a UTF-8 destination.
776  Return the number of bytes occupied by the string in the destination
777  Flags can have:
778   STR_TERMINATE means include the null termination
779   STR_UPPER     means uppercase in the destination
780  dest_len is the maximum length allowed in the destination. If dest_len
781  is -1 then no maxiumum is used.
782 **/
783
784 static size_t push_utf8(void *dest, const char *src, size_t dest_len, int flags)
785 {
786         size_t src_len = strlen(src);
787         pstring tmpbuf;
788
789         /* treat a pstring as "unlimited" length */
790         if (dest_len == (size_t)-1)
791                 dest_len = sizeof(pstring);
792
793         if (flags & STR_UPPER) {
794                 pstrcpy(tmpbuf, src);
795                 strupper_m(tmpbuf);
796                 src = tmpbuf;
797         }
798
799         if (flags & STR_TERMINATE)
800                 src_len++;
801
802         return convert_string(CH_UNIX, CH_UTF8, src, src_len, dest, dest_len);
803 }
804
805 size_t push_utf8_fstring(void *dest, const char *src)
806 {
807         return push_utf8(dest, src, sizeof(fstring), STR_TERMINATE);
808 }
809
810 /**
811  * Copy a string from a unix char* src to a UTF-8 destination, allocating a buffer using talloc
812  *
813  * @param dest always set at least to NULL 
814  *
815  * @returns The number of bytes occupied by the string in the destination
816  **/
817
818 size_t push_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src)
819 {
820         size_t src_len = strlen(src)+1;
821
822         *dest = NULL;
823         return convert_string_talloc(ctx, CH_UNIX, CH_UTF8, src, src_len, (void**)dest);
824 }
825
826 /**
827  * Copy a string from a unix char* src to a UTF-8 destination, allocating a buffer
828  *
829  * @param dest always set at least to NULL 
830  *
831  * @returns The number of bytes occupied by the string in the destination
832  **/
833
834 size_t push_utf8_allocate(char **dest, const char *src)
835 {
836         size_t src_len = strlen(src)+1;
837
838         *dest = NULL;
839         return convert_string_allocate(NULL, CH_UNIX, CH_UTF8, src, src_len, (void **)dest);    
840 }
841
842 /**
843  Copy a string from a ucs2 source to a unix char* destination.
844  Flags can have:
845   STR_TERMINATE means the string in src is null terminated.
846   STR_NOALIGN   means don't try to align.
847  if STR_TERMINATE is set then src_len is ignored if it is -1.
848  src_len is the length of the source area in bytes
849  Return the number of bytes occupied by the string in src.
850  The resulting string in "dest" is always null terminated.
851 **/
852
853 size_t pull_ucs2(const void *base_ptr, char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
854 {
855         size_t ret;
856
857         if (dest_len == (size_t)-1)
858                 dest_len = sizeof(pstring);
859
860         if (ucs2_align(base_ptr, src, flags)) {
861                 src = (const void *)((const char *)src + 1);
862                 if (src_len > 0)
863                         src_len--;
864         }
865
866         if (flags & STR_TERMINATE) {
867                 if (src_len == (size_t)-1) {
868                         src_len = strlen_w(src)*2 + 2;
869                 } else {
870                         size_t len = strnlen_w(src, src_len/2);
871                         if (len < src_len/2)
872                                 len++;
873                         src_len = len*2;
874                 }
875         }
876
877         /* ucs2 is always a multiple of 2 bytes */
878         if (src_len != (size_t)-1)
879                 src_len &= ~1;
880         
881         ret = convert_string(CH_UCS2, CH_UNIX, src, src_len, dest, dest_len);
882         if (dest_len)
883                 dest[MIN(ret, dest_len-1)] = 0;
884         else 
885                 dest[0] = 0;
886
887         return src_len;
888 }
889
890 size_t pull_ucs2_pstring(char *dest, const void *src)
891 {
892         return pull_ucs2(NULL, dest, src, sizeof(pstring), -1, STR_TERMINATE);
893 }
894
895 size_t pull_ucs2_fstring(char *dest, const void *src)
896 {
897         return pull_ucs2(NULL, dest, src, sizeof(fstring), -1, STR_TERMINATE);
898 }
899
900 /**
901  * Copy a string from a UCS2 src to a unix char * destination, allocating a buffer using talloc
902  *
903  * @param dest always set at least to NULL 
904  *
905  * @returns The number of bytes occupied by the string in the destination
906  **/
907
908 size_t pull_ucs2_talloc(TALLOC_CTX *ctx, char **dest, const smb_ucs2_t *src)
909 {
910         size_t src_len = (strlen_w(src)+1) * sizeof(smb_ucs2_t);
911         *dest = NULL;
912         return convert_string_talloc(ctx, CH_UCS2, CH_UNIX, src, src_len, (void **)dest);
913 }
914
915 /**
916  * Copy a string from a UCS2 src to a unix char * destination, allocating a buffer
917  *
918  * @param dest always set at least to NULL 
919  *
920  * @returns The number of bytes occupied by the string in the destination
921  **/
922
923 size_t pull_ucs2_allocate(char **dest, const smb_ucs2_t *src)
924 {
925         size_t src_len = (strlen_w(src)+1) * sizeof(smb_ucs2_t);
926         *dest = NULL;
927         return convert_string_allocate(NULL, CH_UCS2, CH_UNIX, src, src_len, (void **)dest);    
928 }
929
930 /**
931  * Copy a string from a UTF-8 src to a unix char * destination, allocating a buffer using talloc
932  *
933  * @param dest always set at least to NULL 
934  *
935  * @returns The number of bytes occupied by the string in the destination
936  **/
937
938 size_t pull_utf8_talloc(TALLOC_CTX *ctx, char **dest, const char *src)
939 {
940         size_t src_len = strlen(src)+1;
941         *dest = NULL;
942         return convert_string_talloc(ctx, CH_UTF8, CH_UNIX, src, src_len, (void **)dest);       
943 }
944
945 /**
946  * Copy a string from a UTF-8 src to a unix char * destination, allocating a buffer
947  *
948  * @param dest always set at least to NULL 
949  *
950  * @returns The number of bytes occupied by the string in the destination
951  **/
952
953 size_t pull_utf8_allocate(void **dest, const char *src)
954 {
955         size_t src_len = strlen(src)+1;
956         *dest = NULL;
957         return convert_string_allocate(NULL, CH_UTF8, CH_UNIX, src, src_len, dest);     
958 }
959  
960 /**
961  Copy a string from a char* src to a unicode or ascii
962  dos codepage destination choosing unicode or ascii based on the 
963  flags in the SMB buffer starting at base_ptr.
964  Return the number of bytes occupied by the string in the destination.
965  flags can have:
966   STR_TERMINATE means include the null termination.
967   STR_UPPER     means uppercase in the destination.
968   STR_ASCII     use ascii even with unicode packet.
969   STR_NOALIGN   means don't do alignment.
970  dest_len is the maximum length allowed in the destination. If dest_len
971  is -1 then no maxiumum is used.
972 **/
973
974 size_t push_string_fn(const char *function, unsigned int line, const void *base_ptr, void *dest, const char *src, size_t dest_len, int flags)
975 {
976 #ifdef DEVELOPER
977         /* We really need to zero fill here, not clobber
978          * region, as we want to ensure that valgrind thinks
979          * all of the outgoing buffer has been written to
980          * so a send() or write() won't trap an error.
981          * JRA.
982          */
983 #if 0
984         if (dest_len != (size_t)-1)
985                 clobber_region(function, line, dest, dest_len);
986 #else
987         if (dest_len != (size_t)-1)
988                 memset(dest, '\0', dest_len);
989 #endif
990 #endif
991
992         if (!(flags & STR_ASCII) && \
993             ((flags & STR_UNICODE || \
994               (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
995                 return push_ucs2(base_ptr, dest, src, dest_len, flags);
996         }
997         return push_ascii(dest, src, dest_len, flags);
998 }
999
1000
1001 /**
1002  Copy a string from a unicode or ascii source (depending on
1003  the packet flags) to a char* destination.
1004  Flags can have:
1005   STR_TERMINATE means the string in src is null terminated.
1006   STR_UNICODE   means to force as unicode.
1007   STR_ASCII     use ascii even with unicode packet.
1008   STR_NOALIGN   means don't do alignment.
1009  if STR_TERMINATE is set then src_len is ignored is it is -1
1010  src_len is the length of the source area in bytes.
1011  Return the number of bytes occupied by the string in src.
1012  The resulting string in "dest" is always null terminated.
1013 **/
1014
1015 size_t pull_string_fn(const char *function, unsigned int line, const void *base_ptr, char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
1016 {
1017 #ifdef DEVELOPER
1018         if (dest_len != (size_t)-1)
1019                 clobber_region(function, line, dest, dest_len);
1020 #endif
1021
1022         if (!(flags & STR_ASCII) && \
1023             ((flags & STR_UNICODE || \
1024               (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
1025                 return pull_ucs2(base_ptr, dest, src, dest_len, src_len, flags);
1026         }
1027         return pull_ascii(dest, src, dest_len, src_len, flags);
1028 }
1029
1030 size_t align_string(const void *base_ptr, const char *p, int flags)
1031 {
1032         if (!(flags & STR_ASCII) && \
1033             ((flags & STR_UNICODE || \
1034               (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
1035                 return ucs2_align(base_ptr, p, flags);
1036         }
1037         return 0;
1038 }
1039