2 Unix SMB/Netbios implementation.
4 minimal iconv implementation
5 Copyright (C) Andrew Tridgell 2001
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 2 of the License, or
10 (at your option) any later version.
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.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 static size_t ascii_pull(char **, size_t *, char **, size_t *);
25 static size_t ascii_push(char **, size_t *, char **, size_t *);
26 static size_t weird_pull(char **, size_t *, char **, size_t *);
27 static size_t weird_push(char **, size_t *, char **, size_t *);
28 static size_t iconv_copy(char **, size_t *, char **, size_t *);
31 for each charset we have a function that pulls from that charset to
32 a ucs2 buffer, and a function that pushes to a ucs2 buffer
36 size_t (*pull)(char **inbuf, size_t *inbytesleft,
37 char **outbuf, size_t *outbytesleft);
38 size_t (*push)(char **inbuf, size_t *inbytesleft,
39 char **outbuf, size_t *outbytesleft);
41 {"UCS2", iconv_copy, iconv_copy},
42 {"ASCII", ascii_pull, ascii_push},
43 {"WEIRD", weird_pull, weird_push},
48 this is a simple portable iconv() implementaion. It only knows about
49 a very small number of character sets - just enough that Samba works
50 on systems that don't have iconv
52 size_t smb_iconv(smb_iconv_t cd,
53 char **inbuf, size_t *inbytesleft,
54 char **outbuf, size_t *outbytesleft)
60 #ifdef HAVE_NATIVE_ICONV
62 return iconv(cd->cd, inbuf, inbytesleft, outbuf, outbytesleft);
66 if (!inbuf || ! *inbuf || !outbuf || ! *outbuf) return 0;
68 /* in most cases we can go direct */
70 return cd->direct(inbuf, inbytesleft, outbuf, outbytesleft);
73 /* otherwise we have to do it chunks at a time */
74 while (*inbytesleft > 0) {
76 bufsize = sizeof(cvtbuf);
77 if (cd->pull(inbuf, inbytesleft, &bufp, &bufsize) == -1 &&
78 errno != E2BIG) return -1;
81 bufsize = sizeof(cvtbuf) - bufsize;
82 if (cd->push(&bufp, &bufsize, outbuf, outbytesleft) == -1) return -1;
89 simple iconv_open() wrapper
91 smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode)
95 #ifdef HAVE_NATIVE_ICONV
99 for (from=0; charsets[from].name; from++) {
100 if (strcasecmp(charsets[from].name, fromcode) == 0) break;
102 for (to=0; charsets[to].name; to++) {
103 if (strcasecmp(charsets[to].name, tocode) == 0) break;
106 if (!charsets[from].name || !charsets[to].name) {
107 #ifdef HAVE_NATIVE_ICONV
108 cd = iconv_open(tocode, fromcode);
113 return (smb_iconv_t)-1;
117 ret = (smb_iconv_t)malloc(sizeof(*ret));
120 return (smb_iconv_t)-1;
122 memset(ret, 0, sizeof(*ret));
124 #ifdef HAVE_NATIVE_ICONV
125 /* see if we wil be using the native iconv */
132 /* check for the simplest null conversion */
134 ret->direct = iconv_copy;
138 /* check for conversion to/from ucs2 */
140 ret->direct = charsets[to].push;
144 ret->direct = charsets[from].pull;
148 /* the general case has to go via a buffer */
149 ret->pull = charsets[from].pull;
150 ret->push = charsets[to].push;
155 simple iconv_close() wrapper
157 int smb_iconv_close (smb_iconv_t cd)
159 #ifdef HAVE_NATIVE_ICONV
164 memset(cd, 0, sizeof(*cd));
170 /**********************************************************************
171 the following functions implement the builtin character sets in Samba
172 and also the "test" character sets that are designed to test
173 multi-byte character set support for english users
174 ***********************************************************************/
176 static size_t ascii_pull(char **inbuf, size_t *inbytesleft,
177 char **outbuf, size_t *outbytesleft)
179 while (*inbytesleft >= 1 && *outbytesleft >= 2) {
180 (*outbuf)[0] = (*inbuf)[0];
183 (*outbytesleft) -= 2;
188 if (*inbytesleft > 0) {
196 static size_t ascii_push(char **inbuf, size_t *inbytesleft,
197 char **outbuf, size_t *outbytesleft)
201 while (*inbytesleft >= 2 && *outbytesleft >= 1) {
202 (*outbuf)[0] = (*inbuf)[0];
203 if ((*inbuf)[1]) ir_count++;
205 (*outbytesleft) -= 1;
210 if (*inbytesleft == 1) {
215 if (*inbytesleft > 1) {
224 /* the "weird" character set is very useful for testing multi-byte
225 support and finding bugs. Don't use on a production system!
237 static size_t weird_pull(char **inbuf, size_t *inbytesleft,
238 char **outbuf, size_t *outbytesleft)
240 while (*inbytesleft >= 1 && *outbytesleft >= 2) {
243 for (i=0;weird_table[i].from;i++) {
244 if (strncmp((*inbuf),
246 weird_table[i].len) == 0) {
247 if (*inbytesleft < weird_table[i].len) {
248 DEBUG(0,("ERROR: truncated weird string\n"));
249 /* smb_panic("weird_pull"); */
252 (*outbuf)[0] = weird_table[i].from;
254 (*inbytesleft) -= weird_table[i].len;
255 (*outbytesleft) -= 2;
256 (*inbuf) += weird_table[i].len;
264 (*outbuf)[0] = (*inbuf)[0];
267 (*outbytesleft) -= 2;
272 if (*inbytesleft > 0) {
280 static size_t weird_push(char **inbuf, size_t *inbytesleft,
281 char **outbuf, size_t *outbytesleft)
285 while (*inbytesleft >= 2 && *outbytesleft >= 1) {
288 for (i=0;weird_table[i].from;i++) {
289 if ((*inbuf)[0] == weird_table[i].from &&
291 if (*outbytesleft < weird_table[i].len) {
292 DEBUG(0,("No room for weird character\n"));
293 /* smb_panic("weird_push"); */
295 memcpy(*outbuf, weird_table[i].to,
298 (*outbytesleft) -= weird_table[i].len;
300 (*outbuf) += weird_table[i].len;
308 (*outbuf)[0] = (*inbuf)[0];
309 if ((*inbuf)[1]) ir_count++;
311 (*outbytesleft) -= 1;
316 if (*inbytesleft == 1) {
321 if (*inbytesleft > 1) {
329 static size_t iconv_copy(char **inbuf, size_t *inbytesleft,
330 char **outbuf, size_t *outbytesleft)
334 n = MIN(*inbytesleft, *outbytesleft);
336 memmove(*outbuf, *inbuf, n);
339 (*outbytesleft) -= n;
343 if (*inbytesleft > 0) {