2 Unix SMB/Netbios implementation.
4 Character set conversion Extensions
5 Copyright (C) Igor Vergeichik <iverg@mail.ru> 2001
6 Copyright (C) Andrew Tridgell 2001
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.
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.
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.
25 static pstring cvtbuf;
27 static smb_iconv_t conv_handles[NUM_CHARSETS][NUM_CHARSETS];
29 static int initialized;
31 /****************************************************************************
32 return the name of a charset to give to iconv()
33 ****************************************************************************/
34 static char *charset_name(charset_t ch)
38 if (ch == CH_UCS2) ret = "UCS-2LE";
39 else if (ch == CH_UNIX) ret = lp_unix_charset();
40 else if (ch == CH_DOS) ret = lp_dos_charset();
41 else if (ch == CH_DISPLAY) ret = lp_display_charset();
43 if (!ret || !*ret) ret = "ASCII";
47 /****************************************************************************
48 Initialize iconv conversion descriptors
49 ****************************************************************************/
54 /* so that charset_name() works we need to get the UNIX<->UCS2 going
56 if (!conv_handles[CH_UNIX][CH_UCS2]) {
57 conv_handles[CH_UNIX][CH_UCS2] = smb_iconv_open("UCS-2LE", "ASCII");
59 if (!conv_handles[CH_UCS2][CH_UNIX]) {
60 conv_handles[CH_UCS2][CH_UNIX] = smb_iconv_open("ASCII", "UCS-2LE");
64 for (c1=0;c1<NUM_CHARSETS;c1++) {
65 for (c2=0;c2<NUM_CHARSETS;c2++) {
66 char *n1 = charset_name((charset_t)c1);
67 char *n2 = charset_name((charset_t)c2);
68 if (conv_handles[c1][c2]) {
69 smb_iconv_close(conv_handles[c1][c2]);
71 conv_handles[c1][c2] = smb_iconv_open(n2,n1);
72 if (conv_handles[c1][c2] == (smb_iconv_t)-1) {
73 DEBUG(0,("Conversion from %s to %s not supported\n",
74 charset_name((charset_t)c1), charset_name((charset_t)c2)));
75 conv_handles[c1][c2] = NULL;
81 /****************************************************************************
82 Convert string from one encoding to another, making error checking etc
84 descriptor - conversion descriptor, created in init_iconv
85 src - pointer to source string (multibyte or singlebyte)
86 srclen - length of the source string in bytes
87 dest - pointer to destination string (multibyte or singlebyte)
88 destlen - maximal length allowed for string
89 return the number of bytes occupied in the destination
90 ****************************************************************************/
91 size_t convert_string(charset_t from, charset_t to,
92 void const *src, size_t srclen,
93 void *dest, size_t destlen)
97 char* inbuf = (char*)src;
98 char* outbuf = (char*)dest;
99 smb_iconv_t descriptor;
101 if (srclen == -1) srclen = strlen(src)+1;
109 descriptor = conv_handles[from][to];
111 if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
112 /* conversion not supported, use as is */
113 int len = MIN(srclen,destlen);
114 memcpy(dest,src,len);
120 retval=smb_iconv(descriptor,&inbuf, &i_len, &outbuf, &o_len);
123 char *reason="unknown error";
125 { case EINVAL: reason="Incomplete multibyte sequence"; break;
126 case E2BIG: reason="No more room";
127 DEBUG(0, ("Required %d, available %d\n",
129 /* we are not sure we need srclen bytes,
130 may be more, may be less.
131 We only know we need more than destlen
136 case EILSEQ: reason="Illegal myltibyte sequence"; break;
138 DEBUG(0,("Conversion error: %s(%s)\n",reason,inbuf));
139 /* smb_panic(reason); */
141 return destlen-o_len;
144 /* you must provide source lenght -1 is not accepted as lenght.
145 this function will return the size in bytes of the converted string
146 or -1 in case of error.
148 size_t convert_string_allocate(charset_t from, charset_t to,
149 void const *src, size_t srclen, void **dest)
151 size_t i_len, o_len, destlen;
153 char* inbuf = (char *)src;
155 smb_iconv_t descriptor;
159 if (src == NULL || srclen == -1) return -1;
167 descriptor = conv_handles[from][to];
169 if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
170 /* conversion not supported, return -1*/
174 destlen = MAX(srclen, 1024);
177 destlen = destlen * 2;
178 ob = (char *)realloc(outbuf, destlen);
180 DEBUG(0, ("convert_string_allocate: realloc failed!\n"));
187 retval = smb_iconv(descriptor,
192 char *reason="unknown error";
196 reason="Incomplete multibyte sequence";
202 reason="Illegal myltibyte sequence";
205 DEBUG(0,("Conversion error: %s(%s)\n",reason,inbuf));
206 /* smb_panic(reason); */
210 destlen = destlen - o_len;
211 *dest = (char *)malloc(destlen);
213 DEBUG(0, ("convert_string_allocate: out of memory!\n"));
217 memcpy(*dest, outbuf, destlen);
223 int unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen)
226 smb_ucs2_t *buffer=(smb_ucs2_t*)cvtbuf;
227 size=convert_string(CH_UNIX, CH_UCS2, src, srclen, buffer, sizeof(cvtbuf));
228 if (!strupper_w(buffer) && (dest == src)) return srclen;
229 return convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen);
232 int unix_strlower(const char *src, size_t srclen, char *dest, size_t destlen)
235 smb_ucs2_t *buffer=(smb_ucs2_t*)cvtbuf;
236 size=convert_string(CH_UNIX, CH_UCS2, src, srclen, buffer, sizeof(cvtbuf));
237 if (!strlower_w(buffer) && (dest == src)) return srclen;
238 return convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen);
242 int ucs2_align(const void *base_ptr, const void *p, int flags)
244 if (flags & (STR_NOALIGN|STR_ASCII)) return 0;
245 return PTR_DIFF(p, base_ptr) & 1;
249 /****************************************************************************
250 copy a string from a char* unix src to a dos codepage string destination
251 return the number of bytes occupied by the string in the destination
253 STR_TERMINATE means include the null termination
254 STR_UPPER means uppercase in the destination
255 dest_len is the maximum length allowed in the destination. If dest_len
256 is -1 then no maxiumum is used
257 ****************************************************************************/
258 int push_ascii(void *dest, const char *src, int dest_len, int flags)
260 int src_len = strlen(src);
263 /* treat a pstring as "unlimited" length */
264 if (dest_len == -1) {
265 dest_len = sizeof(pstring);
268 if (flags & STR_UPPER) {
269 pstrcpy(tmpbuf, src);
274 if (flags & STR_TERMINATE) {
278 return convert_string(CH_UNIX, CH_DOS, src, src_len, dest, dest_len);
281 int push_ascii_fstring(void *dest, const char *src)
283 return push_ascii(dest, src, sizeof(fstring), STR_TERMINATE);
286 int push_ascii_pstring(void *dest, const char *src)
288 return push_ascii(dest, src, sizeof(pstring), STR_TERMINATE);
291 int push_pstring(void *dest, const char *src)
293 return push_ascii(dest, src, sizeof(pstring), STR_TERMINATE);
297 /****************************************************************************
298 copy a string from a dos codepage source to a unix char* destination
300 STR_TERMINATE means the string in src is null terminated
301 if STR_TERMINATE is set then src_len is ignored
302 src_len is the length of the source area in bytes
303 return the number of bytes occupied by the string in src
304 the resulting string in "dest" is always null terminated
305 ****************************************************************************/
306 int pull_ascii(char *dest, const void *src, int dest_len, int src_len, int flags)
310 if (dest_len == -1) {
311 dest_len = sizeof(pstring);
314 if (flags & STR_TERMINATE) src_len = strlen(src)+1;
316 ret = convert_string(CH_DOS, CH_UNIX, src, src_len, dest, dest_len);
318 if (dest_len) dest[MIN(ret, dest_len-1)] = 0;
323 int pull_ascii_pstring(char *dest, const void *src)
325 return pull_ascii(dest, src, sizeof(pstring), -1, STR_TERMINATE);
328 int pull_ascii_fstring(char *dest, const void *src)
330 return pull_ascii(dest, src, sizeof(fstring), -1, STR_TERMINATE);
333 /****************************************************************************
334 copy a string from a char* src to a unicode destination
335 return the number of bytes occupied by the string in the destination
337 STR_TERMINATE means include the null termination
338 STR_UPPER means uppercase in the destination
339 STR_NOALIGN means don't do alignment
340 dest_len is the maximum length allowed in the destination. If dest_len
341 is -1 then no maxiumum is used
342 ****************************************************************************/
343 int push_ucs2(const void *base_ptr, void *dest, const char *src, int dest_len, int flags)
346 int src_len = strlen(src);
349 /* treat a pstring as "unlimited" length */
350 if (dest_len == -1) {
351 dest_len = sizeof(pstring);
354 if (flags & STR_UPPER) {
355 pstrcpy(tmpbuf, src);
360 if (flags & STR_TERMINATE) {
364 if (ucs2_align(base_ptr, dest, flags)) {
366 dest = (void *)((char *)dest + 1);
367 if (dest_len) dest_len--;
371 /* ucs2 is always a multiple of 2 bytes */
374 len += convert_string(CH_UNIX, CH_UCS2, src, src_len, dest, dest_len);
379 /****************************************************************************
380 copy a string from a ucs2 source to a unix char* destination
382 STR_TERMINATE means the string in src is null terminated
383 STR_NOALIGN means don't try to align
384 if STR_TERMINATE is set then src_len is ignored
385 src_len is the length of the source area in bytes
386 return the number of bytes occupied by the string in src
387 the resulting string in "dest" is always null terminated
388 ****************************************************************************/
389 int pull_ucs2(const void *base_ptr, char *dest, const void *src, int dest_len, int src_len, int flags)
393 if (dest_len == -1) {
394 dest_len = sizeof(pstring);
397 if (ucs2_align(base_ptr, src, flags)) {
398 src = (const void *)((const char *)src + 1);
399 if (src_len > 0) src_len--;
402 if (flags & STR_TERMINATE) src_len = strlen_w(src)*2+2;
404 /* ucs2 is always a multiple of 2 bytes */
407 ret = convert_string(CH_UCS2, CH_UNIX, src, src_len, dest, dest_len);
408 if (dest_len) dest[MIN(ret, dest_len-1)] = 0;
413 int pull_ucs2_pstring(char *dest, const void *src)
415 return pull_ucs2(NULL, dest, src, sizeof(pstring), -1, STR_TERMINATE);
418 int pull_ucs2_fstring(char *dest, const void *src)
420 return pull_ucs2(NULL, dest, src, sizeof(fstring), -1, STR_TERMINATE);
424 /****************************************************************************
425 copy a string from a char* src to a unicode or ascii
426 dos codepage destination choosing unicode or ascii based on the
427 flags in the SMB buffer starting at base_ptr
428 return the number of bytes occupied by the string in the destination
430 STR_TERMINATE means include the null termination
431 STR_UPPER means uppercase in the destination
432 STR_ASCII use ascii even with unicode packet
433 STR_NOALIGN means don't do alignment
434 dest_len is the maximum length allowed in the destination. If dest_len
435 is -1 then no maxiumum is used
436 ****************************************************************************/
437 int push_string(const void *base_ptr, void *dest, const char *src, int dest_len, int flags)
439 if (!(flags & STR_ASCII) && \
440 ((flags & STR_UNICODE || \
441 (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
442 return push_ucs2(base_ptr, dest, src, dest_len, flags);
444 return push_ascii(dest, src, dest_len, flags);
448 /****************************************************************************
449 copy a string from a unicode or ascii source (depending on
450 the packet flags) to a char* destination
452 STR_TERMINATE means the string in src is null terminated
453 STR_UNICODE means to force as unicode
454 STR_ASCII use ascii even with unicode packet
455 STR_NOALIGN means don't do alignment
456 if STR_TERMINATE is set then src_len is ignored
457 src_len is the length of the source area in bytes
458 return the number of bytes occupied by the string in src
459 the resulting string in "dest" is always null terminated
460 ****************************************************************************/
461 int pull_string(const void *base_ptr, char *dest, const void *src, int dest_len, int src_len,
464 if (!(flags & STR_ASCII) && \
465 ((flags & STR_UNICODE || \
466 (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
467 return pull_ucs2(base_ptr, dest, src, dest_len, src_len, flags);
469 return pull_ascii(dest, src, dest_len, src_len, flags);
472 int align_string(const void *base_ptr, const char *p, int flags)
474 if (!(flags & STR_ASCII) && \
475 ((flags & STR_UNICODE || \
476 (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
477 return ucs2_align(base_ptr, p, flags);