Blame uri.c

Packit 423ecb
/**
Packit 423ecb
 * uri.c: set of generic URI related routines
Packit 423ecb
 *
Packit 423ecb
 * Reference: RFCs 3986, 2732 and 2373
Packit 423ecb
 *
Packit 423ecb
 * See Copyright for the status of this software.
Packit 423ecb
 *
Packit 423ecb
 * daniel@veillard.com
Packit 423ecb
 */
Packit 423ecb
Packit 423ecb
#define IN_LIBXML
Packit 423ecb
#include "libxml.h"
Packit 423ecb
Packit 423ecb
#include <string.h>
Packit 423ecb
Packit 423ecb
#include <libxml/xmlmemory.h>
Packit 423ecb
#include <libxml/uri.h>
Packit 423ecb
#include <libxml/globals.h>
Packit 423ecb
#include <libxml/xmlerror.h>
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * MAX_URI_LENGTH:
Packit 423ecb
 *
Packit 423ecb
 * The definition of the URI regexp in the above RFC has no size limit
Packit 423ecb
 * In practice they are usually relativey short except for the
Packit 423ecb
 * data URI scheme as defined in RFC 2397. Even for data URI the usual
Packit 423ecb
 * maximum size before hitting random practical limits is around 64 KB
Packit 423ecb
 * and 4KB is usually a maximum admitted limit for proper operations.
Packit 423ecb
 * The value below is more a security limit than anything else and
Packit 423ecb
 * really should never be hit by 'normal' operations
Packit 423ecb
 * Set to 1 MByte in 2012, this is only enforced on output
Packit 423ecb
 */
Packit 423ecb
#define MAX_URI_LENGTH 1024 * 1024
Packit 423ecb
Packit 423ecb
static void
Packit 423ecb
xmlURIErrMemory(const char *extra)
Packit 423ecb
{
Packit 423ecb
    if (extra)
Packit 423ecb
        __xmlRaiseError(NULL, NULL, NULL,
Packit 423ecb
                        NULL, NULL, XML_FROM_URI,
Packit 423ecb
                        XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
Packit 423ecb
                        extra, NULL, NULL, 0, 0,
Packit 423ecb
                        "Memory allocation failed : %s\n", extra);
Packit 423ecb
    else
Packit 423ecb
        __xmlRaiseError(NULL, NULL, NULL,
Packit 423ecb
                        NULL, NULL, XML_FROM_URI,
Packit 423ecb
                        XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
Packit 423ecb
                        NULL, NULL, NULL, 0, 0,
Packit 423ecb
                        "Memory allocation failed\n");
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
static void xmlCleanURI(xmlURIPtr uri);
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 * Old rule from 2396 used in legacy handling code
Packit 423ecb
 * alpha    = lowalpha | upalpha
Packit 423ecb
 */
Packit 423ecb
#define IS_ALPHA(x) (IS_LOWALPHA(x) || IS_UPALPHA(x))
Packit 423ecb
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 * lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" |
Packit 423ecb
 *            "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" |
Packit 423ecb
 *            "u" | "v" | "w" | "x" | "y" | "z"
Packit 423ecb
 */
Packit 423ecb
Packit 423ecb
#define IS_LOWALPHA(x) (((x) >= 'a') && ((x) <= 'z'))
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 * upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" |
Packit 423ecb
 *           "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" |
Packit 423ecb
 *           "U" | "V" | "W" | "X" | "Y" | "Z"
Packit 423ecb
 */
Packit 423ecb
#define IS_UPALPHA(x) (((x) >= 'A') && ((x) <= 'Z'))
Packit 423ecb
Packit 423ecb
#ifdef IS_DIGIT
Packit 423ecb
#undef IS_DIGIT
Packit 423ecb
#endif
Packit 423ecb
/*
Packit 423ecb
 * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
Packit 423ecb
 */
Packit 423ecb
#define IS_DIGIT(x) (((x) >= '0') && ((x) <= '9'))
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 * alphanum = alpha | digit
Packit 423ecb
 */
Packit 423ecb
Packit 423ecb
#define IS_ALPHANUM(x) (IS_ALPHA(x) || IS_DIGIT(x))
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
Packit 423ecb
 */
Packit 423ecb
Packit 423ecb
#define IS_MARK(x) (((x) == '-') || ((x) == '_') || ((x) == '.') ||     \
Packit 423ecb
    ((x) == '!') || ((x) == '~') || ((x) == '*') || ((x) == '\'') ||    \
Packit 423ecb
    ((x) == '(') || ((x) == ')'))
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 * unwise = "{" | "}" | "|" | "\" | "^" | "`"
Packit 423ecb
 */
Packit 423ecb
Packit 423ecb
#define IS_UNWISE(p)                                                    \
Packit 423ecb
      (((*(p) == '{')) || ((*(p) == '}')) || ((*(p) == '|')) ||         \
Packit 423ecb
       ((*(p) == '\\')) || ((*(p) == '^')) || ((*(p) == '[')) ||        \
Packit 423ecb
       ((*(p) == ']')) || ((*(p) == '`')))
Packit 423ecb
/*
Packit 423ecb
 * reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," |
Packit 423ecb
 *            "[" | "]"
Packit 423ecb
 */
Packit 423ecb
Packit 423ecb
#define IS_RESERVED(x) (((x) == ';') || ((x) == '/') || ((x) == '?') || \
Packit 423ecb
        ((x) == ':') || ((x) == '@') || ((x) == '&') || ((x) == '=') || \
Packit 423ecb
        ((x) == '+') || ((x) == '$') || ((x) == ',') || ((x) == '[') || \
Packit 423ecb
        ((x) == ']'))
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 * unreserved = alphanum | mark
Packit 423ecb
 */
Packit 423ecb
Packit 423ecb
#define IS_UNRESERVED(x) (IS_ALPHANUM(x) || IS_MARK(x))
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 * Skip to next pointer char, handle escaped sequences
Packit 423ecb
 */
Packit 423ecb
Packit 423ecb
#define NEXT(p) ((*p == '%')? p += 3 : p++)
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 * Productions from the spec.
Packit 423ecb
 *
Packit 423ecb
 *    authority     = server | reg_name
Packit 423ecb
 *    reg_name      = 1*( unreserved | escaped | "$" | "," |
Packit 423ecb
 *                        ";" | ":" | "@" | "&" | "=" | "+" )
Packit 423ecb
 *
Packit 423ecb
 * path          = [ abs_path | opaque_part ]
Packit 423ecb
 */
Packit 423ecb
Packit 423ecb
#define STRNDUP(s, n) (char *) xmlStrndup((const xmlChar *)(s), (n))
Packit 423ecb
Packit 423ecb
/************************************************************************
Packit 423ecb
 *									*
Packit 423ecb
 *                         RFC 3986 parser				*
Packit 423ecb
 *									*
Packit 423ecb
 ************************************************************************/
Packit 423ecb
Packit 423ecb
#define ISA_DIGIT(p) ((*(p) >= '0') && (*(p) <= '9'))
Packit 423ecb
#define ISA_ALPHA(p) (((*(p) >= 'a') && (*(p) <= 'z')) ||		\
Packit 423ecb
                      ((*(p) >= 'A') && (*(p) <= 'Z')))
Packit 423ecb
#define ISA_HEXDIG(p)							\
Packit 423ecb
       (ISA_DIGIT(p) || ((*(p) >= 'a') && (*(p) <= 'f')) ||		\
Packit 423ecb
        ((*(p) >= 'A') && (*(p) <= 'F')))
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
Packit 423ecb
 *                     / "*" / "+" / "," / ";" / "="
Packit 423ecb
 */
Packit 423ecb
#define ISA_SUB_DELIM(p)						\
Packit 423ecb
      (((*(p) == '!')) || ((*(p) == '$')) || ((*(p) == '&')) ||		\
Packit 423ecb
       ((*(p) == '(')) || ((*(p) == ')')) || ((*(p) == '*')) ||		\
Packit 423ecb
       ((*(p) == '+')) || ((*(p) == ',')) || ((*(p) == ';')) ||		\
Packit 423ecb
       ((*(p) == '=')) || ((*(p) == '\'')))
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 *    gen-delims    = ":" / "/" / "?" / "#" / "[" / "]" / "@"
Packit 423ecb
 */
Packit 423ecb
#define ISA_GEN_DELIM(p)						\
Packit 423ecb
      (((*(p) == ':')) || ((*(p) == '/')) || ((*(p) == '?')) ||         \
Packit 423ecb
       ((*(p) == '#')) || ((*(p) == '[')) || ((*(p) == ']')) ||         \
Packit 423ecb
       ((*(p) == '@')))
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 *    reserved      = gen-delims / sub-delims
Packit 423ecb
 */
Packit 423ecb
#define ISA_RESERVED(p) (ISA_GEN_DELIM(p) || (ISA_SUB_DELIM(p)))
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
Packit 423ecb
 */
Packit 423ecb
#define ISA_UNRESERVED(p)						\
Packit 423ecb
      ((ISA_ALPHA(p)) || (ISA_DIGIT(p)) || ((*(p) == '-')) ||		\
Packit 423ecb
       ((*(p) == '.')) || ((*(p) == '_')) || ((*(p) == '~')))
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 *    pct-encoded   = "%" HEXDIG HEXDIG
Packit 423ecb
 */
Packit 423ecb
#define ISA_PCT_ENCODED(p)						\
Packit 423ecb
     ((*(p) == '%') && (ISA_HEXDIG(p + 1)) && (ISA_HEXDIG(p + 2)))
Packit 423ecb
Packit 423ecb
/*
Packit 423ecb
 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
Packit 423ecb
 */
Packit 423ecb
#define ISA_PCHAR(p)							\
Packit 423ecb
     (ISA_UNRESERVED(p) || ISA_PCT_ENCODED(p) || ISA_SUB_DELIM(p) ||	\
Packit 423ecb
      ((*(p) == ':')) || ((*(p) == '@')))
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlParse3986Scheme:
Packit 423ecb
 * @uri:  pointer to an URI structure
Packit 423ecb
 * @str:  pointer to the string to analyze
Packit 423ecb
 *
Packit 423ecb
 * Parse an URI scheme
Packit 423ecb
 *
Packit 423ecb
 * ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 or the error code
Packit 423ecb
 */
Packit 423ecb
static int
Packit 423ecb
xmlParse3986Scheme(xmlURIPtr uri, const char **str) {
Packit 423ecb
    const char *cur;
Packit 423ecb
Packit 423ecb
    if (str == NULL)
Packit 423ecb
	return(-1);
Packit 423ecb
Packit 423ecb
    cur = *str;
Packit 423ecb
    if (!ISA_ALPHA(cur))
Packit 423ecb
	return(2);
Packit 423ecb
    cur++;
Packit 423ecb
    while (ISA_ALPHA(cur) || ISA_DIGIT(cur) ||
Packit 423ecb
           (*cur == '+') || (*cur == '-') || (*cur == '.')) cur++;
Packit 423ecb
    if (uri != NULL) {
Packit 423ecb
	if (uri->scheme != NULL) xmlFree(uri->scheme);
Packit 423ecb
	uri->scheme = STRNDUP(*str, cur - *str);
Packit 423ecb
    }
Packit 423ecb
    *str = cur;
Packit 423ecb
    return(0);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlParse3986Fragment:
Packit 423ecb
 * @uri:  pointer to an URI structure
Packit 423ecb
 * @str:  pointer to the string to analyze
Packit 423ecb
 *
Packit 423ecb
 * Parse the query part of an URI
Packit 423ecb
 *
Packit 423ecb
 * fragment      = *( pchar / "/" / "?" )
Packit 423ecb
 * NOTE: the strict syntax as defined by 3986 does not allow '[' and ']'
Packit 423ecb
 *       in the fragment identifier but this is used very broadly for
Packit 423ecb
 *       xpointer scheme selection, so we are allowing it here to not break
Packit 423ecb
 *       for example all the DocBook processing chains.
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 or the error code
Packit 423ecb
 */
Packit 423ecb
static int
Packit 423ecb
xmlParse3986Fragment(xmlURIPtr uri, const char **str)
Packit 423ecb
{
Packit 423ecb
    const char *cur;
Packit 423ecb
Packit 423ecb
    if (str == NULL)
Packit 423ecb
        return (-1);
Packit 423ecb
Packit 423ecb
    cur = *str;
Packit 423ecb
Packit 423ecb
    while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') ||
Packit 423ecb
           (*cur == '[') || (*cur == ']') ||
Packit 423ecb
           ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
Packit 423ecb
        NEXT(cur);
Packit 423ecb
    if (uri != NULL) {
Packit 423ecb
        if (uri->fragment != NULL)
Packit 423ecb
            xmlFree(uri->fragment);
Packit 423ecb
	if (uri->cleanup & 2)
Packit 423ecb
	    uri->fragment = STRNDUP(*str, cur - *str);
Packit 423ecb
	else
Packit 423ecb
	    uri->fragment = xmlURIUnescapeString(*str, cur - *str, NULL);
Packit 423ecb
    }
Packit 423ecb
    *str = cur;
Packit 423ecb
    return (0);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlParse3986Query:
Packit 423ecb
 * @uri:  pointer to an URI structure
Packit 423ecb
 * @str:  pointer to the string to analyze
Packit 423ecb
 *
Packit 423ecb
 * Parse the query part of an URI
Packit 423ecb
 *
Packit 423ecb
 * query = *uric
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 or the error code
Packit 423ecb
 */
Packit 423ecb
static int
Packit 423ecb
xmlParse3986Query(xmlURIPtr uri, const char **str)
Packit 423ecb
{
Packit 423ecb
    const char *cur;
Packit 423ecb
Packit 423ecb
    if (str == NULL)
Packit 423ecb
        return (-1);
Packit 423ecb
Packit 423ecb
    cur = *str;
Packit 423ecb
Packit 423ecb
    while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') ||
Packit 423ecb
           ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
Packit 423ecb
        NEXT(cur);
Packit 423ecb
    if (uri != NULL) {
Packit 423ecb
        if (uri->query != NULL)
Packit 423ecb
            xmlFree(uri->query);
Packit 423ecb
	if (uri->cleanup & 2)
Packit 423ecb
	    uri->query = STRNDUP(*str, cur - *str);
Packit 423ecb
	else
Packit 423ecb
	    uri->query = xmlURIUnescapeString(*str, cur - *str, NULL);
Packit 423ecb
Packit 423ecb
	/* Save the raw bytes of the query as well.
Packit 423ecb
	 * See: http://mail.gnome.org/archives/xml/2007-April/thread.html#00114
Packit 423ecb
	 */
Packit 423ecb
	if (uri->query_raw != NULL)
Packit 423ecb
	    xmlFree (uri->query_raw);
Packit 423ecb
	uri->query_raw = STRNDUP (*str, cur - *str);
Packit 423ecb
    }
Packit 423ecb
    *str = cur;
Packit 423ecb
    return (0);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlParse3986Port:
Packit 423ecb
 * @uri:  pointer to an URI structure
Packit 423ecb
 * @str:  the string to analyze
Packit 423ecb
 *
Packit 423ecb
 * Parse a port part and fills in the appropriate fields
Packit 423ecb
 * of the @uri structure
Packit 423ecb
 *
Packit 423ecb
 * port          = *DIGIT
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 or the error code
Packit 423ecb
 */
Packit 423ecb
static int
Packit 423ecb
xmlParse3986Port(xmlURIPtr uri, const char **str)
Packit 423ecb
{
Packit 423ecb
    const char *cur = *str;
Packit 423ecb
    unsigned port = 0; /* unsigned for defined overflow behavior */
Packit 423ecb
Packit 423ecb
    if (ISA_DIGIT(cur)) {
Packit 423ecb
	while (ISA_DIGIT(cur)) {
Packit 423ecb
	    port = port * 10 + (*cur - '0');
Packit 423ecb
Packit 423ecb
	    cur++;
Packit 423ecb
	}
Packit 423ecb
	if (uri != NULL)
Packit 423ecb
	    uri->port = port & INT_MAX; /* port value modulo INT_MAX+1 */
Packit 423ecb
	*str = cur;
Packit 423ecb
	return(0);
Packit 423ecb
    }
Packit 423ecb
    return(1);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlParse3986Userinfo:
Packit 423ecb
 * @uri:  pointer to an URI structure
Packit 423ecb
 * @str:  the string to analyze
Packit 423ecb
 *
Packit 423ecb
 * Parse an user informations part and fills in the appropriate fields
Packit 423ecb
 * of the @uri structure
Packit 423ecb
 *
Packit 423ecb
 * userinfo      = *( unreserved / pct-encoded / sub-delims / ":" )
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 or the error code
Packit 423ecb
 */
Packit 423ecb
static int
Packit 423ecb
xmlParse3986Userinfo(xmlURIPtr uri, const char **str)
Packit 423ecb
{
Packit 423ecb
    const char *cur;
Packit 423ecb
Packit 423ecb
    cur = *str;
Packit 423ecb
    while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) ||
Packit 423ecb
           ISA_SUB_DELIM(cur) || (*cur == ':'))
Packit 423ecb
	NEXT(cur);
Packit 423ecb
    if (*cur == '@') {
Packit 423ecb
	if (uri != NULL) {
Packit 423ecb
	    if (uri->user != NULL) xmlFree(uri->user);
Packit 423ecb
	    if (uri->cleanup & 2)
Packit 423ecb
		uri->user = STRNDUP(*str, cur - *str);
Packit 423ecb
	    else
Packit 423ecb
		uri->user = xmlURIUnescapeString(*str, cur - *str, NULL);
Packit 423ecb
	}
Packit 423ecb
	*str = cur;
Packit 423ecb
	return(0);
Packit 423ecb
    }
Packit 423ecb
    return(1);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlParse3986DecOctet:
Packit 423ecb
 * @str:  the string to analyze
Packit 423ecb
 *
Packit 423ecb
 *    dec-octet     = DIGIT                 ; 0-9
Packit 423ecb
 *                  / %x31-39 DIGIT         ; 10-99
Packit 423ecb
 *                  / "1" 2DIGIT            ; 100-199
Packit 423ecb
 *                  / "2" %x30-34 DIGIT     ; 200-249
Packit 423ecb
 *                  / "25" %x30-35          ; 250-255
Packit 423ecb
 *
Packit 423ecb
 * Skip a dec-octet.
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 if found and skipped, 1 otherwise
Packit 423ecb
 */
Packit 423ecb
static int
Packit 423ecb
xmlParse3986DecOctet(const char **str) {
Packit 423ecb
    const char *cur = *str;
Packit 423ecb
Packit 423ecb
    if (!(ISA_DIGIT(cur)))
Packit 423ecb
        return(1);
Packit 423ecb
    if (!ISA_DIGIT(cur+1))
Packit 423ecb
	cur++;
Packit 423ecb
    else if ((*cur != '0') && (ISA_DIGIT(cur + 1)) && (!ISA_DIGIT(cur+2)))
Packit 423ecb
	cur += 2;
Packit 423ecb
    else if ((*cur == '1') && (ISA_DIGIT(cur + 1)) && (ISA_DIGIT(cur + 2)))
Packit 423ecb
	cur += 3;
Packit 423ecb
    else if ((*cur == '2') && (*(cur + 1) >= '0') &&
Packit 423ecb
	     (*(cur + 1) <= '4') && (ISA_DIGIT(cur + 2)))
Packit 423ecb
	cur += 3;
Packit 423ecb
    else if ((*cur == '2') && (*(cur + 1) == '5') &&
Packit 423ecb
	     (*(cur + 2) >= '0') && (*(cur + 1) <= '5'))
Packit 423ecb
	cur += 3;
Packit 423ecb
    else
Packit 423ecb
        return(1);
Packit 423ecb
    *str = cur;
Packit 423ecb
    return(0);
Packit 423ecb
}
Packit 423ecb
/**
Packit 423ecb
 * xmlParse3986Host:
Packit 423ecb
 * @uri:  pointer to an URI structure
Packit 423ecb
 * @str:  the string to analyze
Packit 423ecb
 *
Packit 423ecb
 * Parse an host part and fills in the appropriate fields
Packit 423ecb
 * of the @uri structure
Packit 423ecb
 *
Packit 423ecb
 * host          = IP-literal / IPv4address / reg-name
Packit 423ecb
 * IP-literal    = "[" ( IPv6address / IPvFuture  ) "]"
Packit 423ecb
 * IPv4address   = dec-octet "." dec-octet "." dec-octet "." dec-octet
Packit 423ecb
 * reg-name      = *( unreserved / pct-encoded / sub-delims )
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 or the error code
Packit 423ecb
 */
Packit 423ecb
static int
Packit 423ecb
xmlParse3986Host(xmlURIPtr uri, const char **str)
Packit 423ecb
{
Packit 423ecb
    const char *cur = *str;
Packit 423ecb
    const char *host;
Packit 423ecb
Packit 423ecb
    host = cur;
Packit 423ecb
    /*
Packit 423ecb
     * IPv6 and future adressing scheme are enclosed between brackets
Packit 423ecb
     */
Packit 423ecb
    if (*cur == '[') {
Packit 423ecb
        cur++;
Packit 423ecb
	while ((*cur != ']') && (*cur != 0))
Packit 423ecb
	    cur++;
Packit 423ecb
	if (*cur != ']')
Packit 423ecb
	    return(1);
Packit 423ecb
	cur++;
Packit 423ecb
	goto found;
Packit 423ecb
    }
Packit 423ecb
    /*
Packit 423ecb
     * try to parse an IPv4
Packit 423ecb
     */
Packit 423ecb
    if (ISA_DIGIT(cur)) {
Packit 423ecb
        if (xmlParse3986DecOctet(&cur) != 0)
Packit 423ecb
	    goto not_ipv4;
Packit 423ecb
	if (*cur != '.')
Packit 423ecb
	    goto not_ipv4;
Packit 423ecb
	cur++;
Packit 423ecb
        if (xmlParse3986DecOctet(&cur) != 0)
Packit 423ecb
	    goto not_ipv4;
Packit 423ecb
	if (*cur != '.')
Packit 423ecb
	    goto not_ipv4;
Packit 423ecb
        if (xmlParse3986DecOctet(&cur) != 0)
Packit 423ecb
	    goto not_ipv4;
Packit 423ecb
	if (*cur != '.')
Packit 423ecb
	    goto not_ipv4;
Packit 423ecb
        if (xmlParse3986DecOctet(&cur) != 0)
Packit 423ecb
	    goto not_ipv4;
Packit 423ecb
	goto found;
Packit 423ecb
not_ipv4:
Packit 423ecb
        cur = *str;
Packit 423ecb
    }
Packit 423ecb
    /*
Packit 423ecb
     * then this should be a hostname which can be empty
Packit 423ecb
     */
Packit 423ecb
    while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur))
Packit 423ecb
        NEXT(cur);
Packit 423ecb
found:
Packit 423ecb
    if (uri != NULL) {
Packit 423ecb
	if (uri->authority != NULL) xmlFree(uri->authority);
Packit 423ecb
	uri->authority = NULL;
Packit 423ecb
	if (uri->server != NULL) xmlFree(uri->server);
Packit 423ecb
	if (cur != host) {
Packit 423ecb
	    if (uri->cleanup & 2)
Packit 423ecb
		uri->server = STRNDUP(host, cur - host);
Packit 423ecb
	    else
Packit 423ecb
		uri->server = xmlURIUnescapeString(host, cur - host, NULL);
Packit 423ecb
	} else
Packit 423ecb
	    uri->server = NULL;
Packit 423ecb
    }
Packit 423ecb
    *str = cur;
Packit 423ecb
    return(0);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlParse3986Authority:
Packit 423ecb
 * @uri:  pointer to an URI structure
Packit 423ecb
 * @str:  the string to analyze
Packit 423ecb
 *
Packit 423ecb
 * Parse an authority part and fills in the appropriate fields
Packit 423ecb
 * of the @uri structure
Packit 423ecb
 *
Packit 423ecb
 * authority     = [ userinfo "@" ] host [ ":" port ]
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 or the error code
Packit 423ecb
 */
Packit 423ecb
static int
Packit 423ecb
xmlParse3986Authority(xmlURIPtr uri, const char **str)
Packit 423ecb
{
Packit 423ecb
    const char *cur;
Packit 423ecb
    int ret;
Packit 423ecb
Packit 423ecb
    cur = *str;
Packit 423ecb
    /*
Packit 423ecb
     * try to parse an userinfo and check for the trailing @
Packit 423ecb
     */
Packit 423ecb
    ret = xmlParse3986Userinfo(uri, &cur);
Packit 423ecb
    if ((ret != 0) || (*cur != '@'))
Packit 423ecb
        cur = *str;
Packit 423ecb
    else
Packit 423ecb
        cur++;
Packit 423ecb
    ret = xmlParse3986Host(uri, &cur);
Packit 423ecb
    if (ret != 0) return(ret);
Packit 423ecb
    if (*cur == ':') {
Packit 423ecb
        cur++;
Packit 423ecb
        ret = xmlParse3986Port(uri, &cur);
Packit 423ecb
	if (ret != 0) return(ret);
Packit 423ecb
    }
Packit 423ecb
    *str = cur;
Packit 423ecb
    return(0);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlParse3986Segment:
Packit 423ecb
 * @str:  the string to analyze
Packit 423ecb
 * @forbid: an optional forbidden character
Packit 423ecb
 * @empty: allow an empty segment
Packit 423ecb
 *
Packit 423ecb
 * Parse a segment and fills in the appropriate fields
Packit 423ecb
 * of the @uri structure
Packit 423ecb
 *
Packit 423ecb
 * segment       = *pchar
Packit 423ecb
 * segment-nz    = 1*pchar
Packit 423ecb
 * segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
Packit 423ecb
 *               ; non-zero-length segment without any colon ":"
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 or the error code
Packit 423ecb
 */
Packit 423ecb
static int
Packit 423ecb
xmlParse3986Segment(const char **str, char forbid, int empty)
Packit 423ecb
{
Packit 423ecb
    const char *cur;
Packit 423ecb
Packit 423ecb
    cur = *str;
Packit 423ecb
    if (!ISA_PCHAR(cur)) {
Packit 423ecb
        if (empty)
Packit 423ecb
	    return(0);
Packit 423ecb
	return(1);
Packit 423ecb
    }
Packit 423ecb
    while (ISA_PCHAR(cur) && (*cur != forbid))
Packit 423ecb
        NEXT(cur);
Packit 423ecb
    *str = cur;
Packit 423ecb
    return (0);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlParse3986PathAbEmpty:
Packit 423ecb
 * @uri:  pointer to an URI structure
Packit 423ecb
 * @str:  the string to analyze
Packit 423ecb
 *
Packit 423ecb
 * Parse an path absolute or empty and fills in the appropriate fields
Packit 423ecb
 * of the @uri structure
Packit 423ecb
 *
Packit 423ecb
 * path-abempty  = *( "/" segment )
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 or the error code
Packit 423ecb
 */
Packit 423ecb
static int
Packit 423ecb
xmlParse3986PathAbEmpty(xmlURIPtr uri, const char **str)
Packit 423ecb
{
Packit 423ecb
    const char *cur;
Packit 423ecb
    int ret;
Packit 423ecb
Packit 423ecb
    cur = *str;
Packit 423ecb
Packit 423ecb
    while (*cur == '/') {
Packit 423ecb
        cur++;
Packit 423ecb
	ret = xmlParse3986Segment(&cur, 0, 1);
Packit 423ecb
	if (ret != 0) return(ret);
Packit 423ecb
    }
Packit 423ecb
    if (uri != NULL) {
Packit 423ecb
	if (uri->path != NULL) xmlFree(uri->path);
Packit 423ecb
        if (*str != cur) {
Packit 423ecb
            if (uri->cleanup & 2)
Packit 423ecb
                uri->path = STRNDUP(*str, cur - *str);
Packit 423ecb
            else
Packit 423ecb
                uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
Packit 423ecb
        } else {
Packit 423ecb
            uri->path = NULL;
Packit 423ecb
        }
Packit 423ecb
    }
Packit 423ecb
    *str = cur;
Packit 423ecb
    return (0);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlParse3986PathAbsolute:
Packit 423ecb
 * @uri:  pointer to an URI structure
Packit 423ecb
 * @str:  the string to analyze
Packit 423ecb
 *
Packit 423ecb
 * Parse an path absolute and fills in the appropriate fields
Packit 423ecb
 * of the @uri structure
Packit 423ecb
 *
Packit 423ecb
 * path-absolute = "/" [ segment-nz *( "/" segment ) ]
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 or the error code
Packit 423ecb
 */
Packit 423ecb
static int
Packit 423ecb
xmlParse3986PathAbsolute(xmlURIPtr uri, const char **str)
Packit 423ecb
{
Packit 423ecb
    const char *cur;
Packit 423ecb
    int ret;
Packit 423ecb
Packit 423ecb
    cur = *str;
Packit 423ecb
Packit 423ecb
    if (*cur != '/')
Packit 423ecb
        return(1);
Packit 423ecb
    cur++;
Packit 423ecb
    ret = xmlParse3986Segment(&cur, 0, 0);
Packit 423ecb
    if (ret == 0) {
Packit 423ecb
	while (*cur == '/') {
Packit 423ecb
	    cur++;
Packit 423ecb
	    ret = xmlParse3986Segment(&cur, 0, 1);
Packit 423ecb
	    if (ret != 0) return(ret);
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
    if (uri != NULL) {
Packit 423ecb
	if (uri->path != NULL) xmlFree(uri->path);
Packit 423ecb
        if (cur != *str) {
Packit 423ecb
            if (uri->cleanup & 2)
Packit 423ecb
                uri->path = STRNDUP(*str, cur - *str);
Packit 423ecb
            else
Packit 423ecb
                uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
Packit 423ecb
        } else {
Packit 423ecb
            uri->path = NULL;
Packit 423ecb
        }
Packit 423ecb
    }
Packit 423ecb
    *str = cur;
Packit 423ecb
    return (0);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlParse3986PathRootless:
Packit 423ecb
 * @uri:  pointer to an URI structure
Packit 423ecb
 * @str:  the string to analyze
Packit 423ecb
 *
Packit 423ecb
 * Parse an path without root and fills in the appropriate fields
Packit 423ecb
 * of the @uri structure
Packit 423ecb
 *
Packit 423ecb
 * path-rootless = segment-nz *( "/" segment )
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 or the error code
Packit 423ecb
 */
Packit 423ecb
static int
Packit 423ecb
xmlParse3986PathRootless(xmlURIPtr uri, const char **str)
Packit 423ecb
{
Packit 423ecb
    const char *cur;
Packit 423ecb
    int ret;
Packit 423ecb
Packit 423ecb
    cur = *str;
Packit 423ecb
Packit 423ecb
    ret = xmlParse3986Segment(&cur, 0, 0);
Packit 423ecb
    if (ret != 0) return(ret);
Packit 423ecb
    while (*cur == '/') {
Packit 423ecb
        cur++;
Packit 423ecb
	ret = xmlParse3986Segment(&cur, 0, 1);
Packit 423ecb
	if (ret != 0) return(ret);
Packit 423ecb
    }
Packit 423ecb
    if (uri != NULL) {
Packit 423ecb
	if (uri->path != NULL) xmlFree(uri->path);
Packit 423ecb
        if (cur != *str) {
Packit 423ecb
            if (uri->cleanup & 2)
Packit 423ecb
                uri->path = STRNDUP(*str, cur - *str);
Packit 423ecb
            else
Packit 423ecb
                uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
Packit 423ecb
        } else {
Packit 423ecb
            uri->path = NULL;
Packit 423ecb
        }
Packit 423ecb
    }
Packit 423ecb
    *str = cur;
Packit 423ecb
    return (0);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlParse3986PathNoScheme:
Packit 423ecb
 * @uri:  pointer to an URI structure
Packit 423ecb
 * @str:  the string to analyze
Packit 423ecb
 *
Packit 423ecb
 * Parse an path which is not a scheme and fills in the appropriate fields
Packit 423ecb
 * of the @uri structure
Packit 423ecb
 *
Packit 423ecb
 * path-noscheme = segment-nz-nc *( "/" segment )
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 or the error code
Packit 423ecb
 */
Packit 423ecb
static int
Packit 423ecb
xmlParse3986PathNoScheme(xmlURIPtr uri, const char **str)
Packit 423ecb
{
Packit 423ecb
    const char *cur;
Packit 423ecb
    int ret;
Packit 423ecb
Packit 423ecb
    cur = *str;
Packit 423ecb
Packit 423ecb
    ret = xmlParse3986Segment(&cur, ':', 0);
Packit 423ecb
    if (ret != 0) return(ret);
Packit 423ecb
    while (*cur == '/') {
Packit 423ecb
        cur++;
Packit 423ecb
	ret = xmlParse3986Segment(&cur, 0, 1);
Packit 423ecb
	if (ret != 0) return(ret);
Packit 423ecb
    }
Packit 423ecb
    if (uri != NULL) {
Packit 423ecb
	if (uri->path != NULL) xmlFree(uri->path);
Packit 423ecb
        if (cur != *str) {
Packit 423ecb
            if (uri->cleanup & 2)
Packit 423ecb
                uri->path = STRNDUP(*str, cur - *str);
Packit 423ecb
            else
Packit 423ecb
                uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
Packit 423ecb
        } else {
Packit 423ecb
            uri->path = NULL;
Packit 423ecb
        }
Packit 423ecb
    }
Packit 423ecb
    *str = cur;
Packit 423ecb
    return (0);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlParse3986HierPart:
Packit 423ecb
 * @uri:  pointer to an URI structure
Packit 423ecb
 * @str:  the string to analyze
Packit 423ecb
 *
Packit 423ecb
 * Parse an hierarchical part and fills in the appropriate fields
Packit 423ecb
 * of the @uri structure
Packit 423ecb
 *
Packit 423ecb
 * hier-part     = "//" authority path-abempty
Packit 423ecb
 *                / path-absolute
Packit 423ecb
 *                / path-rootless
Packit 423ecb
 *                / path-empty
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 or the error code
Packit 423ecb
 */
Packit 423ecb
static int
Packit 423ecb
xmlParse3986HierPart(xmlURIPtr uri, const char **str)
Packit 423ecb
{
Packit 423ecb
    const char *cur;
Packit 423ecb
    int ret;
Packit 423ecb
Packit 423ecb
    cur = *str;
Packit 423ecb
Packit 423ecb
    if ((*cur == '/') && (*(cur + 1) == '/')) {
Packit 423ecb
        cur += 2;
Packit 423ecb
	ret = xmlParse3986Authority(uri, &cur);
Packit 423ecb
	if (ret != 0) return(ret);
Packit 423ecb
	if (uri->server == NULL)
Packit 423ecb
	    uri->port = -1;
Packit 423ecb
	ret = xmlParse3986PathAbEmpty(uri, &cur);
Packit 423ecb
	if (ret != 0) return(ret);
Packit 423ecb
	*str = cur;
Packit 423ecb
	return(0);
Packit 423ecb
    } else if (*cur == '/') {
Packit 423ecb
        ret = xmlParse3986PathAbsolute(uri, &cur);
Packit 423ecb
	if (ret != 0) return(ret);
Packit 423ecb
    } else if (ISA_PCHAR(cur)) {
Packit 423ecb
        ret = xmlParse3986PathRootless(uri, &cur);
Packit 423ecb
	if (ret != 0) return(ret);
Packit 423ecb
    } else {
Packit 423ecb
	/* path-empty is effectively empty */
Packit 423ecb
	if (uri != NULL) {
Packit 423ecb
	    if (uri->path != NULL) xmlFree(uri->path);
Packit 423ecb
	    uri->path = NULL;
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
    *str = cur;
Packit 423ecb
    return (0);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlParse3986RelativeRef:
Packit 423ecb
 * @uri:  pointer to an URI structure
Packit 423ecb
 * @str:  the string to analyze
Packit 423ecb
 *
Packit 423ecb
 * Parse an URI string and fills in the appropriate fields
Packit 423ecb
 * of the @uri structure
Packit 423ecb
 *
Packit 423ecb
 * relative-ref  = relative-part [ "?" query ] [ "#" fragment ]
Packit 423ecb
 * relative-part = "//" authority path-abempty
Packit 423ecb
 *               / path-absolute
Packit 423ecb
 *               / path-noscheme
Packit 423ecb
 *               / path-empty
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 or the error code
Packit 423ecb
 */
Packit 423ecb
static int
Packit 423ecb
xmlParse3986RelativeRef(xmlURIPtr uri, const char *str) {
Packit 423ecb
    int ret;
Packit 423ecb
Packit 423ecb
    if ((*str == '/') && (*(str + 1) == '/')) {
Packit 423ecb
        str += 2;
Packit 423ecb
	ret = xmlParse3986Authority(uri, &str);
Packit 423ecb
	if (ret != 0) return(ret);
Packit 423ecb
	ret = xmlParse3986PathAbEmpty(uri, &str);
Packit 423ecb
	if (ret != 0) return(ret);
Packit 423ecb
    } else if (*str == '/') {
Packit 423ecb
	ret = xmlParse3986PathAbsolute(uri, &str);
Packit 423ecb
	if (ret != 0) return(ret);
Packit 423ecb
    } else if (ISA_PCHAR(str)) {
Packit 423ecb
        ret = xmlParse3986PathNoScheme(uri, &str);
Packit 423ecb
	if (ret != 0) return(ret);
Packit 423ecb
    } else {
Packit 423ecb
	/* path-empty is effectively empty */
Packit 423ecb
	if (uri != NULL) {
Packit 423ecb
	    if (uri->path != NULL) xmlFree(uri->path);
Packit 423ecb
	    uri->path = NULL;
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    if (*str == '?') {
Packit 423ecb
	str++;
Packit 423ecb
	ret = xmlParse3986Query(uri, &str);
Packit 423ecb
	if (ret != 0) return(ret);
Packit 423ecb
    }
Packit 423ecb
    if (*str == '#') {
Packit 423ecb
	str++;
Packit 423ecb
	ret = xmlParse3986Fragment(uri, &str);
Packit 423ecb
	if (ret != 0) return(ret);
Packit 423ecb
    }
Packit 423ecb
    if (*str != 0) {
Packit 423ecb
	xmlCleanURI(uri);
Packit 423ecb
	return(1);
Packit 423ecb
    }
Packit 423ecb
    return(0);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlParse3986URI:
Packit 423ecb
 * @uri:  pointer to an URI structure
Packit 423ecb
 * @str:  the string to analyze
Packit 423ecb
 *
Packit 423ecb
 * Parse an URI string and fills in the appropriate fields
Packit 423ecb
 * of the @uri structure
Packit 423ecb
 *
Packit 423ecb
 * scheme ":" hier-part [ "?" query ] [ "#" fragment ]
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 or the error code
Packit 423ecb
 */
Packit 423ecb
static int
Packit 423ecb
xmlParse3986URI(xmlURIPtr uri, const char *str) {
Packit 423ecb
    int ret;
Packit 423ecb
Packit 423ecb
    ret = xmlParse3986Scheme(uri, &str);
Packit 423ecb
    if (ret != 0) return(ret);
Packit 423ecb
    if (*str != ':') {
Packit 423ecb
	return(1);
Packit 423ecb
    }
Packit 423ecb
    str++;
Packit 423ecb
    ret = xmlParse3986HierPart(uri, &str);
Packit 423ecb
    if (ret != 0) return(ret);
Packit 423ecb
    if (*str == '?') {
Packit 423ecb
	str++;
Packit 423ecb
	ret = xmlParse3986Query(uri, &str);
Packit 423ecb
	if (ret != 0) return(ret);
Packit 423ecb
    }
Packit 423ecb
    if (*str == '#') {
Packit 423ecb
	str++;
Packit 423ecb
	ret = xmlParse3986Fragment(uri, &str);
Packit 423ecb
	if (ret != 0) return(ret);
Packit 423ecb
    }
Packit 423ecb
    if (*str != 0) {
Packit 423ecb
	xmlCleanURI(uri);
Packit 423ecb
	return(1);
Packit 423ecb
    }
Packit 423ecb
    return(0);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlParse3986URIReference:
Packit 423ecb
 * @uri:  pointer to an URI structure
Packit 423ecb
 * @str:  the string to analyze
Packit 423ecb
 *
Packit 423ecb
 * Parse an URI reference string and fills in the appropriate fields
Packit 423ecb
 * of the @uri structure
Packit 423ecb
 *
Packit 423ecb
 * URI-reference = URI / relative-ref
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 or the error code
Packit 423ecb
 */
Packit 423ecb
static int
Packit 423ecb
xmlParse3986URIReference(xmlURIPtr uri, const char *str) {
Packit 423ecb
    int ret;
Packit 423ecb
Packit 423ecb
    if (str == NULL)
Packit 423ecb
	return(-1);
Packit 423ecb
    xmlCleanURI(uri);
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * Try first to parse absolute refs, then fallback to relative if
Packit 423ecb
     * it fails.
Packit 423ecb
     */
Packit 423ecb
    ret = xmlParse3986URI(uri, str);
Packit 423ecb
    if (ret != 0) {
Packit 423ecb
	xmlCleanURI(uri);
Packit 423ecb
        ret = xmlParse3986RelativeRef(uri, str);
Packit 423ecb
	if (ret != 0) {
Packit 423ecb
	    xmlCleanURI(uri);
Packit 423ecb
	    return(ret);
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
    return(0);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlParseURI:
Packit 423ecb
 * @str:  the URI string to analyze
Packit 423ecb
 *
Packit 423ecb
 * Parse an URI based on RFC 3986
Packit 423ecb
 *
Packit 423ecb
 * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
Packit 423ecb
 *
Packit 423ecb
 * Returns a newly built xmlURIPtr or NULL in case of error
Packit 423ecb
 */
Packit 423ecb
xmlURIPtr
Packit 423ecb
xmlParseURI(const char *str) {
Packit 423ecb
    xmlURIPtr uri;
Packit 423ecb
    int ret;
Packit 423ecb
Packit 423ecb
    if (str == NULL)
Packit 423ecb
	return(NULL);
Packit 423ecb
    uri = xmlCreateURI();
Packit 423ecb
    if (uri != NULL) {
Packit 423ecb
	ret = xmlParse3986URIReference(uri, str);
Packit 423ecb
        if (ret) {
Packit 423ecb
	    xmlFreeURI(uri);
Packit 423ecb
	    return(NULL);
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
    return(uri);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlParseURIReference:
Packit 423ecb
 * @uri:  pointer to an URI structure
Packit 423ecb
 * @str:  the string to analyze
Packit 423ecb
 *
Packit 423ecb
 * Parse an URI reference string based on RFC 3986 and fills in the
Packit 423ecb
 * appropriate fields of the @uri structure
Packit 423ecb
 *
Packit 423ecb
 * URI-reference = URI / relative-ref
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 or the error code
Packit 423ecb
 */
Packit 423ecb
int
Packit 423ecb
xmlParseURIReference(xmlURIPtr uri, const char *str) {
Packit 423ecb
    return(xmlParse3986URIReference(uri, str));
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlParseURIRaw:
Packit 423ecb
 * @str:  the URI string to analyze
Packit 423ecb
 * @raw:  if 1 unescaping of URI pieces are disabled
Packit 423ecb
 *
Packit 423ecb
 * Parse an URI but allows to keep intact the original fragments.
Packit 423ecb
 *
Packit 423ecb
 * URI-reference = URI / relative-ref
Packit 423ecb
 *
Packit 423ecb
 * Returns a newly built xmlURIPtr or NULL in case of error
Packit 423ecb
 */
Packit 423ecb
xmlURIPtr
Packit 423ecb
xmlParseURIRaw(const char *str, int raw) {
Packit 423ecb
    xmlURIPtr uri;
Packit 423ecb
    int ret;
Packit 423ecb
Packit 423ecb
    if (str == NULL)
Packit 423ecb
	return(NULL);
Packit 423ecb
    uri = xmlCreateURI();
Packit 423ecb
    if (uri != NULL) {
Packit 423ecb
        if (raw) {
Packit 423ecb
	    uri->cleanup |= 2;
Packit 423ecb
	}
Packit 423ecb
	ret = xmlParseURIReference(uri, str);
Packit 423ecb
        if (ret) {
Packit 423ecb
	    xmlFreeURI(uri);
Packit 423ecb
	    return(NULL);
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
    return(uri);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/************************************************************************
Packit 423ecb
 *									*
Packit 423ecb
 *			Generic URI structure functions			*
Packit 423ecb
 *									*
Packit 423ecb
 ************************************************************************/
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlCreateURI:
Packit 423ecb
 *
Packit 423ecb
 * Simply creates an empty xmlURI
Packit 423ecb
 *
Packit 423ecb
 * Returns the new structure or NULL in case of error
Packit 423ecb
 */
Packit 423ecb
xmlURIPtr
Packit 423ecb
xmlCreateURI(void) {
Packit 423ecb
    xmlURIPtr ret;
Packit 423ecb
Packit 423ecb
    ret = (xmlURIPtr) xmlMalloc(sizeof(xmlURI));
Packit 423ecb
    if (ret == NULL) {
Packit 423ecb
        xmlURIErrMemory("creating URI structure\n");
Packit 423ecb
	return(NULL);
Packit 423ecb
    }
Packit 423ecb
    memset(ret, 0, sizeof(xmlURI));
Packit 423ecb
    return(ret);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlSaveUriRealloc:
Packit 423ecb
 *
Packit 423ecb
 * Function to handle properly a reallocation when saving an URI
Packit 423ecb
 * Also imposes some limit on the length of an URI string output
Packit 423ecb
 */
Packit 423ecb
static xmlChar *
Packit 423ecb
xmlSaveUriRealloc(xmlChar *ret, int *max) {
Packit 423ecb
    xmlChar *temp;
Packit 423ecb
    int tmp;
Packit 423ecb
Packit 423ecb
    if (*max > MAX_URI_LENGTH) {
Packit 423ecb
        xmlURIErrMemory("reaching arbitrary MAX_URI_LENGTH limit\n");
Packit 423ecb
        return(NULL);
Packit 423ecb
    }
Packit 423ecb
    tmp = *max * 2;
Packit 423ecb
    temp = (xmlChar *) xmlRealloc(ret, (tmp + 1));
Packit 423ecb
    if (temp == NULL) {
Packit 423ecb
        xmlURIErrMemory("saving URI\n");
Packit 423ecb
        return(NULL);
Packit 423ecb
    }
Packit 423ecb
    *max = tmp;
Packit 423ecb
    return(temp);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlSaveUri:
Packit 423ecb
 * @uri:  pointer to an xmlURI
Packit 423ecb
 *
Packit 423ecb
 * Save the URI as an escaped string
Packit 423ecb
 *
Packit 423ecb
 * Returns a new string (to be deallocated by caller)
Packit 423ecb
 */
Packit 423ecb
xmlChar *
Packit 423ecb
xmlSaveUri(xmlURIPtr uri) {
Packit 423ecb
    xmlChar *ret = NULL;
Packit 423ecb
    xmlChar *temp;
Packit 423ecb
    const char *p;
Packit 423ecb
    int len;
Packit 423ecb
    int max;
Packit 423ecb
Packit 423ecb
    if (uri == NULL) return(NULL);
Packit 423ecb
Packit 423ecb
Packit 423ecb
    max = 80;
Packit 423ecb
    ret = (xmlChar *) xmlMallocAtomic((max + 1) * sizeof(xmlChar));
Packit 423ecb
    if (ret == NULL) {
Packit 423ecb
        xmlURIErrMemory("saving URI\n");
Packit 423ecb
	return(NULL);
Packit 423ecb
    }
Packit 423ecb
    len = 0;
Packit 423ecb
Packit 423ecb
    if (uri->scheme != NULL) {
Packit 423ecb
	p = uri->scheme;
Packit 423ecb
	while (*p != 0) {
Packit 423ecb
	    if (len >= max) {
Packit 423ecb
                temp = xmlSaveUriRealloc(ret, &max;;
Packit 423ecb
                if (temp == NULL) goto mem_error;
Packit 423ecb
		ret = temp;
Packit 423ecb
	    }
Packit 423ecb
	    ret[len++] = *p++;
Packit 423ecb
	}
Packit 423ecb
	if (len >= max) {
Packit 423ecb
            temp = xmlSaveUriRealloc(ret, &max;;
Packit 423ecb
            if (temp == NULL) goto mem_error;
Packit 423ecb
            ret = temp;
Packit 423ecb
	}
Packit 423ecb
	ret[len++] = ':';
Packit 423ecb
    }
Packit 423ecb
    if (uri->opaque != NULL) {
Packit 423ecb
	p = uri->opaque;
Packit 423ecb
	while (*p != 0) {
Packit 423ecb
	    if (len + 3 >= max) {
Packit 423ecb
                temp = xmlSaveUriRealloc(ret, &max;;
Packit 423ecb
                if (temp == NULL) goto mem_error;
Packit 423ecb
                ret = temp;
Packit 423ecb
	    }
Packit 423ecb
	    if (IS_RESERVED(*(p)) || IS_UNRESERVED(*(p)))
Packit 423ecb
		ret[len++] = *p++;
Packit 423ecb
	    else {
Packit 423ecb
		int val = *(unsigned char *)p++;
Packit 423ecb
		int hi = val / 0x10, lo = val % 0x10;
Packit 423ecb
		ret[len++] = '%';
Packit 423ecb
		ret[len++] = hi + (hi > 9? 'A'-10 : '0');
Packit 423ecb
		ret[len++] = lo + (lo > 9? 'A'-10 : '0');
Packit 423ecb
	    }
Packit 423ecb
	}
Packit 423ecb
    } else {
Packit 423ecb
	if ((uri->server != NULL) || (uri->port == -1)) {
Packit 423ecb
	    if (len + 3 >= max) {
Packit 423ecb
                temp = xmlSaveUriRealloc(ret, &max;;
Packit 423ecb
                if (temp == NULL) goto mem_error;
Packit 423ecb
                ret = temp;
Packit 423ecb
	    }
Packit 423ecb
	    ret[len++] = '/';
Packit 423ecb
	    ret[len++] = '/';
Packit 423ecb
	    if (uri->user != NULL) {
Packit 423ecb
		p = uri->user;
Packit 423ecb
		while (*p != 0) {
Packit 423ecb
		    if (len + 3 >= max) {
Packit 423ecb
                        temp = xmlSaveUriRealloc(ret, &max;;
Packit 423ecb
                        if (temp == NULL) goto mem_error;
Packit 423ecb
                        ret = temp;
Packit 423ecb
		    }
Packit 423ecb
		    if ((IS_UNRESERVED(*(p))) ||
Packit 423ecb
			((*(p) == ';')) || ((*(p) == ':')) ||
Packit 423ecb
			((*(p) == '&')) || ((*(p) == '=')) ||
Packit 423ecb
			((*(p) == '+')) || ((*(p) == '$')) ||
Packit 423ecb
			((*(p) == ',')))
Packit 423ecb
			ret[len++] = *p++;
Packit 423ecb
		    else {
Packit 423ecb
			int val = *(unsigned char *)p++;
Packit 423ecb
			int hi = val / 0x10, lo = val % 0x10;
Packit 423ecb
			ret[len++] = '%';
Packit 423ecb
			ret[len++] = hi + (hi > 9? 'A'-10 : '0');
Packit 423ecb
			ret[len++] = lo + (lo > 9? 'A'-10 : '0');
Packit 423ecb
		    }
Packit 423ecb
		}
Packit 423ecb
		if (len + 3 >= max) {
Packit 423ecb
                    temp = xmlSaveUriRealloc(ret, &max;;
Packit 423ecb
                    if (temp == NULL) goto mem_error;
Packit 423ecb
                    ret = temp;
Packit 423ecb
		}
Packit 423ecb
		ret[len++] = '@';
Packit 423ecb
	    }
Packit 423ecb
	    if (uri->server != NULL) {
Packit 423ecb
		p = uri->server;
Packit 423ecb
		while (*p != 0) {
Packit 423ecb
		    if (len >= max) {
Packit 423ecb
			temp = xmlSaveUriRealloc(ret, &max;;
Packit 423ecb
			if (temp == NULL) goto mem_error;
Packit 423ecb
			ret = temp;
Packit 423ecb
		    }
Packit 423ecb
		    ret[len++] = *p++;
Packit 423ecb
		}
Packit 423ecb
		if (uri->port > 0) {
Packit 423ecb
		    if (len + 10 >= max) {
Packit 423ecb
			temp = xmlSaveUriRealloc(ret, &max;;
Packit 423ecb
			if (temp == NULL) goto mem_error;
Packit 423ecb
			ret = temp;
Packit 423ecb
		    }
Packit 423ecb
		    len += snprintf((char *) &ret[len], max - len, ":%d", uri->port);
Packit 423ecb
		}
Packit 423ecb
	    }
Packit 423ecb
	} else if (uri->authority != NULL) {
Packit 423ecb
	    if (len + 3 >= max) {
Packit 423ecb
                temp = xmlSaveUriRealloc(ret, &max;;
Packit 423ecb
                if (temp == NULL) goto mem_error;
Packit 423ecb
                ret = temp;
Packit 423ecb
	    }
Packit 423ecb
	    ret[len++] = '/';
Packit 423ecb
	    ret[len++] = '/';
Packit 423ecb
	    p = uri->authority;
Packit 423ecb
	    while (*p != 0) {
Packit 423ecb
		if (len + 3 >= max) {
Packit 423ecb
                    temp = xmlSaveUriRealloc(ret, &max;;
Packit 423ecb
                    if (temp == NULL) goto mem_error;
Packit 423ecb
                    ret = temp;
Packit 423ecb
		}
Packit 423ecb
		if ((IS_UNRESERVED(*(p))) ||
Packit 423ecb
                    ((*(p) == '$')) || ((*(p) == ',')) || ((*(p) == ';')) ||
Packit 423ecb
                    ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) ||
Packit 423ecb
                    ((*(p) == '=')) || ((*(p) == '+')))
Packit 423ecb
		    ret[len++] = *p++;
Packit 423ecb
		else {
Packit 423ecb
		    int val = *(unsigned char *)p++;
Packit 423ecb
		    int hi = val / 0x10, lo = val % 0x10;
Packit 423ecb
		    ret[len++] = '%';
Packit 423ecb
		    ret[len++] = hi + (hi > 9? 'A'-10 : '0');
Packit 423ecb
		    ret[len++] = lo + (lo > 9? 'A'-10 : '0');
Packit 423ecb
		}
Packit 423ecb
	    }
Packit 423ecb
	} else if (uri->scheme != NULL) {
Packit 423ecb
	    if (len + 3 >= max) {
Packit 423ecb
                temp = xmlSaveUriRealloc(ret, &max;;
Packit 423ecb
                if (temp == NULL) goto mem_error;
Packit 423ecb
                ret = temp;
Packit 423ecb
	    }
Packit 423ecb
	}
Packit 423ecb
	if (uri->path != NULL) {
Packit 423ecb
	    p = uri->path;
Packit 423ecb
	    /*
Packit 423ecb
	     * the colon in file:///d: should not be escaped or
Packit 423ecb
	     * Windows accesses fail later.
Packit 423ecb
	     */
Packit 423ecb
	    if ((uri->scheme != NULL) &&
Packit 423ecb
		(p[0] == '/') &&
Packit 423ecb
		(((p[1] >= 'a') && (p[1] <= 'z')) ||
Packit 423ecb
		 ((p[1] >= 'A') && (p[1] <= 'Z'))) &&
Packit 423ecb
		(p[2] == ':') &&
Packit 423ecb
	        (xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) {
Packit 423ecb
		if (len + 3 >= max) {
Packit 423ecb
                    temp = xmlSaveUriRealloc(ret, &max;;
Packit 423ecb
                    if (temp == NULL) goto mem_error;
Packit 423ecb
                    ret = temp;
Packit 423ecb
		}
Packit 423ecb
		ret[len++] = *p++;
Packit 423ecb
		ret[len++] = *p++;
Packit 423ecb
		ret[len++] = *p++;
Packit 423ecb
	    }
Packit 423ecb
	    while (*p != 0) {
Packit 423ecb
		if (len + 3 >= max) {
Packit 423ecb
                    temp = xmlSaveUriRealloc(ret, &max;;
Packit 423ecb
                    if (temp == NULL) goto mem_error;
Packit 423ecb
                    ret = temp;
Packit 423ecb
		}
Packit 423ecb
		if ((IS_UNRESERVED(*(p))) || ((*(p) == '/')) ||
Packit 423ecb
                    ((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) ||
Packit 423ecb
	            ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||
Packit 423ecb
	            ((*(p) == ',')))
Packit 423ecb
		    ret[len++] = *p++;
Packit 423ecb
		else {
Packit 423ecb
		    int val = *(unsigned char *)p++;
Packit 423ecb
		    int hi = val / 0x10, lo = val % 0x10;
Packit 423ecb
		    ret[len++] = '%';
Packit 423ecb
		    ret[len++] = hi + (hi > 9? 'A'-10 : '0');
Packit 423ecb
		    ret[len++] = lo + (lo > 9? 'A'-10 : '0');
Packit 423ecb
		}
Packit 423ecb
	    }
Packit 423ecb
	}
Packit 423ecb
	if (uri->query_raw != NULL) {
Packit 423ecb
	    if (len + 1 >= max) {
Packit 423ecb
                temp = xmlSaveUriRealloc(ret, &max;;
Packit 423ecb
                if (temp == NULL) goto mem_error;
Packit 423ecb
                ret = temp;
Packit 423ecb
	    }
Packit 423ecb
	    ret[len++] = '?';
Packit 423ecb
	    p = uri->query_raw;
Packit 423ecb
	    while (*p != 0) {
Packit 423ecb
		if (len + 1 >= max) {
Packit 423ecb
                    temp = xmlSaveUriRealloc(ret, &max;;
Packit 423ecb
                    if (temp == NULL) goto mem_error;
Packit 423ecb
                    ret = temp;
Packit 423ecb
		}
Packit 423ecb
		ret[len++] = *p++;
Packit 423ecb
	    }
Packit 423ecb
	} else if (uri->query != NULL) {
Packit 423ecb
	    if (len + 3 >= max) {
Packit 423ecb
                temp = xmlSaveUriRealloc(ret, &max;;
Packit 423ecb
                if (temp == NULL) goto mem_error;
Packit 423ecb
                ret = temp;
Packit 423ecb
	    }
Packit 423ecb
	    ret[len++] = '?';
Packit 423ecb
	    p = uri->query;
Packit 423ecb
	    while (*p != 0) {
Packit 423ecb
		if (len + 3 >= max) {
Packit 423ecb
                    temp = xmlSaveUriRealloc(ret, &max;;
Packit 423ecb
                    if (temp == NULL) goto mem_error;
Packit 423ecb
                    ret = temp;
Packit 423ecb
		}
Packit 423ecb
		if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p))))
Packit 423ecb
		    ret[len++] = *p++;
Packit 423ecb
		else {
Packit 423ecb
		    int val = *(unsigned char *)p++;
Packit 423ecb
		    int hi = val / 0x10, lo = val % 0x10;
Packit 423ecb
		    ret[len++] = '%';
Packit 423ecb
		    ret[len++] = hi + (hi > 9? 'A'-10 : '0');
Packit 423ecb
		    ret[len++] = lo + (lo > 9? 'A'-10 : '0');
Packit 423ecb
		}
Packit 423ecb
	    }
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
    if (uri->fragment != NULL) {
Packit 423ecb
	if (len + 3 >= max) {
Packit 423ecb
            temp = xmlSaveUriRealloc(ret, &max;;
Packit 423ecb
            if (temp == NULL) goto mem_error;
Packit 423ecb
            ret = temp;
Packit 423ecb
	}
Packit 423ecb
	ret[len++] = '#';
Packit 423ecb
	p = uri->fragment;
Packit 423ecb
	while (*p != 0) {
Packit 423ecb
	    if (len + 3 >= max) {
Packit 423ecb
                temp = xmlSaveUriRealloc(ret, &max;;
Packit 423ecb
                if (temp == NULL) goto mem_error;
Packit 423ecb
                ret = temp;
Packit 423ecb
	    }
Packit 423ecb
	    if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p))))
Packit 423ecb
		ret[len++] = *p++;
Packit 423ecb
	    else {
Packit 423ecb
		int val = *(unsigned char *)p++;
Packit 423ecb
		int hi = val / 0x10, lo = val % 0x10;
Packit 423ecb
		ret[len++] = '%';
Packit 423ecb
		ret[len++] = hi + (hi > 9? 'A'-10 : '0');
Packit 423ecb
		ret[len++] = lo + (lo > 9? 'A'-10 : '0');
Packit 423ecb
	    }
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
    if (len >= max) {
Packit 423ecb
        temp = xmlSaveUriRealloc(ret, &max;;
Packit 423ecb
        if (temp == NULL) goto mem_error;
Packit 423ecb
        ret = temp;
Packit 423ecb
    }
Packit 423ecb
    ret[len] = 0;
Packit 423ecb
    return(ret);
Packit 423ecb
Packit 423ecb
mem_error:
Packit 423ecb
    xmlFree(ret);
Packit 423ecb
    return(NULL);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlPrintURI:
Packit 423ecb
 * @stream:  a FILE* for the output
Packit 423ecb
 * @uri:  pointer to an xmlURI
Packit 423ecb
 *
Packit 423ecb
 * Prints the URI in the stream @stream.
Packit 423ecb
 */
Packit 423ecb
void
Packit 423ecb
xmlPrintURI(FILE *stream, xmlURIPtr uri) {
Packit 423ecb
    xmlChar *out;
Packit 423ecb
Packit 423ecb
    out = xmlSaveUri(uri);
Packit 423ecb
    if (out != NULL) {
Packit 423ecb
	fprintf(stream, "%s", (char *) out);
Packit 423ecb
	xmlFree(out);
Packit 423ecb
    }
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlCleanURI:
Packit 423ecb
 * @uri:  pointer to an xmlURI
Packit 423ecb
 *
Packit 423ecb
 * Make sure the xmlURI struct is free of content
Packit 423ecb
 */
Packit 423ecb
static void
Packit 423ecb
xmlCleanURI(xmlURIPtr uri) {
Packit 423ecb
    if (uri == NULL) return;
Packit 423ecb
Packit 423ecb
    if (uri->scheme != NULL) xmlFree(uri->scheme);
Packit 423ecb
    uri->scheme = NULL;
Packit 423ecb
    if (uri->server != NULL) xmlFree(uri->server);
Packit 423ecb
    uri->server = NULL;
Packit 423ecb
    if (uri->user != NULL) xmlFree(uri->user);
Packit 423ecb
    uri->user = NULL;
Packit 423ecb
    if (uri->path != NULL) xmlFree(uri->path);
Packit 423ecb
    uri->path = NULL;
Packit 423ecb
    if (uri->fragment != NULL) xmlFree(uri->fragment);
Packit 423ecb
    uri->fragment = NULL;
Packit 423ecb
    if (uri->opaque != NULL) xmlFree(uri->opaque);
Packit 423ecb
    uri->opaque = NULL;
Packit 423ecb
    if (uri->authority != NULL) xmlFree(uri->authority);
Packit 423ecb
    uri->authority = NULL;
Packit 423ecb
    if (uri->query != NULL) xmlFree(uri->query);
Packit 423ecb
    uri->query = NULL;
Packit 423ecb
    if (uri->query_raw != NULL) xmlFree(uri->query_raw);
Packit 423ecb
    uri->query_raw = NULL;
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlFreeURI:
Packit 423ecb
 * @uri:  pointer to an xmlURI
Packit 423ecb
 *
Packit 423ecb
 * Free up the xmlURI struct
Packit 423ecb
 */
Packit 423ecb
void
Packit 423ecb
xmlFreeURI(xmlURIPtr uri) {
Packit 423ecb
    if (uri == NULL) return;
Packit 423ecb
Packit 423ecb
    if (uri->scheme != NULL) xmlFree(uri->scheme);
Packit 423ecb
    if (uri->server != NULL) xmlFree(uri->server);
Packit 423ecb
    if (uri->user != NULL) xmlFree(uri->user);
Packit 423ecb
    if (uri->path != NULL) xmlFree(uri->path);
Packit 423ecb
    if (uri->fragment != NULL) xmlFree(uri->fragment);
Packit 423ecb
    if (uri->opaque != NULL) xmlFree(uri->opaque);
Packit 423ecb
    if (uri->authority != NULL) xmlFree(uri->authority);
Packit 423ecb
    if (uri->query != NULL) xmlFree(uri->query);
Packit 423ecb
    if (uri->query_raw != NULL) xmlFree(uri->query_raw);
Packit 423ecb
    xmlFree(uri);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/************************************************************************
Packit 423ecb
 *									*
Packit 423ecb
 *			Helper functions				*
Packit 423ecb
 *									*
Packit 423ecb
 ************************************************************************/
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlNormalizeURIPath:
Packit 423ecb
 * @path:  pointer to the path string
Packit 423ecb
 *
Packit 423ecb
 * Applies the 5 normalization steps to a path string--that is, RFC 2396
Packit 423ecb
 * Section 5.2, steps 6.c through 6.g.
Packit 423ecb
 *
Packit 423ecb
 * Normalization occurs directly on the string, no new allocation is done
Packit 423ecb
 *
Packit 423ecb
 * Returns 0 or an error code
Packit 423ecb
 */
Packit 423ecb
int
Packit 423ecb
xmlNormalizeURIPath(char *path) {
Packit 423ecb
    char *cur, *out;
Packit 423ecb
Packit 423ecb
    if (path == NULL)
Packit 423ecb
	return(-1);
Packit 423ecb
Packit 423ecb
    /* Skip all initial "/" chars.  We want to get to the beginning of the
Packit 423ecb
     * first non-empty segment.
Packit 423ecb
     */
Packit 423ecb
    cur = path;
Packit 423ecb
    while (cur[0] == '/')
Packit 423ecb
      ++cur;
Packit 423ecb
    if (cur[0] == '\0')
Packit 423ecb
      return(0);
Packit 423ecb
Packit 423ecb
    /* Keep everything we've seen so far.  */
Packit 423ecb
    out = cur;
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * Analyze each segment in sequence for cases (c) and (d).
Packit 423ecb
     */
Packit 423ecb
    while (cur[0] != '\0') {
Packit 423ecb
	/*
Packit 423ecb
	 * c) All occurrences of "./", where "." is a complete path segment,
Packit 423ecb
	 *    are removed from the buffer string.
Packit 423ecb
	 */
Packit 423ecb
	if ((cur[0] == '.') && (cur[1] == '/')) {
Packit 423ecb
	    cur += 2;
Packit 423ecb
	    /* '//' normalization should be done at this point too */
Packit 423ecb
	    while (cur[0] == '/')
Packit 423ecb
		cur++;
Packit 423ecb
	    continue;
Packit 423ecb
	}
Packit 423ecb
Packit 423ecb
	/*
Packit 423ecb
	 * d) If the buffer string ends with "." as a complete path segment,
Packit 423ecb
	 *    that "." is removed.
Packit 423ecb
	 */
Packit 423ecb
	if ((cur[0] == '.') && (cur[1] == '\0'))
Packit 423ecb
	    break;
Packit 423ecb
Packit 423ecb
	/* Otherwise keep the segment.  */
Packit 423ecb
	while (cur[0] != '/') {
Packit 423ecb
            if (cur[0] == '\0')
Packit 423ecb
              goto done_cd;
Packit 423ecb
	    (out++)[0] = (cur++)[0];
Packit 423ecb
	}
Packit 423ecb
	/* nomalize // */
Packit 423ecb
	while ((cur[0] == '/') && (cur[1] == '/'))
Packit 423ecb
	    cur++;
Packit 423ecb
Packit 423ecb
        (out++)[0] = (cur++)[0];
Packit 423ecb
    }
Packit 423ecb
 done_cd:
Packit 423ecb
    out[0] = '\0';
Packit 423ecb
Packit 423ecb
    /* Reset to the beginning of the first segment for the next sequence.  */
Packit 423ecb
    cur = path;
Packit 423ecb
    while (cur[0] == '/')
Packit 423ecb
      ++cur;
Packit 423ecb
    if (cur[0] == '\0')
Packit 423ecb
	return(0);
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * Analyze each segment in sequence for cases (e) and (f).
Packit 423ecb
     *
Packit 423ecb
     * e) All occurrences of "<segment>/../", where <segment> is a
Packit 423ecb
     *    complete path segment not equal to "..", are removed from the
Packit 423ecb
     *    buffer string.  Removal of these path segments is performed
Packit 423ecb
     *    iteratively, removing the leftmost matching pattern on each
Packit 423ecb
     *    iteration, until no matching pattern remains.
Packit 423ecb
     *
Packit 423ecb
     * f) If the buffer string ends with "<segment>/..", where <segment>
Packit 423ecb
     *    is a complete path segment not equal to "..", that
Packit 423ecb
     *    "<segment>/.." is removed.
Packit 423ecb
     *
Packit 423ecb
     * To satisfy the "iterative" clause in (e), we need to collapse the
Packit 423ecb
     * string every time we find something that needs to be removed.  Thus,
Packit 423ecb
     * we don't need to keep two pointers into the string: we only need a
Packit 423ecb
     * "current position" pointer.
Packit 423ecb
     */
Packit 423ecb
    while (1) {
Packit 423ecb
        char *segp, *tmp;
Packit 423ecb
Packit 423ecb
        /* At the beginning of each iteration of this loop, "cur" points to
Packit 423ecb
         * the first character of the segment we want to examine.
Packit 423ecb
         */
Packit 423ecb
Packit 423ecb
        /* Find the end of the current segment.  */
Packit 423ecb
        segp = cur;
Packit 423ecb
        while ((segp[0] != '/') && (segp[0] != '\0'))
Packit 423ecb
          ++segp;
Packit 423ecb
Packit 423ecb
        /* If this is the last segment, we're done (we need at least two
Packit 423ecb
         * segments to meet the criteria for the (e) and (f) cases).
Packit 423ecb
         */
Packit 423ecb
        if (segp[0] == '\0')
Packit 423ecb
          break;
Packit 423ecb
Packit 423ecb
        /* If the first segment is "..", or if the next segment _isn't_ "..",
Packit 423ecb
         * keep this segment and try the next one.
Packit 423ecb
         */
Packit 423ecb
        ++segp;
Packit 423ecb
        if (((cur[0] == '.') && (cur[1] == '.') && (segp == cur+3))
Packit 423ecb
            || ((segp[0] != '.') || (segp[1] != '.')
Packit 423ecb
                || ((segp[2] != '/') && (segp[2] != '\0')))) {
Packit 423ecb
          cur = segp;
Packit 423ecb
          continue;
Packit 423ecb
        }
Packit 423ecb
Packit 423ecb
        /* If we get here, remove this segment and the next one and back up
Packit 423ecb
         * to the previous segment (if there is one), to implement the
Packit 423ecb
         * "iteratively" clause.  It's pretty much impossible to back up
Packit 423ecb
         * while maintaining two pointers into the buffer, so just compact
Packit 423ecb
         * the whole buffer now.
Packit 423ecb
         */
Packit 423ecb
Packit 423ecb
        /* If this is the end of the buffer, we're done.  */
Packit 423ecb
        if (segp[2] == '\0') {
Packit 423ecb
          cur[0] = '\0';
Packit 423ecb
          break;
Packit 423ecb
        }
Packit 423ecb
        /* Valgrind complained, strcpy(cur, segp + 3); */
Packit 423ecb
        /* string will overlap, do not use strcpy */
Packit 423ecb
        tmp = cur;
Packit 423ecb
        segp += 3;
Packit 423ecb
        while ((*tmp++ = *segp++) != 0)
Packit 423ecb
          ;
Packit 423ecb
Packit 423ecb
        /* If there are no previous segments, then keep going from here.  */
Packit 423ecb
        segp = cur;
Packit 423ecb
        while ((segp > path) && ((--segp)[0] == '/'))
Packit 423ecb
          ;
Packit 423ecb
        if (segp == path)
Packit 423ecb
          continue;
Packit 423ecb
Packit 423ecb
        /* "segp" is pointing to the end of a previous segment; find it's
Packit 423ecb
         * start.  We need to back up to the previous segment and start
Packit 423ecb
         * over with that to handle things like "foo/bar/../..".  If we
Packit 423ecb
         * don't do this, then on the first pass we'll remove the "bar/..",
Packit 423ecb
         * but be pointing at the second ".." so we won't realize we can also
Packit 423ecb
         * remove the "foo/..".
Packit 423ecb
         */
Packit 423ecb
        cur = segp;
Packit 423ecb
        while ((cur > path) && (cur[-1] != '/'))
Packit 423ecb
          --cur;
Packit 423ecb
    }
Packit 423ecb
    out[0] = '\0';
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * g) If the resulting buffer string still begins with one or more
Packit 423ecb
     *    complete path segments of "..", then the reference is
Packit 423ecb
     *    considered to be in error. Implementations may handle this
Packit 423ecb
     *    error by retaining these components in the resolved path (i.e.,
Packit 423ecb
     *    treating them as part of the final URI), by removing them from
Packit 423ecb
     *    the resolved path (i.e., discarding relative levels above the
Packit 423ecb
     *    root), or by avoiding traversal of the reference.
Packit 423ecb
     *
Packit 423ecb
     * We discard them from the final path.
Packit 423ecb
     */
Packit 423ecb
    if (path[0] == '/') {
Packit 423ecb
      cur = path;
Packit 423ecb
      while ((cur[0] == '/') && (cur[1] == '.') && (cur[2] == '.')
Packit 423ecb
             && ((cur[3] == '/') || (cur[3] == '\0')))
Packit 423ecb
	cur += 3;
Packit 423ecb
Packit 423ecb
      if (cur != path) {
Packit 423ecb
	out = path;
Packit 423ecb
	while (cur[0] != '\0')
Packit 423ecb
          (out++)[0] = (cur++)[0];
Packit 423ecb
	out[0] = 0;
Packit 423ecb
      }
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    return(0);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
static int is_hex(char c) {
Packit 423ecb
    if (((c >= '0') && (c <= '9')) ||
Packit 423ecb
        ((c >= 'a') && (c <= 'f')) ||
Packit 423ecb
        ((c >= 'A') && (c <= 'F')))
Packit 423ecb
	return(1);
Packit 423ecb
    return(0);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlURIUnescapeString:
Packit 423ecb
 * @str:  the string to unescape
Packit 423ecb
 * @len:   the length in bytes to unescape (or <= 0 to indicate full string)
Packit 423ecb
 * @target:  optional destination buffer
Packit 423ecb
 *
Packit 423ecb
 * Unescaping routine, but does not check that the string is an URI. The
Packit 423ecb
 * output is a direct unsigned char translation of %XX values (no encoding)
Packit 423ecb
 * Note that the length of the result can only be smaller or same size as
Packit 423ecb
 * the input string.
Packit 423ecb
 *
Packit 423ecb
 * Returns a copy of the string, but unescaped, will return NULL only in case
Packit 423ecb
 * of error
Packit 423ecb
 */
Packit 423ecb
char *
Packit 423ecb
xmlURIUnescapeString(const char *str, int len, char *target) {
Packit 423ecb
    char *ret, *out;
Packit 423ecb
    const char *in;
Packit 423ecb
Packit 423ecb
    if (str == NULL)
Packit 423ecb
	return(NULL);
Packit 423ecb
    if (len <= 0) len = strlen(str);
Packit 423ecb
    if (len < 0) return(NULL);
Packit 423ecb
Packit 423ecb
    if (target == NULL) {
Packit 423ecb
	ret = (char *) xmlMallocAtomic(len + 1);
Packit 423ecb
	if (ret == NULL) {
Packit 423ecb
            xmlURIErrMemory("unescaping URI value\n");
Packit 423ecb
	    return(NULL);
Packit 423ecb
	}
Packit 423ecb
    } else
Packit 423ecb
	ret = target;
Packit 423ecb
    in = str;
Packit 423ecb
    out = ret;
Packit 423ecb
    while(len > 0) {
Packit 423ecb
	if ((len > 2) && (*in == '%') && (is_hex(in[1])) && (is_hex(in[2]))) {
Packit 423ecb
	    in++;
Packit 423ecb
	    if ((*in >= '0') && (*in <= '9'))
Packit 423ecb
	        *out = (*in - '0');
Packit 423ecb
	    else if ((*in >= 'a') && (*in <= 'f'))
Packit 423ecb
	        *out = (*in - 'a') + 10;
Packit 423ecb
	    else if ((*in >= 'A') && (*in <= 'F'))
Packit 423ecb
	        *out = (*in - 'A') + 10;
Packit 423ecb
	    in++;
Packit 423ecb
	    if ((*in >= '0') && (*in <= '9'))
Packit 423ecb
	        *out = *out * 16 + (*in - '0');
Packit 423ecb
	    else if ((*in >= 'a') && (*in <= 'f'))
Packit 423ecb
	        *out = *out * 16 + (*in - 'a') + 10;
Packit 423ecb
	    else if ((*in >= 'A') && (*in <= 'F'))
Packit 423ecb
	        *out = *out * 16 + (*in - 'A') + 10;
Packit 423ecb
	    in++;
Packit 423ecb
	    len -= 3;
Packit 423ecb
	    out++;
Packit 423ecb
	} else {
Packit 423ecb
	    *out++ = *in++;
Packit 423ecb
	    len--;
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
    *out = 0;
Packit 423ecb
    return(ret);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlURIEscapeStr:
Packit 423ecb
 * @str:  string to escape
Packit 423ecb
 * @list: exception list string of chars not to escape
Packit 423ecb
 *
Packit 423ecb
 * This routine escapes a string to hex, ignoring reserved characters (a-z)
Packit 423ecb
 * and the characters in the exception list.
Packit 423ecb
 *
Packit 423ecb
 * Returns a new escaped string or NULL in case of error.
Packit 423ecb
 */
Packit 423ecb
xmlChar *
Packit 423ecb
xmlURIEscapeStr(const xmlChar *str, const xmlChar *list) {
Packit 423ecb
    xmlChar *ret, ch;
Packit 423ecb
    xmlChar *temp;
Packit 423ecb
    const xmlChar *in;
Packit 423ecb
    int len, out;
Packit 423ecb
Packit 423ecb
    if (str == NULL)
Packit 423ecb
	return(NULL);
Packit 423ecb
    if (str[0] == 0)
Packit 423ecb
	return(xmlStrdup(str));
Packit 423ecb
    len = xmlStrlen(str);
Packit 423ecb
    if (!(len > 0)) return(NULL);
Packit 423ecb
Packit 423ecb
    len += 20;
Packit 423ecb
    ret = (xmlChar *) xmlMallocAtomic(len);
Packit 423ecb
    if (ret == NULL) {
Packit 423ecb
        xmlURIErrMemory("escaping URI value\n");
Packit 423ecb
	return(NULL);
Packit 423ecb
    }
Packit 423ecb
    in = (const xmlChar *) str;
Packit 423ecb
    out = 0;
Packit 423ecb
    while(*in != 0) {
Packit 423ecb
	if (len - out <= 3) {
Packit 423ecb
            temp = xmlSaveUriRealloc(ret, &len;;
Packit 423ecb
	    if (temp == NULL) {
Packit 423ecb
                xmlURIErrMemory("escaping URI value\n");
Packit 423ecb
		xmlFree(ret);
Packit 423ecb
		return(NULL);
Packit 423ecb
	    }
Packit 423ecb
	    ret = temp;
Packit 423ecb
	}
Packit 423ecb
Packit 423ecb
	ch = *in;
Packit 423ecb
Packit 423ecb
	if ((ch != '@') && (!IS_UNRESERVED(ch)) && (!xmlStrchr(list, ch))) {
Packit 423ecb
	    unsigned char val;
Packit 423ecb
	    ret[out++] = '%';
Packit 423ecb
	    val = ch >> 4;
Packit 423ecb
	    if (val <= 9)
Packit 423ecb
		ret[out++] = '0' + val;
Packit 423ecb
	    else
Packit 423ecb
		ret[out++] = 'A' + val - 0xA;
Packit 423ecb
	    val = ch & 0xF;
Packit 423ecb
	    if (val <= 9)
Packit 423ecb
		ret[out++] = '0' + val;
Packit 423ecb
	    else
Packit 423ecb
		ret[out++] = 'A' + val - 0xA;
Packit 423ecb
	    in++;
Packit 423ecb
	} else {
Packit 423ecb
	    ret[out++] = *in++;
Packit 423ecb
	}
Packit 423ecb
Packit 423ecb
    }
Packit 423ecb
    ret[out] = 0;
Packit 423ecb
    return(ret);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlURIEscape:
Packit 423ecb
 * @str:  the string of the URI to escape
Packit 423ecb
 *
Packit 423ecb
 * Escaping routine, does not do validity checks !
Packit 423ecb
 * It will try to escape the chars needing this, but this is heuristic
Packit 423ecb
 * based it's impossible to be sure.
Packit 423ecb
 *
Packit 423ecb
 * Returns an copy of the string, but escaped
Packit 423ecb
 *
Packit 423ecb
 * 25 May 2001
Packit 423ecb
 * Uses xmlParseURI and xmlURIEscapeStr to try to escape correctly
Packit 423ecb
 * according to RFC2396.
Packit 423ecb
 *   - Carl Douglas
Packit 423ecb
 */
Packit 423ecb
xmlChar *
Packit 423ecb
xmlURIEscape(const xmlChar * str)
Packit 423ecb
{
Packit 423ecb
    xmlChar *ret, *segment = NULL;
Packit 423ecb
    xmlURIPtr uri;
Packit 423ecb
    int ret2;
Packit 423ecb
Packit 423ecb
#define NULLCHK(p) if(!p) { \
Packit 423ecb
         xmlURIErrMemory("escaping URI value\n"); \
Packit 423ecb
         xmlFreeURI(uri); \
Packit 423ecb
         return NULL; } \
Packit 423ecb
Packit 423ecb
    if (str == NULL)
Packit 423ecb
        return (NULL);
Packit 423ecb
Packit 423ecb
    uri = xmlCreateURI();
Packit 423ecb
    if (uri != NULL) {
Packit 423ecb
	/*
Packit 423ecb
	 * Allow escaping errors in the unescaped form
Packit 423ecb
	 */
Packit 423ecb
        uri->cleanup = 1;
Packit 423ecb
        ret2 = xmlParseURIReference(uri, (const char *)str);
Packit 423ecb
        if (ret2) {
Packit 423ecb
            xmlFreeURI(uri);
Packit 423ecb
            return (NULL);
Packit 423ecb
        }
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    if (!uri)
Packit 423ecb
        return NULL;
Packit 423ecb
Packit 423ecb
    ret = NULL;
Packit 423ecb
Packit 423ecb
    if (uri->scheme) {
Packit 423ecb
        segment = xmlURIEscapeStr(BAD_CAST uri->scheme, BAD_CAST "+-.");
Packit 423ecb
        NULLCHK(segment)
Packit 423ecb
        ret = xmlStrcat(ret, segment);
Packit 423ecb
        ret = xmlStrcat(ret, BAD_CAST ":");
Packit 423ecb
        xmlFree(segment);
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    if (uri->authority) {
Packit 423ecb
        segment =
Packit 423ecb
            xmlURIEscapeStr(BAD_CAST uri->authority, BAD_CAST "/?;:@");
Packit 423ecb
        NULLCHK(segment)
Packit 423ecb
        ret = xmlStrcat(ret, BAD_CAST "//");
Packit 423ecb
        ret = xmlStrcat(ret, segment);
Packit 423ecb
        xmlFree(segment);
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    if (uri->user) {
Packit 423ecb
        segment = xmlURIEscapeStr(BAD_CAST uri->user, BAD_CAST ";:&=+$,");
Packit 423ecb
        NULLCHK(segment)
Packit 423ecb
		ret = xmlStrcat(ret,BAD_CAST "//");
Packit 423ecb
        ret = xmlStrcat(ret, segment);
Packit 423ecb
        ret = xmlStrcat(ret, BAD_CAST "@");
Packit 423ecb
        xmlFree(segment);
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    if (uri->server) {
Packit 423ecb
        segment = xmlURIEscapeStr(BAD_CAST uri->server, BAD_CAST "/?;:@");
Packit 423ecb
        NULLCHK(segment)
Packit 423ecb
		if (uri->user == NULL)
Packit 423ecb
		ret = xmlStrcat(ret, BAD_CAST "//");
Packit 423ecb
        ret = xmlStrcat(ret, segment);
Packit 423ecb
        xmlFree(segment);
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    if (uri->port) {
Packit 423ecb
        xmlChar port[10];
Packit 423ecb
Packit 423ecb
        snprintf((char *) port, 10, "%d", uri->port);
Packit 423ecb
        ret = xmlStrcat(ret, BAD_CAST ":");
Packit 423ecb
        ret = xmlStrcat(ret, port);
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    if (uri->path) {
Packit 423ecb
        segment =
Packit 423ecb
            xmlURIEscapeStr(BAD_CAST uri->path, BAD_CAST ":@&=+$,/?;");
Packit 423ecb
        NULLCHK(segment)
Packit 423ecb
        ret = xmlStrcat(ret, segment);
Packit 423ecb
        xmlFree(segment);
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    if (uri->query_raw) {
Packit 423ecb
        ret = xmlStrcat(ret, BAD_CAST "?");
Packit 423ecb
        ret = xmlStrcat(ret, BAD_CAST uri->query_raw);
Packit 423ecb
    }
Packit 423ecb
    else if (uri->query) {
Packit 423ecb
        segment =
Packit 423ecb
            xmlURIEscapeStr(BAD_CAST uri->query, BAD_CAST ";/?:@&=+,$");
Packit 423ecb
        NULLCHK(segment)
Packit 423ecb
        ret = xmlStrcat(ret, BAD_CAST "?");
Packit 423ecb
        ret = xmlStrcat(ret, segment);
Packit 423ecb
        xmlFree(segment);
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    if (uri->opaque) {
Packit 423ecb
        segment = xmlURIEscapeStr(BAD_CAST uri->opaque, BAD_CAST "");
Packit 423ecb
        NULLCHK(segment)
Packit 423ecb
        ret = xmlStrcat(ret, segment);
Packit 423ecb
        xmlFree(segment);
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    if (uri->fragment) {
Packit 423ecb
        segment = xmlURIEscapeStr(BAD_CAST uri->fragment, BAD_CAST "#");
Packit 423ecb
        NULLCHK(segment)
Packit 423ecb
        ret = xmlStrcat(ret, BAD_CAST "#");
Packit 423ecb
        ret = xmlStrcat(ret, segment);
Packit 423ecb
        xmlFree(segment);
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    xmlFreeURI(uri);
Packit 423ecb
#undef NULLCHK
Packit 423ecb
Packit 423ecb
    return (ret);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/************************************************************************
Packit 423ecb
 *									*
Packit 423ecb
 *			Public functions				*
Packit 423ecb
 *									*
Packit 423ecb
 ************************************************************************/
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlBuildURI:
Packit 423ecb
 * @URI:  the URI instance found in the document
Packit 423ecb
 * @base:  the base value
Packit 423ecb
 *
Packit 423ecb
 * Computes he final URI of the reference done by checking that
Packit 423ecb
 * the given URI is valid, and building the final URI using the
Packit 423ecb
 * base URI. This is processed according to section 5.2 of the
Packit 423ecb
 * RFC 2396
Packit 423ecb
 *
Packit 423ecb
 * 5.2. Resolving Relative References to Absolute Form
Packit 423ecb
 *
Packit 423ecb
 * Returns a new URI string (to be freed by the caller) or NULL in case
Packit 423ecb
 *         of error.
Packit 423ecb
 */
Packit 423ecb
xmlChar *
Packit 423ecb
xmlBuildURI(const xmlChar *URI, const xmlChar *base) {
Packit 423ecb
    xmlChar *val = NULL;
Packit 423ecb
    int ret, len, indx, cur, out;
Packit 423ecb
    xmlURIPtr ref = NULL;
Packit 423ecb
    xmlURIPtr bas = NULL;
Packit 423ecb
    xmlURIPtr res = NULL;
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * 1) The URI reference is parsed into the potential four components and
Packit 423ecb
     *    fragment identifier, as described in Section 4.3.
Packit 423ecb
     *
Packit 423ecb
     *    NOTE that a completely empty URI is treated by modern browsers
Packit 423ecb
     *    as a reference to "." rather than as a synonym for the current
Packit 423ecb
     *    URI.  Should we do that here?
Packit 423ecb
     */
Packit 423ecb
    if (URI == NULL)
Packit 423ecb
	ret = -1;
Packit 423ecb
    else {
Packit 423ecb
	if (*URI) {
Packit 423ecb
	    ref = xmlCreateURI();
Packit 423ecb
	    if (ref == NULL)
Packit 423ecb
		goto done;
Packit 423ecb
	    ret = xmlParseURIReference(ref, (const char *) URI);
Packit 423ecb
	}
Packit 423ecb
	else
Packit 423ecb
	    ret = 0;
Packit 423ecb
    }
Packit 423ecb
    if (ret != 0)
Packit 423ecb
	goto done;
Packit 423ecb
    if ((ref != NULL) && (ref->scheme != NULL)) {
Packit 423ecb
	/*
Packit 423ecb
	 * The URI is absolute don't modify.
Packit 423ecb
	 */
Packit 423ecb
	val = xmlStrdup(URI);
Packit 423ecb
	goto done;
Packit 423ecb
    }
Packit 423ecb
    if (base == NULL)
Packit 423ecb
	ret = -1;
Packit 423ecb
    else {
Packit 423ecb
	bas = xmlCreateURI();
Packit 423ecb
	if (bas == NULL)
Packit 423ecb
	    goto done;
Packit 423ecb
	ret = xmlParseURIReference(bas, (const char *) base);
Packit 423ecb
    }
Packit 423ecb
    if (ret != 0) {
Packit 423ecb
	if (ref)
Packit 423ecb
	    val = xmlSaveUri(ref);
Packit 423ecb
	goto done;
Packit 423ecb
    }
Packit 423ecb
    if (ref == NULL) {
Packit 423ecb
	/*
Packit 423ecb
	 * the base fragment must be ignored
Packit 423ecb
	 */
Packit 423ecb
	if (bas->fragment != NULL) {
Packit 423ecb
	    xmlFree(bas->fragment);
Packit 423ecb
	    bas->fragment = NULL;
Packit 423ecb
	}
Packit 423ecb
	val = xmlSaveUri(bas);
Packit 423ecb
	goto done;
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * 2) If the path component is empty and the scheme, authority, and
Packit 423ecb
     *    query components are undefined, then it is a reference to the
Packit 423ecb
     *    current document and we are done.  Otherwise, the reference URI's
Packit 423ecb
     *    query and fragment components are defined as found (or not found)
Packit 423ecb
     *    within the URI reference and not inherited from the base URI.
Packit 423ecb
     *
Packit 423ecb
     *    NOTE that in modern browsers, the parsing differs from the above
Packit 423ecb
     *    in the following aspect:  the query component is allowed to be
Packit 423ecb
     *    defined while still treating this as a reference to the current
Packit 423ecb
     *    document.
Packit 423ecb
     */
Packit 423ecb
    res = xmlCreateURI();
Packit 423ecb
    if (res == NULL)
Packit 423ecb
	goto done;
Packit 423ecb
    if ((ref->scheme == NULL) && (ref->path == NULL) &&
Packit 423ecb
	((ref->authority == NULL) && (ref->server == NULL))) {
Packit 423ecb
	if (bas->scheme != NULL)
Packit 423ecb
	    res->scheme = xmlMemStrdup(bas->scheme);
Packit 423ecb
	if (bas->authority != NULL)
Packit 423ecb
	    res->authority = xmlMemStrdup(bas->authority);
Packit 423ecb
	else if ((bas->server != NULL) || (bas->port == -1)) {
Packit 423ecb
	    if (bas->server != NULL)
Packit 423ecb
		res->server = xmlMemStrdup(bas->server);
Packit 423ecb
	    if (bas->user != NULL)
Packit 423ecb
		res->user = xmlMemStrdup(bas->user);
Packit 423ecb
	    res->port = bas->port;
Packit 423ecb
	}
Packit 423ecb
	if (bas->path != NULL)
Packit 423ecb
	    res->path = xmlMemStrdup(bas->path);
Packit 423ecb
	if (ref->query_raw != NULL)
Packit 423ecb
	    res->query_raw = xmlMemStrdup (ref->query_raw);
Packit 423ecb
	else if (ref->query != NULL)
Packit 423ecb
	    res->query = xmlMemStrdup(ref->query);
Packit 423ecb
	else if (bas->query_raw != NULL)
Packit 423ecb
	    res->query_raw = xmlMemStrdup(bas->query_raw);
Packit 423ecb
	else if (bas->query != NULL)
Packit 423ecb
	    res->query = xmlMemStrdup(bas->query);
Packit 423ecb
	if (ref->fragment != NULL)
Packit 423ecb
	    res->fragment = xmlMemStrdup(ref->fragment);
Packit 423ecb
	goto step_7;
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * 3) If the scheme component is defined, indicating that the reference
Packit 423ecb
     *    starts with a scheme name, then the reference is interpreted as an
Packit 423ecb
     *    absolute URI and we are done.  Otherwise, the reference URI's
Packit 423ecb
     *    scheme is inherited from the base URI's scheme component.
Packit 423ecb
     */
Packit 423ecb
    if (ref->scheme != NULL) {
Packit 423ecb
	val = xmlSaveUri(ref);
Packit 423ecb
	goto done;
Packit 423ecb
    }
Packit 423ecb
    if (bas->scheme != NULL)
Packit 423ecb
	res->scheme = xmlMemStrdup(bas->scheme);
Packit 423ecb
Packit 423ecb
    if (ref->query_raw != NULL)
Packit 423ecb
	res->query_raw = xmlMemStrdup(ref->query_raw);
Packit 423ecb
    else if (ref->query != NULL)
Packit 423ecb
	res->query = xmlMemStrdup(ref->query);
Packit 423ecb
    if (ref->fragment != NULL)
Packit 423ecb
	res->fragment = xmlMemStrdup(ref->fragment);
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * 4) If the authority component is defined, then the reference is a
Packit 423ecb
     *    network-path and we skip to step 7.  Otherwise, the reference
Packit 423ecb
     *    URI's authority is inherited from the base URI's authority
Packit 423ecb
     *    component, which will also be undefined if the URI scheme does not
Packit 423ecb
     *    use an authority component.
Packit 423ecb
     */
Packit 423ecb
    if ((ref->authority != NULL) || (ref->server != NULL)) {
Packit 423ecb
	if (ref->authority != NULL)
Packit 423ecb
	    res->authority = xmlMemStrdup(ref->authority);
Packit 423ecb
	else {
Packit 423ecb
	    res->server = xmlMemStrdup(ref->server);
Packit 423ecb
	    if (ref->user != NULL)
Packit 423ecb
		res->user = xmlMemStrdup(ref->user);
Packit 423ecb
            res->port = ref->port;
Packit 423ecb
	}
Packit 423ecb
	if (ref->path != NULL)
Packit 423ecb
	    res->path = xmlMemStrdup(ref->path);
Packit 423ecb
	goto step_7;
Packit 423ecb
    }
Packit 423ecb
    if (bas->authority != NULL)
Packit 423ecb
	res->authority = xmlMemStrdup(bas->authority);
Packit 423ecb
    else if ((bas->server != NULL) || (bas->port == -1)) {
Packit 423ecb
	if (bas->server != NULL)
Packit 423ecb
	    res->server = xmlMemStrdup(bas->server);
Packit 423ecb
	if (bas->user != NULL)
Packit 423ecb
	    res->user = xmlMemStrdup(bas->user);
Packit 423ecb
	res->port = bas->port;
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * 5) If the path component begins with a slash character ("/"), then
Packit 423ecb
     *    the reference is an absolute-path and we skip to step 7.
Packit 423ecb
     */
Packit 423ecb
    if ((ref->path != NULL) && (ref->path[0] == '/')) {
Packit 423ecb
	res->path = xmlMemStrdup(ref->path);
Packit 423ecb
	goto step_7;
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * 6) If this step is reached, then we are resolving a relative-path
Packit 423ecb
     *    reference.  The relative path needs to be merged with the base
Packit 423ecb
     *    URI's path.  Although there are many ways to do this, we will
Packit 423ecb
     *    describe a simple method using a separate string buffer.
Packit 423ecb
     *
Packit 423ecb
     * Allocate a buffer large enough for the result string.
Packit 423ecb
     */
Packit 423ecb
    len = 2; /* extra / and 0 */
Packit 423ecb
    if (ref->path != NULL)
Packit 423ecb
	len += strlen(ref->path);
Packit 423ecb
    if (bas->path != NULL)
Packit 423ecb
	len += strlen(bas->path);
Packit 423ecb
    res->path = (char *) xmlMallocAtomic(len);
Packit 423ecb
    if (res->path == NULL) {
Packit 423ecb
        xmlURIErrMemory("resolving URI against base\n");
Packit 423ecb
	goto done;
Packit 423ecb
    }
Packit 423ecb
    res->path[0] = 0;
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * a) All but the last segment of the base URI's path component is
Packit 423ecb
     *    copied to the buffer.  In other words, any characters after the
Packit 423ecb
     *    last (right-most) slash character, if any, are excluded.
Packit 423ecb
     */
Packit 423ecb
    cur = 0;
Packit 423ecb
    out = 0;
Packit 423ecb
    if (bas->path != NULL) {
Packit 423ecb
	while (bas->path[cur] != 0) {
Packit 423ecb
	    while ((bas->path[cur] != 0) && (bas->path[cur] != '/'))
Packit 423ecb
		cur++;
Packit 423ecb
	    if (bas->path[cur] == 0)
Packit 423ecb
		break;
Packit 423ecb
Packit 423ecb
	    cur++;
Packit 423ecb
	    while (out < cur) {
Packit 423ecb
		res->path[out] = bas->path[out];
Packit 423ecb
		out++;
Packit 423ecb
	    }
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
    res->path[out] = 0;
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * b) The reference's path component is appended to the buffer
Packit 423ecb
     *    string.
Packit 423ecb
     */
Packit 423ecb
    if (ref->path != NULL && ref->path[0] != 0) {
Packit 423ecb
	indx = 0;
Packit 423ecb
	/*
Packit 423ecb
	 * Ensure the path includes a '/'
Packit 423ecb
	 */
Packit 423ecb
	if ((out == 0) && (bas->server != NULL))
Packit 423ecb
	    res->path[out++] = '/';
Packit 423ecb
	while (ref->path[indx] != 0) {
Packit 423ecb
	    res->path[out++] = ref->path[indx++];
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
    res->path[out] = 0;
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * Steps c) to h) are really path normalization steps
Packit 423ecb
     */
Packit 423ecb
    xmlNormalizeURIPath(res->path);
Packit 423ecb
Packit 423ecb
step_7:
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * 7) The resulting URI components, including any inherited from the
Packit 423ecb
     *    base URI, are recombined to give the absolute form of the URI
Packit 423ecb
     *    reference.
Packit 423ecb
     */
Packit 423ecb
    val = xmlSaveUri(res);
Packit 423ecb
Packit 423ecb
done:
Packit 423ecb
    if (ref != NULL)
Packit 423ecb
	xmlFreeURI(ref);
Packit 423ecb
    if (bas != NULL)
Packit 423ecb
	xmlFreeURI(bas);
Packit 423ecb
    if (res != NULL)
Packit 423ecb
	xmlFreeURI(res);
Packit 423ecb
    return(val);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlBuildRelativeURI:
Packit 423ecb
 * @URI:  the URI reference under consideration
Packit 423ecb
 * @base:  the base value
Packit 423ecb
 *
Packit 423ecb
 * Expresses the URI of the reference in terms relative to the
Packit 423ecb
 * base.  Some examples of this operation include:
Packit 423ecb
 *     base = "http://site1.com/docs/book1.html"
Packit 423ecb
 *        URI input                        URI returned
Packit 423ecb
 *     docs/pic1.gif                    pic1.gif
Packit 423ecb
 *     docs/img/pic1.gif                img/pic1.gif
Packit 423ecb
 *     img/pic1.gif                     ../img/pic1.gif
Packit 423ecb
 *     http://site1.com/docs/pic1.gif   pic1.gif
Packit 423ecb
 *     http://site2.com/docs/pic1.gif   http://site2.com/docs/pic1.gif
Packit 423ecb
 *
Packit 423ecb
 *     base = "docs/book1.html"
Packit 423ecb
 *        URI input                        URI returned
Packit 423ecb
 *     docs/pic1.gif                    pic1.gif
Packit 423ecb
 *     docs/img/pic1.gif                img/pic1.gif
Packit 423ecb
 *     img/pic1.gif                     ../img/pic1.gif
Packit 423ecb
 *     http://site1.com/docs/pic1.gif   http://site1.com/docs/pic1.gif
Packit 423ecb
 *
Packit 423ecb
 *
Packit 423ecb
 * Note: if the URI reference is really wierd or complicated, it may be
Packit 423ecb
 *       worthwhile to first convert it into a "nice" one by calling
Packit 423ecb
 *       xmlBuildURI (using 'base') before calling this routine,
Packit 423ecb
 *       since this routine (for reasonable efficiency) assumes URI has
Packit 423ecb
 *       already been through some validation.
Packit 423ecb
 *
Packit 423ecb
 * Returns a new URI string (to be freed by the caller) or NULL in case
Packit 423ecb
 * error.
Packit 423ecb
 */
Packit 423ecb
xmlChar *
Packit 423ecb
xmlBuildRelativeURI (const xmlChar * URI, const xmlChar * base)
Packit 423ecb
{
Packit 423ecb
    xmlChar *val = NULL;
Packit 423ecb
    int ret;
Packit 423ecb
    int ix;
Packit 423ecb
    int nbslash = 0;
Packit 423ecb
    int len;
Packit 423ecb
    xmlURIPtr ref = NULL;
Packit 423ecb
    xmlURIPtr bas = NULL;
Packit 423ecb
    xmlChar *bptr, *uptr, *vptr;
Packit 423ecb
    int remove_path = 0;
Packit 423ecb
Packit 423ecb
    if ((URI == NULL) || (*URI == 0))
Packit 423ecb
	return NULL;
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * First parse URI into a standard form
Packit 423ecb
     */
Packit 423ecb
    ref = xmlCreateURI ();
Packit 423ecb
    if (ref == NULL)
Packit 423ecb
	return NULL;
Packit 423ecb
    /* If URI not already in "relative" form */
Packit 423ecb
    if (URI[0] != '.') {
Packit 423ecb
	ret = xmlParseURIReference (ref, (const char *) URI);
Packit 423ecb
	if (ret != 0)
Packit 423ecb
	    goto done;		/* Error in URI, return NULL */
Packit 423ecb
    } else
Packit 423ecb
	ref->path = (char *)xmlStrdup(URI);
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * Next parse base into the same standard form
Packit 423ecb
     */
Packit 423ecb
    if ((base == NULL) || (*base == 0)) {
Packit 423ecb
	val = xmlStrdup (URI);
Packit 423ecb
	goto done;
Packit 423ecb
    }
Packit 423ecb
    bas = xmlCreateURI ();
Packit 423ecb
    if (bas == NULL)
Packit 423ecb
	goto done;
Packit 423ecb
    if (base[0] != '.') {
Packit 423ecb
	ret = xmlParseURIReference (bas, (const char *) base);
Packit 423ecb
	if (ret != 0)
Packit 423ecb
	    goto done;		/* Error in base, return NULL */
Packit 423ecb
    } else
Packit 423ecb
	bas->path = (char *)xmlStrdup(base);
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * If the scheme / server on the URI differs from the base,
Packit 423ecb
     * just return the URI
Packit 423ecb
     */
Packit 423ecb
    if ((ref->scheme != NULL) &&
Packit 423ecb
	((bas->scheme == NULL) ||
Packit 423ecb
	 (xmlStrcmp ((xmlChar *)bas->scheme, (xmlChar *)ref->scheme)) ||
Packit 423ecb
	 (xmlStrcmp ((xmlChar *)bas->server, (xmlChar *)ref->server)))) {
Packit 423ecb
	val = xmlStrdup (URI);
Packit 423ecb
	goto done;
Packit 423ecb
    }
Packit 423ecb
    if (xmlStrEqual((xmlChar *)bas->path, (xmlChar *)ref->path)) {
Packit 423ecb
	val = xmlStrdup(BAD_CAST "");
Packit 423ecb
	goto done;
Packit 423ecb
    }
Packit 423ecb
    if (bas->path == NULL) {
Packit 423ecb
	val = xmlStrdup((xmlChar *)ref->path);
Packit 423ecb
	goto done;
Packit 423ecb
    }
Packit 423ecb
    if (ref->path == NULL) {
Packit 423ecb
        ref->path = (char *) "/";
Packit 423ecb
	remove_path = 1;
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * At this point (at last!) we can compare the two paths
Packit 423ecb
     *
Packit 423ecb
     * First we take care of the special case where either of the
Packit 423ecb
     * two path components may be missing (bug 316224)
Packit 423ecb
     */
Packit 423ecb
    if (bas->path == NULL) {
Packit 423ecb
	if (ref->path != NULL) {
Packit 423ecb
	    uptr = (xmlChar *) ref->path;
Packit 423ecb
	    if (*uptr == '/')
Packit 423ecb
		uptr++;
Packit 423ecb
	    /* exception characters from xmlSaveUri */
Packit 423ecb
	    val = xmlURIEscapeStr(uptr, BAD_CAST "/;&=+$,");
Packit 423ecb
	}
Packit 423ecb
	goto done;
Packit 423ecb
    }
Packit 423ecb
    bptr = (xmlChar *)bas->path;
Packit 423ecb
    if (ref->path == NULL) {
Packit 423ecb
	for (ix = 0; bptr[ix] != 0; ix++) {
Packit 423ecb
	    if (bptr[ix] == '/')
Packit 423ecb
		nbslash++;
Packit 423ecb
	}
Packit 423ecb
	uptr = NULL;
Packit 423ecb
	len = 1;	/* this is for a string terminator only */
Packit 423ecb
    } else {
Packit 423ecb
        xmlChar *rptr = (xmlChar *) ref->path;
Packit 423ecb
        int pos = 0;
Packit 423ecb
Packit 423ecb
        /*
Packit 423ecb
         * Next we compare the two strings and find where they first differ
Packit 423ecb
         */
Packit 423ecb
	if ((*rptr == '.') && (rptr[1] == '/'))
Packit 423ecb
            rptr += 2;
Packit 423ecb
	if ((*bptr == '.') && (bptr[1] == '/'))
Packit 423ecb
            bptr += 2;
Packit 423ecb
	else if ((*bptr == '/') && (*rptr != '/'))
Packit 423ecb
	    bptr++;
Packit 423ecb
	while ((bptr[pos] == rptr[pos]) && (bptr[pos] != 0))
Packit 423ecb
	    pos++;
Packit 423ecb
Packit 423ecb
	if (bptr[pos] == rptr[pos]) {
Packit 423ecb
	    val = xmlStrdup(BAD_CAST "");
Packit 423ecb
	    goto done;		/* (I can't imagine why anyone would do this) */
Packit 423ecb
	}
Packit 423ecb
Packit 423ecb
	/*
Packit 423ecb
	 * In URI, "back up" to the last '/' encountered.  This will be the
Packit 423ecb
	 * beginning of the "unique" suffix of URI
Packit 423ecb
	 */
Packit 423ecb
	ix = pos;
Packit 423ecb
	if ((rptr[ix] == '/') && (ix > 0))
Packit 423ecb
	    ix--;
Packit 423ecb
	else if ((rptr[ix] == 0) && (ix > 1) && (rptr[ix - 1] == '/'))
Packit 423ecb
	    ix -= 2;
Packit 423ecb
	for (; ix > 0; ix--) {
Packit 423ecb
	    if (rptr[ix] == '/')
Packit 423ecb
		break;
Packit 423ecb
	}
Packit 423ecb
	if (ix == 0) {
Packit 423ecb
	    uptr = (xmlChar *)rptr;
Packit 423ecb
	} else {
Packit 423ecb
	    ix++;
Packit 423ecb
	    uptr = (xmlChar *)&rptr[ix];
Packit 423ecb
	}
Packit 423ecb
Packit 423ecb
	/*
Packit 423ecb
	 * In base, count the number of '/' from the differing point
Packit 423ecb
	 */
Packit 423ecb
	if (bptr[pos] != rptr[pos]) {/* check for trivial URI == base */
Packit 423ecb
	    for (; bptr[ix] != 0; ix++) {
Packit 423ecb
		if (bptr[ix] == '/')
Packit 423ecb
		    nbslash++;
Packit 423ecb
	    }
Packit 423ecb
	}
Packit 423ecb
	len = xmlStrlen (uptr) + 1;
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    if (nbslash == 0) {
Packit 423ecb
	if (uptr != NULL)
Packit 423ecb
	    /* exception characters from xmlSaveUri */
Packit 423ecb
	    val = xmlURIEscapeStr(uptr, BAD_CAST "/;&=+$,");
Packit 423ecb
	goto done;
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    /*
Packit 423ecb
     * Allocate just enough space for the returned string -
Packit 423ecb
     * length of the remainder of the URI, plus enough space
Packit 423ecb
     * for the "../" groups, plus one for the terminator
Packit 423ecb
     */
Packit 423ecb
    val = (xmlChar *) xmlMalloc (len + 3 * nbslash);
Packit 423ecb
    if (val == NULL) {
Packit 423ecb
        xmlURIErrMemory("building relative URI\n");
Packit 423ecb
	goto done;
Packit 423ecb
    }
Packit 423ecb
    vptr = val;
Packit 423ecb
    /*
Packit 423ecb
     * Put in as many "../" as needed
Packit 423ecb
     */
Packit 423ecb
    for (; nbslash>0; nbslash--) {
Packit 423ecb
	*vptr++ = '.';
Packit 423ecb
	*vptr++ = '.';
Packit 423ecb
	*vptr++ = '/';
Packit 423ecb
    }
Packit 423ecb
    /*
Packit 423ecb
     * Finish up with the end of the URI
Packit 423ecb
     */
Packit 423ecb
    if (uptr != NULL) {
Packit 423ecb
        if ((vptr > val) && (len > 0) &&
Packit 423ecb
	    (uptr[0] == '/') && (vptr[-1] == '/')) {
Packit 423ecb
	    memcpy (vptr, uptr + 1, len - 1);
Packit 423ecb
	    vptr[len - 2] = 0;
Packit 423ecb
	} else {
Packit 423ecb
	    memcpy (vptr, uptr, len);
Packit 423ecb
	    vptr[len - 1] = 0;
Packit 423ecb
	}
Packit 423ecb
    } else {
Packit 423ecb
	vptr[len - 1] = 0;
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    /* escape the freshly-built path */
Packit 423ecb
    vptr = val;
Packit 423ecb
	/* exception characters from xmlSaveUri */
Packit 423ecb
    val = xmlURIEscapeStr(vptr, BAD_CAST "/;&=+$,");
Packit 423ecb
    xmlFree(vptr);
Packit 423ecb
Packit 423ecb
done:
Packit 423ecb
    /*
Packit 423ecb
     * Free the working variables
Packit 423ecb
     */
Packit 423ecb
    if (remove_path != 0)
Packit 423ecb
        ref->path = NULL;
Packit 423ecb
    if (ref != NULL)
Packit 423ecb
	xmlFreeURI (ref);
Packit 423ecb
    if (bas != NULL)
Packit 423ecb
	xmlFreeURI (bas);
Packit 423ecb
Packit 423ecb
    return val;
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlCanonicPath:
Packit 423ecb
 * @path:  the resource locator in a filesystem notation
Packit 423ecb
 *
Packit 423ecb
 * Constructs a canonic path from the specified path.
Packit 423ecb
 *
Packit 423ecb
 * Returns a new canonic path, or a duplicate of the path parameter if the
Packit 423ecb
 * construction fails. The caller is responsible for freeing the memory occupied
Packit 423ecb
 * by the returned string. If there is insufficient memory available, or the
Packit 423ecb
 * argument is NULL, the function returns NULL.
Packit 423ecb
 */
Packit 423ecb
#define IS_WINDOWS_PATH(p)					\
Packit 423ecb
	((p != NULL) &&						\
Packit 423ecb
	 (((p[0] >= 'a') && (p[0] <= 'z')) ||			\
Packit 423ecb
	  ((p[0] >= 'A') && (p[0] <= 'Z'))) &&			\
Packit 423ecb
	 (p[1] == ':') && ((p[2] == '/') || (p[2] == '\\')))
Packit 423ecb
xmlChar *
Packit 423ecb
xmlCanonicPath(const xmlChar *path)
Packit 423ecb
{
Packit 423ecb
/*
Packit 423ecb
 * For Windows implementations, additional work needs to be done to
Packit 423ecb
 * replace backslashes in pathnames with "forward slashes"
Packit 423ecb
 */
Packit 423ecb
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit 423ecb
    int len = 0;
Packit 423ecb
    char *p = NULL;
Packit 423ecb
#endif
Packit 423ecb
    xmlURIPtr uri;
Packit 423ecb
    xmlChar *ret;
Packit 423ecb
    const xmlChar *absuri;
Packit 423ecb
Packit 423ecb
    if (path == NULL)
Packit 423ecb
	return(NULL);
Packit 423ecb
Packit 423ecb
#if defined(_WIN32)
Packit 423ecb
    /*
Packit 423ecb
     * We must not change the backslashes to slashes if the the path
Packit 423ecb
     * starts with \\?\
Packit 423ecb
     * Those paths can be up to 32k characters long.
Packit 423ecb
     * Was added specifically for OpenOffice, those paths can't be converted
Packit 423ecb
     * to URIs anyway.
Packit 423ecb
     */
Packit 423ecb
    if ((path[0] == '\\') && (path[1] == '\\') && (path[2] == '?') &&
Packit 423ecb
        (path[3] == '\\') )
Packit 423ecb
	return xmlStrdup((const xmlChar *) path);
Packit 423ecb
#endif
Packit 423ecb
Packit 423ecb
	/* sanitize filename starting with // so it can be used as URI */
Packit 423ecb
    if ((path[0] == '/') && (path[1] == '/') && (path[2] != '/'))
Packit 423ecb
        path++;
Packit 423ecb
Packit 423ecb
    if ((uri = xmlParseURI((const char *) path)) != NULL) {
Packit 423ecb
	xmlFreeURI(uri);
Packit 423ecb
	return xmlStrdup(path);
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    /* Check if this is an "absolute uri" */
Packit 423ecb
    absuri = xmlStrstr(path, BAD_CAST "://");
Packit 423ecb
    if (absuri != NULL) {
Packit 423ecb
        int l, j;
Packit 423ecb
	unsigned char c;
Packit 423ecb
	xmlChar *escURI;
Packit 423ecb
Packit 423ecb
        /*
Packit 423ecb
	 * this looks like an URI where some parts have not been
Packit 423ecb
	 * escaped leading to a parsing problem.  Check that the first
Packit 423ecb
	 * part matches a protocol.
Packit 423ecb
	 */
Packit 423ecb
	l = absuri - path;
Packit 423ecb
	/* Bypass if first part (part before the '://') is > 20 chars */
Packit 423ecb
	if ((l <= 0) || (l > 20))
Packit 423ecb
	    goto path_processing;
Packit 423ecb
	/* Bypass if any non-alpha characters are present in first part */
Packit 423ecb
	for (j = 0;j < l;j++) {
Packit 423ecb
	    c = path[j];
Packit 423ecb
	    if (!(((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))))
Packit 423ecb
	        goto path_processing;
Packit 423ecb
	}
Packit 423ecb
Packit 423ecb
	/* Escape all except the characters specified in the supplied path */
Packit 423ecb
        escURI = xmlURIEscapeStr(path, BAD_CAST ":/?_.#&;=");
Packit 423ecb
	if (escURI != NULL) {
Packit 423ecb
	    /* Try parsing the escaped path */
Packit 423ecb
	    uri = xmlParseURI((const char *) escURI);
Packit 423ecb
	    /* If successful, return the escaped string */
Packit 423ecb
	    if (uri != NULL) {
Packit 423ecb
	        xmlFreeURI(uri);
Packit 423ecb
		return escURI;
Packit 423ecb
	    }
Packit 423ecb
            xmlFree(escURI);
Packit 423ecb
	}
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
path_processing:
Packit 423ecb
/* For Windows implementations, replace backslashes with 'forward slashes' */
Packit 423ecb
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit 423ecb
    /*
Packit 423ecb
     * Create a URI structure
Packit 423ecb
     */
Packit 423ecb
    uri = xmlCreateURI();
Packit 423ecb
    if (uri == NULL) {		/* Guard against 'out of memory' */
Packit 423ecb
        return(NULL);
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    len = xmlStrlen(path);
Packit 423ecb
    if ((len > 2) && IS_WINDOWS_PATH(path)) {
Packit 423ecb
        /* make the scheme 'file' */
Packit 423ecb
	uri->scheme = (char *) xmlStrdup(BAD_CAST "file");
Packit 423ecb
	/* allocate space for leading '/' + path + string terminator */
Packit 423ecb
	uri->path = xmlMallocAtomic(len + 2);
Packit 423ecb
	if (uri->path == NULL) {
Packit 423ecb
	    xmlFreeURI(uri);	/* Guard agains 'out of memory' */
Packit 423ecb
	    return(NULL);
Packit 423ecb
	}
Packit 423ecb
	/* Put in leading '/' plus path */
Packit 423ecb
	uri->path[0] = '/';
Packit 423ecb
	p = uri->path + 1;
Packit 423ecb
	strncpy(p, (char *) path, len + 1);
Packit 423ecb
    } else {
Packit 423ecb
	uri->path = (char *) xmlStrdup(path);
Packit 423ecb
	if (uri->path == NULL) {
Packit 423ecb
	    xmlFreeURI(uri);
Packit 423ecb
	    return(NULL);
Packit 423ecb
	}
Packit 423ecb
	p = uri->path;
Packit 423ecb
    }
Packit 423ecb
    /* Now change all occurences of '\' to '/' */
Packit 423ecb
    while (*p != '\0') {
Packit 423ecb
	if (*p == '\\')
Packit 423ecb
	    *p = '/';
Packit 423ecb
	p++;
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    if (uri->scheme == NULL) {
Packit 423ecb
	ret = xmlStrdup((const xmlChar *) uri->path);
Packit 423ecb
    } else {
Packit 423ecb
	ret = xmlSaveUri(uri);
Packit 423ecb
    }
Packit 423ecb
Packit 423ecb
    xmlFreeURI(uri);
Packit 423ecb
#else
Packit 423ecb
    ret = xmlStrdup((const xmlChar *) path);
Packit 423ecb
#endif
Packit 423ecb
    return(ret);
Packit 423ecb
}
Packit 423ecb
Packit 423ecb
/**
Packit 423ecb
 * xmlPathToURI:
Packit 423ecb
 * @path:  the resource locator in a filesystem notation
Packit 423ecb
 *
Packit 423ecb
 * Constructs an URI expressing the existing path
Packit 423ecb
 *
Packit 423ecb
 * Returns a new URI, or a duplicate of the path parameter if the
Packit 423ecb
 * construction fails. The caller is responsible for freeing the memory
Packit 423ecb
 * occupied by the returned string. If there is insufficient memory available,
Packit 423ecb
 * or the argument is NULL, the function returns NULL.
Packit 423ecb
 */
Packit 423ecb
xmlChar *
Packit 423ecb
xmlPathToURI(const xmlChar *path)
Packit 423ecb
{
Packit 423ecb
    xmlURIPtr uri;
Packit 423ecb
    xmlURI temp;
Packit 423ecb
    xmlChar *ret, *cal;
Packit 423ecb
Packit 423ecb
    if (path == NULL)
Packit 423ecb
        return(NULL);
Packit 423ecb
Packit 423ecb
    if ((uri = xmlParseURI((const char *) path)) != NULL) {
Packit 423ecb
	xmlFreeURI(uri);
Packit 423ecb
	return xmlStrdup(path);
Packit 423ecb
    }
Packit 423ecb
    cal = xmlCanonicPath(path);
Packit 423ecb
    if (cal == NULL)
Packit 423ecb
        return(NULL);
Packit 423ecb
#if defined(_WIN32) && !defined(__CYGWIN__)
Packit 423ecb
    /* xmlCanonicPath can return an URI on Windows (is that the intended behaviour?)
Packit 423ecb
       If 'cal' is a valid URI allready then we are done here, as continuing would make
Packit 423ecb
       it invalid. */
Packit 423ecb
    if ((uri = xmlParseURI((const char *) cal)) != NULL) {
Packit 423ecb
	xmlFreeURI(uri);
Packit 423ecb
	return cal;
Packit 423ecb
    }
Packit 423ecb
    /* 'cal' can contain a relative path with backslashes. If that is processed
Packit 423ecb
       by xmlSaveURI, they will be escaped and the external entity loader machinery
Packit 423ecb
       will fail. So convert them to slashes. Misuse 'ret' for walking. */
Packit 423ecb
    ret = cal;
Packit 423ecb
    while (*ret != '\0') {
Packit 423ecb
	if (*ret == '\\')
Packit 423ecb
	    *ret = '/';
Packit 423ecb
	ret++;
Packit 423ecb
    }
Packit 423ecb
#endif
Packit 423ecb
    memset(&temp, 0, sizeof(temp));
Packit 423ecb
    temp.path = (char *) cal;
Packit 423ecb
    ret = xmlSaveUri(&temp);
Packit 423ecb
    xmlFree(cal);
Packit 423ecb
    return(ret);
Packit 423ecb
}
Packit 423ecb
#define bottom_uri
Packit 423ecb
#include "elfgcchack.h"