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