Fix a signal cleanup problem.
[gnupg.git] / common / percent.c
blobe0c359289ec4c69d5c0244a3f4835eff84778623
1 /* percent.c - Percent escaping
2 * Copyright (C) 2008, 2009 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuPG 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 General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include <config.h>
21 #include <stdlib.h>
22 #include <errno.h>
23 #include <ctype.h>
24 #include <assert.h>
26 #include "util.h"
29 /* Create a newly alloced string from STRING with all spaces and
30 control characters converted to plus signs or %xx sequences. The
31 function returns the new string or NULL in case of a malloc
32 failure.
34 Note that we also escape the quote character to work around a bug
35 in the mingw32 runtime which does not correcty handle command line
36 quoting. We correctly double the quote mark when calling a program
37 (i.e. gpg-protect-tool), but the pre-main code does not notice the
38 double quote as an escaped quote. We do this also on POSIX systems
39 for consistency. */
40 char *
41 percent_plus_escape (const char *string)
43 char *buffer, *p;
44 const char *s;
45 size_t length;
47 for (length=1, s=string; *s; s++)
49 if (*s == '+' || *s == '\"' || *s == '%'
50 || *(const unsigned char *)s < 0x20)
51 length += 3;
52 else
53 length++;
56 buffer = p = xtrymalloc (length);
57 if (!buffer)
58 return NULL;
60 for (s=string; *s; s++)
62 if (*s == '+' || *s == '\"' || *s == '%'
63 || *(const unsigned char *)s < 0x20)
65 snprintf (p, 4, "%%%02X", *(unsigned char *)s);
66 p += 3;
68 else if (*s == ' ')
69 *p++ = '+';
70 else
71 *p++ = *s;
73 *p = 0;
75 return buffer;
80 /* Do the percent and plus/space unescaping from STRING to BUFFER and
81 return the length of the valid buffer. Plus unescaping is only
82 done if WITHPLUS is true. An escaped Nul character will be
83 replaced by NULREPL. */
84 static size_t
85 do_unescape (unsigned char *buffer, const unsigned char *string,
86 int withplus, int nulrepl)
88 unsigned char *p = buffer;
90 while (*string)
92 if (*string == '%' && string[1] && string[2])
94 string++;
95 *p = xtoi_2 (string);
96 if (!*p)
97 *p = nulrepl;
98 string++;
100 else if (*string == '+' && withplus)
101 *p = ' ';
102 else
103 *p = *string;
104 p++;
105 string++;
108 return (p - buffer);
112 /* Count space required after unescaping STRING. Note that this will
113 never be larger than strlen (STRING). */
114 static size_t
115 count_unescape (const unsigned char *string)
117 size_t n = 0;
119 while (*string)
121 if (*string == '%' && string[1] && string[2])
123 string++;
124 string++;
126 string++;
127 n++;
130 return n;
134 /* Helper. */
135 static char *
136 do_plus_or_plain_unescape (const char *string, int withplus, int nulrepl)
138 size_t nbytes, n;
139 char *newstring;
141 nbytes = count_unescape (string);
142 newstring = xtrymalloc (nbytes+1);
143 if (newstring)
145 n = do_unescape (newstring, string, withplus, nulrepl);
146 assert (n == nbytes);
147 newstring[n] = 0;
149 return newstring;
153 /* Create a new allocated string from STRING with all "%xx" sequences
154 decoded and all plus signs replaced by a space. Embedded Nul
155 characters are replaced by the value of NULREPL. The function
156 returns the new string or NULL in case of a malloc failure. */
157 char *
158 percent_plus_unescape (const char *string, int nulrepl)
160 return do_plus_or_plain_unescape (string, 1, nulrepl);
164 /* Create a new allocated string from STRING with all "%xx" sequences
165 decoded. Embedded Nul characters are replaced by the value of
166 NULREPL. The function returns the new string or NULL in case of a
167 malloc failure. */
168 char *
169 percent_unescape (const char *string, int nulrepl)
171 return do_plus_or_plain_unescape (string, 0, nulrepl);
175 static size_t
176 do_unescape_inplace (char *string, int withplus, int nulrepl)
178 unsigned char *p, *p0;
180 p = p0 = string;
181 while (*string)
183 if (*string == '%' && string[1] && string[2])
185 string++;
186 *p = xtoi_2 (string);
187 if (!*p)
188 *p = nulrepl;
189 string++;
191 else if (*string == '+' && withplus)
192 *p = ' ';
193 else
194 *p = *string;
195 p++;
196 string++;
199 return (p - p0);
203 /* Perform percent and plus unescaping in STRING and return the new
204 valid length of the string. Embedded Nul characters are replaced
205 by the value of NULREPL. A terminating Nul character is not
206 inserted; the caller might want to call this function this way:
208 foo[percent_plus_unescape_inplace (foo, 0)] = 0;
210 size_t
211 percent_plus_unescape_inplace (char *string, int nulrepl)
213 return do_unescape_inplace (string, 1, nulrepl);
217 /* Perform percent unescaping in STRING and return the new valid
218 length of the string. Embedded Nul characters are replaced by the
219 value of NULREPL. A terminating Nul character is not inserted; the
220 caller might want to call this function this way:
222 foo[percent_unescape_inplace (foo, 0)] = 0;
224 size_t
225 percent_unescape_inplace (char *string, int nulrepl)
227 return do_unescape_inplace (string, 0, nulrepl);