Annotation of embedaddon/libxml2/uri.c, revision 1.1.1.1

1.1       misho       1: /**
                      2:  * uri.c: set of generic URI related routines 
                      3:  *
                      4:  * Reference: RFCs 3986, 2732 and 2373
                      5:  *
                      6:  * See Copyright for the status of this software.
                      7:  *
                      8:  * daniel@veillard.com
                      9:  */
                     10: 
                     11: #define IN_LIBXML
                     12: #include "libxml.h"
                     13: 
                     14: #include <string.h>
                     15: 
                     16: #include <libxml/xmlmemory.h>
                     17: #include <libxml/uri.h>
                     18: #include <libxml/globals.h>
                     19: #include <libxml/xmlerror.h>
                     20: 
                     21: static void xmlCleanURI(xmlURIPtr uri);
                     22: 
                     23: /*
                     24:  * Old rule from 2396 used in legacy handling code
                     25:  * alpha    = lowalpha | upalpha
                     26:  */
                     27: #define IS_ALPHA(x) (IS_LOWALPHA(x) || IS_UPALPHA(x))
                     28: 
                     29: 
                     30: /*
                     31:  * lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" |
                     32:  *            "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" |
                     33:  *            "u" | "v" | "w" | "x" | "y" | "z"
                     34:  */
                     35: 
                     36: #define IS_LOWALPHA(x) (((x) >= 'a') && ((x) <= 'z'))
                     37: 
                     38: /*
                     39:  * upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" |
                     40:  *           "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" |
                     41:  *           "U" | "V" | "W" | "X" | "Y" | "Z"
                     42:  */
                     43: #define IS_UPALPHA(x) (((x) >= 'A') && ((x) <= 'Z'))
                     44: 
                     45: #ifdef IS_DIGIT
                     46: #undef IS_DIGIT
                     47: #endif
                     48: /*
                     49:  * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
                     50:  */
                     51: #define IS_DIGIT(x) (((x) >= '0') && ((x) <= '9'))
                     52: 
                     53: /*
                     54:  * alphanum = alpha | digit
                     55:  */
                     56: 
                     57: #define IS_ALPHANUM(x) (IS_ALPHA(x) || IS_DIGIT(x))
                     58: 
                     59: /*
                     60:  * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
                     61:  */
                     62: 
                     63: #define IS_MARK(x) (((x) == '-') || ((x) == '_') || ((x) == '.') ||     \
                     64:     ((x) == '!') || ((x) == '~') || ((x) == '*') || ((x) == '\'') ||    \
                     65:     ((x) == '(') || ((x) == ')'))
                     66: 
                     67: /*
                     68:  * unwise = "{" | "}" | "|" | "\" | "^" | "`"
                     69:  */
                     70: 
                     71: #define IS_UNWISE(p)                                                    \
                     72:       (((*(p) == '{')) || ((*(p) == '}')) || ((*(p) == '|')) ||         \
                     73:        ((*(p) == '\\')) || ((*(p) == '^')) || ((*(p) == '[')) ||        \
                     74:        ((*(p) == ']')) || ((*(p) == '`')))
                     75: /*
                     76:  * reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," |
                     77:  *            "[" | "]"
                     78:  */
                     79: 
                     80: #define IS_RESERVED(x) (((x) == ';') || ((x) == '/') || ((x) == '?') || \
                     81:         ((x) == ':') || ((x) == '@') || ((x) == '&') || ((x) == '=') || \
                     82:         ((x) == '+') || ((x) == '$') || ((x) == ',') || ((x) == '[') || \
                     83:         ((x) == ']'))
                     84: 
                     85: /*
                     86:  * unreserved = alphanum | mark
                     87:  */
                     88: 
                     89: #define IS_UNRESERVED(x) (IS_ALPHANUM(x) || IS_MARK(x))
                     90: 
                     91: /*
                     92:  * Skip to next pointer char, handle escaped sequences
                     93:  */
                     94: 
                     95: #define NEXT(p) ((*p == '%')? p += 3 : p++)
                     96: 
                     97: /*
                     98:  * Productions from the spec.
                     99:  *
                    100:  *    authority     = server | reg_name
                    101:  *    reg_name      = 1*( unreserved | escaped | "$" | "," |
                    102:  *                        ";" | ":" | "@" | "&" | "=" | "+" )
                    103:  *
                    104:  * path          = [ abs_path | opaque_part ]
                    105:  */
                    106: 
                    107: #define STRNDUP(s, n) (char *) xmlStrndup((const xmlChar *)(s), (n))
                    108: 
                    109: /************************************************************************
                    110:  *                                                                     *
                    111:  *                         RFC 3986 parser                             *
                    112:  *                                                                     *
                    113:  ************************************************************************/
                    114: 
                    115: #define ISA_DIGIT(p) ((*(p) >= '0') && (*(p) <= '9'))
                    116: #define ISA_ALPHA(p) (((*(p) >= 'a') && (*(p) <= 'z')) ||              \
                    117:                       ((*(p) >= 'A') && (*(p) <= 'Z')))
                    118: #define ISA_HEXDIG(p)                                                  \
                    119:        (ISA_DIGIT(p) || ((*(p) >= 'a') && (*(p) <= 'f')) ||            \
                    120:         ((*(p) >= 'A') && (*(p) <= 'F')))
                    121: 
                    122: /*
                    123:  *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
                    124:  *                     / "*" / "+" / "," / ";" / "="
                    125:  */
                    126: #define ISA_SUB_DELIM(p)                                               \
                    127:       (((*(p) == '!')) || ((*(p) == '$')) || ((*(p) == '&')) ||                \
                    128:        ((*(p) == '(')) || ((*(p) == ')')) || ((*(p) == '*')) ||                \
                    129:        ((*(p) == '+')) || ((*(p) == ',')) || ((*(p) == ';')) ||                \
                    130:        ((*(p) == '=')) || ((*(p) == '\'')))
                    131: 
                    132: /*
                    133:  *    gen-delims    = ":" / "/" / "?" / "#" / "[" / "]" / "@"
                    134:  */
                    135: #define ISA_GEN_DELIM(p)                                               \
                    136:       (((*(p) == ':')) || ((*(p) == '/')) || ((*(p) == '?')) ||         \
                    137:        ((*(p) == '#')) || ((*(p) == '[')) || ((*(p) == ']')) ||         \
                    138:        ((*(p) == '@')))
                    139: 
                    140: /*
                    141:  *    reserved      = gen-delims / sub-delims
                    142:  */
                    143: #define ISA_RESERVED(p) (ISA_GEN_DELIM(p) || (ISA_SUB_DELIM(p)))
                    144: 
                    145: /*
                    146:  *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
                    147:  */
                    148: #define ISA_UNRESERVED(p)                                              \
                    149:       ((ISA_ALPHA(p)) || (ISA_DIGIT(p)) || ((*(p) == '-')) ||          \
                    150:        ((*(p) == '.')) || ((*(p) == '_')) || ((*(p) == '~')))
                    151: 
                    152: /*
                    153:  *    pct-encoded   = "%" HEXDIG HEXDIG
                    154:  */
                    155: #define ISA_PCT_ENCODED(p)                                             \
                    156:      ((*(p) == '%') && (ISA_HEXDIG(p + 1)) && (ISA_HEXDIG(p + 2)))
                    157: 
                    158: /*
                    159:  *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
                    160:  */
                    161: #define ISA_PCHAR(p)                                                   \
                    162:      (ISA_UNRESERVED(p) || ISA_PCT_ENCODED(p) || ISA_SUB_DELIM(p) ||   \
                    163:       ((*(p) == ':')) || ((*(p) == '@')))
                    164: 
                    165: /**
                    166:  * xmlParse3986Scheme:
                    167:  * @uri:  pointer to an URI structure
                    168:  * @str:  pointer to the string to analyze
                    169:  *
                    170:  * Parse an URI scheme
                    171:  *
                    172:  * ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
                    173:  *
                    174:  * Returns 0 or the error code
                    175:  */
                    176: static int
                    177: xmlParse3986Scheme(xmlURIPtr uri, const char **str) {
                    178:     const char *cur;
                    179: 
                    180:     if (str == NULL)
                    181:        return(-1);
                    182: 
                    183:     cur = *str;
                    184:     if (!ISA_ALPHA(cur))
                    185:        return(2);
                    186:     cur++;
                    187:     while (ISA_ALPHA(cur) || ISA_DIGIT(cur) ||
                    188:            (*cur == '+') || (*cur == '-') || (*cur == '.')) cur++;
                    189:     if (uri != NULL) {
                    190:        if (uri->scheme != NULL) xmlFree(uri->scheme);
                    191:        uri->scheme = STRNDUP(*str, cur - *str);
                    192:     }
                    193:     *str = cur;
                    194:     return(0);
                    195: }
                    196: 
                    197: /**
                    198:  * xmlParse3986Fragment:
                    199:  * @uri:  pointer to an URI structure
                    200:  * @str:  pointer to the string to analyze
                    201:  *
                    202:  * Parse the query part of an URI
                    203:  *
                    204:  * fragment      = *( pchar / "/" / "?" )
                    205:  * NOTE: the strict syntax as defined by 3986 does not allow '[' and ']'
                    206:  *       in the fragment identifier but this is used very broadly for
                    207:  *       xpointer scheme selection, so we are allowing it here to not break
                    208:  *       for example all the DocBook processing chains.
                    209:  *
                    210:  * Returns 0 or the error code
                    211:  */
                    212: static int
                    213: xmlParse3986Fragment(xmlURIPtr uri, const char **str)
                    214: {
                    215:     const char *cur;
                    216: 
                    217:     if (str == NULL)
                    218:         return (-1);
                    219: 
                    220:     cur = *str;
                    221: 
                    222:     while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') ||
                    223:            (*cur == '[') || (*cur == ']') ||
                    224:            ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
                    225:         NEXT(cur);
                    226:     if (uri != NULL) {
                    227:         if (uri->fragment != NULL)
                    228:             xmlFree(uri->fragment);
                    229:        if (uri->cleanup & 2)
                    230:            uri->fragment = STRNDUP(*str, cur - *str);
                    231:        else
                    232:            uri->fragment = xmlURIUnescapeString(*str, cur - *str, NULL);
                    233:     }
                    234:     *str = cur;
                    235:     return (0);
                    236: }
                    237: 
                    238: /**
                    239:  * xmlParse3986Query:
                    240:  * @uri:  pointer to an URI structure
                    241:  * @str:  pointer to the string to analyze
                    242:  *
                    243:  * Parse the query part of an URI
                    244:  *
                    245:  * query = *uric
                    246:  *
                    247:  * Returns 0 or the error code
                    248:  */
                    249: static int
                    250: xmlParse3986Query(xmlURIPtr uri, const char **str)
                    251: {
                    252:     const char *cur;
                    253: 
                    254:     if (str == NULL)
                    255:         return (-1);
                    256: 
                    257:     cur = *str;
                    258: 
                    259:     while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') ||
                    260:            ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
                    261:         NEXT(cur);
                    262:     if (uri != NULL) {
                    263:         if (uri->query != NULL)
                    264:             xmlFree(uri->query);
                    265:        if (uri->cleanup & 2)
                    266:            uri->query = STRNDUP(*str, cur - *str);
                    267:        else
                    268:            uri->query = xmlURIUnescapeString(*str, cur - *str, NULL);
                    269: 
                    270:        /* Save the raw bytes of the query as well.
                    271:         * See: http://mail.gnome.org/archives/xml/2007-April/thread.html#00114
                    272:         */
                    273:        if (uri->query_raw != NULL)
                    274:            xmlFree (uri->query_raw);
                    275:        uri->query_raw = STRNDUP (*str, cur - *str);
                    276:     }
                    277:     *str = cur;
                    278:     return (0);
                    279: }
                    280: 
                    281: /**
                    282:  * xmlParse3986Port:
                    283:  * @uri:  pointer to an URI structure
                    284:  * @str:  the string to analyze
                    285:  *
                    286:  * Parse a port  part and fills in the appropriate fields
                    287:  * of the @uri structure
                    288:  *
                    289:  * port          = *DIGIT
                    290:  *
                    291:  * Returns 0 or the error code
                    292:  */
                    293: static int
                    294: xmlParse3986Port(xmlURIPtr uri, const char **str)
                    295: {
                    296:     const char *cur = *str;
                    297: 
                    298:     if (ISA_DIGIT(cur)) {
                    299:        if (uri != NULL)
                    300:            uri->port = 0;
                    301:        while (ISA_DIGIT(cur)) {
                    302:            if (uri != NULL)
                    303:                uri->port = uri->port * 10 + (*cur - '0');
                    304:            cur++;
                    305:        }
                    306:        *str = cur;
                    307:        return(0);
                    308:     }
                    309:     return(1);
                    310: }
                    311: 
                    312: /**
                    313:  * xmlParse3986Userinfo:
                    314:  * @uri:  pointer to an URI structure
                    315:  * @str:  the string to analyze
                    316:  *
                    317:  * Parse an user informations part and fills in the appropriate fields
                    318:  * of the @uri structure
                    319:  *
                    320:  * userinfo      = *( unreserved / pct-encoded / sub-delims / ":" )
                    321:  *
                    322:  * Returns 0 or the error code
                    323:  */
                    324: static int
                    325: xmlParse3986Userinfo(xmlURIPtr uri, const char **str)
                    326: {
                    327:     const char *cur;
                    328: 
                    329:     cur = *str;
                    330:     while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) ||
                    331:            ISA_SUB_DELIM(cur) || (*cur == ':'))
                    332:        NEXT(cur);
                    333:     if (*cur == '@') {
                    334:        if (uri != NULL) {
                    335:            if (uri->user != NULL) xmlFree(uri->user);
                    336:            if (uri->cleanup & 2)
                    337:                uri->user = STRNDUP(*str, cur - *str);
                    338:            else
                    339:                uri->user = xmlURIUnescapeString(*str, cur - *str, NULL);
                    340:        }
                    341:        *str = cur;
                    342:        return(0);
                    343:     }
                    344:     return(1);
                    345: }
                    346: 
                    347: /**
                    348:  * xmlParse3986DecOctet:
                    349:  * @str:  the string to analyze
                    350:  *
                    351:  *    dec-octet     = DIGIT                 ; 0-9
                    352:  *                  / %x31-39 DIGIT         ; 10-99
                    353:  *                  / "1" 2DIGIT            ; 100-199
                    354:  *                  / "2" %x30-34 DIGIT     ; 200-249
                    355:  *                  / "25" %x30-35          ; 250-255
                    356:  *
                    357:  * Skip a dec-octet.
                    358:  *
                    359:  * Returns 0 if found and skipped, 1 otherwise
                    360:  */
                    361: static int
                    362: xmlParse3986DecOctet(const char **str) {
                    363:     const char *cur = *str;
                    364: 
                    365:     if (!(ISA_DIGIT(cur)))
                    366:         return(1);
                    367:     if (!ISA_DIGIT(cur+1))
                    368:        cur++;
                    369:     else if ((*cur != '0') && (ISA_DIGIT(cur + 1)) && (!ISA_DIGIT(cur+2)))
                    370:        cur += 2;
                    371:     else if ((*cur == '1') && (ISA_DIGIT(cur + 1)) && (ISA_DIGIT(cur + 2)))
                    372:        cur += 3;
                    373:     else if ((*cur == '2') && (*(cur + 1) >= '0') &&
                    374:             (*(cur + 1) <= '4') && (ISA_DIGIT(cur + 2)))
                    375:        cur += 3;
                    376:     else if ((*cur == '2') && (*(cur + 1) == '5') &&
                    377:             (*(cur + 2) >= '0') && (*(cur + 1) <= '5'))
                    378:        cur += 3;
                    379:     else
                    380:         return(1);
                    381:     *str = cur;
                    382:     return(0);
                    383: }
                    384: /**
                    385:  * xmlParse3986Host:
                    386:  * @uri:  pointer to an URI structure
                    387:  * @str:  the string to analyze
                    388:  *
                    389:  * Parse an host part and fills in the appropriate fields
                    390:  * of the @uri structure
                    391:  *
                    392:  * host          = IP-literal / IPv4address / reg-name
                    393:  * IP-literal    = "[" ( IPv6address / IPvFuture  ) "]"
                    394:  * IPv4address   = dec-octet "." dec-octet "." dec-octet "." dec-octet
                    395:  * reg-name      = *( unreserved / pct-encoded / sub-delims )
                    396:  *
                    397:  * Returns 0 or the error code
                    398:  */
                    399: static int
                    400: xmlParse3986Host(xmlURIPtr uri, const char **str)
                    401: {
                    402:     const char *cur = *str;
                    403:     const char *host;
                    404: 
                    405:     host = cur;
                    406:     /*
                    407:      * IPv6 and future adressing scheme are enclosed between brackets
                    408:      */
                    409:     if (*cur == '[') {
                    410:         cur++;
                    411:        while ((*cur != ']') && (*cur != 0))
                    412:            cur++;
                    413:        if (*cur != ']')
                    414:            return(1);
                    415:        cur++;
                    416:        goto found;
                    417:     }
                    418:     /*
                    419:      * try to parse an IPv4
                    420:      */
                    421:     if (ISA_DIGIT(cur)) {
                    422:         if (xmlParse3986DecOctet(&cur) != 0)
                    423:            goto not_ipv4;
                    424:        if (*cur != '.')
                    425:            goto not_ipv4;
                    426:        cur++;
                    427:         if (xmlParse3986DecOctet(&cur) != 0)
                    428:            goto not_ipv4;
                    429:        if (*cur != '.')
                    430:            goto not_ipv4;
                    431:         if (xmlParse3986DecOctet(&cur) != 0)
                    432:            goto not_ipv4;
                    433:        if (*cur != '.')
                    434:            goto not_ipv4;
                    435:         if (xmlParse3986DecOctet(&cur) != 0)
                    436:            goto not_ipv4;
                    437:        goto found;
                    438: not_ipv4:
                    439:         cur = *str;
                    440:     }
                    441:     /*
                    442:      * then this should be a hostname which can be empty
                    443:      */
                    444:     while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur))
                    445:         NEXT(cur);
                    446: found:
                    447:     if (uri != NULL) {
                    448:        if (uri->authority != NULL) xmlFree(uri->authority);
                    449:        uri->authority = NULL;
                    450:        if (uri->server != NULL) xmlFree(uri->server);
                    451:        if (cur != host) {
                    452:            if (uri->cleanup & 2)
                    453:                uri->server = STRNDUP(host, cur - host);
                    454:            else
                    455:                uri->server = xmlURIUnescapeString(host, cur - host, NULL);
                    456:        } else
                    457:            uri->server = NULL;
                    458:     }
                    459:     *str = cur;
                    460:     return(0);
                    461: }
                    462: 
                    463: /**
                    464:  * xmlParse3986Authority:
                    465:  * @uri:  pointer to an URI structure
                    466:  * @str:  the string to analyze
                    467:  *
                    468:  * Parse an authority part and fills in the appropriate fields
                    469:  * of the @uri structure
                    470:  *
                    471:  * authority     = [ userinfo "@" ] host [ ":" port ]
                    472:  *
                    473:  * Returns 0 or the error code
                    474:  */
                    475: static int
                    476: xmlParse3986Authority(xmlURIPtr uri, const char **str)
                    477: {
                    478:     const char *cur;
                    479:     int ret;
                    480: 
                    481:     cur = *str;
                    482:     /*
                    483:      * try to parse an userinfo and check for the trailing @
                    484:      */
                    485:     ret = xmlParse3986Userinfo(uri, &cur);
                    486:     if ((ret != 0) || (*cur != '@'))
                    487:         cur = *str;
                    488:     else
                    489:         cur++;
                    490:     ret = xmlParse3986Host(uri, &cur);
                    491:     if (ret != 0) return(ret);
                    492:     if (*cur == ':') {
                    493:         cur++;
                    494:         ret = xmlParse3986Port(uri, &cur);
                    495:        if (ret != 0) return(ret);
                    496:     }
                    497:     *str = cur;
                    498:     return(0);
                    499: }
                    500: 
                    501: /**
                    502:  * xmlParse3986Segment:
                    503:  * @str:  the string to analyze
                    504:  * @forbid: an optional forbidden character
                    505:  * @empty: allow an empty segment
                    506:  *
                    507:  * Parse a segment and fills in the appropriate fields
                    508:  * of the @uri structure
                    509:  *
                    510:  * segment       = *pchar
                    511:  * segment-nz    = 1*pchar
                    512:  * segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
                    513:  *               ; non-zero-length segment without any colon ":"
                    514:  *
                    515:  * Returns 0 or the error code
                    516:  */
                    517: static int
                    518: xmlParse3986Segment(const char **str, char forbid, int empty)
                    519: {
                    520:     const char *cur;
                    521: 
                    522:     cur = *str;
                    523:     if (!ISA_PCHAR(cur)) {
                    524:         if (empty)
                    525:            return(0);
                    526:        return(1);
                    527:     }
                    528:     while (ISA_PCHAR(cur) && (*cur != forbid))
                    529:         NEXT(cur);
                    530:     *str = cur;
                    531:     return (0);
                    532: }
                    533: 
                    534: /**
                    535:  * xmlParse3986PathAbEmpty:
                    536:  * @uri:  pointer to an URI structure
                    537:  * @str:  the string to analyze
                    538:  *
                    539:  * Parse an path absolute or empty and fills in the appropriate fields
                    540:  * of the @uri structure
                    541:  *
                    542:  * path-abempty  = *( "/" segment )
                    543:  *
                    544:  * Returns 0 or the error code
                    545:  */
                    546: static int
                    547: xmlParse3986PathAbEmpty(xmlURIPtr uri, const char **str)
                    548: {
                    549:     const char *cur;
                    550:     int ret;
                    551: 
                    552:     cur = *str;
                    553: 
                    554:     while (*cur == '/') {
                    555:         cur++;
                    556:        ret = xmlParse3986Segment(&cur, 0, 1);
                    557:        if (ret != 0) return(ret);
                    558:     }
                    559:     if (uri != NULL) {
                    560:        if (uri->path != NULL) xmlFree(uri->path);
                    561:         if (*str != cur) {
                    562:             if (uri->cleanup & 2)
                    563:                 uri->path = STRNDUP(*str, cur - *str);
                    564:             else
                    565:                 uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
                    566:         } else {
                    567:             uri->path = NULL;
                    568:         }
                    569:     }
                    570:     *str = cur;
                    571:     return (0);
                    572: }
                    573: 
                    574: /**
                    575:  * xmlParse3986PathAbsolute:
                    576:  * @uri:  pointer to an URI structure
                    577:  * @str:  the string to analyze
                    578:  *
                    579:  * Parse an path absolute and fills in the appropriate fields
                    580:  * of the @uri structure
                    581:  *
                    582:  * path-absolute = "/" [ segment-nz *( "/" segment ) ]
                    583:  *
                    584:  * Returns 0 or the error code
                    585:  */
                    586: static int
                    587: xmlParse3986PathAbsolute(xmlURIPtr uri, const char **str)
                    588: {
                    589:     const char *cur;
                    590:     int ret;
                    591: 
                    592:     cur = *str;
                    593: 
                    594:     if (*cur != '/')
                    595:         return(1);
                    596:     cur++;
                    597:     ret = xmlParse3986Segment(&cur, 0, 0);
                    598:     if (ret == 0) {
                    599:        while (*cur == '/') {
                    600:            cur++;
                    601:            ret = xmlParse3986Segment(&cur, 0, 1);
                    602:            if (ret != 0) return(ret);
                    603:        }
                    604:     }
                    605:     if (uri != NULL) {
                    606:        if (uri->path != NULL) xmlFree(uri->path);
                    607:         if (cur != *str) {
                    608:             if (uri->cleanup & 2)
                    609:                 uri->path = STRNDUP(*str, cur - *str);
                    610:             else
                    611:                 uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
                    612:         } else {
                    613:             uri->path = NULL;
                    614:         }
                    615:     }
                    616:     *str = cur;
                    617:     return (0);
                    618: }
                    619: 
                    620: /**
                    621:  * xmlParse3986PathRootless:
                    622:  * @uri:  pointer to an URI structure
                    623:  * @str:  the string to analyze
                    624:  *
                    625:  * Parse an path without root and fills in the appropriate fields
                    626:  * of the @uri structure
                    627:  *
                    628:  * path-rootless = segment-nz *( "/" segment )
                    629:  *
                    630:  * Returns 0 or the error code
                    631:  */
                    632: static int
                    633: xmlParse3986PathRootless(xmlURIPtr uri, const char **str)
                    634: {
                    635:     const char *cur;
                    636:     int ret;
                    637: 
                    638:     cur = *str;
                    639: 
                    640:     ret = xmlParse3986Segment(&cur, 0, 0);
                    641:     if (ret != 0) return(ret);
                    642:     while (*cur == '/') {
                    643:         cur++;
                    644:        ret = xmlParse3986Segment(&cur, 0, 1);
                    645:        if (ret != 0) return(ret);
                    646:     }
                    647:     if (uri != NULL) {
                    648:        if (uri->path != NULL) xmlFree(uri->path);
                    649:         if (cur != *str) {
                    650:             if (uri->cleanup & 2)
                    651:                 uri->path = STRNDUP(*str, cur - *str);
                    652:             else
                    653:                 uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
                    654:         } else {
                    655:             uri->path = NULL;
                    656:         }
                    657:     }
                    658:     *str = cur;
                    659:     return (0);
                    660: }
                    661: 
                    662: /**
                    663:  * xmlParse3986PathNoScheme:
                    664:  * @uri:  pointer to an URI structure
                    665:  * @str:  the string to analyze
                    666:  *
                    667:  * Parse an path which is not a scheme and fills in the appropriate fields
                    668:  * of the @uri structure
                    669:  *
                    670:  * path-noscheme = segment-nz-nc *( "/" segment )
                    671:  *
                    672:  * Returns 0 or the error code
                    673:  */
                    674: static int
                    675: xmlParse3986PathNoScheme(xmlURIPtr uri, const char **str)
                    676: {
                    677:     const char *cur;
                    678:     int ret;
                    679: 
                    680:     cur = *str;
                    681: 
                    682:     ret = xmlParse3986Segment(&cur, ':', 0);
                    683:     if (ret != 0) return(ret);
                    684:     while (*cur == '/') {
                    685:         cur++;
                    686:        ret = xmlParse3986Segment(&cur, 0, 1);
                    687:        if (ret != 0) return(ret);
                    688:     }
                    689:     if (uri != NULL) {
                    690:        if (uri->path != NULL) xmlFree(uri->path);
                    691:         if (cur != *str) {
                    692:             if (uri->cleanup & 2)
                    693:                 uri->path = STRNDUP(*str, cur - *str);
                    694:             else
                    695:                 uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
                    696:         } else {
                    697:             uri->path = NULL;
                    698:         }
                    699:     }
                    700:     *str = cur;
                    701:     return (0);
                    702: }
                    703: 
                    704: /**
                    705:  * xmlParse3986HierPart:
                    706:  * @uri:  pointer to an URI structure
                    707:  * @str:  the string to analyze
                    708:  *
                    709:  * Parse an hierarchical part and fills in the appropriate fields
                    710:  * of the @uri structure
                    711:  *
                    712:  * hier-part     = "//" authority path-abempty
                    713:  *                / path-absolute
                    714:  *                / path-rootless
                    715:  *                / path-empty
                    716:  *
                    717:  * Returns 0 or the error code
                    718:  */
                    719: static int
                    720: xmlParse3986HierPart(xmlURIPtr uri, const char **str)
                    721: {
                    722:     const char *cur;
                    723:     int ret;
                    724: 
                    725:     cur = *str;
                    726: 
                    727:     if ((*cur == '/') && (*(cur + 1) == '/')) {
                    728:         cur += 2;
                    729:        ret = xmlParse3986Authority(uri, &cur);
                    730:        if (ret != 0) return(ret);
                    731:        ret = xmlParse3986PathAbEmpty(uri, &cur);
                    732:        if (ret != 0) return(ret);
                    733:        *str = cur;
                    734:        return(0);
                    735:     } else if (*cur == '/') {
                    736:         ret = xmlParse3986PathAbsolute(uri, &cur);
                    737:        if (ret != 0) return(ret);
                    738:     } else if (ISA_PCHAR(cur)) {
                    739:         ret = xmlParse3986PathRootless(uri, &cur);
                    740:        if (ret != 0) return(ret);
                    741:     } else {
                    742:        /* path-empty is effectively empty */
                    743:        if (uri != NULL) {
                    744:            if (uri->path != NULL) xmlFree(uri->path);
                    745:            uri->path = NULL;
                    746:        }
                    747:     }
                    748:     *str = cur;
                    749:     return (0);
                    750: }
                    751: 
                    752: /**
                    753:  * xmlParse3986RelativeRef:
                    754:  * @uri:  pointer to an URI structure
                    755:  * @str:  the string to analyze
                    756:  *
                    757:  * Parse an URI string and fills in the appropriate fields
                    758:  * of the @uri structure
                    759:  *
                    760:  * relative-ref  = relative-part [ "?" query ] [ "#" fragment ]
                    761:  * relative-part = "//" authority path-abempty
                    762:  *               / path-absolute
                    763:  *               / path-noscheme
                    764:  *               / path-empty
                    765:  *
                    766:  * Returns 0 or the error code
                    767:  */
                    768: static int
                    769: xmlParse3986RelativeRef(xmlURIPtr uri, const char *str) {
                    770:     int ret;
                    771: 
                    772:     if ((*str == '/') && (*(str + 1) == '/')) {
                    773:         str += 2;
                    774:        ret = xmlParse3986Authority(uri, &str);
                    775:        if (ret != 0) return(ret);
                    776:        ret = xmlParse3986PathAbEmpty(uri, &str);
                    777:        if (ret != 0) return(ret);
                    778:     } else if (*str == '/') {
                    779:        ret = xmlParse3986PathAbsolute(uri, &str);
                    780:        if (ret != 0) return(ret);
                    781:     } else if (ISA_PCHAR(str)) {
                    782:         ret = xmlParse3986PathNoScheme(uri, &str);
                    783:        if (ret != 0) return(ret);
                    784:     } else {
                    785:        /* path-empty is effectively empty */
                    786:        if (uri != NULL) {
                    787:            if (uri->path != NULL) xmlFree(uri->path);
                    788:            uri->path = NULL;
                    789:        }
                    790:     }
                    791: 
                    792:     if (*str == '?') {
                    793:        str++;
                    794:        ret = xmlParse3986Query(uri, &str);
                    795:        if (ret != 0) return(ret);
                    796:     }
                    797:     if (*str == '#') {
                    798:        str++;
                    799:        ret = xmlParse3986Fragment(uri, &str);
                    800:        if (ret != 0) return(ret);
                    801:     }
                    802:     if (*str != 0) {
                    803:        xmlCleanURI(uri);
                    804:        return(1);
                    805:     }
                    806:     return(0);
                    807: }
                    808: 
                    809: 
                    810: /**
                    811:  * xmlParse3986URI:
                    812:  * @uri:  pointer to an URI structure
                    813:  * @str:  the string to analyze
                    814:  *
                    815:  * Parse an URI string and fills in the appropriate fields
                    816:  * of the @uri structure
                    817:  *
                    818:  * scheme ":" hier-part [ "?" query ] [ "#" fragment ]
                    819:  *
                    820:  * Returns 0 or the error code
                    821:  */
                    822: static int
                    823: xmlParse3986URI(xmlURIPtr uri, const char *str) {
                    824:     int ret;
                    825: 
                    826:     ret = xmlParse3986Scheme(uri, &str);
                    827:     if (ret != 0) return(ret);
                    828:     if (*str != ':') {
                    829:        return(1);
                    830:     }
                    831:     str++;
                    832:     ret = xmlParse3986HierPart(uri, &str);
                    833:     if (ret != 0) return(ret);
                    834:     if (*str == '?') {
                    835:        str++;
                    836:        ret = xmlParse3986Query(uri, &str);
                    837:        if (ret != 0) return(ret);
                    838:     }
                    839:     if (*str == '#') {
                    840:        str++;
                    841:        ret = xmlParse3986Fragment(uri, &str);
                    842:        if (ret != 0) return(ret);
                    843:     }
                    844:     if (*str != 0) {
                    845:        xmlCleanURI(uri);
                    846:        return(1);
                    847:     }
                    848:     return(0);
                    849: }
                    850: 
                    851: /**
                    852:  * xmlParse3986URIReference:
                    853:  * @uri:  pointer to an URI structure
                    854:  * @str:  the string to analyze
                    855:  *
                    856:  * Parse an URI reference string and fills in the appropriate fields
                    857:  * of the @uri structure
                    858:  *
                    859:  * URI-reference = URI / relative-ref
                    860:  *
                    861:  * Returns 0 or the error code
                    862:  */
                    863: static int
                    864: xmlParse3986URIReference(xmlURIPtr uri, const char *str) {
                    865:     int ret;
                    866: 
                    867:     if (str == NULL)
                    868:        return(-1);
                    869:     xmlCleanURI(uri);
                    870: 
                    871:     /*
                    872:      * Try first to parse absolute refs, then fallback to relative if
                    873:      * it fails.
                    874:      */
                    875:     ret = xmlParse3986URI(uri, str);
                    876:     if (ret != 0) {
                    877:        xmlCleanURI(uri);
                    878:         ret = xmlParse3986RelativeRef(uri, str);
                    879:        if (ret != 0) {
                    880:            xmlCleanURI(uri);
                    881:            return(ret);
                    882:        }
                    883:     }
                    884:     return(0);
                    885: }
                    886: 
                    887: /**
                    888:  * xmlParseURI:
                    889:  * @str:  the URI string to analyze
                    890:  *
                    891:  * Parse an URI based on RFC 3986
                    892:  *
                    893:  * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
                    894:  *
                    895:  * Returns a newly built xmlURIPtr or NULL in case of error
                    896:  */
                    897: xmlURIPtr
                    898: xmlParseURI(const char *str) {
                    899:     xmlURIPtr uri;
                    900:     int ret;
                    901: 
                    902:     if (str == NULL)
                    903:        return(NULL);
                    904:     uri = xmlCreateURI();
                    905:     if (uri != NULL) {
                    906:        ret = xmlParse3986URIReference(uri, str);
                    907:         if (ret) {
                    908:            xmlFreeURI(uri);
                    909:            return(NULL);
                    910:        }
                    911:     }
                    912:     return(uri);
                    913: }
                    914: 
                    915: /**
                    916:  * xmlParseURIReference:
                    917:  * @uri:  pointer to an URI structure
                    918:  * @str:  the string to analyze
                    919:  *
                    920:  * Parse an URI reference string based on RFC 3986 and fills in the
                    921:  * appropriate fields of the @uri structure
                    922:  *
                    923:  * URI-reference = URI / relative-ref
                    924:  *
                    925:  * Returns 0 or the error code
                    926:  */
                    927: int
                    928: xmlParseURIReference(xmlURIPtr uri, const char *str) {
                    929:     return(xmlParse3986URIReference(uri, str));
                    930: }
                    931: 
                    932: /**
                    933:  * xmlParseURIRaw:
                    934:  * @str:  the URI string to analyze
                    935:  * @raw:  if 1 unescaping of URI pieces are disabled
                    936:  *
                    937:  * Parse an URI but allows to keep intact the original fragments.
                    938:  *
                    939:  * URI-reference = URI / relative-ref
                    940:  *
                    941:  * Returns a newly built xmlURIPtr or NULL in case of error
                    942:  */
                    943: xmlURIPtr
                    944: xmlParseURIRaw(const char *str, int raw) {
                    945:     xmlURIPtr uri;
                    946:     int ret;
                    947: 
                    948:     if (str == NULL)
                    949:        return(NULL);
                    950:     uri = xmlCreateURI();
                    951:     if (uri != NULL) {
                    952:         if (raw) {
                    953:            uri->cleanup |= 2;
                    954:        }
                    955:        ret = xmlParseURIReference(uri, str);
                    956:         if (ret) {
                    957:            xmlFreeURI(uri);
                    958:            return(NULL);
                    959:        }
                    960:     }
                    961:     return(uri);
                    962: }
                    963: 
                    964: /************************************************************************
                    965:  *                                                                     *
                    966:  *                     Generic URI structure functions                 *
                    967:  *                                                                     *
                    968:  ************************************************************************/
                    969: 
                    970: /**
                    971:  * xmlCreateURI:
                    972:  *
                    973:  * Simply creates an empty xmlURI
                    974:  *
                    975:  * Returns the new structure or NULL in case of error
                    976:  */
                    977: xmlURIPtr
                    978: xmlCreateURI(void) {
                    979:     xmlURIPtr ret;
                    980: 
                    981:     ret = (xmlURIPtr) xmlMalloc(sizeof(xmlURI));
                    982:     if (ret == NULL) {
                    983:        xmlGenericError(xmlGenericErrorContext,
                    984:                "xmlCreateURI: out of memory\n");
                    985:        return(NULL);
                    986:     }
                    987:     memset(ret, 0, sizeof(xmlURI));
                    988:     return(ret);
                    989: }
                    990: 
                    991: /**
                    992:  * xmlSaveUri:
                    993:  * @uri:  pointer to an xmlURI
                    994:  *
                    995:  * Save the URI as an escaped string
                    996:  *
                    997:  * Returns a new string (to be deallocated by caller)
                    998:  */
                    999: xmlChar *
                   1000: xmlSaveUri(xmlURIPtr uri) {
                   1001:     xmlChar *ret = NULL;
                   1002:     xmlChar *temp;
                   1003:     const char *p;
                   1004:     int len;
                   1005:     int max;
                   1006: 
                   1007:     if (uri == NULL) return(NULL);
                   1008: 
                   1009: 
                   1010:     max = 80;
                   1011:     ret = (xmlChar *) xmlMallocAtomic((max + 1) * sizeof(xmlChar));
                   1012:     if (ret == NULL) {
                   1013:        xmlGenericError(xmlGenericErrorContext,
                   1014:                "xmlSaveUri: out of memory\n");
                   1015:        return(NULL);
                   1016:     }
                   1017:     len = 0;
                   1018: 
                   1019:     if (uri->scheme != NULL) {
                   1020:        p = uri->scheme;
                   1021:        while (*p != 0) {
                   1022:            if (len >= max) {
                   1023:                max *= 2;
                   1024:                temp = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
                   1025:                if (temp == NULL) {
                   1026:                    xmlGenericError(xmlGenericErrorContext,
                   1027:                            "xmlSaveUri: out of memory\n");
                   1028:                    xmlFree(ret);
                   1029:                    return(NULL);
                   1030:                }
                   1031:                ret = temp;
                   1032:            }
                   1033:            ret[len++] = *p++;
                   1034:        }
                   1035:        if (len >= max) {
                   1036:            max *= 2;
                   1037:            temp = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
                   1038:            if (temp == NULL) {
                   1039:                xmlGenericError(xmlGenericErrorContext,
                   1040:                        "xmlSaveUri: out of memory\n");
                   1041:                xmlFree(ret);
                   1042:                return(NULL);
                   1043:            }
                   1044:            ret = temp;
                   1045:        }
                   1046:        ret[len++] = ':';
                   1047:     }
                   1048:     if (uri->opaque != NULL) {
                   1049:        p = uri->opaque;
                   1050:        while (*p != 0) {
                   1051:            if (len + 3 >= max) {
                   1052:                max *= 2;
                   1053:                temp = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
                   1054:                if (temp == NULL) {
                   1055:                    xmlGenericError(xmlGenericErrorContext,
                   1056:                            "xmlSaveUri: out of memory\n");
                   1057:                    xmlFree(ret);
                   1058:                    return(NULL);
                   1059:                }
                   1060:                ret = temp;
                   1061:            }
                   1062:            if (IS_RESERVED(*(p)) || IS_UNRESERVED(*(p)))
                   1063:                ret[len++] = *p++;
                   1064:            else {
                   1065:                int val = *(unsigned char *)p++;
                   1066:                int hi = val / 0x10, lo = val % 0x10;
                   1067:                ret[len++] = '%';
                   1068:                ret[len++] = hi + (hi > 9? 'A'-10 : '0');
                   1069:                ret[len++] = lo + (lo > 9? 'A'-10 : '0');
                   1070:            }
                   1071:        }
                   1072:     } else {
                   1073:        if (uri->server != NULL) {
                   1074:            if (len + 3 >= max) {
                   1075:                max *= 2;
                   1076:                temp = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
                   1077:                if (temp == NULL) {
                   1078:                    xmlGenericError(xmlGenericErrorContext,
                   1079:                            "xmlSaveUri: out of memory\n");
                   1080:                   xmlFree(ret);  
                   1081:                    return(NULL);
                   1082:                }
                   1083:                ret = temp;
                   1084:            }
                   1085:            ret[len++] = '/';
                   1086:            ret[len++] = '/';
                   1087:            if (uri->user != NULL) {
                   1088:                p = uri->user;
                   1089:                while (*p != 0) {
                   1090:                    if (len + 3 >= max) {
                   1091:                        max *= 2;
                   1092:                        temp = (xmlChar *) xmlRealloc(ret,
                   1093:                                (max + 1) * sizeof(xmlChar));
                   1094:                        if (temp == NULL) {
                   1095:                            xmlGenericError(xmlGenericErrorContext,
                   1096:                                    "xmlSaveUri: out of memory\n");
                   1097:                            xmlFree(ret);
                   1098:                            return(NULL);
                   1099:                        }
                   1100:                        ret = temp;
                   1101:                    }
                   1102:                    if ((IS_UNRESERVED(*(p))) ||
                   1103:                        ((*(p) == ';')) || ((*(p) == ':')) ||
                   1104:                        ((*(p) == '&')) || ((*(p) == '=')) ||
                   1105:                        ((*(p) == '+')) || ((*(p) == '$')) ||
                   1106:                        ((*(p) == ',')))
                   1107:                        ret[len++] = *p++;
                   1108:                    else {
                   1109:                        int val = *(unsigned char *)p++;
                   1110:                        int hi = val / 0x10, lo = val % 0x10;
                   1111:                        ret[len++] = '%';
                   1112:                        ret[len++] = hi + (hi > 9? 'A'-10 : '0');
                   1113:                        ret[len++] = lo + (lo > 9? 'A'-10 : '0');
                   1114:                    }
                   1115:                }
                   1116:                if (len + 3 >= max) {
                   1117:                    max *= 2;
                   1118:                    temp = (xmlChar *) xmlRealloc(ret,
                   1119:                            (max + 1) * sizeof(xmlChar));
                   1120:                    if (temp == NULL) {
                   1121:                        xmlGenericError(xmlGenericErrorContext,
                   1122:                                "xmlSaveUri: out of memory\n");
                   1123:                        xmlFree(ret);
                   1124:                        return(NULL);
                   1125:                    }
                   1126:                    ret = temp;
                   1127:                }
                   1128:                ret[len++] = '@';
                   1129:            }
                   1130:            p = uri->server;
                   1131:            while (*p != 0) {
                   1132:                if (len >= max) {
                   1133:                    max *= 2;
                   1134:                    temp = (xmlChar *) xmlRealloc(ret,
                   1135:                            (max + 1) * sizeof(xmlChar));
                   1136:                    if (temp == NULL) {
                   1137:                        xmlGenericError(xmlGenericErrorContext,
                   1138:                                "xmlSaveUri: out of memory\n");
                   1139:                        xmlFree(ret);
                   1140:                        return(NULL);
                   1141:                    }
                   1142:                    ret = temp;
                   1143:                }
                   1144:                ret[len++] = *p++;
                   1145:            }
                   1146:            if (uri->port > 0) {
                   1147:                if (len + 10 >= max) {
                   1148:                    max *= 2;
                   1149:                    temp = (xmlChar *) xmlRealloc(ret,
                   1150:                            (max + 1) * sizeof(xmlChar));
                   1151:                    if (temp == NULL) {
                   1152:                        xmlGenericError(xmlGenericErrorContext,
                   1153:                                "xmlSaveUri: out of memory\n");
                   1154:                      xmlFree(ret);
                   1155:                        return(NULL);
                   1156:                    }
                   1157:                    ret = temp;
                   1158:                }
                   1159:                len += snprintf((char *) &ret[len], max - len, ":%d", uri->port);
                   1160:            }
                   1161:        } else if (uri->authority != NULL) {
                   1162:            if (len + 3 >= max) {
                   1163:                max *= 2;
                   1164:                temp = (xmlChar *) xmlRealloc(ret,
                   1165:                        (max + 1) * sizeof(xmlChar));
                   1166:                if (temp == NULL) {
                   1167:                        xmlGenericError(xmlGenericErrorContext,
                   1168:                                "xmlSaveUri: out of memory\n");
                   1169:                      xmlFree(ret);
                   1170:                        return(NULL);
                   1171:                    }
                   1172:                    ret = temp;
                   1173:            }
                   1174:            ret[len++] = '/';
                   1175:            ret[len++] = '/';
                   1176:            p = uri->authority;
                   1177:            while (*p != 0) {
                   1178:                if (len + 3 >= max) {
                   1179:                    max *= 2;
                   1180:                    temp = (xmlChar *) xmlRealloc(ret,
                   1181:                            (max + 1) * sizeof(xmlChar));
                   1182:                    if (temp == NULL) {
                   1183:                        xmlGenericError(xmlGenericErrorContext,
                   1184:                                "xmlSaveUri: out of memory\n");
                   1185:                      xmlFree(ret);
                   1186:                        return(NULL);
                   1187:                    }
                   1188:                    ret = temp;
                   1189:                }
                   1190:                if ((IS_UNRESERVED(*(p))) ||
                   1191:                     ((*(p) == '$')) || ((*(p) == ',')) || ((*(p) == ';')) ||
                   1192:                     ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) ||
                   1193:                     ((*(p) == '=')) || ((*(p) == '+')))
                   1194:                    ret[len++] = *p++;
                   1195:                else {
                   1196:                    int val = *(unsigned char *)p++;
                   1197:                    int hi = val / 0x10, lo = val % 0x10;
                   1198:                    ret[len++] = '%';
                   1199:                    ret[len++] = hi + (hi > 9? 'A'-10 : '0');
                   1200:                    ret[len++] = lo + (lo > 9? 'A'-10 : '0');
                   1201:                }
                   1202:            }
                   1203:        } else if (uri->scheme != NULL) {
                   1204:            if (len + 3 >= max) {
                   1205:                max *= 2;
                   1206:                temp = (xmlChar *) xmlRealloc(ret,
                   1207:                        (max + 1) * sizeof(xmlChar));
                   1208:                if (temp == NULL) {
                   1209:                        xmlGenericError(xmlGenericErrorContext,
                   1210:                                "xmlSaveUri: out of memory\n");
                   1211:                      xmlFree(ret);
                   1212:                        return(NULL);
                   1213:                    }
                   1214:                    ret = temp;
                   1215:            }
                   1216:            ret[len++] = '/';
                   1217:            ret[len++] = '/';
                   1218:        }
                   1219:        if (uri->path != NULL) {
                   1220:            p = uri->path;
                   1221:            /*
                   1222:             * the colon in file:///d: should not be escaped or
                   1223:             * Windows accesses fail later.
                   1224:             */
                   1225:            if ((uri->scheme != NULL) &&
                   1226:                (p[0] == '/') &&
                   1227:                (((p[1] >= 'a') && (p[1] <= 'z')) ||
                   1228:                 ((p[1] >= 'A') && (p[1] <= 'Z'))) &&
                   1229:                (p[2] == ':') &&
                   1230:                (xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) {
                   1231:                if (len + 3 >= max) {
                   1232:                    max *= 2;
                   1233:                    ret = (xmlChar *) xmlRealloc(ret,
                   1234:                            (max + 1) * sizeof(xmlChar));
                   1235:                    if (ret == NULL) {
                   1236:                        xmlGenericError(xmlGenericErrorContext,
                   1237:                                "xmlSaveUri: out of memory\n");
                   1238:                        return(NULL);
                   1239:                    }
                   1240:                }
                   1241:                ret[len++] = *p++;
                   1242:                ret[len++] = *p++;
                   1243:                ret[len++] = *p++;
                   1244:            }
                   1245:            while (*p != 0) {
                   1246:                if (len + 3 >= max) {
                   1247:                    max *= 2;
                   1248:                    temp = (xmlChar *) xmlRealloc(ret,
                   1249:                            (max + 1) * sizeof(xmlChar));
                   1250:                    if (temp == NULL) {
                   1251:                        xmlGenericError(xmlGenericErrorContext,
                   1252:                                "xmlSaveUri: out of memory\n");
                   1253:                      xmlFree(ret);
                   1254:                        return(NULL);
                   1255:                    }
                   1256:                    ret = temp;
                   1257:                }
                   1258:                if ((IS_UNRESERVED(*(p))) || ((*(p) == '/')) ||
                   1259:                     ((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) ||
                   1260:                    ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||
                   1261:                    ((*(p) == ',')))
                   1262:                    ret[len++] = *p++;
                   1263:                else {
                   1264:                    int val = *(unsigned char *)p++;
                   1265:                    int hi = val / 0x10, lo = val % 0x10;
                   1266:                    ret[len++] = '%';
                   1267:                    ret[len++] = hi + (hi > 9? 'A'-10 : '0');
                   1268:                    ret[len++] = lo + (lo > 9? 'A'-10 : '0');
                   1269:                }
                   1270:            }
                   1271:        }
                   1272:        if (uri->query_raw != NULL) {
                   1273:            if (len + 1 >= max) {
                   1274:                max *= 2;
                   1275:                temp = (xmlChar *) xmlRealloc(ret,
                   1276:                        (max + 1) * sizeof(xmlChar));
                   1277:                if (temp == NULL) {
                   1278:                        xmlGenericError(xmlGenericErrorContext,
                   1279:                                "xmlSaveUri: out of memory\n");
                   1280:                      xmlFree(ret);
                   1281:                        return(NULL);
                   1282:                    }
                   1283:                    ret = temp;
                   1284:            }
                   1285:            ret[len++] = '?';
                   1286:            p = uri->query_raw;
                   1287:            while (*p != 0) {
                   1288:                if (len + 1 >= max) {
                   1289:                    max *= 2;
                   1290:                    temp = (xmlChar *) xmlRealloc(ret,
                   1291:                            (max + 1) * sizeof(xmlChar));
                   1292:                    if (temp == NULL) {
                   1293:                        xmlGenericError(xmlGenericErrorContext,
                   1294:                                "xmlSaveUri: out of memory\n");
                   1295:                      xmlFree(ret);
                   1296:                        return(NULL);
                   1297:                    }
                   1298:                    ret = temp;
                   1299:                }
                   1300:                ret[len++] = *p++;
                   1301:            }
                   1302:        } else if (uri->query != NULL) {
                   1303:            if (len + 3 >= max) {
                   1304:                max *= 2;
                   1305:                temp = (xmlChar *) xmlRealloc(ret,
                   1306:                        (max + 1) * sizeof(xmlChar));
                   1307:                if (temp == NULL) {
                   1308:                        xmlGenericError(xmlGenericErrorContext,
                   1309:                                "xmlSaveUri: out of memory\n");
                   1310:                      xmlFree(ret);
                   1311:                        return(NULL);
                   1312:                    }
                   1313:                    ret = temp;
                   1314:            }
                   1315:            ret[len++] = '?';
                   1316:            p = uri->query;
                   1317:            while (*p != 0) {
                   1318:                if (len + 3 >= max) {
                   1319:                    max *= 2;
                   1320:                    temp = (xmlChar *) xmlRealloc(ret,
                   1321:                            (max + 1) * sizeof(xmlChar));
                   1322:                    if (temp == NULL) {
                   1323:                        xmlGenericError(xmlGenericErrorContext,
                   1324:                                "xmlSaveUri: out of memory\n");
                   1325:                      xmlFree(ret);
                   1326:                        return(NULL);
                   1327:                    }
                   1328:                    ret = temp;
                   1329:                }
                   1330:                if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p)))) 
                   1331:                    ret[len++] = *p++;
                   1332:                else {
                   1333:                    int val = *(unsigned char *)p++;
                   1334:                    int hi = val / 0x10, lo = val % 0x10;
                   1335:                    ret[len++] = '%';
                   1336:                    ret[len++] = hi + (hi > 9? 'A'-10 : '0');
                   1337:                    ret[len++] = lo + (lo > 9? 'A'-10 : '0');
                   1338:                }
                   1339:            }
                   1340:        }
                   1341:     }
                   1342:     if (uri->fragment != NULL) {
                   1343:        if (len + 3 >= max) {
                   1344:            max *= 2;
                   1345:            temp = (xmlChar *) xmlRealloc(ret,
                   1346:                    (max + 1) * sizeof(xmlChar));
                   1347:            if (temp == NULL) {
                   1348:                        xmlGenericError(xmlGenericErrorContext,
                   1349:                                "xmlSaveUri: out of memory\n");
                   1350:                      xmlFree(ret);
                   1351:                        return(NULL);
                   1352:                    }
                   1353:                    ret = temp;
                   1354:        }
                   1355:        ret[len++] = '#';
                   1356:        p = uri->fragment;
                   1357:        while (*p != 0) {
                   1358:            if (len + 3 >= max) {
                   1359:                max *= 2;
                   1360:                temp = (xmlChar *) xmlRealloc(ret,
                   1361:                        (max + 1) * sizeof(xmlChar));
                   1362:                if (temp == NULL) {
                   1363:                        xmlGenericError(xmlGenericErrorContext,
                   1364:                                "xmlSaveUri: out of memory\n");
                   1365:                      xmlFree(ret);
                   1366:                        return(NULL);
                   1367:                    }
                   1368:                    ret = temp;
                   1369:            }
                   1370:            if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p)))) 
                   1371:                ret[len++] = *p++;
                   1372:            else {
                   1373:                int val = *(unsigned char *)p++;
                   1374:                int hi = val / 0x10, lo = val % 0x10;
                   1375:                ret[len++] = '%';
                   1376:                ret[len++] = hi + (hi > 9? 'A'-10 : '0');
                   1377:                ret[len++] = lo + (lo > 9? 'A'-10 : '0');
                   1378:            }
                   1379:        }
                   1380:     }
                   1381:     if (len >= max) {
                   1382:        max *= 2;
                   1383:        temp = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
                   1384:        if (temp == NULL) {
                   1385:                        xmlGenericError(xmlGenericErrorContext,
                   1386:                                "xmlSaveUri: out of memory\n");
                   1387:                      xmlFree(ret);
                   1388:                        return(NULL);
                   1389:                    }
                   1390:                    ret = temp;
                   1391:     }
                   1392:     ret[len] = 0;
                   1393:     return(ret);
                   1394: }
                   1395: 
                   1396: /**
                   1397:  * xmlPrintURI:
                   1398:  * @stream:  a FILE* for the output
                   1399:  * @uri:  pointer to an xmlURI
                   1400:  *
                   1401:  * Prints the URI in the stream @stream.
                   1402:  */
                   1403: void
                   1404: xmlPrintURI(FILE *stream, xmlURIPtr uri) {
                   1405:     xmlChar *out;
                   1406: 
                   1407:     out = xmlSaveUri(uri);
                   1408:     if (out != NULL) {
                   1409:        fprintf(stream, "%s", (char *) out);
                   1410:        xmlFree(out);
                   1411:     }
                   1412: }
                   1413: 
                   1414: /**
                   1415:  * xmlCleanURI:
                   1416:  * @uri:  pointer to an xmlURI
                   1417:  *
                   1418:  * Make sure the xmlURI struct is free of content
                   1419:  */
                   1420: static void
                   1421: xmlCleanURI(xmlURIPtr uri) {
                   1422:     if (uri == NULL) return;
                   1423: 
                   1424:     if (uri->scheme != NULL) xmlFree(uri->scheme);
                   1425:     uri->scheme = NULL;
                   1426:     if (uri->server != NULL) xmlFree(uri->server);
                   1427:     uri->server = NULL;
                   1428:     if (uri->user != NULL) xmlFree(uri->user);
                   1429:     uri->user = NULL;
                   1430:     if (uri->path != NULL) xmlFree(uri->path);
                   1431:     uri->path = NULL;
                   1432:     if (uri->fragment != NULL) xmlFree(uri->fragment);
                   1433:     uri->fragment = NULL;
                   1434:     if (uri->opaque != NULL) xmlFree(uri->opaque);
                   1435:     uri->opaque = NULL;
                   1436:     if (uri->authority != NULL) xmlFree(uri->authority);
                   1437:     uri->authority = NULL;
                   1438:     if (uri->query != NULL) xmlFree(uri->query);
                   1439:     uri->query = NULL;
                   1440:     if (uri->query_raw != NULL) xmlFree(uri->query_raw);
                   1441:     uri->query_raw = NULL;
                   1442: }
                   1443: 
                   1444: /**
                   1445:  * xmlFreeURI:
                   1446:  * @uri:  pointer to an xmlURI
                   1447:  *
                   1448:  * Free up the xmlURI struct
                   1449:  */
                   1450: void
                   1451: xmlFreeURI(xmlURIPtr uri) {
                   1452:     if (uri == NULL) return;
                   1453: 
                   1454:     if (uri->scheme != NULL) xmlFree(uri->scheme);
                   1455:     if (uri->server != NULL) xmlFree(uri->server);
                   1456:     if (uri->user != NULL) xmlFree(uri->user);
                   1457:     if (uri->path != NULL) xmlFree(uri->path);
                   1458:     if (uri->fragment != NULL) xmlFree(uri->fragment);
                   1459:     if (uri->opaque != NULL) xmlFree(uri->opaque);
                   1460:     if (uri->authority != NULL) xmlFree(uri->authority);
                   1461:     if (uri->query != NULL) xmlFree(uri->query);
                   1462:     if (uri->query_raw != NULL) xmlFree(uri->query_raw);
                   1463:     xmlFree(uri);
                   1464: }
                   1465: 
                   1466: /************************************************************************
                   1467:  *                                                                     *
                   1468:  *                     Helper functions                                *
                   1469:  *                                                                     *
                   1470:  ************************************************************************/
                   1471: 
                   1472: /**
                   1473:  * xmlNormalizeURIPath:
                   1474:  * @path:  pointer to the path string
                   1475:  *
                   1476:  * Applies the 5 normalization steps to a path string--that is, RFC 2396
                   1477:  * Section 5.2, steps 6.c through 6.g.
                   1478:  *
                   1479:  * Normalization occurs directly on the string, no new allocation is done
                   1480:  *
                   1481:  * Returns 0 or an error code
                   1482:  */
                   1483: int
                   1484: xmlNormalizeURIPath(char *path) {
                   1485:     char *cur, *out;
                   1486: 
                   1487:     if (path == NULL)
                   1488:        return(-1);
                   1489: 
                   1490:     /* Skip all initial "/" chars.  We want to get to the beginning of the
                   1491:      * first non-empty segment.
                   1492:      */
                   1493:     cur = path;
                   1494:     while (cur[0] == '/')
                   1495:       ++cur;
                   1496:     if (cur[0] == '\0')
                   1497:       return(0);
                   1498: 
                   1499:     /* Keep everything we've seen so far.  */
                   1500:     out = cur;
                   1501: 
                   1502:     /*
                   1503:      * Analyze each segment in sequence for cases (c) and (d).
                   1504:      */
                   1505:     while (cur[0] != '\0') {
                   1506:        /*
                   1507:         * c) All occurrences of "./", where "." is a complete path segment,
                   1508:         *    are removed from the buffer string.
                   1509:         */
                   1510:        if ((cur[0] == '.') && (cur[1] == '/')) {
                   1511:            cur += 2;
                   1512:            /* '//' normalization should be done at this point too */
                   1513:            while (cur[0] == '/')
                   1514:                cur++;
                   1515:            continue;
                   1516:        }
                   1517: 
                   1518:        /*
                   1519:         * d) If the buffer string ends with "." as a complete path segment,
                   1520:         *    that "." is removed.
                   1521:         */
                   1522:        if ((cur[0] == '.') && (cur[1] == '\0'))
                   1523:            break;
                   1524: 
                   1525:        /* Otherwise keep the segment.  */
                   1526:        while (cur[0] != '/') {
                   1527:             if (cur[0] == '\0')
                   1528:               goto done_cd;
                   1529:            (out++)[0] = (cur++)[0];
                   1530:        }
                   1531:        /* nomalize // */
                   1532:        while ((cur[0] == '/') && (cur[1] == '/'))
                   1533:            cur++;
                   1534: 
                   1535:         (out++)[0] = (cur++)[0];
                   1536:     }
                   1537:  done_cd:
                   1538:     out[0] = '\0';
                   1539: 
                   1540:     /* Reset to the beginning of the first segment for the next sequence.  */
                   1541:     cur = path;
                   1542:     while (cur[0] == '/')
                   1543:       ++cur;
                   1544:     if (cur[0] == '\0')
                   1545:        return(0);
                   1546: 
                   1547:     /*
                   1548:      * Analyze each segment in sequence for cases (e) and (f).
                   1549:      *
                   1550:      * e) All occurrences of "<segment>/../", where <segment> is a
                   1551:      *    complete path segment not equal to "..", are removed from the
                   1552:      *    buffer string.  Removal of these path segments is performed
                   1553:      *    iteratively, removing the leftmost matching pattern on each
                   1554:      *    iteration, until no matching pattern remains.
                   1555:      *
                   1556:      * f) If the buffer string ends with "<segment>/..", where <segment>
                   1557:      *    is a complete path segment not equal to "..", that
                   1558:      *    "<segment>/.." is removed.
                   1559:      *
                   1560:      * To satisfy the "iterative" clause in (e), we need to collapse the
                   1561:      * string every time we find something that needs to be removed.  Thus,
                   1562:      * we don't need to keep two pointers into the string: we only need a
                   1563:      * "current position" pointer.
                   1564:      */
                   1565:     while (1) {
                   1566:         char *segp, *tmp;
                   1567: 
                   1568:         /* At the beginning of each iteration of this loop, "cur" points to
                   1569:          * the first character of the segment we want to examine.
                   1570:          */
                   1571: 
                   1572:         /* Find the end of the current segment.  */
                   1573:         segp = cur;
                   1574:         while ((segp[0] != '/') && (segp[0] != '\0'))
                   1575:           ++segp;
                   1576: 
                   1577:         /* If this is the last segment, we're done (we need at least two
                   1578:          * segments to meet the criteria for the (e) and (f) cases).
                   1579:          */
                   1580:         if (segp[0] == '\0')
                   1581:           break;
                   1582: 
                   1583:         /* If the first segment is "..", or if the next segment _isn't_ "..",
                   1584:          * keep this segment and try the next one.
                   1585:          */
                   1586:         ++segp;
                   1587:         if (((cur[0] == '.') && (cur[1] == '.') && (segp == cur+3))
                   1588:             || ((segp[0] != '.') || (segp[1] != '.')
                   1589:                 || ((segp[2] != '/') && (segp[2] != '\0')))) {
                   1590:           cur = segp;
                   1591:           continue;
                   1592:         }
                   1593: 
                   1594:         /* If we get here, remove this segment and the next one and back up
                   1595:          * to the previous segment (if there is one), to implement the
                   1596:          * "iteratively" clause.  It's pretty much impossible to back up
                   1597:          * while maintaining two pointers into the buffer, so just compact
                   1598:          * the whole buffer now.
                   1599:          */
                   1600: 
                   1601:         /* If this is the end of the buffer, we're done.  */
                   1602:         if (segp[2] == '\0') {
                   1603:           cur[0] = '\0';
                   1604:           break;
                   1605:         }
                   1606:         /* Valgrind complained, strcpy(cur, segp + 3); */
                   1607:        /* string will overlap, do not use strcpy */
                   1608:        tmp = cur;
                   1609:        segp += 3;
                   1610:        while ((*tmp++ = *segp++) != 0);
                   1611: 
                   1612:         /* If there are no previous segments, then keep going from here.  */
                   1613:         segp = cur;
                   1614:         while ((segp > path) && ((--segp)[0] == '/'))
                   1615:           ;
                   1616:         if (segp == path)
                   1617:           continue;
                   1618: 
                   1619:         /* "segp" is pointing to the end of a previous segment; find it's
                   1620:          * start.  We need to back up to the previous segment and start
                   1621:          * over with that to handle things like "foo/bar/../..".  If we
                   1622:          * don't do this, then on the first pass we'll remove the "bar/..",
                   1623:          * but be pointing at the second ".." so we won't realize we can also
                   1624:          * remove the "foo/..".
                   1625:          */
                   1626:         cur = segp;
                   1627:         while ((cur > path) && (cur[-1] != '/'))
                   1628:           --cur;
                   1629:     }
                   1630:     out[0] = '\0';
                   1631: 
                   1632:     /*
                   1633:      * g) If the resulting buffer string still begins with one or more
                   1634:      *    complete path segments of "..", then the reference is
                   1635:      *    considered to be in error. Implementations may handle this
                   1636:      *    error by retaining these components in the resolved path (i.e.,
                   1637:      *    treating them as part of the final URI), by removing them from
                   1638:      *    the resolved path (i.e., discarding relative levels above the
                   1639:      *    root), or by avoiding traversal of the reference.
                   1640:      *
                   1641:      * We discard them from the final path.
                   1642:      */
                   1643:     if (path[0] == '/') {
                   1644:       cur = path;
                   1645:       while ((cur[0] == '/') && (cur[1] == '.') && (cur[2] == '.')
                   1646:              && ((cur[3] == '/') || (cur[3] == '\0')))
                   1647:        cur += 3;
                   1648: 
                   1649:       if (cur != path) {
                   1650:        out = path;
                   1651:        while (cur[0] != '\0')
                   1652:           (out++)[0] = (cur++)[0];
                   1653:        out[0] = 0;
                   1654:       }
                   1655:     }
                   1656: 
                   1657:     return(0);
                   1658: }
                   1659: 
                   1660: static int is_hex(char c) {
                   1661:     if (((c >= '0') && (c <= '9')) ||
                   1662:         ((c >= 'a') && (c <= 'f')) ||
                   1663:         ((c >= 'A') && (c <= 'F')))
                   1664:        return(1);
                   1665:     return(0);
                   1666: }
                   1667: 
                   1668: /**
                   1669:  * xmlURIUnescapeString:
                   1670:  * @str:  the string to unescape
                   1671:  * @len:   the length in bytes to unescape (or <= 0 to indicate full string)
                   1672:  * @target:  optional destination buffer
                   1673:  *
                   1674:  * Unescaping routine, but does not check that the string is an URI. The
                   1675:  * output is a direct unsigned char translation of %XX values (no encoding)
                   1676:  * Note that the length of the result can only be smaller or same size as
                   1677:  * the input string.
                   1678:  *
                   1679:  * Returns a copy of the string, but unescaped, will return NULL only in case
                   1680:  * of error
                   1681:  */
                   1682: char *
                   1683: xmlURIUnescapeString(const char *str, int len, char *target) {
                   1684:     char *ret, *out;
                   1685:     const char *in;
                   1686: 
                   1687:     if (str == NULL)
                   1688:        return(NULL);
                   1689:     if (len <= 0) len = strlen(str);
                   1690:     if (len < 0) return(NULL);
                   1691: 
                   1692:     if (target == NULL) {
                   1693:        ret = (char *) xmlMallocAtomic(len + 1);
                   1694:        if (ret == NULL) {
                   1695:            xmlGenericError(xmlGenericErrorContext,
                   1696:                    "xmlURIUnescapeString: out of memory\n");
                   1697:            return(NULL);
                   1698:        }
                   1699:     } else
                   1700:        ret = target;
                   1701:     in = str;
                   1702:     out = ret;
                   1703:     while(len > 0) {
                   1704:        if ((len > 2) && (*in == '%') && (is_hex(in[1])) && (is_hex(in[2]))) {
                   1705:            in++;
                   1706:            if ((*in >= '0') && (*in <= '9')) 
                   1707:                *out = (*in - '0');
                   1708:            else if ((*in >= 'a') && (*in <= 'f'))
                   1709:                *out = (*in - 'a') + 10;
                   1710:            else if ((*in >= 'A') && (*in <= 'F'))
                   1711:                *out = (*in - 'A') + 10;
                   1712:            in++;
                   1713:            if ((*in >= '0') && (*in <= '9')) 
                   1714:                *out = *out * 16 + (*in - '0');
                   1715:            else if ((*in >= 'a') && (*in <= 'f'))
                   1716:                *out = *out * 16 + (*in - 'a') + 10;
                   1717:            else if ((*in >= 'A') && (*in <= 'F'))
                   1718:                *out = *out * 16 + (*in - 'A') + 10;
                   1719:            in++;
                   1720:            len -= 3;
                   1721:            out++;
                   1722:        } else {
                   1723:            *out++ = *in++;
                   1724:            len--;
                   1725:        }
                   1726:     }
                   1727:     *out = 0;
                   1728:     return(ret);
                   1729: }
                   1730: 
                   1731: /**
                   1732:  * xmlURIEscapeStr:
                   1733:  * @str:  string to escape
                   1734:  * @list: exception list string of chars not to escape
                   1735:  *
                   1736:  * This routine escapes a string to hex, ignoring reserved characters (a-z)
                   1737:  * and the characters in the exception list.
                   1738:  *
                   1739:  * Returns a new escaped string or NULL in case of error.
                   1740:  */
                   1741: xmlChar *
                   1742: xmlURIEscapeStr(const xmlChar *str, const xmlChar *list) {
                   1743:     xmlChar *ret, ch;
                   1744:     xmlChar *temp;
                   1745:     const xmlChar *in;
                   1746: 
                   1747:     unsigned int len, out;
                   1748: 
                   1749:     if (str == NULL)
                   1750:        return(NULL);
                   1751:     if (str[0] == 0)
                   1752:        return(xmlStrdup(str));
                   1753:     len = xmlStrlen(str);
                   1754:     if (!(len > 0)) return(NULL);
                   1755: 
                   1756:     len += 20;
                   1757:     ret = (xmlChar *) xmlMallocAtomic(len);
                   1758:     if (ret == NULL) {
                   1759:        xmlGenericError(xmlGenericErrorContext,
                   1760:                "xmlURIEscapeStr: out of memory\n");
                   1761:        return(NULL);
                   1762:     }
                   1763:     in = (const xmlChar *) str;
                   1764:     out = 0;
                   1765:     while(*in != 0) {
                   1766:        if (len - out <= 3) {
                   1767:            len += 20;
                   1768:            temp = (xmlChar *) xmlRealloc(ret, len);
                   1769:            if (temp == NULL) {
                   1770:                xmlGenericError(xmlGenericErrorContext,
                   1771:                        "xmlURIEscapeStr: out of memory\n");
                   1772:                xmlFree(ret);
                   1773:                return(NULL);
                   1774:            }
                   1775:            ret = temp;
                   1776:        }
                   1777: 
                   1778:        ch = *in;
                   1779: 
                   1780:        if ((ch != '@') && (!IS_UNRESERVED(ch)) && (!xmlStrchr(list, ch))) {
                   1781:            unsigned char val;
                   1782:            ret[out++] = '%';
                   1783:            val = ch >> 4;
                   1784:            if (val <= 9)
                   1785:                ret[out++] = '0' + val;
                   1786:            else
                   1787:                ret[out++] = 'A' + val - 0xA;
                   1788:            val = ch & 0xF;
                   1789:            if (val <= 9)
                   1790:                ret[out++] = '0' + val;
                   1791:            else
                   1792:                ret[out++] = 'A' + val - 0xA;
                   1793:            in++;
                   1794:        } else {
                   1795:            ret[out++] = *in++;
                   1796:        }
                   1797: 
                   1798:     }
                   1799:     ret[out] = 0;
                   1800:     return(ret);
                   1801: }
                   1802: 
                   1803: /**
                   1804:  * xmlURIEscape:
                   1805:  * @str:  the string of the URI to escape
                   1806:  *
                   1807:  * Escaping routine, does not do validity checks !
                   1808:  * It will try to escape the chars needing this, but this is heuristic
                   1809:  * based it's impossible to be sure.
                   1810:  *
                   1811:  * Returns an copy of the string, but escaped
                   1812:  *
                   1813:  * 25 May 2001
                   1814:  * Uses xmlParseURI and xmlURIEscapeStr to try to escape correctly
                   1815:  * according to RFC2396.
                   1816:  *   - Carl Douglas
                   1817:  */
                   1818: xmlChar *
                   1819: xmlURIEscape(const xmlChar * str)
                   1820: {
                   1821:     xmlChar *ret, *segment = NULL;
                   1822:     xmlURIPtr uri;
                   1823:     int ret2;
                   1824: 
                   1825: #define NULLCHK(p) if(!p) { \
                   1826:                    xmlGenericError(xmlGenericErrorContext, \
                   1827:                         "xmlURIEscape: out of memory\n"); \
                   1828:                         xmlFreeURI(uri); \
                   1829:                         return NULL; } \
                   1830: 
                   1831:     if (str == NULL)
                   1832:         return (NULL);
                   1833: 
                   1834:     uri = xmlCreateURI();
                   1835:     if (uri != NULL) {
                   1836:        /*
                   1837:         * Allow escaping errors in the unescaped form
                   1838:         */
                   1839:         uri->cleanup = 1;
                   1840:         ret2 = xmlParseURIReference(uri, (const char *)str);
                   1841:         if (ret2) {
                   1842:             xmlFreeURI(uri);
                   1843:             return (NULL);
                   1844:         }
                   1845:     }
                   1846: 
                   1847:     if (!uri)
                   1848:         return NULL;
                   1849: 
                   1850:     ret = NULL;
                   1851: 
                   1852:     if (uri->scheme) {
                   1853:         segment = xmlURIEscapeStr(BAD_CAST uri->scheme, BAD_CAST "+-.");
                   1854:         NULLCHK(segment)
                   1855:         ret = xmlStrcat(ret, segment);
                   1856:         ret = xmlStrcat(ret, BAD_CAST ":");
                   1857:         xmlFree(segment);
                   1858:     }
                   1859: 
                   1860:     if (uri->authority) {
                   1861:         segment =
                   1862:             xmlURIEscapeStr(BAD_CAST uri->authority, BAD_CAST "/?;:@");
                   1863:         NULLCHK(segment)
                   1864:         ret = xmlStrcat(ret, BAD_CAST "//");
                   1865:         ret = xmlStrcat(ret, segment);
                   1866:         xmlFree(segment);
                   1867:     }
                   1868: 
                   1869:     if (uri->user) {
                   1870:         segment = xmlURIEscapeStr(BAD_CAST uri->user, BAD_CAST ";:&=+$,");
                   1871:         NULLCHK(segment)
                   1872:                ret = xmlStrcat(ret,BAD_CAST "//");     
                   1873:         ret = xmlStrcat(ret, segment);
                   1874:         ret = xmlStrcat(ret, BAD_CAST "@");
                   1875:         xmlFree(segment);
                   1876:     }
                   1877: 
                   1878:     if (uri->server) {
                   1879:         segment = xmlURIEscapeStr(BAD_CAST uri->server, BAD_CAST "/?;:@");
                   1880:         NULLCHK(segment)
                   1881:                if (uri->user == NULL)
                   1882:                ret = xmlStrcat(ret, BAD_CAST "//");
                   1883:         ret = xmlStrcat(ret, segment);
                   1884:         xmlFree(segment);
                   1885:     }
                   1886: 
                   1887:     if (uri->port) {
                   1888:         xmlChar port[10];
                   1889: 
                   1890:         snprintf((char *) port, 10, "%d", uri->port);
                   1891:         ret = xmlStrcat(ret, BAD_CAST ":");
                   1892:         ret = xmlStrcat(ret, port);
                   1893:     }
                   1894: 
                   1895:     if (uri->path) {
                   1896:         segment =
                   1897:             xmlURIEscapeStr(BAD_CAST uri->path, BAD_CAST ":@&=+$,/?;");
                   1898:         NULLCHK(segment)
                   1899:         ret = xmlStrcat(ret, segment);
                   1900:         xmlFree(segment);
                   1901:     }
                   1902: 
                   1903:     if (uri->query_raw) {
                   1904:         ret = xmlStrcat(ret, BAD_CAST "?");
                   1905:         ret = xmlStrcat(ret, BAD_CAST uri->query_raw);
                   1906:     }
                   1907:     else if (uri->query) {
                   1908:         segment =
                   1909:             xmlURIEscapeStr(BAD_CAST uri->query, BAD_CAST ";/?:@&=+,$");
                   1910:         NULLCHK(segment)
                   1911:         ret = xmlStrcat(ret, BAD_CAST "?");
                   1912:         ret = xmlStrcat(ret, segment);
                   1913:         xmlFree(segment);
                   1914:     }
                   1915: 
                   1916:     if (uri->opaque) {
                   1917:         segment = xmlURIEscapeStr(BAD_CAST uri->opaque, BAD_CAST "");
                   1918:         NULLCHK(segment)
                   1919:         ret = xmlStrcat(ret, segment);
                   1920:         xmlFree(segment);
                   1921:     }
                   1922: 
                   1923:     if (uri->fragment) {
                   1924:         segment = xmlURIEscapeStr(BAD_CAST uri->fragment, BAD_CAST "#");
                   1925:         NULLCHK(segment)
                   1926:         ret = xmlStrcat(ret, BAD_CAST "#");
                   1927:         ret = xmlStrcat(ret, segment);
                   1928:         xmlFree(segment);
                   1929:     }
                   1930: 
                   1931:     xmlFreeURI(uri);
                   1932: #undef NULLCHK
                   1933: 
                   1934:     return (ret);
                   1935: }
                   1936: 
                   1937: /************************************************************************
                   1938:  *                                                                     *
                   1939:  *                     Public functions                                *
                   1940:  *                                                                     *
                   1941:  ************************************************************************/
                   1942: 
                   1943: /**
                   1944:  * xmlBuildURI:
                   1945:  * @URI:  the URI instance found in the document
                   1946:  * @base:  the base value
                   1947:  *
                   1948:  * Computes he final URI of the reference done by checking that
                   1949:  * the given URI is valid, and building the final URI using the
                   1950:  * base URI. This is processed according to section 5.2 of the 
                   1951:  * RFC 2396
                   1952:  *
                   1953:  * 5.2. Resolving Relative References to Absolute Form
                   1954:  *
                   1955:  * Returns a new URI string (to be freed by the caller) or NULL in case
                   1956:  *         of error.
                   1957:  */
                   1958: xmlChar *
                   1959: xmlBuildURI(const xmlChar *URI, const xmlChar *base) {
                   1960:     xmlChar *val = NULL;
                   1961:     int ret, len, indx, cur, out;
                   1962:     xmlURIPtr ref = NULL;
                   1963:     xmlURIPtr bas = NULL;
                   1964:     xmlURIPtr res = NULL;
                   1965: 
                   1966:     /*
                   1967:      * 1) The URI reference is parsed into the potential four components and
                   1968:      *    fragment identifier, as described in Section 4.3.
                   1969:      *
                   1970:      *    NOTE that a completely empty URI is treated by modern browsers
                   1971:      *    as a reference to "." rather than as a synonym for the current
                   1972:      *    URI.  Should we do that here?
                   1973:      */
                   1974:     if (URI == NULL) 
                   1975:        ret = -1;
                   1976:     else {
                   1977:        if (*URI) {
                   1978:            ref = xmlCreateURI();
                   1979:            if (ref == NULL)
                   1980:                goto done;
                   1981:            ret = xmlParseURIReference(ref, (const char *) URI);
                   1982:        }
                   1983:        else
                   1984:            ret = 0;
                   1985:     }
                   1986:     if (ret != 0)
                   1987:        goto done;
                   1988:     if ((ref != NULL) && (ref->scheme != NULL)) {
                   1989:        /*
                   1990:         * The URI is absolute don't modify.
                   1991:         */
                   1992:        val = xmlStrdup(URI);
                   1993:        goto done;
                   1994:     }
                   1995:     if (base == NULL)
                   1996:        ret = -1;
                   1997:     else {
                   1998:        bas = xmlCreateURI();
                   1999:        if (bas == NULL)
                   2000:            goto done;
                   2001:        ret = xmlParseURIReference(bas, (const char *) base);
                   2002:     }
                   2003:     if (ret != 0) {
                   2004:        if (ref)
                   2005:            val = xmlSaveUri(ref);
                   2006:        goto done;
                   2007:     }
                   2008:     if (ref == NULL) {
                   2009:        /*
                   2010:         * the base fragment must be ignored
                   2011:         */
                   2012:        if (bas->fragment != NULL) {
                   2013:            xmlFree(bas->fragment);
                   2014:            bas->fragment = NULL;
                   2015:        }
                   2016:        val = xmlSaveUri(bas);
                   2017:        goto done;
                   2018:     }
                   2019: 
                   2020:     /*
                   2021:      * 2) If the path component is empty and the scheme, authority, and
                   2022:      *    query components are undefined, then it is a reference to the
                   2023:      *    current document and we are done.  Otherwise, the reference URI's
                   2024:      *    query and fragment components are defined as found (or not found)
                   2025:      *    within the URI reference and not inherited from the base URI.
                   2026:      *
                   2027:      *    NOTE that in modern browsers, the parsing differs from the above
                   2028:      *    in the following aspect:  the query component is allowed to be
                   2029:      *    defined while still treating this as a reference to the current
                   2030:      *    document.
                   2031:      */
                   2032:     res = xmlCreateURI();
                   2033:     if (res == NULL)
                   2034:        goto done;
                   2035:     if ((ref->scheme == NULL) && (ref->path == NULL) &&
                   2036:        ((ref->authority == NULL) && (ref->server == NULL))) {
                   2037:        if (bas->scheme != NULL)
                   2038:            res->scheme = xmlMemStrdup(bas->scheme);
                   2039:        if (bas->authority != NULL)
                   2040:            res->authority = xmlMemStrdup(bas->authority);
                   2041:        else if (bas->server != NULL) {
                   2042:            res->server = xmlMemStrdup(bas->server);
                   2043:            if (bas->user != NULL)
                   2044:                res->user = xmlMemStrdup(bas->user);
                   2045:            res->port = bas->port;              
                   2046:        }
                   2047:        if (bas->path != NULL)
                   2048:            res->path = xmlMemStrdup(bas->path);
                   2049:        if (ref->query_raw != NULL)
                   2050:            res->query_raw = xmlMemStrdup (ref->query_raw);
                   2051:        else if (ref->query != NULL)
                   2052:            res->query = xmlMemStrdup(ref->query);
                   2053:        else if (bas->query_raw != NULL)
                   2054:            res->query_raw = xmlMemStrdup(bas->query_raw);
                   2055:        else if (bas->query != NULL)
                   2056:            res->query = xmlMemStrdup(bas->query);
                   2057:        if (ref->fragment != NULL)
                   2058:            res->fragment = xmlMemStrdup(ref->fragment);
                   2059:        goto step_7;
                   2060:     }
                   2061: 
                   2062:     /*
                   2063:      * 3) If the scheme component is defined, indicating that the reference
                   2064:      *    starts with a scheme name, then the reference is interpreted as an
                   2065:      *    absolute URI and we are done.  Otherwise, the reference URI's
                   2066:      *    scheme is inherited from the base URI's scheme component.
                   2067:      */
                   2068:     if (ref->scheme != NULL) {
                   2069:        val = xmlSaveUri(ref);
                   2070:        goto done;
                   2071:     }
                   2072:     if (bas->scheme != NULL)
                   2073:        res->scheme = xmlMemStrdup(bas->scheme);
                   2074:  
                   2075:     if (ref->query_raw != NULL)
                   2076:        res->query_raw = xmlMemStrdup(ref->query_raw);
                   2077:     else if (ref->query != NULL)
                   2078:        res->query = xmlMemStrdup(ref->query);
                   2079:     if (ref->fragment != NULL)
                   2080:        res->fragment = xmlMemStrdup(ref->fragment);
                   2081: 
                   2082:     /*
                   2083:      * 4) If the authority component is defined, then the reference is a
                   2084:      *    network-path and we skip to step 7.  Otherwise, the reference
                   2085:      *    URI's authority is inherited from the base URI's authority
                   2086:      *    component, which will also be undefined if the URI scheme does not
                   2087:      *    use an authority component.
                   2088:      */
                   2089:     if ((ref->authority != NULL) || (ref->server != NULL)) {
                   2090:        if (ref->authority != NULL)
                   2091:            res->authority = xmlMemStrdup(ref->authority);
                   2092:        else {
                   2093:            res->server = xmlMemStrdup(ref->server);
                   2094:            if (ref->user != NULL)
                   2095:                res->user = xmlMemStrdup(ref->user);
                   2096:             res->port = ref->port;             
                   2097:        }
                   2098:        if (ref->path != NULL)
                   2099:            res->path = xmlMemStrdup(ref->path);
                   2100:        goto step_7;
                   2101:     }
                   2102:     if (bas->authority != NULL)
                   2103:        res->authority = xmlMemStrdup(bas->authority);
                   2104:     else if (bas->server != NULL) {
                   2105:        res->server = xmlMemStrdup(bas->server);
                   2106:        if (bas->user != NULL)
                   2107:            res->user = xmlMemStrdup(bas->user);
                   2108:        res->port = bas->port;          
                   2109:     }
                   2110: 
                   2111:     /*
                   2112:      * 5) If the path component begins with a slash character ("/"), then
                   2113:      *    the reference is an absolute-path and we skip to step 7.
                   2114:      */
                   2115:     if ((ref->path != NULL) && (ref->path[0] == '/')) {
                   2116:        res->path = xmlMemStrdup(ref->path);
                   2117:        goto step_7;
                   2118:     }
                   2119: 
                   2120: 
                   2121:     /*
                   2122:      * 6) If this step is reached, then we are resolving a relative-path
                   2123:      *    reference.  The relative path needs to be merged with the base
                   2124:      *    URI's path.  Although there are many ways to do this, we will
                   2125:      *    describe a simple method using a separate string buffer.
                   2126:      *
                   2127:      * Allocate a buffer large enough for the result string.
                   2128:      */
                   2129:     len = 2; /* extra / and 0 */
                   2130:     if (ref->path != NULL)
                   2131:        len += strlen(ref->path);
                   2132:     if (bas->path != NULL)
                   2133:        len += strlen(bas->path);
                   2134:     res->path = (char *) xmlMallocAtomic(len);
                   2135:     if (res->path == NULL) {
                   2136:        xmlGenericError(xmlGenericErrorContext,
                   2137:                "xmlBuildURI: out of memory\n");
                   2138:        goto done;
                   2139:     }
                   2140:     res->path[0] = 0;
                   2141: 
                   2142:     /*
                   2143:      * a) All but the last segment of the base URI's path component is
                   2144:      *    copied to the buffer.  In other words, any characters after the
                   2145:      *    last (right-most) slash character, if any, are excluded.
                   2146:      */
                   2147:     cur = 0;
                   2148:     out = 0;
                   2149:     if (bas->path != NULL) {
                   2150:        while (bas->path[cur] != 0) {
                   2151:            while ((bas->path[cur] != 0) && (bas->path[cur] != '/'))
                   2152:                cur++;
                   2153:            if (bas->path[cur] == 0)
                   2154:                break;
                   2155: 
                   2156:            cur++;
                   2157:            while (out < cur) {
                   2158:                res->path[out] = bas->path[out];
                   2159:                out++;
                   2160:            }
                   2161:        }
                   2162:     }
                   2163:     res->path[out] = 0;
                   2164: 
                   2165:     /*
                   2166:      * b) The reference's path component is appended to the buffer
                   2167:      *    string.
                   2168:      */
                   2169:     if (ref->path != NULL && ref->path[0] != 0) {
                   2170:        indx = 0;
                   2171:        /*
                   2172:         * Ensure the path includes a '/'
                   2173:         */
                   2174:        if ((out == 0) && (bas->server != NULL))
                   2175:            res->path[out++] = '/';
                   2176:        while (ref->path[indx] != 0) {
                   2177:            res->path[out++] = ref->path[indx++];
                   2178:        }
                   2179:     }
                   2180:     res->path[out] = 0;
                   2181: 
                   2182:     /*
                   2183:      * Steps c) to h) are really path normalization steps
                   2184:      */
                   2185:     xmlNormalizeURIPath(res->path);
                   2186: 
                   2187: step_7:
                   2188: 
                   2189:     /*
                   2190:      * 7) The resulting URI components, including any inherited from the
                   2191:      *    base URI, are recombined to give the absolute form of the URI
                   2192:      *    reference.
                   2193:      */
                   2194:     val = xmlSaveUri(res);
                   2195: 
                   2196: done:
                   2197:     if (ref != NULL)
                   2198:        xmlFreeURI(ref);
                   2199:     if (bas != NULL)
                   2200:        xmlFreeURI(bas);
                   2201:     if (res != NULL)
                   2202:        xmlFreeURI(res);
                   2203:     return(val);
                   2204: }
                   2205: 
                   2206: /**
                   2207:  * xmlBuildRelativeURI:
                   2208:  * @URI:  the URI reference under consideration
                   2209:  * @base:  the base value
                   2210:  *
                   2211:  * Expresses the URI of the reference in terms relative to the
                   2212:  * base.  Some examples of this operation include:
                   2213:  *     base = "http://site1.com/docs/book1.html"
                   2214:  *        URI input                        URI returned
                   2215:  *     docs/pic1.gif                    pic1.gif
                   2216:  *     docs/img/pic1.gif                img/pic1.gif
                   2217:  *     img/pic1.gif                     ../img/pic1.gif
                   2218:  *     http://site1.com/docs/pic1.gif   pic1.gif
                   2219:  *     http://site2.com/docs/pic1.gif   http://site2.com/docs/pic1.gif
                   2220:  *
                   2221:  *     base = "docs/book1.html"
                   2222:  *        URI input                        URI returned
                   2223:  *     docs/pic1.gif                    pic1.gif
                   2224:  *     docs/img/pic1.gif                img/pic1.gif
                   2225:  *     img/pic1.gif                     ../img/pic1.gif
                   2226:  *     http://site1.com/docs/pic1.gif   http://site1.com/docs/pic1.gif
                   2227:  *
                   2228:  *
                   2229:  * Note: if the URI reference is really wierd or complicated, it may be
                   2230:  *       worthwhile to first convert it into a "nice" one by calling
                   2231:  *       xmlBuildURI (using 'base') before calling this routine,
                   2232:  *       since this routine (for reasonable efficiency) assumes URI has
                   2233:  *       already been through some validation.
                   2234:  *
                   2235:  * Returns a new URI string (to be freed by the caller) or NULL in case
                   2236:  * error.
                   2237:  */
                   2238: xmlChar *
                   2239: xmlBuildRelativeURI (const xmlChar * URI, const xmlChar * base)
                   2240: {
                   2241:     xmlChar *val = NULL;
                   2242:     int ret;
                   2243:     int ix;
                   2244:     int pos = 0;
                   2245:     int nbslash = 0;
                   2246:     int len;
                   2247:     xmlURIPtr ref = NULL;
                   2248:     xmlURIPtr bas = NULL;
                   2249:     xmlChar *bptr, *uptr, *vptr;
                   2250:     int remove_path = 0;
                   2251: 
                   2252:     if ((URI == NULL) || (*URI == 0))
                   2253:        return NULL;
                   2254: 
                   2255:     /*
                   2256:      * First parse URI into a standard form
                   2257:      */
                   2258:     ref = xmlCreateURI ();
                   2259:     if (ref == NULL)
                   2260:        return NULL;
                   2261:     /* If URI not already in "relative" form */
                   2262:     if (URI[0] != '.') {
                   2263:        ret = xmlParseURIReference (ref, (const char *) URI);
                   2264:        if (ret != 0)
                   2265:            goto done;          /* Error in URI, return NULL */
                   2266:     } else
                   2267:        ref->path = (char *)xmlStrdup(URI);
                   2268: 
                   2269:     /*
                   2270:      * Next parse base into the same standard form
                   2271:      */
                   2272:     if ((base == NULL) || (*base == 0)) {
                   2273:        val = xmlStrdup (URI);
                   2274:        goto done;
                   2275:     }
                   2276:     bas = xmlCreateURI ();
                   2277:     if (bas == NULL)
                   2278:        goto done;
                   2279:     if (base[0] != '.') {
                   2280:        ret = xmlParseURIReference (bas, (const char *) base);
                   2281:        if (ret != 0)
                   2282:            goto done;          /* Error in base, return NULL */
                   2283:     } else
                   2284:        bas->path = (char *)xmlStrdup(base);
                   2285: 
                   2286:     /*
                   2287:      * If the scheme / server on the URI differs from the base,
                   2288:      * just return the URI
                   2289:      */
                   2290:     if ((ref->scheme != NULL) &&
                   2291:        ((bas->scheme == NULL) ||
                   2292:         (xmlStrcmp ((xmlChar *)bas->scheme, (xmlChar *)ref->scheme)) ||
                   2293:         (xmlStrcmp ((xmlChar *)bas->server, (xmlChar *)ref->server)))) {
                   2294:        val = xmlStrdup (URI);
                   2295:        goto done;
                   2296:     }
                   2297:     if (xmlStrEqual((xmlChar *)bas->path, (xmlChar *)ref->path)) {
                   2298:        val = xmlStrdup(BAD_CAST "");
                   2299:        goto done;
                   2300:     }
                   2301:     if (bas->path == NULL) {
                   2302:        val = xmlStrdup((xmlChar *)ref->path);
                   2303:        goto done;
                   2304:     }
                   2305:     if (ref->path == NULL) {
                   2306:         ref->path = (char *) "/";
                   2307:        remove_path = 1;
                   2308:     }
                   2309: 
                   2310:     /*
                   2311:      * At this point (at last!) we can compare the two paths
                   2312:      *
                   2313:      * First we take care of the special case where either of the
                   2314:      * two path components may be missing (bug 316224)
                   2315:      */
                   2316:     if (bas->path == NULL) {
                   2317:        if (ref->path != NULL) {
                   2318:            uptr = (xmlChar *) ref->path;
                   2319:            if (*uptr == '/')
                   2320:                uptr++;
                   2321:            /* exception characters from xmlSaveUri */
                   2322:            val = xmlURIEscapeStr(uptr, BAD_CAST "/;&=+$,");
                   2323:        }
                   2324:        goto done;
                   2325:     }
                   2326:     bptr = (xmlChar *)bas->path;
                   2327:     if (ref->path == NULL) {
                   2328:        for (ix = 0; bptr[ix] != 0; ix++) {
                   2329:            if (bptr[ix] == '/')
                   2330:                nbslash++;
                   2331:        }
                   2332:        uptr = NULL;
                   2333:        len = 1;        /* this is for a string terminator only */
                   2334:     } else {
                   2335:     /*
                   2336:      * Next we compare the two strings and find where they first differ
                   2337:      */
                   2338:        if ((ref->path[pos] == '.') && (ref->path[pos+1] == '/'))
                   2339:             pos += 2;
                   2340:        if ((*bptr == '.') && (bptr[1] == '/'))
                   2341:             bptr += 2;
                   2342:        else if ((*bptr == '/') && (ref->path[pos] != '/'))
                   2343:            bptr++;
                   2344:        while ((bptr[pos] == ref->path[pos]) && (bptr[pos] != 0))
                   2345:            pos++;
                   2346: 
                   2347:        if (bptr[pos] == ref->path[pos]) {
                   2348:            val = xmlStrdup(BAD_CAST "");
                   2349:            goto done;          /* (I can't imagine why anyone would do this) */
                   2350:        }
                   2351: 
                   2352:        /*
                   2353:         * In URI, "back up" to the last '/' encountered.  This will be the
                   2354:         * beginning of the "unique" suffix of URI
                   2355:         */
                   2356:        ix = pos;
                   2357:        if ((ref->path[ix] == '/') && (ix > 0))
                   2358:            ix--;
                   2359:        else if ((ref->path[ix] == 0) && (ix > 1) && (ref->path[ix - 1] == '/'))
                   2360:            ix -= 2;
                   2361:        for (; ix > 0; ix--) {
                   2362:            if (ref->path[ix] == '/')
                   2363:                break;
                   2364:        }
                   2365:        if (ix == 0) {
                   2366:            uptr = (xmlChar *)ref->path;
                   2367:        } else {
                   2368:            ix++;
                   2369:            uptr = (xmlChar *)&ref->path[ix];
                   2370:        }
                   2371: 
                   2372:        /*
                   2373:         * In base, count the number of '/' from the differing point
                   2374:         */
                   2375:        if (bptr[pos] != ref->path[pos]) {/* check for trivial URI == base */
                   2376:            for (; bptr[ix] != 0; ix++) {
                   2377:                if (bptr[ix] == '/')
                   2378:                    nbslash++;
                   2379:            }
                   2380:        }
                   2381:        len = xmlStrlen (uptr) + 1;
                   2382:     }
                   2383:     
                   2384:     if (nbslash == 0) {
                   2385:        if (uptr != NULL)
                   2386:            /* exception characters from xmlSaveUri */
                   2387:            val = xmlURIEscapeStr(uptr, BAD_CAST "/;&=+$,");
                   2388:        goto done;
                   2389:     }
                   2390: 
                   2391:     /*
                   2392:      * Allocate just enough space for the returned string -
                   2393:      * length of the remainder of the URI, plus enough space
                   2394:      * for the "../" groups, plus one for the terminator
                   2395:      */
                   2396:     val = (xmlChar *) xmlMalloc (len + 3 * nbslash);
                   2397:     if (val == NULL) {
                   2398:        xmlGenericError(xmlGenericErrorContext,
                   2399:                "xmlBuildRelativeURI: out of memory\n");
                   2400:        goto done;
                   2401:     }
                   2402:     vptr = val;
                   2403:     /*
                   2404:      * Put in as many "../" as needed
                   2405:      */
                   2406:     for (; nbslash>0; nbslash--) {
                   2407:        *vptr++ = '.';
                   2408:        *vptr++ = '.';
                   2409:        *vptr++ = '/';
                   2410:     }
                   2411:     /*
                   2412:      * Finish up with the end of the URI
                   2413:      */
                   2414:     if (uptr != NULL) {
                   2415:         if ((vptr > val) && (len > 0) &&
                   2416:            (uptr[0] == '/') && (vptr[-1] == '/')) {
                   2417:            memcpy (vptr, uptr + 1, len - 1);
                   2418:            vptr[len - 2] = 0;
                   2419:        } else {
                   2420:            memcpy (vptr, uptr, len);
                   2421:            vptr[len - 1] = 0;
                   2422:        }
                   2423:     } else {
                   2424:        vptr[len - 1] = 0;
                   2425:     }
                   2426: 
                   2427:     /* escape the freshly-built path */
                   2428:     vptr = val;
                   2429:        /* exception characters from xmlSaveUri */
                   2430:     val = xmlURIEscapeStr(vptr, BAD_CAST "/;&=+$,");
                   2431:     xmlFree(vptr);
                   2432: 
                   2433: done:
                   2434:     /*
                   2435:      * Free the working variables
                   2436:      */
                   2437:     if (remove_path != 0)
                   2438:         ref->path = NULL;
                   2439:     if (ref != NULL)
                   2440:        xmlFreeURI (ref);
                   2441:     if (bas != NULL)
                   2442:        xmlFreeURI (bas);
                   2443: 
                   2444:     return val;
                   2445: }
                   2446: 
                   2447: /**
                   2448:  * xmlCanonicPath:
                   2449:  * @path:  the resource locator in a filesystem notation
                   2450:  *
                   2451:  * Constructs a canonic path from the specified path. 
                   2452:  *
                   2453:  * Returns a new canonic path, or a duplicate of the path parameter if the 
                   2454:  * construction fails. The caller is responsible for freeing the memory occupied
                   2455:  * by the returned string. If there is insufficient memory available, or the 
                   2456:  * argument is NULL, the function returns NULL.
                   2457:  */
                   2458: #define IS_WINDOWS_PATH(p)                                     \
                   2459:        ((p != NULL) &&                                         \
                   2460:         (((p[0] >= 'a') && (p[0] <= 'z')) ||                   \
                   2461:          ((p[0] >= 'A') && (p[0] <= 'Z'))) &&                  \
                   2462:         (p[1] == ':') && ((p[2] == '/') || (p[2] == '\\')))
                   2463: xmlChar *
                   2464: xmlCanonicPath(const xmlChar *path)
                   2465: {
                   2466: /*
                   2467:  * For Windows implementations, additional work needs to be done to
                   2468:  * replace backslashes in pathnames with "forward slashes"
                   2469:  */
                   2470: #if defined(_WIN32) && !defined(__CYGWIN__)    
                   2471:     int len = 0;
                   2472:     int i = 0;
                   2473:     xmlChar *p = NULL;
                   2474: #endif
                   2475:     xmlURIPtr uri;
                   2476:     xmlChar *ret;
                   2477:     const xmlChar *absuri;
                   2478: 
                   2479:     if (path == NULL)
                   2480:        return(NULL);
                   2481: 
                   2482:     /* sanitize filename starting with // so it can be used as URI */
                   2483:     if ((path[0] == '/') && (path[1] == '/') && (path[2] != '/'))
                   2484:         path++;
                   2485: 
                   2486:     if ((uri = xmlParseURI((const char *) path)) != NULL) {
                   2487:        xmlFreeURI(uri);
                   2488:        return xmlStrdup(path);
                   2489:     }
                   2490: 
                   2491:     /* Check if this is an "absolute uri" */
                   2492:     absuri = xmlStrstr(path, BAD_CAST "://");
                   2493:     if (absuri != NULL) {
                   2494:         int l, j;
                   2495:        unsigned char c;
                   2496:        xmlChar *escURI;
                   2497: 
                   2498:         /*
                   2499:         * this looks like an URI where some parts have not been
                   2500:         * escaped leading to a parsing problem.  Check that the first
                   2501:         * part matches a protocol.
                   2502:         */
                   2503:        l = absuri - path;
                   2504:        /* Bypass if first part (part before the '://') is > 20 chars */
                   2505:        if ((l <= 0) || (l > 20))
                   2506:            goto path_processing;
                   2507:        /* Bypass if any non-alpha characters are present in first part */
                   2508:        for (j = 0;j < l;j++) {
                   2509:            c = path[j];
                   2510:            if (!(((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))))
                   2511:                goto path_processing;
                   2512:        }
                   2513: 
                   2514:        /* Escape all except the characters specified in the supplied path */
                   2515:         escURI = xmlURIEscapeStr(path, BAD_CAST ":/?_.#&;=");
                   2516:        if (escURI != NULL) {
                   2517:            /* Try parsing the escaped path */
                   2518:            uri = xmlParseURI((const char *) escURI);
                   2519:            /* If successful, return the escaped string */
                   2520:            if (uri != NULL) {
                   2521:                xmlFreeURI(uri);
                   2522:                return escURI;
                   2523:            }
                   2524:        }
                   2525:     }
                   2526: 
                   2527: path_processing:
                   2528: /* For Windows implementations, replace backslashes with 'forward slashes' */
                   2529: #if defined(_WIN32) && !defined(__CYGWIN__)    
                   2530:     /*
                   2531:      * Create a URI structure
                   2532:      */
                   2533:     uri = xmlCreateURI();
                   2534:     if (uri == NULL) {         /* Guard against 'out of memory' */
                   2535:         return(NULL);
                   2536:     }
                   2537: 
                   2538:     len = xmlStrlen(path);
                   2539:     if ((len > 2) && IS_WINDOWS_PATH(path)) {
                   2540:         /* make the scheme 'file' */
                   2541:        uri->scheme = xmlStrdup(BAD_CAST "file");
                   2542:        /* allocate space for leading '/' + path + string terminator */
                   2543:        uri->path = xmlMallocAtomic(len + 2);
                   2544:        if (uri->path == NULL) {
                   2545:            xmlFreeURI(uri);    /* Guard agains 'out of memory' */
                   2546:            return(NULL);
                   2547:        }
                   2548:        /* Put in leading '/' plus path */
                   2549:        uri->path[0] = '/';
                   2550:        p = uri->path + 1;
                   2551:        strncpy(p, path, len + 1);
                   2552:     } else {
                   2553:        uri->path = xmlStrdup(path);
                   2554:        if (uri->path == NULL) {
                   2555:            xmlFreeURI(uri);
                   2556:            return(NULL);
                   2557:        }
                   2558:        p = uri->path;
                   2559:     }
                   2560:     /* Now change all occurences of '\' to '/' */
                   2561:     while (*p != '\0') {
                   2562:        if (*p == '\\')
                   2563:            *p = '/';
                   2564:        p++;
                   2565:     }
                   2566: 
                   2567:     if (uri->scheme == NULL) {
                   2568:        ret = xmlStrdup((const xmlChar *) uri->path);
                   2569:     } else {
                   2570:        ret = xmlSaveUri(uri);
                   2571:     }
                   2572: 
                   2573:     xmlFreeURI(uri);
                   2574: #else
                   2575:     ret = xmlStrdup((const xmlChar *) path);
                   2576: #endif
                   2577:     return(ret);
                   2578: }
                   2579: 
                   2580: /**
                   2581:  * xmlPathToURI:
                   2582:  * @path:  the resource locator in a filesystem notation
                   2583:  *
                   2584:  * Constructs an URI expressing the existing path
                   2585:  *
                   2586:  * Returns a new URI, or a duplicate of the path parameter if the 
                   2587:  * construction fails. The caller is responsible for freeing the memory
                   2588:  * occupied by the returned string. If there is insufficient memory available,
                   2589:  * or the argument is NULL, the function returns NULL.
                   2590:  */
                   2591: xmlChar *
                   2592: xmlPathToURI(const xmlChar *path)
                   2593: {
                   2594:     xmlURIPtr uri;
                   2595:     xmlURI temp;
                   2596:     xmlChar *ret, *cal;
                   2597: 
                   2598:     if (path == NULL)
                   2599:         return(NULL);
                   2600: 
                   2601:     if ((uri = xmlParseURI((const char *) path)) != NULL) {
                   2602:        xmlFreeURI(uri);
                   2603:        return xmlStrdup(path);
                   2604:     }
                   2605:     cal = xmlCanonicPath(path);
                   2606:     if (cal == NULL)
                   2607:         return(NULL);
                   2608: #if defined(_WIN32) && !defined(__CYGWIN__)
                   2609:     /* xmlCanonicPath can return an URI on Windows (is that the intended behaviour?) 
                   2610:        If 'cal' is a valid URI allready then we are done here, as continuing would make
                   2611:        it invalid. */
                   2612:     if ((uri = xmlParseURI((const char *) cal)) != NULL) {
                   2613:        xmlFreeURI(uri);
                   2614:        return cal;
                   2615:     }
                   2616:     /* 'cal' can contain a relative path with backslashes. If that is processed
                   2617:        by xmlSaveURI, they will be escaped and the external entity loader machinery
                   2618:        will fail. So convert them to slashes. Misuse 'ret' for walking. */
                   2619:     ret = cal;
                   2620:     while (*ret != '\0') {
                   2621:        if (*ret == '\\')
                   2622:            *ret = '/';
                   2623:        ret++;
                   2624:     }
                   2625: #endif
                   2626:     memset(&temp, 0, sizeof(temp));
                   2627:     temp.path = (char *) cal;
                   2628:     ret = xmlSaveUri(&temp);
                   2629:     xmlFree(cal);
                   2630:     return(ret);
                   2631: }
                   2632: #define bottom_uri
                   2633: #include "elfgcchack.h"

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>