• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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