gpg: In a list of card keys show the standard keys.
[gnupg.git] / common / percent.c
1 /* percent.c - Percent escaping
2  * Copyright (C) 2008, 2009 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * This file is free software; you can redistribute it and/or modify
7  * it under the terms of either
8  *
9  *   - the GNU Lesser General Public License as published by the Free
10  *     Software Foundation; either version 3 of the License, or (at
11  *     your option) any later version.
12  *
13  * or
14  *
15  *   - the GNU General Public License as published by the Free
16  *     Software Foundation; either version 2 of the License, or (at
17  *     your option) any later version.
18  *
19  * or both in parallel, as here.
20  *
21  * This file is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, see <https://www.gnu.org/licenses/>.
28  */
29
30 #include <config.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <ctype.h>
34 #include <assert.h>
35
36 #include "util.h"
37
38
39 /* Create a newly alloced string from STRING with all spaces and
40  * control characters converted to plus signs or %xx sequences.  The
41  * function returns the new string or NULL in case of a malloc
42  * failure.
43  *
44  * Note that this fucntion also escapes the quote character to work
45  * around a bug in the mingw32 runtime which does not correctly handle
46  * command line quoting.  We correctly double the quote mark when
47  * calling a program (i.e. gpg-protect-tool), but the pre-main code
48  * does not notice the double quote as an escaped quote.  We do this
49  * also on POSIX systems for consistency.  */
50 char *
51 percent_plus_escape (const char *string)
52 {
53   char *buffer, *p;
54   const char *s;
55   size_t length;
56
57   for (length=1, s=string; *s; s++)
58     {
59       if (*s == '+' || *s == '\"' || *s == '%'
60           || *(const unsigned char *)s < 0x20)
61         length += 3;
62       else
63         length++;
64     }
65
66   buffer = p = xtrymalloc (length);
67   if (!buffer)
68     return NULL;
69
70   for (s=string; *s; s++)
71     {
72       if (*s == '+' || *s == '\"' || *s == '%'
73           || *(const unsigned char *)s < 0x20)
74         {
75           snprintf (p, 4, "%%%02X", *(unsigned char *)s);
76           p += 3;
77         }
78       else if (*s == ' ')
79         *p++ = '+';
80       else
81         *p++ = *s;
82     }
83   *p = 0;
84
85   return buffer;
86
87 }
88
89
90 /* Create a newly malloced string from (DATA,DATALEN) with embedded
91  * nuls quoted as %00.  The standard percent unescaping can be used to
92  * reverse this encoding.  With PLUS_ESCAPE set plus-escaping (spaces
93  * are replaced by a '+') and escaping of characters with values less
94  * than 0x20 is used.  If PREFIX is not NULL it will be prepended to
95  * the output in standard escape format; that is PLUS_ESCAPING is
96  * ignored for PREFIX. */
97 char *
98 percent_data_escape (int plus_escape, const char *prefix,
99                      const void *data, size_t datalen)
100 {
101   char *buffer, *p;
102   const unsigned char *s;
103   size_t n;
104   size_t length = 1;
105
106   if (prefix)
107     {
108       for (s = prefix; *s; s++)
109         {
110           if (*s == '%' || *s < 0x20)
111             length += 3;
112           else
113             length++;
114         }
115     }
116
117   for (s=data, n=datalen; n; s++, n--)
118     {
119       if (!*s || *s == '%' || (plus_escape && (*s < ' ' || *s == '+')))
120         length += 3;
121       else
122         length++;
123     }
124
125   buffer = p = xtrymalloc (length);
126   if (!buffer)
127     return NULL;
128
129   if (prefix)
130     {
131       for (s = prefix; *s; s++)
132         {
133           if (*s == '%' || *s < 0x20)
134             {
135               snprintf (p, 4, "%%%02X", *s);
136               p += 3;
137             }
138           else
139             *p++ = *s;
140         }
141     }
142
143   for (s=data, n=datalen; n; s++, n--)
144     {
145       if (!*s)
146         {
147           memcpy (p, "%00", 3);
148           p += 3;
149         }
150       else if (*s == '%')
151         {
152           memcpy (p, "%25", 3);
153           p += 3;
154         }
155       else if (plus_escape && *s == ' ')
156         {
157           *p++ = '+';
158         }
159       else if (plus_escape && (*s < ' ' || *s == '+'))
160         {
161           snprintf (p, 4, "%%%02X", *s);
162           p += 3;
163         }
164       else
165         *p++ = *s;
166     }
167   *p = 0;
168
169   return buffer;
170 }
171
172
173 /* Do the percent and plus/space unescaping from STRING to BUFFER and
174    return the length of the valid buffer.  Plus unescaping is only
175    done if WITHPLUS is true.  An escaped Nul character will be
176    replaced by NULREPL.  */
177 static size_t
178 do_unescape (unsigned char *buffer, const unsigned char *string,
179              int withplus, int nulrepl)
180 {
181   unsigned char *p = buffer;
182
183   while (*string)
184     {
185       if (*string == '%' && string[1] && string[2])
186         {
187           string++;
188           *p = xtoi_2 (string);
189           if (!*p)
190             *p = nulrepl;
191           string++;
192         }
193       else if (*string == '+' && withplus)
194         *p = ' ';
195       else
196         *p = *string;
197       p++;
198       string++;
199     }
200
201   return (p - buffer);
202 }
203
204
205 /* Count space required after unescaping STRING.  Note that this will
206    never be larger than strlen (STRING).  */
207 static size_t
208 count_unescape (const unsigned char *string)
209 {
210   size_t n = 0;
211
212   while (*string)
213     {
214       if (*string == '%' && string[1] && string[2])
215         {
216           string++;
217           string++;
218         }
219       string++;
220       n++;
221     }
222
223   return n;
224 }
225
226
227 /* Helper.  */
228 static char *
229 do_plus_or_plain_unescape (const char *string, int withplus, int nulrepl)
230 {
231   size_t nbytes, n;
232   char *newstring;
233
234   nbytes = count_unescape (string);
235   newstring = xtrymalloc (nbytes+1);
236   if (newstring)
237     {
238       n = do_unescape (newstring, string, withplus, nulrepl);
239       assert (n == nbytes);
240       newstring[n] = 0;
241     }
242   return newstring;
243 }
244
245
246 /* Create a new allocated string from STRING with all "%xx" sequences
247    decoded and all plus signs replaced by a space.  Embedded Nul
248    characters are replaced by the value of NULREPL.  The function
249    returns the new string or NULL in case of a malloc failure.  */
250 char *
251 percent_plus_unescape (const char *string, int nulrepl)
252 {
253   return do_plus_or_plain_unescape (string, 1, nulrepl);
254 }
255
256
257 /* Create a new allocated string from STRING with all "%xx" sequences
258    decoded.  Embedded Nul characters are replaced by the value of
259    NULREPL.  The function returns the new string or NULL in case of a
260    malloc failure.  */
261 char *
262 percent_unescape (const char *string, int nulrepl)
263 {
264   return do_plus_or_plain_unescape (string, 0, nulrepl);
265 }
266
267
268 static size_t
269 do_unescape_inplace (char *string, int withplus, int nulrepl)
270 {
271   unsigned char *p, *p0;
272
273   p = p0 = string;
274   while (*string)
275     {
276       if (*string == '%' && string[1] && string[2])
277         {
278           string++;
279           *p = xtoi_2 (string);
280           if (!*p)
281             *p = nulrepl;
282           string++;
283         }
284       else if (*string == '+' && withplus)
285         *p = ' ';
286       else
287         *p = *string;
288       p++;
289       string++;
290     }
291
292   return (p - p0);
293 }
294
295
296 /* Perform percent and plus unescaping in STRING and return the new
297    valid length of the string.  Embedded Nul characters are replaced
298    by the value of NULREPL.  A terminating Nul character is not
299    inserted; the caller might want to call this function this way:
300
301       foo[percent_plus_unescape_inplace (foo, 0)] = 0;
302  */
303 size_t
304 percent_plus_unescape_inplace (char *string, int nulrepl)
305 {
306   return do_unescape_inplace (string, 1, nulrepl);
307 }
308
309
310 /* Perform percent unescaping in STRING and return the new valid
311    length of the string.  Embedded Nul characters are replaced by the
312    value of NULREPL.  A terminating Nul character is not inserted; the
313    caller might want to call this function this way:
314
315       foo[percent_unescape_inplace (foo, 0)] = 0;
316  */
317 size_t
318 percent_unescape_inplace (char *string, int nulrepl)
319 {
320   return do_unescape_inplace (string, 0, nulrepl);
321 }