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