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