make strupper() and strlower() not modify the string if it doesn't
[samba.git] / source3 / lib / util_unistr.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    Samba utility functions
5    Copyright (C) Andrew Tridgell 1992-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 extern int DEBUGLEVEL;
25
26 #ifndef MAXUNI
27 #define MAXUNI 1024
28 #endif
29
30 /*******************************************************************
31  Write a string in (little-endian) unicode format. src is in
32  the current DOS codepage. len is the length in bytes of the
33  string pointed to by dst.
34
35  if null_terminate is True then null terminate the packet (adds 2 bytes)
36
37  the return value is the length in bytes consumed by the string, including the
38  null termination if applied
39 ********************************************************************/
40
41 size_t dos_PutUniCode(char *dst,const char *src, ssize_t len, BOOL null_terminate)
42 {
43         return push_ucs2(NULL, dst, src, len, 
44                          STR_UNICODE|STR_NOALIGN | (null_terminate?STR_TERMINATE:0));
45 }
46
47
48 /*******************************************************************
49  Skip past a unicode string, but not more than len. Always move
50  past a terminating zero if found.
51 ********************************************************************/
52
53 char *skip_unibuf(char *src, size_t len)
54 {
55     char *srcend = src + len;
56
57     while (src < srcend && SVAL(src,0))
58         src += 2;
59
60     if(!SVAL(src,0))
61         src += 2;
62
63     return src;
64 }
65
66 /* Copy a string from little-endian or big-endian unicode source (depending
67  * on flags) to internal samba format destination
68  */ 
69 int rpcstr_pull(char* dest, void *src, int dest_len, int src_len, int flags)
70 {
71         if(dest_len==-1) dest_len=MAXUNI-3;
72         return pull_ucs2(NULL, dest, src, dest_len, src_len, flags|STR_UNICODE|STR_NOALIGN);
73 }
74
75 /* Copy a string from a unistr2 source to internal samba format
76    destination.  Use this instead of direct calls to rpcstr_pull() to avoid
77    having to determine whether the source string is null terminated. */
78
79 int rpcstr_pull_unistr2_fstring(char *dest, UNISTR2 *src)
80 {
81         return pull_ucs2(NULL, dest, src->buffer, sizeof(fstring),
82                          src->uni_str_len * 2, 0);
83 }
84
85 /* Converts a string from internal samba format to unicode
86  */ 
87 int rpcstr_push(void* dest, const char *src, int dest_len, int flags)
88 {
89         return push_ucs2(NULL, dest, src, dest_len, flags|STR_UNICODE|STR_NOALIGN);
90 }
91
92 /*******************************************************************
93  Return a DOS codepage version of a little-endian unicode string.
94  len is the filename length (ignoring any terminating zero) in uin16
95  units. Always null terminates.
96  Hack alert: uses fixed buffer(s).
97 ********************************************************************/
98 char *dos_unistrn2(const uint16 *src, int len)
99 {
100         static char lbufs[8][MAXUNI];
101         static int nexti;
102         char *lbuf = lbufs[nexti];
103         nexti = (nexti+1)%8;
104         pull_ucs2(NULL, lbuf, src, MAXUNI-3, len*2, STR_NOALIGN);
105         return lbuf;
106 }
107
108 /*******************************************************************
109  Convert a (little-endian) UNISTR2 structure to an ASCII string
110 ********************************************************************/
111 void unistr2_to_ascii(char *dest, const UNISTR2 *str, size_t maxlen)
112 {
113         if (str == NULL) {
114                 *dest='\0';
115                 return;
116         }
117         pull_ucs2(NULL, dest, str->buffer, maxlen, str->uni_str_len*2, STR_NOALIGN);
118 }
119
120
121 /*******************************************************************
122 Return a number stored in a buffer
123 ********************************************************************/
124
125 uint32 buffer2_to_uint32(BUFFER2 *str)
126 {
127         if (str->buf_len == 4)
128                 return IVAL(str->buffer, 0);
129         else
130                 return 0;
131 }
132
133 /*******************************************************************
134  Mapping tables for UNICODE character. Allows toupper/tolower and
135  isXXX functions to work.
136
137  tridge: split into 2 pieces. This saves us 5/6 of the memory
138  with a small speed penalty
139  The magic constants are the lower/upper range of the tables two
140  parts
141 ********************************************************************/
142
143 typedef struct {
144         smb_ucs2_t lower;
145         smb_ucs2_t upper;
146         unsigned char flags;
147 } smb_unicode_table_t;
148
149 #define TABLE1_BOUNDARY 9450
150 #define TABLE2_BOUNDARY 64256
151
152 static smb_unicode_table_t map_table1[] = {
153 #include "unicode_map_table1.h"
154 };
155
156 static smb_unicode_table_t map_table2[] = {
157 #include "unicode_map_table2.h"
158 };
159
160 static unsigned char map_table_flags(smb_ucs2_t v)
161 {
162         v = SVAL(&v,0);
163         if (v < TABLE1_BOUNDARY) return map_table1[v].flags;
164         if (v >= TABLE2_BOUNDARY) return map_table2[v - TABLE2_BOUNDARY].flags;
165         return 0;
166 }
167
168 static smb_ucs2_t map_table_lower(smb_ucs2_t v)
169 {
170         v = SVAL(&v,0);
171         if (v < TABLE1_BOUNDARY) return map_table1[v].lower;
172         if (v >= TABLE2_BOUNDARY) return map_table2[v - TABLE2_BOUNDARY].lower;
173         return v;
174 }
175
176 static smb_ucs2_t map_table_upper(smb_ucs2_t v)
177 {
178         v = SVAL(&v,0);
179         if (v < TABLE1_BOUNDARY) return map_table1[v].upper;
180         if (v >= TABLE2_BOUNDARY) return map_table2[v - TABLE2_BOUNDARY].upper;
181         return v;
182 }
183
184 /*******************************************************************
185  Is an upper case wchar.
186 ********************************************************************/
187
188 int isupper_w( smb_ucs2_t val)
189 {
190         return (map_table_flags(val) & UNI_UPPER);
191 }
192
193 /*******************************************************************
194  Is a lower case wchar.
195 ********************************************************************/
196
197 int islower_w( smb_ucs2_t val)
198 {
199         return (map_table_flags(val) & UNI_LOWER);
200 }
201
202 /*******************************************************************
203  Convert a wchar to upper case.
204 ********************************************************************/
205
206 smb_ucs2_t toupper_w( smb_ucs2_t val )
207 {
208         val = map_table_upper(val);
209         val = SVAL(&val,0);
210         return val;
211 }
212
213 /*******************************************************************
214  Convert a wchar to lower case.
215 ********************************************************************/
216
217 smb_ucs2_t tolower_w( smb_ucs2_t val )
218 {
219         val = map_table_lower(val);
220         val = SVAL(&val,0);
221         return val;
222 }
223
224 /*******************************************************************
225  Count the number of characters in a smb_ucs2_t string.
226 ********************************************************************/
227 size_t strlen_w(const smb_ucs2_t *src)
228 {
229         size_t len;
230
231         for(len = 0; *src++; len++) ;
232
233         return len;
234 }
235
236 /*******************************************************************
237 wide strchr()
238 ********************************************************************/
239 smb_ucs2_t *strchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
240 {
241         while (*s != 0) {
242                 if (c == *s) return (smb_ucs2_t *)s;
243                 s++;
244         }
245         return NULL;
246 }
247
248
249 /*******************************************************************
250  Convert a string to lower case.
251  return True if any char is converted
252 ********************************************************************/
253 BOOL strlower_w(smb_ucs2_t *s)
254 {
255         BOOL ret = False;
256         while (*s) {
257                 if (isupper_w(*s)) {
258                         *s = tolower_w(*s);
259                         ret = True;
260                 }
261                 s++;
262         }
263         return ret;
264 }
265
266 /*******************************************************************
267  Convert a string to upper case.
268  return True if any char is converted
269 ********************************************************************/
270 BOOL strupper_w(smb_ucs2_t *s)
271 {
272         BOOL ret = False;
273         while (*s) {
274                 if (islower_w(*s)) {
275                         *s = toupper_w(*s);
276                         ret = True;
277                 }
278                 s++;
279         }
280         return ret;
281 }
282
283 /*******************************************************************
284 case insensitive string comparison
285 ********************************************************************/
286 int strcasecmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b)
287 {
288         while (*b && tolower_w(*a) == tolower_w(*b)) { a++; b++; }
289         return (tolower_w(*a) - tolower_w(*b));
290 }
291
292
293 /*******************************************************************
294 duplicate string
295 ********************************************************************/
296 smb_ucs2_t *strdup_w(const smb_ucs2_t *src)
297 {
298         smb_ucs2_t *dest;
299         uint32 len;
300         
301         len = strlen_w(src);
302         dest = (smb_ucs2_t *)malloc((len+1)*sizeof(smb_ucs2_t));
303         if (!dest) {
304                 DEBUG(0,("strdup_w: out of memory!\n"));
305                 return NULL;
306         }
307
308         memcpy(dest, src, (len+1)*sizeof(smb_ucs2_t));
309         
310         return dest;
311 }
312
313 /*******************************************************************
314 copy a string with max len
315 ********************************************************************/
316
317 smb_ucs2_t *strncpy_w(smb_ucs2_t *dest, const smb_ucs2_t *src, const size_t max)
318 {
319         size_t len;
320         
321         if (!dest || !src) return NULL;
322         
323         for (len = 0; (src[len] != 0) && (len < max); len++)
324                 dest[len] = src[len];
325         while (len < max)
326                 dest[len++] = 0;
327         
328         return dest;
329 }
330
331
332 /*******************************************************************
333 append a string of len bytes and add a terminator
334 ********************************************************************/
335
336 smb_ucs2_t *strncat_w(smb_ucs2_t *dest, const smb_ucs2_t *src, const size_t max)
337 {       
338         size_t start;
339         size_t len;     
340         
341         if (!dest || !src) return NULL;
342         
343         start = strlen_w(dest);
344         len = strlen_w(src);
345         if (len > max) len = max;
346
347         memcpy(&dest[start], src, len);                 
348         dest[start+len+1] = 0;
349         
350         return dest;
351 }
352
353
354 /*
355   The *_wa() functions take a combination of 7 bit ascii
356   and wide characters They are used so that you can use string
357   functions combining C string constants with ucs2 strings
358
359   The char* arguments must NOT be multibyte - to be completely sure
360   of this only pass string constants */
361
362
363 void pstrcpy_wa(smb_ucs2_t *dest, const char *src)
364 {
365         int i;
366         for (i=0;i<PSTRING_LEN;i++) {
367                 dest[i] = UCS2_CHAR(src[i]);
368                 if (src[i] == 0) return;
369         }
370 }
371
372 int strcmp_wa(const smb_ucs2_t *a, const char *b)
373 {
374         while (*b && *a == UCS2_CHAR(*b)) { a++; b++; }
375         return (*a - UCS2_CHAR(*b));
376 }
377
378
379
380 smb_ucs2_t *strchr_wa(const smb_ucs2_t *s, char c)
381 {
382         while (*s != 0) {
383                 if (UCS2_CHAR(c) == *s) return (smb_ucs2_t *)s;
384                 s++;
385         }
386         return NULL;
387 }
388
389 smb_ucs2_t *strrchr_wa(const smb_ucs2_t *s, char c)
390 {
391         const smb_ucs2_t *p = s;
392         int len = strlen_w(s);
393         if (len == 0) return NULL;
394         p += (len-1);
395         do {
396                 if (UCS2_CHAR(c) == *p) return (smb_ucs2_t *)p;
397         } while (p-- != s);
398         return NULL;
399 }
400
401 smb_ucs2_t *strpbrk_wa(const smb_ucs2_t *s, const char *p)
402 {
403         while (*s != 0) {
404                 int i;
405                 for (i=0; p[i] && *s != UCS2_CHAR(p[i]); i++) 
406                         ;
407                 if (p[i]) return (smb_ucs2_t *)s;
408                 s++;
409         }
410         return NULL;
411 }
412
413
414 /*******************************************************************
415 copy a string with max len
416 ********************************************************************/
417
418 smb_ucs2_t *strncpy_wa(smb_ucs2_t *dest, const char *src, const size_t max)
419 {
420         smb_ucs2_t *ucs2_src;
421
422         if (!dest || !src) return NULL;
423         ucs2_src = (smb_ucs2_t *)malloc((strlen(src)+1)*sizeof(smb_ucs2_t));
424         if (!ucs2_src) {
425                 DEBUG(0,("strncpy_wa: out of memory!\n"));
426                 return NULL;
427         }
428         push_ucs2(NULL, ucs2_src, src, -1, STR_TERMINATE|STR_NOALIGN);
429         
430         strncpy_w(dest, ucs2_src, max);
431         SAFE_FREE(ucs2_src);
432         return dest;
433 }
434
435
436 /*******************************************************************
437 append a string of len bytes and add a terminator
438 ********************************************************************/
439
440 smb_ucs2_t *strncat_wa(smb_ucs2_t *dest, const char *src, const size_t max)
441 {
442         smb_ucs2_t *ucs2_src;
443
444         if (!dest || !src) return NULL;
445         ucs2_src = (smb_ucs2_t *)malloc((strlen(src)+1)*sizeof(smb_ucs2_t));
446         if (!ucs2_src) {
447                 DEBUG(0,("strncat_wa: out of memory!\n"));
448                 return NULL;
449         }
450         push_ucs2(NULL, ucs2_src, src, -1, STR_TERMINATE|STR_NOALIGN);
451         
452         strncat_w(dest, ucs2_src, max);
453         SAFE_FREE(ucs2_src);
454         return dest;
455 }
456