1 /* sexp.c - S-Expression handling
2 * Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
4 * This file is part of Libgcrypt.
6 * Libgcrypt is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser general Public License as
8 * published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
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 Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
30 #define GCRYPT_NO_MPI_MACROS 1
34 typedef struct gcry_sexp *NODE;
35 typedef unsigned short DATALEN;
43 #define ST_DATA 1 /* datalen follows */
44 #define ST_HINT 2 /* datalen follows */
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))
54 #define TOKEN_SPECIALS "-./_:*+="
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);
63 dump_mpi( gcry_mpi_t 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 );
73 fputs( buffer, stderr );
78 dump_string (const byte *p, size_t n, int delim )
82 if ((*p & 0x80) || iscntrl( *p ) || *p == delim )
97 log_printf ("\\x%02x", *p );
100 log_printf ("%c", *p);
106 gcry_sexp_dump (const gcry_sexp_t a)
114 log_printf ( "[nil]\n");
119 while ( (type = *p) != ST_STOP )
125 log_printf ("%*s[open]\n", 2*indent, "");
131 log_printf ("%*s[close]\n", 2*indent, "");
135 memcpy ( &n, p, sizeof n );
137 log_printf ("%*s[data=\"", 2*indent, "" );
138 dump_string (p, n, '\"' );
139 log_printf ("\"]\n");
144 log_printf ("%*s[unknown tag %d]\n", 2*indent, "", type);
151 * Pass list through except when it is an empty list - in that case
152 * return NULL and release the passed list.
155 normalize ( gcry_sexp_t list )
161 if ( *p == ST_STOP ) {
163 gcry_sexp_release ( list );
166 if( *p == ST_OPEN && p[1] == ST_CLOSE ) {
168 gcry_sexp_release ( list );
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().
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.
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. */
191 gcry_sexp_create (gcry_sexp_t *retsexp, void *buffer, size_t length,
192 int autodetect, void (*freefnc)(void*) )
196 volatile va_list dummy_arg_ptr;
199 return gpg_error (GPG_ERR_INV_ARG);
201 if (autodetect < 0 || autodetect > 1 || !buffer)
202 return gpg_error (GPG_ERR_INV_ARG);
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);
211 else if (!length && autodetect)
212 { /* buffer is a string */
213 length = strlen ((char *)buffer);
216 errcode = sexp_sscan (&se, NULL, buffer, length, 0, dummy_arg_ptr, NULL);
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 */
230 return gpg_error (GPG_ERR_NO_ERROR);
233 /* Same as gcry_sexp_create but don't transfer ownership */
235 gcry_sexp_new (gcry_sexp_t *retsexp, const void *buffer, size_t length,
238 return gcry_sexp_create (retsexp, (void *)buffer, length, autodetect, NULL);
243 * Release resource of the given SEXP object.
246 gcry_sexp_release( gcry_sexp_t sexp )
253 * Make a pair from lists a and b, don't use a or b later on.
254 * Special behaviour: If one is a single element list we put the
255 * element straight into the new pair.
258 gcry_sexp_cons( const gcry_sexp_t a, const gcry_sexp_t b )
260 /* NYI: Implementation should be quite easy with our new data representation */
267 * Make a list from all items in the array the end of the array is marked
268 * with a NULL. y a NULL
271 gcry_sexp_alist( const gcry_sexp_t *array )
273 /* NYI: Implementaion should be quite easy with our new data representation */
279 * Make a list from all items, the end of list is indicated by a NULL
282 gcry_sexp_vlist( const gcry_sexp_t a, ... )
284 /* NYI: Implementaion should be quite easy with our new data representation */
291 * Append n to the list a
292 * Returns: a new ist (which maybe a)
295 gcry_sexp_append( const gcry_sexp_t a, const gcry_sexp_t n )
297 /* NYI: Implementaion should be quite easy with our new data representation */
303 gcry_sexp_prepend( const gcry_sexp_t a, const gcry_sexp_t n )
305 /* NYI: Implementaion should be quite easy with our new data representation */
313 * Locate token in a list. The token must be the car of a sublist.
314 * Returns: A new list with this sublist or NULL if not found.
317 gcry_sexp_find_token( const gcry_sexp_t list, const char *tok, size_t toklen )
326 toklen = strlen(tok);
328 while ( *p != ST_STOP ) {
329 if ( *p == ST_OPEN && p[1] == ST_DATA ) {
330 const byte *head = p;
333 memcpy ( &n, p, sizeof n ); p += sizeof n;
334 if ( n == toklen && !memcmp( p, tok, toklen ) ) { /* found it */
339 /* look for the end of the list */
340 for ( p += n; level; p++ ) {
341 if ( *p == ST_DATA ) {
342 memcpy ( &n, ++p, sizeof n );
344 p--; /* compensate for later increment */
346 else if ( *p == ST_OPEN ) {
349 else if ( *p == ST_CLOSE ) {
352 else if ( *p == ST_STOP ) {
358 newlist = gcry_xmalloc ( sizeof *newlist + n );
360 memcpy ( d, head, n ); d += n;
362 return normalize ( newlist );
366 else if ( *p == ST_DATA ) {
367 memcpy ( &n, ++p, sizeof n ); p += sizeof n;
377 * Return the length of the given list
380 gcry_sexp_length( const gcry_sexp_t list )
392 while ( (type=*p) != ST_STOP ) {
394 if ( type == ST_DATA ) {
395 memcpy ( &n, p, sizeof n );
400 else if ( type == ST_OPEN ) {
405 else if ( type == ST_CLOSE ) {
415 * Extract the CAR of the given list
418 gcry_sexp_nth( const gcry_sexp_t list, int number )
426 if ( !list || list->d[0] != ST_OPEN )
430 while ( number > 0 ) {
432 if ( *p == ST_DATA ) {
433 memcpy ( &n, ++p, sizeof n );
439 else if ( *p == ST_OPEN ) {
442 else if ( *p == ST_CLOSE ) {
447 else if ( *p == ST_STOP ) {
453 if ( *p == ST_DATA ) {
454 memcpy ( &n, p, sizeof n ); p += sizeof n;
455 newlist = gcry_xmalloc ( sizeof *newlist + n + 1 );
457 memcpy ( d, p, n ); d += n;
460 else if ( *p == ST_OPEN ) {
461 const byte *head = p;
466 if ( *p == ST_DATA ) {
467 memcpy ( &n, ++p, sizeof n );
471 else if ( *p == ST_OPEN ) {
474 else if ( *p == ST_CLOSE ) {
477 else if ( *p == ST_STOP ) {
483 newlist = gcry_xmalloc ( sizeof *newlist + n );
485 memcpy ( d, head, n ); d += n;
491 return normalize (newlist);
495 gcry_sexp_car( const gcry_sexp_t list )
497 return gcry_sexp_nth ( list, 0 );
501 * Get data from the car. The returned value is valid as long as the list
505 gcry_sexp_nth_data( const gcry_sexp_t list, int number, size_t *datalen )
517 p++; /* yep, a list */
519 return NULL; /* not a list but an n > 0 element requested */
521 /* skip n elements */
522 while ( number > 0 ) {
523 if ( *p == ST_DATA ) {
524 memcpy ( &n, ++p, sizeof n );
530 else if ( *p == ST_OPEN ) {
533 else if ( *p == ST_CLOSE ) {
538 else if ( *p == ST_STOP ) {
545 if ( *p == ST_DATA ) {
546 memcpy ( &n, ++p, sizeof n );
555 * Get a MPI from the car
558 gcry_sexp_nth_mpi( gcry_sexp_t list, int number, int mpifmt )
567 mpifmt = GCRYMPI_FMT_STD;
571 p++; /* yep, a list */
573 return NULL; /* not a list but an n > 0 element requested */
575 /* skip n elements */
576 while ( number > 0 ) {
577 if ( *p == ST_DATA ) {
578 memcpy ( &n, ++p, sizeof n );
584 else if ( *p == ST_OPEN ) {
587 else if ( *p == ST_CLOSE ) {
592 else if ( *p == ST_STOP ) {
598 if ( *p == ST_DATA ) {
602 memcpy ( &n, ++p, sizeof n );
605 if( !gcry_mpi_scan( &a, mpifmt, p, &nbytes ) )
617 gcry_sexp_cdr( const gcry_sexp_t list )
627 if ( !list || list->d[0] != ST_OPEN )
633 if ( *p == ST_DATA ) {
634 memcpy ( &n, ++p, sizeof n );
640 else if ( *p == ST_OPEN ) {
643 else if ( *p == ST_CLOSE ) {
648 else if ( *p == ST_STOP ) {
657 if ( *p == ST_DATA ) {
658 memcpy ( &n, ++p, sizeof n );
662 else if ( *p == ST_OPEN ) {
665 else if ( *p == ST_CLOSE ) {
668 else if ( *p == ST_STOP ) {
675 newlist = gcry_xmalloc ( sizeof *newlist + n + 2 );
678 memcpy ( d, head, n ); d += n;
682 return normalize (newlist);
686 gcry_sexp_cadr ( const gcry_sexp_t list )
690 a = gcry_sexp_cdr ( list );
691 b = gcry_sexp_car ( a );
692 gcry_sexp_release ( a );
699 hextobyte( const byte *s )
703 if( *s >= '0' && *s <= '9' )
705 else if( *s >= 'A' && *s <= 'F' )
706 c = 16 * (10 + *s - 'A');
707 else if( *s >= 'a' && *s <= 'f' ) {
708 c = 16 * (10 + *s - 'a');
711 if( *s >= '0' && *s <= '9' )
713 else if( *s >= 'A' && *s <= 'F' )
715 else if( *s >= 'a' && *s <= 'f' ) {
721 struct make_space_ctx {
728 make_space ( struct make_space_ctx *c, size_t n )
730 size_t used = c->pos - c->sexp->d;
732 if ( used + n + sizeof(DATALEN) + 1 >= c->allocated ) {
736 c->allocated += 2*(n+sizeof(DATALEN)+1);
737 newsexp = gcry_xrealloc ( c->sexp, sizeof *newsexp + c->allocated - 1 );
738 newhead = newsexp->d;
739 c->pos = newhead + used;
745 /* Unquote STRING of LENGTH and store it into BUF. The surrounding
746 quotes are must already be removed from STRING. We assume that the
747 quoted string is syntacillay correct. */
749 unquote_string (const unsigned char *string, size_t length, unsigned char *buf)
752 const unsigned char *s = string;
753 unsigned char *d = buf;
762 case 'b': *d++ = '\b'; break;
763 case 't': *d++ = '\t'; break;
764 case 'v': *d++ = '\v'; break;
765 case 'n': *d++ = '\n'; break;
766 case 'f': *d++ = '\f'; break;
767 case 'r': *d++ = '\r'; break;
768 case '"': *d++ = '\"'; break;
769 case '\'': *d++ = '\''; break;
770 case '\\': *d++ = '\\'; break;
772 case '\r': /* ignore CR[,LF] */
773 if (n>1 && s[1] == '\n')
780 case '\n': /* ignore LF[,CR] */
781 if (n>1 && s[1] == '\r')
787 case 'x': /* hex value */
788 if (n>2 && hexdigitp (s+1) && hexdigitp (s+2))
797 if (n>2 && octdigitp (s) && octdigitp (s+1) && octdigitp (s+2))
799 *d++ = (atoi_1 (s)*64) + (atoi_1 (s+1)*8) + atoi_1 (s+2);
807 else if( *s == '\\' )
817 * Scan the provided buffer and return the S expression in our internal
818 * format. Returns a newly allocated expression. If erroff is not NULL and
819 * a parsing error has occured, the offset into buffer will be returned.
820 * If ARGFLAG is true, the function supports some printf like
824 * %s - string (no autoswitch to secure allocation)
825 * %d - integer stored as string (no autoswitch to secure allocation)
826 * all other format elements are currently not defined and return an error.
827 * this includes the "%%" sequence becauce the percent sign is not an
829 * FIXME: We should find a way to store the secure-MPIS not in the string
830 * but as reference to somewhere - this can help us to save huge amounts
831 * of secure memory. The problem is, that if only one element is secure, all
832 * other elements are automagicaly copied to secure meory too, so the most
833 * common operation gcry_sexp_cdr_mpi() will always return a secure MPI
834 * regardless whether it is needed or not.
837 sexp_sscan (gcry_sexp_t *retsexp, size_t *erroff,
838 const char *buffer, size_t length, int argflag,
839 va_list arg_ptr, void **arg_list)
841 static const char tokenchars[] = "\
842 abcdefghijklmnopqrstuvwxyz\
843 ABCDEFGHIJKLMNOPQRSTUVWXYZ\
847 const char *digptr = NULL;
848 const char *quoted = NULL;
849 const char *tokenp = NULL;
850 const char *hexfmt = NULL;
851 const char *base64 = NULL;
852 const char *disphint = NULL;
853 const char *percent = NULL;
858 struct make_space_ctx c;
862 erroff = &dummy_erroff;
864 /* Depending on wether ARG_LIST is non-zero or not, this macro gives
865 us the next argument, either from the variable argument list as
866 specified by ARG_PTR or from the arugment array ARG_LIST. */
867 #define ARG_NEXT(storage, type) \
871 storage = va_arg (arg_ptr, type); \
873 storage = *((type *) (arg_list[arg_counter++])); \
877 /* FIXME: replace all the returns by a jump to the leave label
878 * and invent better error codes. Make sure that everything is cleaned up*/
879 #define MAKE_SPACE(n) do { make_space ( &c, (n) ); } while (0)
880 #define STORE_LEN(p,n) do { \
881 DATALEN ashort = (n); \
882 memcpy ( (p), &ashort, sizeof(ashort) ); \
883 (p) += sizeof (ashort); \
886 /* We assume that the internal representation takes less memory
887 * than the provided one. However, we add space for one extra datalen
888 * so that the code which does the ST_CLOSE can use MAKE_SPACE */
889 c.allocated = length + sizeof(DATALEN);
890 c.sexp = gcry_xmalloc ( sizeof *c.sexp + c.allocated - 1 );
893 for(p=buffer,n=length; n; p++, n-- ) {
894 if( tokenp && !hexfmt ) {
895 if( strchr( tokenchars, *p ) )
897 datalen = p - tokenp;
898 MAKE_SPACE ( datalen );
900 STORE_LEN ( c.pos, datalen );
901 memcpy ( c.pos, tokenp, datalen );
908 case 'b': case 't': case 'v': case 'n': case 'f':
909 case 'r': case '"': case '\'': case '\\':
912 case '0': case '1': case '2': case '3': case '4':
913 case '5': case '6': case '7':
914 if( !(n > 2 && p[1] >= '0' && p[1] <= '7'
915 && p[2] >= '0' && p[2] <= '7') ) {
916 *erroff = p - buffer;
917 /* Invalid octal value. */
918 return gpg_error (GPG_ERR_SEXP_BAD_QUOTATION);
924 if( !(n > 2 && isxdigit(p[1]) && isxdigit(p[2]) ) ) {
925 *erroff = p - buffer;
926 /* Invalid hex value. */
927 return gpg_error (GPG_ERR_SEXP_BAD_QUOTATION);
932 case '\r': /* ignore CR[,LF] */
933 if( n && p[1] == '\n' ) {
938 case '\n': /* ignore LF[,CR] */
939 if( n && p[1] == '\r' ) {
945 *erroff = p - buffer;
946 /* Invalid quoted string escape. */
947 return gpg_error (GPG_ERR_SEXP_BAD_QUOTATION);
950 else if( *p == '\\' )
952 else if( *p == '\"' ) {
953 /* keep it easy - we know that the unquoted string will
958 quoted++; /* skip leading quote */
959 MAKE_SPACE (p - quoted);
962 STORE_LEN (c.pos, 0); /* will be fixed up later */
963 len = unquote_string (quoted, p - quoted, c.pos);
965 STORE_LEN (save, len);
972 else if( *p == '#' ) {
973 if( (hexcount & 1) ) {
974 *erroff = p - buffer;
975 return gpg_error (GPG_ERR_SEXP_ODD_HEX_NUMBERS);
978 datalen = hexcount/2;
979 MAKE_SPACE (datalen);
981 STORE_LEN (c.pos, datalen);
982 for( hexfmt++; hexfmt < p; hexfmt++ ) {
983 if( isspace( *hexfmt ) )
985 *c.pos++ = hextobyte( hexfmt );
990 else if( !isspace( *p ) ) {
991 *erroff = p - buffer;
992 return gpg_error (GPG_ERR_SEXP_BAD_HEX_CHAR);
1002 else if( *p == ':' ) {
1003 datalen = atoi( digptr ); /* fixme: check for overflow */
1005 if( datalen > n-1 ) {
1006 *erroff = p - buffer;
1007 /* Buffer too short. */
1008 return gpg_error (GPG_ERR_SEXP_STRING_TOO_LONG);
1010 /* make a new list entry */
1011 MAKE_SPACE (datalen);
1013 STORE_LEN (c.pos, datalen);
1014 memcpy (c.pos, p+1, datalen );
1019 else if( *p == '\"' ) {
1020 digptr = NULL; /* we ignore the optional length */
1024 else if( *p == '#' ) {
1025 digptr = NULL; /* we ignore the optional length */
1029 else if( *p == '|' ) {
1030 digptr = NULL; /* we ignore the optional length */
1034 *erroff = p - buffer;
1035 return gpg_error (GPG_ERR_SEXP_INV_LEN_SPEC);
1038 else if ( percent ) {
1039 if ( *p == 'm' ) { /* insert an MPI */
1043 ARG_NEXT (m, gcry_mpi_t);
1045 if ( gcry_mpi_print( GCRYMPI_FMT_STD, NULL, &nm, m ) )
1049 if ( !gcry_is_secure ( c.sexp->d )
1050 && gcry_mpi_get_flag ( m, GCRYMPI_FLAG_SECURE ) ) {
1051 /* we have to switch to secure allocation */
1052 gcry_sexp_t newsexp;
1055 newsexp = gcry_xmalloc_secure ( sizeof *newsexp
1056 + c.allocated - 1 );
1057 newhead = newsexp->d;
1058 memcpy ( newhead, c.sexp->d, (c.pos - c.sexp->d) );
1059 c.pos = newhead + ( c.pos - c.sexp->d );
1060 gcry_free ( c.sexp );
1065 STORE_LEN (c.pos, nm);
1066 if ( gcry_mpi_print( GCRYMPI_FMT_STD, c.pos, &nm, m ) )
1070 else if ( *p == 's' ) { /* insert an string */
1074 ARG_NEXT (astr, const char *);
1075 alen = strlen (astr);
1079 STORE_LEN (c.pos, alen);
1080 memcpy ( c.pos, astr, alen );
1083 else if ( *p == 'd' ) { /* insert an integer as string */
1088 ARG_NEXT (aint, int);
1089 sprintf ( buf, "%d", aint );
1090 alen = strlen ( buf );
1093 STORE_LEN (c.pos, alen);
1094 memcpy ( c.pos, buf, alen );
1098 *erroff = p - buffer;
1099 /* Invalid format specifier. */
1100 return gpg_error (GPG_ERR_SEXP_INV_LEN_SPEC);
1104 else if( *p == '(' ) {
1106 *erroff = p - buffer;
1107 /* Open display hint. */
1108 return gpg_error (GPG_ERR_SEXP_UNMATCHED_DH);
1113 else if( *p == ')' ) { /* walk up */
1115 *erroff = p - buffer;
1116 /* Open display hint. */
1117 return gpg_error (GPG_ERR_SEXP_UNMATCHED_DH);
1120 *c.pos++ = ST_CLOSE;
1122 else if( *p == '\"' ) {
1126 else if( *p == '#' ) {
1130 else if( *p == '|' )
1132 else if( *p == '[' ) {
1134 *erroff = p - buffer;
1135 /* Open display hint. */
1136 return gpg_error (GPG_ERR_SEXP_NESTED_DH);
1140 else if( *p == ']' ) {
1142 *erroff = p - buffer;
1143 /* Open display hint. */
1144 return gpg_error (GPG_ERR_SEXP_UNMATCHED_DH);
1148 else if( isdigit(*p) ) {
1149 if( *p == '0' ) { /* a length may not begin with zero */
1150 *erroff = p - buffer;
1151 return gpg_error (GPG_ERR_SEXP_ZERO_PREFIX);
1155 else if( strchr( tokenchars, *p ) )
1157 else if( isspace(*p) )
1159 else if( *p == '{' ) {
1160 /* fixme: handle rescanning:
1161 * we can do this by saving our current state
1162 * and start over at p+1 -- Hmmm. At this point here
1163 * we are in a well defined state, so we don't need to save
1166 *erroff = p - buffer;
1167 return gpg_error (GPG_ERR_SEXP_UNEXPECTED_PUNC);
1169 else if( strchr( "&\\", *p ) ) { /*reserved punctuation*/
1170 *erroff = p - buffer;
1171 return gpg_error (GPG_ERR_SEXP_UNEXPECTED_PUNC);
1173 else if( argflag && *p == '%' ) {
1176 else { /* bad or unavailable*/
1177 *erroff = p - buffer;
1178 return gpg_error (GPG_ERR_SEXP_BAD_CHARACTER);
1185 *retsexp = normalize ( c.sexp );
1186 return gpg_error (GPG_ERR_NO_ERROR);
1192 gcry_sexp_build (gcry_sexp_t *retsexp, size_t *erroff, const char *format, ...)
1197 va_start (arg_ptr, format);
1198 rc = sexp_sscan (retsexp, erroff, format, strlen(format), 1,
1205 /* Like gcry_sexp_build, but uses an array instead of variable
1206 function arguments. */
1208 gcry_sexp_build_array (gcry_sexp_t *retsexp, size_t *erroff,
1209 const char *format, void **arg_list)
1211 /* We don't need the va_list because it is controlled by the
1212 following flag, however we have to pass it but can't initialize
1213 it as there is no portable way to do so. volatile is needed to
1214 suppress the compiler warning */
1215 volatile va_list dummy_arg_ptr;
1219 rc = sexp_sscan (retsexp, erroff, format, strlen(format), 1,
1220 dummy_arg_ptr, arg_list);
1226 gcry_sexp_sscan (gcry_sexp_t *retsexp, size_t *erroff,
1227 const char *buffer, size_t length)
1229 /* We don't need the va_list because it is controlled by the
1230 following flag, however we have to pass it but can't initialize
1231 it as there is no portable way to do so. volatile is needed to
1232 suppress the compiler warning */
1233 volatile va_list dummy_arg_ptr;
1235 return sexp_sscan (retsexp, erroff, buffer, length, 0,
1236 dummy_arg_ptr, NULL);
1240 /* Figure out a suitable encoding for BUFFER of LENGTH.
1246 suitable_encoding (const unsigned char *buffer, size_t length)
1248 const unsigned char *s;
1249 int maybe_token = 1;
1254 for (s=buffer; length; s++, length--)
1256 if ( (*s < 0x20 || (*s >= 0x7f && *s <= 0xa0))
1257 && !strchr ("\b\t\v\n\f\r\"\'\\", *s))
1258 return 0; /*binary*/
1260 && !alphap (s) && !digitp (s) && !strchr (TOKEN_SPECIALS, *s))
1264 if ( maybe_token && !digitp (s) )
1271 convert_to_hex (const unsigned char *src, size_t len, unsigned char *dest)
1278 for (i=0; i < len; i++, dest += 2 )
1279 sprintf (dest, "%02X", src[i]);
1286 convert_to_string (const unsigned char *s, size_t len, unsigned char *dest)
1290 unsigned char *p = dest;
1292 for (; len; len--, s++ )
1296 case '\b': *p++ = '\\'; *p++ = 'b'; break;
1297 case '\t': *p++ = '\\'; *p++ = 't'; break;
1298 case '\v': *p++ = '\\'; *p++ = 'v'; break;
1299 case '\n': *p++ = '\\'; *p++ = 'n'; break;
1300 case '\f': *p++ = '\\'; *p++ = 'f'; break;
1301 case '\r': *p++ = '\\'; *p++ = 'r'; break;
1302 case '\"': *p++ = '\\'; *p++ = '\"'; break;
1303 case '\'': *p++ = '\\'; *p++ = '\''; break;
1304 case '\\': *p++ = '\\'; *p++ = '\\'; break;
1306 if ( (*s < 0x20 || (*s >= 0x7f && *s <= 0xa0)))
1308 sprintf (p, "\\x%02x", *s);
1321 for (; len; len--, s++ )
1333 case '\\': count += 2; break;
1335 if ( (*s < 0x20 || (*s >= 0x7f && *s <= 0xa0)))
1348 convert_to_token (const unsigned char *src, size_t len, unsigned char *dest)
1351 memcpy (dest, src, len);
1357 * Print SEXP to buffer using the MODE. Returns the length of the
1358 * SEXP in buffer or 0 if the buffer is too short (We have at least an
1359 * empty list consisting of 2 bytes). If a buffer of NULL is provided,
1360 * the required length is returned.
1363 gcry_sexp_sprint( const gcry_sexp_t list, int mode,
1364 char *buffer, size_t maxlength )
1366 static byte empty[3] = { ST_OPEN, ST_CLOSE, ST_STOP };
1374 s = list? list->d : empty;
1376 while ( *s != ST_STOP )
1382 if ( mode != GCRYSEXP_FMT_CANON )
1391 if ( len >= maxlength )
1393 if ( mode != GCRYSEXP_FMT_CANON )
1397 for (i=0; i < indent; i++)
1409 if ( len >= maxlength )
1414 if (*s != ST_OPEN && *s != ST_STOP && mode != GCRYSEXP_FMT_CANON)
1420 if (len >= maxlength)
1423 for (i=0; i < indent; i++)
1430 memcpy ( &n, s, sizeof n ); s += sizeof n;
1431 if (mode == GCRYSEXP_FMT_ADVANCED)
1436 switch ( (type=suitable_encoding (s, n)))
1438 case 1: nn = convert_to_string (s, n, NULL); break;
1439 case 2: nn = convert_to_token (s, n, NULL); break;
1440 default: nn = convert_to_hex (s, n, NULL); break;
1445 if (len >= maxlength)
1449 case 1: convert_to_string (s, n, d); break;
1450 case 2: convert_to_token (s, n, d); break;
1451 default: convert_to_hex (s, n, d); break;
1455 if (s[n] != ST_CLOSE)
1460 if (len >= maxlength)
1468 sprintf (numbuf, "%u:", (unsigned int)n );
1469 len += strlen (numbuf) + n;
1472 if ( len >= maxlength )
1474 d = stpcpy ( d, numbuf );
1475 memcpy ( d, s, n ); d += n;
1484 if ( mode != GCRYSEXP_FMT_CANON )
1489 if ( len >= maxlength )
1496 if ( len >= maxlength )
1498 *d++ = 0; /* for convenience we make a C string */
1501 len++; /* we need one byte more for this */
1507 /* Scan a cannocial encoded buffer with implicit length values and
1508 return the actual length this S-expression uses. For a valid S-Exp
1509 it should never return 0. If LENGTH is not zero, the maximum
1510 length to scan is given - this can be used for syntax checks of
1511 data passed from outside. errorcode and erroff may both be passed as
1514 gcry_sexp_canon_len (const unsigned char *buffer, size_t length,
1515 size_t *erroff, gpg_error_t *errcode)
1517 const unsigned char *p;
1518 const char *disphint=NULL;
1519 unsigned int datalen = 0;
1520 size_t dummy_erroff;
1521 gpg_error_t dummy_errcode;
1526 erroff = &dummy_erroff;
1528 errcode = &dummy_errcode;
1530 *errcode = gpg_error (GPG_ERR_NO_ERROR);
1536 *errcode = gpg_error (GPG_ERR_SEXP_NOT_CANONICAL);
1540 for (p=buffer; ; p++, count++ )
1542 if (length && count >= length)
1545 *errcode = gpg_error (GPG_ERR_SEXP_STRING_TOO_LONG);
1553 if (length && (count+datalen) >= length)
1556 *errcode = gpg_error (GPG_ERR_SEXP_STRING_TOO_LONG);
1564 datalen = datalen*10 + atoi_1(p);
1568 *errcode = gpg_error (GPG_ERR_SEXP_INV_LEN_SPEC);
1577 *errcode = gpg_error (GPG_ERR_SEXP_UNMATCHED_DH);
1587 *errcode = gpg_error (GPG_ERR_SEXP_UNMATCHED_PAREN);
1593 *errcode = gpg_error (GPG_ERR_SEXP_UNMATCHED_DH);
1597 return ++count; /* ready */
1604 *errcode = gpg_error (GPG_ERR_SEXP_NESTED_DH);
1614 *errcode = gpg_error (GPG_ERR_SEXP_UNMATCHED_DH);
1619 else if (digitp (p) )
1624 *errcode = gpg_error (GPG_ERR_SEXP_ZERO_PREFIX);
1627 datalen = atoi_1 (p);
1629 else if (*p == '&' || *p == '\\')
1632 *errcode = gpg_error (GPG_ERR_SEXP_UNEXPECTED_PUNC);
1638 *errcode = gpg_error (GPG_ERR_SEXP_BAD_CHARACTER);