72fbdc470fe9172640d4ecf0e0fdcca1eda1829f
[ira/wip.git] / source3 / torture / smbiconv.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Charset module tester
4
5    Copyright (C) Jelmer Vernooij 2003
6    Based on iconv/icon_prog.c from the GNU C Library, 
7       Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
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 #undef realloc
25
26 static int
27 process_block (smb_iconv_t cd, const char *addr, size_t len, FILE *output)
28 {
29 #define OUTBUF_SIZE     32768
30   const char *start = addr;
31   char outbuf[OUTBUF_SIZE];
32   char *outptr;
33   size_t outlen;
34   size_t n;
35
36   while (len > 0)
37     {
38       outptr = outbuf;
39       outlen = OUTBUF_SIZE;
40       n = smb_iconv (cd,  &addr, &len, &outptr, &outlen);
41
42       if (outptr != outbuf)
43         {
44           /* We have something to write out.  */
45           int errno_save = errno;
46
47           if (fwrite (outbuf, 1, outptr - outbuf, output)
48               < (size_t) (outptr - outbuf)
49               || ferror (output))
50             {
51               /* Error occurred while printing the result.  */
52               DEBUG (0, ("conversion stopped due to problem in writing the output"));
53               return -1;
54             }
55
56           errno = errno_save;
57         }
58
59       if (errno != E2BIG)
60         {
61           /* iconv() ran into a problem.  */
62           switch (errno)
63             {
64             case EILSEQ:
65               DEBUG(0,("illegal input sequence at position %ld", 
66                      (long) (addr - start)));
67               break;
68             case EINVAL:
69               DEBUG(0, ("\
70 incomplete character or shift sequence at end of buffer"));
71               break;
72             case EBADF:
73               DEBUG(0, ("internal error (illegal descriptor)"));
74               break;
75             default:
76               DEBUG(0, ("unknown iconv() error %d", errno));
77               break;
78             }
79
80           return -1;
81         }
82     }
83
84   return 0;
85 }
86
87
88 static int
89 process_fd (smb_iconv_t cd, int fd, FILE *output)
90 {
91   /* we have a problem with reading from a descriptor since we must not
92      provide the iconv() function an incomplete character or shift
93      sequence at the end of the buffer.  Since we have to deal with
94      arbitrary encodings we must read the whole text in a buffer and
95      process it in one step.  */
96   static char *inbuf = NULL;
97   static size_t maxlen = 0;
98   char *inptr = NULL;
99   size_t actlen = 0;
100
101   while (actlen < maxlen)
102     {
103       ssize_t n = read (fd, inptr, maxlen - actlen);
104
105       if (n == 0)
106         /* No more text to read.  */
107         break;
108
109       if (n == -1)
110         {
111           /* Error while reading.  */
112           DEBUG(0, ("error while reading the input"));
113           return -1;
114         }
115
116       inptr += n;
117       actlen += n;
118     }
119
120   if (actlen == maxlen)
121     while (1)
122       {
123         ssize_t n;
124         char *new_inbuf;
125
126         /* Increase the buffer.  */
127         new_inbuf = (char *) realloc (inbuf, maxlen + 32768);
128         if (new_inbuf == NULL)
129           {
130             DEBUG(0, ("unable to allocate buffer for input"));
131             return -1;
132           }
133         inbuf = new_inbuf;
134         maxlen += 32768;
135         inptr = inbuf + actlen;
136
137         do
138           {
139             n = read (fd, inptr, maxlen - actlen);
140
141             if (n == 0)
142               /* No more text to read.  */
143               break;
144
145             if (n == -1)
146               {
147                 /* Error while reading.  */
148                 DEBUG(0, ("error while reading the input"));
149                 return -1;
150               }
151
152             inptr += n;
153             actlen += n;
154           }
155         while (actlen < maxlen);
156
157         if (n == 0)
158           /* Break again so we leave both loops.  */
159           break;
160       }
161
162   /* Now we have all the input in the buffer.  Process it in one run.  */
163   return process_block (cd, inbuf, actlen, output);
164 }
165
166 /* Main function */
167
168 int main(int argc, char *argv[])
169 {
170         const char *file = NULL;
171         const char *from = "";
172         const char *to = "";
173         char *output = NULL;
174         const char *preload_modules[] = {NULL, NULL};
175         FILE *out = stdout;
176         int fd;
177         smb_iconv_t cd;
178
179         /* make sure the vars that get altered (4th field) are in
180            a fixed location or certain compilers complain */
181         poptContext pc;
182         struct poptOption long_options[] = {
183                 POPT_AUTOHELP
184                 { "from-code", 'f', POPT_ARG_STRING, &from, 0, "Encoding of original text" },
185                 { "to-code", 't', POPT_ARG_STRING, &to, 0, "Encoding for output" },
186                 { "output", 'o', POPT_ARG_STRING, &output, 0, "Write output to this file" },
187                 { "preload-modules", 'p', POPT_ARG_STRING, &preload_modules[0], 0, "Modules to load" },
188                 POPT_COMMON_SAMBA
189                 POPT_TABLEEND
190         };
191
192         setlinebuf(stdout);
193
194         pc = poptGetContext("smbiconv", argc, (const char **) argv,
195                             long_options, 0);
196
197         poptSetOtherOptionHelp(pc, "[FILE] ...");
198         
199         while(poptGetNextOpt(pc) != -1);
200
201         /* the following functions are part of the Samba debugging
202            facilities.  See lib/debug.c */
203         setup_logging("smbiconv", True);
204
205         if (preload_modules[0]) smb_load_modules(preload_modules);
206
207         if(output) {
208                 out = fopen(output, "w");
209
210                 if(!out) {
211                         DEBUG(0, ("Can't open output file '%s': %s, exiting...\n", output, strerror(errno)));
212                         return 1;
213                 }
214         }
215
216         cd = smb_iconv_open(to, from);
217         if (cd == (smb_iconv_t)-1) {
218                 DEBUG(0,("unable to find from or to encoding, exiting...\n"));
219                 return 1;
220         }
221
222         while((file = poptGetArg(pc))) {
223                 if(strcmp(file, "-") == 0) fd = 0;
224                 else {
225                         fd = open(file, O_RDONLY);
226                         
227                         if(!fd) {
228                                 DEBUG(0, ("Can't open input file '%s': %s, ignoring...\n", file, strerror(errno)));
229                                 continue;
230                         }
231                 }
232
233                 /* Loop thru all arguments */
234                 process_fd(cd, fd, out);
235
236                 close(fd);
237         }
238         poptFreeContext(pc);
239
240         fclose(out);
241
242         return 0;
243 }