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