ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

uri.c
Go to the documentation of this file.
00001 
00011 #define IN_LIBXML
00012 #include "libxml.h"
00013 
00014 #include <string.h>
00015 
00016 #include <libxml/xmlmemory.h>
00017 #include <libxml/uri.h>
00018 #include <libxml/globals.h>
00019 #include <libxml/xmlerror.h>
00020 
00021 static void xmlCleanURI(xmlURIPtr uri);
00022 
00023 /*
00024  * Old rule from 2396 used in legacy handling code
00025  * alpha    = lowalpha | upalpha
00026  */
00027 #define IS_ALPHA(x) (IS_LOWALPHA(x) || IS_UPALPHA(x))
00028 
00029 
00030 /*
00031  * lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" |
00032  *            "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" |
00033  *            "u" | "v" | "w" | "x" | "y" | "z"
00034  */
00035 
00036 #define IS_LOWALPHA(x) (((x) >= 'a') && ((x) <= 'z'))
00037 
00038 /*
00039  * upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" |
00040  *           "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" |
00041  *           "U" | "V" | "W" | "X" | "Y" | "Z"
00042  */
00043 #define IS_UPALPHA(x) (((x) >= 'A') && ((x) <= 'Z'))
00044 
00045 #ifdef IS_DIGIT
00046 #undef IS_DIGIT
00047 #endif
00048 /*
00049  * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
00050  */
00051 #define IS_DIGIT(x) (((x) >= '0') && ((x) <= '9'))
00052 
00053 /*
00054  * alphanum = alpha | digit
00055  */
00056 
00057 #define IS_ALPHANUM(x) (IS_ALPHA(x) || IS_DIGIT(x))
00058 
00059 /*
00060  * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
00061  */
00062 
00063 #define IS_MARK(x) (((x) == '-') || ((x) == '_') || ((x) == '.') ||     \
00064     ((x) == '!') || ((x) == '~') || ((x) == '*') || ((x) == '\'') ||    \
00065     ((x) == '(') || ((x) == ')'))
00066 
00067 /*
00068  * unwise = "{" | "}" | "|" | "\" | "^" | "`"
00069  */
00070 
00071 #define IS_UNWISE(p)                                                    \
00072       (((*(p) == '{')) || ((*(p) == '}')) || ((*(p) == '|')) ||         \
00073        ((*(p) == '\\')) || ((*(p) == '^')) || ((*(p) == '[')) ||        \
00074        ((*(p) == ']')) || ((*(p) == '`')))
00075 /*
00076  * reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," |
00077  *            "[" | "]"
00078  */
00079 
00080 #define IS_RESERVED(x) (((x) == ';') || ((x) == '/') || ((x) == '?') || \
00081         ((x) == ':') || ((x) == '@') || ((x) == '&') || ((x) == '=') || \
00082         ((x) == '+') || ((x) == '$') || ((x) == ',') || ((x) == '[') || \
00083         ((x) == ']'))
00084 
00085 /*
00086  * unreserved = alphanum | mark
00087  */
00088 
00089 #define IS_UNRESERVED(x) (IS_ALPHANUM(x) || IS_MARK(x))
00090 
00091 /*
00092  * Skip to next pointer char, handle escaped sequences
00093  */
00094 
00095 #define NEXT(p) ((*p == '%')? p += 3 : p++)
00096 
00097 /*
00098  * Productions from the spec.
00099  *
00100  *    authority     = server | reg_name
00101  *    reg_name      = 1*( unreserved | escaped | "$" | "," |
00102  *                        ";" | ":" | "@" | "&" | "=" | "+" )
00103  *
00104  * path          = [ abs_path | opaque_part ]
00105  */
00106 
00107 #define STRNDUP(s, n) (char *) xmlStrndup((const xmlChar *)(s), (n))
00108 
00109 /************************************************************************
00110  *                                  *
00111  *                         RFC 3986 parser              *
00112  *                                  *
00113  ************************************************************************/
00114 
00115 #define ISA_DIGIT(p) ((*(p) >= '0') && (*(p) <= '9'))
00116 #define ISA_ALPHA(p) (((*(p) >= 'a') && (*(p) <= 'z')) ||       \
00117                       ((*(p) >= 'A') && (*(p) <= 'Z')))
00118 #define ISA_HEXDIG(p)                           \
00119        (ISA_DIGIT(p) || ((*(p) >= 'a') && (*(p) <= 'f')) ||     \
00120         ((*(p) >= 'A') && (*(p) <= 'F')))
00121 
00122 /*
00123  *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
00124  *                     / "*" / "+" / "," / ";" / "="
00125  */
00126 #define ISA_SUB_DELIM(p)                        \
00127       (((*(p) == '!')) || ((*(p) == '$')) || ((*(p) == '&')) ||     \
00128        ((*(p) == '(')) || ((*(p) == ')')) || ((*(p) == '*')) ||     \
00129        ((*(p) == '+')) || ((*(p) == ',')) || ((*(p) == ';')) ||     \
00130        ((*(p) == '=')) || ((*(p) == '\'')))
00131 
00132 /*
00133  *    gen-delims    = ":" / "/" / "?" / "#" / "[" / "]" / "@"
00134  */
00135 #define ISA_GEN_DELIM(p)                        \
00136       (((*(p) == ':')) || ((*(p) == '/')) || ((*(p) == '?')) ||         \
00137        ((*(p) == '#')) || ((*(p) == '[')) || ((*(p) == ']')) ||         \
00138        ((*(p) == '@')))
00139 
00140 /*
00141  *    reserved      = gen-delims / sub-delims
00142  */
00143 #define ISA_RESERVED(p) (ISA_GEN_DELIM(p) || (ISA_SUB_DELIM(p)))
00144 
00145 /*
00146  *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
00147  */
00148 #define ISA_UNRESERVED(p)                       \
00149       ((ISA_ALPHA(p)) || (ISA_DIGIT(p)) || ((*(p) == '-')) ||       \
00150        ((*(p) == '.')) || ((*(p) == '_')) || ((*(p) == '~')))
00151 
00152 /*
00153  *    pct-encoded   = "%" HEXDIG HEXDIG
00154  */
00155 #define ISA_PCT_ENCODED(p)                      \
00156      ((*(p) == '%') && (ISA_HEXDIG(p + 1)) && (ISA_HEXDIG(p + 2)))
00157 
00158 /*
00159  *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
00160  */
00161 #define ISA_PCHAR(p)                            \
00162      (ISA_UNRESERVED(p) || ISA_PCT_ENCODED(p) || ISA_SUB_DELIM(p) ||    \
00163       ((*(p) == ':')) || ((*(p) == '@')))
00164 
00176 static int
00177 xmlParse3986Scheme(xmlURIPtr uri, const char **str) {
00178     const char *cur;
00179 
00180     if (str == NULL)
00181     return(-1);
00182 
00183     cur = *str;
00184     if (!ISA_ALPHA(cur))
00185     return(2);
00186     cur++;
00187     while (ISA_ALPHA(cur) || ISA_DIGIT(cur) ||
00188            (*cur == '+') || (*cur == '-') || (*cur == '.')) cur++;
00189     if (uri != NULL) {
00190     if (uri->scheme != NULL) xmlFree(uri->scheme);
00191     uri->scheme = STRNDUP(*str, cur - *str);
00192     }
00193     *str = cur;
00194     return(0);
00195 }
00196 
00212 static int
00213 xmlParse3986Fragment(xmlURIPtr uri, const char **str)
00214 {
00215     const char *cur;
00216 
00217     if (str == NULL)
00218         return (-1);
00219 
00220     cur = *str;
00221 
00222     while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') ||
00223            (*cur == '[') || (*cur == ']') ||
00224            ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
00225         NEXT(cur);
00226     if (uri != NULL) {
00227         if (uri->fragment != NULL)
00228             xmlFree(uri->fragment);
00229     if (uri->cleanup & 2)
00230         uri->fragment = STRNDUP(*str, cur - *str);
00231     else
00232         uri->fragment = xmlURIUnescapeString(*str, cur - *str, NULL);
00233     }
00234     *str = cur;
00235     return (0);
00236 }
00237 
00249 static int
00250 xmlParse3986Query(xmlURIPtr uri, const char **str)
00251 {
00252     const char *cur;
00253 
00254     if (str == NULL)
00255         return (-1);
00256 
00257     cur = *str;
00258 
00259     while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') ||
00260            ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
00261         NEXT(cur);
00262     if (uri != NULL) {
00263         if (uri->query != NULL)
00264             xmlFree(uri->query);
00265     if (uri->cleanup & 2)
00266         uri->query = STRNDUP(*str, cur - *str);
00267     else
00268         uri->query = xmlURIUnescapeString(*str, cur - *str, NULL);
00269 
00270     /* Save the raw bytes of the query as well.
00271      * See: http://mail.gnome.org/archives/xml/2007-April/thread.html#00114
00272      */
00273     if (uri->query_raw != NULL)
00274         xmlFree (uri->query_raw);
00275     uri->query_raw = STRNDUP (*str, cur - *str);
00276     }
00277     *str = cur;
00278     return (0);
00279 }
00280 
00293 static int
00294 xmlParse3986Port(xmlURIPtr uri, const char **str)
00295 {
00296     const char *cur = *str;
00297 
00298     if (ISA_DIGIT(cur)) {
00299     if (uri != NULL)
00300         uri->port = 0;
00301     while (ISA_DIGIT(cur)) {
00302         if (uri != NULL)
00303         uri->port = uri->port * 10 + (*cur - '0');
00304         cur++;
00305     }
00306     *str = cur;
00307     return(0);
00308     }
00309     return(1);
00310 }
00311 
00324 static int
00325 xmlParse3986Userinfo(xmlURIPtr uri, const char **str)
00326 {
00327     const char *cur;
00328 
00329     cur = *str;
00330     while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) ||
00331            ISA_SUB_DELIM(cur) || (*cur == ':'))
00332     NEXT(cur);
00333     if (*cur == '@') {
00334     if (uri != NULL) {
00335         if (uri->user != NULL) xmlFree(uri->user);
00336         if (uri->cleanup & 2)
00337         uri->user = STRNDUP(*str, cur - *str);
00338         else
00339         uri->user = xmlURIUnescapeString(*str, cur - *str, NULL);
00340     }
00341     *str = cur;
00342     return(0);
00343     }
00344     return(1);
00345 }
00346 
00361 static int
00362 xmlParse3986DecOctet(const char **str) {
00363     const char *cur = *str;
00364 
00365     if (!(ISA_DIGIT(cur)))
00366         return(1);
00367     if (!ISA_DIGIT(cur+1))
00368     cur++;
00369     else if ((*cur != '0') && (ISA_DIGIT(cur + 1)) && (!ISA_DIGIT(cur+2)))
00370     cur += 2;
00371     else if ((*cur == '1') && (ISA_DIGIT(cur + 1)) && (ISA_DIGIT(cur + 2)))
00372     cur += 3;
00373     else if ((*cur == '2') && (*(cur + 1) >= '0') &&
00374          (*(cur + 1) <= '4') && (ISA_DIGIT(cur + 2)))
00375     cur += 3;
00376     else if ((*cur == '2') && (*(cur + 1) == '5') &&
00377          (*(cur + 2) >= '0') && (*(cur + 1) <= '5'))
00378     cur += 3;
00379     else
00380         return(1);
00381     *str = cur;
00382     return(0);
00383 }
00399 static int
00400 xmlParse3986Host(xmlURIPtr uri, const char **str)
00401 {
00402     const char *cur = *str;
00403     const char *host;
00404 
00405     host = cur;
00406     /*
00407      * IPv6 and future adressing scheme are enclosed between brackets
00408      */
00409     if (*cur == '[') {
00410         cur++;
00411     while ((*cur != ']') && (*cur != 0))
00412         cur++;
00413     if (*cur != ']')
00414         return(1);
00415     cur++;
00416     goto found;
00417     }
00418     /*
00419      * try to parse an IPv4
00420      */
00421     if (ISA_DIGIT(cur)) {
00422         if (xmlParse3986DecOctet(&cur) != 0)
00423         goto not_ipv4;
00424     if (*cur != '.')
00425         goto not_ipv4;
00426     cur++;
00427         if (xmlParse3986DecOctet(&cur) != 0)
00428         goto not_ipv4;
00429     if (*cur != '.')
00430         goto not_ipv4;
00431         if (xmlParse3986DecOctet(&cur) != 0)
00432         goto not_ipv4;
00433     if (*cur != '.')
00434         goto not_ipv4;
00435         if (xmlParse3986DecOctet(&cur) != 0)
00436         goto not_ipv4;
00437     goto found;
00438 not_ipv4:
00439         cur = *str;
00440     }
00441     /*
00442      * then this should be a hostname which can be empty
00443      */
00444     while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur))
00445         NEXT(cur);
00446 found:
00447     if (uri != NULL) {
00448     if (uri->authority != NULL) xmlFree(uri->authority);
00449     uri->authority = NULL;
00450     if (uri->server != NULL) xmlFree(uri->server);
00451     if (cur != host) {
00452         if (uri->cleanup & 2)
00453         uri->server = STRNDUP(host, cur - host);
00454         else
00455         uri->server = xmlURIUnescapeString(host, cur - host, NULL);
00456     } else
00457         uri->server = NULL;
00458     }
00459     *str = cur;
00460     return(0);
00461 }
00462 
00475 static int
00476 xmlParse3986Authority(xmlURIPtr uri, const char **str)
00477 {
00478     const char *cur;
00479     int ret;
00480 
00481     cur = *str;
00482     /*
00483      * try to parse an userinfo and check for the trailing @
00484      */
00485     ret = xmlParse3986Userinfo(uri, &cur);
00486     if ((ret != 0) || (*cur != '@'))
00487         cur = *str;
00488     else
00489         cur++;
00490     ret = xmlParse3986Host(uri, &cur);
00491     if (ret != 0) return(ret);
00492     if (*cur == ':') {
00493         cur++;
00494         ret = xmlParse3986Port(uri, &cur);
00495     if (ret != 0) return(ret);
00496     }
00497     *str = cur;
00498     return(0);
00499 }
00500 
00517 static int
00518 xmlParse3986Segment(const char **str, char forbid, int empty)
00519 {
00520     const char *cur;
00521 
00522     cur = *str;
00523     if (!ISA_PCHAR(cur)) {
00524         if (empty)
00525         return(0);
00526     return(1);
00527     }
00528     while (ISA_PCHAR(cur) && (*cur != forbid))
00529         NEXT(cur);
00530     *str = cur;
00531     return (0);
00532 }
00533 
00546 static int
00547 xmlParse3986PathAbEmpty(xmlURIPtr uri, const char **str)
00548 {
00549     const char *cur;
00550     int ret;
00551 
00552     cur = *str;
00553 
00554     while (*cur == '/') {
00555         cur++;
00556     ret = xmlParse3986Segment(&cur, 0, 1);
00557     if (ret != 0) return(ret);
00558     }
00559     if (uri != NULL) {
00560     if (uri->path != NULL) xmlFree(uri->path);
00561         if (*str != cur) {
00562             if (uri->cleanup & 2)
00563                 uri->path = STRNDUP(*str, cur - *str);
00564             else
00565                 uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
00566         } else {
00567             uri->path = NULL;
00568         }
00569     }
00570     *str = cur;
00571     return (0);
00572 }
00573 
00586 static int
00587 xmlParse3986PathAbsolute(xmlURIPtr uri, const char **str)
00588 {
00589     const char *cur;
00590     int ret;
00591 
00592     cur = *str;
00593 
00594     if (*cur != '/')
00595         return(1);
00596     cur++;
00597     ret = xmlParse3986Segment(&cur, 0, 0);
00598     if (ret == 0) {
00599     while (*cur == '/') {
00600         cur++;
00601         ret = xmlParse3986Segment(&cur, 0, 1);
00602         if (ret != 0) return(ret);
00603     }
00604     }
00605     if (uri != NULL) {
00606     if (uri->path != NULL) xmlFree(uri->path);
00607         if (cur != *str) {
00608             if (uri->cleanup & 2)
00609                 uri->path = STRNDUP(*str, cur - *str);
00610             else
00611                 uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
00612         } else {
00613             uri->path = NULL;
00614         }
00615     }
00616     *str = cur;
00617     return (0);
00618 }
00619 
00632 static int
00633 xmlParse3986PathRootless(xmlURIPtr uri, const char **str)
00634 {
00635     const char *cur;
00636     int ret;
00637 
00638     cur = *str;
00639 
00640     ret = xmlParse3986Segment(&cur, 0, 0);
00641     if (ret != 0) return(ret);
00642     while (*cur == '/') {
00643         cur++;
00644     ret = xmlParse3986Segment(&cur, 0, 1);
00645     if (ret != 0) return(ret);
00646     }
00647     if (uri != NULL) {
00648     if (uri->path != NULL) xmlFree(uri->path);
00649         if (cur != *str) {
00650             if (uri->cleanup & 2)
00651                 uri->path = STRNDUP(*str, cur - *str);
00652             else
00653                 uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
00654         } else {
00655             uri->path = NULL;
00656         }
00657     }
00658     *str = cur;
00659     return (0);
00660 }
00661 
00674 static int
00675 xmlParse3986PathNoScheme(xmlURIPtr uri, const char **str)
00676 {
00677     const char *cur;
00678     int ret;
00679 
00680     cur = *str;
00681 
00682     ret = xmlParse3986Segment(&cur, ':', 0);
00683     if (ret != 0) return(ret);
00684     while (*cur == '/') {
00685         cur++;
00686     ret = xmlParse3986Segment(&cur, 0, 1);
00687     if (ret != 0) return(ret);
00688     }
00689     if (uri != NULL) {
00690     if (uri->path != NULL) xmlFree(uri->path);
00691         if (cur != *str) {
00692             if (uri->cleanup & 2)
00693                 uri->path = STRNDUP(*str, cur - *str);
00694             else
00695                 uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
00696         } else {
00697             uri->path = NULL;
00698         }
00699     }
00700     *str = cur;
00701     return (0);
00702 }
00703 
00719 static int
00720 xmlParse3986HierPart(xmlURIPtr uri, const char **str)
00721 {
00722     const char *cur;
00723     int ret;
00724 
00725     cur = *str;
00726 
00727     if ((*cur == '/') && (*(cur + 1) == '/')) {
00728         cur += 2;
00729     ret = xmlParse3986Authority(uri, &cur);
00730     if (ret != 0) return(ret);
00731     ret = xmlParse3986PathAbEmpty(uri, &cur);
00732     if (ret != 0) return(ret);
00733     *str = cur;
00734     return(0);
00735     } else if (*cur == '/') {
00736         ret = xmlParse3986PathAbsolute(uri, &cur);
00737     if (ret != 0) return(ret);
00738     } else if (ISA_PCHAR(cur)) {
00739         ret = xmlParse3986PathRootless(uri, &cur);
00740     if (ret != 0) return(ret);
00741     } else {
00742     /* path-empty is effectively empty */
00743     if (uri != NULL) {
00744         if (uri->path != NULL) xmlFree(uri->path);
00745         uri->path = NULL;
00746     }
00747     }
00748     *str = cur;
00749     return (0);
00750 }
00751 
00768 static int
00769 xmlParse3986RelativeRef(xmlURIPtr uri, const char *str) {
00770     int ret;
00771 
00772     if ((*str == '/') && (*(str + 1) == '/')) {
00773         str += 2;
00774     ret = xmlParse3986Authority(uri, &str);
00775     if (ret != 0) return(ret);
00776     ret = xmlParse3986PathAbEmpty(uri, &str);
00777     if (ret != 0) return(ret);
00778     } else if (*str == '/') {
00779     ret = xmlParse3986PathAbsolute(uri, &str);
00780     if (ret != 0) return(ret);
00781     } else if (ISA_PCHAR(str)) {
00782         ret = xmlParse3986PathNoScheme(uri, &str);
00783     if (ret != 0) return(ret);
00784     } else {
00785     /* path-empty is effectively empty */
00786     if (uri != NULL) {
00787         if (uri->path != NULL) xmlFree(uri->path);
00788         uri->path = NULL;
00789     }
00790     }
00791 
00792     if (*str == '?') {
00793     str++;
00794     ret = xmlParse3986Query(uri, &str);
00795     if (ret != 0) return(ret);
00796     }
00797     if (*str == '#') {
00798     str++;
00799     ret = xmlParse3986Fragment(uri, &str);
00800     if (ret != 0) return(ret);
00801     }
00802     if (*str != 0) {
00803     xmlCleanURI(uri);
00804     return(1);
00805     }
00806     return(0);
00807 }
00808 
00809 
00822 static int
00823 xmlParse3986URI(xmlURIPtr uri, const char *str) {
00824     int ret;
00825 
00826     ret = xmlParse3986Scheme(uri, &str);
00827     if (ret != 0) return(ret);
00828     if (*str != ':') {
00829     return(1);
00830     }
00831     str++;
00832     ret = xmlParse3986HierPart(uri, &str);
00833     if (ret != 0) return(ret);
00834     if (*str == '?') {
00835     str++;
00836     ret = xmlParse3986Query(uri, &str);
00837     if (ret != 0) return(ret);
00838     }
00839     if (*str == '#') {
00840     str++;
00841     ret = xmlParse3986Fragment(uri, &str);
00842     if (ret != 0) return(ret);
00843     }
00844     if (*str != 0) {
00845     xmlCleanURI(uri);
00846     return(1);
00847     }
00848     return(0);
00849 }
00850 
00863 static int
00864 xmlParse3986URIReference(xmlURIPtr uri, const char *str) {
00865     int ret;
00866 
00867     if (str == NULL)
00868     return(-1);
00869     xmlCleanURI(uri);
00870 
00871     /*
00872      * Try first to parse absolute refs, then fallback to relative if
00873      * it fails.
00874      */
00875     ret = xmlParse3986URI(uri, str);
00876     if (ret != 0) {
00877     xmlCleanURI(uri);
00878         ret = xmlParse3986RelativeRef(uri, str);
00879     if (ret != 0) {
00880         xmlCleanURI(uri);
00881         return(ret);
00882     }
00883     }
00884     return(0);
00885 }
00886 
00897 xmlURIPtr
00898 xmlParseURI(const char *str) {
00899     xmlURIPtr uri;
00900     int ret;
00901 
00902     if (str == NULL)
00903     return(NULL);
00904     uri = xmlCreateURI();
00905     if (uri != NULL) {
00906     ret = xmlParse3986URIReference(uri, str);
00907         if (ret) {
00908         xmlFreeURI(uri);
00909         return(NULL);
00910     }
00911     }
00912     return(uri);
00913 }
00914 
00927 int
00928 xmlParseURIReference(xmlURIPtr uri, const char *str) {
00929     return(xmlParse3986URIReference(uri, str));
00930 }
00931 
00943 xmlURIPtr
00944 xmlParseURIRaw(const char *str, int raw) {
00945     xmlURIPtr uri;
00946     int ret;
00947 
00948     if (str == NULL)
00949     return(NULL);
00950     uri = xmlCreateURI();
00951     if (uri != NULL) {
00952         if (raw) {
00953         uri->cleanup |= 2;
00954     }
00955     ret = xmlParseURIReference(uri, str);
00956         if (ret) {
00957         xmlFreeURI(uri);
00958         return(NULL);
00959     }
00960     }
00961     return(uri);
00962 }
00963 
00964 /************************************************************************
00965  *                                  *
00966  *          Generic URI structure functions         *
00967  *                                  *
00968  ************************************************************************/
00969 
00977 xmlURIPtr
00978 xmlCreateURI(void) {
00979     xmlURIPtr ret;
00980 
00981     ret = (xmlURIPtr) xmlMalloc(sizeof(xmlURI));
00982     if (ret == NULL) {
00983     xmlGenericError(xmlGenericErrorContext,
00984         "xmlCreateURI: out of memory\n");
00985     return(NULL);
00986     }
00987     memset(ret, 0, sizeof(xmlURI));
00988     return(ret);
00989 }
00990 
00999 xmlChar *
01000 xmlSaveUri(xmlURIPtr uri) {
01001     xmlChar *ret = NULL;
01002     xmlChar *temp;
01003     const char *p;
01004     int len;
01005     int max;
01006 
01007     if (uri == NULL) return(NULL);
01008 
01009 
01010     max = 80;
01011     ret = (xmlChar *) xmlMallocAtomic((max + 1) * sizeof(xmlChar));
01012     if (ret == NULL) {
01013     xmlGenericError(xmlGenericErrorContext,
01014         "xmlSaveUri: out of memory\n");
01015     return(NULL);
01016     }
01017     len = 0;
01018 
01019     if (uri->scheme != NULL) {
01020     p = uri->scheme;
01021     while (*p != 0) {
01022         if (len >= max) {
01023         max *= 2;
01024         temp = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
01025         if (temp == NULL) {
01026             xmlGenericError(xmlGenericErrorContext,
01027                 "xmlSaveUri: out of memory\n");
01028             xmlFree(ret);
01029             return(NULL);
01030         }
01031         ret = temp;
01032         }
01033         ret[len++] = *p++;
01034     }
01035     if (len >= max) {
01036         max *= 2;
01037         temp = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
01038         if (temp == NULL) {
01039         xmlGenericError(xmlGenericErrorContext,
01040             "xmlSaveUri: out of memory\n");
01041         xmlFree(ret);
01042         return(NULL);
01043         }
01044         ret = temp;
01045     }
01046     ret[len++] = ':';
01047     }
01048     if (uri->opaque != NULL) {
01049     p = uri->opaque;
01050     while (*p != 0) {
01051         if (len + 3 >= max) {
01052         max *= 2;
01053         temp = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
01054         if (temp == NULL) {
01055             xmlGenericError(xmlGenericErrorContext,
01056                 "xmlSaveUri: out of memory\n");
01057             xmlFree(ret);
01058             return(NULL);
01059         }
01060         ret = temp;
01061         }
01062         if (IS_RESERVED(*(p)) || IS_UNRESERVED(*(p)))
01063         ret[len++] = *p++;
01064         else {
01065         int val = *(unsigned char *)p++;
01066         int hi = val / 0x10, lo = val % 0x10;
01067         ret[len++] = '%';
01068         ret[len++] = hi + (hi > 9? 'A'-10 : '0');
01069         ret[len++] = lo + (lo > 9? 'A'-10 : '0');
01070         }
01071     }
01072     } else {
01073     if (uri->server != NULL) {
01074         if (len + 3 >= max) {
01075         max *= 2;
01076         temp = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
01077         if (temp == NULL) {
01078             xmlGenericError(xmlGenericErrorContext,
01079                 "xmlSaveUri: out of memory\n");
01080                   xmlFree(ret);  
01081             return(NULL);
01082         }
01083         ret = temp;
01084         }
01085         ret[len++] = '/';
01086         ret[len++] = '/';
01087         if (uri->user != NULL) {
01088         p = uri->user;
01089         while (*p != 0) {
01090             if (len + 3 >= max) {
01091             max *= 2;
01092             temp = (xmlChar *) xmlRealloc(ret,
01093                 (max + 1) * sizeof(xmlChar));
01094             if (temp == NULL) {
01095                 xmlGenericError(xmlGenericErrorContext,
01096                     "xmlSaveUri: out of memory\n");
01097                 xmlFree(ret);
01098                 return(NULL);
01099             }
01100             ret = temp;
01101             }
01102             if ((IS_UNRESERVED(*(p))) ||
01103             ((*(p) == ';')) || ((*(p) == ':')) ||
01104             ((*(p) == '&')) || ((*(p) == '=')) ||
01105             ((*(p) == '+')) || ((*(p) == '$')) ||
01106             ((*(p) == ',')))
01107             ret[len++] = *p++;
01108             else {
01109             int val = *(unsigned char *)p++;
01110             int hi = val / 0x10, lo = val % 0x10;
01111             ret[len++] = '%';
01112             ret[len++] = hi + (hi > 9? 'A'-10 : '0');
01113             ret[len++] = lo + (lo > 9? 'A'-10 : '0');
01114             }
01115         }
01116         if (len + 3 >= max) {
01117             max *= 2;
01118             temp = (xmlChar *) xmlRealloc(ret,
01119                 (max + 1) * sizeof(xmlChar));
01120             if (temp == NULL) {
01121             xmlGenericError(xmlGenericErrorContext,
01122                 "xmlSaveUri: out of memory\n");
01123             xmlFree(ret);
01124             return(NULL);
01125             }
01126             ret = temp;
01127         }
01128         ret[len++] = '@';
01129         }
01130         p = uri->server;
01131         while (*p != 0) {
01132         if (len >= max) {
01133             max *= 2;
01134             temp = (xmlChar *) xmlRealloc(ret,
01135                 (max + 1) * sizeof(xmlChar));
01136             if (temp == NULL) {
01137             xmlGenericError(xmlGenericErrorContext,
01138                 "xmlSaveUri: out of memory\n");
01139             xmlFree(ret);
01140             return(NULL);
01141             }
01142             ret = temp;
01143         }
01144         ret[len++] = *p++;
01145         }
01146         if (uri->port > 0) {
01147         if (len + 10 >= max) {
01148             max *= 2;
01149             temp = (xmlChar *) xmlRealloc(ret,
01150                 (max + 1) * sizeof(xmlChar));
01151             if (temp == NULL) {
01152             xmlGenericError(xmlGenericErrorContext,
01153                 "xmlSaveUri: out of memory\n");
01154                      xmlFree(ret);
01155             return(NULL);
01156             }
01157             ret = temp;
01158         }
01159         len += snprintf((char *) &ret[len], max - len, ":%d", uri->port);
01160         }
01161     } else if (uri->authority != NULL) {
01162         if (len + 3 >= max) {
01163         max *= 2;
01164         temp = (xmlChar *) xmlRealloc(ret,
01165             (max + 1) * sizeof(xmlChar));
01166         if (temp == NULL) {
01167             xmlGenericError(xmlGenericErrorContext,
01168                 "xmlSaveUri: out of memory\n");
01169                      xmlFree(ret);
01170             return(NULL);
01171             }
01172             ret = temp;
01173         }
01174         ret[len++] = '/';
01175         ret[len++] = '/';
01176         p = uri->authority;
01177         while (*p != 0) {
01178         if (len + 3 >= max) {
01179             max *= 2;
01180             temp = (xmlChar *) xmlRealloc(ret,
01181                 (max + 1) * sizeof(xmlChar));
01182             if (temp == NULL) {
01183             xmlGenericError(xmlGenericErrorContext,
01184                 "xmlSaveUri: out of memory\n");
01185                      xmlFree(ret);
01186             return(NULL);
01187             }
01188             ret = temp;
01189         }
01190         if ((IS_UNRESERVED(*(p))) ||
01191                     ((*(p) == '$')) || ((*(p) == ',')) || ((*(p) == ';')) ||
01192                     ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) ||
01193                     ((*(p) == '=')) || ((*(p) == '+')))
01194             ret[len++] = *p++;
01195         else {
01196             int val = *(unsigned char *)p++;
01197             int hi = val / 0x10, lo = val % 0x10;
01198             ret[len++] = '%';
01199             ret[len++] = hi + (hi > 9? 'A'-10 : '0');
01200             ret[len++] = lo + (lo > 9? 'A'-10 : '0');
01201         }
01202         }
01203     } else if (uri->scheme != NULL) {
01204         if (len + 3 >= max) {
01205         max *= 2;
01206         temp = (xmlChar *) xmlRealloc(ret,
01207             (max + 1) * sizeof(xmlChar));
01208         if (temp == NULL) {
01209             xmlGenericError(xmlGenericErrorContext,
01210                 "xmlSaveUri: out of memory\n");
01211                      xmlFree(ret);
01212             return(NULL);
01213             }
01214             ret = temp;
01215         }
01216         ret[len++] = '/';
01217         ret[len++] = '/';
01218     }
01219     if (uri->path != NULL) {
01220         p = uri->path;
01221         /*
01222          * the colon in file:///d: should not be escaped or
01223          * Windows accesses fail later.
01224          */
01225         if ((uri->scheme != NULL) &&
01226         (p[0] == '/') &&
01227         (((p[1] >= 'a') && (p[1] <= 'z')) ||
01228          ((p[1] >= 'A') && (p[1] <= 'Z'))) &&
01229         (p[2] == ':') &&
01230             (xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) {
01231         if (len + 3 >= max) {
01232             max *= 2;
01233             ret = (xmlChar *) xmlRealloc(ret,
01234                 (max + 1) * sizeof(xmlChar));
01235             if (ret == NULL) {
01236             xmlGenericError(xmlGenericErrorContext,
01237                 "xmlSaveUri: out of memory\n");
01238             return(NULL);
01239             }
01240         }
01241         ret[len++] = *p++;
01242         ret[len++] = *p++;
01243         ret[len++] = *p++;
01244         }
01245         while (*p != 0) {
01246         if (len + 3 >= max) {
01247             max *= 2;
01248             temp = (xmlChar *) xmlRealloc(ret,
01249                 (max + 1) * sizeof(xmlChar));
01250             if (temp == NULL) {
01251             xmlGenericError(xmlGenericErrorContext,
01252                 "xmlSaveUri: out of memory\n");
01253                      xmlFree(ret);
01254             return(NULL);
01255             }
01256             ret = temp;
01257         }
01258         if ((IS_UNRESERVED(*(p))) || ((*(p) == '/')) ||
01259                     ((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) ||
01260                 ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||
01261                 ((*(p) == ',')))
01262             ret[len++] = *p++;
01263         else {
01264             int val = *(unsigned char *)p++;
01265             int hi = val / 0x10, lo = val % 0x10;
01266             ret[len++] = '%';
01267             ret[len++] = hi + (hi > 9? 'A'-10 : '0');
01268             ret[len++] = lo + (lo > 9? 'A'-10 : '0');
01269         }
01270         }
01271     }
01272     if (uri->query_raw != NULL) {
01273         if (len + 1 >= max) {
01274         max *= 2;
01275         temp = (xmlChar *) xmlRealloc(ret,
01276             (max + 1) * sizeof(xmlChar));
01277         if (temp == NULL) {
01278             xmlGenericError(xmlGenericErrorContext,
01279                 "xmlSaveUri: out of memory\n");
01280                      xmlFree(ret);
01281             return(NULL);
01282             }
01283             ret = temp;
01284         }
01285         ret[len++] = '?';
01286         p = uri->query_raw;
01287         while (*p != 0) {
01288         if (len + 1 >= max) {
01289             max *= 2;
01290             temp = (xmlChar *) xmlRealloc(ret,
01291                 (max + 1) * sizeof(xmlChar));
01292             if (temp == NULL) {
01293             xmlGenericError(xmlGenericErrorContext,
01294                 "xmlSaveUri: out of memory\n");
01295                      xmlFree(ret);
01296             return(NULL);
01297             }
01298             ret = temp;
01299         }
01300         ret[len++] = *p++;
01301         }
01302     } else if (uri->query != NULL) {
01303         if (len + 3 >= max) {
01304         max *= 2;
01305         temp = (xmlChar *) xmlRealloc(ret,
01306             (max + 1) * sizeof(xmlChar));
01307         if (temp == NULL) {
01308             xmlGenericError(xmlGenericErrorContext,
01309                 "xmlSaveUri: out of memory\n");
01310                      xmlFree(ret);
01311             return(NULL);
01312             }
01313             ret = temp;
01314         }
01315         ret[len++] = '?';
01316         p = uri->query;
01317         while (*p != 0) {
01318         if (len + 3 >= max) {
01319             max *= 2;
01320             temp = (xmlChar *) xmlRealloc(ret,
01321                 (max + 1) * sizeof(xmlChar));
01322             if (temp == NULL) {
01323             xmlGenericError(xmlGenericErrorContext,
01324                 "xmlSaveUri: out of memory\n");
01325                      xmlFree(ret);
01326             return(NULL);
01327             }
01328             ret = temp;
01329         }
01330         if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p)))) 
01331             ret[len++] = *p++;
01332         else {
01333             int val = *(unsigned char *)p++;
01334             int hi = val / 0x10, lo = val % 0x10;
01335             ret[len++] = '%';
01336             ret[len++] = hi + (hi > 9? 'A'-10 : '0');
01337             ret[len++] = lo + (lo > 9? 'A'-10 : '0');
01338         }
01339         }
01340     }
01341     }
01342     if (uri->fragment != NULL) {
01343     if (len + 3 >= max) {
01344         max *= 2;
01345         temp = (xmlChar *) xmlRealloc(ret,
01346             (max + 1) * sizeof(xmlChar));
01347         if (temp == NULL) {
01348             xmlGenericError(xmlGenericErrorContext,
01349                 "xmlSaveUri: out of memory\n");
01350                      xmlFree(ret);
01351             return(NULL);
01352             }
01353             ret = temp;
01354     }
01355     ret[len++] = '#';
01356     p = uri->fragment;
01357     while (*p != 0) {
01358         if (len + 3 >= max) {
01359         max *= 2;
01360         temp = (xmlChar *) xmlRealloc(ret,
01361             (max + 1) * sizeof(xmlChar));
01362         if (temp == NULL) {
01363             xmlGenericError(xmlGenericErrorContext,
01364                 "xmlSaveUri: out of memory\n");
01365                      xmlFree(ret);
01366             return(NULL);
01367             }
01368             ret = temp;
01369         }
01370         if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p)))) 
01371         ret[len++] = *p++;
01372         else {
01373         int val = *(unsigned char *)p++;
01374         int hi = val / 0x10, lo = val % 0x10;
01375         ret[len++] = '%';
01376         ret[len++] = hi + (hi > 9? 'A'-10 : '0');
01377         ret[len++] = lo + (lo > 9? 'A'-10 : '0');
01378         }
01379     }
01380     }
01381     if (len >= max) {
01382     max *= 2;
01383     temp = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
01384     if (temp == NULL) {
01385             xmlGenericError(xmlGenericErrorContext,
01386                 "xmlSaveUri: out of memory\n");
01387                      xmlFree(ret);
01388             return(NULL);
01389             }
01390             ret = temp;
01391     }
01392     ret[len] = 0;
01393     return(ret);
01394 }
01395 
01403 void
01404 xmlPrintURI(FILE *stream, xmlURIPtr uri) {
01405     xmlChar *out;
01406 
01407     out = xmlSaveUri(uri);
01408     if (out != NULL) {
01409     fprintf(stream, "%s", (char *) out);
01410     xmlFree(out);
01411     }
01412 }
01413 
01420 static void
01421 xmlCleanURI(xmlURIPtr uri) {
01422     if (uri == NULL) return;
01423 
01424     if (uri->scheme != NULL) xmlFree(uri->scheme);
01425     uri->scheme = NULL;
01426     if (uri->server != NULL) xmlFree(uri->server);
01427     uri->server = NULL;
01428     if (uri->user != NULL) xmlFree(uri->user);
01429     uri->user = NULL;
01430     if (uri->path != NULL) xmlFree(uri->path);
01431     uri->path = NULL;
01432     if (uri->fragment != NULL) xmlFree(uri->fragment);
01433     uri->fragment = NULL;
01434     if (uri->opaque != NULL) xmlFree(uri->opaque);
01435     uri->opaque = NULL;
01436     if (uri->authority != NULL) xmlFree(uri->authority);
01437     uri->authority = NULL;
01438     if (uri->query != NULL) xmlFree(uri->query);
01439     uri->query = NULL;
01440     if (uri->query_raw != NULL) xmlFree(uri->query_raw);
01441     uri->query_raw = NULL;
01442 }
01443 
01450 void
01451 xmlFreeURI(xmlURIPtr uri) {
01452     if (uri == NULL) return;
01453 
01454     if (uri->scheme != NULL) xmlFree(uri->scheme);
01455     if (uri->server != NULL) xmlFree(uri->server);
01456     if (uri->user != NULL) xmlFree(uri->user);
01457     if (uri->path != NULL) xmlFree(uri->path);
01458     if (uri->fragment != NULL) xmlFree(uri->fragment);
01459     if (uri->opaque != NULL) xmlFree(uri->opaque);
01460     if (uri->authority != NULL) xmlFree(uri->authority);
01461     if (uri->query != NULL) xmlFree(uri->query);
01462     if (uri->query_raw != NULL) xmlFree(uri->query_raw);
01463     xmlFree(uri);
01464 }
01465 
01466 /************************************************************************
01467  *                                  *
01468  *          Helper functions                *
01469  *                                  *
01470  ************************************************************************/
01471 
01483 int
01484 xmlNormalizeURIPath(char *path) {
01485     char *cur, *out;
01486 
01487     if (path == NULL)
01488     return(-1);
01489 
01490     /* Skip all initial "/" chars.  We want to get to the beginning of the
01491      * first non-empty segment.
01492      */
01493     cur = path;
01494     while (cur[0] == '/')
01495       ++cur;
01496     if (cur[0] == '\0')
01497       return(0);
01498 
01499     /* Keep everything we've seen so far.  */
01500     out = cur;
01501 
01502     /*
01503      * Analyze each segment in sequence for cases (c) and (d).
01504      */
01505     while (cur[0] != '\0') {
01506     /*
01507      * c) All occurrences of "./", where "." is a complete path segment,
01508      *    are removed from the buffer string.
01509      */
01510     if ((cur[0] == '.') && (cur[1] == '/')) {
01511         cur += 2;
01512         /* '//' normalization should be done at this point too */
01513         while (cur[0] == '/')
01514         cur++;
01515         continue;
01516     }
01517 
01518     /*
01519      * d) If the buffer string ends with "." as a complete path segment,
01520      *    that "." is removed.
01521      */
01522     if ((cur[0] == '.') && (cur[1] == '\0'))
01523         break;
01524 
01525     /* Otherwise keep the segment.  */
01526     while (cur[0] != '/') {
01527             if (cur[0] == '\0')
01528               goto done_cd;
01529         (out++)[0] = (cur++)[0];
01530     }
01531     /* nomalize // */
01532     while ((cur[0] == '/') && (cur[1] == '/'))
01533         cur++;
01534 
01535         (out++)[0] = (cur++)[0];
01536     }
01537  done_cd:
01538     out[0] = '\0';
01539 
01540     /* Reset to the beginning of the first segment for the next sequence.  */
01541     cur = path;
01542     while (cur[0] == '/')
01543       ++cur;
01544     if (cur[0] == '\0')
01545     return(0);
01546 
01547     /*
01548      * Analyze each segment in sequence for cases (e) and (f).
01549      *
01550      * e) All occurrences of "<segment>/../", where <segment> is a
01551      *    complete path segment not equal to "..", are removed from the
01552      *    buffer string.  Removal of these path segments is performed
01553      *    iteratively, removing the leftmost matching pattern on each
01554      *    iteration, until no matching pattern remains.
01555      *
01556      * f) If the buffer string ends with "<segment>/..", where <segment>
01557      *    is a complete path segment not equal to "..", that
01558      *    "<segment>/.." is removed.
01559      *
01560      * To satisfy the "iterative" clause in (e), we need to collapse the
01561      * string every time we find something that needs to be removed.  Thus,
01562      * we don't need to keep two pointers into the string: we only need a
01563      * "current position" pointer.
01564      */
01565     while (1) {
01566         char *segp, *tmp;
01567 
01568         /* At the beginning of each iteration of this loop, "cur" points to
01569          * the first character of the segment we want to examine.
01570          */
01571 
01572         /* Find the end of the current segment.  */
01573         segp = cur;
01574         while ((segp[0] != '/') && (segp[0] != '\0'))
01575           ++segp;
01576 
01577         /* If this is the last segment, we're done (we need at least two
01578          * segments to meet the criteria for the (e) and (f) cases).
01579          */
01580         if (segp[0] == '\0')
01581           break;
01582 
01583         /* If the first segment is "..", or if the next segment _isn't_ "..",
01584          * keep this segment and try the next one.
01585          */
01586         ++segp;
01587         if (((cur[0] == '.') && (cur[1] == '.') && (segp == cur+3))
01588             || ((segp[0] != '.') || (segp[1] != '.')
01589                 || ((segp[2] != '/') && (segp[2] != '\0')))) {
01590           cur = segp;
01591           continue;
01592         }
01593 
01594         /* If we get here, remove this segment and the next one and back up
01595          * to the previous segment (if there is one), to implement the
01596          * "iteratively" clause.  It's pretty much impossible to back up
01597          * while maintaining two pointers into the buffer, so just compact
01598          * the whole buffer now.
01599          */
01600 
01601         /* If this is the end of the buffer, we're done.  */
01602         if (segp[2] == '\0') {
01603           cur[0] = '\0';
01604           break;
01605         }
01606         /* Valgrind complained, strcpy(cur, segp + 3); */
01607     /* string will overlap, do not use strcpy */
01608     tmp = cur;
01609     segp += 3;
01610     while ((*tmp++ = *segp++) != 0);
01611 
01612         /* If there are no previous segments, then keep going from here.  */
01613         segp = cur;
01614         while ((segp > path) && ((--segp)[0] == '/'))
01615           ;
01616         if (segp == path)
01617           continue;
01618 
01619         /* "segp" is pointing to the end of a previous segment; find it's
01620          * start.  We need to back up to the previous segment and start
01621          * over with that to handle things like "foo/bar/../..".  If we
01622          * don't do this, then on the first pass we'll remove the "bar/..",
01623          * but be pointing at the second ".." so we won't realize we can also
01624          * remove the "foo/..".
01625          */
01626         cur = segp;
01627         while ((cur > path) && (cur[-1] != '/'))
01628           --cur;
01629     }
01630     out[0] = '\0';
01631 
01632     /*
01633      * g) If the resulting buffer string still begins with one or more
01634      *    complete path segments of "..", then the reference is
01635      *    considered to be in error. Implementations may handle this
01636      *    error by retaining these components in the resolved path (i.e.,
01637      *    treating them as part of the final URI), by removing them from
01638      *    the resolved path (i.e., discarding relative levels above the
01639      *    root), or by avoiding traversal of the reference.
01640      *
01641      * We discard them from the final path.
01642      */
01643     if (path[0] == '/') {
01644       cur = path;
01645       while ((cur[0] == '/') && (cur[1] == '.') && (cur[2] == '.')
01646              && ((cur[3] == '/') || (cur[3] == '\0')))
01647     cur += 3;
01648 
01649       if (cur != path) {
01650     out = path;
01651     while (cur[0] != '\0')
01652           (out++)[0] = (cur++)[0];
01653     out[0] = 0;
01654       }
01655     }
01656 
01657     return(0);
01658 }
01659 
01660 static int is_hex(char c) {
01661     if (((c >= '0') && (c <= '9')) ||
01662         ((c >= 'a') && (c <= 'f')) ||
01663         ((c >= 'A') && (c <= 'F')))
01664     return(1);
01665     return(0);
01666 }
01667 
01682 char *
01683 xmlURIUnescapeString(const char *str, int len, char *target) {
01684     char *ret, *out;
01685     const char *in;
01686 
01687     if (str == NULL)
01688     return(NULL);
01689     if (len <= 0) len = strlen(str);
01690     if (len < 0) return(NULL);
01691 
01692     if (target == NULL) {
01693     ret = (char *) xmlMallocAtomic(len + 1);
01694     if (ret == NULL) {
01695         xmlGenericError(xmlGenericErrorContext,
01696             "xmlURIUnescapeString: out of memory\n");
01697         return(NULL);
01698     }
01699     } else
01700     ret = target;
01701     in = str;
01702     out = ret;
01703     while(len > 0) {
01704     if ((len > 2) && (*in == '%') && (is_hex(in[1])) && (is_hex(in[2]))) {
01705         in++;
01706         if ((*in >= '0') && (*in <= '9')) 
01707             *out = (*in - '0');
01708         else if ((*in >= 'a') && (*in <= 'f'))
01709             *out = (*in - 'a') + 10;
01710         else if ((*in >= 'A') && (*in <= 'F'))
01711             *out = (*in - 'A') + 10;
01712         in++;
01713         if ((*in >= '0') && (*in <= '9')) 
01714             *out = *out * 16 + (*in - '0');
01715         else if ((*in >= 'a') && (*in <= 'f'))
01716             *out = *out * 16 + (*in - 'a') + 10;
01717         else if ((*in >= 'A') && (*in <= 'F'))
01718             *out = *out * 16 + (*in - 'A') + 10;
01719         in++;
01720         len -= 3;
01721         out++;
01722     } else {
01723         *out++ = *in++;
01724         len--;
01725     }
01726     }
01727     *out = 0;
01728     return(ret);
01729 }
01730 
01741 xmlChar *
01742 xmlURIEscapeStr(const xmlChar *str, const xmlChar *list) {
01743     xmlChar *ret, ch;
01744     xmlChar *temp;
01745     const xmlChar *in;
01746 
01747     unsigned int len, out;
01748 
01749     if (str == NULL)
01750     return(NULL);
01751     if (str[0] == 0)
01752     return(xmlStrdup(str));
01753     len = xmlStrlen(str);
01754     if (!(len > 0)) return(NULL);
01755 
01756     len += 20;
01757     ret = (xmlChar *) xmlMallocAtomic(len);
01758     if (ret == NULL) {
01759     xmlGenericError(xmlGenericErrorContext,
01760         "xmlURIEscapeStr: out of memory\n");
01761     return(NULL);
01762     }
01763     in = (const xmlChar *) str;
01764     out = 0;
01765     while(*in != 0) {
01766     if (len - out <= 3) {
01767         len += 20;
01768         temp = (xmlChar *) xmlRealloc(ret, len);
01769         if (temp == NULL) {
01770         xmlGenericError(xmlGenericErrorContext,
01771             "xmlURIEscapeStr: out of memory\n");
01772         xmlFree(ret);
01773         return(NULL);
01774         }
01775         ret = temp;
01776     }
01777 
01778     ch = *in;
01779 
01780     if ((ch != '@') && (!IS_UNRESERVED(ch)) && (!xmlStrchr(list, ch))) {
01781         unsigned char val;
01782         ret[out++] = '%';
01783         val = ch >> 4;
01784         if (val <= 9)
01785         ret[out++] = '0' + val;
01786         else
01787         ret[out++] = 'A' + val - 0xA;
01788         val = ch & 0xF;
01789         if (val <= 9)
01790         ret[out++] = '0' + val;
01791         else
01792         ret[out++] = 'A' + val - 0xA;
01793         in++;
01794     } else {
01795         ret[out++] = *in++;
01796     }
01797 
01798     }
01799     ret[out] = 0;
01800     return(ret);
01801 }
01802 
01818 xmlChar *
01819 xmlURIEscape(const xmlChar * str)
01820 {
01821     xmlChar *ret, *segment = NULL;
01822     xmlURIPtr uri;
01823     int ret2;
01824 
01825 #define NULLCHK(p) if(!p) { \
01826                    xmlGenericError(xmlGenericErrorContext, \
01827                         "xmlURIEscape: out of memory\n"); \
01828                         xmlFreeURI(uri); \
01829                         return NULL; } \
01830 
01831     if (str == NULL)
01832         return (NULL);
01833 
01834     uri = xmlCreateURI();
01835     if (uri != NULL) {
01836     /*
01837      * Allow escaping errors in the unescaped form
01838      */
01839         uri->cleanup = 1;
01840         ret2 = xmlParseURIReference(uri, (const char *)str);
01841         if (ret2) {
01842             xmlFreeURI(uri);
01843             return (NULL);
01844         }
01845     }
01846 
01847     if (!uri)
01848         return NULL;
01849 
01850     ret = NULL;
01851 
01852     if (uri->scheme) {
01853         segment = xmlURIEscapeStr(BAD_CAST uri->scheme, BAD_CAST "+-.");
01854         NULLCHK(segment)
01855         ret = xmlStrcat(ret, segment);
01856         ret = xmlStrcat(ret, BAD_CAST ":");
01857         xmlFree(segment);
01858     }
01859 
01860     if (uri->authority) {
01861         segment =
01862             xmlURIEscapeStr(BAD_CAST uri->authority, BAD_CAST "/?;:@");
01863         NULLCHK(segment)
01864         ret = xmlStrcat(ret, BAD_CAST "//");
01865         ret = xmlStrcat(ret, segment);
01866         xmlFree(segment);
01867     }
01868 
01869     if (uri->user) {
01870         segment = xmlURIEscapeStr(BAD_CAST uri->user, BAD_CAST ";:&=+$,");
01871         NULLCHK(segment)
01872         ret = xmlStrcat(ret,BAD_CAST "//"); 
01873         ret = xmlStrcat(ret, segment);
01874         ret = xmlStrcat(ret, BAD_CAST "@");
01875         xmlFree(segment);
01876     }
01877 
01878     if (uri->server) {
01879         segment = xmlURIEscapeStr(BAD_CAST uri->server, BAD_CAST "/?;:@");
01880         NULLCHK(segment)
01881         if (uri->user == NULL)
01882         ret = xmlStrcat(ret, BAD_CAST "//");
01883         ret = xmlStrcat(ret, segment);
01884         xmlFree(segment);
01885     }
01886 
01887     if (uri->port) {
01888         xmlChar port[10];
01889 
01890         snprintf((char *) port, 10, "%d", uri->port);
01891         ret = xmlStrcat(ret, BAD_CAST ":");
01892         ret = xmlStrcat(ret, port);
01893     }
01894 
01895     if (uri->path) {
01896         segment =
01897             xmlURIEscapeStr(BAD_CAST uri->path, BAD_CAST ":@&=+$,/?;");
01898         NULLCHK(segment)
01899         ret = xmlStrcat(ret, segment);
01900         xmlFree(segment);
01901     }
01902 
01903     if (uri->query_raw) {
01904         ret = xmlStrcat(ret, BAD_CAST "?");
01905         ret = xmlStrcat(ret, BAD_CAST uri->query_raw);
01906     }
01907     else if (uri->query) {
01908         segment =
01909             xmlURIEscapeStr(BAD_CAST uri->query, BAD_CAST ";/?:@&=+,$");
01910         NULLCHK(segment)
01911         ret = xmlStrcat(ret, BAD_CAST "?");
01912         ret = xmlStrcat(ret, segment);
01913         xmlFree(segment);
01914     }
01915 
01916     if (uri->opaque) {
01917         segment = xmlURIEscapeStr(BAD_CAST uri->opaque, BAD_CAST "");
01918         NULLCHK(segment)
01919         ret = xmlStrcat(ret, segment);
01920         xmlFree(segment);
01921     }
01922 
01923     if (uri->fragment) {
01924         segment = xmlURIEscapeStr(BAD_CAST uri->fragment, BAD_CAST "#");
01925         NULLCHK(segment)
01926         ret = xmlStrcat(ret, BAD_CAST "#");
01927         ret = xmlStrcat(ret, segment);
01928         xmlFree(segment);
01929     }
01930 
01931     xmlFreeURI(uri);
01932 #undef NULLCHK
01933 
01934     return (ret);
01935 }
01936 
01937 /************************************************************************
01938  *                                  *
01939  *          Public functions                *
01940  *                                  *
01941  ************************************************************************/
01942 
01958 xmlChar *
01959 xmlBuildURI(const xmlChar *URI, const xmlChar *base) {
01960     xmlChar *val = NULL;
01961     int ret, len, indx, cur, out;
01962     xmlURIPtr ref = NULL;
01963     xmlURIPtr bas = NULL;
01964     xmlURIPtr res = NULL;
01965 
01966     /*
01967      * 1) The URI reference is parsed into the potential four components and
01968      *    fragment identifier, as described in Section 4.3.
01969      *
01970      *    NOTE that a completely empty URI is treated by modern browsers
01971      *    as a reference to "." rather than as a synonym for the current
01972      *    URI.  Should we do that here?
01973      */
01974     if (URI == NULL) 
01975     ret = -1;
01976     else {
01977     if (*URI) {
01978         ref = xmlCreateURI();
01979         if (ref == NULL)
01980         goto done;
01981         ret = xmlParseURIReference(ref, (const char *) URI);
01982     }
01983     else
01984         ret = 0;
01985     }
01986     if (ret != 0)
01987     goto done;
01988     if ((ref != NULL) && (ref->scheme != NULL)) {
01989     /*
01990      * The URI is absolute don't modify.
01991      */
01992     val = xmlStrdup(URI);
01993     goto done;
01994     }
01995     if (base == NULL)
01996     ret = -1;
01997     else {
01998     bas = xmlCreateURI();
01999     if (bas == NULL)
02000         goto done;
02001     ret = xmlParseURIReference(bas, (const char *) base);
02002     }
02003     if (ret != 0) {
02004     if (ref)
02005         val = xmlSaveUri(ref);
02006     goto done;
02007     }
02008     if (ref == NULL) {
02009     /*
02010      * the base fragment must be ignored
02011      */
02012     if (bas->fragment != NULL) {
02013         xmlFree(bas->fragment);
02014         bas->fragment = NULL;
02015     }
02016     val = xmlSaveUri(bas);
02017     goto done;
02018     }
02019 
02020     /*
02021      * 2) If the path component is empty and the scheme, authority, and
02022      *    query components are undefined, then it is a reference to the
02023      *    current document and we are done.  Otherwise, the reference URI's
02024      *    query and fragment components are defined as found (or not found)
02025      *    within the URI reference and not inherited from the base URI.
02026      *
02027      *    NOTE that in modern browsers, the parsing differs from the above
02028      *    in the following aspect:  the query component is allowed to be
02029      *    defined while still treating this as a reference to the current
02030      *    document.
02031      */
02032     res = xmlCreateURI();
02033     if (res == NULL)
02034     goto done;
02035     if ((ref->scheme == NULL) && (ref->path == NULL) &&
02036     ((ref->authority == NULL) && (ref->server == NULL))) {
02037     if (bas->scheme != NULL)
02038         res->scheme = xmlMemStrdup(bas->scheme);
02039     if (bas->authority != NULL)
02040         res->authority = xmlMemStrdup(bas->authority);
02041     else if (bas->server != NULL) {
02042         res->server = xmlMemStrdup(bas->server);
02043         if (bas->user != NULL)
02044         res->user = xmlMemStrdup(bas->user);
02045         res->port = bas->port;      
02046     }
02047     if (bas->path != NULL)
02048         res->path = xmlMemStrdup(bas->path);
02049     if (ref->query_raw != NULL)
02050         res->query_raw = xmlMemStrdup (ref->query_raw);
02051     else if (ref->query != NULL)
02052         res->query = xmlMemStrdup(ref->query);
02053     else if (bas->query_raw != NULL)
02054         res->query_raw = xmlMemStrdup(bas->query_raw);
02055     else if (bas->query != NULL)
02056         res->query = xmlMemStrdup(bas->query);
02057     if (ref->fragment != NULL)
02058         res->fragment = xmlMemStrdup(ref->fragment);
02059     goto step_7;
02060     }
02061 
02062     /*
02063      * 3) If the scheme component is defined, indicating that the reference
02064      *    starts with a scheme name, then the reference is interpreted as an
02065      *    absolute URI and we are done.  Otherwise, the reference URI's
02066      *    scheme is inherited from the base URI's scheme component.
02067      */
02068     if (ref->scheme != NULL) {
02069     val = xmlSaveUri(ref);
02070     goto done;
02071     }
02072     if (bas->scheme != NULL)
02073     res->scheme = xmlMemStrdup(bas->scheme);
02074  
02075     if (ref->query_raw != NULL)
02076     res->query_raw = xmlMemStrdup(ref->query_raw);
02077     else if (ref->query != NULL)
02078     res->query = xmlMemStrdup(ref->query);
02079     if (ref->fragment != NULL)
02080     res->fragment = xmlMemStrdup(ref->fragment);
02081 
02082     /*
02083      * 4) If the authority component is defined, then the reference is a
02084      *    network-path and we skip to step 7.  Otherwise, the reference
02085      *    URI's authority is inherited from the base URI's authority
02086      *    component, which will also be undefined if the URI scheme does not
02087      *    use an authority component.
02088      */
02089     if ((ref->authority != NULL) || (ref->server != NULL)) {
02090     if (ref->authority != NULL)
02091         res->authority = xmlMemStrdup(ref->authority);
02092     else {
02093         res->server = xmlMemStrdup(ref->server);
02094         if (ref->user != NULL)
02095         res->user = xmlMemStrdup(ref->user);
02096             res->port = ref->port;      
02097     }
02098     if (ref->path != NULL)
02099         res->path = xmlMemStrdup(ref->path);
02100     goto step_7;
02101     }
02102     if (bas->authority != NULL)
02103     res->authority = xmlMemStrdup(bas->authority);
02104     else if (bas->server != NULL) {
02105     res->server = xmlMemStrdup(bas->server);
02106     if (bas->user != NULL)
02107         res->user = xmlMemStrdup(bas->user);
02108     res->port = bas->port;      
02109     }
02110 
02111     /*
02112      * 5) If the path component begins with a slash character ("/"), then
02113      *    the reference is an absolute-path and we skip to step 7.
02114      */
02115     if ((ref->path != NULL) && (ref->path[0] == '/')) {
02116     res->path = xmlMemStrdup(ref->path);
02117     goto step_7;
02118     }
02119 
02120 
02121     /*
02122      * 6) If this step is reached, then we are resolving a relative-path
02123      *    reference.  The relative path needs to be merged with the base
02124      *    URI's path.  Although there are many ways to do this, we will
02125      *    describe a simple method using a separate string buffer.
02126      *
02127      * Allocate a buffer large enough for the result string.
02128      */
02129     len = 2; /* extra / and 0 */
02130     if (ref->path != NULL)
02131     len += strlen(ref->path);
02132     if (bas->path != NULL)
02133     len += strlen(bas->path);
02134     res->path = (char *) xmlMallocAtomic(len);
02135     if (res->path == NULL) {
02136     xmlGenericError(xmlGenericErrorContext,
02137         "xmlBuildURI: out of memory\n");
02138     goto done;
02139     }
02140     res->path[0] = 0;
02141 
02142     /*
02143      * a) All but the last segment of the base URI's path component is
02144      *    copied to the buffer.  In other words, any characters after the
02145      *    last (right-most) slash character, if any, are excluded.
02146      */
02147     cur = 0;
02148     out = 0;
02149     if (bas->path != NULL) {
02150     while (bas->path[cur] != 0) {
02151         while ((bas->path[cur] != 0) && (bas->path[cur] != '/'))
02152         cur++;
02153         if (bas->path[cur] == 0)
02154         break;
02155 
02156         cur++;
02157         while (out < cur) {
02158         res->path[out] = bas->path[out];
02159         out++;
02160         }
02161     }
02162     }
02163     res->path[out] = 0;
02164 
02165     /*
02166      * b) The reference's path component is appended to the buffer
02167      *    string.
02168      */
02169     if (ref->path != NULL && ref->path[0] != 0) {
02170     indx = 0;
02171     /*
02172      * Ensure the path includes a '/'
02173      */
02174     if ((out == 0) && (bas->server != NULL))
02175         res->path[out++] = '/';
02176     while (ref->path[indx] != 0) {
02177         res->path[out++] = ref->path[indx++];
02178     }
02179     }
02180     res->path[out] = 0;
02181 
02182     /*
02183      * Steps c) to h) are really path normalization steps
02184      */
02185     xmlNormalizeURIPath(res->path);
02186 
02187 step_7:
02188 
02189     /*
02190      * 7) The resulting URI components, including any inherited from the
02191      *    base URI, are recombined to give the absolute form of the URI
02192      *    reference.
02193      */
02194     val = xmlSaveUri(res);
02195 
02196 done:
02197     if (ref != NULL)
02198     xmlFreeURI(ref);
02199     if (bas != NULL)
02200     xmlFreeURI(bas);
02201     if (res != NULL)
02202     xmlFreeURI(res);
02203     return(val);
02204 }
02205 
02238 xmlChar *
02239 xmlBuildRelativeURI (const xmlChar * URI, const xmlChar * base)
02240 {
02241     xmlChar *val = NULL;
02242     int ret;
02243     int ix;
02244     int pos = 0;
02245     int nbslash = 0;
02246     int len;
02247     xmlURIPtr ref = NULL;
02248     xmlURIPtr bas = NULL;
02249     xmlChar *bptr, *uptr, *vptr;
02250     int remove_path = 0;
02251 
02252     if ((URI == NULL) || (*URI == 0))
02253     return NULL;
02254 
02255     /*
02256      * First parse URI into a standard form
02257      */
02258     ref = xmlCreateURI ();
02259     if (ref == NULL)
02260     return NULL;
02261     /* If URI not already in "relative" form */
02262     if (URI[0] != '.') {
02263     ret = xmlParseURIReference (ref, (const char *) URI);
02264     if (ret != 0)
02265         goto done;      /* Error in URI, return NULL */
02266     } else
02267     ref->path = (char *)xmlStrdup(URI);
02268 
02269     /*
02270      * Next parse base into the same standard form
02271      */
02272     if ((base == NULL) || (*base == 0)) {
02273     val = xmlStrdup (URI);
02274     goto done;
02275     }
02276     bas = xmlCreateURI ();
02277     if (bas == NULL)
02278     goto done;
02279     if (base[0] != '.') {
02280     ret = xmlParseURIReference (bas, (const char *) base);
02281     if (ret != 0)
02282         goto done;      /* Error in base, return NULL */
02283     } else
02284     bas->path = (char *)xmlStrdup(base);
02285 
02286     /*
02287      * If the scheme / server on the URI differs from the base,
02288      * just return the URI
02289      */
02290     if ((ref->scheme != NULL) &&
02291     ((bas->scheme == NULL) ||
02292      (xmlStrcmp ((xmlChar *)bas->scheme, (xmlChar *)ref->scheme)) ||
02293      (xmlStrcmp ((xmlChar *)bas->server, (xmlChar *)ref->server)))) {
02294     val = xmlStrdup (URI);
02295     goto done;
02296     }
02297     if (xmlStrEqual((xmlChar *)bas->path, (xmlChar *)ref->path)) {
02298     val = xmlStrdup(BAD_CAST "");
02299     goto done;
02300     }
02301     if (bas->path == NULL) {
02302     val = xmlStrdup((xmlChar *)ref->path);
02303     goto done;
02304     }
02305     if (ref->path == NULL) {
02306         ref->path = (char *) "/";
02307     remove_path = 1;
02308     }
02309 
02310     /*
02311      * At this point (at last!) we can compare the two paths
02312      *
02313      * First we take care of the special case where either of the
02314      * two path components may be missing (bug 316224)
02315      */
02316     if (bas->path == NULL) {
02317     if (ref->path != NULL) {
02318         uptr = (xmlChar *) ref->path;
02319         if (*uptr == '/')
02320         uptr++;
02321         /* exception characters from xmlSaveUri */
02322         val = xmlURIEscapeStr(uptr, BAD_CAST "/;&=+$,");
02323     }
02324     goto done;
02325     }
02326     bptr = (xmlChar *)bas->path;
02327     if (ref->path == NULL) {
02328     for (ix = 0; bptr[ix] != 0; ix++) {
02329         if (bptr[ix] == '/')
02330         nbslash++;
02331     }
02332     uptr = NULL;
02333     len = 1;    /* this is for a string terminator only */
02334     } else {
02335     /*
02336      * Next we compare the two strings and find where they first differ
02337      */
02338     if ((ref->path[pos] == '.') && (ref->path[pos+1] == '/'))
02339             pos += 2;
02340     if ((*bptr == '.') && (bptr[1] == '/'))
02341             bptr += 2;
02342     else if ((*bptr == '/') && (ref->path[pos] != '/'))
02343         bptr++;
02344     while ((bptr[pos] == ref->path[pos]) && (bptr[pos] != 0))
02345         pos++;
02346 
02347     if (bptr[pos] == ref->path[pos]) {
02348         val = xmlStrdup(BAD_CAST "");
02349         goto done;      /* (I can't imagine why anyone would do this) */
02350     }
02351 
02352     /*
02353      * In URI, "back up" to the last '/' encountered.  This will be the
02354      * beginning of the "unique" suffix of URI
02355      */
02356     ix = pos;
02357     if ((ref->path[ix] == '/') && (ix > 0))
02358         ix--;
02359     else if ((ref->path[ix] == 0) && (ix > 1) && (ref->path[ix - 1] == '/'))
02360         ix -= 2;
02361     for (; ix > 0; ix--) {
02362         if (ref->path[ix] == '/')
02363         break;
02364     }
02365     if (ix == 0) {
02366         uptr = (xmlChar *)ref->path;
02367     } else {
02368         ix++;
02369         uptr = (xmlChar *)&ref->path[ix];
02370     }
02371 
02372     /*
02373      * In base, count the number of '/' from the differing point
02374      */
02375     if (bptr[pos] != ref->path[pos]) {/* check for trivial URI == base */
02376         for (; bptr[ix] != 0; ix++) {
02377         if (bptr[ix] == '/')
02378             nbslash++;
02379         }
02380     }
02381     len = xmlStrlen (uptr) + 1;
02382     }
02383     
02384     if (nbslash == 0) {
02385     if (uptr != NULL)
02386         /* exception characters from xmlSaveUri */
02387         val = xmlURIEscapeStr(uptr, BAD_CAST "/;&=+$,");
02388     goto done;
02389     }
02390 
02391     /*
02392      * Allocate just enough space for the returned string -
02393      * length of the remainder of the URI, plus enough space
02394      * for the "../" groups, plus one for the terminator
02395      */
02396     val = (xmlChar *) xmlMalloc (len + 3 * nbslash);
02397     if (val == NULL) {
02398     xmlGenericError(xmlGenericErrorContext,
02399         "xmlBuildRelativeURI: out of memory\n");
02400     goto done;
02401     }
02402     vptr = val;
02403     /*
02404      * Put in as many "../" as needed
02405      */
02406     for (; nbslash>0; nbslash--) {
02407     *vptr++ = '.';
02408     *vptr++ = '.';
02409     *vptr++ = '/';
02410     }
02411     /*
02412      * Finish up with the end of the URI
02413      */
02414     if (uptr != NULL) {
02415         if ((vptr > val) && (len > 0) &&
02416         (uptr[0] == '/') && (vptr[-1] == '/')) {
02417         memcpy (vptr, uptr + 1, len - 1);
02418         vptr[len - 2] = 0;
02419     } else {
02420         memcpy (vptr, uptr, len);
02421         vptr[len - 1] = 0;
02422     }
02423     } else {
02424     vptr[len - 1] = 0;
02425     }
02426 
02427     /* escape the freshly-built path */
02428     vptr = val;
02429     /* exception characters from xmlSaveUri */
02430     val = xmlURIEscapeStr(vptr, BAD_CAST "/;&=+$,");
02431     xmlFree(vptr);
02432 
02433 done:
02434     /*
02435      * Free the working variables
02436      */
02437     if (remove_path != 0)
02438         ref->path = NULL;
02439     if (ref != NULL)
02440     xmlFreeURI (ref);
02441     if (bas != NULL)
02442     xmlFreeURI (bas);
02443 
02444     return val;
02445 }
02446 
02458 #define IS_WINDOWS_PATH(p)                  \
02459     ((p != NULL) &&                     \
02460      (((p[0] >= 'a') && (p[0] <= 'z')) ||           \
02461       ((p[0] >= 'A') && (p[0] <= 'Z'))) &&          \
02462      (p[1] == ':') && ((p[2] == '/') || (p[2] == '\\')))
02463 xmlChar *
02464 xmlCanonicPath(const xmlChar *path)
02465 {
02466 /*
02467  * For Windows implementations, additional work needs to be done to
02468  * replace backslashes in pathnames with "forward slashes"
02469  */
02470 #if defined(_WIN32) && !defined(__CYGWIN__)    
02471     int len = 0;
02472     int i = 0;
02473     xmlChar *p = NULL;
02474 #endif
02475     xmlURIPtr uri;
02476     xmlChar *ret;
02477     const xmlChar *absuri;
02478 
02479     if (path == NULL)
02480     return(NULL);
02481 
02482     /* sanitize filename starting with // so it can be used as URI */
02483     if ((path[0] == '/') && (path[1] == '/') && (path[2] != '/'))
02484         path++;
02485 
02486     if ((uri = xmlParseURI((const char *) path)) != NULL) {
02487     xmlFreeURI(uri);
02488     return xmlStrdup(path);
02489     }
02490 
02491     /* Check if this is an "absolute uri" */
02492     absuri = xmlStrstr(path, BAD_CAST "://");
02493     if (absuri != NULL) {
02494         int l, j;
02495     unsigned char c;
02496     xmlChar *escURI;
02497 
02498         /*
02499      * this looks like an URI where some parts have not been
02500      * escaped leading to a parsing problem.  Check that the first
02501      * part matches a protocol.
02502      */
02503     l = absuri - path;
02504     /* Bypass if first part (part before the '://') is > 20 chars */
02505     if ((l <= 0) || (l > 20))
02506         goto path_processing;
02507     /* Bypass if any non-alpha characters are present in first part */
02508     for (j = 0;j < l;j++) {
02509         c = path[j];
02510         if (!(((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))))
02511             goto path_processing;
02512     }
02513 
02514     /* Escape all except the characters specified in the supplied path */
02515         escURI = xmlURIEscapeStr(path, BAD_CAST ":/?_.#&;=");
02516     if (escURI != NULL) {
02517         /* Try parsing the escaped path */
02518         uri = xmlParseURI((const char *) escURI);
02519         /* If successful, return the escaped string */
02520         if (uri != NULL) {
02521             xmlFreeURI(uri);
02522         return escURI;
02523         }
02524     }
02525     }
02526 
02527 path_processing:
02528 /* For Windows implementations, replace backslashes with 'forward slashes' */
02529 #if defined(_WIN32) && !defined(__CYGWIN__)    
02530     /*
02531      * Create a URI structure
02532      */
02533     uri = xmlCreateURI();
02534     if (uri == NULL) {      /* Guard against 'out of memory' */
02535         return(NULL);
02536     }
02537 
02538     len = xmlStrlen(path);
02539     if ((len > 2) && IS_WINDOWS_PATH(path)) {
02540         /* make the scheme 'file' */
02541     uri->scheme = xmlStrdup(BAD_CAST "file");
02542     /* allocate space for leading '/' + path + string terminator */
02543     uri->path = xmlMallocAtomic(len + 2);
02544     if (uri->path == NULL) {
02545         xmlFreeURI(uri);    /* Guard agains 'out of memory' */
02546         return(NULL);
02547     }
02548     /* Put in leading '/' plus path */
02549     uri->path[0] = '/';
02550     p = uri->path + 1;
02551     strncpy(p, path, len + 1);
02552     } else {
02553     uri->path = xmlStrdup(path);
02554     if (uri->path == NULL) {
02555         xmlFreeURI(uri);
02556         return(NULL);
02557     }
02558     p = uri->path;
02559     }
02560     /* Now change all occurences of '\' to '/' */
02561     while (*p != '\0') {
02562     if (*p == '\\')
02563         *p = '/';
02564     p++;
02565     }
02566 
02567     if (uri->scheme == NULL) {
02568     ret = xmlStrdup((const xmlChar *) uri->path);
02569     } else {
02570     ret = xmlSaveUri(uri);
02571     }
02572 
02573     xmlFreeURI(uri);
02574 #else
02575     ret = xmlStrdup((const xmlChar *) path);
02576 #endif
02577     return(ret);
02578 }
02579 
02591 xmlChar *
02592 xmlPathToURI(const xmlChar *path)
02593 {
02594     xmlURIPtr uri;
02595     xmlURI temp;
02596     xmlChar *ret, *cal;
02597 
02598     if (path == NULL)
02599         return(NULL);
02600 
02601     if ((uri = xmlParseURI((const char *) path)) != NULL) {
02602     xmlFreeURI(uri);
02603     return xmlStrdup(path);
02604     }
02605     cal = xmlCanonicPath(path);
02606     if (cal == NULL)
02607         return(NULL);
02608 #if defined(_WIN32) && !defined(__CYGWIN__)
02609     /* xmlCanonicPath can return an URI on Windows (is that the intended behaviour?) 
02610        If 'cal' is a valid URI allready then we are done here, as continuing would make
02611        it invalid. */
02612     if ((uri = xmlParseURI((const char *) cal)) != NULL) {
02613     xmlFreeURI(uri);
02614     return cal;
02615     }
02616     /* 'cal' can contain a relative path with backslashes. If that is processed
02617        by xmlSaveURI, they will be escaped and the external entity loader machinery
02618        will fail. So convert them to slashes. Misuse 'ret' for walking. */
02619     ret = cal;
02620     while (*ret != '\0') {
02621     if (*ret == '\\')
02622         *ret = '/';
02623     ret++;
02624     }
02625 #endif
02626     memset(&temp, 0, sizeof(temp));
02627     temp.path = (char *) cal;
02628     ret = xmlSaveUri(&temp);
02629     xmlFree(cal);
02630     return(ret);
02631 }
02632 #define bottom_uri
02633 #include "elfgcchack.h"

Generated on Sat May 26 2012 04:25:17 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.