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 extern int DEBUGLEVEL;
27 static pstring cvtbuf;
29 static smb_iconv_t conv_handles[NUM_CHARSETS][NUM_CHARSETS];
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(c1);
67 char *n2 = charset_name(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(c1), charset_name(c2)));
75 conv_handles[c1][c2] = NULL;
81 /****************************************************************************
82 Convert string from one encoding to another, makeing error checking etc
84 descriptor - conversion descriptor, created in init_iconv
85 src - pointer to source string (multibute 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 const char* inbuf = (const char*)src;
98 char* outbuf = (char*)dest;
99 static int initialised;
100 smb_iconv_t descriptor;
102 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);
122 { char *reason="unknown error";
124 { case EINVAL: reason="Incomplete multybyte sequence"; break;
125 case E2BIG: reason="No more room";
126 DEBUG(0, ("Required %d, available %d\n",
129 case EILSEQ: reason="Illegal myltybyte sequence"; break;
131 DEBUG(0,("Conversion error:%s(%s)\n",reason,inbuf));
132 /* smb_panic(reason); */
134 return destlen-o_len;
137 int unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen)
140 smb_ucs2_t *buffer=(smb_ucs2_t*)cvtbuf;
141 size=convert_string(CH_UNIX, CH_UCS2, src, srclen, buffer, sizeof(cvtbuf));
143 if (!strupper_w(buffer) && (dest == src)) return srclen;
144 return convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen);
147 int unix_strlower(const char *src, size_t srclen, char *dest, size_t destlen)
150 smb_ucs2_t *buffer=(smb_ucs2_t*)cvtbuf;
151 size=convert_string(CH_UNIX, CH_UCS2, src, srclen, buffer, sizeof(cvtbuf));
153 if (!strlower_w(buffer) && (dest == src)) return srclen;
154 return convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen);
158 int ucs2_align(const void *base_ptr, const void *p, int flags)
160 if (flags & (STR_NOALIGN|STR_ASCII)) return 0;
161 return PTR_DIFF(p, base_ptr) & 1;
165 /****************************************************************************
166 copy a string from a char* unix src to a dos codepage string destination
167 return the number of bytes occupied by the string in the destination
169 STR_TERMINATE means include the null termination
170 STR_UPPER means uppercase in the destination
171 dest_len is the maximum length allowed in the destination. If dest_len
172 is -1 then no maxiumum is used
173 ****************************************************************************/
174 int push_ascii(void *dest, const char *src, int dest_len, int flags)
176 int src_len = strlen(src);
179 /* treat a pstring as "unlimited" length */
180 if (dest_len == -1) {
181 dest_len = sizeof(pstring);
184 if (flags & STR_UPPER) {
185 pstrcpy(tmpbuf, src);
190 if (flags & STR_TERMINATE) {
194 return convert_string(CH_UNIX, CH_DOS, src, src_len, dest, dest_len);
197 int push_ascii_fstring(void *dest, const char *src)
199 return push_ascii(dest, src, sizeof(fstring), STR_TERMINATE);
202 int push_ascii_pstring(void *dest, const char *src)
204 return push_ascii(dest, src, sizeof(pstring), STR_TERMINATE);
207 int push_pstring(void *dest, const char *src)
209 return push_ascii(dest, src, sizeof(pstring), STR_TERMINATE);
213 /****************************************************************************
214 copy a string from a dos codepage source to a unix char* destination
216 STR_TERMINATE means the string in src is null terminated
217 if STR_TERMINATE is set then src_len is ignored
218 src_len is the length of the source area in bytes
219 return the number of bytes occupied by the string in src
220 the resulting string in "dest" is always null terminated
221 ****************************************************************************/
222 int pull_ascii(char *dest, const void *src, int dest_len, int src_len, int flags)
226 if (dest_len == -1) {
227 dest_len = sizeof(pstring);
230 if (flags & STR_TERMINATE) src_len = strlen(src)+1;
232 ret = convert_string(CH_DOS, CH_UNIX, src, src_len, dest, dest_len);
234 if (dest_len) dest[MIN(ret, dest_len-1)] = 0;
239 int pull_ascii_pstring(char *dest, const void *src)
241 return pull_ascii(dest, src, sizeof(pstring), -1, STR_TERMINATE);
244 int pull_ascii_fstring(char *dest, const void *src)
246 return pull_ascii(dest, src, sizeof(fstring), -1, STR_TERMINATE);
249 /****************************************************************************
250 copy a string from a char* src to a unicode 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 STR_NOALIGN means don't do alignment
256 dest_len is the maximum length allowed in the destination. If dest_len
257 is -1 then no maxiumum is used
258 ****************************************************************************/
259 int push_ucs2(const void *base_ptr, void *dest, const char *src, int dest_len, int flags)
262 int src_len = strlen(src);
265 /* treat a pstring as "unlimited" length */
266 if (dest_len == -1) {
267 dest_len = sizeof(pstring);
270 if (flags & STR_UPPER) {
271 pstrcpy(tmpbuf, src);
276 if (flags & STR_TERMINATE) {
280 if (ucs2_align(base_ptr, dest, flags)) {
282 dest = (void *)((char *)dest + 1);
283 if (dest_len) dest_len--;
287 /* ucs2 is always a multiple of 2 bytes */
290 len += convert_string(CH_UNIX, CH_UCS2, src, src_len, dest, dest_len);
295 /****************************************************************************
296 copy a string from a ucs2 source to a unix char* destination
298 STR_TERMINATE means the string in src is null terminated
299 STR_NOALIGN means don't try to align
300 if STR_TERMINATE is set then src_len is ignored
301 src_len is the length of the source area in bytes
302 return the number of bytes occupied by the string in src
303 the resulting string in "dest" is always null terminated
304 ****************************************************************************/
305 int pull_ucs2(const void *base_ptr, char *dest, const void *src, int dest_len, int src_len, int flags)
309 if (dest_len == -1) {
310 dest_len = sizeof(pstring);
313 if (ucs2_align(base_ptr, src, flags)) {
314 src = (const void *)((const char *)src + 1);
315 if (src_len > 0) src_len--;
318 if (flags & STR_TERMINATE) src_len = strlen_w(src)*2+2;
320 /* ucs2 is always a multiple of 2 bytes */
323 ret = convert_string(CH_UCS2, CH_UNIX, src, src_len, dest, dest_len);
324 if (dest_len) dest[MIN(ret, dest_len-1)] = 0;
329 int pull_ucs2_pstring(char *dest, const void *src)
331 return pull_ucs2(NULL, dest, src, sizeof(pstring), -1, STR_TERMINATE);
334 int pull_ucs2_fstring(char *dest, const void *src)
336 return pull_ucs2(NULL, dest, src, sizeof(fstring), -1, STR_TERMINATE);
340 /****************************************************************************
341 copy a string from a char* src to a unicode or ascii
342 dos code page destination choosing unicode or ascii based on the
343 flags in the SMB buffer starting at base_ptr
344 return the number of bytes occupied by the string in the destination
346 STR_TERMINATE means include the null termination
347 STR_UPPER means uppercase in the destination
348 STR_ASCII use ascii even with unicode packet
349 STR_NOALIGN means don't do alignment
350 dest_len is the maximum length allowed in the destination. If dest_len
351 is -1 then no maxiumum is used
352 ****************************************************************************/
353 int push_string(const void *base_ptr, void *dest, const char *src, int dest_len, int flags)
355 if (!(flags & STR_ASCII) && \
356 ((flags & STR_UNICODE || \
357 (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
358 return push_ucs2(base_ptr, dest, src, dest_len, flags);
360 return push_ascii(dest, src, dest_len, flags);
364 /****************************************************************************
365 copy a string from a unicode or ascii source (depending on
366 the packet flags) to a char* destination
368 STR_TERMINATE means the string in src is null terminated
369 STR_UNICODE means to force as unicode
370 STR_ASCII use ascii even with unicode packet
371 STR_NOALIGN means don't do alignment
372 if STR_TERMINATE is set then src_len is ignored
373 src_len is the length of the source area in bytes
374 return the number of bytes occupied by the string in src
375 the resulting string in "dest" is always null terminated
376 ****************************************************************************/
377 int pull_string(const void *base_ptr, char *dest, const void *src, int dest_len, int src_len,
380 if (!(flags & STR_ASCII) && \
381 ((flags & STR_UNICODE || \
382 (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
383 return pull_ucs2(base_ptr, dest, src, dest_len, src_len, flags);
385 return pull_ascii(dest, src, dest_len, src_len, flags);
388 int align_string(const void *base_ptr, const char *p, int flags)
390 if (!(flags & STR_ASCII) && \
391 ((flags & STR_UNICODE || \
392 (SVAL(base_ptr, smb_flg2) & FLAGS2_UNICODE_STRINGS)))) {
393 return ucs2_align(base_ptr, p, flags);