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);
439286503Speter                size += 2;
440286503Speter                found = 1;
441266733Speter            }
442266733Speter            else {
443266733Speter                *d++ = c;
444266733Speter            }
445266733Speter            ++s;
446266733Speter            size++;
447266733Speter            slen--;
448266733Speter        }
449266733Speter        *d = '\0';
450266733Speter    }
451266733Speter    else {
452266733Speter        while ((c = *s) && slen) {
453266733Speter            if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
454266733Speter                size += 2;
455266733Speter                found = 1;
456266733Speter            }
457266733Speter            ++s;
458266733Speter            size++;
459266733Speter            slen--;
460266733Speter        }
461266733Speter    }
462266733Speter
463266733Speter    if (len) {
464266733Speter        *len = size;
465266733Speter    }
466266733Speter    if (!found) {
467266733Speter        return APR_NOTFOUND;
468266733Speter    }
469266733Speter
470266733Speter    return APR_SUCCESS;
471266733Speter}
472266733Speter
473266733SpeterAPR_DECLARE(const char *) apr_pescape_path(apr_pool_t *p, const char *str,
474266733Speter        int partial)
475266733Speter{
476266733Speter    apr_size_t len;
477266733Speter
478266733Speter    switch (apr_escape_path(NULL, str, APR_ESCAPE_STRING, partial, &len)) {
479266733Speter    case APR_SUCCESS: {
480266733Speter        char *path = apr_palloc(p, len);
481266733Speter        apr_escape_path(path, str, APR_ESCAPE_STRING, partial, NULL);
482266733Speter        return path;
483266733Speter    }
484266733Speter    case APR_NOTFOUND: {
485266733Speter        break;
486266733Speter    }
487266733Speter    }
488266733Speter
489266733Speter    return str;
490266733Speter}
491266733Speter
492266733SpeterAPR_DECLARE(apr_status_t) apr_escape_urlencoded(char *escaped, const char *str,
493266733Speter        apr_ssize_t slen, apr_size_t *len)
494266733Speter{
495266733Speter    apr_size_t size = 1;
496266733Speter    int found = 0;
497266733Speter    const unsigned char *s = (const unsigned char *) str;
498266733Speter    unsigned char *d = (unsigned char *) escaped;
499266733Speter    unsigned c;
500266733Speter
501266733Speter    if (s) {
502266733Speter        if (d) {
503266733Speter            while ((c = *s) && slen) {
504266733Speter                if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
505266733Speter                    d = c2x(c, '%', d);
506266733Speter                    size += 2;
507266733Speter                    found = 1;
508266733Speter                }
509266733Speter                else if (c == ' ') {
510266733Speter                    *d++ = '+';
511266733Speter                    found = 1;
512266733Speter                }
513266733Speter                else {
514266733Speter                    *d++ = c;
515266733Speter                }
516266733Speter                ++s;
517266733Speter                size++;
518266733Speter                slen--;
519266733Speter            }
520266733Speter            *d = '\0';
521266733Speter        }
522266733Speter        else {
523266733Speter            while ((c = *s) && slen) {
524266733Speter                if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
525266733Speter                    size += 2;
526266733Speter                    found = 1;
527266733Speter                }
528266733Speter                else if (c == ' ') {
529266733Speter                    found = 1;
530266733Speter                }
531266733Speter                ++s;
532266733Speter                size++;
533266733Speter                slen--;
534266733Speter            }
535266733Speter        }
536266733Speter    }
537266733Speter
538266733Speter    if (len) {
539266733Speter        *len = size;
540266733Speter    }
541266733Speter    if (!found) {
542266733Speter        return APR_NOTFOUND;
543266733Speter    }
544266733Speter
545266733Speter    return APR_SUCCESS;
546266733Speter}
547266733Speter
548266733SpeterAPR_DECLARE(const char *) apr_pescape_urlencoded(apr_pool_t *p, const char *str)
549266733Speter{
550266733Speter    apr_size_t len;
551266733Speter
552266733Speter    switch (apr_escape_urlencoded(NULL, str, APR_ESCAPE_STRING, &len)) {
553266733Speter    case APR_SUCCESS: {
554266733Speter        char *encoded = apr_palloc(p, len);
555266733Speter        apr_escape_urlencoded(encoded, str, APR_ESCAPE_STRING, NULL);
556266733Speter        return encoded;
557266733Speter    }
558266733Speter    case APR_NOTFOUND: {
559266733Speter        break;
560266733Speter    }
561266733Speter    }
562266733Speter
563266733Speter    return str;
564266733Speter}
565266733Speter
566266733SpeterAPR_DECLARE(apr_status_t) apr_escape_entity(char *escaped, const char *str,
567266733Speter        apr_ssize_t slen, int toasc, apr_size_t *len)
568266733Speter{
569266733Speter    apr_size_t size = 1;
570266733Speter    int found = 0;
571266733Speter    const unsigned char *s = (const unsigned char *) str;
572266733Speter    unsigned char *d = (unsigned char *) escaped;
573266733Speter    unsigned c;
574266733Speter
575266733Speter    if (s) {
576266733Speter        if (d) {
577266733Speter            while ((c = *s) && slen) {
578266733Speter                if (TEST_CHAR(c, T_ESCAPE_XML)) {
579266733Speter                    switch (c) {
580266733Speter                    case '>': {
581266733Speter                        memcpy(d, "&gt;", 4);
582266733Speter                        size += 4;
583266733Speter                        d += 4;
584266733Speter                        break;
585266733Speter                    }
586266733Speter                    case '<': {
587266733Speter                        memcpy(d, "&lt;", 4);
588266733Speter                        size += 4;
589266733Speter                        d += 4;
590266733Speter                        break;
591266733Speter                    }
592266733Speter                    case '&': {
593266733Speter                        memcpy(d, "&amp;", 5);
594266733Speter                        size += 5;
595266733Speter                        d += 5;
596266733Speter                        break;
597266733Speter                    }
598266733Speter                    case '\"': {
599266733Speter                        memcpy(d, "&quot;", 6);
600266733Speter                        size += 6;
601266733Speter                        d += 6;
602266733Speter                        break;
603266733Speter                    }
604266733Speter                    case '\'': {
605266733Speter                        memcpy(d, "&apos;", 6);
606266733Speter                        size += 6;
607266733Speter                        d += 6;
608266733Speter                        break;
609266733Speter                    }
610266733Speter                    }
611266733Speter                    found = 1;
612266733Speter                }
613266733Speter                else if (toasc && !apr_isascii(c)) {
614266733Speter                    int offset = apr_snprintf((char *) d, 6, "&#%3.3d;", c);
615266733Speter                    size += offset;
616266733Speter                    d += offset;
617266733Speter                    found = 1;
618266733Speter                }
619266733Speter                else {
620266733Speter                    *d++ = c;
621266733Speter                    size++;
622266733Speter                }
623266733Speter                ++s;
624266733Speter                slen--;
625266733Speter            }
626266733Speter            *d = '\0';
627266733Speter        }
628266733Speter        else {
629266733Speter            while ((c = *s) && slen) {
630266733Speter                if (TEST_CHAR(c, T_ESCAPE_XML)) {
631266733Speter                    switch (c) {
632266733Speter                    case '>': {
633266733Speter                        size += 4;
634266733Speter                        break;
635266733Speter                    }
636266733Speter                    case '<': {
637266733Speter                        size += 4;
638266733Speter                        break;
639266733Speter                    }
640266733Speter                    case '&': {
641266733Speter                        size += 5;
642266733Speter                        break;
643266733Speter                    }
644266733Speter                    case '\"': {
645266733Speter                        size += 6;
646266733Speter                        break;
647266733Speter                    }
648266733Speter                    case '\'': {
649266733Speter                        size += 6;
650266733Speter                        break;
651266733Speter                    }
652266733Speter                    }
653266733Speter                    found = 1;
654266733Speter                }
655266733Speter                else if (toasc && !apr_isascii(c)) {
656266733Speter                    char buf[8];
657266733Speter                    size += apr_snprintf(buf, 6, "&#%3.3d;", c);
658266733Speter                    found = 1;
659266733Speter                }
660266733Speter                else {
661266733Speter                    size++;
662266733Speter                }
663266733Speter                ++s;
664266733Speter                slen--;
665266733Speter            }
666266733Speter        }
667266733Speter    }
668266733Speter
669266733Speter    if (len) {
670266733Speter        *len = size;
671266733Speter    }
672266733Speter    if (!found) {
673266733Speter        return APR_NOTFOUND;
674266733Speter    }
675266733Speter
676266733Speter    return APR_SUCCESS;
677266733Speter}
678266733Speter
679266733SpeterAPR_DECLARE(const char *) apr_pescape_entity(apr_pool_t *p, const char *str,
680266733Speter        int toasc)
681266733Speter{
682266733Speter    apr_size_t len;
683266733Speter
684266733Speter    switch (apr_escape_entity(NULL, str, APR_ESCAPE_STRING, toasc, &len)) {
685266733Speter    case APR_SUCCESS: {
686266733Speter        char *cmd = apr_palloc(p, len);
687266733Speter        apr_escape_entity(cmd, str, APR_ESCAPE_STRING, toasc, NULL);
688266733Speter        return cmd;
689266733Speter    }
690266733Speter    case APR_NOTFOUND: {
691266733Speter        break;
692266733Speter    }
693266733Speter    }
694266733Speter
695266733Speter    return str;
696266733Speter}
697266733Speter
698266733Speter/* maximum length of any ISO-LATIN-1 HTML entity name. */
699266733Speter#define MAXENTLEN (6)
700266733Speter
701266733SpeterAPR_DECLARE(apr_status_t) apr_unescape_entity(char *unescaped, const char *str,
702266733Speter        apr_ssize_t slen, apr_size_t *len)
703266733Speter{
704266733Speter    int found = 0;
705266733Speter    apr_size_t size = 1;
706266733Speter    int val, i, j;
707266733Speter    char *d = unescaped;
708266733Speter    const char *s = str;
709266733Speter    const char *ents;
710266733Speter    static const char * const entlist[MAXENTLEN + 1] =
711266733Speter    {
712266733Speter            NULL, /* 0 */
713266733Speter            NULL, /* 1 */
714266733Speter            "lt\074gt\076", /* 2 */
715266733Speter            "amp\046ETH\320eth\360", /* 3 */
716266733Speter            "quot\042Auml\304Euml\313Iuml\317Ouml\326Uuml\334auml\344euml"
717266733Speter            "\353iuml\357ouml\366uuml\374yuml\377", /* 4 */
718266733Speter            "Acirc\302Aring\305AElig\306Ecirc\312Icirc\316Ocirc\324Ucirc"
719266733Speter            "\333THORN\336szlig\337acirc\342aring\345aelig\346ecirc\352"
720266733Speter            "icirc\356ocirc\364ucirc\373thorn\376", /* 5 */
721266733Speter            "Agrave\300Aacute\301Atilde\303Ccedil\307Egrave\310Eacute\311"
722266733Speter            "Igrave\314Iacute\315Ntilde\321Ograve\322Oacute\323Otilde"
723266733Speter            "\325Oslash\330Ugrave\331Uacute\332Yacute\335agrave\340"
724266733Speter            "aacute\341atilde\343ccedil\347egrave\350eacute\351igrave"
725266733Speter            "\354iacute\355ntilde\361ograve\362oacute\363otilde\365"
726266733Speter            "oslash\370ugrave\371uacute\372yacute\375" /* 6 */
727266733Speter    };
728266733Speter
729266733Speter    if (s) {
730266733Speter        if (d) {
731266733Speter            for (; *s != '\0' && slen; s++, d++, size++, slen--) {
732266733Speter                if (*s != '&') {
733266733Speter                    *d = *s;
734266733Speter                    continue;
735266733Speter                }
736266733Speter                /* find end of entity */
737266733Speter                for (i = 1; s[i] != ';' && s[i] != '\0' && (slen - i) != 0;
738266733Speter                        i++) {
739266733Speter                    continue;
740266733Speter                }
741266733Speter
742266733Speter                if (s[i] == '\0' || (slen - i) == 0) { /* treat as normal data */
743266733Speter                    *d = *s;
744266733Speter                    continue;
745266733Speter                }
746266733Speter
747266733Speter                /* is it numeric ? */
748266733Speter                if (s[1] == '#') {
749266733Speter                    for (j = 2, val = 0; j < i && apr_isdigit(s[j]); j++) {
750266733Speter                        val = val * 10 + s[j] - '0';
751266733Speter                    }
752266733Speter                    s += i;
753266733Speter                    if (j < i || val <= 8 || (val >= 11 && val <= 31)
754266733Speter                            || (val >= 127 && val <= 160) || val >= 256) {
755266733Speter                        d--; /* no data to output */
756266733Speter                        size--;
757266733Speter                    }
758266733Speter                    else {
759266733Speter                        *d = RAW_ASCII_CHAR(val);
760266733Speter                        found = 1;
761266733Speter                    }
762266733Speter                }
763266733Speter                else {
764266733Speter                    j = i - 1;
765266733Speter                    if (j > MAXENTLEN || entlist[j] == NULL) {
766266733Speter                        /* wrong length */
767266733Speter                        *d = '&';
768266733Speter                        continue; /* skip it */
769266733Speter                    }
770266733Speter                    for (ents = entlist[j]; *ents != '\0'; ents += i) {
771266733Speter                        if (strncmp(s + 1, ents, j) == 0) {
772266733Speter                            break;
773266733Speter                        }
774266733Speter                    }
775266733Speter
776266733Speter                    if (*ents == '\0') {
777266733Speter                        *d = '&'; /* unknown */
778266733Speter                    }
779266733Speter                    else {
780266733Speter                        *d = RAW_ASCII_CHAR(((const unsigned char *) ents)[j]);
781266733Speter                        s += i;
782266733Speter                        slen -= i;
783266733Speter                        found = 1;
784266733Speter                    }
785266733Speter                }
786266733Speter            }
787266733Speter            *d = '\0';
788266733Speter        }
789266733Speter        else {
790266733Speter            for (; *s != '\0' && slen; s++, size++, slen--) {
791266733Speter                if (*s != '&') {
792266733Speter                    continue;
793266733Speter                }
794266733Speter                /* find end of entity */
795266733Speter                for (i = 1; s[i] != ';' && s[i] != '\0' && (slen - i) != 0;
796266733Speter                        i++) {
797266733Speter                    continue;
798266733Speter                }
799266733Speter
800266733Speter                if (s[i] == '\0' || (slen - i) == 0) { /* treat as normal data */
801266733Speter                    continue;
802266733Speter                }
803266733Speter
804266733Speter                /* is it numeric ? */
805266733Speter                if (s[1] == '#') {
806266733Speter                    for (j = 2, val = 0; j < i && apr_isdigit(s[j]); j++) {
807266733Speter                        val = val * 10 + s[j] - '0';
808266733Speter                    }
809266733Speter                    s += i;
810266733Speter                    if (j < i || val <= 8 || (val >= 11 && val <= 31)
811266733Speter                            || (val >= 127 && val <= 160) || val >= 256) {
812266733Speter                        /* no data to output */
813266733Speter                        size--;
814266733Speter                    }
815266733Speter                    else {
816266733Speter                        found = 1;
817266733Speter                    }
818266733Speter                }
819266733Speter                else {
820266733Speter                    j = i - 1;
821266733Speter                    if (j > MAXENTLEN || entlist[j] == NULL) {
822266733Speter                        /* wrong length */
823266733Speter                        continue; /* skip it */
824266733Speter                    }
825266733Speter                    for (ents = entlist[j]; *ents != '\0'; ents += i) {
826266733Speter                        if (strncmp(s + 1, ents, j) == 0) {
827266733Speter                            break;
828266733Speter                        }
829266733Speter                    }
830266733Speter
831266733Speter                    if (*ents == '\0') {
832266733Speter                        /* unknown */
833266733Speter                    }
834266733Speter                    else {
835266733Speter                        s += i;
836266733Speter                        slen -= i;
837266733Speter                        found = 1;
838266733Speter                    }
839266733Speter                }
840266733Speter            }
841266733Speter        }
842266733Speter    }
843266733Speter
844266733Speter    if (len) {
845266733Speter        *len = size;
846266733Speter    }
847266733Speter    if (!found) {
848266733Speter        return APR_NOTFOUND;
849266733Speter    }
850266733Speter
851266733Speter    return APR_SUCCESS;
852266733Speter}
853266733Speter
854266733SpeterAPR_DECLARE(const char *) apr_punescape_entity(apr_pool_t *p, const char *str)
855266733Speter{
856266733Speter    apr_size_t len;
857266733Speter
858266733Speter    switch (apr_unescape_entity(NULL, str, APR_ESCAPE_STRING, &len)) {
859266733Speter    case APR_SUCCESS: {
860266733Speter        char *cmd = apr_palloc(p, len);
861266733Speter        apr_unescape_entity(cmd, str, APR_ESCAPE_STRING, NULL);
862266733Speter        return cmd;
863266733Speter    }
864266733Speter    case APR_NOTFOUND: {
865266733Speter        break;
866266733Speter    }
867266733Speter    }
868266733Speter
869266733Speter    return str;
870266733Speter}
871266733Speter
872266733SpeterAPR_DECLARE(apr_status_t) apr_escape_echo(char *escaped, const char *str,
873266733Speter        apr_ssize_t slen, int quote, apr_size_t *len)
874266733Speter{
875266733Speter    apr_size_t size = 1;
876266733Speter    int found = 0;
877266733Speter    const unsigned char *s = (const unsigned char *) str;
878266733Speter    unsigned char *d = (unsigned char *) escaped;
879266733Speter    unsigned c;
880266733Speter
881266733Speter    if (s) {
882266733Speter        if (d) {
883266733Speter            while ((c = *s) && slen) {
884266733Speter                if (TEST_CHAR(c, T_ESCAPE_ECHO)) {
885266733Speter                    *d++ = '\\';
886266733Speter                    size++;
887266733Speter                    switch (c) {
888266733Speter                    case '\a':
889266733Speter                        *d++ = 'a';
890266733Speter                        size++;
891266733Speter                        found = 1;
892266733Speter                        break;
893266733Speter                    case '\b':
894266733Speter                        *d++ = 'b';
895266733Speter                        size++;
896266733Speter                        found = 1;
897266733Speter                        break;
898266733Speter                    case '\f':
899266733Speter                        *d++ = 'f';
900266733Speter                        size++;
901266733Speter                        found = 1;
902266733Speter                        break;
903266733Speter                    case '\n':
904266733Speter                        *d++ = 'n';
905266733Speter                        size++;
906266733Speter                        found = 1;
907266733Speter                        break;
908266733Speter                    case '\r':
909266733Speter                        *d++ = 'r';
910266733Speter                        size++;
911266733Speter                        found = 1;
912266733Speter                        break;
913266733Speter                    case '\t':
914266733Speter                        *d++ = 't';
915266733Speter                        size++;
916266733Speter                        found = 1;
917266733Speter                        break;
918266733Speter                    case '\v':
919266733Speter                        *d++ = 'v';
920266733Speter                        size++;
921266733Speter                        found = 1;
922266733Speter                        break;
923266733Speter                    case '\\':
924266733Speter                        *d++ = '\\';
925266733Speter                        size++;
926266733Speter                        found = 1;
927266733Speter                        break;
928266733Speter                    case '"':
929266733Speter                        if (quote) {
930266733Speter                            *d++ = c;
931266733Speter                            size++;
932266733Speter                            found = 1;
933266733Speter                        }
934266733Speter                        else {
935266733Speter                            d[-1] = c;
936266733Speter                        }
937266733Speter                        break;
938266733Speter                    default:
939266733Speter                        c2x(c, 'x', d);
940266733Speter                        d += 3;
941266733Speter                        size += 3;
942266733Speter                        found = 1;
943266733Speter                        break;
944266733Speter                    }
945266733Speter                }
946266733Speter                else {
947266733Speter                    *d++ = c;
948266733Speter                    size++;
949266733Speter                }
950266733Speter                ++s;
951266733Speter                slen--;
952266733Speter            }
953266733Speter            *d = '\0';
954266733Speter        }
955266733Speter        else {
956266733Speter            while ((c = *s) && slen) {
957266733Speter                if (TEST_CHAR(c, T_ESCAPE_ECHO)) {
958266733Speter                    size++;
959266733Speter                    switch (c) {
960266733Speter                    case '\a':
961266733Speter                    case '\b':
962266733Speter                    case '\f':
963266733Speter                    case '\n':
964266733Speter                    case '\r':
965266733Speter                    case '\t':
966266733Speter                    case '\v':
967266733Speter                    case '\\':
968266733Speter                        size++;
969266733Speter                        found = 1;
970266733Speter                        break;
971266733Speter                    case '"':
972266733Speter                        if (quote) {
973266733Speter                            size++;
974266733Speter                            found = 1;
975266733Speter                        }
976266733Speter                        break;
977266733Speter                    default:
978266733Speter                        size += 3;
979266733Speter                        found = 1;
980266733Speter                        break;
981266733Speter                    }
982266733Speter                }
983266733Speter                else {
984266733Speter                    size++;
985266733Speter                }
986266733Speter                ++s;
987266733Speter                slen--;
988266733Speter            }
989266733Speter        }
990266733Speter    }
991266733Speter
992266733Speter    if (len) {
993266733Speter        *len = size;
994266733Speter    }
995266733Speter    if (!found) {
996266733Speter        return APR_NOTFOUND;
997266733Speter    }
998266733Speter
999266733Speter    return APR_SUCCESS;
1000266733Speter}
1001266733Speter
1002266733SpeterAPR_DECLARE(const char *) apr_pescape_echo(apr_pool_t *p, const char *str,
1003266733Speter        int quote)
1004266733Speter{
1005266733Speter    apr_size_t len;
1006266733Speter
1007266733Speter    switch (apr_escape_echo(NULL, str, APR_ESCAPE_STRING, quote, &len)) {
1008266733Speter    case APR_SUCCESS: {
1009266733Speter        char *cmd = apr_palloc(p, len);
1010266733Speter        apr_escape_echo(cmd, str, APR_ESCAPE_STRING, quote, NULL);
1011266733Speter        return cmd;
1012266733Speter    }
1013266733Speter    case APR_NOTFOUND: {
1014266733Speter        break;
1015266733Speter    }
1016266733Speter    }
1017266733Speter
1018266733Speter    return str;
1019266733Speter}
1020266733Speter
1021266733SpeterAPR_DECLARE(apr_status_t) apr_escape_hex(char *dest, const void *src,
1022266733Speter        apr_size_t srclen, int colon, apr_size_t *len)
1023266733Speter{
1024266733Speter    const unsigned char *in = src;
1025266733Speter    apr_size_t size;
1026266733Speter
1027266733Speter    if (!src) {
1028266733Speter        return APR_NOTFOUND;
1029266733Speter    }
1030266733Speter
1031266733Speter    if (dest) {
1032266733Speter        for (size = 0; size < srclen; size++) {
1033266733Speter            if (colon && size) {
1034266733Speter                *dest++ = ':';
1035266733Speter            }
1036266733Speter            *dest++ = c2x_table[in[size] >> 4];
1037266733Speter            *dest++ = c2x_table[in[size] & 0xf];
1038266733Speter        }
1039266733Speter        *dest = '\0';
1040266733Speter    }
1041266733Speter
1042266733Speter    if (len) {
1043266733Speter        if (colon && srclen) {
1044266733Speter            *len = srclen * 3;
1045266733Speter        }
1046266733Speter        else {
1047266733Speter            *len = srclen * 2 + 1;
1048266733Speter        }
1049266733Speter    }
1050266733Speter
1051266733Speter    return APR_SUCCESS;
1052266733Speter}
1053266733Speter
1054266733SpeterAPR_DECLARE(const char *) apr_pescape_hex(apr_pool_t *p, const void *src,
1055266733Speter        apr_size_t srclen, int colon)
1056266733Speter{
1057266733Speter    apr_size_t len;
1058266733Speter
1059266733Speter    switch (apr_escape_hex(NULL, src, srclen, colon, &len)) {
1060266733Speter    case APR_SUCCESS: {
1061266733Speter        char *cmd = apr_palloc(p, len);
1062266733Speter        apr_escape_hex(cmd, src, srclen, colon, NULL);
1063266733Speter        return cmd;
1064266733Speter    }
1065266733Speter    case APR_NOTFOUND: {
1066266733Speter        break;
1067266733Speter    }
1068266733Speter    }
1069266733Speter
1070266733Speter    return src;
1071266733Speter}
1072266733Speter
1073266733SpeterAPR_DECLARE(apr_status_t) apr_unescape_hex(void *dest, const char *str,
1074266733Speter        apr_ssize_t slen, int colon, apr_size_t *len)
1075266733Speter{
1076266733Speter    apr_size_t size = 0;
1077266733Speter    int flip = 0;
1078266733Speter    const unsigned char *s = (const unsigned char *) str;
1079266733Speter    unsigned char *d = (unsigned char *) dest;
1080266733Speter    unsigned c;
1081266733Speter    unsigned char u = 0;
1082266733Speter
1083266733Speter    if (s) {
1084266733Speter        if (d) {
1085266733Speter            while ((c = *s) && slen) {
1086266733Speter
1087266733Speter                if (!flip) {
1088266733Speter                    u = 0;
1089266733Speter                }
1090266733Speter
1091266733Speter                if (colon && c == ':' && !flip) {
1092266733Speter                    ++s;
1093266733Speter                    slen--;
1094266733Speter                    continue;
1095266733Speter                }
1096266733Speter                else if (apr_isdigit(c)) {
1097266733Speter                    u |= c - '0';
1098266733Speter                }
1099266733Speter                else if (apr_isupper(c) && c <= 'F') {
1100266733Speter                    u |= c - ('A' - 10);
1101266733Speter                }
1102266733Speter                else if (apr_islower(c) && c <= 'f') {
1103266733Speter                    u |= c - ('a' - 10);
1104266733Speter                }
1105266733Speter                else {
1106266733Speter                    return APR_BADCH;
1107266733Speter                }
1108266733Speter
1109266733Speter                if (flip) {
1110266733Speter                    *d++ = u;
1111266733Speter                    size++;
1112266733Speter                }
1113266733Speter                else {
1114266733Speter                    u <<= 4;
1115266733Speter                    *d = u;
1116266733Speter                }
1117266733Speter                flip = !flip;
1118266733Speter
1119266733Speter                ++s;
1120266733Speter                slen--;
1121266733Speter            }
1122266733Speter        }
1123266733Speter        else {
1124266733Speter            while ((c = *s) && slen) {
1125266733Speter
1126266733Speter                if (colon && c == ':' && !flip) {
1127266733Speter                    ++s;
1128266733Speter                    slen--;
1129266733Speter                    continue;
1130266733Speter                }
1131266733Speter                else if (apr_isdigit(c)) {
1132266733Speter                    /* valid */
1133266733Speter                }
1134266733Speter                else if (apr_isupper(c) && c <= 'F') {
1135266733Speter                    /* valid */
1136266733Speter                }
1137266733Speter                else if (apr_islower(c) && c <= 'f') {
1138266733Speter                    /* valid */
1139266733Speter                }
1140266733Speter                else {
1141266733Speter                    return APR_BADCH;
1142266733Speter                }
1143266733Speter
1144266733Speter                if (flip) {
1145266733Speter                    size++;
1146266733Speter                }
1147266733Speter                flip = !flip;
1148266733Speter
1149266733Speter                ++s;
1150266733Speter                slen--;
1151266733Speter            }
1152266733Speter        }
1153266733Speter    }
1154266733Speter
1155266733Speter    if (len) {
1156266733Speter        *len = size;
1157266733Speter    }
1158266733Speter    if (!s) {
1159266733Speter        return APR_NOTFOUND;
1160266733Speter    }
1161266733Speter
1162266733Speter    return APR_SUCCESS;
1163266733Speter}
1164266733Speter
1165266733SpeterAPR_DECLARE(const void *) apr_punescape_hex(apr_pool_t *p, const char *str,
1166266733Speter        int colon, apr_size_t *len)
1167266733Speter{
1168266733Speter    apr_size_t size;
1169266733Speter
1170266733Speter    switch (apr_unescape_hex(NULL, str, APR_ESCAPE_STRING, colon, &size)) {
1171266733Speter    case APR_SUCCESS: {
1172266733Speter        void *cmd = apr_palloc(p, size);
1173266733Speter        apr_unescape_hex(cmd, str, APR_ESCAPE_STRING, colon, len);
1174266733Speter        return cmd;
1175266733Speter    }
1176266733Speter    case APR_BADCH:
1177266733Speter    case APR_NOTFOUND: {
1178266733Speter        break;
1179266733Speter    }
1180266733Speter    }
1181266733Speter
1182266733Speter    return NULL;
1183266733Speter}
1184