Line data Source code
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 <http://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 440 : percent_plus_escape (const char *string)
52 : {
53 : char *buffer, *p;
54 : const char *s;
55 : size_t length;
56 :
57 76930 : for (length=1, s=string; *s; s++)
58 : {
59 76490 : if (*s == '+' || *s == '\"' || *s == '%'
60 75621 : || *(const unsigned char *)s < 0x20)
61 2595 : length += 3;
62 : else
63 73895 : length++;
64 : }
65 :
66 440 : buffer = p = xtrymalloc (length);
67 440 : if (!buffer)
68 0 : return NULL;
69 :
70 76930 : for (s=string; *s; s++)
71 : {
72 76490 : if (*s == '+' || *s == '\"' || *s == '%'
73 75621 : || *(const unsigned char *)s < 0x20)
74 : {
75 2595 : snprintf (p, 4, "%%%02X", *(unsigned char *)s);
76 2595 : p += 3;
77 : }
78 73895 : else if (*s == ' ')
79 8470 : *p++ = '+';
80 : else
81 65425 : *p++ = *s;
82 : }
83 440 : *p = 0;
84 :
85 440 : 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 9 : do_unescape (unsigned char *buffer, const unsigned char *string,
96 : int withplus, int nulrepl)
97 : {
98 9 : unsigned char *p = buffer;
99 :
100 40 : while (*string)
101 : {
102 22 : if (*string == '%' && string[1] && string[2])
103 : {
104 9 : string++;
105 9 : *p = xtoi_2 (string);
106 9 : if (!*p)
107 0 : *p = nulrepl;
108 9 : string++;
109 : }
110 13 : else if (*string == '+' && withplus)
111 7 : *p = ' ';
112 : else
113 6 : *p = *string;
114 22 : p++;
115 22 : string++;
116 : }
117 :
118 9 : 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 9 : count_unescape (const unsigned char *string)
126 : {
127 9 : size_t n = 0;
128 :
129 40 : while (*string)
130 : {
131 22 : if (*string == '%' && string[1] && string[2])
132 : {
133 9 : string++;
134 9 : string++;
135 : }
136 22 : string++;
137 22 : n++;
138 : }
139 :
140 9 : return n;
141 : }
142 :
143 :
144 : /* Helper. */
145 : static char *
146 9 : do_plus_or_plain_unescape (const char *string, int withplus, int nulrepl)
147 : {
148 : size_t nbytes, n;
149 : char *newstring;
150 :
151 9 : nbytes = count_unescape (string);
152 9 : newstring = xtrymalloc (nbytes+1);
153 9 : if (newstring)
154 : {
155 9 : n = do_unescape (newstring, string, withplus, nulrepl);
156 9 : assert (n == nbytes);
157 9 : newstring[n] = 0;
158 : }
159 9 : 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 9 : percent_plus_unescape (const char *string, int nulrepl)
169 : {
170 9 : 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 0 : percent_unescape (const char *string, int nulrepl)
180 : {
181 0 : return do_plus_or_plain_unescape (string, 0, nulrepl);
182 : }
183 :
184 :
185 : static size_t
186 9 : do_unescape_inplace (char *string, int withplus, int nulrepl)
187 : {
188 : unsigned char *p, *p0;
189 :
190 9 : p = p0 = string;
191 40 : while (*string)
192 : {
193 22 : if (*string == '%' && string[1] && string[2])
194 : {
195 9 : string++;
196 9 : *p = xtoi_2 (string);
197 9 : if (!*p)
198 0 : *p = nulrepl;
199 9 : string++;
200 : }
201 13 : else if (*string == '+' && withplus)
202 7 : *p = ' ';
203 : else
204 6 : *p = *string;
205 22 : p++;
206 22 : string++;
207 : }
208 :
209 9 : 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 9 : percent_plus_unescape_inplace (char *string, int nulrepl)
222 : {
223 9 : 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 0 : percent_unescape_inplace (char *string, int nulrepl)
236 : {
237 0 : return do_unescape_inplace (string, 0, nulrepl);
238 : }
|