r16420: Fix Klocwork #1674. Null deref.
[metze/samba/wip.git] / source3 / lib / util_unistr.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Samba utility functions
4    Copyright (C) Andrew Tridgell 1992-2001
5    Copyright (C) Simo Sorce 2001
6    Copyright (C) Jeremy Allison 2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 #ifndef MAXUNI
26 #define MAXUNI 1024
27 #endif
28
29 /* these 3 tables define the unicode case handling.  They are loaded
30    at startup either via mmap() or read() from the lib directory */
31 static smb_ucs2_t *upcase_table;
32 static smb_ucs2_t *lowcase_table;
33 static uint8 *valid_table;
34 static BOOL upcase_table_use_unmap;
35 static BOOL lowcase_table_use_unmap;
36 static BOOL valid_table_use_unmap;
37
38 /**
39  * This table says which Unicode characters are valid dos
40  * characters.
41  *
42  * Each value is just a single bit.
43  **/
44 static uint8 doschar_table[8192]; /* 65536 characters / 8 bits/byte */
45
46 /**
47  * Destroy global objects allocated by load_case_tables()
48  **/
49 void gfree_case_tables(void)
50 {
51         if ( upcase_table ) {
52                 if ( upcase_table_use_unmap )
53                         unmap_file(upcase_table, 0x20000);
54                 else
55                         SAFE_FREE(upcase_table);
56         }
57
58         if ( lowcase_table ) {
59                 if ( lowcase_table_use_unmap )
60                         unmap_file(lowcase_table, 0x20000);
61                 else
62                         SAFE_FREE(lowcase_table);
63         }
64
65         if ( valid_table ) {
66                 if ( valid_table_use_unmap )
67                         unmap_file(valid_table, 0x10000);
68                 else
69                         SAFE_FREE(valid_table);
70         }
71 }
72
73 /**
74  * Load or generate the case handling tables.
75  *
76  * The case tables are defined in UCS2 and don't depend on any
77  * configured parameters, so they never need to be reloaded.
78  **/
79
80 void load_case_tables(void)
81 {
82         static int initialised;
83         char *old_locale = NULL, *saved_locale = NULL;
84         int i;
85
86         if (initialised) {
87                 return;
88         }
89         initialised = 1;
90
91         upcase_table = map_file(lib_path("upcase.dat"), 0x20000);
92         upcase_table_use_unmap = ( upcase_table != NULL );
93
94         lowcase_table = map_file(lib_path("lowcase.dat"), 0x20000);
95         lowcase_table_use_unmap = ( lowcase_table != NULL );
96
97 #ifdef HAVE_SETLOCALE
98         /* Get the name of the current locale.  */
99         old_locale = setlocale(LC_ALL, NULL);
100
101         if (old_locale) {
102                 /* Save it as it is in static storage. */
103                 saved_locale = SMB_STRDUP(old_locale);
104         }
105
106         /* We set back the locale to C to get ASCII-compatible toupper/lower functions. */
107         setlocale(LC_ALL, "C");
108 #endif
109
110         /* we would like Samba to limp along even if these tables are
111            not available */
112         if (!upcase_table) {
113                 DEBUG(1,("creating lame upcase table\n"));
114                 upcase_table = SMB_MALLOC(0x20000);
115                 for (i=0;i<0x10000;i++) {
116                         smb_ucs2_t v;
117                         SSVAL(&v, 0, i);
118                         upcase_table[v] = i;
119                 }
120                 for (i=0;i<256;i++) {
121                         smb_ucs2_t v;
122                         SSVAL(&v, 0, UCS2_CHAR(i));
123                         upcase_table[v] = UCS2_CHAR(islower(i)?toupper(i):i);
124                 }
125         }
126
127         if (!lowcase_table) {
128                 DEBUG(1,("creating lame lowcase table\n"));
129                 lowcase_table = SMB_MALLOC(0x20000);
130                 for (i=0;i<0x10000;i++) {
131                         smb_ucs2_t v;
132                         SSVAL(&v, 0, i);
133                         lowcase_table[v] = i;
134                 }
135                 for (i=0;i<256;i++) {
136                         smb_ucs2_t v;
137                         SSVAL(&v, 0, UCS2_CHAR(i));
138                         lowcase_table[v] = UCS2_CHAR(isupper(i)?tolower(i):i);
139                 }
140         }
141
142 #ifdef HAVE_SETLOCALE
143         /* Restore the old locale. */
144         if (saved_locale) {
145                 setlocale (LC_ALL, saved_locale);
146                 SAFE_FREE(saved_locale);
147         }
148 #endif
149 }
150
151 /*
152   see if a ucs2 character can be mapped correctly to a dos character
153   and mapped back to the same character in ucs2
154 */
155
156 int check_dos_char(smb_ucs2_t c)
157 {
158         lazy_initialize_conv();
159         
160         /* Find the right byte, and right bit within the byte; return
161          * 1 or 0 */
162         return (doschar_table[(c & 0xffff) / 8] & (1 << (c & 7))) != 0;
163 }
164
165
166 static int check_dos_char_slowly(smb_ucs2_t c)
167 {
168         char buf[10];
169         smb_ucs2_t c2 = 0;
170         int len1, len2;
171
172         len1 = convert_string(CH_UCS2, CH_DOS, &c, 2, buf, sizeof(buf),False);
173         if (len1 == 0) {
174                 return 0;
175         }
176         len2 = convert_string(CH_DOS, CH_UCS2, buf, len1, &c2, 2,False);
177         if (len2 != 2) {
178                 return 0;
179         }
180         return (c == c2);
181 }
182
183
184 /**
185  * Fill out doschar table the hard way, by examining each character
186  **/
187
188 void init_doschar_table(void)
189 {
190         int i, j, byteval;
191
192         /* For each byte of packed table */
193         
194         for (i = 0; i <= 0xffff; i += 8) {
195                 byteval = 0;
196                 for (j = 0; j <= 7; j++) {
197                         smb_ucs2_t c;
198
199                         c = i + j;
200                         
201                         if (check_dos_char_slowly(c)) {
202                                 byteval |= 1 << j;
203                         }
204                 }
205                 doschar_table[i/8] = byteval;
206         }
207 }
208
209
210 /**
211  * Load the valid character map table from <tt>valid.dat</tt> or
212  * create from the configured codepage.
213  *
214  * This function is called whenever the configuration is reloaded.
215  * However, the valid character table is not changed if it's loaded
216  * from a file, because we can't unmap files.
217  **/
218
219 void init_valid_table(void)
220 {
221         static int mapped_file;
222         int i;
223         const char *allowed = ".!#$%&'()_-@^`~";
224         uint8 *valid_file;
225
226         if (mapped_file) {
227                 /* Can't unmap files, so stick with what we have */
228                 return;
229         }
230
231         valid_file = map_file(lib_path("valid.dat"), 0x10000);
232         if (valid_file) {
233                 valid_table = valid_file;
234                 mapped_file = 1;
235                 valid_table_use_unmap = True;
236                 return;
237         }
238
239         /* Otherwise, we're using a dynamically created valid_table.
240          * It might need to be regenerated if the code page changed.
241          * We know that we're not using a mapped file, so we can
242          * free() the old one. */
243         if (valid_table) 
244                 SAFE_FREE(valid_table);
245
246         /* use free rather than unmap */
247         valid_table_use_unmap = False;
248
249         DEBUG(2,("creating default valid table\n"));
250         valid_table = SMB_MALLOC(0x10000);
251         for (i=0;i<128;i++) {
252                 valid_table[i] = isalnum(i) || strchr(allowed,i);
253         }
254         
255         for (;i<0x10000;i++) {
256                 smb_ucs2_t c;
257                 SSVAL(&c, 0, i);
258                 valid_table[i] = check_dos_char(c);
259         }
260 }
261
262 /*******************************************************************
263  Write a string in (little-endian) unicode format. src is in
264  the current DOS codepage. len is the length in bytes of the
265  string pointed to by dst.
266
267  if null_terminate is True then null terminate the packet (adds 2 bytes)
268
269  the return value is the length in bytes consumed by the string, including the
270  null termination if applied
271 ********************************************************************/
272
273 size_t dos_PutUniCode(char *dst,const char *src, size_t len, BOOL null_terminate)
274 {
275         int flags = null_terminate ? STR_UNICODE|STR_NOALIGN|STR_TERMINATE
276                                    : STR_UNICODE|STR_NOALIGN;
277         return push_ucs2(NULL, dst, src, len, flags);
278 }
279
280
281 /*******************************************************************
282  Skip past a unicode string, but not more than len. Always move
283  past a terminating zero if found.
284 ********************************************************************/
285
286 char *skip_unibuf(char *src, size_t len)
287 {
288         char *srcend = src + len;
289
290         while (src < srcend && SVAL(src,0)) {
291                 src += 2;
292         }
293
294         if(!SVAL(src,0)) {
295                 src += 2;
296         }
297
298         return src;
299 }
300
301 /* Copy a string from little-endian or big-endian unicode source (depending
302  * on flags) to internal samba format destination
303  */ 
304
305 int rpcstr_pull(char* dest, void *src, int dest_len, int src_len, int flags)
306 {
307         if (!src) {
308                 dest[0] = 0;
309                 return 0;
310         }
311         if(dest_len==-1) {
312                 dest_len=MAXUNI-3;
313         }
314         return pull_ucs2(NULL, dest, src, dest_len, src_len, flags|STR_UNICODE|STR_NOALIGN);
315 }
316
317 /* Copy a string from a unistr2 source to internal samba format
318    destination.  Use this instead of direct calls to rpcstr_pull() to avoid
319    having to determine whether the source string is null terminated. */
320
321 int rpcstr_pull_unistr2_fstring(char *dest, UNISTR2 *src)
322 {
323         return pull_ucs2(NULL, dest, src->buffer, sizeof(fstring),
324                          src->uni_str_len * 2, 0);
325 }
326
327 /* Helper function to return a talloc'ed string. I have implemented it with a
328  * copy because I don't really know how pull_ucs2 and friends calculate the
329  * target size. If this turns out to be a major bottleneck someone with deeper
330  * multi-byte knowledge needs to revisit this.
331  * My (VL) use is dsr_getdcname, which returns 6 strings, the alternative would
332  * have been to manually talloc_strdup them in rpc_client/cli_netlogon.c.
333  */
334
335 char *rpcstr_pull_unistr2_talloc(TALLOC_CTX *mem_ctx, const UNISTR2 *src)
336 {
337         pstring tmp;
338         size_t result;
339
340         result = pull_ucs2(NULL, tmp, src->buffer, sizeof(tmp),
341                            src->uni_str_len * 2, 0);
342         if (result == (size_t)-1) {
343                 return NULL;
344         }
345
346         return talloc_strdup(mem_ctx, tmp);
347 }
348
349 /* Converts a string from internal samba format to unicode
350  */ 
351
352 int rpcstr_push(void* dest, const char *src, size_t dest_len, int flags)
353 {
354         return push_ucs2(NULL, dest, src, dest_len, flags|STR_UNICODE|STR_NOALIGN);
355 }
356
357 /*******************************************************************
358  Convert a (little-endian) UNISTR2 structure to an ASCII string.
359 ********************************************************************/
360
361 void unistr2_to_ascii(char *dest, const UNISTR2 *str, size_t maxlen)
362 {
363         if (str == NULL) {
364                 *dest='\0';
365                 return;
366         }
367         pull_ucs2(NULL, dest, str->buffer, maxlen, str->uni_str_len*2, STR_NOALIGN);
368 }
369
370 /*******************************************************************
371  Convert a (little-endian) UNISTR3 structure to an ASCII string.
372 ********************************************************************/
373
374 void unistr3_to_ascii(char *dest, const UNISTR3 *str, size_t maxlen)
375 {
376         if (str == NULL) {
377                 *dest='\0';
378                 return;
379         }
380         pull_ucs2(NULL, dest, str->str.buffer, maxlen, str->uni_str_len*2,
381                   STR_NOALIGN);
382 }
383         
384 /*******************************************************************
385  Give a static string for displaying a UNISTR2.
386 ********************************************************************/
387
388 const char *unistr2_static(const UNISTR2 *str)
389 {
390         static pstring ret;
391         unistr2_to_ascii(ret, str, sizeof(ret));
392         return ret;
393 }
394
395 /*******************************************************************
396  Duplicate a UNISTR2 string into a null terminated char*
397  using a talloc context.
398 ********************************************************************/
399
400 char *unistr2_tdup(TALLOC_CTX *ctx, const UNISTR2 *str)
401 {
402         char *s;
403         int maxlen = (str->uni_str_len+1)*4;
404         if (!str->buffer) {
405                 return NULL;
406         }
407         s = (char *)TALLOC(ctx, maxlen); /* convervative */
408         if (!s) {
409                 return NULL;
410         }
411         pull_ucs2(NULL, s, str->buffer, maxlen, str->uni_str_len*2, STR_NOALIGN);
412         return s;
413 }
414
415 /*******************************************************************
416  Convert a wchar to upper case.
417 ********************************************************************/
418
419 smb_ucs2_t toupper_w(smb_ucs2_t val)
420 {
421         return upcase_table[SVAL(&val,0)];
422 }
423
424 /*******************************************************************
425  Convert a wchar to lower case.
426 ********************************************************************/
427
428 smb_ucs2_t tolower_w( smb_ucs2_t val )
429 {
430         return lowcase_table[SVAL(&val,0)];
431 }
432
433 /*******************************************************************
434  Determine if a character is lowercase.
435 ********************************************************************/
436
437 BOOL islower_w(smb_ucs2_t c)
438 {
439         return upcase_table[SVAL(&c,0)] != c;
440 }
441
442 /*******************************************************************
443  Determine if a character is uppercase.
444 ********************************************************************/
445
446 BOOL isupper_w(smb_ucs2_t c)
447 {
448         return lowcase_table[SVAL(&c,0)] != c;
449 }
450
451 /*******************************************************************
452  Determine if a character is valid in a 8.3 name.
453 ********************************************************************/
454
455 BOOL isvalid83_w(smb_ucs2_t c)
456 {
457         return valid_table[SVAL(&c,0)] != 0;
458 }
459
460 /*******************************************************************
461  Count the number of characters in a smb_ucs2_t string.
462 ********************************************************************/
463
464 size_t strlen_w(const smb_ucs2_t *src)
465 {
466         size_t len;
467         smb_ucs2_t c;
468
469         for(len = 0; *(COPY_UCS2_CHAR(&c,src)); src++, len++) {
470                 ;
471         }
472
473         return len;
474 }
475
476 /*******************************************************************
477  Count up to max number of characters in a smb_ucs2_t string.
478 ********************************************************************/
479
480 size_t strnlen_w(const smb_ucs2_t *src, size_t max)
481 {
482         size_t len;
483         smb_ucs2_t c;
484
485         for(len = 0; *(COPY_UCS2_CHAR(&c,src)) && (len < max); src++, len++) {
486                 ;
487         }
488
489         return len;
490 }
491
492 /*******************************************************************
493  Wide strchr().
494 ********************************************************************/
495
496 smb_ucs2_t *strchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
497 {
498         smb_ucs2_t cp;
499         while (*(COPY_UCS2_CHAR(&cp,s))) {
500                 if (c == cp) {
501                         return (smb_ucs2_t *)s;
502                 }
503                 s++;
504         }
505         if (c == cp) {
506                 return (smb_ucs2_t *)s;
507         }
508
509         return NULL;
510 }
511
512 smb_ucs2_t *strchr_wa(const smb_ucs2_t *s, char c)
513 {
514         return strchr_w(s, UCS2_CHAR(c));
515 }
516
517 /*******************************************************************
518  Wide strrchr().
519 ********************************************************************/
520
521 smb_ucs2_t *strrchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
522 {
523         smb_ucs2_t cp;
524         const smb_ucs2_t *p = s;
525         int len = strlen_w(s);
526
527         if (len == 0) {
528                 return NULL;
529         }
530         p += (len - 1);
531         do {
532                 if (c == *(COPY_UCS2_CHAR(&cp,p))) {
533                         return (smb_ucs2_t *)p;
534                 }
535         } while (p-- != s);
536         return NULL;
537 }
538
539 /*******************************************************************
540  Wide version of strrchr that returns after doing strrchr 'n' times.
541 ********************************************************************/
542
543 smb_ucs2_t *strnrchr_w(const smb_ucs2_t *s, smb_ucs2_t c, unsigned int n)
544 {
545         smb_ucs2_t cp;
546         const smb_ucs2_t *p = s;
547         int len = strlen_w(s);
548
549         if (len == 0 || !n) {
550                 return NULL;
551         }
552         p += (len - 1);
553         do {
554                 if (c == *(COPY_UCS2_CHAR(&cp,p))) {
555                         n--;
556                 }
557
558                 if (!n) {
559                         return (smb_ucs2_t *)p;
560                 }
561         } while (p-- != s);
562         return NULL;
563 }
564
565 /*******************************************************************
566  Wide strstr().
567 ********************************************************************/
568
569 smb_ucs2_t *strstr_w(const smb_ucs2_t *s, const smb_ucs2_t *ins)
570 {
571         smb_ucs2_t *r;
572         size_t inslen;
573
574         if (!s || !*s || !ins || !*ins) {
575                 return NULL;
576         }
577
578         inslen = strlen_w(ins);
579         r = (smb_ucs2_t *)s;
580
581         while ((r = strchr_w(r, *ins))) {
582                 if (strncmp_w(r, ins, inslen) == 0) {
583                         return r;
584                 }
585                 r++;
586         }
587
588         return NULL;
589 }
590
591 /*******************************************************************
592  Convert a string to lower case.
593  return True if any char is converted
594 ********************************************************************/
595
596 BOOL strlower_w(smb_ucs2_t *s)
597 {
598         smb_ucs2_t cp;
599         BOOL ret = False;
600
601         while (*(COPY_UCS2_CHAR(&cp,s))) {
602                 smb_ucs2_t v = tolower_w(cp);
603                 if (v != cp) {
604                         COPY_UCS2_CHAR(s,&v);
605                         ret = True;
606                 }
607                 s++;
608         }
609         return ret;
610 }
611
612 /*******************************************************************
613  Convert a string to upper case.
614  return True if any char is converted
615 ********************************************************************/
616
617 BOOL strupper_w(smb_ucs2_t *s)
618 {
619         smb_ucs2_t cp;
620         BOOL ret = False;
621         while (*(COPY_UCS2_CHAR(&cp,s))) {
622                 smb_ucs2_t v = toupper_w(cp);
623                 if (v != cp) {
624                         COPY_UCS2_CHAR(s,&v);
625                         ret = True;
626                 }
627                 s++;
628         }
629         return ret;
630 }
631
632 /*******************************************************************
633  Convert a string to "normal" form.
634 ********************************************************************/
635
636 void strnorm_w(smb_ucs2_t *s, int case_default)
637 {
638         if (case_default == CASE_UPPER) {
639                 strupper_w(s);
640         } else {
641                 strlower_w(s);
642         }
643 }
644
645 int strcmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b)
646 {
647         smb_ucs2_t cpa, cpb;
648
649         while ((*(COPY_UCS2_CHAR(&cpb,b))) && (*(COPY_UCS2_CHAR(&cpa,a)) == cpb)) {
650                 a++;
651                 b++;
652         }
653         return (*(COPY_UCS2_CHAR(&cpa,a)) - *(COPY_UCS2_CHAR(&cpb,b)));
654         /* warning: if *a != *b and both are not 0 we return a random
655                 greater or lesser than 0 number not realted to which
656                 string is longer */
657 }
658
659 int strncmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b, size_t len)
660 {
661         smb_ucs2_t cpa, cpb;
662         size_t n = 0;
663
664         while ((n < len) && (*(COPY_UCS2_CHAR(&cpb,b))) && (*(COPY_UCS2_CHAR(&cpa,a)) == cpb)) {
665                 a++;
666                 b++;
667                 n++;
668         }
669         return (len - n)?(*(COPY_UCS2_CHAR(&cpa,a)) - *(COPY_UCS2_CHAR(&cpb,b))):0;
670 }
671
672 /*******************************************************************
673  Case insensitive string comparison.
674 ********************************************************************/
675
676 int strcasecmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b)
677 {
678         smb_ucs2_t cpa, cpb;
679
680         while ((*COPY_UCS2_CHAR(&cpb,b)) && toupper_w(*(COPY_UCS2_CHAR(&cpa,a))) == toupper_w(cpb)) {
681                 a++;
682                 b++;
683         }
684         return (tolower_w(*(COPY_UCS2_CHAR(&cpa,a))) - tolower_w(*(COPY_UCS2_CHAR(&cpb,b))));
685 }
686
687 /*******************************************************************
688  Case insensitive string comparison, length limited.
689 ********************************************************************/
690
691 int strncasecmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b, size_t len)
692 {
693         smb_ucs2_t cpa, cpb;
694         size_t n = 0;
695
696         while ((n < len) && *COPY_UCS2_CHAR(&cpb,b) && (toupper_w(*(COPY_UCS2_CHAR(&cpa,a))) == toupper_w(cpb))) {
697                 a++;
698                 b++;
699                 n++;
700         }
701         return (len - n)?(tolower_w(*(COPY_UCS2_CHAR(&cpa,a))) - tolower_w(*(COPY_UCS2_CHAR(&cpb,b)))):0;
702 }
703
704 /*******************************************************************
705  Compare 2 strings.
706 ********************************************************************/
707
708 BOOL strequal_w(const smb_ucs2_t *s1, const smb_ucs2_t *s2)
709 {
710         if (s1 == s2) {
711                 return(True);
712         }
713         if (!s1 || !s2) {
714                 return(False);
715         }
716   
717         return(strcasecmp_w(s1,s2)==0);
718 }
719
720 /*******************************************************************
721  Compare 2 strings up to and including the nth char.
722 ******************************************************************/
723
724 BOOL strnequal_w(const smb_ucs2_t *s1,const smb_ucs2_t *s2,size_t n)
725 {
726         if (s1 == s2) {
727                 return(True);
728         }
729         if (!s1 || !s2 || !n) {
730                 return(False);
731         }
732   
733         return(strncasecmp_w(s1,s2,n)==0);
734 }
735
736 /*******************************************************************
737  Duplicate string.
738 ********************************************************************/
739
740 smb_ucs2_t *strdup_w(const smb_ucs2_t *src)
741 {
742         return strndup_w(src, 0);
743 }
744
745 /* if len == 0 then duplicate the whole string */
746
747 smb_ucs2_t *strndup_w(const smb_ucs2_t *src, size_t len)
748 {
749         smb_ucs2_t *dest;
750         
751         if (!len) {
752                 len = strlen_w(src);
753         }
754         dest = SMB_MALLOC_ARRAY(smb_ucs2_t, len + 1);
755         if (!dest) {
756                 DEBUG(0,("strdup_w: out of memory!\n"));
757                 return NULL;
758         }
759
760         memcpy(dest, src, len * sizeof(smb_ucs2_t));
761         dest[len] = 0;
762         return dest;
763 }
764
765 /*******************************************************************
766  Copy a string with max len.
767 ********************************************************************/
768
769 smb_ucs2_t *strncpy_w(smb_ucs2_t *dest, const smb_ucs2_t *src, const size_t max)
770 {
771         smb_ucs2_t cp;
772         size_t len;
773         
774         if (!dest || !src) {
775                 return NULL;
776         }
777         
778         for (len = 0; (*COPY_UCS2_CHAR(&cp,(src+len))) && (len < max); len++) {
779                 cp = *COPY_UCS2_CHAR(dest+len,src+len);
780         }
781         cp = 0;
782         for ( /*nothing*/ ; len < max; len++ ) {
783                 cp = *COPY_UCS2_CHAR(dest+len,&cp);
784         }
785         
786         return dest;
787 }
788
789 /*******************************************************************
790  Append a string of len bytes and add a terminator.
791 ********************************************************************/
792
793 smb_ucs2_t *strncat_w(smb_ucs2_t *dest, const smb_ucs2_t *src, const size_t max)
794 {       
795         size_t start;
796         size_t len;     
797         smb_ucs2_t z = 0;
798
799         if (!dest || !src) {
800                 return NULL;
801         }
802         
803         start = strlen_w(dest);
804         len = strnlen_w(src, max);
805
806         memcpy(&dest[start], src, len*sizeof(smb_ucs2_t));                      
807         z = *COPY_UCS2_CHAR(dest+start+len,&z);
808
809         return dest;
810 }
811
812 smb_ucs2_t *strcat_w(smb_ucs2_t *dest, const smb_ucs2_t *src)
813 {       
814         size_t start;
815         size_t len;     
816         smb_ucs2_t z = 0;
817         
818         if (!dest || !src) {
819                 return NULL;
820         }
821         
822         start = strlen_w(dest);
823         len = strlen_w(src);
824
825         memcpy(&dest[start], src, len*sizeof(smb_ucs2_t));                      
826         z = *COPY_UCS2_CHAR(dest+start+len,&z);
827         
828         return dest;
829 }
830
831
832 /*******************************************************************
833  Replace any occurence of oldc with newc in unicode string.
834 ********************************************************************/
835
836 void string_replace_w(smb_ucs2_t *s, smb_ucs2_t oldc, smb_ucs2_t newc)
837 {
838         smb_ucs2_t cp;
839
840         for(;*(COPY_UCS2_CHAR(&cp,s));s++) {
841                 if(cp==oldc) {
842                         COPY_UCS2_CHAR(s,&newc);
843                 }
844         }
845 }
846
847 /*******************************************************************
848  Trim unicode string.
849 ********************************************************************/
850
851 BOOL trim_string_w(smb_ucs2_t *s, const smb_ucs2_t *front,
852                                   const smb_ucs2_t *back)
853 {
854         BOOL ret = False;
855         size_t len, front_len, back_len;
856
857         if (!s) {
858                 return False;
859         }
860
861         len = strlen_w(s);
862
863         if (front && *front) {
864                 front_len = strlen_w(front);
865                 while (len && strncmp_w(s, front, front_len) == 0) {
866                         memmove(s, (s + front_len), (len - front_len + 1) * sizeof(smb_ucs2_t));
867                         len -= front_len;
868                         ret = True;
869                 }
870         }
871         
872         if (back && *back) {
873                 back_len = strlen_w(back);
874                 while (len && strncmp_w((s + (len - back_len)), back, back_len) == 0) {
875                         s[len - back_len] = 0;
876                         len -= back_len;
877                         ret = True;
878                 }
879         }
880
881         return ret;
882 }
883
884 /*
885   The *_wa() functions take a combination of 7 bit ascii
886   and wide characters They are used so that you can use string
887   functions combining C string constants with ucs2 strings
888
889   The char* arguments must NOT be multibyte - to be completely sure
890   of this only pass string constants */
891
892 int strcmp_wa(const smb_ucs2_t *a, const char *b)
893 {
894         smb_ucs2_t cp = 0;
895
896         while (*b && *(COPY_UCS2_CHAR(&cp,a)) == UCS2_CHAR(*b)) {
897                 a++;
898                 b++;
899         }
900         return (*(COPY_UCS2_CHAR(&cp,a)) - UCS2_CHAR(*b));
901 }
902
903 int strncmp_wa(const smb_ucs2_t *a, const char *b, size_t len)
904 {
905         smb_ucs2_t cp = 0;
906         size_t n = 0;
907
908         while ((n < len) && *b && *(COPY_UCS2_CHAR(&cp,a)) == UCS2_CHAR(*b)) {
909                 a++;
910                 b++;
911                 n++;
912         }
913         return (len - n)?(*(COPY_UCS2_CHAR(&cp,a)) - UCS2_CHAR(*b)):0;
914 }
915
916 smb_ucs2_t *strpbrk_wa(const smb_ucs2_t *s, const char *p)
917 {
918         smb_ucs2_t cp;
919
920         while (*(COPY_UCS2_CHAR(&cp,s))) {
921                 int i;
922                 for (i=0; p[i] && cp != UCS2_CHAR(p[i]); i++) 
923                         ;
924                 if (p[i]) {
925                         return (smb_ucs2_t *)s;
926                 }
927                 s++;
928         }
929         return NULL;
930 }
931
932 smb_ucs2_t *strstr_wa(const smb_ucs2_t *s, const char *ins)
933 {
934         smb_ucs2_t *r;
935         size_t inslen;
936
937         if (!s || !ins) { 
938                 return NULL;
939         }
940
941         inslen = strlen(ins);
942         r = (smb_ucs2_t *)s;
943
944         while ((r = strchr_w(r, UCS2_CHAR(*ins)))) {
945                 if (strncmp_wa(r, ins, inslen) == 0) 
946                         return r;
947                 r++;
948         }
949
950         return NULL;
951 }
952
953 BOOL trim_string_wa(smb_ucs2_t *s, const char *front,
954                                   const char *back)
955 {
956         wpstring f, b;
957
958         if (front) {
959                 push_ucs2(NULL, f, front, sizeof(wpstring) - 1, STR_TERMINATE);
960         } else {
961                 *f = 0;
962         }
963         if (back) {
964                 push_ucs2(NULL, b, back, sizeof(wpstring) - 1, STR_TERMINATE);
965         } else {
966                 *b = 0;
967         }
968         return trim_string_w(s, f, b);
969 }
970
971 /*******************************************************************
972  Returns the length in number of wide characters.
973 ******************************************************************/
974
975 int unistrlen(uint16 *s)
976 {
977         int len;
978
979         if (!s) {
980                 return -1;
981         }
982
983         for (len=0; SVAL(s,0); s++,len++) {
984                 ;
985         }
986
987         return len;
988 }
989
990 /*******************************************************************
991  Strcpy for unicode strings. Returns length (in num of wide chars).
992  Not odd align safe.
993 ********************************************************************/
994
995 int unistrcpy(uint16 *dst, uint16 *src)
996 {
997         int num_wchars = 0;
998
999         while (SVAL(src,0)) {
1000                 *dst++ = *src++;
1001                 num_wchars++;
1002         }
1003         *dst = 0;
1004
1005         return num_wchars;
1006 }
1007
1008 /**
1009  * Samba ucs2 type to UNISTR2 conversion
1010  *
1011  * @param ctx Talloc context to create the dst strcture (if null) and the 
1012  *            contents of the unicode string.
1013  * @param dst UNISTR2 destination. If equals null, then it's allocated.
1014  * @param src smb_ucs2_t source.
1015  * @param max_len maximum number of unicode characters to copy. If equals
1016  *        null, then null-termination of src is taken
1017  *
1018  * @return copied UNISTR2 destination
1019  **/
1020
1021 UNISTR2* ucs2_to_unistr2(TALLOC_CTX *ctx, UNISTR2* dst, smb_ucs2_t* src)
1022 {
1023         size_t len;
1024
1025         if (!src) {
1026                 return NULL;
1027         }
1028
1029         len = strlen_w(src);
1030         
1031         /* allocate UNISTR2 destination if not given */
1032         if (!dst) {
1033                 dst = TALLOC_P(ctx, UNISTR2);
1034                 if (!dst)
1035                         return NULL;
1036         }
1037         if (!dst->buffer) {
1038                 dst->buffer = TALLOC_ARRAY(ctx, uint16, len + 1);
1039                 if (!dst->buffer)
1040                         return NULL;
1041         }
1042         
1043         /* set UNISTR2 parameters */
1044         dst->uni_max_len = len + 1;
1045         dst->offset = 0;
1046         dst->uni_str_len = len;
1047         
1048         /* copy the actual unicode string */
1049         strncpy_w(dst->buffer, src, dst->uni_max_len);
1050         
1051         return dst;
1052 }
1053
1054 /*************************************************************
1055  ascii only toupper - saves the need for smbd to be in C locale.
1056 *************************************************************/
1057
1058 int toupper_ascii(int c)
1059 {
1060         smb_ucs2_t uc = toupper_w(UCS2_CHAR(c));
1061         return UCS2_TO_CHAR(uc);
1062 }
1063
1064 /*************************************************************
1065  ascii only tolower - saves the need for smbd to be in C locale.
1066 *************************************************************/
1067
1068 int tolower_ascii(int c)
1069 {
1070         smb_ucs2_t uc = tolower_w(UCS2_CHAR(c));
1071         return UCS2_TO_CHAR(uc);
1072 }
1073
1074 /*************************************************************
1075  ascii only isupper - saves the need for smbd to be in C locale.
1076 *************************************************************/
1077
1078 int isupper_ascii(int c)
1079 {
1080         return isupper_w(UCS2_CHAR(c));
1081 }
1082
1083 /*************************************************************
1084  ascii only islower - saves the need for smbd to be in C locale.
1085 *************************************************************/
1086
1087 int islower_ascii(int c)
1088 {
1089         return islower_w(UCS2_CHAR(c));
1090 }