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