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