1 /* sane - Scanner Access Now Easy.
2 Copyright (C) 1997 David Mosberger-Tang
3 This file is part of the SANE package.
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
17
18 As a special exception, the authors of SANE give permission for
19 additional uses of the libraries contained in this release of SANE.
20
21 The exception is that, if you link a SANE library with other files
22 to produce an executable, this does not by itself cause the
23 resulting executable to be covered by the GNU General Public
24 License. Your use of that executable is in no way restricted on
25 account of linking the SANE library code into it.
26
27 This exception does not, however, invalidate any other reasons why
28 the executable file might be covered by the GNU General Public
29 License.
30
31 If you submit changes to SANE to the maintainers to be included in
32 a subsequent release, you agree by submitting the changes that
33 those changes may be distributed with this exception intact.
34
35 If you write modifications of your own for SANE, it is your choice
36 whether to permit this exception to apply to your modifications.
37 If you do not wish that, delete this exception notice. */
38
39 #include "../include/sane/config.h"
40
41 #include <ctype.h>
42 #include <errno.h>
43 #include <stdlib.h>
44 #include <string.h>
45
46 #include "../include/sane/sane.h"
47 #include "../include/sane/sanei_wire.h"
48 #include "../include/sane/sanei_codec_ascii.h"
49
50 static const char *hexdigit = "0123456789abcdef";
51
52 static void
skip_ws(Wire * w)53 skip_ws (Wire *w)
54 {
55 while (1)
56 {
57 sanei_w_space (w, 1);
58 if (w->status != 0)
59 return;
60
61 if (!isspace (*w->buffer.curr))
62 return;
63
64 ++w->buffer.curr;
65 }
66 }
67
68 static unsigned
get_digit(Wire * w)69 get_digit (Wire *w)
70 {
71 unsigned digit;
72
73 sanei_w_space (w, 1);
74 digit = tolower(*w->buffer.curr++) - '0';
75 if (digit > 9)
76 digit -= 'a' - ('9' + 1);
77 if (digit > 0xf)
78 {
79 w->status = EINVAL;
80 return 0;
81 }
82 return digit;
83 }
84
85 static SANE_Byte
get_byte(Wire * w)86 get_byte (Wire *w)
87 {
88 return get_digit (w) << 4 | get_digit (w);
89 }
90
91 static void
ascii_w_byte(Wire * w,void * v)92 ascii_w_byte (Wire *w, void *v)
93 {
94 SANE_Byte *b = v;
95
96 switch (w->direction)
97 {
98 case WIRE_ENCODE:
99 sanei_w_space (w, 3);
100 *w->buffer.curr++ = hexdigit[(*b >> 4) & 0x0f];
101 *w->buffer.curr++ = hexdigit[(*b >> 0) & 0x0f];
102 *w->buffer.curr++ = '\n';
103 break;
104
105 case WIRE_DECODE:
106 skip_ws (w);
107 *b = get_byte (w);
108 break;
109
110 case WIRE_FREE:
111 break;
112 }
113 }
114
115 static void
ascii_w_char(Wire * w,void * v)116 ascii_w_char (Wire *w, void *v)
117 {
118 SANE_Char *c = v;
119
120 switch (w->direction)
121 {
122 case WIRE_ENCODE:
123 sanei_w_space (w, 5);
124 *w->buffer.curr++ = '\'';
125 if (*c == '\'' || *c == '\\')
126 *w->buffer.curr++ = '\\';
127 *w->buffer.curr++ = *c;
128 *w->buffer.curr++ = '\'';
129 *w->buffer.curr++ = '\n';
130 break;
131
132 case WIRE_DECODE:
133 sanei_w_space (w, 4);
134 if (*w->buffer.curr++ != '\'')
135 {
136 w->status = EINVAL;
137 return;
138 }
139 *c = *w->buffer.curr++;
140 if (*c == '\\')
141 {
142 sanei_w_space (w, 2);
143 *c = *w->buffer.curr++;
144 }
145 if (*w->buffer.curr++ != '\'')
146 {
147 w->status = EINVAL;
148 return;
149 }
150 break;
151
152 case WIRE_FREE:
153 break;
154 }
155 }
156
157 static void
ascii_w_string(Wire * w,void * v)158 ascii_w_string (Wire *w, void *v)
159 {
160 size_t len, alloced_len;
161 SANE_String *s = v;
162 char * str, ch;
163 int done;
164
165 switch (w->direction)
166 {
167 case WIRE_ENCODE:
168 if (*s)
169 {
170 sanei_w_space (w, 1);
171 *w->buffer.curr++ = '"';
172 str = *s;
173 while ((ch = *str++))
174 {
175 sanei_w_space (w, 2);
176 if (ch == '"' || ch == '\\')
177 *w->buffer.curr++ = '\\';
178 *w->buffer.curr++ = ch;
179 }
180 *w->buffer.curr++ = '"';
181 }
182 else
183 {
184 sanei_w_space (w, 5);
185 *w->buffer.curr++ = '(';
186 *w->buffer.curr++ = 'n';
187 *w->buffer.curr++ = 'i';
188 *w->buffer.curr++ = 'l';
189 *w->buffer.curr++ = ')';
190 }
191 sanei_w_space (w, 1);
192 *w->buffer.curr++ = '\n';
193 break;
194
195 case WIRE_DECODE:
196 skip_ws (w);
197 sanei_w_space (w, 1);
198 ch = *w->buffer.curr++;
199 if (ch == '"')
200 {
201 alloced_len = len = 0;
202 str = 0;
203 done = 0;
204 do
205 {
206 sanei_w_space (w, 1);
207 if (w->status != 0)
208 return;
209
210 ch = *w->buffer.curr++;
211 if (ch == '"')
212 done = 1;
213
214 if (ch == '\\')
215 {
216 sanei_w_space (w, 1);
217 ch = *w->buffer.curr++;
218 }
219
220 if (len >= alloced_len)
221 {
222 alloced_len += 1024;
223 if (!str)
224 str = malloc (alloced_len);
225 else
226 str = realloc (str, alloced_len);
227
228 if (str == 0)
229 {
230 /* Malloc failed, so return an error. */
231 w->status = ENOMEM;
232 return;
233 }
234 }
235 str[len++] = ch;
236 }
237 while (!done);
238
239 str[len - 1] = '\0';
240 *s = realloc (str, len);
241
242 if (*s == 0)
243 {
244 /* Malloc failed, so return an error. */
245 w->status = ENOMEM;
246 return;
247 }
248 }
249 else if (ch == '(')
250 {
251 sanei_w_space (w, 4);
252 if ( *w->buffer.curr++ != 'n'
253 || *w->buffer.curr++ != 'i'
254 || *w->buffer.curr++ != 'l'
255 || *w->buffer.curr++ != ')')
256 {
257 w->status = EINVAL;
258 return;
259 }
260 *s = 0;
261 }
262 else
263 {
264 w->status = EINVAL;
265 return;
266 }
267 break;
268
269 case WIRE_FREE:
270 if (*s)
271 free (*s);
272 break;
273 }
274 }
275
276 static void
ascii_w_word(Wire * w,void * v)277 ascii_w_word (Wire *w, void *v)
278 {
279 SANE_Word val, *word = v;
280 int i, is_negative = 0;
281 char buf[16];
282
283 switch (w->direction)
284 {
285 case WIRE_ENCODE:
286 val = *word;
287 i = sizeof (buf) - 1;
288 if (val < 0)
289 {
290 is_negative = 1;
291 val = -val;
292 }
293 do
294 {
295 buf[i--] = '0' + (val % 10);
296 val /= 10;
297 }
298 while (val);
299 if (is_negative)
300 buf[i--] = '-';
301
302 sanei_w_space (w, sizeof (buf) - i);
303 memcpy (w->buffer.curr, buf + i + 1, sizeof (buf) - i - 1);
304 w->buffer.curr += sizeof (buf) - i - 1;
305 *w->buffer.curr++ = '\n';
306 break;
307
308 case WIRE_DECODE:
309 skip_ws (w);
310 val = 0;
311 sanei_w_space (w, 1);
312 if (*w->buffer.curr == '-')
313 {
314 is_negative = 1;
315 ++w->buffer.curr;
316 }
317 while (1)
318 {
319 sanei_w_space (w, 1);
320 if (w->status != 0)
321 return;
322
323 if (!isdigit (*w->buffer.curr))
324 break;
325
326 val = 10*val + (*w->buffer.curr++ - '0');
327 }
328 *word = is_negative ? -val : val;
329 break;
330
331 case WIRE_FREE:
332 break;
333 }
334 }
335
336 void
sanei_codec_ascii_init(Wire * w)337 sanei_codec_ascii_init (Wire *w)
338 {
339 w->codec.w_byte = ascii_w_byte;
340 w->codec.w_char = ascii_w_char;
341 w->codec.w_word = ascii_w_word;
342 w->codec.w_string = ascii_w_string;
343 }
344