The big character set handling changeover!
[kai/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  smb_ucs2_t wchar_list_sep[] = { (smb_ucs2_t)' ', (smb_ucs2_t)'\t', (smb_ucs2_t)',',
27                                                                 (smb_ucs2_t)';', (smb_ucs2_t)':', (smb_ucs2_t)'\n',
28                                                                 (smb_ucs2_t)'\r', 0 };
29 /*
30  * The following are the codepage to ucs2 and vica versa maps.
31  * These are dynamically loaded from a unicode translation file.
32  */
33
34 #define CONV_DEBUGLEVEL         83
35
36 #ifndef MAXUNI
37 #define MAXUNI 1024
38 #endif
39
40 /*******************************************************************
41  Write a string in (little-endian) unicode format. src is in
42  the current DOS codepage. len is the length in bytes of the
43  string pointed to by dst.
44
45  if null_terminate is True then null terminate the packet (adds 2 bytes)
46
47  the return value is the length in bytes consumed by the string, including the
48  null termination if applied
49 ********************************************************************/
50
51 size_t dos_PutUniCode(char *dst,const char *src, ssize_t len, BOOL null_terminate)
52 {
53         return push_ucs2(NULL, dst, src, len, 
54                          STR_UNICODE|STR_NOALIGN | (null_terminate?STR_TERMINATE:0));
55 }
56
57
58 /*******************************************************************
59  Skip past a unicode string, but not more than len. Always move
60  past a terminating zero if found.
61 ********************************************************************/
62
63 char *skip_unibuf(char *src, size_t len)
64 {
65     char *srcend = src + len;
66
67     while (src < srcend && SVAL(src,0))
68         src += 2;
69
70     if(!SVAL(src,0))
71         src += 2;
72
73     return src;
74 }
75
76 /* Copy a string from little-endian or big-endian unicode source (depending
77  * on flags) to internal samba format destination
78  */ 
79 int rpcstr_pull(char* dest, void *src, int dest_len, int src_len, int flags)
80 {
81         if(dest_len==-1) dest_len=MAXUNI-3;
82         return pull_ucs2(NULL, dest, src, dest_len, src_len, flags|STR_UNICODE|STR_NOALIGN);
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(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, 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         if (v < TABLE1_BOUNDARY) return map_table1[v].flags;
163         if (v >= TABLE2_BOUNDARY) return map_table2[v - TABLE2_BOUNDARY].flags;
164         return 0;
165 }
166
167 static smb_ucs2_t map_table_lower(smb_ucs2_t v)
168 {
169         if (v < TABLE1_BOUNDARY) return map_table1[v].lower;
170         if (v >= TABLE2_BOUNDARY) return map_table2[v - TABLE2_BOUNDARY].lower;
171         return v;
172 }
173
174 static smb_ucs2_t map_table_upper(smb_ucs2_t v)
175 {
176         if (v < TABLE1_BOUNDARY) return map_table1[v].upper;
177         if (v >= TABLE2_BOUNDARY) return map_table2[v - TABLE2_BOUNDARY].upper;
178         return v;
179 }
180
181 /*******************************************************************
182  Is an upper case wchar.
183 ********************************************************************/
184
185 int isupper_w( smb_ucs2_t val)
186 {
187         return (map_table_flags(val) & UNI_UPPER);
188 }
189
190 /*******************************************************************
191  Is a lower case wchar.
192 ********************************************************************/
193
194 int islower_w( smb_ucs2_t val)
195 {
196         return (map_table_flags(val) & UNI_LOWER);
197 }
198
199 /*******************************************************************
200  Convert a wchar to upper case.
201 ********************************************************************/
202
203 smb_ucs2_t toupper_w( smb_ucs2_t val )
204 {
205         return map_table_upper(val);
206 }
207
208 /*******************************************************************
209  Convert a wchar to lower case.
210 ********************************************************************/
211
212 smb_ucs2_t tolower_w( smb_ucs2_t val )
213 {
214         return map_table_lower(val);
215 }
216
217 /*******************************************************************
218  Count the number of characters in a smb_ucs2_t string.
219 ********************************************************************/
220 size_t strlen_w(const smb_ucs2_t *src)
221 {
222         size_t len;
223
224         for(len = 0; *src++; len++) ;
225
226         return len;
227 }
228
229 /*******************************************************************
230 wide strchr()
231 ********************************************************************/
232 smb_ucs2_t *strchr_w(const smb_ucs2_t *s, smb_ucs2_t c)
233 {
234         while (*s != 0) {
235                 if (c == *s) return (smb_ucs2_t *)s;
236                 s++;
237         }
238         return NULL;
239 }
240
241
242 /*******************************************************************
243  Convert a string to lower case.
244 ********************************************************************/
245 void strlower_w(smb_ucs2_t *s)
246 {
247         while (*s) {
248                 if (isupper_w(*s))
249                         *s = tolower_w(*s);
250                 s++;
251         }
252 }
253
254 /*******************************************************************
255  Convert a string to upper case.
256 ********************************************************************/
257 void strupper_w(smb_ucs2_t *s)
258 {
259         while (*s) {
260                 if (islower_w(*s))
261                         *s = toupper_w(*s);
262                 s++;
263         }
264 }
265
266 /*******************************************************************
267 case insensitive string comparison
268 ********************************************************************/
269 int strcasecmp_w(const smb_ucs2_t *a, const smb_ucs2_t *b)
270 {
271         while (*b && tolower_w(*a) == tolower_w(*b)) { a++; b++; }
272         return (tolower_w(*a) - tolower_w(*b));
273 }
274
275
276 /*
277   The *_wa() functions take a combination of 7 bit ascii
278   and wide characters They are used so that you can use string
279   functions combining C string constants with ucs2 strings
280
281   The char* arguments must NOT be multibyte - to be completely sure
282   of this only pass string constants */
283
284
285 void pstrcpy_wa(smb_ucs2_t *dest, const char *src)
286 {
287         int i;
288         for (i=0;i<PSTRING_LEN;i++) {
289                 dest[i] = UCS2_CHAR(src[i]);
290                 if (src[i] == 0) return;
291         }
292 }
293
294 int strcmp_wa(const smb_ucs2_t *a, const char *b)
295 {
296         while (*b && *a == UCS2_CHAR(*b)) { a++; b++; }
297         return (*a - UCS2_CHAR(*b));
298 }
299
300 smb_ucs2_t *strchr_wa(const smb_ucs2_t *s, char c)
301 {
302         while (*s != 0) {
303                 if (UCS2_CHAR(c) == *s) return (smb_ucs2_t *)s;
304                 s++;
305         }
306         return NULL;
307 }
308
309 smb_ucs2_t *strrchr_wa(const smb_ucs2_t *s, char c)
310 {
311         const smb_ucs2_t *p = s;
312         int len = strlen_w(s);
313         if (len == 0) return NULL;
314         p += (len-1);
315         while (p != s) {
316                 if (UCS2_CHAR(c) == *p) return (smb_ucs2_t *)p;
317                 p--;
318         }
319         return NULL;
320 }
321
322 smb_ucs2_t *strpbrk_wa(const smb_ucs2_t *s, const char *p)
323 {
324         while (*s != 0) {
325                 int i;
326                 for (i=0; p[i] && *s != UCS2_CHAR(p[i]); i++) 
327                         ;
328                 if (p[i]) return (smb_ucs2_t *)s;
329                 s++;
330         }
331         return NULL;
332 }
333