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