chiark / gitweb /
dirmngr: New debug message on correctly initialized libdns.
[gnupg2.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 we also escape the quote character to work around a bug
45    in the mingw32 runtime which does not correcty handle command line
46    quoting.  We correctly double the quote mark when calling a program
47    (i.e. gpg-protect-tool), but the pre-main code does not notice the
48    double quote as an escaped quote.  We do this also on POSIX systems
49    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 /* Do the percent and plus/space unescaping from STRING to BUFFER and
91    return the length of the valid buffer.  Plus unescaping is only
92    done if WITHPLUS is true.  An escaped Nul character will be
93    replaced by NULREPL.  */
94 static size_t
95 do_unescape (unsigned char *buffer, const unsigned char *string,
96              int withplus, int nulrepl)
97 {
98   unsigned char *p = buffer;
99
100   while (*string)
101     {
102       if (*string == '%' && string[1] && string[2])
103         {
104           string++;
105           *p = xtoi_2 (string);
106           if (!*p)
107             *p = nulrepl;
108           string++;
109         }
110       else if (*string == '+' && withplus)
111         *p = ' ';
112       else
113         *p = *string;
114       p++;
115       string++;
116     }
117
118   return (p - buffer);
119 }
120
121
122 /* Count space required after unescaping STRING.  Note that this will
123    never be larger than strlen (STRING).  */
124 static size_t
125 count_unescape (const unsigned char *string)
126 {
127   size_t n = 0;
128
129   while (*string)
130     {
131       if (*string == '%' && string[1] && string[2])
132         {
133           string++;
134           string++;
135         }
136       string++;
137       n++;
138     }
139
140   return n;
141 }
142
143
144 /* Helper.  */
145 static char *
146 do_plus_or_plain_unescape (const char *string, int withplus, int nulrepl)
147 {
148   size_t nbytes, n;
149   char *newstring;
150
151   nbytes = count_unescape (string);
152   newstring = xtrymalloc (nbytes+1);
153   if (newstring)
154     {
155       n = do_unescape (newstring, string, withplus, nulrepl);
156       assert (n == nbytes);
157       newstring[n] = 0;
158     }
159   return newstring;
160 }
161
162
163 /* Create a new allocated string from STRING with all "%xx" sequences
164    decoded and all plus signs replaced by a space.  Embedded Nul
165    characters are replaced by the value of NULREPL.  The function
166    returns the new string or NULL in case of a malloc failure.  */
167 char *
168 percent_plus_unescape (const char *string, int nulrepl)
169 {
170   return do_plus_or_plain_unescape (string, 1, nulrepl);
171 }
172
173
174 /* Create a new allocated string from STRING with all "%xx" sequences
175    decoded.  Embedded Nul characters are replaced by the value of
176    NULREPL.  The function returns the new string or NULL in case of a
177    malloc failure.  */
178 char *
179 percent_unescape (const char *string, int nulrepl)
180 {
181   return do_plus_or_plain_unescape (string, 0, nulrepl);
182 }
183
184
185 static size_t
186 do_unescape_inplace (char *string, int withplus, int nulrepl)
187 {
188   unsigned char *p, *p0;
189
190   p = p0 = string;
191   while (*string)
192     {
193       if (*string == '%' && string[1] && string[2])
194         {
195           string++;
196           *p = xtoi_2 (string);
197           if (!*p)
198             *p = nulrepl;
199           string++;
200         }
201       else if (*string == '+' && withplus)
202         *p = ' ';
203       else
204         *p = *string;
205       p++;
206       string++;
207     }
208
209   return (p - p0);
210 }
211
212
213 /* Perform percent and plus unescaping in STRING and return the new
214    valid length of the string.  Embedded Nul characters are replaced
215    by the value of NULREPL.  A terminating Nul character is not
216    inserted; the caller might want to call this function this way:
217
218       foo[percent_plus_unescape_inplace (foo, 0)] = 0;
219  */
220 size_t
221 percent_plus_unescape_inplace (char *string, int nulrepl)
222 {
223   return do_unescape_inplace (string, 1, nulrepl);
224 }
225
226
227 /* Perform percent unescaping in STRING and return the new valid
228    length of the string.  Embedded Nul characters are replaced by the
229    value of NULREPL.  A terminating Nul character is not inserted; the
230    caller might want to call this function this way:
231
232       foo[percent_unescape_inplace (foo, 0)] = 0;
233  */
234 size_t
235 percent_unescape_inplace (char *string, int nulrepl)
236 {
237   return do_unescape_inplace (string, 0, nulrepl);
238 }