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, ">", 4); 580266733Speter size += 4; 581266733Speter d += 4; 582266733Speter break; 583266733Speter } 584266733Speter case '<': { 585266733Speter memcpy(d, "<", 4); 586266733Speter size += 4; 587266733Speter d += 4; 588266733Speter break; 589266733Speter } 590266733Speter case '&': { 591266733Speter memcpy(d, "&", 5); 592266733Speter size += 5; 593266733Speter d += 5; 594266733Speter break; 595266733Speter } 596266733Speter case '\"': { 597266733Speter memcpy(d, """, 6); 598266733Speter size += 6; 599266733Speter d += 6; 600266733Speter break; 601266733Speter } 602266733Speter case '\'': { 603266733Speter memcpy(d, "'", 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