"Fossies" - the Fresh Open Source Software Archive

Member "apr-1.7.0/encoding/apr_escape.c" (25 Jun 2018, 33351 Bytes) of package /linux/www/apr-1.7.0.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "apr_escape.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.6.5_vs_1.7.0.

    1 /* Licensed to the Apache Software Foundation (ASF) under one or more
    2  * contributor license agreements.  See the NOTICE file distributed with
    3  * this work for additional information regarding copyright ownership.
    4  * The ASF licenses this file to You under the Apache License, Version 2.0
    5  * (the "License"); you may not use this file except in compliance with
    6  * the License.  You may obtain a copy of the License at
    7  *
    8  *     http://www.apache.org/licenses/LICENSE-2.0
    9  *
   10  * Unless required by applicable law or agreed to in writing, software
   11  * distributed under the License is distributed on an "AS IS" BASIS,
   12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13  * See the License for the specific language governing permissions and
   14  * limitations under the License.
   15  */
   16 
   17 /* escape/unescape functions.
   18  *
   19  * These functions perform various escaping operations, and are provided in
   20  * pairs, a function to query the length of and escape existing buffers, as
   21  * well as companion functions to perform the same process to memory
   22  * allocated from a pool.
   23  *
   24  * The API is designed to have the smallest possible RAM footprint, and so
   25  * will only allocate the exact amount of RAM needed for each conversion.
   26  */
   27 
   28 #include "apr_escape.h"
   29 #include "apr_escape_test_char.h"
   30 #include "apr_encode_private.h"
   31 #include "apr_lib.h"
   32 #include "apr_strings.h"
   33 
   34 /* we assume the folks using this ensure 0 <= c < 256... which means
   35  * you need a cast to (unsigned char) first, you can't just plug a
   36  * char in here and get it to work, because if char is signed then it
   37  * will first be sign extended.
   38  */
   39 #define TEST_CHAR(c, f)        (test_char_table[(unsigned)(c)] & (f))
   40 
   41 APR_DECLARE(apr_status_t) apr_escape_shell(char *escaped, const char *str,
   42         apr_ssize_t slen, apr_size_t *len)
   43 {
   44     unsigned char *d;
   45     const unsigned char *s;
   46     apr_size_t size = 1;
   47     int found = 0;
   48 
   49     d = (unsigned char *) escaped;
   50     s = (const unsigned char *) str;
   51 
   52     if (s) {
   53         if (d) {
   54             for (; *s && slen; ++s, slen--) {
   55 #if defined(OS2) || defined(WIN32)
   56                 /*
   57                  * Newlines to Win32/OS2 CreateProcess() are ill advised.
   58                  * Convert them to spaces since they are effectively white
   59                  * space to most applications
   60                  */
   61                 if (*s == '\r' || *s == '\n') {
   62                     if (d) {
   63                         *d++ = ' ';
   64                         found = 1;
   65                     }
   66                     continue;
   67                 }
   68 #endif
   69                 if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
   70                     *d++ = '\\';
   71                     size++;
   72                     found = 1;
   73                 }
   74                 *d++ = *s;
   75                 size++;
   76             }
   77             *d = '\0';
   78         }
   79         else {
   80             for (; *s && slen; ++s, slen--) {
   81                 if (TEST_CHAR(*s, T_ESCAPE_SHELL_CMD)) {
   82                     size++;
   83                     found = 1;
   84                 }
   85                 size++;
   86             }
   87         }
   88     }
   89 
   90     if (len) {
   91         *len = size;
   92     }
   93     if (!found) {
   94         return APR_NOTFOUND;
   95     }
   96 
   97     return APR_SUCCESS;
   98 }
   99 
  100 APR_DECLARE(const char *) apr_pescape_shell(apr_pool_t *p, const char *str)
  101 {
  102     apr_size_t len;
  103 
  104     switch (apr_escape_shell(NULL, str, APR_ESCAPE_STRING, &len)) {
  105     case APR_SUCCESS: {
  106         char *cmd = apr_palloc(p, len);
  107         apr_escape_shell(cmd, str, APR_ESCAPE_STRING, NULL);
  108         return cmd;
  109     }
  110     case APR_NOTFOUND: {
  111         break;
  112     }
  113     }
  114 
  115     return str;
  116 }
  117 
  118 static char x2c(const char *what)
  119 {
  120     register char digit;
  121 
  122 #if !APR_CHARSET_EBCDIC
  123     digit =
  124             ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
  125     digit *= 16;
  126     digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
  127 #else /*APR_CHARSET_EBCDIC*/
  128     char xstr[5];
  129     xstr[0]='0';
  130     xstr[1]='x';
  131     xstr[2]=what[0];
  132     xstr[3]=what[1];
  133     xstr[4]='\0';
  134     digit = ENCODE_TO_NATIVE[0xFF & strtol(xstr, NULL, 16)];
  135 #endif /*APR_CHARSET_EBCDIC*/
  136     return (digit);
  137 }
  138 
  139 APR_DECLARE(apr_status_t) apr_unescape_url(char *escaped, const char *url,
  140         apr_ssize_t slen, const char *forbid, const char *reserved, int plus,
  141         apr_size_t *len)
  142 {
  143     apr_size_t size = 1;
  144     int found = 0;
  145     const char *s = (const char *) url;
  146     char *d = (char *) escaped;
  147     register int badesc, badpath;
  148 
  149     if (!url) {
  150         return APR_NOTFOUND;
  151     }
  152 
  153     badesc = 0;
  154     badpath = 0;
  155     if (s) {
  156         if (d) {
  157             for (; *s && slen; ++s, d++, slen--) {
  158                 if (plus && *s == '+') {
  159                     *d = ' ';
  160                     found = 1;
  161                 }
  162                 else if (*s != '%') {
  163                     *d = *s;
  164                 }
  165                 else {
  166                     if (!apr_isxdigit(*(s + 1)) || !apr_isxdigit(*(s + 2))) {
  167                         badesc = 1;
  168                         *d = '%';
  169                     }
  170                     else {
  171                         char decoded;
  172                         decoded = x2c(s + 1);
  173                         if ((decoded == '\0')
  174                                 || (forbid && strchr(forbid, decoded))) {
  175                             badpath = 1;
  176                             *d = decoded;
  177                             s += 2;
  178                             slen -= 2;
  179                         }
  180                         else if (reserved && strchr(reserved, decoded)) {
  181                             *d++ = *s++;
  182                             *d++ = *s++;
  183                             *d = *s;
  184                             size += 2;
  185                         }
  186                         else {
  187                             *d = decoded;
  188                             s += 2;
  189                             slen -= 2;
  190                             found = 1;
  191                         }
  192                     }
  193                 }
  194                 size++;
  195             }
  196             *d = '\0';
  197         }
  198         else {
  199             for (; *s && slen; ++s, slen--) {
  200                 if (plus && *s == '+') {
  201                     found = 1;
  202                 }
  203                 else if (*s != '%') {
  204                     /* character unchanged */
  205                 }
  206                 else {
  207                     if (!apr_isxdigit(*(s + 1)) || !apr_isxdigit(*(s + 2))) {
  208                         badesc = 1;
  209                     }
  210                     else {
  211                         char decoded;
  212                         decoded = x2c(s + 1);
  213                         if ((decoded == '\0')
  214                                 || (forbid && strchr(forbid, decoded))) {
  215                             badpath = 1;
  216                             s += 2;
  217                             slen -= 2;
  218                         }
  219                         else if (reserved && strchr(reserved, decoded)) {
  220                             s += 2;
  221                             slen -= 2;
  222                             size += 2;
  223                         }
  224                         else {
  225                             s += 2;
  226                             slen -= 2;
  227                             found = 1;
  228                         }
  229                     }
  230                 }
  231                 size++;
  232             }
  233         }
  234     }
  235 
  236     if (len) {
  237         *len = size;
  238     }
  239     if (badesc) {
  240         return APR_EINVAL;
  241     }
  242     else if (badpath) {
  243         return APR_BADCH;
  244     }
  245     else if (!found) {
  246         return APR_NOTFOUND;
  247     }
  248 
  249     return APR_SUCCESS;
  250 }
  251 
  252 APR_DECLARE(const char *) apr_punescape_url(apr_pool_t *p, const char *url,
  253         const char *forbid, const char *reserved, int plus)
  254 {
  255     apr_size_t len;
  256 
  257     switch (apr_unescape_url(NULL, url, APR_ESCAPE_STRING, forbid, reserved,
  258             plus, &len)) {
  259     case APR_SUCCESS: {
  260         char *buf = apr_palloc(p, len);
  261         apr_unescape_url(buf, url, APR_ESCAPE_STRING, forbid, reserved, plus,
  262                 NULL);
  263         return buf;
  264     }
  265     case APR_EINVAL:
  266     case APR_BADCH: {
  267         return NULL;
  268     }
  269     case APR_NOTFOUND: {
  270         break;
  271     }
  272     }
  273 
  274     return url;
  275 }
  276 
  277 /* c2x takes an unsigned, and expects the caller has guaranteed that
  278  * 0 <= what < 256... which usually means that you have to cast to
  279  * unsigned char first, because (unsigned)(char)(x) first goes through
  280  * signed extension to an int before the unsigned cast.
  281  *
  282  * The reason for this assumption is to assist gcc code generation --
  283  * the unsigned char -> unsigned extension is already done earlier in
  284  * both uses of this code, so there's no need to waste time doing it
  285  * again.
  286  */
  287 static const char c2x_table[] = "0123456789abcdef";
  288 
  289 static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
  290         unsigned char *where)
  291 {
  292 #if APR_CHARSET_EBCDIC
  293     what = convert_e2a[(unsigned char)what];
  294 #endif /*APR_CHARSET_EBCDIC*/
  295     *where++ = prefix;
  296     *where++ = c2x_table[what >> 4];
  297     *where++ = c2x_table[what & 0xf];
  298     return where;
  299 }
  300 
  301 APR_DECLARE(apr_status_t) apr_escape_path_segment(char *escaped,
  302         const char *str, apr_ssize_t slen, apr_size_t *len)
  303 {
  304     apr_size_t size = 1;
  305     int found = 0;
  306     const unsigned char *s = (const unsigned char *) str;
  307     unsigned char *d = (unsigned char *) escaped;
  308     unsigned c;
  309 
  310     if (s) {
  311         if (d) {
  312             while ((c = *s) && slen) {
  313                 if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
  314                     d = c2x(c, '%', d);
  315                     size += 2;
  316                     found = 1;
  317                 }
  318                 else {
  319                     *d++ = c;
  320                 }
  321                 ++s;
  322                 size++;
  323                 slen--;
  324             }
  325             *d = '\0';
  326         }
  327         else {
  328             while ((c = *s) && slen) {
  329                 if (TEST_CHAR(c, T_ESCAPE_PATH_SEGMENT)) {
  330                     size += 2;
  331                     found = 1;
  332                 }
  333                 ++s;
  334                 size++;
  335                 slen--;
  336             }
  337         }
  338     }
  339 
  340     if (len) {
  341         *len = size;
  342     }
  343     if (!found) {
  344         return APR_NOTFOUND;
  345     }
  346 
  347     return APR_SUCCESS;
  348 }
  349 
  350 APR_DECLARE(const char *) apr_pescape_path_segment(apr_pool_t *p,
  351         const char *str)
  352 {
  353     apr_size_t len;
  354 
  355     switch (apr_escape_path_segment(NULL, str, APR_ESCAPE_STRING, &len)) {
  356     case APR_SUCCESS: {
  357         char *cmd = apr_palloc(p, len);
  358         apr_escape_path_segment(cmd, str, APR_ESCAPE_STRING, NULL);
  359         return cmd;
  360     }
  361     case APR_NOTFOUND: {
  362         break;
  363     }
  364     }
  365 
  366     return str;
  367 }
  368 
  369 APR_DECLARE(apr_status_t) apr_escape_path(char *escaped, const char *path,
  370         apr_ssize_t slen, int partial, apr_size_t *len)
  371 {
  372     apr_size_t size = 1;
  373     int found = 0;
  374     const unsigned char *s = (const unsigned char *) path;
  375     unsigned char *d = (unsigned char *) escaped;
  376     unsigned c;
  377 
  378     if (!path) {
  379         return APR_NOTFOUND;
  380     }
  381 
  382     if (!partial) {
  383         const char *colon = strchr(path, ':');
  384         const char *slash = strchr(path, '/');
  385 
  386         if (colon && (!slash || colon < slash)) {
  387             if (d) {
  388                 *d++ = '.';
  389                 *d++ = '/';
  390             }
  391             size += 2;
  392             found = 1;
  393         }
  394     }
  395     if (d) {
  396         while ((c = *s) && slen) {
  397             if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
  398                 d = c2x(c, '%', d);
  399                 size += 2;
  400                 found = 1;
  401             }
  402             else {
  403                 *d++ = c;
  404             }
  405             ++s;
  406             size++;
  407             slen--;
  408         }
  409         *d = '\0';
  410     }
  411     else {
  412         while ((c = *s) && slen) {
  413             if (TEST_CHAR(c, T_OS_ESCAPE_PATH)) {
  414                 size += 2;
  415                 found = 1;
  416             }
  417             ++s;
  418             size++;
  419             slen--;
  420         }
  421     }
  422 
  423     if (len) {
  424         *len = size;
  425     }
  426     if (!found) {
  427         return APR_NOTFOUND;
  428     }
  429 
  430     return APR_SUCCESS;
  431 }
  432 
  433 APR_DECLARE(const char *) apr_pescape_path(apr_pool_t *p, const char *str,
  434         int partial)
  435 {
  436     apr_size_t len;
  437 
  438     switch (apr_escape_path(NULL, str, APR_ESCAPE_STRING, partial, &len)) {
  439     case APR_SUCCESS: {
  440         char *path = apr_palloc(p, len);
  441         apr_escape_path(path, str, APR_ESCAPE_STRING, partial, NULL);
  442         return path;
  443     }
  444     case APR_NOTFOUND: {
  445         break;
  446     }
  447     }
  448 
  449     return str;
  450 }
  451 
  452 APR_DECLARE(apr_status_t) apr_escape_urlencoded(char *escaped, const char *str,
  453         apr_ssize_t slen, apr_size_t *len)
  454 {
  455     apr_size_t size = 1;
  456     int found = 0;
  457     const unsigned char *s = (const unsigned char *) str;
  458     unsigned char *d = (unsigned char *) escaped;
  459     unsigned c;
  460 
  461     if (s) {
  462         if (d) {
  463             while ((c = *s) && slen) {
  464                 if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
  465                     d = c2x(c, '%', d);
  466                     size += 2;
  467                     found = 1;
  468                 }
  469                 else if (c == ' ') {
  470                     *d++ = '+';
  471                     found = 1;
  472                 }
  473                 else {
  474                     *d++ = c;
  475                 }
  476                 ++s;
  477                 size++;
  478                 slen--;
  479             }
  480             *d = '\0';
  481         }
  482         else {
  483             while ((c = *s) && slen) {
  484                 if (TEST_CHAR(c, T_ESCAPE_URLENCODED)) {
  485                     size += 2;
  486                     found = 1;
  487                 }
  488                 else if (c == ' ') {
  489                     found = 1;
  490                 }
  491                 ++s;
  492                 size++;
  493                 slen--;
  494             }
  495         }
  496     }
  497 
  498     if (len) {
  499         *len = size;
  500     }
  501     if (!found) {
  502         return APR_NOTFOUND;
  503     }
  504 
  505     return APR_SUCCESS;
  506 }
  507 
  508 APR_DECLARE(const char *) apr_pescape_urlencoded(apr_pool_t *p, const char *str)
  509 {
  510     apr_size_t len;
  511 
  512     switch (apr_escape_urlencoded(NULL, str, APR_ESCAPE_STRING, &len)) {
  513     case APR_SUCCESS: {
  514         char *encoded = apr_palloc(p, len);
  515         apr_escape_urlencoded(encoded, str, APR_ESCAPE_STRING, NULL);
  516         return encoded;
  517     }
  518     case APR_NOTFOUND: {
  519         break;
  520     }
  521     }
  522 
  523     return str;
  524 }
  525 
  526 APR_DECLARE(apr_status_t) apr_escape_entity(char *escaped, const char *str,
  527         apr_ssize_t slen, int toasc, apr_size_t *len)
  528 {
  529     apr_size_t size = 1;
  530     int found = 0;
  531     const unsigned char *s = (const unsigned char *) str;
  532     unsigned char *d = (unsigned char *) escaped;
  533     unsigned c;
  534 
  535     if (s) {
  536         if (d) {
  537             while ((c = *s) && slen) {
  538                 if (TEST_CHAR(c, T_ESCAPE_XML)) {
  539                     switch (c) {
  540                     case '>': {
  541                         memcpy(d, "&gt;", 4);
  542                         size += 4;
  543                         d += 4;
  544                         break;
  545                     }
  546                     case '<': {
  547                         memcpy(d, "&lt;", 4);
  548                         size += 4;
  549                         d += 4;
  550                         break;
  551                     }
  552                     case '&': {
  553                         memcpy(d, "&amp;", 5);
  554                         size += 5;
  555                         d += 5;
  556                         break;
  557                     }
  558                     case '\"': {
  559                         memcpy(d, "&quot;", 6);
  560                         size += 6;
  561                         d += 6;
  562                         break;
  563                     }
  564                     case '\'': {
  565                         memcpy(d, "&apos;", 6);
  566                         size += 6;
  567                         d += 6;
  568                         break;
  569                     }
  570                     }
  571                     found = 1;
  572                 }
  573                 else if (toasc && !apr_isascii(c)) {
  574                     int offset = apr_snprintf((char *) d, 6, "&#%3.3d;", c);
  575                     size += offset;
  576                     d += offset;
  577                     found = 1;
  578                 }
  579                 else {
  580                     *d++ = c;
  581                     size++;
  582                 }
  583                 ++s;
  584                 slen--;
  585             }
  586             *d = '\0';
  587         }
  588         else {
  589             while ((c = *s) && slen) {
  590                 if (TEST_CHAR(c, T_ESCAPE_XML)) {
  591                     switch (c) {
  592                     case '>': {
  593                         size += 4;
  594                         break;
  595                     }
  596                     case '<': {
  597                         size += 4;
  598                         break;
  599                     }
  600                     case '&': {
  601                         size += 5;
  602                         break;
  603                     }
  604                     case '\"': {
  605                         size += 6;
  606                         break;
  607                     }
  608                     case '\'': {
  609                         size += 6;
  610                         break;
  611                     }
  612                     }
  613                     found = 1;
  614                 }
  615                 else if (toasc && !apr_isascii(c)) {
  616                     char buf[8];
  617                     size += apr_snprintf(buf, 6, "&#%3.3d;", c);
  618                     found = 1;
  619                 }
  620                 else {
  621                     size++;
  622                 }
  623                 ++s;
  624                 slen--;
  625             }
  626         }
  627     }
  628 
  629     if (len) {
  630         *len = size;
  631     }
  632     if (!found) {
  633         return APR_NOTFOUND;
  634     }
  635 
  636     return APR_SUCCESS;
  637 }
  638 
  639 APR_DECLARE(const char *) apr_pescape_entity(apr_pool_t *p, const char *str,
  640         int toasc)
  641 {
  642     apr_size_t len;
  643 
  644     switch (apr_escape_entity(NULL, str, APR_ESCAPE_STRING, toasc, &len)) {
  645     case APR_SUCCESS: {
  646         char *cmd = apr_palloc(p, len);
  647         apr_escape_entity(cmd, str, APR_ESCAPE_STRING, toasc, NULL);
  648         return cmd;
  649     }
  650     case APR_NOTFOUND: {
  651         break;
  652     }
  653     }
  654 
  655     return str;
  656 }
  657 
  658 /* maximum length of any ISO-LATIN-1 HTML entity name. */
  659 #define MAXENTLEN (6)
  660 
  661 APR_DECLARE(apr_status_t) apr_unescape_entity(char *unescaped, const char *str,
  662         apr_ssize_t slen, apr_size_t *len)
  663 {
  664     int found = 0;
  665     apr_size_t size = 1;
  666     int val, i, j;
  667     char *d = unescaped;
  668     const char *s = str;
  669     const char *ents;
  670     static const char * const entlist[MAXENTLEN + 1] =
  671     {
  672             NULL, /* 0 */
  673             NULL, /* 1 */
  674             "lt\074gt\076", /* 2 */
  675             "amp\046ETH\320eth\360", /* 3 */
  676             "quot\042Auml\304Euml\313Iuml\317Ouml\326Uuml\334auml\344euml"
  677             "\353iuml\357ouml\366uuml\374yuml\377", /* 4 */
  678             "Acirc\302Aring\305AElig\306Ecirc\312Icirc\316Ocirc\324Ucirc"
  679             "\333THORN\336szlig\337acirc\342aring\345aelig\346ecirc\352"
  680             "icirc\356ocirc\364ucirc\373thorn\376", /* 5 */
  681             "Agrave\300Aacute\301Atilde\303Ccedil\307Egrave\310Eacute\311"
  682             "Igrave\314Iacute\315Ntilde\321Ograve\322Oacute\323Otilde"
  683             "\325Oslash\330Ugrave\331Uacute\332Yacute\335agrave\340"
  684             "aacute\341atilde\343ccedil\347egrave\350eacute\351igrave"
  685             "\354iacute\355ntilde\361ograve\362oacute\363otilde\365"
  686             "oslash\370ugrave\371uacute\372yacute\375" /* 6 */
  687     };
  688 
  689     if (s) {
  690         if (d) {
  691             for (; *s != '\0' && slen; s++, d++, size++, slen--) {
  692                 if (*s != '&') {
  693                     *d = *s;
  694                     continue;
  695                 }
  696                 /* find end of entity */
  697                 for (i = 1; s[i] != ';' && s[i] != '\0' && (slen - i) != 0;
  698                         i++) {
  699                     continue;
  700                 }
  701 
  702                 if (s[i] == '\0' || (slen - i) == 0) { /* treat as normal data */
  703                     *d = *s;
  704                     continue;
  705                 }
  706 
  707                 /* is it numeric ? */
  708                 if (s[1] == '#') {
  709                     for (j = 2, val = 0; j < i && apr_isdigit(s[j]); j++) {
  710                         val = val * 10 + s[j] - '0';
  711                     }
  712                     s += i;
  713                     if (j < i || val <= 8 || (val >= 11 && val <= 31)
  714                             || (val >= 127 && val <= 160) || val >= 256) {
  715                         d--; /* no data to output */
  716                         size--;
  717                     }
  718                     else {
  719                         *d = ENCODE_TO_ASCII(val);
  720                         found = 1;
  721                     }
  722                 }
  723                 else {
  724                     j = i - 1;
  725                     if (j > MAXENTLEN || entlist[j] == NULL) {
  726                         /* wrong length */
  727                         *d = '&';
  728                         continue; /* skip it */
  729                     }
  730                     for (ents = entlist[j]; *ents != '\0'; ents += i) {
  731                         if (strncmp(s + 1, ents, j) == 0) {
  732                             break;
  733                         }
  734                     }
  735 
  736                     if (*ents == '\0') {
  737                         *d = '&'; /* unknown */
  738                     }
  739                     else {
  740                         *d = ENCODE_TO_ASCII(((const unsigned char *) ents)[j]);
  741                         s += i;
  742                         slen -= i;
  743                         found = 1;
  744                     }
  745                 }
  746             }
  747             *d = '\0';
  748         }
  749         else {
  750             for (; *s != '\0' && slen; s++, size++, slen--) {
  751                 if (*s != '&') {
  752                     continue;
  753                 }
  754                 /* find end of entity */
  755                 for (i = 1; s[i] != ';' && s[i] != '\0' && (slen - i) != 0;
  756                         i++) {
  757                     continue;
  758                 }
  759 
  760                 if (s[i] == '\0' || (slen - i) == 0) { /* treat as normal data */
  761                     continue;
  762                 }
  763 
  764                 /* is it numeric ? */
  765                 if (s[1] == '#') {
  766                     for (j = 2, val = 0; j < i && apr_isdigit(s[j]); j++) {
  767                         val = val * 10 + s[j] - '0';
  768                     }
  769                     s += i;
  770                     if (j < i || val <= 8 || (val >= 11 && val <= 31)
  771                             || (val >= 127 && val <= 160) || val >= 256) {
  772                         /* no data to output */
  773                         size--;
  774                     }
  775                     else {
  776                         found = 1;
  777                     }
  778                 }
  779                 else {
  780                     j = i - 1;
  781                     if (j > MAXENTLEN || entlist[j] == NULL) {
  782                         /* wrong length */
  783                         continue; /* skip it */
  784                     }
  785                     for (ents = entlist[j]; *ents != '\0'; ents += i) {
  786                         if (strncmp(s + 1, ents, j) == 0) {
  787                             break;
  788                         }
  789                     }
  790 
  791                     if (*ents == '\0') {
  792                         /* unknown */
  793                     }
  794                     else {
  795                         s += i;
  796                         slen -= i;
  797                         found = 1;
  798                     }
  799                 }
  800             }
  801         }
  802     }
  803 
  804     if (len) {
  805         *len = size;
  806     }
  807     if (!found) {
  808         return APR_NOTFOUND;
  809     }
  810 
  811     return APR_SUCCESS;
  812 }
  813 
  814 APR_DECLARE(const char *) apr_punescape_entity(apr_pool_t *p, const char *str)
  815 {
  816     apr_size_t len;
  817 
  818     switch (apr_unescape_entity(NULL, str, APR_ESCAPE_STRING, &len)) {
  819     case APR_SUCCESS: {
  820         char *cmd = apr_palloc(p, len);
  821         apr_unescape_entity(cmd, str, APR_ESCAPE_STRING, NULL);
  822         return cmd;
  823     }
  824     case APR_NOTFOUND: {
  825         break;
  826     }
  827     }
  828 
  829     return str;
  830 }
  831 
  832 APR_DECLARE(apr_status_t) apr_escape_echo(char *escaped, const char *str,
  833         apr_ssize_t slen, int quote, apr_size_t *len)
  834 {
  835     apr_size_t size = 1;
  836     int found = 0;
  837     const unsigned char *s = (const unsigned char *) str;
  838     unsigned char *d = (unsigned char *) escaped;
  839     unsigned c;
  840 
  841     if (s) {
  842         if (d) {
  843             while ((c = *s) && slen) {
  844                 if (TEST_CHAR(c, T_ESCAPE_ECHO)) {
  845                     *d++ = '\\';
  846                     size++;
  847                     switch (c) {
  848                     case '\a':
  849                         *d++ = 'a';
  850                         size++;
  851                         found = 1;
  852                         break;
  853                     case '\b':
  854                         *d++ = 'b';
  855                         size++;
  856                         found = 1;
  857                         break;
  858                     case '\f':
  859                         *d++ = 'f';
  860                         size++;
  861                         found = 1;
  862                         break;
  863                     case '\n':
  864                         *d++ = 'n';
  865                         size++;
  866                         found = 1;
  867                         break;
  868                     case '\r':
  869                         *d++ = 'r';
  870                         size++;
  871                         found = 1;
  872                         break;
  873                     case '\t':
  874                         *d++ = 't';
  875                         size++;
  876                         found = 1;
  877                         break;
  878                     case '\v':
  879                         *d++ = 'v';
  880                         size++;
  881                         found = 1;
  882                         break;
  883                     case '\\':
  884                         *d++ = '\\';
  885                         size++;
  886                         found = 1;
  887                         break;
  888                     case '"':
  889                         if (quote) {
  890                             *d++ = c;
  891                             size++;
  892                             found = 1;
  893                         }
  894                         else {
  895                             d[-1] = c;
  896                         }
  897                         break;
  898                     default:
  899                         c2x(c, 'x', d);
  900                         d += 3;
  901                         size += 3;
  902                         found = 1;
  903                         break;
  904                     }
  905                 }
  906                 else {
  907                     *d++ = c;
  908                     size++;
  909                 }
  910                 ++s;
  911                 slen--;
  912             }
  913             *d = '\0';
  914         }
  915         else {
  916             while ((c = *s) && slen) {
  917                 if (TEST_CHAR(c, T_ESCAPE_ECHO)) {
  918                     size++;
  919                     switch (c) {
  920                     case '\a':
  921                     case '\b':
  922                     case '\f':
  923                     case '\n':
  924                     case '\r':
  925                     case '\t':
  926                     case '\v':
  927                     case '\\':
  928                         size++;
  929                         found = 1;
  930                         break;
  931                     case '"':
  932                         if (quote) {
  933                             size++;
  934                             found = 1;
  935                         }
  936                         break;
  937                     default:
  938                         size += 3;
  939                         found = 1;
  940                         break;
  941                     }
  942                 }
  943                 else {
  944                     size++;
  945                 }
  946                 ++s;
  947                 slen--;
  948             }
  949         }
  950     }
  951 
  952     if (len) {
  953         *len = size;
  954     }
  955     if (!found) {
  956         return APR_NOTFOUND;
  957     }
  958 
  959     return APR_SUCCESS;
  960 }
  961 
  962 APR_DECLARE(const char *) apr_pescape_echo(apr_pool_t *p, const char *str,
  963         int quote)
  964 {
  965     apr_size_t len;
  966 
  967     switch (apr_escape_echo(NULL, str, APR_ESCAPE_STRING, quote, &len)) {
  968     case APR_SUCCESS: {
  969         char *cmd = apr_palloc(p, len);
  970         apr_escape_echo(cmd, str, APR_ESCAPE_STRING, quote, NULL);
  971         return cmd;
  972     }
  973     case APR_NOTFOUND: {
  974         break;
  975     }
  976     }
  977 
  978     return str;
  979 }
  980 
  981 APR_DECLARE(apr_status_t) apr_escape_hex(char *dest, const void *src,
  982         apr_size_t srclen, int colon, apr_size_t *len)
  983 {
  984     const unsigned char *in = src;
  985     apr_size_t size;
  986 
  987     if (!src) {
  988         return APR_NOTFOUND;
  989     }
  990 
  991     if (dest) {
  992         for (size = 0; size < srclen; size++) {
  993             if (colon && size) {
  994                 *dest++ = ':';
  995             }
  996             *dest++ = c2x_table[in[size] >> 4];
  997             *dest++ = c2x_table[in[size] & 0xf];
  998         }
  999         *dest = '\0';
 1000     }
 1001 
 1002     if (len) {
 1003         if (colon && srclen) {
 1004             *len = srclen * 3;
 1005         }
 1006         else {
 1007             *len = srclen * 2 + 1;
 1008         }
 1009     }
 1010 
 1011     return APR_SUCCESS;
 1012 }
 1013 
 1014 APR_DECLARE(const char *) apr_pescape_hex(apr_pool_t *p, const void *src,
 1015         apr_size_t srclen, int colon)
 1016 {
 1017     apr_size_t len;
 1018 
 1019     switch (apr_escape_hex(NULL, src, srclen, colon, &len)) {
 1020     case APR_SUCCESS: {
 1021         char *cmd = apr_palloc(p, len);
 1022         apr_escape_hex(cmd, src, srclen, colon, NULL);
 1023         return cmd;
 1024     }
 1025     case APR_NOTFOUND: {
 1026         break;
 1027     }
 1028     }
 1029 
 1030     return src;
 1031 }
 1032 
 1033 APR_DECLARE(apr_status_t) apr_unescape_hex(void *dest, const char *str,
 1034         apr_ssize_t slen, int colon, apr_size_t *len)
 1035 {
 1036     apr_size_t size = 0;
 1037     int flip = 0;
 1038     const unsigned char *s = (const unsigned char *) str;
 1039     unsigned char *d = (unsigned char *) dest;
 1040     unsigned c;
 1041     unsigned char u = 0;
 1042 
 1043     if (s) {
 1044         if (d) {
 1045             while ((c = *s) && slen) {
 1046 
 1047                 if (!flip) {
 1048                     u = 0;
 1049                 }
 1050 
 1051                 if (colon && c == ':' && !flip) {
 1052                     ++s;
 1053                     slen--;
 1054                     continue;
 1055                 }
 1056                 else if (apr_isdigit(c)) {
 1057                     u |= c - '0';
 1058                 }
 1059                 else if (apr_isupper(c) && c <= 'F') {
 1060                     u |= c - ('A' - 10);
 1061                 }
 1062                 else if (apr_islower(c) && c <= 'f') {
 1063                     u |= c - ('a' - 10);
 1064                 }
 1065                 else {
 1066                     return APR_BADCH;
 1067                 }
 1068 
 1069                 if (flip) {
 1070                     *d++ = u;
 1071                     size++;
 1072                 }
 1073                 else {
 1074                     u <<= 4;
 1075                     *d = u;
 1076                 }
 1077                 flip = !flip;
 1078 
 1079                 ++s;
 1080                 slen--;
 1081             }
 1082         }
 1083         else {
 1084             while ((c = *s) && slen) {
 1085 
 1086                 if (colon && c == ':' && !flip) {
 1087                     ++s;
 1088                     slen--;
 1089                     continue;
 1090                 }
 1091                 else if (apr_isdigit(c)) {
 1092                     /* valid */
 1093                 }
 1094                 else if (apr_isupper(c) && c <= 'F') {
 1095                     /* valid */
 1096                 }
 1097                 else if (apr_islower(c) && c <= 'f') {
 1098                     /* valid */
 1099                 }
 1100                 else {
 1101                     return APR_BADCH;
 1102                 }
 1103 
 1104                 if (flip) {
 1105                     size++;
 1106                 }
 1107                 flip = !flip;
 1108 
 1109                 ++s;
 1110                 slen--;
 1111             }
 1112         }
 1113     }
 1114 
 1115     if (len) {
 1116         *len = size;
 1117     }
 1118     if (!s) {
 1119         return APR_NOTFOUND;
 1120     }
 1121 
 1122     return APR_SUCCESS;
 1123 }
 1124 
 1125 APR_DECLARE(const void *) apr_punescape_hex(apr_pool_t *p, const char *str,
 1126         int colon, apr_size_t *len)
 1127 {
 1128     apr_size_t size;
 1129 
 1130     switch (apr_unescape_hex(NULL, str, APR_ESCAPE_STRING, colon, &size)) {
 1131     case APR_SUCCESS: {
 1132         void *cmd = apr_palloc(p, size);
 1133         apr_unescape_hex(cmd, str, APR_ESCAPE_STRING, colon, len);
 1134         return cmd;
 1135     }
 1136     case APR_BADCH:
 1137     case APR_NOTFOUND: {
 1138         break;
 1139     }
 1140     }
 1141 
 1142     return NULL;
 1143 }
 1144 
 1145 APR_DECLARE(apr_status_t) apr_escape_ldap(char *escaped, const void *str,
 1146         apr_ssize_t slen, int flags, apr_size_t *len)
 1147 {
 1148     apr_size_t size = 1;
 1149     int found = 0;
 1150     const unsigned char *s = (const unsigned char *) str;
 1151     unsigned char *d = (unsigned char *) escaped;
 1152     unsigned c;
 1153 
 1154     if (s) {
 1155         if (d) {
 1156             while (((c = *s) && slen) || (slen > 0)) {
 1157                 if (((flags & APR_ESCAPE_LDAP_DN) && TEST_CHAR(c, T_ESCAPE_LDAP_DN))
 1158                      || ((flags & APR_ESCAPE_LDAP_FILTER) && TEST_CHAR(c, T_ESCAPE_LDAP_FILTER))) {
 1159                     d = c2x(c, '\\', d);
 1160                     size += 2;
 1161                     found = 1;
 1162                 }
 1163                 else {
 1164                     *d++ = c;
 1165                 }
 1166                 ++s;
 1167                 size++;
 1168                 slen--;
 1169             }
 1170             *d = '\0';
 1171         }
 1172         else {
 1173             while (((c = *s) && slen) || (slen > 0)) {
 1174                 if (((flags & APR_ESCAPE_LDAP_DN) && TEST_CHAR(c, T_ESCAPE_LDAP_DN)) 
 1175                      || ((flags & APR_ESCAPE_LDAP_FILTER) && TEST_CHAR(c, T_ESCAPE_LDAP_FILTER))) {
 1176                     size += 2;
 1177                     found = 1;
 1178                 }
 1179                 ++s;
 1180                 size++;
 1181                 slen--;
 1182             }
 1183         }
 1184     }
 1185 
 1186     if (len) {
 1187         *len = size;
 1188     }
 1189     if (!found) {
 1190         return APR_NOTFOUND;
 1191     }
 1192 
 1193     return APR_SUCCESS;
 1194 }
 1195 
 1196 APR_DECLARE(const char *) apr_pescape_ldap(apr_pool_t *p, const void *src,
 1197         apr_ssize_t srclen, int flags)
 1198 {
 1199     apr_size_t len;
 1200 
 1201     switch (apr_escape_ldap(NULL, src, srclen, flags, &len)) {
 1202     case APR_SUCCESS: {
 1203         char *encoded = apr_palloc(p, len);
 1204         apr_escape_ldap(encoded, src, srclen, flags, NULL);
 1205         return encoded;
 1206     }
 1207     case APR_NOTFOUND: {
 1208         break;
 1209     }
 1210     }
 1211 
 1212     return src;
 1213 }
 1214