lib/util/charset Merge talloc-based pull and push charset functions
[samba.git] / lib / util / charset / 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 3 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, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "system/locale.h"
23
24 /**
25  String replace.
26  NOTE: oldc and newc must be 7 bit characters
27 **/
28 _PUBLIC_ void string_replace_m(char *s, char oldc, char newc)
29 {
30         struct smb_iconv_handle *ic = get_iconv_handle();
31         while (s && *s) {
32                 size_t size;
33                 codepoint_t c = next_codepoint_handle(ic, s, &size);
34                 if (c == oldc) {
35                         *s = newc;
36                 }
37                 s += size;
38         }
39 }
40
41 /**
42  Convert a string to lower case, allocated with talloc
43 **/
44 _PUBLIC_ char *strlower_talloc_handle(struct smb_iconv_handle *iconv_handle,
45                                       TALLOC_CTX *ctx, const char *src)
46 {
47         size_t size=0;
48         char *dest;
49
50         if(src == NULL) {
51                 return NULL;
52         }
53
54         /* this takes advantage of the fact that upper/lower can't
55            change the length of a character by more than 1 byte */
56         dest = talloc_array(ctx, char, 2*(strlen(src))+1);
57         if (dest == NULL) {
58                 return NULL;
59         }
60
61         while (*src) {
62                 size_t c_size;
63                 codepoint_t c = next_codepoint_handle(iconv_handle, src, &c_size);
64                 src += c_size;
65
66                 c = tolower_m(c);
67
68                 c_size = push_codepoint_handle(iconv_handle, dest+size, c);
69                 if (c_size == -1) {
70                         talloc_free(dest);
71                         return NULL;
72                 }
73                 size += c_size;
74         }
75
76         dest[size] = 0;
77
78         /* trim it so talloc_append_string() works */
79         dest = talloc_realloc(ctx, dest, char, size+1);
80
81         talloc_set_name_const(dest, dest);
82
83         return dest;
84 }
85
86 _PUBLIC_ char *strlower_talloc(TALLOC_CTX *ctx, const char *src)
87 {
88         struct smb_iconv_handle *iconv_handle = get_iconv_handle();
89         return strlower_talloc_handle(iconv_handle, ctx, src);
90 }
91
92 /**
93  Convert a string to UPPER case, allocated with talloc
94  source length limited to n bytes, iconv handle supplied
95 **/
96 _PUBLIC_ char *strupper_talloc_n_handle(struct smb_iconv_handle *iconv_handle,
97                                         TALLOC_CTX *ctx, const char *src, size_t n)
98 {
99         size_t size=0;
100         char *dest;
101
102         if (!src) {
103                 return NULL;
104         }
105
106         /* this takes advantage of the fact that upper/lower can't
107            change the length of a character by more than 1 byte */
108         dest = talloc_array(ctx, char, 2*(n+1));
109         if (dest == NULL) {
110                 return NULL;
111         }
112
113         while (n-- && *src) {
114                 size_t c_size;
115                 codepoint_t c = next_codepoint_handle(iconv_handle, src, &c_size);
116                 src += c_size;
117
118                 c = toupper_m(c);
119
120                 c_size = push_codepoint_handle(iconv_handle, dest+size, c);
121                 if (c_size == -1) {
122                         talloc_free(dest);
123                         return NULL;
124                 }
125                 size += c_size;
126         }
127
128         dest[size] = 0;
129
130         /* trim it so talloc_append_string() works */
131         dest = talloc_realloc(ctx, dest, char, size+1);
132
133         talloc_set_name_const(dest, dest);
134
135         return dest;
136 }
137
138 /**
139  Convert a string to UPPER case, allocated with talloc
140  source length limited to n bytes
141 **/
142 _PUBLIC_ char *strupper_talloc_n(TALLOC_CTX *ctx, const char *src, size_t n)
143 {
144         struct smb_iconv_handle *iconv_handle = get_iconv_handle();
145         return strupper_talloc_n_handle(iconv_handle, ctx, src, n);
146 }
147 /**
148  Convert a string to UPPER case, allocated with talloc
149 **/
150 _PUBLIC_ char *strupper_talloc(TALLOC_CTX *ctx, const char *src)
151 {
152         return strupper_talloc_n(ctx, src, src?strlen(src):0);
153 }
154
155 /**
156  talloc_strdup() a unix string to upper case.
157 **/
158 _PUBLIC_ char *talloc_strdup_upper(TALLOC_CTX *ctx, const char *src)
159 {
160         return strupper_talloc(ctx, src);
161 }
162
163 /**
164  Convert a string to lower case.
165 **/
166 _PUBLIC_ void strlower_m(char *s)
167 {
168         char *d;
169         struct smb_iconv_handle *iconv_handle;
170
171         /* this is quite a common operation, so we want it to be
172            fast. We optimise for the ascii case, knowing that all our
173            supported multi-byte character sets are ascii-compatible
174            (ie. they match for the first 128 chars) */
175         while (*s && !(((uint8_t)*s) & 0x80)) {
176                 *s = tolower((uint8_t)*s);
177                 s++;
178         }
179
180         if (!*s)
181                 return;
182
183         iconv_handle = get_iconv_handle();
184
185         d = s;
186
187         while (*s) {
188                 size_t c_size, c_size2;
189                 codepoint_t c = next_codepoint_handle(iconv_handle, s, &c_size);
190                 c_size2 = push_codepoint_handle(iconv_handle, d, tolower_m(c));
191                 if (c_size2 > c_size) {
192                         DEBUG(0,("FATAL: codepoint 0x%x (0x%x) expanded from %d to %d bytes in strlower_m\n",
193                                  c, tolower_m(c), (int)c_size, (int)c_size2));
194                         smb_panic("codepoint expansion in strlower_m\n");
195                 }
196                 s += c_size;
197                 d += c_size2;
198         }
199         *d = 0;
200 }
201
202 /**
203  Convert a string to UPPER case.
204 **/
205 _PUBLIC_ void strupper_m(char *s)
206 {
207         char *d;
208         struct smb_iconv_handle *iconv_handle;
209
210         /* this is quite a common operation, so we want it to be
211            fast. We optimise for the ascii case, knowing that all our
212            supported multi-byte character sets are ascii-compatible
213            (ie. they match for the first 128 chars) */
214         while (*s && !(((uint8_t)*s) & 0x80)) {
215                 *s = toupper((uint8_t)*s);
216                 s++;
217         }
218
219         if (!*s)
220                 return;
221
222         iconv_handle = get_iconv_handle();
223
224         d = s;
225
226         while (*s) {
227                 size_t c_size, c_size2;
228                 codepoint_t c = next_codepoint_handle(iconv_handle, s, &c_size);
229                 c_size2 = push_codepoint_handle(iconv_handle, d, toupper_m(c));
230                 if (c_size2 > c_size) {
231                         DEBUG(0,("FATAL: codepoint 0x%x (0x%x) expanded from %d to %d bytes in strupper_m\n",
232                                  c, toupper_m(c), (int)c_size, (int)c_size2));
233                         smb_panic("codepoint expansion in strupper_m\n");
234                 }
235                 s += c_size;
236                 d += c_size2;
237         }
238         *d = 0;
239 }
240
241
242 /**
243  Find the number of 'c' chars in a string
244 **/
245 _PUBLIC_ size_t count_chars_m(const char *s, char c)
246 {
247         struct smb_iconv_handle *ic = get_iconv_handle();
248         size_t count = 0;
249
250         while (*s) {
251                 size_t size;
252                 codepoint_t c2 = next_codepoint_handle(ic, s, &size);
253                 if (c2 == c) count++;
254                 s += size;
255         }
256
257         return count;
258 }
259
260
261 /**
262  * Copy a string from a char* unix src to a dos codepage string destination.
263  *
264  * @converted_size the number of bytes occupied by the string in the destination.
265  * @return bool true if success.
266  *
267  * @param flags can include
268  * <dl>
269  * <dt>STR_TERMINATE</dt> <dd>means include the null termination</dd>
270  * <dt>STR_UPPER</dt> <dd>means uppercase in the destination</dd>
271  * </dl>
272  *
273  * @param dest_len the maximum length in bytes allowed in the
274  * destination.  If @p dest_len is -1 then no maximum is used.
275  **/
276 static bool push_ascii(void *dest, const char *src, size_t dest_len, int flags, size_t *converted_size)
277 {
278         size_t src_len;
279         bool ret;
280
281         if (flags & STR_UPPER) {
282                 char *tmpbuf = strupper_talloc(NULL, src);
283                 if (tmpbuf == NULL) {
284                         return false;
285                 }
286                 ret = push_ascii(dest, tmpbuf, dest_len, flags & ~STR_UPPER, converted_size);
287                 talloc_free(tmpbuf);
288                 return ret;
289         }
290
291         src_len = strlen(src);
292
293         if (flags & (STR_TERMINATE | STR_TERMINATE_ASCII))
294                 src_len++;
295
296         return convert_string(CH_UNIX, CH_DOS, src, src_len, dest, dest_len, converted_size);
297 }
298
299 /**
300  * Copy a string from a dos codepage source to a unix char* destination.
301  *
302  * The resulting string in "dest" is always null terminated.
303  *
304  * @param flags can have:
305  * <dl>
306  * <dt>STR_TERMINATE</dt>
307  * <dd>STR_TERMINATE means the string in @p src
308  * is null terminated, and src_len is ignored.</dd>
309  * </dl>
310  *
311  * @param src_len is the length of the source area in bytes.
312  * @returns the number of bytes occupied by the string in @p src.
313  **/
314 static ssize_t pull_ascii(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
315 {
316         size_t size = 0;
317
318         if (flags & (STR_TERMINATE | STR_TERMINATE_ASCII)) {
319                 if (src_len == (size_t)-1) {
320                         src_len = strlen((const char *)src) + 1;
321                 } else {
322                         size_t len = strnlen((const char *)src, src_len);
323                         if (len < src_len)
324                                 len++;
325                         src_len = len;
326                 }
327         }
328
329         /* We're ignoring the return here.. */
330         (void)convert_string(CH_DOS, CH_UNIX, src, src_len, dest, dest_len, &size);
331
332         if (dest_len)
333                 dest[MIN(size, dest_len-1)] = 0;
334
335         return src_len;
336 }
337
338 /**
339  * Copy a string from a char* src to a unicode destination.
340  *
341  * @returns the number of bytes occupied by the string in the destination.
342  *
343  * @param flags can have:
344  *
345  * <dl>
346  * <dt>STR_TERMINATE <dd>means include the null termination.
347  * <dt>STR_UPPER     <dd>means uppercase in the destination.
348  * <dt>STR_NOALIGN   <dd>means don't do alignment.
349  * </dl>
350  *
351  * @param dest_len is the maximum length allowed in the
352  * destination. If dest_len is -1 then no maxiumum is used.
353  **/
354 static ssize_t push_ucs2(void *dest, const char *src, size_t dest_len, int flags)
355 {
356         size_t len=0;
357         size_t src_len = strlen(src);
358         size_t size = 0;
359         bool ret;
360
361         if (flags & STR_UPPER) {
362                 char *tmpbuf = strupper_talloc(NULL, src);
363                 ssize_t retval;
364                 if (tmpbuf == NULL) {
365                         return -1;
366                 }
367                 retval = push_ucs2(dest, tmpbuf, dest_len, flags & ~STR_UPPER);
368                 talloc_free(tmpbuf);
369                 return retval;
370         }
371
372         if (flags & STR_TERMINATE)
373                 src_len++;
374
375         if (ucs2_align(NULL, dest, flags)) {
376                 *(char *)dest = 0;
377                 dest = (void *)((char *)dest + 1);
378                 if (dest_len) dest_len--;
379                 len++;
380         }
381
382         /* ucs2 is always a multiple of 2 bytes */
383         dest_len &= ~1;
384
385         ret = convert_string(CH_UNIX, CH_UTF16, src, src_len, dest, dest_len, &size);
386         if (ret == false) {
387                 return 0;
388         }
389
390         len += size;
391
392         return (ssize_t)len;
393 }
394
395
396 /**
397  Copy a string from a ucs2 source to a unix char* destination.
398  Flags can have:
399   STR_TERMINATE means the string in src is null terminated.
400   STR_NOALIGN   means don't try to align.
401  if STR_TERMINATE is set then src_len is ignored if it is -1.
402  src_len is the length of the source area in bytes
403  Return the number of bytes occupied by the string in src.
404  The resulting string in "dest" is always null terminated.
405 **/
406
407 static size_t pull_ucs2(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
408 {
409         size_t size = 0;
410
411         if (ucs2_align(NULL, src, flags)) {
412                 src = (const void *)((const char *)src + 1);
413                 if (src_len > 0)
414                         src_len--;
415         }
416
417         if (flags & STR_TERMINATE) {
418                 if (src_len == (size_t)-1) {
419                         src_len = utf16_len(src);
420                 } else {
421                         src_len = utf16_len_n(src, src_len);
422                 }
423         }
424
425         /* ucs2 is always a multiple of 2 bytes */
426         if (src_len != (size_t)-1)
427                 src_len &= ~1;
428
429         /* We're ignoring the return here.. */
430         (void)convert_string(CH_UTF16, CH_UNIX, src, src_len, dest, dest_len, &size);
431         if (dest_len)
432                 dest[MIN(size, dest_len-1)] = 0;
433
434         return src_len;
435 }
436
437 /**
438  Copy a string from a char* src to a unicode or ascii
439  dos codepage destination choosing unicode or ascii based on the 
440  flags in the SMB buffer starting at base_ptr.
441  Return the number of bytes occupied by the string in the destination.
442  flags can have:
443   STR_TERMINATE means include the null termination.
444   STR_UPPER     means uppercase in the destination.
445   STR_ASCII     use ascii even with unicode packet.
446   STR_NOALIGN   means don't do alignment.
447  dest_len is the maximum length allowed in the destination. If dest_len
448  is -1 then no maxiumum is used.
449 **/
450
451 _PUBLIC_ ssize_t push_string(void *dest, const char *src, size_t dest_len, int flags)
452 {
453         if (flags & STR_ASCII) {
454                 size_t size = 0;
455                 if (push_ascii(dest, src, dest_len, flags, &size)) {
456                         return (ssize_t)size;
457                 } else {
458                         return (ssize_t)-1;
459                 }
460         } else if (flags & STR_UNICODE) {
461                 return push_ucs2(dest, src, dest_len, flags);
462         } else {
463                 smb_panic("push_string requires either STR_ASCII or STR_UNICODE flag to be set");
464                 return -1;
465         }
466 }
467
468
469 /**
470  Copy a string from a unicode or ascii source (depending on
471  the packet flags) to a char* destination.
472  Flags can have:
473   STR_TERMINATE means the string in src is null terminated.
474   STR_UNICODE   means to force as unicode.
475   STR_ASCII     use ascii even with unicode packet.
476   STR_NOALIGN   means don't do alignment.
477  if STR_TERMINATE is set then src_len is ignored is it is -1
478  src_len is the length of the source area in bytes.
479  Return the number of bytes occupied by the string in src.
480  The resulting string in "dest" is always null terminated.
481 **/
482
483 _PUBLIC_ ssize_t pull_string(char *dest, const void *src, size_t dest_len, size_t src_len, int flags)
484 {
485         if (flags & STR_ASCII) {
486                 return pull_ascii(dest, src, dest_len, src_len, flags);
487         } else if (flags & STR_UNICODE) {
488                 return pull_ucs2(dest, src, dest_len, src_len, flags);
489         } else {
490                 smb_panic("pull_string requires either STR_ASCII or STR_UNICODE flag to be set");
491                 return -1;
492         }
493 }