Imported Upstream version 3.2
[platform/upstream/nettle.git] / tools / input.c
1 /* input.c
2
3    Copyright (C) 2002, 2003, 2008 Niels Möller
4
5    This file is part of GNU Nettle.
6
7    GNU Nettle is free software: you can redistribute it and/or
8    modify it under the terms of either:
9
10      * the GNU Lesser General Public License as published by the Free
11        Software Foundation; either version 3 of the License, or (at your
12        option) any later version.
13
14    or
15
16      * the GNU General Public License as published by the Free
17        Software Foundation; either version 2 of the License, or (at your
18        option) any later version.
19
20    or both in parallel, as here.
21
22    GNU Nettle is distributed in the hope that it will be useful,
23    but WITHOUT ANY WARRANTY; without even the implied warranty of
24    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25    General Public License for more details.
26
27    You should have received copies of the GNU General Public License and
28    the GNU Lesser General Public License along with this program.  If
29    not, see http://www.gnu.org/licenses/.
30 */
31
32 #if HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <assert.h>
37 #include <errno.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include "input.h"
42
43 void
44 sexp_input_init(struct sexp_input *input, FILE *f)
45 {
46   input->f = f;
47   input->coding = NULL;
48 }
49
50 static void
51 sexp_get_raw_char(struct sexp_input *input)
52 {
53   int c = getc(input->f);
54   
55   if (c < 0)
56     {
57       if (ferror(input->f))
58         die("Read error: %s\n", strerror(errno));
59       
60       input->ctype = SEXP_EOF_CHAR;
61     }
62   else
63     {
64       input->ctype = SEXP_NORMAL_CHAR;
65       input->c = c;
66     }
67 }
68
69 void
70 sexp_get_char(struct sexp_input *input)
71 {
72   if (input->coding)
73     for (;;)
74       {
75         size_t done;
76
77         sexp_get_raw_char(input);
78         if (input->ctype == SEXP_EOF_CHAR)
79           die("Unexpected end of file in coded data.\n");
80
81         if (input->c == input->terminator)
82           {
83             input->ctype = SEXP_END_CHAR;
84             return;
85           }
86
87         done = 1;
88
89         /* Decodes in place. Should always work, when we decode one
90          * character at a time. */
91         if (!input->coding->decode_update(&input->state,
92                                           &done, &input->c,
93                                           1, &input->c))
94           die("Invalid coded data.\n");
95         
96         if (done)
97           return;
98       }
99   else
100     sexp_get_raw_char(input);
101 }
102
103 static uint8_t
104 sexp_next_char(struct sexp_input *input)
105 {
106   sexp_get_char(input);
107   if (input->ctype != SEXP_NORMAL_CHAR)
108     die("Unexpected end of file.\n");
109
110   return input->c;
111 }
112
113 static void
114 sexp_push_char(struct sexp_input *input,
115                struct nettle_buffer *string)
116 {
117   assert(input->ctype == SEXP_NORMAL_CHAR);
118     
119   if (!NETTLE_BUFFER_PUTC(string, input->c))
120     die("Virtual memory exhasuted.\n");
121 }
122
123 static void
124 sexp_input_start_coding(struct sexp_input *input,
125                         const struct nettle_armor *coding,
126                         uint8_t terminator)
127 {
128   assert(!input->coding);
129   
130   input->coding = coding;
131   input->coding->decode_init(&input->state);
132   input->terminator = terminator;
133 }
134
135 static void
136 sexp_input_end_coding(struct sexp_input *input)
137 {
138   assert(input->coding);
139
140   if (!input->coding->decode_final(&input->state))
141     die("Invalid coded data.\n");
142   
143   input->coding = NULL;
144 }
145
146
147 /* Return 0 at end-of-string */
148 static int
149 sexp_get_quoted_char(struct sexp_input *input)
150 {
151   sexp_next_char(input);
152
153   switch (input->c)
154     {
155     default:
156       return 1;
157     case '\"':
158       return 0;
159     case '\\':
160       sexp_next_char(input);
161         
162       switch (input->c)
163         {
164         case 'b': input->c = '\b'; return 1;
165         case 't': input->c = '\t'; return 1;
166         case 'n': input->c = '\n'; return 1;
167         case 'f': input->c = '\f'; return 1;
168         case 'r': input->c = '\r'; return 1;
169         case '\\': input->c = '\\'; return 1;
170         case 'o':
171         case 'x':
172           /* FIXME: Not implemnted */
173           abort();
174         case '\n':
175           if (sexp_next_char(input) == '\r')
176             sexp_next_char(input);
177
178           break;
179         case '\r':
180           if (sexp_next_char(input) == '\n')
181             sexp_next_char(input);
182
183           break;
184         }
185       return 1;
186     }
187 }
188
189 static void
190 sexp_get_token_string(struct sexp_input *input,
191                       struct nettle_buffer *string)
192 {
193   assert(!input->coding);
194   assert(input->ctype == SEXP_NORMAL_CHAR);
195   
196   if (!TOKEN_CHAR(input->c))
197     die("Invalid token.\n");
198
199   do
200     {
201       sexp_push_char(input, string);
202       sexp_get_char(input);
203     }
204   while (input->ctype == SEXP_NORMAL_CHAR && TOKEN_CHAR(input->c));
205   
206   assert (string->size);
207 }
208
209 static void
210 sexp_get_string(struct sexp_input *input,
211                 struct nettle_buffer *string)
212 {
213   nettle_buffer_reset(string);
214   input->token = SEXP_STRING;
215   
216   switch (input->c)
217     {
218     case '\"':
219       while (sexp_get_quoted_char(input))
220         sexp_push_char(input, string);
221       
222       sexp_get_char(input);
223       break;
224       
225     case '#':
226       sexp_input_start_coding(input, &nettle_base16, '#');
227       goto decode;
228
229     case '|':
230       sexp_input_start_coding(input, &nettle_base64, '|');
231
232     decode:
233       for (;;)
234         {
235           sexp_get_char(input);
236           switch (input->ctype)
237             {
238             case SEXP_NORMAL_CHAR:
239               sexp_push_char(input, string);
240               break;
241             case SEXP_EOF_CHAR:
242               die("Unexpected end of file in coded string.\n");
243             case SEXP_END_CHAR:
244               sexp_input_end_coding(input);
245               sexp_get_char(input);
246               return;
247             }
248         }
249
250       break;
251
252     default:
253       sexp_get_token_string(input, string);
254       break;
255     }
256 }
257
258 static void
259 sexp_get_string_length(struct sexp_input *input, enum sexp_mode mode,
260                        struct nettle_buffer *string)
261 {
262   unsigned length;
263
264   nettle_buffer_reset(string);
265   input->token = SEXP_STRING;
266   
267   length = input->c - '0';
268   
269   if (!length)
270     /* There must be no more digits */
271     sexp_next_char(input);
272
273   else
274     {
275       assert(length < 10);
276       /* Get rest of digits */
277       for (;;)
278         {
279           sexp_next_char(input);
280           
281           if (input->c < '0' || input->c > '9')
282             break;
283           
284           /* FIXME: Check for overflow? */
285           length = length * 10 + input->c - '0';
286         }
287     }
288
289   switch(input->c)
290     {
291     case ':':
292       /* Verbatim */
293       for (; length; length--)
294         {
295           sexp_next_char(input);
296           sexp_push_char(input, string);
297         }
298       
299       break;
300
301     case '"':
302       if (mode != SEXP_ADVANCED)
303         die("Encountered quoted string in canonical mode.\n");
304
305       for (; length; length--)
306         if (sexp_get_quoted_char(input))
307           sexp_push_char(input, string);
308         else
309           die("Unexpected end of string.\n");
310       
311       if (sexp_get_quoted_char(input))
312         die("Quoted string longer than expected.\n");
313
314       break;
315       
316     case '#':
317       sexp_input_start_coding(input, &nettle_base16, '#');
318       goto decode;
319
320     case '|':
321       sexp_input_start_coding(input, &nettle_base64, '|');
322
323     decode:
324       for (; length; length--)
325         {
326           sexp_next_char(input);
327           sexp_push_char(input, string);
328         }
329       sexp_get_char(input);
330       if (input->ctype != SEXP_END_CHAR)
331         die("Coded string too long.\n");
332
333       sexp_input_end_coding(input);
334       
335       break;
336       
337     default:
338       die("Invalid string.\n");
339     }
340
341   /* Skip the ending character. */
342   sexp_get_char(input);  
343 }
344
345 static void
346 sexp_get_comment(struct sexp_input *input, struct nettle_buffer *string)
347 {
348   nettle_buffer_reset(string);
349
350   assert(input->ctype == SEXP_NORMAL_CHAR);
351   assert(input->c == ';');
352
353   do
354     {
355       sexp_push_char(input, string);
356       sexp_get_raw_char(input);
357     }
358   while (input->ctype == SEXP_NORMAL_CHAR && input->c != '\n');
359
360   input->token = SEXP_COMMENT;
361 }
362
363 /* When called, input->c should be the first character of the current
364  * token.
365  *
366  * When returning, input->c should be the first character of the next
367  * token. */
368 void
369 sexp_get_token(struct sexp_input *input, enum sexp_mode mode,
370                struct nettle_buffer *string)
371 {
372   for(;;)
373     switch(input->ctype)
374       {
375       case SEXP_EOF_CHAR:
376         input->token = SEXP_EOF;
377         return;
378
379       case SEXP_END_CHAR:
380         input->token = SEXP_CODING_END;
381         sexp_input_end_coding(input);
382         sexp_get_char(input);
383         return;
384
385       case SEXP_NORMAL_CHAR:
386         switch(input->c)
387           {
388           case '0': case '1': case '2': case '3': case '4':
389           case '5': case '6': case '7': case '8': case '9':
390             sexp_get_string_length(input, mode, string);
391             return;
392           
393           case '(':
394             input->token = SEXP_LIST_START;
395             sexp_get_char(input);
396             return;
397           
398           case ')':
399             input->token = SEXP_LIST_END;
400             sexp_get_char(input);
401             return;
402
403           case '[':
404             input->token = SEXP_DISPLAY_START;
405             sexp_get_char(input);
406             return;
407
408           case ']':
409             input->token = SEXP_DISPLAY_END;
410             sexp_get_char(input);
411             return;
412
413           case '{':
414             if (mode == SEXP_CANONICAL)
415               die("Unexpected transport data in canonical mode.\n");
416             
417             sexp_input_start_coding(input, &nettle_base64, '}');
418             sexp_get_char(input);
419
420             input->token = SEXP_TRANSPORT_START;
421             
422             return;
423           
424           case ' ':  /* SPC, TAB, LF, CR */
425           case '\t':
426           case '\n':
427           case '\r':
428             if (mode == SEXP_CANONICAL)
429               die("Whitespace encountered in canonical mode.\n");
430
431             sexp_get_char(input);
432             break;
433
434           case ';': /* Comments */
435             if (mode == SEXP_CANONICAL)
436               die("Comment encountered in canonical mode.\n");
437
438             sexp_get_comment(input, string);
439             return;
440           
441           default:
442             /* Ought to be a string */
443             if (mode != SEXP_ADVANCED)
444               die("Encountered advanced string in canonical mode.\n");
445
446             sexp_get_string(input, string);
447             return;
448           }
449       }
450 }