Release alpha15.
[nivanova/samba-autobuild/.git] / lib / util / charset / charcnv.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Character set conversion Extensions
4    Copyright (C) Igor Vergeichik <iverg@mail.ru> 2001
5    Copyright (C) Andrew Tridgell 2001
6    Copyright (C) Simo Sorce 2001
7    Copyright (C) Jelmer Vernooij 2007
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
22 */
23 #include "includes.h"
24 #include "system/iconv.h"
25 #include "libcli/smb/smb_common.h"
26
27 /**
28  * @file
29  *
30  * @brief Character-set conversion routines built on our iconv.
31  * 
32  * @note Samba's internal character set (at least in the 3.0 series)
33  * is always the same as the one for the Unix filesystem.  It is
34  * <b>not</b> necessarily UTF-8 and may be different on machines that
35  * need i18n filenames to be compatible with Unix software.  It does
36  * have to be a superset of ASCII.  All multibyte sequences must start
37  * with a byte with the high bit set.
38  *
39  * @sa lib/iconv.c
40  */
41
42 /**
43  * Convert string from one encoding to another, making error checking etc
44  *
45  * @param mem_ctx Memory context
46  * @param cd Iconv handle
47  * @param src pointer to source string (multibyte or singlebyte)
48  * @param srclen length of the source string in bytes
49  * @param dest pointer to destination string (multibyte or singlebyte)
50  * @param destlen maximal length allowed for string
51  * @returns the number of bytes occupied in the destination
52  **/
53 _PUBLIC_ ssize_t iconv_talloc(TALLOC_CTX *ctx, 
54                                        smb_iconv_t cd,
55                                        void const *src, size_t srclen, 
56                                        void *dst)
57 {
58         size_t i_len, o_len, destlen;
59         void **dest = (void **)dst;
60         size_t retval;
61         const char *inbuf = (const char *)src;
62         char *outbuf, *ob;
63
64         *dest = NULL;
65
66         /* it is _very_ rare that a conversion increases the size by
67            more than 3x */
68         destlen = srclen;
69         outbuf = NULL;
70 convert:
71         destlen = 2 + (destlen*3);
72         ob = talloc_realloc(ctx, outbuf, char, destlen);
73         if (!ob) {
74                 DEBUG(0, ("iconv_talloc: realloc failed!\n"));
75                 talloc_free(outbuf);
76                 return (size_t)-1;
77         } else {
78                 outbuf = ob;
79         }
80
81         /* we give iconv 2 less bytes to allow us to terminate at the
82            end */
83         i_len = srclen;
84         o_len = destlen-2;
85         retval = smb_iconv(cd,
86                            &inbuf, &i_len,
87                            &outbuf, &o_len);
88         if(retval == (size_t)-1)                {
89                 const char *reason="unknown error";
90                 switch(errno) {
91                         case EINVAL:
92                                 reason="Incomplete multibyte sequence";
93                                 break;
94                         case E2BIG:
95                                 goto convert;           
96                         case EILSEQ:
97                                 reason="Illegal multibyte sequence";
98                                 break;
99                 }
100                 DEBUG(0,("Conversion error: %s - ",reason));
101                 dump_data(0, (const uint8_t *) inbuf, i_len);
102                 talloc_free(ob);
103                 return (size_t)-1;
104         }
105         
106         destlen = (destlen-2) - o_len;
107
108         /* guarantee null termination in all charsets */
109         SSVAL(ob, destlen, 0);
110
111         *dest = ob;
112
113         return destlen;
114
115 }
116
117 /**
118  * Convert string from one encoding to another, making error checking etc
119  *
120  * @param src pointer to source string (multibyte or singlebyte)
121  * @param srclen length of the source string in bytes
122  * @param dest pointer to destination string (multibyte or singlebyte)
123  * @param destlen maximal length allowed for string
124  * @returns the number of bytes occupied in the destination
125  * on error, returns -1, and sets errno
126  **/
127 _PUBLIC_ bool convert_string_error_handle(struct smb_iconv_handle *ic,
128                                           charset_t from, charset_t to,
129                                           void const *src, size_t srclen,
130                                           void *dest, size_t destlen,
131                                           size_t *converted_size)
132 {
133         size_t i_len, o_len;
134         ssize_t retval;
135         const char* inbuf = (const char*)src;
136         char* outbuf = (char*)dest;
137         smb_iconv_t descriptor;
138
139         if (srclen == (size_t)-1)
140                 srclen = strlen(inbuf)+1;
141
142         descriptor = get_conv_handle(ic, from, to);
143         if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
144                 if (converted_size) {
145                         *converted_size = 0;
146                 }
147                 errno = EINVAL;
148                 return -1;
149         }
150
151         i_len=srclen;
152         o_len=destlen;
153
154         retval = smb_iconv(descriptor,  &inbuf, &i_len, &outbuf, &o_len);
155
156         if (converted_size != NULL)
157                 *converted_size = destlen-o_len;
158         return (retval != (ssize_t)-1);
159 }
160
161
162 /**
163  * Convert string from one encoding to another, making error checking etc
164  *
165  * @param src pointer to source string (multibyte or singlebyte)
166  * @param srclen length of the source string in bytes
167  * @param dest pointer to destination string (multibyte or singlebyte)
168  * @param destlen maximal length allowed for string
169  * @returns the number of bytes occupied in the destination
170  **/
171 _PUBLIC_ bool convert_string_handle(struct smb_iconv_handle *ic,
172                                          charset_t from, charset_t to,
173                                          void const *src, size_t srclen,
174                                          void *dest, size_t destlen, size_t *converted_size)
175 {
176         bool retval;
177
178         retval = convert_string_error_handle(ic, from, to, src, srclen, dest, destlen, converted_size);
179         if(retval==false) {
180                 const char *reason;
181                 switch(errno) {
182                 case EINVAL:
183                         reason="Incomplete multibyte sequence";
184                         return false;
185                 case E2BIG:
186                         reason="No more room";
187                         if (from == CH_UNIX) {
188                                 DEBUG(0,("E2BIG: convert_string_handle(%s,%s): srclen=%d destlen=%d - '%s'\n",
189                                          charset_name(ic, from), charset_name(ic, to),
190                                          (int)srclen, (int)destlen,
191                                          (const char *)src));
192                         } else {
193                                 DEBUG(0,("E2BIG: convert_string_handle(%s,%s): srclen=%d destlen=%d\n",
194                                          charset_name(ic, from), charset_name(ic, to),
195                                          (int)srclen, (int)destlen));
196                         }
197                         return false;
198                 case EILSEQ:
199                         reason="Illegal multibyte sequence";
200                         return false;
201                 default:
202                         return false;
203                 }
204         }
205         return true;
206 }
207         
208 /**
209  * Convert between character sets, allocating a new buffer using talloc for the result.
210  *
211  * @param srclen length of source buffer.
212  * @param dest always set at least to NULL
213  * @note -1 is not accepted for srclen.
214  *
215  * @returns Size in bytes of the converted string; or -1 in case of error.
216  **/
217
218 _PUBLIC_ bool convert_string_talloc_handle(TALLOC_CTX *ctx,
219                                                 struct smb_iconv_handle *ic,
220                                                 charset_t from, charset_t to, 
221                                                 void const *src, size_t srclen, 
222                                                 void *dst, size_t *converted_size)
223 {
224         void **dest = (void **)dst;
225         smb_iconv_t descriptor;
226         ssize_t ret;
227
228         *dest = NULL;
229
230         if (src == NULL || srclen == (size_t)-1 || srclen == 0)
231                 return false;
232
233         descriptor = get_conv_handle(ic, from, to);
234
235         if (descriptor == (smb_iconv_t)-1 || descriptor == (smb_iconv_t)0) {
236                 /* conversion not supported, return -1*/
237                 DEBUG(3, ("convert_string_talloc_handle: conversion from %s to %s not supported!\n",
238                           charset_name(ic, from), 
239                           charset_name(ic, to)));
240                 return false;
241         }
242
243         ret = iconv_talloc(ctx, descriptor, src, srclen, dest);
244         if (ret == -1)
245                 return false;
246         if (converted_size != NULL)
247                 *converted_size = ret;
248         return true;
249 }
250