2004-08-23 Moritz Schulte <moritz@g10code.com>
[libgcrypt.git] / src / sexp.c
1 /* sexp.c  -  S-Expression handling
2  * Copyright (C) 1999, 2000, 2001, 2002, 2003,
3  *               2004 Free Software Foundation, Inc.
4  *
5  * This file is part of Libgcrypt.
6  *
7  * Libgcrypt is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser general Public License as
9  * published by the Free Software Foundation; either version 2.1 of
10  * the License, or (at your option) any later version.
11  *
12  * Libgcrypt is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  */
21
22
23 #include <config.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdarg.h>
28 #include <ctype.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 {
39   byte d[1];
40 };
41
42 #define ST_STOP  0
43 #define ST_DATA  1  /* datalen follows */
44 #define ST_HINT  2  /* datalen follows */
45 #define ST_OPEN  3
46 #define ST_CLOSE 4
47
48 /* the atoi macros assume that the buffer has only valid digits */
49 #define atoi_1(p)   (*(p) - '0' )
50 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
51                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
52 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
53
54 #define TOKEN_SPECIALS  "-./_:*+="
55
56 static gcry_error_t
57 sexp_sscan (gcry_sexp_t *retsexp, size_t *erroff,
58             const char *buffer, size_t length, int argflag,
59             va_list arg_ptr, void **arg_list);
60
61 #if 0
62 static void
63 dump_mpi( gcry_mpi_t a )
64 {
65     char buffer[1000];
66     size_t n = 1000;
67
68     if( !a )
69         fputs("[no MPI]", stderr );
70     else if( gcry_mpi_print( GCRYMPI_FMT_HEX, buffer, &n, a ) )
71         fputs("[MPI too large to print]", stderr );
72     else
73         fputs( buffer, stderr );
74 }
75 #endif
76
77 static void
78 dump_string (const byte *p, size_t n, int delim )
79 {
80   for (; n; n--, p++ )
81     {
82       if ((*p & 0x80) || iscntrl( *p ) || *p == delim ) 
83         {
84           if( *p == '\n' )
85             log_printf ("\\n");
86           else if( *p == '\r' )
87             log_printf ("\\r");
88           else if( *p == '\f' )
89             log_printf ("\\f");
90           else if( *p == '\v' )
91             log_printf ("\\v");
92             else if( *p == '\b' )
93               log_printf ("\\b");
94           else if( !*p )       
95             log_printf ("\\0");
96           else
97             log_printf ("\\x%02x", *p );
98         }
99       else
100         log_printf ("%c", *p);
101     }
102 }
103
104
105 void
106 gcry_sexp_dump (const gcry_sexp_t a)
107 {
108   const byte *p;
109   int indent = 0;
110   int type;
111
112   if (!a)
113     {
114       log_printf ( "[nil]\n");
115       return;
116     }
117
118   p = a->d;
119   while ( (type = *p) != ST_STOP )
120     {
121       p++;
122       switch ( type )
123         {
124         case ST_OPEN:
125           log_printf ("%*s[open]\n", 2*indent, "");
126           indent++;
127           break;
128         case ST_CLOSE:
129           if( indent )
130             indent--;
131           log_printf ("%*s[close]\n", 2*indent, "");
132           break;
133         case ST_DATA: {
134           DATALEN n;
135           memcpy ( &n, p, sizeof n );
136           p += sizeof n;
137           log_printf ("%*s[data=\"", 2*indent, "" );
138           dump_string (p, n, '\"' );
139           log_printf ("\"]\n");
140           p += n;
141         }
142         break;
143         default:
144           log_printf ("%*s[unknown tag %d]\n", 2*indent, "", type);
145           break;
146         }
147     }
148 }
149
150 /****************
151  * Pass list through except when it is an empty list - in that case
152  * return NULL and release the passed list.
153  */
154 static gcry_sexp_t
155 normalize ( gcry_sexp_t list )
156 {
157     char *p;
158     if ( !list )
159         return NULL;
160     p = list->d;
161     if ( *p == ST_STOP ) {
162         /* this is "" */
163         gcry_sexp_release ( list );
164         return NULL;
165     }
166     if( *p == ST_OPEN && p[1] == ST_CLOSE ) {
167         /* this is "()" */
168         gcry_sexp_release ( list );
169         return NULL;
170     }
171
172     return list;
173 }
174
175 /* Create a new S-expression object by reading LENGTH bytes from
176    BUFFER, assuming it is canonilized encoded or autodetected encoding
177    when AUTODETECT is set to 1.  With FREEFNC not NULL, ownership of
178    the buffer is transferred to tyhe newle created object.  FREEFNC
179    should be the freefnc used to release BUFFER; there is no guarantee
180    at which point this function is called; most likey you want to use
181    free() or gcry_free(). 
182  
183    Passing LENGTH and AUTODETECT as 0 is allowed to indicate that
184    BUFFER points to a valid canonical encoded S-expression.  A LENGTH
185    of 0 and AUTODETECT 1 indicates that buffer points to a
186    null-terminated string.
187   
188    This function returns 0 and and the pointer to the new object in
189    RETSEXP or an error code in which case RETSEXP is set to NULL.  */
190 gcry_error_t
191 gcry_sexp_create (gcry_sexp_t *retsexp, void *buffer, size_t length,
192                   int autodetect, void (*freefnc)(void*) )
193 {
194   gcry_error_t errcode;
195   gcry_sexp_t se;
196   volatile va_list dummy_arg_ptr;
197
198   if (!retsexp)
199     return gcry_error (GPG_ERR_INV_ARG);
200   *retsexp = NULL;
201   if (autodetect < 0 || autodetect > 1 || !buffer)
202     return gcry_error (GPG_ERR_INV_ARG);
203
204   if (!length && !autodetect)
205     { /* What a brave caller to assume that there is really a canonical
206          encoded S-expression in buffer */
207       length = gcry_sexp_canon_len (buffer, 0, NULL, &errcode);
208       if (!length)
209         return errcode;
210     }
211   else if (!length && autodetect)
212     { /* buffer is a string */
213       length = strlen ((char *)buffer);
214     }
215
216   errcode = sexp_sscan (&se, NULL, buffer, length, 0, dummy_arg_ptr, NULL);
217   if (errcode)
218     return errcode;
219
220   *retsexp = se;
221   if (freefnc)
222     {
223       /* For now we release the buffer immediately.  As soon as we
224          have changed the internal represenation of S-expression to
225          the canoncial format - which has the advantage of faster
226          parsing - we will use this function as a closure in our
227          GCRYSEXP object and use the BUFFER directly */
228       freefnc (buffer);
229     }
230   return gcry_error (GPG_ERR_NO_ERROR);
231 }
232
233 /* Same as gcry_sexp_create but don't transfer ownership */
234 gcry_error_t
235 gcry_sexp_new (gcry_sexp_t *retsexp, const void *buffer, size_t length,
236                int autodetect)
237 {
238   return gcry_sexp_create (retsexp, (void *)buffer, length, autodetect, NULL);
239 }
240
241
242 /****************
243  * Release resource of the given SEXP object.
244  */
245 void
246 gcry_sexp_release( gcry_sexp_t sexp )
247 {
248   if (sexp)
249     {
250       if (gcry_is_secure (sexp))
251         {
252           /* Extra paranoid wiping. */
253           const byte *p = sexp->d;
254           int type;
255
256           while ( (type = *p) != ST_STOP )
257             {
258               p++;
259               switch ( type )
260                 {
261                 case ST_OPEN:
262                   break;
263                 case ST_CLOSE:
264                   break;
265                 case ST_DATA: 
266                   {
267                     DATALEN n;
268                     memcpy ( &n, p, sizeof n );
269                     p += sizeof n;
270                     p += n;
271                   }
272                   break;
273                 default:
274                   break;
275                 }
276             }
277           wipememory (sexp->d, p - sexp->d);
278         }
279       gcry_free ( sexp );
280     }
281 }
282
283
284 /****************
285  * Make a pair from lists a and b, don't use a or b later on.
286  * Special behaviour:  If one is a single element list we put the
287  * element straight into the new pair.
288  */
289 gcry_sexp_t
290 gcry_sexp_cons( const gcry_sexp_t a, const gcry_sexp_t b )
291 {
292   /* NYI: Implementation should be quite easy with our new data
293      representation */
294   BUG ();
295   return NULL;
296 }
297
298
299 /****************
300  * Make a list from all items in the array the end of the array is marked
301  * with a NULL.
302  */
303 gcry_sexp_t
304 gcry_sexp_alist( const gcry_sexp_t *array )
305 {
306   /* NYI: Implementation should be quite easy with our new data
307      representation. */
308   BUG ();
309   return NULL;
310 }
311
312 /****************
313  * Make a list from all items, the end of list is indicated by a NULL
314  */
315 gcry_sexp_t
316 gcry_sexp_vlist( const gcry_sexp_t a, ... )
317 {
318   /* NYI: Implementation should be quite easy with our new data
319      representation. */
320   BUG ();
321   return NULL;
322 }
323
324
325 /****************
326  * Append n to the list a
327  * Returns: a new ist (which maybe a)
328  */
329 gcry_sexp_t
330 gcry_sexp_append( const gcry_sexp_t a, const gcry_sexp_t n )
331 {
332   /* NYI: Implementation should be quite easy with our new data
333      representation. */
334   BUG ();
335   return NULL;
336 }
337
338 gcry_sexp_t
339 gcry_sexp_prepend( const gcry_sexp_t a, const gcry_sexp_t n )
340 {
341   /* NYI: Implementation should be quite easy with our new data
342      representation. */
343   BUG ();
344   return NULL;
345 }
346
347
348
349 /****************
350  * Locate token in a list. The token must be the car of a sublist.
351  * Returns: A new list with this sublist or NULL if not found.
352  */
353 gcry_sexp_t
354 gcry_sexp_find_token( const gcry_sexp_t list, const char *tok, size_t toklen )
355 {
356     const byte *p;
357     DATALEN n;
358
359     if ( !list )
360         return NULL;
361
362     if( !toklen )
363         toklen = strlen(tok);
364     p = list->d;
365     while ( *p != ST_STOP ) {
366         if ( *p == ST_OPEN && p[1] == ST_DATA ) {
367             const byte *head = p;
368
369             p += 2;
370             memcpy ( &n, p, sizeof n ); p += sizeof n;
371             if ( n == toklen && !memcmp( p, tok, toklen ) ) { /* found it */
372                 gcry_sexp_t newlist;
373                 byte *d;
374                 int level = 1;
375
376                 /* look for the end of the list */
377                 for ( p += n; level; p++ ) {
378                     if ( *p == ST_DATA ) {
379                         memcpy ( &n, ++p, sizeof n );
380                         p += sizeof n + n;
381                         p--; /* compensate for later increment */
382                     }
383                     else if ( *p == ST_OPEN ) {
384                         level++;
385                     }
386                     else if ( *p == ST_CLOSE ) {
387                         level--;
388                     }
389                     else if ( *p == ST_STOP ) {
390                         BUG ();
391                     }
392                 } while ( level );
393                 n = p - head;
394
395                 newlist = gcry_xmalloc ( sizeof *newlist + n );
396                 d = newlist->d;
397                 memcpy ( d, head, n ); d += n;
398                 *d++ = ST_STOP;
399                 return normalize ( newlist );
400             }
401             p += n;
402         }
403         else if ( *p == ST_DATA ) {
404             memcpy ( &n, ++p, sizeof n ); p += sizeof n;
405             p += n;
406         }
407         else
408             p++;
409     }
410     return NULL;
411 }
412
413 /****************
414  * Return the length of the given list
415  */
416 int
417 gcry_sexp_length( const gcry_sexp_t list )
418 {
419     const byte *p;
420     DATALEN n;
421     int type;
422     int length = 0;
423     int level = 0;
424
425     if ( !list )
426         return 0;
427
428     p = list->d;
429     while ( (type=*p) != ST_STOP ) {
430         p++;
431         if ( type == ST_DATA ) {
432             memcpy ( &n, p, sizeof n );
433             p += sizeof n + n;
434             if ( level == 1 )
435                 length++;
436         }
437         else if ( type == ST_OPEN ) {
438             if ( level == 1 )
439                 length++;
440             level++;
441         }
442         else if ( type == ST_CLOSE ) {
443             level--;
444         }
445     }
446     return length;
447 }
448
449
450
451 /****************
452  * Extract the CAR of the given list
453  */
454 gcry_sexp_t
455 gcry_sexp_nth( const gcry_sexp_t list, int number )
456 {
457     const byte *p;
458     DATALEN n;
459     gcry_sexp_t newlist;
460     byte *d;
461     int level = 0;
462
463     if ( !list || list->d[0] != ST_OPEN )
464         return NULL;
465     p = list->d;
466
467     while ( number > 0 ) {
468         p++;
469         if ( *p == ST_DATA ) {
470             memcpy ( &n, ++p, sizeof n );
471             p += sizeof n + n;
472             p--;
473             if ( !level )
474                 number--;
475         }
476         else if ( *p == ST_OPEN ) {
477             level++;
478         }
479         else if ( *p == ST_CLOSE ) {
480             level--;
481             if ( !level )
482                 number--;
483         }
484         else if ( *p == ST_STOP ) {
485             return NULL;
486         }
487     }
488     p++;
489
490     if ( *p == ST_DATA ) {
491         memcpy ( &n, p, sizeof n ); p += sizeof n;
492         newlist = gcry_xmalloc ( sizeof *newlist + n + 1 );
493         d = newlist->d;
494         memcpy ( d, p, n ); d += n;
495         *d++ = ST_STOP;
496     }
497     else if ( *p == ST_OPEN ) {
498         const byte *head = p;
499
500         level = 1;
501         do {
502             p++;
503             if ( *p == ST_DATA ) {
504                 memcpy ( &n, ++p, sizeof n );
505                 p += sizeof n + n;
506                 p--;
507             }
508             else if ( *p == ST_OPEN ) {
509                 level++;
510             }
511             else if ( *p == ST_CLOSE ) {
512                 level--;
513             }
514             else if ( *p == ST_STOP ) {
515                 BUG ();
516             }
517         } while ( level );
518         n = p + 1 - head;
519
520         newlist = gcry_xmalloc ( sizeof *newlist + n );
521         d = newlist->d;
522         memcpy ( d, head, n ); d += n;
523         *d++ = ST_STOP;
524     }
525     else
526         newlist = NULL;
527
528     return normalize (newlist);
529 }
530
531 gcry_sexp_t
532 gcry_sexp_car( const gcry_sexp_t list )
533 {
534     return gcry_sexp_nth ( list, 0 );
535 }
536
537 /****************
538  * Get data from the car.  The returned value is valid as long as the list
539  * is not modified.
540  */
541 const char *
542 gcry_sexp_nth_data( const gcry_sexp_t list, int number, size_t *datalen )
543 {
544     const byte *p;
545     DATALEN n;
546     int level = 0;
547
548     *datalen = 0;
549     if ( !list ) {
550         return NULL;
551     }
552     p = list->d;
553     if ( *p == ST_OPEN )
554         p++;         /* yep, a list */
555     else if (number )
556         return NULL; /* not a list but an n > 0 element requested */
557
558     /* skip n elements */
559     while ( number > 0 ) {
560         if ( *p == ST_DATA ) {
561             memcpy ( &n, ++p, sizeof n );
562             p += sizeof n + n;
563             p--;
564             if ( !level )
565                 number--;
566         }
567         else if ( *p == ST_OPEN ) {
568             level++;
569         }
570         else if ( *p == ST_CLOSE ) {
571             level--;
572             if ( !level )
573                 number--;
574         }
575         else if ( *p == ST_STOP ) {
576             return NULL;
577         }
578         p++;
579     }
580
581
582     if ( *p == ST_DATA ) {
583         memcpy ( &n, ++p, sizeof n );
584         *datalen = n;
585         return p + sizeof n;
586     }
587
588     return NULL;
589 }
590
591 /****************
592  * Get a MPI from the car
593  */
594 gcry_mpi_t
595 gcry_sexp_nth_mpi( gcry_sexp_t list, int number, int mpifmt )
596 {
597     const byte *p;
598     DATALEN n;
599     int level = 0;
600
601     if ( !list )
602         return NULL;
603     if ( !mpifmt )
604         mpifmt = GCRYMPI_FMT_STD;
605
606     p = list->d;
607     if ( *p == ST_OPEN )
608         p++;         /* yep, a list */
609     else if (number )
610         return NULL; /* not a list but an n > 0 element requested */
611
612     /* skip n elements */
613     while ( number > 0 ) {
614         if ( *p == ST_DATA ) {
615             memcpy ( &n, ++p, sizeof n );
616             p += sizeof n + n;
617             p--;
618             if ( !level )
619                 number--;
620         }
621         else if ( *p == ST_OPEN ) {
622             level++;
623         }
624         else if ( *p == ST_CLOSE ) {
625             level--;
626             if ( !level )
627                 number--;
628         }
629         else if ( *p == ST_STOP ) {
630             return NULL;
631         }
632         p++;
633     }
634
635     if ( *p == ST_DATA ) {
636         gcry_mpi_t a;
637         size_t nbytes;
638
639         memcpy ( &n, ++p, sizeof n );
640         p += sizeof n;
641         nbytes = n;
642         if( !gcry_mpi_scan( &a, mpifmt, p, n, &nbytes ) )
643             return a;
644     }
645
646     return NULL;
647 }
648
649
650 /****************
651  * Get the CDR
652  */
653 gcry_sexp_t
654 gcry_sexp_cdr( const gcry_sexp_t list )
655 {
656     const byte *p;
657     const byte *head;
658     DATALEN n;
659     gcry_sexp_t newlist;
660     byte *d;
661     int level = 0;
662     int skip = 1;
663
664     if ( !list || list->d[0] != ST_OPEN )
665         return NULL;
666     p = list->d;
667
668     while ( skip > 0 ) {
669         p++;
670         if ( *p == ST_DATA ) {
671             memcpy ( &n, ++p, sizeof n );
672             p += sizeof n + n;
673             p--;
674             if ( !level )
675                 skip--;
676         }
677         else if ( *p == ST_OPEN ) {
678             level++;
679         }
680         else if ( *p == ST_CLOSE ) {
681             level--;
682             if ( !level )
683                 skip--;
684         }
685         else if ( *p == ST_STOP ) {
686             return NULL;
687         }
688     }
689     p++;
690
691     head = p;
692     level = 0;
693     do {
694         if ( *p == ST_DATA ) {
695             memcpy ( &n, ++p, sizeof n );
696             p += sizeof n + n;
697             p--;
698         }
699         else if ( *p == ST_OPEN ) {
700             level++;
701         }
702         else if ( *p == ST_CLOSE ) {
703             level--;
704         }
705         else if ( *p == ST_STOP ) {
706             return NULL;
707         }
708         p++;
709     } while ( level );
710     n = p - head;
711
712     newlist = gcry_xmalloc ( sizeof *newlist + n + 2 );
713     d = newlist->d;
714     *d++ = ST_OPEN;
715     memcpy ( d, head, n ); d += n;
716     *d++ = ST_CLOSE;
717     *d++ = ST_STOP;
718
719     return normalize (newlist);
720 }
721
722 gcry_sexp_t
723 gcry_sexp_cadr ( const gcry_sexp_t list )
724 {
725     gcry_sexp_t a, b;
726
727     a = gcry_sexp_cdr ( list );
728     b = gcry_sexp_car ( a );
729     gcry_sexp_release ( a );
730     return b;
731 }
732
733
734
735 static int
736 hextobyte( const byte *s )
737 {
738     int c=0;
739
740     if( *s >= '0' && *s <= '9' )
741         c = 16 * (*s - '0');
742     else if( *s >= 'A' && *s <= 'F' )
743         c = 16 * (10 + *s - 'A');
744     else if( *s >= 'a' && *s <= 'f' ) {
745         c = 16 * (10 + *s - 'a');
746     }
747     s++;
748     if( *s >= '0' && *s <= '9' )
749         c += *s - '0';
750     else if( *s >= 'A' && *s <= 'F' )
751         c += 10 + *s - 'A';
752     else if( *s >= 'a' && *s <= 'f' ) {
753         c += 10 + *s - 'a';
754     }
755     return c;
756 }
757
758 struct make_space_ctx {
759     gcry_sexp_t sexp;
760     size_t allocated;
761     byte *pos;
762 };
763
764 static void
765 make_space ( struct make_space_ctx *c, size_t n )
766 {
767     size_t used = c->pos - c->sexp->d;
768
769     if ( used + n + sizeof(DATALEN) + 1 >= c->allocated ) {
770         gcry_sexp_t newsexp;
771         byte *newhead;
772
773         c->allocated += 2*(n+sizeof(DATALEN)+1);
774         newsexp = gcry_xrealloc ( c->sexp, sizeof *newsexp + c->allocated - 1 );
775         newhead = newsexp->d;
776         c->pos = newhead + used;
777         c->sexp = newsexp;
778     }
779 }
780
781
782 /* Unquote STRING of LENGTH and store it into BUF.  The surrounding
783    quotes are must already be removed from STRING.  We assume that the
784    quoted string is syntacillay correct.  */
785 static size_t
786 unquote_string (const unsigned char *string, size_t length, unsigned char *buf)
787 {
788   int esc = 0;
789   const unsigned char *s = string;
790   unsigned char *d = buf;
791   size_t n = length;
792
793   for (; n; n--, s++)
794     {
795       if (esc)
796         {
797           switch (*s)
798             {
799             case 'b':  *d++ = '\b'; break;
800             case 't':  *d++ = '\t'; break;
801             case 'v':  *d++ = '\v'; break;
802             case 'n':  *d++ = '\n'; break;
803             case 'f':  *d++ = '\f'; break;
804             case 'r':  *d++ = '\r'; break;
805             case '"':  *d++ = '\"'; break;
806             case '\'': *d++ = '\''; break;
807             case '\\': *d++ = '\\'; break;
808
809             case '\r':  /* ignore CR[,LF] */
810               if (n>1 && s[1] == '\n')
811                 {
812                   s++; n--;
813                 }
814               esc = 0;
815               break;
816               
817             case '\n':  /* ignore LF[,CR] */
818               if (n>1 && s[1] == '\r')
819                 {
820                   s++; n--;
821                 }
822               break;
823
824             case 'x': /* hex value */
825               if (n>2 && hexdigitp (s+1) && hexdigitp (s+2))
826                 {
827                   s++; n--;
828                   *d++ = xtoi_2 (s);
829                   s++; n--;
830                 }
831               break;
832
833             default:
834               if (n>2 && octdigitp (s) && octdigitp (s+1) && octdigitp (s+2))
835                 {
836                   *d++ = (atoi_1 (s)*64) + (atoi_1 (s+1)*8) + atoi_1 (s+2);
837                   s += 2;
838                   n -= 2;
839                 }
840               break;
841             }
842           esc = 0;
843         }
844       else if( *s == '\\' )
845         esc = 1;
846       else
847         *d++ = *s;
848     } 
849
850   return d - buf;
851 }
852
853 /****************
854  * Scan the provided buffer and return the S expression in our internal
855  * format.  Returns a newly allocated expression.  If erroff is not NULL and
856  * a parsing error has occured, the offset into buffer will be returned.
857  * If ARGFLAG is true, the function supports some printf like
858  * expressions.
859  *  These are:
860  *      %m - MPI
861  *      %s - string (no autoswitch to secure allocation)
862  *      %d - integer stored as string (no autoswitch to secure allocation)
863  *      %b - memory buffer; this takes _two_ arguments: an integer with the 
864  *           length of the buffer and a pointer to the buffer.
865  *  all other format elements are currently not defined and return an error.
866  *  this includes the "%%" sequence becauce the percent sign is not an
867  *  allowed character.
868  * FIXME: We should find a way to store the secure-MPIs not in the string
869  * but as reference to somewhere - this can help us to save huge amounts
870  * of secure memory.  The problem is, that if only one element is secure, all
871  * other elements are automagicaly copied to secure memory too, so the most
872  * common operation gcry_sexp_cdr_mpi() will always return a secure MPI
873  * regardless whether it is needed or not.
874  */
875 static gcry_error_t
876 sexp_sscan (gcry_sexp_t *retsexp, size_t *erroff,
877             const char *buffer, size_t length, int argflag,
878             va_list arg_ptr, void **arg_list)
879 {
880   gcry_err_code_t err = GPG_ERR_NO_ERROR;
881   static const char tokenchars[] =
882     "abcdefghijklmnopqrstuvwxyz"
883     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
884     "0123456789-./_:*+=";
885   const char *p;
886   size_t n;
887   const char *digptr = NULL;
888   const char *quoted = NULL;
889   const char *tokenp = NULL;
890   const char *hexfmt = NULL;
891   const char *base64 = NULL;
892   const char *disphint = NULL;
893   const char *percent = NULL;
894   int hexcount = 0;
895   int quoted_esc = 0;
896   int datalen = 0;
897   size_t dummy_erroff;
898   struct make_space_ctx c;
899   int arg_counter = 0;
900   int level = 0;
901
902   /* FIXME: invent better error codes (?).  */
903
904   if (! erroff)
905     erroff = &dummy_erroff;
906
907   /* Depending on wether ARG_LIST is non-zero or not, this macro gives
908      us the next argument, either from the variable argument list as
909      specified by ARG_PTR or from the argument array ARG_LIST.  */
910 #define ARG_NEXT(storage, type)                          \
911   do                                                     \
912     {                                                    \
913       if (! arg_list)                                    \
914         storage = va_arg (arg_ptr, type);                \
915       else                                               \
916         storage = *((type *) (arg_list[arg_counter++])); \
917     }                                                    \
918   while (0)
919
920 #define MAKE_SPACE(n)  do { make_space ( &c, (n) ); } while (0)
921 #define STORE_LEN(p,n) do {                                                \
922                             DATALEN ashort = (n);                          \
923                             memcpy ( (p), &ashort, sizeof(ashort) );       \
924                             (p) += sizeof (ashort);                        \
925                         } while (0)
926
927   /* We assume that the internal representation takes less memory
928    * than the provided one.  However, we add space for one extra datalen
929    * so that the code which does the ST_CLOSE can use MAKE_SPACE */
930   c.allocated = length + sizeof(DATALEN);
931   if (buffer && length && gcry_is_secure (buffer))
932     c.sexp = gcry_xmalloc_secure (sizeof *c.sexp + c.allocated - 1);
933   else
934     c.sexp = gcry_xmalloc (sizeof *c.sexp + c.allocated - 1);
935   c.pos = c.sexp->d;
936
937   for (p = buffer, n = length; n; p++, n--)
938     {
939       if (tokenp && (! hexfmt))
940         {
941           if (strchr (tokenchars, *p))
942             continue;
943           else
944             {
945               datalen = p - tokenp;
946               MAKE_SPACE (datalen);
947               *c.pos++ = ST_DATA;
948               STORE_LEN (c.pos, datalen);
949               memcpy (c.pos, tokenp, datalen);
950               c.pos += datalen;
951               tokenp = NULL;
952             }
953         }
954
955       if (quoted)
956         {
957           if (quoted_esc)
958             {
959               switch (*p)
960                 {
961                 case 'b': case 't': case 'v': case 'n': case 'f':
962                 case 'r': case '"': case '\'': case '\\':
963                   quoted_esc = 0;
964                   break;
965
966                 case '0': case '1': case '2': case '3': case '4':
967                 case '5': case '6': case '7':
968                   if (! ((n > 2)
969                          && (p[1] >= '0') && (p[1] <= '7')
970                          && (p[2] >= '0') && (p[2] <= '7')))
971                     {
972                       *erroff = p - buffer;
973                       /* Invalid octal value.  */
974                       err = GPG_ERR_SEXP_BAD_QUOTATION;
975                       //return gcry_error (GPG_ERR_SEXP_BAD_QUOTATION);
976                     }
977                   p += 2;
978                   n -= 2;
979                   quoted_esc = 0;
980                   break;
981                   
982                 case 'x':
983                   if (! ((n > 2) && isxdigit(p[1]) && isxdigit(p[2])))
984                     {
985                       *erroff = p - buffer;
986                       /* Invalid hex value.  */
987                       err = GPG_ERR_SEXP_BAD_QUOTATION;
988                       //return gcry_error (GPG_ERR_SEXP_BAD_QUOTATION);
989                     }
990                   p += 2;
991                   n -= 2;
992                   quoted_esc = 0;
993                   break;
994
995                 case '\r':
996                   /* ignore CR[,LF] */
997                   if (n && (p[1] == '\n'))
998                     {
999                       p++;
1000                       n--;
1001                     }
1002                   quoted_esc = 0;
1003                   break;
1004
1005                 case '\n':
1006                   /* ignore LF[,CR] */
1007                   if (n && (p[1] == '\r'))
1008                     {
1009                       p++;
1010                       n--;
1011                     }
1012                   quoted_esc = 0;
1013                   break;
1014
1015                 default:
1016                   *erroff = p - buffer;
1017                   /* Invalid quoted string escape.  */
1018                   err = GPG_ERR_SEXP_BAD_QUOTATION;
1019                 }
1020             }
1021           else if (*p == '\\')
1022             quoted_esc = 1;
1023           else if (*p == '\"')
1024             {
1025               /* Keep it easy - we know that the unquoted string will
1026                  never be larger. */
1027               char *save;
1028               size_t len;
1029               
1030               quoted++; /* Skip leading quote.  */
1031               MAKE_SPACE (p - quoted);
1032               *c.pos++ = ST_DATA;
1033               save = c.pos;
1034               STORE_LEN (c.pos, 0); /* Will be fixed up later.  */
1035               len = unquote_string (quoted, p - quoted, c.pos);
1036               c.pos += len;
1037               STORE_LEN (save, len);
1038               quoted = NULL;
1039             }
1040         }
1041       else if (hexfmt)
1042         {
1043           if (isxdigit (*p))
1044             hexcount++;
1045           else if (*p == '#')
1046             {
1047               if ((hexcount & 1))
1048                 {
1049                   *erroff = p - buffer;
1050                   err = GPG_ERR_SEXP_ODD_HEX_NUMBERS;
1051                 }
1052
1053               datalen = hexcount / 2;
1054               MAKE_SPACE (datalen);
1055               *c.pos++ = ST_DATA;
1056               STORE_LEN (c.pos, datalen);
1057               for (hexfmt++; hexfmt < p; hexfmt++)
1058                 {
1059                   if (isspace (*hexfmt))
1060                     continue;
1061                   *c.pos++ = hextobyte (hexfmt);
1062                   hexfmt++;
1063                 }
1064               hexfmt = NULL;
1065             }
1066           else if (! isspace (*p))
1067             {
1068               *erroff = p - buffer;
1069               err = GPG_ERR_SEXP_BAD_HEX_CHAR;
1070             }
1071         }
1072       else if (base64)
1073         {
1074           if (*p == '|')
1075             base64 = NULL;
1076         }
1077       else if (digptr)
1078         {
1079           if (isdigit (*p))
1080             ;
1081           else if (*p == ':')
1082             {
1083               datalen = atoi (digptr); /* FIXME: check for overflow.  */
1084               digptr = NULL;
1085               if (datalen > n - 1)
1086                 {
1087                   *erroff = p - buffer;
1088                   /* Buffer too short.  */
1089                   err = GPG_ERR_SEXP_STRING_TOO_LONG;
1090                 }
1091               /* Make a new list entry.  */
1092               MAKE_SPACE (datalen);
1093               *c.pos++ = ST_DATA;
1094               STORE_LEN (c.pos, datalen);
1095               memcpy (c.pos, p + 1, datalen);
1096               c.pos += datalen;
1097               n -= datalen;
1098               p += datalen;
1099             }
1100           else if (*p == '\"')
1101             {
1102               digptr = NULL; /* We ignore the optional length.  */
1103               quoted = p;
1104               quoted_esc = 0;
1105             }
1106           else if (*p == '#')
1107             {
1108               digptr = NULL; /* We ignore the optional length.  */
1109               hexfmt = p;
1110               hexcount = 0;
1111             }
1112           else if (*p == '|')
1113             {
1114               digptr = NULL; /* We ignore the optional length.  */
1115               base64 = p;
1116             }
1117           else
1118             {
1119               *erroff = p - buffer;
1120               err = GPG_ERR_SEXP_INV_LEN_SPEC;
1121             }
1122         }
1123       else if (percent)
1124         {
1125           if (*p == 'm')
1126             {
1127               /* Insert an MPI.  */
1128               gcry_mpi_t m;
1129               size_t nm = 0;
1130
1131               ARG_NEXT (m, gcry_mpi_t);
1132               
1133               if (gcry_mpi_print (GCRYMPI_FMT_STD, NULL, 0, &nm, m))
1134                 BUG ();
1135
1136               MAKE_SPACE (nm);
1137               if ((! gcry_is_secure (c.sexp->d))
1138                   &&  gcry_mpi_get_flag ( m, GCRYMPI_FLAG_SECURE))
1139                 {
1140                   /* We have to switch to secure allocation.  */
1141                   gcry_sexp_t newsexp;
1142                   byte *newhead;
1143
1144                   newsexp = gcry_xmalloc_secure (sizeof *newsexp
1145                                                  + c.allocated - 1);
1146                   newhead = newsexp->d;
1147                   memcpy (newhead, c.sexp->d, (c.pos - c.sexp->d));
1148                   c.pos = newhead + (c.pos - c.sexp->d);
1149                   gcry_free (c.sexp);
1150                   c.sexp = newsexp;
1151                 }
1152
1153               *c.pos++ = ST_DATA;
1154               STORE_LEN (c.pos, nm);
1155               if (gcry_mpi_print (GCRYMPI_FMT_STD, c.pos, nm, &nm, m))
1156                 BUG ();
1157               c.pos += nm;
1158             }
1159           else if (*p == 's')
1160             {
1161               /* Insert an string.  */
1162               const char *astr;
1163               size_t alen;
1164
1165               ARG_NEXT (astr, const char *);
1166               alen = strlen (astr);
1167               
1168               MAKE_SPACE (alen);
1169               *c.pos++ = ST_DATA;
1170               STORE_LEN (c.pos, alen);
1171               memcpy (c.pos, astr, alen);
1172               c.pos += alen;
1173             }
1174           else if (*p == 'b')
1175             {
1176               /* Insert a memory buffer.  */
1177               const char *astr;
1178               int alen;
1179
1180               ARG_NEXT (alen, int);
1181               ARG_NEXT (astr, const char *);
1182               
1183               MAKE_SPACE (alen);
1184               if (alen
1185                   && !gcry_is_secure (c.sexp->d)
1186                   && gcry_is_secure (astr))
1187               {
1188                   /* We have to switch to secure allocation.  */
1189                   gcry_sexp_t newsexp;
1190                   byte *newhead;
1191
1192                   newsexp = gcry_xmalloc_secure (sizeof *newsexp
1193                                                  + c.allocated - 1);
1194                   newhead = newsexp->d;
1195                   memcpy (newhead, c.sexp->d, (c.pos - c.sexp->d));
1196                   c.pos = newhead + (c.pos - c.sexp->d);
1197                   gcry_free (c.sexp);
1198                   c.sexp = newsexp;
1199                 }
1200
1201               *c.pos++ = ST_DATA;
1202               STORE_LEN (c.pos, alen);
1203               memcpy (c.pos, astr, alen);
1204               c.pos += alen;
1205             }
1206           else if (*p == 'd')
1207             {
1208               /* Insert an integer as string.  */
1209               int aint;
1210               size_t alen;
1211               char buf[20];
1212               
1213               ARG_NEXT (aint, int);
1214               sprintf (buf, "%d", aint);
1215               alen = strlen (buf);
1216               MAKE_SPACE (alen);
1217               *c.pos++ = ST_DATA;
1218               STORE_LEN (c.pos, alen);
1219               memcpy (c.pos, buf, alen);
1220               c.pos += alen;
1221             }
1222           else
1223             {
1224               *erroff = p - buffer;
1225               /* Invalid format specifier.  */
1226               err = GPG_ERR_SEXP_INV_LEN_SPEC;
1227             }
1228           percent = NULL;
1229         }
1230       else if (*p == '(')
1231         {
1232           if (disphint)
1233             {
1234               *erroff = p - buffer;
1235               /* Open display hint.  */
1236               err = GPG_ERR_SEXP_UNMATCHED_DH;
1237             }
1238           MAKE_SPACE (0);
1239           *c.pos++ = ST_OPEN;
1240           level++;
1241         }
1242       else if (*p == ')')
1243         {
1244           /* Walk up.  */
1245           if (disphint)
1246             {
1247               *erroff = p - buffer;
1248               /* Open display hint.  */
1249               err = GPG_ERR_SEXP_UNMATCHED_DH;
1250             }
1251           MAKE_SPACE (0);
1252           *c.pos++ = ST_CLOSE;
1253           level--;
1254         }
1255       else if (*p == '\"')
1256         {
1257           quoted = p;
1258           quoted_esc = 0;
1259         }
1260       else if (*p == '#')
1261         {
1262           hexfmt = p;
1263           hexcount = 0;
1264         }
1265       else if (*p == '|')
1266         base64 = p;
1267       else if (*p == '[')
1268         {
1269           if (disphint)
1270             {
1271               *erroff = p - buffer;
1272               /* Open display hint.  */
1273               err = GPG_ERR_SEXP_NESTED_DH;
1274             }
1275           disphint = p;
1276         }
1277       else if (*p == ']')
1278         {
1279           if (! disphint)
1280             {
1281               *erroff = p - buffer;
1282               /* Open display hint.  */
1283               err = GPG_ERR_SEXP_UNMATCHED_DH;
1284             }
1285           disphint = NULL;
1286         }
1287       else if (isdigit (*p))
1288         {
1289           if (*p == '0')
1290             {
1291               /* A length may not begin with zero.  */
1292               *erroff = p - buffer;
1293               err = GPG_ERR_SEXP_ZERO_PREFIX;
1294             }
1295           digptr = p;
1296         }
1297       else if (strchr (tokenchars, *p))
1298         tokenp = p;
1299       else if (isspace (*p))
1300         ;
1301       else if (*p == '{')
1302         {
1303           /* fixme: handle rescanning: we can do this by saving our
1304              current state and start over at p+1 -- Hmmm. At this
1305              point here we are in a well defined state, so we don't
1306              need to save it.  Great.  */
1307           *erroff = p - buffer;
1308           err = GPG_ERR_SEXP_UNEXPECTED_PUNC;
1309         }
1310       else if (strchr ("&\\", *p))
1311         {
1312           /* Reserved punctuation.  */
1313           *erroff = p - buffer;
1314           err = GPG_ERR_SEXP_UNEXPECTED_PUNC;
1315         }
1316       else if (argflag && (*p == '%'))
1317         percent = p;
1318       else
1319         {
1320           /* Bad or unavailable.  */
1321           *erroff = p - buffer;
1322           err = GPG_ERR_SEXP_BAD_CHARACTER;
1323         }
1324     }
1325   MAKE_SPACE (0);
1326   *c.pos++ = ST_STOP;
1327
1328   if (level)
1329     err = GPG_ERR_SEXP_UNMATCHED_PAREN;
1330
1331   if (err)
1332     {
1333       /* Error -> deallocate.  */
1334       if (c.sexp)
1335         {
1336           /* Extra paranoid wipe on error. */
1337           if (gcry_is_secure (c.sexp))
1338             wipememory (c.sexp, sizeof (struct gcry_sexp) + c.allocated - 1);
1339           gcry_free (c.sexp);
1340         }
1341       /* This might be expected by existing code...  */
1342       *retsexp = NULL;
1343     }
1344   else
1345     *retsexp = normalize (c.sexp);
1346
1347   return gcry_error (err);
1348 #undef MAKE_SPACE
1349 #undef STORE_LEN
1350 }
1351
1352 gcry_error_t
1353 gcry_sexp_build (gcry_sexp_t *retsexp, size_t *erroff, const char *format, ...)
1354 {
1355   gcry_error_t rc;
1356   va_list arg_ptr;
1357   
1358   va_start (arg_ptr, format);
1359   rc = sexp_sscan (retsexp, erroff, format, strlen(format), 1,
1360                    arg_ptr, NULL);
1361   va_end (arg_ptr);
1362   
1363   return rc;
1364 }
1365
1366 /* Like gcry_sexp_build, but uses an array instead of variable
1367    function arguments.  */
1368 gcry_error_t
1369 gcry_sexp_build_array (gcry_sexp_t *retsexp, size_t *erroff,
1370                        const char *format, void **arg_list)
1371 {
1372   /* We don't need the va_list because it is controlled by the
1373      following flag, however we have to pass it but can't initialize
1374      it as there is no portable way to do so.  volatile is needed to
1375      suppress the compiler warning */
1376   volatile va_list dummy_arg_ptr;
1377   
1378   gcry_error_t rc;
1379
1380   rc = sexp_sscan (retsexp, erroff, format, strlen(format), 1,
1381                    dummy_arg_ptr, arg_list);
1382
1383   return rc;
1384 }
1385
1386 gcry_error_t
1387 gcry_sexp_sscan (gcry_sexp_t *retsexp, size_t *erroff,
1388                  const char *buffer, size_t length)
1389 {
1390   /* We don't need the va_list because it is controlled by the
1391      following flag, however we have to pass it but can't initialize
1392      it as there is no portable way to do so.  volatile is needed to
1393      suppress the compiler warning */
1394   volatile va_list dummy_arg_ptr;
1395
1396   return sexp_sscan (retsexp, erroff, buffer, length, 0,
1397                      dummy_arg_ptr, NULL);
1398 }
1399
1400 \f
1401 /* Figure out a suitable encoding for BUFFER of LENGTH.
1402    Returns: 0 = Binary
1403             1 = String possible
1404             2 = Token possible
1405 */
1406 static int
1407 suitable_encoding (const unsigned char *buffer, size_t length)
1408 {
1409   const unsigned char *s;
1410   int maybe_token = 1;
1411
1412   if (!length)
1413     return 1;
1414   
1415   for (s=buffer; length; s++, length--)
1416     {
1417       if ( (*s < 0x20 || (*s >= 0x7f && *s <= 0xa0))
1418            && !strchr ("\b\t\v\n\f\r\"\'\\", *s))
1419         return 0; /*binary*/
1420       if ( maybe_token
1421            && !alphap (s) && !digitp (s)  && !strchr (TOKEN_SPECIALS, *s))
1422         maybe_token = 0;
1423     }
1424   s = buffer;
1425   if ( maybe_token && !digitp (s) )
1426     return 2;
1427   return 1;
1428 }
1429
1430
1431 static int
1432 convert_to_hex (const unsigned char *src, size_t len, unsigned char *dest)
1433 {
1434   int i;
1435
1436   if (dest)
1437     {
1438       *dest++ = '#';
1439       for (i=0; i < len; i++, dest += 2 )
1440         sprintf (dest, "%02X", src[i]);
1441       *dest++ = '#';
1442     }
1443   return len*2+2;
1444 }
1445
1446 static int
1447 convert_to_string (const unsigned char *s, size_t len, unsigned char *dest)
1448 {
1449   if (dest)
1450     {
1451       unsigned char *p = dest;
1452       *p++ = '\"';
1453       for (; len; len--, s++ )
1454         {
1455           switch (*s)
1456             {
1457             case '\b': *p++ = '\\'; *p++ = 'b';  break;
1458             case '\t': *p++ = '\\'; *p++ = 't';  break;
1459             case '\v': *p++ = '\\'; *p++ = 'v';  break;
1460             case '\n': *p++ = '\\'; *p++ = 'n';  break;
1461             case '\f': *p++ = '\\'; *p++ = 'f';  break;
1462             case '\r': *p++ = '\\'; *p++ = 'r';  break;
1463             case '\"': *p++ = '\\'; *p++ = '\"';  break;
1464             case '\'': *p++ = '\\'; *p++ = '\'';  break;
1465             case '\\': *p++ = '\\'; *p++ = '\\';  break;
1466             default: 
1467               if ( (*s < 0x20 || (*s >= 0x7f && *s <= 0xa0)))
1468                 {
1469                   sprintf (p, "\\x%02x", *s); 
1470                   p += 4;
1471                 }
1472               else
1473                 *p++ = *s;
1474             }
1475         }
1476       *p++ = '\"';
1477       return p - dest;
1478     }
1479   else
1480     {
1481       int count = 2;
1482       for (; len; len--, s++ )
1483         {
1484           switch (*s)
1485             {
1486             case '\b': 
1487             case '\t': 
1488             case '\v': 
1489             case '\n': 
1490             case '\f': 
1491             case '\r': 
1492             case '\"':
1493             case '\'':
1494             case '\\': count += 2; break;
1495             default: 
1496               if ( (*s < 0x20 || (*s >= 0x7f && *s <= 0xa0)))
1497                 count += 4;
1498               else
1499                 count++;
1500             }
1501         }
1502       return count;
1503     }
1504 }
1505
1506
1507
1508 static int
1509 convert_to_token (const unsigned char *src, size_t len, unsigned char *dest)
1510 {
1511   if (dest)
1512     memcpy (dest, src, len);
1513   return len;
1514 }
1515
1516
1517 /****************
1518  * Print SEXP to buffer using the MODE.  Returns the length of the
1519  * SEXP in buffer or 0 if the buffer is too short (We have at least an
1520  * empty list consisting of 2 bytes).  If a buffer of NULL is provided,
1521  * the required length is returned.
1522  */
1523 size_t
1524 gcry_sexp_sprint( const gcry_sexp_t list, int mode,
1525                                         char *buffer, size_t maxlength )
1526 {
1527   static byte empty[3] = { ST_OPEN, ST_CLOSE, ST_STOP };
1528   const byte *s;
1529   char *d;
1530   DATALEN n;
1531   char numbuf[20];
1532   size_t len = 0;
1533   int i, indent = 0;
1534   
1535   s = list? list->d : empty;
1536   d = buffer;
1537   while ( *s != ST_STOP )
1538     {
1539       switch ( *s )
1540         {
1541         case ST_OPEN:
1542           s++;
1543           if ( mode != GCRYSEXP_FMT_CANON )
1544             {
1545               if (indent)
1546                 len++; 
1547               len += indent;
1548             }
1549           len++;
1550           if ( buffer ) 
1551             {
1552               if ( len >= maxlength )
1553                 return 0;
1554               if ( mode != GCRYSEXP_FMT_CANON )
1555                 {
1556                   if (indent)
1557                     *d++ = '\n'; 
1558                   for (i=0; i < indent; i++)
1559                     *d++ = ' ';
1560                 }
1561               *d++ = '(';
1562             }
1563           indent++;
1564           break;
1565         case ST_CLOSE:
1566           s++;
1567           len++;
1568           if ( buffer ) 
1569             {
1570               if ( len >= maxlength )
1571                 return 0;
1572               *d++ = ')';
1573             }
1574           indent--;
1575           if (*s != ST_OPEN && *s != ST_STOP && mode != GCRYSEXP_FMT_CANON)
1576             {
1577               len++;
1578               len += indent;
1579               if (buffer)
1580                 {
1581                   if (len >= maxlength)
1582                     return 0;
1583                   *d++ = '\n';
1584                   for (i=0; i < indent; i++)
1585                     *d++ = ' ';
1586                 }
1587             }
1588           break;
1589         case ST_DATA:
1590           s++;
1591           memcpy ( &n, s, sizeof n ); s += sizeof n;
1592           if (mode == GCRYSEXP_FMT_ADVANCED)
1593             {
1594               int type;
1595               size_t nn;
1596
1597               switch ( (type=suitable_encoding (s, n)))
1598                 {
1599                 case 1: nn = convert_to_string (s, n, NULL); break;
1600                 case 2: nn = convert_to_token (s, n, NULL); break;
1601                 default: nn = convert_to_hex (s, n, NULL); break;
1602                 }
1603               len += nn;
1604               if (buffer)
1605                 {
1606                   if (len >= maxlength)
1607                     return 0;
1608                   switch (type)
1609                     {
1610                     case 1: convert_to_string (s, n, d); break;
1611                     case 2: convert_to_token (s, n, d); break;
1612                     default: convert_to_hex (s, n, d); break;
1613                     }
1614                   d += nn;
1615                 }
1616               if (s[n] != ST_CLOSE)
1617                 {
1618                   len++;
1619                   if (buffer)
1620                     {
1621                       if (len >= maxlength)
1622                         return 0;
1623                       *d++ = ' ';
1624                     }
1625                 }
1626             }
1627           else
1628             {
1629               sprintf (numbuf, "%u:", (unsigned int)n );
1630               len += strlen (numbuf) + n;
1631               if ( buffer ) 
1632                 {
1633                   if ( len >= maxlength )
1634                     return 0;
1635                   d = stpcpy ( d, numbuf );
1636                   memcpy ( d, s, n ); d += n;
1637                 }
1638             }
1639           s += n;
1640           break;
1641         default:
1642           BUG ();
1643         }
1644     }
1645   if ( mode != GCRYSEXP_FMT_CANON )
1646     {
1647       len++;
1648       if (buffer)
1649         {
1650           if ( len >= maxlength )
1651             return 0;
1652           *d++ = '\n'; 
1653         }
1654     }
1655   if (buffer) 
1656     {
1657       if ( len >= maxlength )
1658         return 0;
1659       *d++ = 0; /* for convenience we make a C string */
1660     }
1661   else
1662     len++; /* we need one byte more for this */
1663
1664   return len;
1665 }
1666
1667
1668 /* Scan a cannocial encoded buffer with implicit length values and
1669    return the actual length this S-expression uses.  For a valid S-Exp
1670    it should never return 0.  If LENGTH is not zero, the maximum
1671    length to scan is given - this can be used for syntax checks of
1672    data passed from outside. errorcode and erroff may both be passed as
1673    NULL.  */
1674 size_t
1675 gcry_sexp_canon_len (const unsigned char *buffer, size_t length, 
1676                      size_t *erroff, gcry_error_t *errcode)
1677 {
1678   const unsigned char *p;
1679   const char *disphint=NULL;
1680   unsigned int datalen = 0;
1681   size_t dummy_erroff;
1682   gcry_error_t dummy_errcode;
1683   size_t count = 0;
1684   int level = 0;
1685
1686   if (!erroff)
1687     erroff = &dummy_erroff;
1688   if (!errcode)
1689     errcode = &dummy_errcode;
1690
1691   *errcode = gcry_error (GPG_ERR_NO_ERROR);
1692   *erroff = 0;
1693   if (!buffer)
1694     return 0;
1695   if (*buffer != '(')
1696     {
1697       *errcode = gcry_error (GPG_ERR_SEXP_NOT_CANONICAL);
1698       return 0;
1699     }
1700
1701   for (p=buffer; ; p++, count++ )
1702     {
1703       if (length && count >= length)
1704         {
1705           *erroff = count;
1706           *errcode = gcry_error (GPG_ERR_SEXP_STRING_TOO_LONG);
1707           return 0;
1708         }
1709       
1710       if (datalen)
1711         {
1712           if (*p == ':')
1713             {
1714               if (length && (count+datalen) >= length)
1715                 {
1716                   *erroff = count;
1717                   *errcode = gcry_error (GPG_ERR_SEXP_STRING_TOO_LONG);
1718                   return 0;
1719                 }
1720               count += datalen;
1721               p += datalen;
1722               datalen = 0;
1723             }
1724           else if (digitp(p))
1725             datalen = datalen*10 + atoi_1(p);
1726           else 
1727             {
1728               *erroff = count;
1729               *errcode = gcry_error (GPG_ERR_SEXP_INV_LEN_SPEC);
1730               return 0;
1731             }
1732         }
1733       else if (*p == '(')
1734         {
1735           if (disphint)
1736             {
1737               *erroff = count;
1738               *errcode = gcry_error (GPG_ERR_SEXP_UNMATCHED_DH);
1739               return 0;
1740             }
1741           level++;
1742         }
1743       else if (*p == ')')
1744         { /* walk up */
1745           if (!level)
1746             {
1747               *erroff = count;
1748               *errcode = gcry_error (GPG_ERR_SEXP_UNMATCHED_PAREN);
1749               return 0;
1750             }
1751           if (disphint)
1752             {
1753               *erroff = count;
1754               *errcode = gcry_error (GPG_ERR_SEXP_UNMATCHED_DH);
1755               return 0;
1756             }
1757           if (!--level)
1758             return ++count; /* ready */
1759         }
1760       else if (*p == '[')
1761         {
1762           if (disphint) 
1763             {
1764               *erroff = count;
1765               *errcode = gcry_error (GPG_ERR_SEXP_NESTED_DH);
1766               return 0;
1767             }
1768           disphint = p;
1769         }
1770       else if (*p == ']')
1771         {
1772           if( !disphint ) 
1773             {
1774               *erroff = count;
1775               *errcode = gcry_error (GPG_ERR_SEXP_UNMATCHED_DH);
1776               return 0;
1777             }
1778           disphint = NULL;
1779         }
1780       else if (digitp (p) )
1781         {
1782           if (*p == '0')
1783             { 
1784               *erroff = count;
1785               *errcode = gcry_error (GPG_ERR_SEXP_ZERO_PREFIX);
1786               return 0;
1787             }
1788           datalen = atoi_1 (p);
1789         }
1790       else if (*p == '&' || *p == '\\')
1791         {
1792           *erroff = count;
1793           *errcode = gcry_error (GPG_ERR_SEXP_UNEXPECTED_PUNC);
1794           return 0;
1795         }
1796       else
1797         { 
1798           *erroff = count;
1799           *errcode = gcry_error (GPG_ERR_SEXP_BAD_CHARACTER);
1800           return 0;
1801         }
1802     }
1803 }