Removed version number from file header.
[ira/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    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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
34
35 /*******************************************************************
36 load the case handling tables
37 ********************************************************************/
38 void load_case_tables(void)
39 {
40         static int initialised;
41         int i;
42
43         if (initialised) return;
44         initialised = 1;
45
46         upcase_table = map_file(lib_path("upcase.dat"), 0x20000);
47         lowcase_table = map_file(lib_path("lowcase.dat"), 0x20000);
48
49         /* we would like Samba to limp along even if these tables are
50            not available */
51         if (!upcase_table) {
52                 DEBUG(1,("creating lame upcase table\n"));
53                 upcase_table = malloc(0x20000);
54                 for (i=0;i<0x10000;i++) upcase_table[i] = i;
55                 for (i=0;i<256;i++) upcase_table[UCS2_CHAR(i)] = UCS2_CHAR(islower(i)?toupper(i):i);
56         }
57
58         if (!lowcase_table) {
59                 DEBUG(1,("creating lame lowcase table\n"));
60                 lowcase_table = malloc(0x20000);
61                 for (i=0;i<0x10000;i++) lowcase_table[i] = i;
62                 for (i=0;i<256;i++) lowcase_table[UCS2_CHAR(i)] = UCS2_CHAR(isupper(i)?tolower(i):i);
63         }
64 }
65
66 /*
67   see if a ucs2 character can be mapped correctly to a dos character
68   and mapped back to the same character in ucs2
69 */
70 static int check_dos_char(smb_ucs2_t c)
71 {
72         char buf[10];
73         smb_ucs2_t c2 = 0;
74         int len1, len2;
75         len1 = convert_string(CH_UCS2, CH_DOS, &c, 2, buf, sizeof(buf));
76         if (len1 == 0) return 0;
77         len2 = convert_string(CH_DOS, CH_UCS2, buf, len1, &c2, 2);
78         if (len2 != 2) return 0;
79         return (c == c2);
80 }
81
82 /*******************************************************************
83 load the valid character map table
84 ********************************************************************/
85 void init_valid_table(void)
86 {
87         static int initialised;
88         static int mapped_file;
89         int i;
90         const char *allowed = ".!#$%&'()_-@^`~";
91
92         if (initialised && mapped_file) return;
93         initialised = 1;
94
95         valid_table = map_file(lib_path("valid.dat"), 0x10000);
96         if (valid_table) {
97                 mapped_file = 1;
98                 return;
99         }
100
101         if (valid_table) free(valid_table);
102
103         DEBUG(2,("creating default valid table\n"));
104         valid_table = malloc(0x10000);
105         for (i=0;i<128;i++) valid_table[UCS2_CHAR(i)] = isalnum(i) || 
106                                     strchr(allowed,i);
107         for (;i<0x10000;i++) {
108                 smb_ucs2_t c;
109                 SSVAL(&c, 0, i);
110                 valid_table[c] = check_dos_char(c);
111         }
112 }
113
114
115 /*******************************************************************
116  Write a string in (little-endian) unicode format. src is in
117  the current DOS codepage. len is the length in bytes of the
118  string pointed to by dst.
119
120  if null_terminate is True then null terminate the packet (adds 2 bytes)
121
122  the return value is the length in bytes consumed by the string, including the
123  null termination if applied
124 ********************************************************************/
125
126 size_t dos_PutUniCode(char *dst,const char *src, ssize_t len, BOOL null_terminate)
127 {
128         return push_ucs2(NULL, dst, src, len, 
129                          STR_UNICODE|STR_NOALIGN | (null_terminate?STR_TERMINATE:0));
130 }
131
132
133 /*******************************************************************
134  Skip past a unicode string, but not more than len. Always move
135  past a terminating zero if found.
136 ********************************************************************/
137
138 char *skip_unibuf(char *src, size_t len)
139 {
140     char *srcend = src + len;
141
142     while (src < srcend && SVAL(src,0))
143         src += 2;
144
145     if(!SVAL(src,0))
146         src += 2;
147
148     return src;
149 }
150
151 /* Copy a string from little-endian or big-endian unicode source (depending
152  * on flags) to internal samba format destination
153  */ 
154 int rpcstr_pull(char* dest, void *src, int dest_len, int src_len, int flags)
155 {
156         if(dest_len==-1) dest_len=MAXUNI-3;
157         return pull_ucs2(NULL, dest, src, dest_len, src_len, flags|STR_UNICODE|STR_NOALIGN);
158 }
159
160 /* Copy a string from a unistr2 source to internal samba format
161    destination.  Use this instead of direct calls to rpcstr_pull() to avoid
162    having to determine whether the source string is null terminated. */
163
164 int rpcstr_pull_unistr2_fstring(char *dest, UNISTR2 *src)
165 {
166         return pull_ucs2(NULL, dest, src->buffer, sizeof(fstring),
167                          src->uni_str_len * 2, 0);
168 }
169
170 /* Converts a string from internal samba format to unicode
171  */ 
172 int rpcstr_push(void* dest, const char *src, int dest_len, int flags)
173 {
174         return push_ucs2(NULL, dest, src, dest_len, flags|STR_UNICODE|STR_NOALIGN);
175 }
176
177 /*******************************************************************
178  Return a DOS codepage version of a little-endian unicode string.
179  len is the filename length (ignoring any terminating zero) in uin16
180  units. Always null terminates.
181  Hack alert: uses fixed buffer(s).
182 ********************************************************************/
183 char *dos_unistrn2(const uint16 *src, int len)
184 {
185         static char lbufs[8][MAXUNI];
186         static int nexti;
187         char *lbuf = lbufs[nexti];
188         nexti = (nexti+1)%8;
189         pull_ucs2(NULL, lbuf, src, MAXUNI-3, len*2, STR_NOALIGN);
190         return lbuf;
191 }
192
193 /*******************************************************************
194  Convert a (little-endian) UNISTR2 structure to an ASCII string
195 ********************************************************************/
196 void unistr2_to_ascii(char *dest, const UNISTR2 *str, size_t maxlen)
197 {
198         if (str == NULL) {
199                 *dest='\0';
200                 return;
201         }
202         pull_ucs2(NULL, dest, str->buffer, maxlen, str->uni_str_len*2, STR_NOALIGN);
203 }
204
205
206 /*******************************************************************
207  duplicate a UNISTR2 string into a null terminated char*
208  using a talloc context
209 ********************************************************************/
210 char *unistr2_tdup(TALLOC_CTX *ctx, const UNISTR2 *str)
211 {
212         char *s;
213         int maxlen = (str->uni_str_len+1)*4;
214         if (!str->buffer) return NULL;
215         s = (char *)talloc(ctx, maxlen); /* convervative */
216         if (!s) return NULL;
217         pull_ucs2(NULL, s, str->buffer, maxlen, str->uni_str_len*2, 
218                   STR_NOALIGN);
219         return s;
220 }
221
222
223 /*******************************************************************
224 Return a number stored in a buffer
225 ********************************************************************/
226
227 uint32 buffer2_to_uint32(BUFFER2 *str)
228 {
229         if (str->buf_len == 4)
230                 return IVAL(str->buffer, 0);
231         else
232                 return 0;
233 }
234
235 /*******************************************************************
236  Convert a wchar to upper case.
237 ********************************************************************/
238
239 smb_ucs2_t toupper_w(smb_ucs2_t val)
240 {
241         return upcase_table[val];
242 }
243
244 /*******************************************************************
245  Convert a wchar to lower case.
246 ********************************************************************/
247
248 smb_ucs2_t tolower_w( smb_ucs2_t val )
249 {
250         return lowcase_table[val];
251 }
252
253 /*******************************************************************
254 determine if a character is lowercase
255 ********************************************************************/
256 BOOL islower_w(smb_ucs2_t c)
257 {
258         return upcase_table[c] != c;
259 }
260
261 /*******************************************************************
262 determine if a character is uppercase
263 ********************************************************************/
264 BOOL isupper_w(smb_ucs2_t c)
265 {
266         return lowcase_table[c] != c;
267 }
268
269
270 /*******************************************************************
271 determine if a character is valid in a 8.3 name
272 ********************************************************************/
273 BOOL isvalid83_w(smb_ucs2_t c)
274 {
275         return valid_table[c] != 0;
276 }
277
278 /*******************************************************************
279  Count the number of characters in a smb_ucs2_t string.
280 ********************************************************************/
281 size_t strlen_w(const smb_ucs2_t *src)
282 {
283         size_t len;
284
285         for(len = 0; *src++; len++) ;
286
287         return len;
288 }
289
290 /*******************************************************************
291  Count up to max number of characters in a smb_ucs2_t string.
292 ********************************************************************/
293 size_t strnlen_w(const smb_ucs2_t *src, size_t max)
294 {
295         size_t len;
296
297         for(len = 0; *src++ && (len < max); len++) ;
298
299         return len;
300 }
301
302 /*******************************************************************
303 wide strchr()
304 ********************************************************************/
305 smb_ucs2_t *strchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
306 {
307         while (*s != 0) {
308                 if (c == *s) return (smb_ucs2_t *)s;
309                 s++;
310         }
311         return NULL;
312 }
313
314 smb_ucs2_t *strchr_wa(const smb_ucs2_t *s, char c)
315 {
316         return strchr_w(s, UCS2_CHAR(c));
317 }
318
319 smb_ucs2_t *strrchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
320 {
321         const smb_ucs2_t *p = s;
322         int len = strlen_w(s);
323         if (len == 0) return NULL;
324         p += (len - 1);
325         do {
326                 if (c == *p) return (smb_ucs2_t *)p;
327         } while (p-- != s);
328         return NULL;
329 }
330
331 /*******************************************************************
332 wide strstr()
333 ********************************************************************/
334 smb_ucs2_t *strstr_w(const smb_ucs2_t *s, const smb_ucs2_t *ins)
335 {
336         smb_ucs2_t *r;
337         size_t slen, inslen;
338
339         if (!s || !*s || !ins || !*ins) return NULL;
340         slen = strlen_w(s);
341         inslen = strlen_w(ins);
342         r = (smb_ucs2_t *)s;
343         while ((r = strchr_w(r, *ins))) {
344                 if (strncmp_w(r, ins, inslen) == 0) return r;
345                 r++;
346         }
347         return NULL;
348 }
349
350 /*******************************************************************
351  Convert a string to lower case.
352  return True if any char is converted
353 ********************************************************************/
354 BOOL strlower_w(smb_ucs2_t *s)
355 {
356         BOOL ret = False;
357         while (*s) {
358                 smb_ucs2_t v = tolower_w(*s);
359                 if (v != *s) {
360                         *s = v;
361                         ret = True;
362                 }
363                 s++;
364         }
365         return ret;
366 }
367
368 /*******************************************************************
369  Convert a string to upper case.
370  return True if any char is converted
371 ********************************************************************/
372 BOOL strupper_w(smb_ucs2_t *s)
373 {
374         BOOL ret = False;
375         while (*s) {
376                 smb_ucs2_t v = toupper_w(*s);
377                 if (v != *s) {
378                         *s = v;
379                         ret = True;
380                 }
381                 s++;
382         }
383         return ret;
384 }
385
386 /*******************************************************************
387   convert a string to "normal" form
388 ********************************************************************/
389 void strnorm_w(smb_ucs2_t *s)
390 {
391   extern int case_default;
392   if (case_default == CASE_UPPER)
393     strupper_w(s);
394   else
395     strlower_w(s);
396 }
397
398 int strcmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b)
399 {
400         while (*b && *a == *b) { a++; b++; }
401         return (*a - *b);
402         /* warning: if *a != *b and both are not 0 we retrun a random
403                 greater or lesser than 0 number not realted to which
404                 string is longer */
405 }
406
407 int strncmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b, size_t len)
408 {
409         size_t n = 0;
410         while ((n < len) && *b && *a == *b) { a++; b++; n++;}
411         return (len - n)?(*a - *b):0;   
412 }
413
414 /*******************************************************************
415 case insensitive string comparison
416 ********************************************************************/
417 int strcasecmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b)
418 {
419         while (*b && toupper_w(*a) == toupper_w(*b)) { a++; b++; }
420         return (tolower_w(*a) - tolower_w(*b));
421 }
422
423 /*******************************************************************
424 case insensitive string comparison, lenght limited
425 ********************************************************************/
426 int strncasecmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b, size_t len)
427 {
428         size_t n = 0;
429         while ((n < len) && *b && (toupper_w(*a) == toupper_w(*b))) { a++; b++; n++; }
430         return (len - n)?(tolower_w(*a) - tolower_w(*b)):0;
431 }
432
433 /*******************************************************************
434   compare 2 strings 
435 ********************************************************************/
436 BOOL strequal_w(const smb_ucs2_t *s1, const smb_ucs2_t *s2)
437 {
438         if (s1 == s2) return(True);
439         if (!s1 || !s2) return(False);
440   
441         return(strcasecmp_w(s1,s2)==0);
442 }
443
444 /*******************************************************************
445   compare 2 strings up to and including the nth char.
446   ******************************************************************/
447 BOOL strnequal_w(const smb_ucs2_t *s1,const smb_ucs2_t *s2,size_t n)
448 {
449   if (s1 == s2) return(True);
450   if (!s1 || !s2 || !n) return(False);
451   
452   return(strncasecmp_w(s1,s2,n)==0);
453 }
454
455 /*******************************************************************
456 duplicate string
457 ********************************************************************/
458 smb_ucs2_t *strdup_w(const smb_ucs2_t *src)
459 {
460         return strndup_w(src, 0);
461 }
462
463 /* if len == 0 then duplicate the whole string */
464 smb_ucs2_t *strndup_w(const smb_ucs2_t *src, size_t len)
465 {
466         smb_ucs2_t *dest;
467         
468         if (!len) len = strlen_w(src);
469         dest = (smb_ucs2_t *)malloc((len + 1) * sizeof(smb_ucs2_t));
470         if (!dest) {
471                 DEBUG(0,("strdup_w: out of memory!\n"));
472                 return NULL;
473         }
474
475         memcpy(dest, src, len * sizeof(smb_ucs2_t));
476         dest[len] = 0;
477         
478         return dest;
479 }
480
481 /*******************************************************************
482 copy a string with max len
483 ********************************************************************/
484
485 smb_ucs2_t *strncpy_w(smb_ucs2_t *dest, const smb_ucs2_t *src, const size_t max)
486 {
487         size_t len;
488         
489         if (!dest || !src) return NULL;
490         
491         for (len = 0; (src[len] != 0) && (len < max); len++)
492                 dest[len] = src[len];
493         while (len < max)
494                 dest[len++] = 0;
495         
496         return dest;
497 }
498
499
500 /*******************************************************************
501 append a string of len bytes and add a terminator
502 ********************************************************************/
503
504 smb_ucs2_t *strncat_w(smb_ucs2_t *dest, const smb_ucs2_t *src, const size_t max)
505 {       
506         size_t start;
507         size_t len;     
508         
509         if (!dest || !src) return NULL;
510         
511         start = strlen_w(dest);
512         len = strnlen_w(src, max);
513
514         memcpy(&dest[start], src, len*sizeof(smb_ucs2_t));                      
515         dest[start+len] = 0;
516         
517         return dest;
518 }
519
520 smb_ucs2_t *strcat_w(smb_ucs2_t *dest, const smb_ucs2_t *src)
521 {       
522         size_t start;
523         size_t len;     
524         
525         if (!dest || !src) return NULL;
526         
527         start = strlen_w(dest);
528         len = strlen_w(src);
529
530         memcpy(&dest[start], src, len*sizeof(smb_ucs2_t));                      
531         dest[start+len] = 0;
532         
533         return dest;
534 }
535
536
537 /*******************************************************************
538 replace any occurence of oldc with newc in unicode string
539 ********************************************************************/
540
541 void string_replace_w(smb_ucs2_t *s, smb_ucs2_t oldc, smb_ucs2_t newc)
542 {
543         for(;*s;s++) {
544                 if(*s==oldc) *s=newc;
545         }
546 }
547
548 /*******************************************************************
549 trim unicode string
550 ********************************************************************/
551
552 BOOL trim_string_w(smb_ucs2_t *s, const smb_ucs2_t *front,
553                                   const smb_ucs2_t *back)
554 {
555         BOOL ret = False;
556         size_t len, front_len, back_len;
557
558         if (!s || !*s) return False;
559
560         len = strlen_w(s);
561
562         if (front && *front) {
563                 front_len = strlen_w(front);
564                 while (len && strncmp_w(s, front, front_len) == 0) {
565                         memmove(s, (s + front_len), (len - front_len + 1) * sizeof(smb_ucs2_t));
566                         len -= front_len;
567                         ret = True;
568                 }
569         }
570         
571         if (back && *back) {
572                 back_len = strlen_w(back);
573                 while (len && strncmp_w((s + (len - back_len)), back, back_len) == 0) {
574                         s[len - back_len] = 0;
575                         len -= back_len;
576                         ret = True;
577                 }
578         }
579
580         return ret;
581 }
582
583 /*
584   The *_wa() functions take a combination of 7 bit ascii
585   and wide characters They are used so that you can use string
586   functions combining C string constants with ucs2 strings
587
588   The char* arguments must NOT be multibyte - to be completely sure
589   of this only pass string constants */
590
591
592 void pstrcpy_wa(smb_ucs2_t *dest, const char *src)
593 {
594         int i;
595         for (i=0;i<PSTRING_LEN;i++) {
596                 dest[i] = UCS2_CHAR(src[i]);
597                 if (src[i] == 0) return;
598         }
599 }
600
601 int strcmp_wa(const smb_ucs2_t *a, const char *b)
602 {
603         while (*b && *a == UCS2_CHAR(*b)) { a++; b++; }
604         return (*a - UCS2_CHAR(*b));
605 }
606
607 int strncmp_wa(const smb_ucs2_t *a, const char *b, size_t len)
608 {
609         size_t n = 0;
610         while ((n < len) && *b && *a == UCS2_CHAR(*b)) { a++; b++; n++;}
611         return (len - n)?(*a - UCS2_CHAR(*b)):0;
612 }
613
614 smb_ucs2_t *strpbrk_wa(const smb_ucs2_t *s, const char *p)
615 {
616         while (*s != 0) {
617                 int i;
618                 for (i=0; p[i] && *s != UCS2_CHAR(p[i]); i++) 
619                         ;
620                 if (p[i]) return (smb_ucs2_t *)s;
621                 s++;
622         }
623         return NULL;
624 }
625
626 smb_ucs2_t *strstr_wa(const smb_ucs2_t *s, const char *ins)
627 {
628         smb_ucs2_t *r;
629         size_t slen, inslen;
630
631         if (!s || !*s || !ins || !*ins) return NULL;
632         slen = strlen_w(s);
633         inslen = strlen(ins);
634         r = (smb_ucs2_t *)s;
635         while ((r = strchr_w(r, UCS2_CHAR(*ins)))) {
636                 if (strncmp_wa(r, ins, inslen) == 0) return r;
637                 r++;
638         }
639         return NULL;
640 }
641
642 /*******************************************************************
643 copy a string with max len
644 ********************************************************************/
645
646 smb_ucs2_t *strncpy_wa(smb_ucs2_t *dest, const char *src, const size_t max)
647 {
648         smb_ucs2_t *ucs2_src;
649
650         if (!dest || !src) return NULL;
651         if (!(ucs2_src = acnv_uxu2(src)))
652                 return NULL;
653         
654         strncpy_w(dest, ucs2_src, max);
655         SAFE_FREE(ucs2_src);
656         return dest;
657 }
658
659 /*******************************************************************
660 convert and duplicate an ascii string
661 ********************************************************************/
662 smb_ucs2_t *strdup_wa(const char *src)
663 {
664         return strndup_wa(src, 0);
665 }
666
667 /* if len == 0 then duplicate the whole string */
668 smb_ucs2_t *strndup_wa(const char *src, size_t len)
669 {
670         smb_ucs2_t *dest, *s;
671
672         s = acnv_dosu2(src);    
673         if (!len) len = strlen_w(s);
674         dest = (smb_ucs2_t *)malloc((len + 1) * sizeof(smb_ucs2_t));
675         if (!dest) {
676                 DEBUG(0,("strdup_w: out of memory!\n"));
677                 SAFE_FREE(s);
678                 return NULL;
679         }
680
681         memcpy(dest, src, len * sizeof(smb_ucs2_t));
682         dest[len] = 0;
683
684         SAFE_FREE(s);
685         return dest;
686 }
687
688 /*******************************************************************
689 append a string of len bytes and add a terminator
690 ********************************************************************/
691
692 smb_ucs2_t *strncat_wa(smb_ucs2_t *dest, const char *src, const size_t max)
693 {
694         smb_ucs2_t *ucs2_src;
695
696         if (!dest || !src) return NULL;
697         if (!(ucs2_src = acnv_uxu2(src)))
698                 return NULL;
699         
700         strncat_w(dest, ucs2_src, max);
701         SAFE_FREE(ucs2_src);
702         return dest;
703 }
704
705 smb_ucs2_t *strcat_wa(smb_ucs2_t *dest, const char *src)
706 {       
707         smb_ucs2_t *ucs2_src;
708         
709         if (!dest || !src) return NULL;
710         if (!(ucs2_src = acnv_uxu2(src)))
711                 return NULL;
712         
713         strcat_w(dest, ucs2_src);
714         SAFE_FREE(ucs2_src);
715         return dest;
716 }
717
718 BOOL trim_string_wa(smb_ucs2_t *s, const char *front,
719                                   const char *back)
720 {
721         wpstring f, b;
722
723         if (front) push_ucs2(NULL, f, front, sizeof(wpstring) - 1, STR_TERMINATE);
724         else *f = 0;
725         if (back) push_ucs2(NULL, b, back, sizeof(wpstring) - 1, STR_TERMINATE);
726         else *b = 0;
727         return trim_string_w(s, f, b);
728 }