1266733Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2266733Speter * contributor license agreements.  See the NOTICE file distributed with
3266733Speter * this work for additional information regarding copyright ownership.
4266733Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5266733Speter * (the "License"); you may not use this file except in compliance with
6266733Speter * the License.  You may obtain a copy of the License at
7266733Speter *
8266733Speter *     http://www.apache.org/licenses/LICENSE-2.0
9266733Speter *
10266733Speter * Unless required by applicable law or agreed to in writing, software
11266733Speter * distributed under the License is distributed on an "AS IS" BASIS,
12266733Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13266733Speter * See the License for the specific language governing permissions and
14266733Speter * limitations under the License.
15266733Speter */
16266733Speter
17266733Speter/* escape/unescape functions.
18266733Speter *
19266733Speter * These functions perform various escaping operations, and are provided in
20266733Speter * pairs, a function to query the length of and escape existing buffers, as
21266733Speter * well as companion functions to perform the same process to memory
22266733Speter * allocated from a pool.
23266733Speter *
24266733Speter * The API is designed to have the smallest possible RAM footprint, and so
25266733Speter * will only allocate the exact amount of RAM needed for each conversion.
26266733Speter */
27266733Speter
28266733Speter#include "apr_escape.h"
29266733Speter#include "apr_escape_test_char.h"
30266733Speter#include "apr_lib.h"
31266733Speter#include "apr_strings.h"
32266733Speter
33266733Speter#if APR_CHARSET_EBCDIC
34266733Speterstatic int convert_a2e[256] = {
35266733Speter  0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
36266733Speter  0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, 0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F,
37266733Speter  0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
38266733Speter  0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
39266733Speter  0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
40266733Speter  0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
41266733Speter  0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
42266733Speter  0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
43266733Speter  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x06, 0x17, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x09, 0x0A, 0x1B,
44266733Speter  0x30, 0x31, 0x1A, 0x33, 0x34, 0x35, 0x36, 0x08, 0x38, 0x39, 0x3A, 0x3B, 0x04, 0x14, 0x3E, 0xFF,
45266733Speter  0x41, 0xAA, 0x4A, 0xB1, 0x9F, 0xB2, 0x6A, 0xB5, 0xBB, 0xB4, 0x9A, 0x8A, 0xB0, 0xCA, 0xAF, 0xBC,
46266733Speter  0x90, 0x8F, 0xEA, 0xFA, 0xBE, 0xA0, 0xB6, 0xB3, 0x9D, 0xDA, 0x9B, 0x8B, 0xB7, 0xB8, 0xB9, 0xAB,
47266733Speter  0x64, 0x65, 0x62, 0x66, 0x63, 0x67, 0x9E, 0x68, 0x74, 0x71, 0x72, 0x73, 0x78, 0x75, 0x76, 0x77,
48266733Speter  0xAC, 0x69, 0xED, 0xEE, 0xEB, 0xEF, 0xEC, 0xBF, 0x80, 0xFD, 0xFE, 0xFB, 0xFC, 0xBA, 0xAE, 0x59,
49266733Speter  0x44, 0x45, 0x42, 0x46, 0x43, 0x47, 0x9C, 0x48, 0x54, 0x51, 0x52, 0x53, 0x58, 0x55, 0x56, 0x57,
50266733Speter  0x8C, 0x49, 0xCD, 0xCE, 0xCB, 0xCF, 0xCC, 0xE1, 0x70, 0xDD, 0xDE, 0xDB, 0xDC, 0x8D, 0x8E, 0xDF };
51266733Speter
52266733Speterstatic int convert_e2a[256] = {
53266733Speter  0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F, 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
54266733Speter  0x10, 0x11, 0x12, 0x13, 0x9D, 0x0A, 0x08, 0x87, 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F,
55266733Speter  0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x17, 0x1B, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07,
56266733Speter  0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A,
57266733Speter  0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5, 0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
58266733Speter  0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF, 0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
59266733Speter  0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5, 0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
60266733Speter  0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF, 0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
61266733Speter  0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1,
62266733Speter  0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4,
63266733Speter  0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0x5B, 0xDE, 0xAE,
64266733Speter  0xAC, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC, 0xBD, 0xBE, 0xDD, 0xA8, 0xAF, 0x5D, 0xB4, 0xD7,
65266733Speter  0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5,
66266733Speter  0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF,
67266733Speter  0x5C, 0xF7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5,
68266733Speter  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F };
69266733Speter#define RAW_ASCII_CHAR(ch)  convert_e2a[(unsigned char)ch]
70266733Speter#else /* APR_CHARSET_EBCDIC */
71266733Speter#define RAW_ASCII_CHAR(ch)  (ch)
72266733Speter#endif /* !APR_CHARSET_EBCDIC */
73266733Speter
74266733Speter/* we assume the folks using this ensure 0 <= c < 256... which means
75266733Speter * you need a cast to (unsigned char) first, you can't just plug a
76266733Speter * char in here and get it to work, because if char is signed then it
77266733Speter * will first be sign extended.
78266733Speter */
79266733Speter#define TEST_CHAR(c, f)        (test_char_table[(unsigned)(c)] & (f))
80266733Speter
81266733SpeterAPR_DECLARE(apr_status_t) apr_escape_shell(char *escaped, const char *str,
82266733Speter        apr_ssize_t slen, apr_size_t *len)
83266733Speter{
84266733Speter    unsigned char *d;
85266733Speter    const unsigned char *s;
86266733Speter    apr_size_t size = 1;
87266733Speter    int found = 0;
88266733Speter
89266733Speter    d = (unsigned char *) escaped;
90266733Speter    s = (const unsigned char *) str;
91266733Speter
92266733Speter    if (s) {
93266733Speter        if (d) {
94266733Speter            for (; *s && slen; ++s, slen--) {
95266733Speter#if defined(OS2) || defined(WIN32)
96266733Speter                /*
97266733Speter                 * Newlines to Win32/OS2 CreateProcess() are ill advised.
98266733Speter                 * Convert them to spaces since they are effectively white
99266733Speter                 * space to most applications
100266733Speter                 */
101266733Speter                if (*s == '\r' || *s == '\n') {
102266733Speter                    if (d) {
103266733Speter                        *d++ = ' ';
104266733Speter                        found = 1;
105266733Speter                    }
106266733Speter                    continue;
107266733Speter                }
108266733Speter#endif
109266733Speter                if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
110266733Speter                    *d++ = '\\';
111266733Speter                    size++;
112266733Speter                    found = 1;
113266733Speter                }
114266733Speter                *d++ = *s;
115266733Speter                size++;
116266733Speter            }
117266733Speter            *d = '\0';
118266733Speter        }
119266733Speter        else {
120266733Speter            for (; *s && slen; ++s, slen--) {
121266733Speter                if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
122266733Speter                    size++;
123266733Speter                    found = 1;
124266733Speter                }
125266733Speter                size++;
126266733Speter            }
127266733Speter        }
128266733Speter    }
129266733Speter
130266733Speter    if (len) {
131266733Speter        *len = size;
132266733Speter    }
133266733Speter    if (!found) {
134266733Speter        return APR_NOTFOUND;
135266733Speter    }
136266733Speter
137266733Speter    return APR_SUCCESS;
138266733Speter}
139266733Speter
140266733SpeterAPR_DECLARE(const char *) apr_pescape_shell(apr_pool_t *p, const char *str)
141266733Speter{
142266733Speter    apr_size_t len;
143266733Speter
144266733Speter    switch (apr_escape_shell(NULL, str, APR_ESCAPE_STRING, &len)) {
145266733Speter    case APR_SUCCESS: {
146266733Speter        char *cmd = apr_palloc(p, len);
147266733Speter        apr_escape_shell(cmd, str, APR_ESCAPE_STRING, NULL);
148266733Speter        return cmd;
149266733Speter    }
150266733Speter    case APR_NOTFOUND: {
151266733Speter        break;
152266733Speter    }
153266733Speter    }
154266733Speter
155266733Speter    return str;
156266733Speter}
157266733Speter
158266733Speterstatic char x2c(const char *what)
159266733Speter{
160266733Speter    register char digit;
161266733Speter
162266733Speter#if !APR_CHARSET_EBCDIC
163266733Speter    digit =
164266733Speter            ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
165266733Speter    digit *= 16;
166266733Speter    digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
167266733Speter#else /*APR_CHARSET_EBCDIC*/
168266733Speter    char xstr[5];
169266733Speter    xstr[0]='0';
170266733Speter    xstr[1]='x';
171266733Speter    xstr[2]=what[0];
172266733Speter    xstr[3]=what[1];
173266733Speter    xstr[4]='\0';
174266733Speter    digit = convert_a2e[0xFF & strtol(xstr, NULL, 16)];
175266733Speter#endif /*APR_CHARSET_EBCDIC*/
176266733Speter    return (digit);
177266733Speter}
178266733Speter
179266733SpeterAPR_DECLARE(apr_status_t) apr_unescape_url(char *escaped, const char *url,
180266733Speter        apr_ssize_t slen, const char *forbid, const char *reserved, int plus,
181266733Speter        apr_size_t *len)
182266733Speter{
183266733Speter    apr_size_t size = 1;
184266733Speter    int found = 0;
185266733Speter    const char *s = (const char *) url;
186266733Speter    char *d = (char *) escaped;
187266733Speter    register int badesc, badpath;
188266733Speter
189266733Speter    if (!url) {
190266733Speter        return APR_NOTFOUND;
191266733Speter    }
192266733Speter
193266733Speter    badesc = 0;
194266733Speter    badpath = 0;
195266733Speter    if (s) {
196266733Speter        if (d) {
197266733Speter            for (; *s && slen; ++s, d++, slen--) {
198266733Speter                if (plus && *s == '+') {
199266733Speter                    *d = ' ';
200266733Speter                    found = 1;
201266733Speter                }
202266733Speter                else if (*s != '%') {
203266733Speter                    *d = *s;
204266733Speter                }
205266733Speter                else {
206266733Speter                    if (!apr_isxdigit(*(s + 1)) || !apr_isxdigit(*(s + 2))) {
207266733Speter                        badesc = 1;
208266733Speter                        *d = '%';
209266733Speter                    }
210266733Speter                    else {
211266733Speter                        char decoded;
212266733Speter                        decoded = x2c(s + 1);
213266733Speter                        if ((decoded == '\0')
214266733Speter                                || (forbid && strchr(forbid, decoded))) {
215266733Speter                            badpath = 1;
216266733Speter                            *d = decoded;
217266733Speter                            s += 2;
218266733Speter                            slen -= 2;
219266733Speter                        }
220266733Speter                        else if (reserved && strchr(reserved, decoded)) {
221266733Speter                            *d++ = *s++;
222266733Speter                            *d++ = *s++;
223266733Speter                            *d = *s;
224266733Speter                            size += 2;
225266733Speter                        }
226266733Speter                        else {
227266733Speter                            *d = decoded;
228266733Speter                            s += 2;
229266733Speter                            slen -= 2;
230266733Speter                            found = 1;
231266733Speter                        }
232266733Speter                    }
233266733Speter                }
234266733Speter                size++;
235266733Speter            }
236266733Speter            *d = '\0';
237266733Speter        }
238266733Speter        else {
239266733Speter            for (; *s && slen; ++s, slen--) {
240266733Speter                if (plus && *s == '+') {
241266733Speter                    found = 1;
242266733Speter                }
243266733Speter                else if (*s != '%') {
244266733Speter                    /* character unchanged */
245266733Speter                }
246266733Speter                else {
247266733Speter                    if (!apr_isxdigit(*(s + 1)) || !apr_isxdigit(*(s + 2))) {
248266733Speter                        badesc = 1;
249266733Speter                    }
250266733Speter                    else {
251266733Speter                        char decoded;
252266733Speter                        decoded = x2c(s + 1);
253266733Speter                        if ((decoded == '\0')
254266733Speter                                || (forbid && strchr(forbid, decoded))) {
255266733Speter                            badpath = 1;
256266733Speter                            s += 2;
257266733Speter                            slen -= 2;
258266733Speter                        }
259266733Speter                        else if (reserved && strchr(reserved, decoded)) {
260266733Speter                            s += 2;
261266733Speter                            slen -= 2;
262266733Speter                            size += 2;
263266733Speter                        }
264266733Speter                        else {
265266733Speter                            s += 2;
266266733Speter                            slen -= 2;
267266733Speter                            found = 1;
268266733Speter                        }
269266733Speter                    }
270266733Speter                }
271266733Speter                size++;
272266733Speter            }
273266733Speter        }
274266733Speter    }
275266733Speter
276266733Speter    if (len) {
277266733Speter        *len = size;
278266733Speter    }
279266733Speter    if (badesc) {
280266733Speter        return APR_EINVAL;
281266733Speter    }
282266733Speter    else if (badpath) {
283266733Speter        return APR_BADCH;
284266733Speter    }
285266733Speter    else if (!found) {
286266733Speter        return APR_NOTFOUND;
287266733Speter    }
288266733Speter
289266733Speter    return APR_SUCCESS;
290266733Speter}
291266733Speter
292266733SpeterAPR_DECLARE(const char *) apr_punescape_url(apr_pool_t *p, const char *url,
293266733Speter        const char *forbid, const char *reserved, int plus)
294266733Speter{
295266733Speter    apr_size_t len;
296266733Speter
297266733Speter    switch (apr_unescape_url(NULL, url, APR_ESCAPE_STRING, forbid, reserved,
298266733Speter            plus, &len)) {
299266733Speter    case APR_SUCCESS: {
300266733Speter        char *buf = apr_palloc(p, len);
301266733Speter        apr_unescape_url(buf, url, APR_ESCAPE_STRING, forbid, reserved, plus,
302266733Speter                NULL);
303266733Speter        return buf;
304266733Speter    }
305266733Speter    case APR_EINVAL:
306266733Speter    case APR_BADCH: {
307266733Speter        return NULL;
308266733Speter    }
309266733Speter    case APR_NOTFOUND: {
310266733Speter        break;
311266733Speter    }
312266733Speter    }
313266733Speter
314266733Speter    return url;
315266733Speter}
316266733Speter
317266733Speter/* c2x takes an unsigned, and expects the caller has guaranteed that
318266733Speter * 0 <= what < 256... which usually means that you have to cast to
319266733Speter * unsigned char first, because (unsigned)(char)(x) first goes through
320266733Speter * signed extension to an int before the unsigned cast.
321266733Speter *
322266733Speter * The reason for this assumption is to assist gcc code generation --
323266733Speter * the unsigned char -> unsigned extension is already done earlier in
324266733Speter * both uses of this code, so there's no need to waste time doing it
325266733Speter * again.
326266733Speter */
327266733Speterstatic const char c2x_table[] = "0123456789abcdef";
328266733Speter
329266733Speterstatic APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
330266733Speter        unsigned char *where)
331266733Speter{
332266733Speter#if APR_CHARSET_EBCDIC
333266733Speter    what = convert_e2a[(unsigned char)what];
334266733Speter#endif /*APR_CHARSET_EBCDIC*/
335266733Speter    *where++ = prefix;
336266733Speter    *where++ = c2x_table[what >> 4];
337266733Speter    *where++ = c2x_table[what & 0xf];
338266733Speter    return where;
339266733Speter}
340266733Speter
341266733SpeterAPR_DECLARE(apr_status_t) apr_escape_path_segment(char *escaped,
342266733Speter        const char *str, apr_ssize_t slen, apr_size_t *len)
343266733Speter{
344266733Speter    apr_size_t size = 1;
345266733Speter    int found = 0;
346266733Speter    const unsigned char *s = (const unsigned char *) str;
347266733Speter    unsigned char *d = (unsigned char *) escaped;
348266733Speter    unsigned c;
349266733Speter
350266733Speter    if (s) {
351266733Speter        if (d) {
352266733Speter            while ((c = *s) && slen) {
353266733Speter                if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
354266733Speter                    d = c2x(c, '%', d);
355266733Speter                    size += 2;
356266733Speter                    found = 1;
357266733Speter                }
358266733Speter                else {
359266733Speter                    *d++ = c;
360266733Speter                }
361266733Speter                ++s;
362266733Speter                size++;
363266733Speter                slen--;
364266733Speter            }
365266733Speter            *d = '\0';
366266733Speter        }
367266733Speter        else {
368266733Speter            while ((c = *s) && slen) {
369266733Speter                if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
370266733Speter                    size += 2;
371266733Speter                    found = 1;
372266733Speter                }
373266733Speter                ++s;
374266733Speter                size++;
375266733Speter                slen--;
376266733Speter            }
377266733Speter        }
378266733Speter    }
379266733Speter
380266733Speter    if (len) {
381266733Speter        *len = size;
382266733Speter    }
383266733Speter    if (!found) {
384266733Speter        return APR_NOTFOUND;
385266733Speter    }
386266733Speter
387266733Speter    return APR_SUCCESS;
388266733Speter}
389266733Speter
390266733SpeterAPR_DECLARE(const char *) apr_pescape_path_segment(apr_pool_t *p,
391266733Speter        const char *str)
392266733Speter{
393266733Speter    apr_size_t len;
394266733Speter
395266733Speter    switch (apr_escape_path_segment(NULL, str, APR_ESCAPE_STRING, &len)) {
396266733Speter    case APR_SUCCESS: {
397266733Speter        char *cmd = apr_palloc(p, len);
398266733Speter        apr_escape_path_segment(cmd, str, APR_ESCAPE_STRING, NULL);
399266733Speter        return cmd;
400266733Speter    }
401266733Speter    case APR_NOTFOUND: {
402266733Speter        break;
403266733Speter    }
404266733Speter    }
405266733Speter
406266733Speter    return str;
407266733Speter}
408266733Speter
409266733SpeterAPR_DECLARE(apr_status_t) apr_escape_path(char *escaped, const char *path,
410266733Speter        apr_ssize_t slen, int partial, apr_size_t *len)
411266733Speter{
412266733Speter    apr_size_t size = 1;
413266733Speter    int found = 0;
414266733Speter    const unsigned char *s = (const unsigned char *) path;
415266733Speter    unsigned char *d = (unsigned char *) escaped;
416266733Speter    unsigned c;
417266733Speter
418266733Speter    if (!path) {
419266733Speter        return APR_NOTFOUND;
420266733Speter    }
421266733Speter
422266733Speter    if (!partial) {
423266733Speter        const char *colon = strchr(path, ':');
424266733Speter        const char *slash = strchr(path, '/');
425266733Speter
426266733Speter        if (colon && (!slash || colon < slash)) {
427266733Speter            if (d) {
428266733Speter                *d++ = '.';
429266733Speter                *d++ = '/';
430266733Speter            }
431266733Speter            size += 2;
432266733Speter            found = 1;
433266733Speter        }
434266733Speter    }
435266733Speter    if (d) {
436266733Speter        while ((c = *s) && slen) {
437266733Speter            if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
438266733Speter                d = c2x(c, '%', d);
439266733Speter            }
440266733Speter            else {
441266733Speter                *d++ = c;
442266733Speter            }
443266733Speter            ++s;
444266733Speter            size++;
445266733Speter            slen--;
446266733Speter        }
447266733Speter        *d = '\0';
448266733Speter    }
449266733Speter    else {
450266733Speter        while ((c = *s) && slen) {
451266733Speter            if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
452266733Speter                size += 2;
453266733Speter                found = 1;
454266733Speter            }
455266733Speter            ++s;
456266733Speter            size++;
457266733Speter            slen--;
458266733Speter        }
459266733Speter    }
460266733Speter
461266733Speter    if (len) {
462266733Speter        *len = size;
463266733Speter    }
464266733Speter    if (!found) {
465266733Speter        return APR_NOTFOUND;
466266733Speter    }
467266733Speter
468266733Speter    return APR_SUCCESS;
469266733Speter}
470266733Speter
471266733SpeterAPR_DECLARE(const char *) apr_pescape_path(apr_pool_t *p, const char *str,
472266733Speter        int partial)
473266733Speter{
474266733Speter    apr_size_t len;
475266733Speter
476266733Speter    switch (apr_escape_path(NULL, str, APR_ESCAPE_STRING, partial, &len)) {
477266733Speter    case APR_SUCCESS: {
478266733Speter        char *path = apr_palloc(p, len);
479266733Speter        apr_escape_path(path, str, APR_ESCAPE_STRING, partial, NULL);
480266733Speter        return path;
481266733Speter    }
482266733Speter    case APR_NOTFOUND: {
483266733Speter        break;
484266733Speter    }
485266733Speter    }
486266733Speter
487266733Speter    return str;
488266733Speter}
489266733Speter
490266733SpeterAPR_DECLARE(apr_status_t) apr_escape_urlencoded(char *escaped, const char *str,
491266733Speter        apr_ssize_t slen, apr_size_t *len)
492266733Speter{
493266733Speter    apr_size_t size = 1;
494266733Speter    int found = 0;
495266733Speter    const unsigned char *s = (const unsigned char *) str;
496266733Speter    unsigned char *d = (unsigned char *) escaped;
497266733Speter    unsigned c;
498266733Speter
499266733Speter    if (s) {
500266733Speter        if (d) {
501266733Speter            while ((c = *s) && slen) {
502266733Speter                if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
503266733Speter                    d = c2x(c, '%', d);
504266733Speter                    size += 2;
505266733Speter                    found = 1;
506266733Speter                }
507266733Speter                else if (c == ' ') {
508266733Speter                    *d++ = '+';
509266733Speter                    found = 1;
510266733Speter                }
511266733Speter                else {
512266733Speter                    *d++ = c;
513266733Speter                }
514266733Speter                ++s;
515266733Speter                size++;
516266733Speter                slen--;
517266733Speter            }
518266733Speter            *d = '\0';
519266733Speter        }
520266733Speter        else {
521266733Speter            while ((c = *s) && slen) {
522266733Speter                if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
523266733Speter                    size += 2;
524266733Speter                    found = 1;
525266733Speter                }
526266733Speter                else if (c == ' ') {
527266733Speter                    found = 1;
528266733Speter                }
529266733Speter                ++s;
530266733Speter                size++;
531266733Speter                slen--;
532266733Speter            }
533266733Speter        }
534266733Speter    }
535266733Speter
536266733Speter    if (len) {
537266733Speter        *len = size;
538266733Speter    }
539266733Speter    if (!found) {
540266733Speter        return APR_NOTFOUND;
541266733Speter    }
542266733Speter
543266733Speter    return APR_SUCCESS;
544266733Speter}
545266733Speter
546266733SpeterAPR_DECLARE(const char *) apr_pescape_urlencoded(apr_pool_t *p, const char *str)
547266733Speter{
548266733Speter    apr_size_t len;
549266733Speter
550266733Speter    switch (apr_escape_urlencoded(NULL, str, APR_ESCAPE_STRING, &len)) {
551266733Speter    case APR_SUCCESS: {
552266733Speter        char *encoded = apr_palloc(p, len);
553266733Speter        apr_escape_urlencoded(encoded, str, APR_ESCAPE_STRING, NULL);
554266733Speter        return encoded;
555266733Speter    }
556266733Speter    case APR_NOTFOUND: {
557266733Speter        break;
558266733Speter    }
559266733Speter    }
560266733Speter
561266733Speter    return str;
562266733Speter}
563266733Speter
564266733SpeterAPR_DECLARE(apr_status_t) apr_escape_entity(char *escaped, const char *str,
565266733Speter        apr_ssize_t slen, int toasc, apr_size_t *len)
566266733Speter{
567266733Speter    apr_size_t size = 1;
568266733Speter    int found = 0;
569266733Speter    const unsigned char *s = (const unsigned char *) str;
570266733Speter    unsigned char *d = (unsigned char *) escaped;
571266733Speter    unsigned c;
572266733Speter
573266733Speter    if (s) {
574266733Speter        if (d) {
575266733Speter            while ((c = *s) && slen) {
576266733Speter                if (TEST_CHAR(c, T_ESCAPE_XML)) {
577266733Speter                    switch (c) {
578266733Speter                    case '>': {
579266733Speter                        memcpy(d, "&gt;", 4);
580266733Speter                        size += 4;
581266733Speter                        d += 4;
582266733Speter                        break;
583266733Speter                    }
584266733Speter                    case '<': {
585266733Speter                        memcpy(d, "&lt;", 4);
586266733Speter                        size += 4;
587266733Speter                        d += 4;
588266733Speter                        break;
589266733Speter                    }
590266733Speter                    case '&': {
591266733Speter                        memcpy(d, "&amp;", 5);
592266733Speter                        size += 5;
593266733Speter                        d += 5;
594266733Speter                        break;
595266733Speter                    }
596266733Speter                    case '\"': {
597266733Speter                        memcpy(d, "&quot;", 6);
598266733Speter                        size += 6;
599266733Speter                        d += 6;
600266733Speter                        break;
601266733Speter                    }
602266733Speter                    case '\'': {
603266733Speter                        memcpy(d, "&apos;", 6);
604266733Speter                        size += 6;
605266733Speter                        d += 6;
606266733Speter                        break;
607266733Speter                    }
608266733Speter                    }
609266733Speter                    found = 1;
610266733Speter                }
611266733Speter                else if (toasc && !apr_isascii(c)) {
612266733Speter                    int offset = apr_snprintf((char *) d, 6, "&#%3.3d;", c);
613266733Speter                    size += offset;
614266733Speter                    d += offset;
615266733Speter                    found = 1;
616266733Speter                }
617266733Speter                else {
618266733Speter                    *d++ = c;
619266733Speter                    size++;
620266733Speter                }
621266733Speter                ++s;
622266733Speter                slen--;
623266733Speter            }
624266733Speter            *d = '\0';
625266733Speter        }
626266733Speter        else {
627266733Speter            while ((c = *s) && slen) {
628266733Speter                if (TEST_CHAR(c, T_ESCAPE_XML)) {
629266733Speter                    switch (c) {
630266733Speter                    case '>': {
631266733Speter                        size += 4;
632266733Speter                        break;
633266733Speter                    }
634266733Speter                    case '<': {
635266733Speter                        size += 4;
636266733Speter                        break;
637266733Speter                    }
638266733Speter                    case '&': {
639266733Speter                        size += 5;
640266733Speter                        break;
641266733Speter                    }
642266733Speter                    case '\"': {
643266733Speter                        size += 6;
644266733Speter                        break;
645266733Speter                    }
646266733Speter                    case '\'': {
647266733Speter                        size += 6;
648266733Speter                        break;
649266733Speter                    }
650266733Speter                    }
651266733Speter                    found = 1;
652266733Speter                }
653266733Speter                else if (toasc && !apr_isascii(c)) {
654266733Speter                    char buf[8];
655266733Speter                    size += apr_snprintf(buf, 6, "&#%3.3d;", c);
656266733Speter                    found = 1;
657266733Speter                }
658266733Speter                else {
659266733Speter                    size++;
660266733Speter                }
661266733Speter                ++s;
662266733Speter                slen--;
663266733Speter            }
664266733Speter        }
665266733Speter    }
666266733Speter
667266733Speter    if (len) {
668266733Speter        *len = size;
669266733Speter    }
670266733Speter    if (!found) {
671266733Speter        return APR_NOTFOUND;
672266733Speter    }
673266733Speter
674266733Speter    return APR_SUCCESS;
675266733Speter}
676266733Speter
677266733SpeterAPR_DECLARE(const char *) apr_pescape_entity(apr_pool_t *p, const char *str,
678266733Speter        int toasc)
679266733Speter{
680266733Speter    apr_size_t len;
681266733Speter
682266733Speter    switch (apr_escape_entity(NULL, str, APR_ESCAPE_STRING, toasc, &len)) {
683266733Speter    case APR_SUCCESS: {
684266733Speter        char *cmd = apr_palloc(p, len);
685266733Speter        apr_escape_entity(cmd, str, APR_ESCAPE_STRING, toasc, NULL);
686266733Speter        return cmd;
687266733Speter    }
688266733Speter    case APR_NOTFOUND: {
689266733Speter        break;
690266733Speter    }
691266733Speter    }
692266733Speter
693266733Speter    return str;
694266733Speter}
695266733Speter
696266733Speter/* maximum length of any ISO-LATIN-1 HTML entity name. */
697266733Speter#define MAXENTLEN (6)
698266733Speter
699266733SpeterAPR_DECLARE(apr_status_t) apr_unescape_entity(char *unescaped, const char *str,
700266733Speter        apr_ssize_t slen, apr_size_t *len)
701266733Speter{
702266733Speter    int found = 0;
703266733Speter    apr_size_t size = 1;
704266733Speter    int val, i, j;
705266733Speter    char *d = unescaped;
706266733Speter    const char *s = str;
707266733Speter    const char *ents;
708266733Speter    static const char * const entlist[MAXENTLEN + 1] =
709266733Speter    {
710266733Speter            NULL, /* 0 */
711266733Speter            NULL, /* 1 */
712266733Speter            "lt\074gt\076", /* 2 */
713266733Speter            "amp\046ETH\320eth\360", /* 3 */
714266733Speter            "quot\042Auml\304Euml\313Iuml\317Ouml\326Uuml\334auml\344euml"
715266733Speter            "\353iuml\357ouml\366uuml\374yuml\377", /* 4 */
716266733Speter            "Acirc\302Aring\305AElig\306Ecirc\312Icirc\316Ocirc\324Ucirc"
717266733Speter            "\333THORN\336szlig\337acirc\342aring\345aelig\346ecirc\352"
718266733Speter            "icirc\356ocirc\364ucirc\373thorn\376", /* 5 */
719266733Speter            "Agrave\300Aacute\301Atilde\303Ccedil\307Egrave\310Eacute\311"
720266733Speter            "Igrave\314Iacute\315Ntilde\321Ograve\322Oacute\323Otilde"
721266733Speter            "\325Oslash\330Ugrave\331Uacute\332Yacute\335agrave\340"
722266733Speter            "aacute\341atilde\343ccedil\347egrave\350eacute\351igrave"
723266733Speter            "\354iacute\355ntilde\361ograve\362oacute\363otilde\365"
724266733Speter            "oslash\370ugrave\371uacute\372yacute\375" /* 6 */
725266733Speter    };
726266733Speter
727266733Speter    if (s) {
728266733Speter        if (d) {
729266733Speter            for (; *s != '\0' && slen; s++, d++, size++, slen--) {
730266733Speter                if (*s != '&') {
731266733Speter                    *d = *s;
732266733Speter                    continue;
733266733Speter                }
734266733Speter                /* find end of entity */
735266733Speter                for (i = 1; s[i] != ';' && s[i] != '\0' && (slen - i) != 0;
736266733Speter                        i++) {
737266733Speter                    continue;
738266733Speter                }
739266733Speter
740266733Speter                if (s[i] == '\0' || (slen - i) == 0) { /* treat as normal data */
741266733Speter                    *d = *s;
742266733Speter                    continue;
743266733Speter                }
744266733Speter
745266733Speter                /* is it numeric ? */
746266733Speter                if (s[1] == '#') {
747266733Speter                    for (j = 2, val = 0; j < i && apr_isdigit(s[j]); j++) {
748266733Speter                        val = val * 10 + s[j] - '0';
749266733Speter                    }
750266733Speter                    s += i;
751266733Speter                    if (j < i || val <= 8 || (val >= 11 && val <= 31)
752266733Speter                            || (val >= 127 && val <= 160) || val >= 256) {
753266733Speter                        d--; /* no data to output */
754266733Speter                        size--;
755266733Speter                    }
756266733Speter                    else {
757266733Speter                        *d = RAW_ASCII_CHAR(val);
758266733Speter                        found = 1;
759266733Speter                    }
760266733Speter                }
761266733Speter                else {
762266733Speter                    j = i - 1;
763266733Speter                    if (j > MAXENTLEN || entlist[j] == NULL) {
764266733Speter                        /* wrong length */
765266733Speter                        *d = '&';
766266733Speter                        continue; /* skip it */
767266733Speter                    }
768266733Speter                    for (ents = entlist[j]; *ents != '\0'; ents += i) {
769266733Speter                        if (strncmp(s + 1, ents, j) == 0) {
770266733Speter                            break;
771266733Speter                        }
772266733Speter                    }
773266733Speter
774266733Speter                    if (*ents == '\0') {
775266733Speter                        *d = '&'; /* unknown */
776266733Speter                    }
777266733Speter                    else {
778266733Speter                        *d = RAW_ASCII_CHAR(((const unsigned char *) ents)[j]);
779266733Speter                        s += i;
780266733Speter                        slen -= i;
781266733Speter                        found = 1;
782266733Speter                    }
783266733Speter                }
784266733Speter            }
785266733Speter            *d = '\0';
786266733Speter        }
787266733Speter        else {
788266733Speter            for (; *s != '\0' && slen; s++, size++, slen--) {
789266733Speter                if (*s != '&') {
790266733Speter                    continue;
791266733Speter                }
792266733Speter                /* find end of entity */
793266733Speter                for (i = 1; s[i] != ';' && s[i] != '\0' && (slen - i) != 0;
794266733Speter                        i++) {
795266733Speter                    continue;
796266733Speter                }
797266733Speter
798266733Speter                if (s[i] == '\0' || (slen - i) == 0) { /* treat as normal data */
799266733Speter                    continue;
800266733Speter                }
801266733Speter
802266733Speter                /* is it numeric ? */
803266733Speter                if (s[1] == '#') {
804266733Speter                    for (j = 2, val = 0; j < i && apr_isdigit(s[j]); j++) {
805266733Speter                        val = val * 10 + s[j] - '0';
806266733Speter                    }
807266733Speter                    s += i;
808266733Speter                    if (j < i || val <= 8 || (val >= 11 && val <= 31)
809266733Speter                            || (val >= 127 && val <= 160) || val >= 256) {
810266733Speter                        /* no data to output */
811266733Speter                        size--;
812266733Speter                    }
813266733Speter                    else {
814266733Speter                        found = 1;
815266733Speter                    }
816266733Speter                }
817266733Speter                else {
818266733Speter                    j = i - 1;
819266733Speter                    if (j > MAXENTLEN || entlist[j] == NULL) {
820266733Speter                        /* wrong length */
821266733Speter                        continue; /* skip it */
822266733Speter                    }
823266733Speter                    for (ents = entlist[j]; *ents != '\0'; ents += i) {
824266733Speter                        if (strncmp(s + 1, ents, j) == 0) {
825266733Speter                            break;
826266733Speter                        }
827266733Speter                    }
828266733Speter
829266733Speter                    if (*ents == '\0') {
830266733Speter                        /* unknown */
831266733Speter                    }
832266733Speter                    else {
833266733Speter                        s += i;
834266733Speter                        slen -= i;
835266733Speter                        found = 1;
836266733Speter                    }
837266733Speter                }
838266733Speter            }
839266733Speter        }
840266733Speter    }
841266733Speter
842266733Speter    if (len) {
843266733Speter        *len = size;
844266733Speter    }
845266733Speter    if (!found) {
846266733Speter        return APR_NOTFOUND;
847266733Speter    }
848266733Speter
849266733Speter    return APR_SUCCESS;
850266733Speter}
851266733Speter
852266733SpeterAPR_DECLARE(const char *) apr_punescape_entity(apr_pool_t *p, const char *str)
853266733Speter{
854266733Speter    apr_size_t len;
855266733Speter
856266733Speter    switch (apr_unescape_entity(NULL, str, APR_ESCAPE_STRING, &len)) {
857266733Speter    case APR_SUCCESS: {
858266733Speter        char *cmd = apr_palloc(p, len);
859266733Speter        apr_unescape_entity(cmd, str, APR_ESCAPE_STRING, NULL);
860266733Speter        return cmd;
861266733Speter    }
862266733Speter    case APR_NOTFOUND: {
863266733Speter        break;
864266733Speter    }
865266733Speter    }
866266733Speter
867266733Speter    return str;
868266733Speter}
869266733Speter
870266733SpeterAPR_DECLARE(apr_status_t) apr_escape_echo(char *escaped, const char *str,
871266733Speter        apr_ssize_t slen, int quote, apr_size_t *len)
872266733Speter{
873266733Speter    apr_size_t size = 1;
874266733Speter    int found = 0;
875266733Speter    const unsigned char *s = (const unsigned char *) str;
876266733Speter    unsigned char *d = (unsigned char *) escaped;
877266733Speter    unsigned c;
878266733Speter
879266733Speter    if (s) {
880266733Speter        if (d) {
881266733Speter            while ((c = *s) && slen) {
882266733Speter                if (TEST_CHAR(c, T_ESCAPE_ECHO)) {
883266733Speter                    *d++ = '\\';
884266733Speter                    size++;
885266733Speter                    switch (c) {
886266733Speter                    case '\a':
887266733Speter                        *d++ = 'a';
888266733Speter                        size++;
889266733Speter                        found = 1;
890266733Speter                        break;
891266733Speter                    case '\b':
892266733Speter                        *d++ = 'b';
893266733Speter                        size++;
894266733Speter                        found = 1;
895266733Speter                        break;
896266733Speter                    case '\f':
897266733Speter                        *d++ = 'f';
898266733Speter                        size++;
899266733Speter                        found = 1;
900266733Speter                        break;
901266733Speter                    case '\n':
902266733Speter                        *d++ = 'n';
903266733Speter                        size++;
904266733Speter                        found = 1;
905266733Speter                        break;
906266733Speter                    case '\r':
907266733Speter                        *d++ = 'r';
908266733Speter                        size++;
909266733Speter                        found = 1;
910266733Speter                        break;
911266733Speter                    case '\t':
912266733Speter                        *d++ = 't';
913266733Speter                        size++;
914266733Speter                        found = 1;
915266733Speter                        break;
916266733Speter                    case '\v':
917266733Speter                        *d++ = 'v';
918266733Speter                        size++;
919266733Speter                        found = 1;
920266733Speter                        break;
921266733Speter                    case '\\':
922266733Speter                        *d++ = '\\';
923266733Speter                        size++;
924266733Speter                        found = 1;
925266733Speter                        break;
926266733Speter                    case '"':
927266733Speter                        if (quote) {
928266733Speter                            *d++ = c;
929266733Speter                            size++;
930266733Speter                            found = 1;
931266733Speter                        }
932266733Speter                        else {
933266733Speter                            d[-1] = c;
934266733Speter                        }
935266733Speter                        break;
936266733Speter                    default:
937266733Speter                        c2x(c, 'x', d);
938266733Speter                        d += 3;
939266733Speter                        size += 3;
940266733Speter                        found = 1;
941266733Speter                        break;
942266733Speter                    }
943266733Speter                }
944266733Speter                else {
945266733Speter                    *d++ = c;
946266733Speter                    size++;
947266733Speter                }
948266733Speter                ++s;
949266733Speter                slen--;
950266733Speter            }
951266733Speter            *d = '\0';
952266733Speter        }
953266733Speter        else {
954266733Speter            while ((c = *s) && slen) {
955266733Speter                if (TEST_CHAR(c, T_ESCAPE_ECHO)) {
956266733Speter                    size++;
957266733Speter                    switch (c) {
958266733Speter                    case '\a':
959266733Speter                    case '\b':
960266733Speter                    case '\f':
961266733Speter                    case '\n':
962266733Speter                    case '\r':
963266733Speter                    case '\t':
964266733Speter                    case '\v':
965266733Speter                    case '\\':
966266733Speter                        size++;
967266733Speter                        found = 1;
968266733Speter                        break;
969266733Speter                    case '"':
970266733Speter                        if (quote) {
971266733Speter                            size++;
972266733Speter                            found = 1;
973266733Speter                        }
974266733Speter                        break;
975266733Speter                    default:
976266733Speter                        size += 3;
977266733Speter                        found = 1;
978266733Speter                        break;
979266733Speter                    }
980266733Speter                }
981266733Speter                else {
982266733Speter                    size++;
983266733Speter                }
984266733Speter                ++s;
985266733Speter                slen--;
986266733Speter            }
987266733Speter        }
988266733Speter    }
989266733Speter
990266733Speter    if (len) {
991266733Speter        *len = size;
992266733Speter    }
993266733Speter    if (!found) {
994266733Speter        return APR_NOTFOUND;
995266733Speter    }
996266733Speter
997266733Speter    return APR_SUCCESS;
998266733Speter}
999266733Speter
1000266733SpeterAPR_DECLARE(const char *) apr_pescape_echo(apr_pool_t *p, const char *str,
1001266733Speter        int quote)
1002266733Speter{
1003266733Speter    apr_size_t len;
1004266733Speter
1005266733Speter    switch (apr_escape_echo(NULL, str, APR_ESCAPE_STRING, quote, &len)) {
1006266733Speter    case APR_SUCCESS: {
1007266733Speter        char *cmd = apr_palloc(p, len);
1008266733Speter        apr_escape_echo(cmd, str, APR_ESCAPE_STRING, quote, NULL);
1009266733Speter        return cmd;
1010266733Speter    }
1011266733Speter    case APR_NOTFOUND: {
1012266733Speter        break;
1013266733Speter    }
1014266733Speter    }
1015266733Speter
1016266733Speter    return str;
1017266733Speter}
1018266733Speter
1019266733SpeterAPR_DECLARE(apr_status_t) apr_escape_hex(char *dest, const void *src,
1020266733Speter        apr_size_t srclen, int colon, apr_size_t *len)
1021266733Speter{
1022266733Speter    const unsigned char *in = src;
1023266733Speter    apr_size_t size;
1024266733Speter
1025266733Speter    if (!src) {
1026266733Speter        return APR_NOTFOUND;
1027266733Speter    }
1028266733Speter
1029266733Speter    if (dest) {
1030266733Speter        for (size = 0; size < srclen; size++) {
1031266733Speter            if (colon && size) {
1032266733Speter                *dest++ = ':';
1033266733Speter            }
1034266733Speter            *dest++ = c2x_table[in[size] >> 4];
1035266733Speter            *dest++ = c2x_table[in[size] & 0xf];
1036266733Speter        }
1037266733Speter        *dest = '\0';
1038266733Speter    }
1039266733Speter
1040266733Speter    if (len) {
1041266733Speter        if (colon && srclen) {
1042266733Speter            *len = srclen * 3;
1043266733Speter        }
1044266733Speter        else {
1045266733Speter            *len = srclen * 2 + 1;
1046266733Speter        }
1047266733Speter    }
1048266733Speter
1049266733Speter    return APR_SUCCESS;
1050266733Speter}
1051266733Speter
1052266733SpeterAPR_DECLARE(const char *) apr_pescape_hex(apr_pool_t *p, const void *src,
1053266733Speter        apr_size_t srclen, int colon)
1054266733Speter{
1055266733Speter    apr_size_t len;
1056266733Speter
1057266733Speter    switch (apr_escape_hex(NULL, src, srclen, colon, &len)) {
1058266733Speter    case APR_SUCCESS: {
1059266733Speter        char *cmd = apr_palloc(p, len);
1060266733Speter        apr_escape_hex(cmd, src, srclen, colon, NULL);
1061266733Speter        return cmd;
1062266733Speter    }
1063266733Speter    case APR_NOTFOUND: {
1064266733Speter        break;
1065266733Speter    }
1066266733Speter    }
1067266733Speter
1068266733Speter    return src;
1069266733Speter}
1070266733Speter
1071266733SpeterAPR_DECLARE(apr_status_t) apr_unescape_hex(void *dest, const char *str,
1072266733Speter        apr_ssize_t slen, int colon, apr_size_t *len)
1073266733Speter{
1074266733Speter    apr_size_t size = 0;
1075266733Speter    int flip = 0;
1076266733Speter    const unsigned char *s = (const unsigned char *) str;
1077266733Speter    unsigned char *d = (unsigned char *) dest;
1078266733Speter    unsigned c;
1079266733Speter    unsigned char u = 0;
1080266733Speter
1081266733Speter    if (s) {
1082266733Speter        if (d) {
1083266733Speter            while ((c = *s) && slen) {
1084266733Speter
1085266733Speter                if (!flip) {
1086266733Speter                    u = 0;
1087266733Speter                }
1088266733Speter
1089266733Speter                if (colon && c == ':' && !flip) {
1090266733Speter                    ++s;
1091266733Speter                    slen--;
1092266733Speter                    continue;
1093266733Speter                }
1094266733Speter                else if (apr_isdigit(c)) {
1095266733Speter                    u |= c - '0';
1096266733Speter                }
1097266733Speter                else if (apr_isupper(c) && c <= 'F') {
1098266733Speter                    u |= c - ('A' - 10);
1099266733Speter                }
1100266733Speter                else if (apr_islower(c) && c <= 'f') {
1101266733Speter                    u |= c - ('a' - 10);
1102266733Speter                }
1103266733Speter                else {
1104266733Speter                    return APR_BADCH;
1105266733Speter                }
1106266733Speter
1107266733Speter                if (flip) {
1108266733Speter                    *d++ = u;
1109266733Speter                    size++;
1110266733Speter                }
1111266733Speter                else {
1112266733Speter                    u <<= 4;
1113266733Speter                    *d = u;
1114266733Speter                }
1115266733Speter                flip = !flip;
1116266733Speter
1117266733Speter                ++s;
1118266733Speter                slen--;
1119266733Speter            }
1120266733Speter        }
1121266733Speter        else {
1122266733Speter            while ((c = *s) && slen) {
1123266733Speter
1124266733Speter                if (colon && c == ':' && !flip) {
1125266733Speter                    ++s;
1126266733Speter                    slen--;
1127266733Speter                    continue;
1128266733Speter                }
1129266733Speter                else if (apr_isdigit(c)) {
1130266733Speter                    /* valid */
1131266733Speter                }
1132266733Speter                else if (apr_isupper(c) && c <= 'F') {
1133266733Speter                    /* valid */
1134266733Speter                }
1135266733Speter                else if (apr_islower(c) && c <= 'f') {
1136266733Speter                    /* valid */
1137266733Speter                }
1138266733Speter                else {
1139266733Speter                    return APR_BADCH;
1140266733Speter                }
1141266733Speter
1142266733Speter                if (flip) {
1143266733Speter                    size++;
1144266733Speter                }
1145266733Speter                flip = !flip;
1146266733Speter
1147266733Speter                ++s;
1148266733Speter                slen--;
1149266733Speter            }
1150266733Speter        }
1151266733Speter    }
1152266733Speter
1153266733Speter    if (len) {
1154266733Speter        *len = size;
1155266733Speter    }
1156266733Speter    if (!s) {
1157266733Speter        return APR_NOTFOUND;
1158266733Speter    }
1159266733Speter
1160266733Speter    return APR_SUCCESS;
1161266733Speter}
1162266733Speter
1163266733SpeterAPR_DECLARE(const void *) apr_punescape_hex(apr_pool_t *p, const char *str,
1164266733Speter        int colon, apr_size_t *len)
1165266733Speter{
1166266733Speter    apr_size_t size;
1167266733Speter
1168266733Speter    switch (apr_unescape_hex(NULL, str, APR_ESCAPE_STRING, colon, &size)) {
1169266733Speter    case APR_SUCCESS: {
1170266733Speter        void *cmd = apr_palloc(p, size);
1171266733Speter        apr_unescape_hex(cmd, str, APR_ESCAPE_STRING, colon, len);
1172266733Speter        return cmd;
1173266733Speter    }
1174266733Speter    case APR_BADCH:
1175266733Speter    case APR_NOTFOUND: {
1176266733Speter        break;
1177266733Speter    }
1178266733Speter    }
1179266733Speter
1180266733Speter    return NULL;
1181266733Speter}
1182