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