Last fixes before the release
[libgcrypt.git] / src / sexp.c
1 /* sexp.c  -  S-Expression handling
2  *      Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Libgcrypt is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <ctype.h>
28 #include <assert.h>
29
30 #define GCRYPT_NO_MPI_MACROS 1
31 #include "g10lib.h"
32 #include "memory.h"
33
34 typedef struct gcry_sexp *NODE;
35 typedef unsigned short DATALEN;
36
37 struct gcry_sexp {
38     byte d[1];
39 };
40
41 #define ST_STOP  0
42 #define ST_DATA  1  /* datalen follows */
43 #define ST_HINT  2  /* datalen follows */
44 #define ST_OPEN  3
45 #define ST_CLOSE 4
46
47 #define digitp(p)   (*(p) >= '0' && *(p) <= '9')
48 #define hexdigitp(a) (digitp (a)                     \
49                       || (*(a) >= 'A' && *(a) <= 'F')  \
50                       || (*(a) >= 'a' && *(a) <= 'f'))
51 /* the atoi macros assume that the buffer has only valid digits */
52 #define atoi_1(p)   (*(p) - '0' )
53
54
55 #if 0
56 static void
57 dump_mpi( GCRY_MPI a )
58 {
59     char buffer[1000];
60     size_t n = 1000;
61
62     if( !a )
63         fputs("[no MPI]", stderr );
64     else if( gcry_mpi_print( GCRYMPI_FMT_HEX, buffer, &n, a ) )
65         fputs("[MPI too large to print]", stderr );
66     else
67         fputs( buffer, stderr );
68 }
69 #endif
70
71 static void
72 dump_string (const byte *p, size_t n, int delim )
73 {
74   for (; n; n--, p++ )
75     {
76       if ((*p & 0x80) || iscntrl( *p ) || *p == delim ) 
77         {
78           if( *p == '\n' )
79             log_printf ("\\n");
80           else if( *p == '\r' )
81             log_printf ("\\r");
82           else if( *p == '\f' )
83             log_printf ("\\f");
84           else if( *p == '\v' )
85             log_printf ("\\v");
86             else if( *p == '\b' )
87               log_printf ("\\b");
88           else if( !*p )       
89             log_printf ("\\0");
90           else
91             log_printf ("\\x%02x", *p );
92         }
93       else
94         log_printf ("%c", *p);
95     }
96 }
97
98
99 void
100 gcry_sexp_dump (const GCRY_SEXP a)
101 {
102   const byte *p;
103   int indent = 0;
104   int type;
105
106   if (!a)
107     {
108       log_printf ( "[nil]\n");
109       return;
110     }
111
112   p = a->d;
113   while ( (type = *p) != ST_STOP )
114     {
115       p++;
116       switch ( type )
117         {
118         case ST_OPEN:
119           log_printf ("%*s[open]\n", 2*indent, "");
120           indent++;
121           break;
122         case ST_CLOSE:
123           if( indent )
124             indent--;
125           log_printf ("%*s[close]\n", 2*indent, "");
126           break;
127         case ST_DATA: {
128           DATALEN n;
129           memcpy ( &n, p, sizeof n );
130           p += sizeof n;
131           log_printf ("%*s[data=\"", 2*indent, "" );
132           dump_string (p, n, '\"' );
133           log_printf ("\"]\n");
134           p += n;
135         }
136         break;
137         default:
138           log_printf ("%*s[unknown tag %d]\n", 2*indent, "", type);
139           break;
140         }
141     }
142 }
143
144 /****************
145  * Pass list through except when it is an empty list - in that case
146  * return NULL and release the passed list.
147  */
148 static GCRY_SEXP
149 normalize ( GCRY_SEXP list )
150 {
151     char *p;
152     if ( !list )
153         return NULL;
154     p = list->d;
155     if ( *p == ST_STOP ) {
156         /* this is "" */
157         gcry_sexp_release ( list );
158         return NULL;
159     }
160     if( *p == ST_OPEN && p[1] == ST_CLOSE ) {
161         /* this is "()" */
162         gcry_sexp_release ( list );
163         return NULL;
164     }
165
166     return list;
167 }
168
169 /****************
170  * Release resource of the given SEXP object.
171  */
172 void
173 gcry_sexp_release( GCRY_SEXP sexp )
174 {
175     gcry_free ( sexp );
176 }
177
178
179 /****************
180  * Make a pair from lists a and b, don't use a or b later on.
181  * Special behaviour:  If one is a single element list we put the
182  * element straight into the new pair.
183  */
184 GCRY_SEXP
185 gcry_sexp_cons( const GCRY_SEXP a, const GCRY_SEXP b )
186 {
187     /* NYI: Implementation should be quite easy with our new data representation */
188     BUG ();
189     return NULL;
190 }
191
192
193 /****************
194  * Make a list from all items in the array the end of the array is marked
195  * with a NULL.                                                                       y a NULL
196  */
197 GCRY_SEXP
198 gcry_sexp_alist( const GCRY_SEXP *array )
199 {
200     /* NYI: Implementaion should be quite easy with our new data representation */
201     BUG ();
202     return NULL;
203 }
204
205 /****************
206  * Make a list from all items, the end of list is indicated by a NULL
207  */
208 GCRY_SEXP
209 gcry_sexp_vlist( const GCRY_SEXP a, ... )
210 {
211     /* NYI: Implementaion should be quite easy with our new data representation */
212     BUG ();
213     return NULL;
214 }
215
216
217 /****************
218  * Append n to the list a
219  * Returns: a new ist (which maybe a)
220  */
221 GCRY_SEXP
222 gcry_sexp_append( const GCRY_SEXP a, const GCRY_SEXP n )
223 {
224     /* NYI: Implementaion should be quite easy with our new data representation */
225     BUG ();
226     return NULL;
227 }
228
229 GCRY_SEXP
230 gcry_sexp_prepend( const GCRY_SEXP a, const GCRY_SEXP n )
231 {
232     /* NYI: Implementaion should be quite easy with our new data representation */
233     BUG ();
234     return NULL;
235 }
236
237
238
239 /****************
240  * Locate token in a list. The token must be the car of a sublist.
241  * Returns: A new list with this sublist or NULL if not found.
242  */
243 GCRY_SEXP
244 gcry_sexp_find_token( const GCRY_SEXP list, const char *tok, size_t toklen )
245 {
246     const byte *p;
247     DATALEN n;
248
249     if ( !list )
250         return NULL;
251
252     if( !toklen )
253         toklen = strlen(tok);
254     p = list->d;
255     while ( *p != ST_STOP ) {
256         if ( *p == ST_OPEN && p[1] == ST_DATA ) {
257             const byte *head = p;
258
259             p += 2;
260             memcpy ( &n, p, sizeof n ); p += sizeof n;
261             if ( n == toklen && !memcmp( p, tok, toklen ) ) { /* found it */
262                 GCRY_SEXP newlist;
263                 byte *d;
264                 int level = 1;
265
266                 /* look for the end of the list */
267                 for ( p += n; level; p++ ) {
268                     if ( *p == ST_DATA ) {
269                         memcpy ( &n, ++p, sizeof n );
270                         p += sizeof n + n;
271                         p--; /* compensate for later increment */
272                     }
273                     else if ( *p == ST_OPEN ) {
274                         level++;
275                     }
276                     else if ( *p == ST_CLOSE ) {
277                         level--;
278                     }
279                     else if ( *p == ST_STOP ) {
280                         BUG ();
281                     }
282                 } while ( level );
283                 n = p - head;
284
285                 newlist = gcry_xmalloc ( sizeof *newlist + n );
286                 d = newlist->d;
287                 memcpy ( d, head, n ); d += n;
288                 *d++ = ST_STOP;
289                 return normalize ( newlist );
290             }
291             p += n;
292         }
293         else if ( *p == ST_DATA ) {
294             memcpy ( &n, ++p, sizeof n ); p += sizeof n;
295             p += n;
296         }
297         else
298             p++;
299     }
300     return NULL;
301 }
302
303 /****************
304  * return the length of the given list
305  */
306 int
307 gcry_sexp_length( const GCRY_SEXP list )
308 {
309     const byte *p;
310     DATALEN n;
311     int type;
312     int length = 0;
313     int level = 0;
314
315     if ( !list )
316         return 0;
317
318     p = list->d;
319     while ( (type=*p) != ST_STOP ) {
320         p++;
321         if ( type == ST_DATA ) {
322             memcpy ( &n, ++p, sizeof n );
323             p += sizeof n + n;
324             p--;
325             if ( !level )
326                 length++;
327         }
328         else if ( type == ST_OPEN ) {
329             if ( !level )
330                 length++;
331             level++;
332         }
333         else if ( type == ST_CLOSE ) {
334             level--;
335         }
336     }
337     return length;
338 }
339
340
341
342 /****************
343  * Extract the CAR of the given list
344  */
345 GCRY_SEXP
346 gcry_sexp_nth( const GCRY_SEXP list, int number )
347 {
348     const byte *p;
349     DATALEN n;
350     GCRY_SEXP newlist;
351     byte *d;
352     int level = 0;
353
354     if ( !list || list->d[0] != ST_OPEN )
355         return NULL;
356     p = list->d;
357
358     while ( number > 0 ) {
359         p++;
360         if ( *p == ST_DATA ) {
361             memcpy ( &n, ++p, sizeof n );
362             p += sizeof n + n;
363             p--;
364             if ( !level )
365                 number--;
366         }
367         else if ( *p == ST_OPEN ) {
368             level++;
369         }
370         else if ( *p == ST_CLOSE ) {
371             level--;
372             if ( !level )
373                 number--;
374         }
375         else if ( *p == ST_STOP ) {
376             return NULL;
377         }
378     }
379     p++;
380
381     if ( *p == ST_DATA ) {
382         memcpy ( &n, p, sizeof n ); p += sizeof n;
383         newlist = gcry_xmalloc ( sizeof *newlist + n + 1 );
384         d = newlist->d;
385         memcpy ( d, p, n ); d += n;
386         *d++ = ST_STOP;
387     }
388     else if ( *p == ST_OPEN ) {
389         const byte *head = p;
390
391         level = 1;
392         do {
393             p++;
394             if ( *p == ST_DATA ) {
395                 memcpy ( &n, ++p, sizeof n );
396                 p += sizeof n + n;
397                 p--;
398             }
399             else if ( *p == ST_OPEN ) {
400                 level++;
401             }
402             else if ( *p == ST_CLOSE ) {
403                 level--;
404             }
405             else if ( *p == ST_STOP ) {
406                 BUG ();
407             }
408         } while ( level );
409         n = p + 1 - head;
410
411         newlist = gcry_xmalloc ( sizeof *newlist + n );
412         d = newlist->d;
413         memcpy ( d, head, n ); d += n;
414         *d++ = ST_STOP;
415     }
416     else
417         newlist = NULL;
418
419     return normalize (newlist);
420 }
421
422 GCRY_SEXP
423 gcry_sexp_car( const GCRY_SEXP list )
424 {
425     return gcry_sexp_nth ( list, 0 );
426 }
427
428 /****************
429  * Get data from the car.  The returned value is valid as long as the list
430  * is not modified.
431  */
432 const char *
433 gcry_sexp_nth_data( const GCRY_SEXP list, int number, size_t *datalen )
434 {
435     const byte *p;
436     DATALEN n;
437     int level = 0;
438
439     *datalen = 0;
440     if ( !list ) {
441         return NULL;
442     }
443     p = list->d;
444     if ( *p == ST_OPEN )
445         p++;         /* yep, a list */
446     else if (number )
447         return NULL; /* not a list but an n > 0 element requested */
448
449     /* skip n elements */
450     while ( number > 0 ) {
451         if ( *p == ST_DATA ) {
452             memcpy ( &n, ++p, sizeof n );
453             p += sizeof n + n;
454             p--;
455             if ( !level )
456                 number--;
457         }
458         else if ( *p == ST_OPEN ) {
459             level++;
460         }
461         else if ( *p == ST_CLOSE ) {
462             level--;
463             if ( !level )
464                 number--;
465         }
466         else if ( *p == ST_STOP ) {
467             return NULL;
468         }
469         p++;
470     }
471
472
473     if ( *p == ST_DATA ) {
474         memcpy ( &n, ++p, sizeof n );
475         *datalen = n;
476         return p + sizeof n;
477     }
478
479     return NULL;
480 }
481
482 /****************
483  * Get a MPI from the car
484  */
485 GCRY_MPI
486 gcry_sexp_nth_mpi( GCRY_SEXP list, int number, int mpifmt )
487 {
488     const byte *p;
489     DATALEN n;
490     int level = 0;
491
492     if ( !list )
493         return NULL;
494     if ( !mpifmt )
495         mpifmt = GCRYMPI_FMT_STD;
496
497     p = list->d;
498     if ( *p == ST_OPEN )
499         p++;         /* yep, a list */
500     else if (number )
501         return NULL; /* not a list but an n > 0 element requested */
502
503     /* skip n elements */
504     while ( number > 0 ) {
505         if ( *p == ST_DATA ) {
506             memcpy ( &n, ++p, sizeof n );
507             p += sizeof n + n;
508             p--;
509             if ( !level )
510                 number--;
511         }
512         else if ( *p == ST_OPEN ) {
513             level++;
514         }
515         else if ( *p == ST_CLOSE ) {
516             level--;
517             if ( !level )
518                 number--;
519         }
520         else if ( *p == ST_STOP ) {
521             return NULL;
522         }
523         p++;
524     }
525
526     if ( *p == ST_DATA ) {
527         MPI a;
528         size_t nbytes;
529
530         memcpy ( &n, ++p, sizeof n );
531         p += sizeof n;
532         nbytes = n;
533         if( !gcry_mpi_scan( &a, mpifmt, p, &nbytes ) )
534             return a;
535     }
536
537     return NULL;
538 }
539
540
541 /****************
542  * Get the CDR
543  */
544 GCRY_SEXP
545 gcry_sexp_cdr( const GCRY_SEXP list )
546 {
547     const byte *p;
548     const byte *head;
549     DATALEN n;
550     GCRY_SEXP newlist;
551     byte *d;
552     int level = 0;
553     int skip = 1;
554
555     if ( !list || list->d[0] != ST_OPEN )
556         return NULL;
557     p = list->d;
558
559     while ( skip > 0 ) {
560         p++;
561         if ( *p == ST_DATA ) {
562             memcpy ( &n, ++p, sizeof n );
563             p += sizeof n + n;
564             p--;
565             if ( !level )
566                 skip--;
567         }
568         else if ( *p == ST_OPEN ) {
569             level++;
570         }
571         else if ( *p == ST_CLOSE ) {
572             level--;
573             if ( !level )
574                 skip--;
575         }
576         else if ( *p == ST_STOP ) {
577             return NULL;
578         }
579     }
580     p++;
581
582     head = p;
583     level = 0;
584     do {
585         if ( *p == ST_DATA ) {
586             memcpy ( &n, ++p, sizeof n );
587             p += sizeof n + n;
588             p--;
589         }
590         else if ( *p == ST_OPEN ) {
591             level++;
592         }
593         else if ( *p == ST_CLOSE ) {
594             level--;
595         }
596         else if ( *p == ST_STOP ) {
597             return NULL;
598         }
599         p++;
600     } while ( level );
601     n = p - head;
602
603     newlist = gcry_xmalloc ( sizeof *newlist + n + 2 );
604     d = newlist->d;
605     *d++ = ST_OPEN;
606     memcpy ( d, head, n ); d += n;
607     *d++ = ST_CLOSE;
608     *d++ = ST_STOP;
609
610     return normalize (newlist);
611 }
612
613 GCRY_SEXP
614 gcry_sexp_cadr ( const GCRY_SEXP list )
615 {
616     GCRY_SEXP a, b;
617
618     a = gcry_sexp_cdr ( list );
619     b = gcry_sexp_car ( a );
620     gcry_sexp_release ( a );
621     return b;
622 }
623
624
625
626 static int
627 hextobyte( const byte *s )
628 {
629     int c=0;
630
631     if( *s >= '0' && *s <= '9' )
632         c = 16 * (*s - '0');
633     else if( *s >= 'A' && *s <= 'F' )
634         c = 16 * (10 + *s - 'A');
635     else if( *s >= 'a' && *s <= 'f' ) {
636         c = 16 * (10 + *s - 'a');
637     }
638     s++;
639     if( *s >= '0' && *s <= '9' )
640         c += *s - '0';
641     else if( *s >= 'A' && *s <= 'F' )
642         c += 10 + *s - 'A';
643     else if( *s >= 'a' && *s <= 'f' ) {
644         c += 10 + *s - 'a';
645     }
646     return c;
647 }
648
649 struct make_space_ctx {
650     GCRY_SEXP sexp;
651     size_t allocated;
652     byte *pos;
653 };
654
655 static void
656 make_space ( struct make_space_ctx *c, size_t n )
657 {
658     size_t used = c->pos - c->sexp->d;
659
660     if ( used + n + sizeof(DATALEN) + 1 >= c->allocated ) {
661         GCRY_SEXP newsexp;
662         byte *newhead;
663
664         c->allocated += 2*(n+sizeof(DATALEN)+1);
665         newsexp = gcry_xrealloc ( c->sexp, sizeof *newsexp + c->allocated - 1 );
666         newhead = newsexp->d;
667         c->pos = newhead + used;
668         c->sexp = newsexp;
669     }
670 }
671
672
673 /****************
674  * Scan the provided buffer and return the S expression in our internal
675  * format.  Returns a newly allocated expression.  If erroff is not NULL and
676  * a parsing error has occured, the offset into buffer will be returned.
677  * If ARGFLAG is true, the function supports some printf like
678  * expressions.
679  *  These are:
680  *      %m - MPI
681  *      %s - string (no autoswitch to secure allocation)
682  *      %d - integer stored as string (no autoswitch to secure allocation)
683  *  all other format elements are currently not defined and return an error.
684  *  this includes the "%%" sequence becauce the percent sign is not an
685  *  allowed character.
686  * FIXME: We should find a way to store the secure-MPIS not in the string
687  * but as reference to somewhere - this can help us to save huge amounts
688  * of secure memory.  The problem is, that if only one element is secure, all
689  * other elements are automagicaly copied to secure meory too, so the most
690  * common operation gcry_sexp_cdr_mpi() will always return a secure MPI
691  * regardless whether it is needed or not.
692  */
693 static int
694 sexp_sscan( GCRY_SEXP *retsexp, size_t *erroff ,
695             const char *buffer, size_t length, va_list arg_ptr, int argflag )
696 {
697     static const char tokenchars[] = "abcdefghijklmnopqrstuvwxyz"
698                                      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
699                                      "0123456789-./_:*+=";
700     const char *p;
701     size_t n;
702     const char *digptr=NULL;
703     const char *quoted=NULL;
704     const char *tokenp=NULL;
705     const char *hexfmt=NULL;
706     const char *base64=NULL;
707     const char *disphint=NULL;
708     const char *percent=NULL;
709     int hexcount=0;
710     int quoted_esc=0;
711     int datalen=0;
712     size_t dummy_erroff;
713
714     struct make_space_ctx c;
715
716     if( !erroff )
717         erroff = &dummy_erroff;
718
719     /* FIXME: replace all the returns by a jump to the leave label
720      * and invent better error codes. Make sure that everything is cleaned up*/
721   #define MAKE_SPACE(n)  do { make_space ( &c, (n) ); } while (0)
722   #define STORE_LEN(p,n) do {                                              \
723                             DATALEN ashort = (n);                          \
724                             memcpy ( (p), &ashort, sizeof(ashort) );       \
725                             (p) += sizeof (ashort);                        \
726                         } while (0)
727
728     /* We assume that the internal representation takes less memory
729      * than the provided one.  However, we add space for one extra datalen
730      * so that the code which does the ST_CLOSE can use MAKE_SPACE */
731     c.allocated = length + sizeof(DATALEN);
732     c.sexp = gcry_xmalloc ( sizeof *c.sexp + c.allocated - 1 );
733     c.pos = c.sexp->d;
734
735     for(p=buffer,n=length; n; p++, n-- ) {
736         if( tokenp && !hexfmt ) {
737             if( strchr( tokenchars, *p ) )
738                 continue;
739             datalen = p - tokenp;
740             MAKE_SPACE ( datalen );
741             *c.pos++ = ST_DATA;
742             STORE_LEN ( c.pos, datalen );
743             memcpy ( c.pos, tokenp, datalen );
744             c.pos += datalen;
745             tokenp = NULL;
746         }
747         if( quoted ) {
748             if( quoted_esc ) {
749                 switch( *p ) {
750                   case 'b': case 't': case 'v': case 'n': case 'f':
751                   case 'r': case '"': case '\'': case '\\':
752                     quoted_esc = 0;
753                     break;
754                   case '0': case '1': case '2': case '3': case '4':
755                   case '5': case '6': case '7':
756                     if( !(n > 2 && p[1] >= '0' && p[1] <= '7'
757                                 && p[2] >= '0' && p[2] <= '7') ) {
758                         *erroff = p - buffer;
759                         return -6;   /* invalid octal value */
760                     }
761                     p += 2; n -= 2;
762                     quoted_esc = 0;
763                     break;
764                   case 'x':
765                     if( !(n > 2 && isxdigit(p[1]) && isxdigit(p[2]) ) ) {
766                         *erroff = p - buffer;
767                         return -6;   /* invalid hex value */
768                     }
769                     p += 2; n -= 2;
770                     quoted_esc = 0;
771                     break;
772                   case '\r':  /* ignore CR[,LF] */
773                     if( n && p[1] == '\n' ) {
774                         p++; n--;
775                     }
776                     quoted_esc = 0;
777                     break;
778                   case '\n':  /* ignore LF[,CR] */
779                     if( n && p[1] == '\r' ) {
780                         p++; n--;
781                     }
782                     quoted_esc = 0;
783                     break;
784                   default:
785                     *erroff = p - buffer;
786                     return -6;   /* invalid quoted string escape */
787                 }
788             }
789             else if( *p == '\\' )
790                 quoted_esc = 1;
791             else if( *p == '\"' ) {
792                 /* fixme: add item */
793                 quoted = NULL;
794             }
795         }
796         else if( hexfmt ) {
797             if( isxdigit( *p ) )
798                 hexcount++;
799             else if( *p == '#' ) {
800                 if( (hexcount & 1) ) {
801                     *erroff = p - buffer;
802                     return -12;  /* odd number of hex digits */
803                 }
804
805                 datalen = hexcount/2;
806                 MAKE_SPACE (datalen);
807                 *c.pos++ = ST_DATA;
808                 STORE_LEN (c.pos, datalen);
809                 for( hexfmt++; hexfmt < p; hexfmt++ ) {
810                     if( isspace( *hexfmt ) )
811                         continue;
812                     *c.pos++ = hextobyte( hexfmt );
813                     hexfmt++;
814                 }
815                 hexfmt = NULL;
816             }
817             else if( !isspace( *p ) ) {
818                 *erroff = p - buffer;
819                 return -11;  /* invalid hex character */
820             }
821         }
822         else if( base64 ) {
823             if( *p == '|' )
824                base64 = NULL;
825         }
826         else if( digptr ) {
827             if( isdigit(*p) )
828                 ;
829             else if( *p == ':' ) {
830                 datalen = atoi( digptr ); /* fixme: check for overflow */
831                 digptr = NULL;
832                 if( datalen > n-1 ) {
833                     *erroff = p - buffer;
834                     return -2; /* buffer too short */
835                 }
836                 /* make a new list entry */
837                 MAKE_SPACE (datalen);
838                 *c.pos++ = ST_DATA;
839                 STORE_LEN (c.pos, datalen);
840                 memcpy (c.pos, p+1, datalen );
841                 c.pos += datalen;
842                 n -= datalen;
843                 p += datalen;
844             }
845             else if( *p == '\"' ) {
846                 digptr = NULL; /* we ignore the optional length */
847                 quoted = p;
848                 quoted_esc = 0;
849             }
850             else if( *p == '#' ) {
851                 digptr = NULL; /* we ignore the optional length */
852                 hexfmt = p;
853                 hexcount = 0;
854             }
855             else if( *p == '|' ) {
856                 digptr = NULL; /* we ignore the optional length */
857                 base64 = p;
858             }
859             else {
860                 *erroff = p - buffer;
861                 return -1;
862             }
863         }
864         else if ( percent ) {
865             if ( *p == 'm' ) { /* insert an MPI */
866                 GCRY_MPI m = va_arg (arg_ptr, GCRY_MPI);
867                 size_t nm;
868
869                 if ( gcry_mpi_print( GCRYMPI_FMT_STD, NULL, &nm, m ) )
870                     BUG ();
871
872                 MAKE_SPACE (nm);
873                 if ( !gcry_is_secure ( c.sexp->d )
874                      &&  gcry_mpi_get_flag ( m, GCRYMPI_FLAG_SECURE ) ) {
875                     /* we have to switch to secure allocation */
876                     GCRY_SEXP newsexp;
877                     byte *newhead;
878
879                     newsexp = gcry_xmalloc_secure ( sizeof *newsexp
880                                                    + c.allocated - 1 );
881                     newhead = newsexp->d;
882                     memcpy ( newhead, c.sexp->d, (c.pos - c.sexp->d) );
883                     c.pos = newhead + ( c.pos - c.sexp->d );
884                     gcry_free ( c.sexp );
885                     c.sexp = newsexp;
886                 }
887
888                 *c.pos++ = ST_DATA;
889                 STORE_LEN (c.pos, nm);
890                 if ( gcry_mpi_print( GCRYMPI_FMT_STD, c.pos, &nm, m ) )
891                     BUG ();
892                 c.pos += nm;
893             }
894             else if ( *p == 's' ) { /* insert an string */
895                 const char *astr = va_arg (arg_ptr, const char *);
896                 size_t alen = strlen ( astr );
897
898                 MAKE_SPACE (alen);
899                 *c.pos++ = ST_DATA;
900                 STORE_LEN (c.pos, alen);
901                 memcpy ( c.pos, astr, alen );
902                 c.pos += alen;
903             }
904             else if ( *p == 'd' ) { /* insert an integer as string */
905                 int aint = va_arg (arg_ptr, int);
906                 size_t alen;
907                 char buf[20];
908
909                 sprintf ( buf, "%d", aint );
910                 alen = strlen ( buf );
911                 MAKE_SPACE (alen);
912                 *c.pos++ = ST_DATA;
913                 STORE_LEN (c.pos, alen);
914                 memcpy ( c.pos, buf, alen );
915                 c.pos += alen;
916             }
917             else {
918                 *erroff = p - buffer;
919                 return -1;  /* invalid format specifier */
920             }
921             percent = NULL;
922         }
923         else if( *p == '(' ) {
924             if( disphint ) {
925                 *erroff = p - buffer;
926                 return -9; /* open display hint */
927             }
928             MAKE_SPACE (0);
929             *c.pos++ = ST_OPEN;
930         }
931         else if( *p == ')' ) { /* walk up */
932             if( disphint ) {
933                 *erroff = p - buffer;
934                 return -9; /* open display hint */
935             }
936             MAKE_SPACE (0);
937             *c.pos++ = ST_CLOSE;
938         }
939         else if( *p == '\"' ) {
940             quoted = p;
941             quoted_esc = 0;
942         }
943         else if( *p == '#' ) {
944             hexfmt = p;
945             hexcount = 0;
946         }
947         else if( *p == '|' )
948             base64 = p;
949         else if( *p == '[' ) {
950             if( disphint ) {
951                 *erroff = p - buffer;
952                 return -8; /* nested display hints */
953             }
954             disphint = p;
955         }
956         else if( *p == ']' ) {
957             if( !disphint ) {
958                 *erroff = p - buffer;
959                 return -9; /* unmatched display hint close */
960             }
961             disphint = NULL;
962         }
963         else if( isdigit(*p) ) {
964             if( *p == '0' ) { /* a length may not begin with zero */
965                 *erroff = p - buffer;
966                 return -7;
967             }
968             digptr = p;
969         }
970         else if( strchr( tokenchars, *p ) )
971             tokenp = p;
972         else if( isspace(*p) )
973             ;
974         else if( *p == '{' ) {
975             /* fixme: handle rescanning:
976              * we can do this by saving our current state
977              * and start over at p+1 -- Hmmm. At this point here
978              * we are in a well defined state, so we don't need to save
979              * it.  Great.
980              */
981             *erroff = p - buffer;
982             return -10; /* unexpected reserved punctuation */
983         }
984         else if( strchr( "&\\", *p ) ) { /*reserved punctuation*/
985             *erroff = p - buffer;
986             return -10; /* unexpected reserved punctuation */
987         }
988         else if( argflag && *p == '%' ) {
989             percent = p;
990         }
991         else { /* bad or unavailable*/
992             *erroff = p - buffer;
993             return -5;
994         }
995
996     }
997     MAKE_SPACE (0);
998     *c.pos++ = ST_STOP;
999
1000     *retsexp = normalize ( c.sexp );
1001     return 0;
1002   #undef MAKE_SPACE
1003   #undef STORE_LEN
1004 }
1005
1006 int
1007 gcry_sexp_build( GCRY_SEXP *retsexp, size_t *erroff, const char *format, ... )
1008 {
1009     int rc;
1010     va_list arg_ptr ;
1011
1012     va_start( arg_ptr, format ) ;
1013     rc = sexp_sscan( retsexp, erroff, format, strlen(format), arg_ptr, 1 );
1014     va_end(arg_ptr);
1015
1016     return rc;
1017 }
1018
1019 int
1020 gcry_sexp_sscan( GCRY_SEXP *retsexp, size_t *erroff,
1021                             const char *buffer, size_t length )
1022 {
1023     va_list dummy_arg_ptr = 0;
1024
1025     return sexp_sscan( retsexp, erroff, buffer, length, dummy_arg_ptr, 0 );
1026 }
1027
1028 /****************
1029  * Print SEXP to buffer using the MODE.  Returns the length of the
1030  * SEXP in buffer or 0 if the buffer is too short (We have at least an
1031  * empty list consisting of 2 bytes).  If a buffer of NULL is provided,
1032  * the required length is returned.
1033  */
1034 size_t
1035 gcry_sexp_sprint( const GCRY_SEXP list, int mode,
1036                                         char *buffer, size_t maxlength )
1037 {
1038     static byte empty[3] = { ST_OPEN, ST_CLOSE, ST_STOP };
1039     const byte *s;
1040     char *d;
1041     DATALEN n;
1042     char numbuf[20];
1043     size_t len = 0;
1044
1045     s = list? list->d : empty;
1046     d = buffer;
1047     while ( *s != ST_STOP ) {
1048         switch ( *s ) {
1049           case ST_OPEN:
1050             s++;
1051             len++;
1052             if ( buffer ) {
1053                 if ( len >= maxlength )
1054                     return 0;
1055                 *d++ = '(';
1056             }
1057             break;
1058           case ST_CLOSE:
1059             s++;
1060             len++;
1061             if ( mode != GCRYSEXP_FMT_CANON )
1062                 len++;
1063             if ( buffer ) {
1064                 if ( len >= maxlength )
1065                     return 0;
1066                 *d++ = ')';
1067                 if ( mode != GCRYSEXP_FMT_CANON )
1068                     *d++ = '\n';
1069             }
1070             break;
1071           case ST_DATA:
1072             s++;
1073             memcpy ( &n, s, sizeof n ); s += sizeof n;
1074             sprintf (numbuf, "%u:", (unsigned int)n );
1075             len += strlen (numbuf) + n;
1076             if ( buffer ) {
1077                 if ( len >= maxlength )
1078                     return 0;
1079                 d = stpcpy ( d, numbuf );
1080                 memcpy ( d, s, n ); d += n;
1081             }
1082             s += n;
1083             break;
1084           default:
1085             BUG ();
1086         }
1087     }
1088     if (buffer) {
1089         if ( len >= maxlength )
1090             return 0;
1091         *d++ = 0; /* for convenience we make a C string */
1092     }
1093     else
1094         len++; /* we need one byte more for this */
1095
1096     return len;
1097 }
1098
1099
1100
1101
1102 /* Scan a cannocial encoded buffer with implicit length values and
1103    return the actual length this S-expression uses.  For a valid S-Exp
1104    it should never return 0.  If LENGTH is not zero, the maximum
1105    length to scan is given - this can be used for syntax checks of
1106    data passed from outside. erroce and erroff may both be passed as
1107    NULL */
1108 size_t
1109 gcry_sexp_canon_len (const unsigned char *buffer, size_t length, 
1110                      size_t *erroff, int *errcode)
1111 {
1112   const unsigned char *p;
1113   const char *disphint=NULL;
1114   unsigned int datalen = 0;
1115   size_t dummy_erroff;
1116   int    dummy_errcode;
1117   size_t count = 0;
1118   int level = 0;
1119
1120   if (!erroff)
1121     erroff = &dummy_erroff;
1122   if (!errcode)
1123     errcode = &dummy_errcode;
1124
1125   *errcode = 0;
1126   *erroff = 0;
1127   if (!buffer)
1128     return 0;
1129
1130   for (p=buffer; ; p++, count++ )
1131     {
1132       if (length && count >= length)
1133         {
1134           *erroff = count;
1135           *errcode = -2; /* string too long */
1136           return 0;
1137         }
1138       
1139       if (datalen)
1140         {
1141           if (*p == ':')
1142             {
1143               if (length && (count+datalen) >= length)
1144                 {
1145                   *erroff = count;
1146                   *errcode = -2; /* string too long */
1147                   return 0;
1148                 }
1149               count += datalen;
1150               p += datalen;
1151               datalen = 0;
1152               if (!level)
1153                 return count+1; /* expression is not a list - return now */
1154             }
1155           else if (digitp(p))
1156             datalen = datalen*10 + atoi_1(p);
1157           else 
1158             {
1159               *erroff = count;
1160               *errcode = -1;
1161               return 0;
1162             }
1163         }
1164       else if (*p == '(')
1165         {
1166           if (disphint)
1167             {
1168               *erroff = count;
1169               *errcode = -9; /* open display hint */
1170               return 0;
1171             }
1172           level++;
1173         }
1174       else if (*p == ')')
1175         { /* walk up */
1176           if (!level)
1177             {
1178               *erroff = count;
1179               *errcode = -3; /* unmatched parenthesis */
1180               return 0;
1181             }
1182           if (disphint)
1183             {
1184               *erroff = count;
1185               *errcode = -9; /* open display hint */
1186               return 0;
1187             }
1188           if (!--level)
1189             return ++count; /* ready */
1190         }
1191       else if (*p == '[')
1192         {
1193           if (disphint) 
1194             {
1195               *erroff = count;
1196               *errcode = -8; /* nested display hints */
1197               return 0;
1198             }
1199           disphint = p;
1200         }
1201       else if (*p == ']')
1202         {
1203           if( !disphint ) 
1204             {
1205               *erroff = count;
1206               *errcode = -9; /* unmatched display hint close */
1207               return 0;
1208             }
1209           disphint = NULL;
1210         }
1211       else if (digitp (p) )
1212         {
1213           if (*p == '0')
1214             { 
1215               *erroff = count;
1216               *errcode = -7; /* a length may not begin with zero */
1217               return 0;
1218             }
1219           datalen = atoi_1 (p);
1220         }
1221       else if (*p == '&' || *p == '\\')
1222         {
1223           *erroff = count;
1224           *errcode = -10; /* unexpected reserved punctuation */
1225           return 0;
1226         }
1227       else
1228         { 
1229           *erroff = count;
1230           *errcode = -5; /* bad character */
1231           return 0;
1232         }
1233     }
1234 }
1235