55d56acf59cffbe879d31dbf50aaa6142d16fb2c
[nivanova/samba-autobuild/.git] / source3 / lib / charcnv.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    Character set conversion Extensions
5    Copyright (C) Igor Vergeichik <iverg@mail.ru> 2001
6    Copyright (C) Andrew Tridgell 2001
7    
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.
12    
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.
17    
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.
21
22 */
23 #include "includes.h"
24
25 extern int DEBUGLEVEL;
26
27 static pstring cvtbuf;
28
29 static smb_iconv_t conv_handles[NUM_CHARSETS][NUM_CHARSETS];
30
31 /****************************************************************************
32 return the name of a charset to give to iconv()
33 ****************************************************************************/
34 static char *charset_name(charset_t ch)
35 {
36         char *ret = NULL;
37
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();
42
43         if (!ret || !*ret) ret = "ASCII";
44         return ret;
45 }
46
47 /****************************************************************************
48  Initialize iconv conversion descriptors 
49 ****************************************************************************/
50 void init_iconv(void)
51 {
52         int c1, c2;
53
54         /* so that charset_name() works we need to get the UNIX<->UCS2 going
55            first */
56         if (!conv_handles[CH_UNIX][CH_UCS2]) {
57                 conv_handles[CH_UNIX][CH_UCS2] = smb_iconv_open("UCS-2LE", "ASCII");
58         }
59         if (!conv_handles[CH_UCS2][CH_UNIX]) {
60                 conv_handles[CH_UCS2][CH_UNIX] = smb_iconv_open("ASCII", "UCS-2LE");
61         }
62         
63
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]);
70                         }
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;
76                         }
77                 }
78         }
79 }
80
81 /****************************************************************************
82  Convert string from one encoding to another, makeing error checking etc
83  Parameters:
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)
94 {
95         size_t i_len, o_len;
96         size_t retval;
97         const char* inbuf = (const char*)src;
98         char* outbuf = (char*)dest;
99         static int initialised;
100         smb_iconv_t descriptor;
101
102         if (srclen == -1) srclen = strlen(src)+1;
103
104         if (!initialised) {
105                 initialised = 1;
106                 init_iconv();
107         }
108
109         descriptor = conv_handles[from][to];
110
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);
115                 return len;
116         }
117
118         i_len=srclen;
119         o_len=destlen;
120         retval=smb_iconv(descriptor,&inbuf, &i_len, &outbuf, &o_len);
121         if(retval==-1)          
122         {       char *reason="unknown error";
123                 switch(errno)
124                 { case EINVAL: reason="Incomplete multybyte sequence"; break;
125                   case E2BIG:  reason="No more room"; 
126                                DEBUG(0, ("Required %d, available %d\n",
127                                srclen, destlen));       
128                                break;
129                   case EILSEQ: reason="Illegal myltybyte sequence"; break;
130                 }
131                 DEBUG(0,("Conversion error:%s(%s)\n",reason,inbuf));
132                 /* smb_panic(reason); */
133         }
134         return destlen-o_len;
135 }
136
137 int unix_strupper(const char *src, size_t srclen, char *dest, size_t destlen)
138 {
139         int size,len;
140         smb_ucs2_t *buffer=(smb_ucs2_t*)cvtbuf;
141         size=convert_string(CH_UNIX, CH_UCS2, src, srclen, buffer, sizeof(cvtbuf));
142         len=size/2;
143         if (!strupper_w(buffer) && (dest == src)) return srclen;
144         return convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen);
145 }
146
147 int unix_strlower(const char *src, size_t srclen, char *dest, size_t destlen)
148 {
149         int size,len;
150         smb_ucs2_t *buffer=(smb_ucs2_t*)cvtbuf;
151         size=convert_string(CH_UNIX, CH_UCS2, src, srclen, buffer, sizeof(cvtbuf));
152         len=size/2;
153         if (!strlower_w(buffer) && (dest == src)) return srclen;
154         return convert_string(CH_UCS2, CH_UNIX, buffer, size, dest, destlen);
155 }
156
157
158 int ucs2_align(const void *base_ptr, const void *p, int flags)
159 {
160         if (flags & (STR_NOALIGN|STR_ASCII)) return 0;
161         return PTR_DIFF(p, base_ptr) & 1;
162 }
163
164
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
168 flags can have:
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)
175 {
176         int src_len = strlen(src);
177         pstring tmpbuf;
178
179         /* treat a pstring as "unlimited" length */
180         if (dest_len == -1) {
181                 dest_len = sizeof(pstring);
182         }
183
184         if (flags & STR_UPPER) {
185                 pstrcpy(tmpbuf, src);
186                 strupper(tmpbuf);
187                 src = tmpbuf;
188         }
189
190         if (flags & STR_TERMINATE) {
191                 src_len++;
192         }
193
194         return convert_string(CH_UNIX, CH_DOS, src, src_len, dest, dest_len);
195 }
196
197 int push_ascii_fstring(void *dest, const char *src)
198 {
199         return push_ascii(dest, src, sizeof(fstring), STR_TERMINATE);
200 }
201
202 int push_ascii_pstring(void *dest, const char *src)
203 {
204         return push_ascii(dest, src, sizeof(pstring), STR_TERMINATE);
205 }
206
207 int push_pstring(void *dest, const char *src)
208 {
209         return push_ascii(dest, src, sizeof(pstring), STR_TERMINATE);
210 }
211
212
213 /****************************************************************************
214 copy a string from a dos codepage source to a unix char* destination
215 flags can have:
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)
223 {
224         int ret;
225
226         if (dest_len == -1) {
227                 dest_len = sizeof(pstring);
228         }
229
230         if (flags & STR_TERMINATE) src_len = strlen(src)+1;
231
232         ret = convert_string(CH_DOS, CH_UNIX, src, src_len, dest, dest_len);
233
234         if (dest_len) dest[MIN(ret, dest_len-1)] = 0;
235
236         return src_len;
237 }
238
239 int pull_ascii_pstring(char *dest, const void *src)
240 {
241         return pull_ascii(dest, src, sizeof(pstring), -1, STR_TERMINATE);
242 }
243
244 int pull_ascii_fstring(char *dest, const void *src)
245 {
246         return pull_ascii(dest, src, sizeof(fstring), -1, STR_TERMINATE);
247 }
248
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
252 flags can have:
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)
260 {
261         int len=0;
262         int src_len = strlen(src);
263         pstring tmpbuf;
264
265         /* treat a pstring as "unlimited" length */
266         if (dest_len == -1) {
267                 dest_len = sizeof(pstring);
268         }
269
270         if (flags & STR_UPPER) {
271                 pstrcpy(tmpbuf, src);
272                 strupper(tmpbuf);
273                 src = tmpbuf;
274         }
275
276         if (flags & STR_TERMINATE) {
277                 src_len++;
278         }
279
280         if (ucs2_align(base_ptr, dest, flags)) {
281                 *(char *)dest = 0;
282                 dest = (void *)((char *)dest + 1);
283                 if (dest_len) dest_len--;
284                 len++;
285         }
286
287         /* ucs2 is always a multiple of 2 bytes */
288         dest_len &= ~1;
289
290         len += convert_string(CH_UNIX, CH_UCS2, src, src_len, dest, dest_len);
291         return len;
292 }
293
294
295 /****************************************************************************
296 copy a string from a ucs2 source to a unix char* destination
297 flags can have:
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)
306 {
307         int ret;
308
309         if (dest_len == -1) {
310                 dest_len = sizeof(pstring);
311         }
312
313         if (ucs2_align(base_ptr, src, flags)) {
314                 src = (const void *)((const char *)src + 1);
315                 if (src_len > 0) src_len--;
316         }
317
318         if (flags & STR_TERMINATE) src_len = strlen_w(src)*2+2;
319
320         /* ucs2 is always a multiple of 2 bytes */
321         src_len &= ~1;
322         
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;
325
326         return src_len;
327 }
328
329 int pull_ucs2_pstring(char *dest, const void *src)
330 {
331         return pull_ucs2(NULL, dest, src, sizeof(pstring), -1, STR_TERMINATE);
332 }
333
334 int pull_ucs2_fstring(char *dest, const void *src)
335 {
336         return pull_ucs2(NULL, dest, src, sizeof(fstring), -1, STR_TERMINATE);
337 }
338
339
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
345 flags can have:
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)
354 {
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);
359         }
360         return push_ascii(dest, src, dest_len, flags);
361 }
362
363
364 /****************************************************************************
365 copy a string from a unicode or ascii source (depending on
366 the packet flags) to a char* destination
367 flags can have:
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, 
378                 int flags)
379 {
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);
384         }
385         return pull_ascii(dest, src, dest_len, src_len, flags);
386 }
387
388 int align_string(const void *base_ptr, const char *p, int flags)
389 {
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);
394         }
395         return 0;
396 }