1 /* sexp-parse.h - S-expression helper functions
2 * Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc.
3 *
4 * This file is free software; you can redistribute it and/or modify
5 * it under the terms of either
6 *
7 * - the GNU Lesser General Public License as published by the Free
8 * Software Foundation; either version 3 of the License, or (at
9 * your option) any later version.
10 *
11 * or
12 *
13 * - the GNU General Public License as published by the Free
14 * Software Foundation; either version 2 of the License, or (at
15 * your option) any later version.
16 *
17 * or both in parallel, as here.
18 *
19 * This file is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see <https://www.gnu.org/licenses/>.
26 */
27
28 #ifndef SEXP_PARSE_H
29 #define SEXP_PARSE_H
30
31 #include <gpg-error.h>
32
33
34 /* Return the length of the next S-Exp part and update the pointer to
35 the first data byte. 0 is returned on error */
36 static inline size_t
snext(unsigned char const ** buf)37 snext (unsigned char const **buf)
38 {
39 const unsigned char *s;
40 int n;
41
42 s = *buf;
43 for (n=0; *s && *s != ':' && (*s >= '0' && *s <= '9'); s++)
44 n = n*10 + (*s - '0');
45 if (!n || *s != ':')
46 return 0; /* we don't allow empty lengths */
47 *buf = s+1;
48 return n;
49 }
50
51 /* Skip over the S-Expression BUF points to and update BUF to point to
52 the character right behind. DEPTH gives the initial number of open
53 lists and may be passed as a positive number to skip over the
54 remainder of an S-Expression if the current position is somewhere
55 in an S-Expression. The function may return an error code if it
56 encounters an impossible condition. */
57 static inline gpg_error_t
sskip(unsigned char const ** buf,int * depth)58 sskip (unsigned char const **buf, int *depth)
59 {
60 const unsigned char *s = *buf;
61 size_t n;
62 int d = *depth;
63
64 while (d > 0)
65 {
66 if (*s == '(')
67 {
68 d++;
69 s++;
70 }
71 else if (*s == ')')
72 {
73 d--;
74 s++;
75 }
76 else
77 {
78 if (!d)
79 return gpg_error (GPG_ERR_INV_SEXP);
80 n = snext (&s);
81 if (!n)
82 return gpg_error (GPG_ERR_INV_SEXP);
83 s += n;
84 }
85 }
86 *buf = s;
87 *depth = d;
88 return 0;
89 }
90
91
92 /* Check whether the string at the address BUF points to matches
93 the token. Return true on match and update BUF to point behind the
94 token. Return false and do not update the buffer if it does not
95 match. */
96 static inline int
smatch(unsigned char const ** buf,size_t buflen,const char * token)97 smatch (unsigned char const **buf, size_t buflen, const char *token)
98 {
99 size_t toklen = strlen (token);
100
101 if (buflen != toklen || memcmp (*buf, token, toklen))
102 return 0;
103 *buf += toklen;
104 return 1;
105 }
106
107 /* Format VALUE for use as the length indicatior of an S-expression.
108 The caller needs to provide a buffer HELP_BUFFER with a length of
109 HELP_BUFLEN. The return value is a pointer into HELP_BUFFER with
110 the formatted length string. The colon and a trailing nul are
111 appended. HELP_BUFLEN must be at least 3 - a more useful value is
112 15. If LENGTH is not NULL, the LENGTH of the resulting string
113 (excluding the terminating nul) is stored at that address. */
114 static inline char *
smklen(char * help_buffer,size_t help_buflen,size_t value,size_t * length)115 smklen (char *help_buffer, size_t help_buflen, size_t value, size_t *length)
116 {
117 char *p = help_buffer + help_buflen;
118
119 if (help_buflen >= 3)
120 {
121 *--p = 0;
122 *--p = ':';
123 do
124 {
125 *--p = '0' + (value % 10);
126 value /= 10;
127 }
128 while (value && p > help_buffer);
129 }
130
131 if (length)
132 *length = (help_buffer + help_buflen) - p;
133 return p;
134 }
135
136
137 #endif /*SEXP_PARSE_H*/
138