Annotation of embedaddon/libxml2/uri.c, revision 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>