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 | if (out != stdout) fclose(out);
|
---|
220 | return 1;
|
---|
221 | }
|
---|
222 |
|
---|
223 | while((file = poptGetArg(pc))) {
|
---|
224 | if(strcmp(file, "-") == 0) fd = 0;
|
---|
225 | else {
|
---|
226 | fd = open(file, O_RDONLY);
|
---|
227 |
|
---|
228 | if(!fd) {
|
---|
229 | DEBUG(0, ("Can't open input file '%s': %s, ignoring...\n", file, strerror(errno)));
|
---|
230 | continue;
|
---|
231 | }
|
---|
232 | }
|
---|
233 |
|
---|
234 | /* Loop thru all arguments */
|
---|
235 | process_fd(cd, fd, out);
|
---|
236 |
|
---|
237 | close(fd);
|
---|
238 | }
|
---|
239 | poptFreeContext(pc);
|
---|
240 |
|
---|
241 | fclose(out);
|
---|
242 |
|
---|
243 | return 0;
|
---|
244 | }
|
---|