13473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/**
257560386503be0fd023f3b7537fd496784f3be18Daniel Veillard * uri.c: set of generic URI related routines
33473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
4d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Reference: RFCs 3986, 2732 and 2373
53473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
63473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor * See Copyright for the status of this software.
73473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
8c5d64345cf19bfd72418eb0a837869b0462e9130Daniel Veillard * daniel@veillard.com
93473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
103473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1134ce8bece2f22cc99d25221b77315cd008f4866bDaniel Veillard#define IN_LIBXML
1270a9da54eb200cd5c5ceafb72aff72c39021c94cBjorn Reese#include "libxml.h"
1370a9da54eb200cd5c5ceafb72aff72c39021c94cBjorn Reese
143473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor#include <string.h>
1522e01bd4c5bc675bd3313404abb570a865917859Brian C. Young#include <limits.h>
163473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
173473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor#include <libxml/xmlmemory.h>
183473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor#include <libxml/uri.h>
19d0463560300f1d8b3e41d70c3728ed84fdc8dd30Daniel Veillard#include <libxml/globals.h>
203473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor#include <libxml/xmlerror.h>
213473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
2257560386503be0fd023f3b7537fd496784f3be18Daniel Veillard/**
2357560386503be0fd023f3b7537fd496784f3be18Daniel Veillard * MAX_URI_LENGTH:
2457560386503be0fd023f3b7537fd496784f3be18Daniel Veillard *
2557560386503be0fd023f3b7537fd496784f3be18Daniel Veillard * The definition of the URI regexp in the above RFC has no size limit
2657560386503be0fd023f3b7537fd496784f3be18Daniel Veillard * In practice they are usually relativey short except for the
2757560386503be0fd023f3b7537fd496784f3be18Daniel Veillard * data URI scheme as defined in RFC 2397. Even for data URI the usual
2857560386503be0fd023f3b7537fd496784f3be18Daniel Veillard * maximum size before hitting random practical limits is around 64 KB
2957560386503be0fd023f3b7537fd496784f3be18Daniel Veillard * and 4KB is usually a maximum admitted limit for proper operations.
3057560386503be0fd023f3b7537fd496784f3be18Daniel Veillard * The value below is more a security limit than anything else and
3157560386503be0fd023f3b7537fd496784f3be18Daniel Veillard * really should never be hit by 'normal' operations
3257560386503be0fd023f3b7537fd496784f3be18Daniel Veillard * Set to 1 MByte in 2012, this is only enforced on output
3357560386503be0fd023f3b7537fd496784f3be18Daniel Veillard */
3457560386503be0fd023f3b7537fd496784f3be18Daniel Veillard#define MAX_URI_LENGTH 1024 * 1024
3557560386503be0fd023f3b7537fd496784f3be18Daniel Veillard
3657560386503be0fd023f3b7537fd496784f3be18Daniel Veillardstatic void
3757560386503be0fd023f3b7537fd496784f3be18Daniel VeillardxmlURIErrMemory(const char *extra)
3857560386503be0fd023f3b7537fd496784f3be18Daniel Veillard{
3957560386503be0fd023f3b7537fd496784f3be18Daniel Veillard    if (extra)
4057560386503be0fd023f3b7537fd496784f3be18Daniel Veillard        __xmlRaiseError(NULL, NULL, NULL,
4157560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                        NULL, NULL, XML_FROM_URI,
4257560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                        XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
4357560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                        extra, NULL, NULL, 0, 0,
4457560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                        "Memory allocation failed : %s\n", extra);
4557560386503be0fd023f3b7537fd496784f3be18Daniel Veillard    else
4657560386503be0fd023f3b7537fd496784f3be18Daniel Veillard        __xmlRaiseError(NULL, NULL, NULL,
4757560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                        NULL, NULL, XML_FROM_URI,
4857560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                        XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
4957560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                        NULL, NULL, NULL, 0, 0,
5057560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                        "Memory allocation failed\n");
5157560386503be0fd023f3b7537fd496784f3be18Daniel Veillard}
5257560386503be0fd023f3b7537fd496784f3be18Daniel Veillard
53d7af555327843a9938a913205ac703c13c225603Daniel Veillardstatic void xmlCleanURI(xmlURIPtr uri);
543473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
553473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/*
56d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Old rule from 2396 used in legacy handling code
573473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor * alpha    = lowalpha | upalpha
583473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
593473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor#define IS_ALPHA(x) (IS_LOWALPHA(x) || IS_UPALPHA(x))
603473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
613473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
623473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/*
633473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor * lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" |
643473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *            "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" |
653473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *            "u" | "v" | "w" | "x" | "y" | "z"
663473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
673473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
683473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor#define IS_LOWALPHA(x) (((x) >= 'a') && ((x) <= 'z'))
693473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
703473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/*
713473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor * upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" |
723473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *           "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" |
733473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *           "U" | "V" | "W" | "X" | "Y" | "Z"
743473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
753473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor#define IS_UPALPHA(x) (((x) >= 'A') && ((x) <= 'Z'))
763473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
77be3eb2088e3e27b897b57855382f80a737f974ceDaniel Veillard#ifdef IS_DIGIT
78be3eb2088e3e27b897b57855382f80a737f974ceDaniel Veillard#undef IS_DIGIT
79be3eb2088e3e27b897b57855382f80a737f974ceDaniel Veillard#endif
803473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/*
813473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
823473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
833473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor#define IS_DIGIT(x) (((x) >= '0') && ((x) <= '9'))
843473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
853473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/*
863473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor * alphanum = alpha | digit
873473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
883473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
893473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor#define IS_ALPHANUM(x) (IS_ALPHA(x) || IS_DIGIT(x))
903473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
913473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/*
923473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
933473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
943473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
95d7af555327843a9938a913205ac703c13c225603Daniel Veillard#define IS_MARK(x) (((x) == '-') || ((x) == '_') || ((x) == '.') ||     \
96d7af555327843a9938a913205ac703c13c225603Daniel Veillard    ((x) == '!') || ((x) == '~') || ((x) == '*') || ((x) == '\'') ||    \
973473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    ((x) == '(') || ((x) == ')'))
983473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
99d7af555327843a9938a913205ac703c13c225603Daniel Veillard/*
100d7af555327843a9938a913205ac703c13c225603Daniel Veillard * unwise = "{" | "}" | "|" | "\" | "^" | "`"
101d7af555327843a9938a913205ac703c13c225603Daniel Veillard */
1023473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
103d7af555327843a9938a913205ac703c13c225603Daniel Veillard#define IS_UNWISE(p)                                                    \
104d7af555327843a9938a913205ac703c13c225603Daniel Veillard      (((*(p) == '{')) || ((*(p) == '}')) || ((*(p) == '|')) ||         \
105d7af555327843a9938a913205ac703c13c225603Daniel Veillard       ((*(p) == '\\')) || ((*(p) == '^')) || ((*(p) == '[')) ||        \
106d7af555327843a9938a913205ac703c13c225603Daniel Veillard       ((*(p) == ']')) || ((*(p) == '`')))
1073473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/*
108015ccb2c747fb73561e2fe72d6214585dd9985e8William M. Brack * reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," |
109d7af555327843a9938a913205ac703c13c225603Daniel Veillard *            "[" | "]"
1103473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
1113473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
112d7af555327843a9938a913205ac703c13c225603Daniel Veillard#define IS_RESERVED(x) (((x) == ';') || ((x) == '/') || ((x) == '?') || \
113d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ((x) == ':') || ((x) == '@') || ((x) == '&') || ((x) == '=') || \
114d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ((x) == '+') || ((x) == '$') || ((x) == ',') || ((x) == '[') || \
115d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ((x) == ']'))
1163473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1173473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/*
1183473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor * unreserved = alphanum | mark
1193473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
1203473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1213473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor#define IS_UNRESERVED(x) (IS_ALPHANUM(x) || IS_MARK(x))
1223473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1233473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/*
124d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Skip to next pointer char, handle escaped sequences
1253473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
1263473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
127d7af555327843a9938a913205ac703c13c225603Daniel Veillard#define NEXT(p) ((*p == '%')? p += 3 : p++)
1283473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1293473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/*
130d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Productions from the spec.
131d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
132d7af555327843a9938a913205ac703c13c225603Daniel Veillard *    authority     = server | reg_name
133d7af555327843a9938a913205ac703c13c225603Daniel Veillard *    reg_name      = 1*( unreserved | escaped | "$" | "," |
134d7af555327843a9938a913205ac703c13c225603Daniel Veillard *                        ";" | ":" | "@" | "&" | "=" | "+" )
135d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
136d7af555327843a9938a913205ac703c13c225603Daniel Veillard * path          = [ abs_path | opaque_part ]
1373473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
138d7af555327843a9938a913205ac703c13c225603Daniel Veillard
139d7af555327843a9938a913205ac703c13c225603Daniel Veillard#define STRNDUP(s, n) (char *) xmlStrndup((const xmlChar *)(s), (n))
140d7af555327843a9938a913205ac703c13c225603Daniel Veillard
141d7af555327843a9938a913205ac703c13c225603Daniel Veillard/************************************************************************
142d7af555327843a9938a913205ac703c13c225603Daniel Veillard *									*
143d7af555327843a9938a913205ac703c13c225603Daniel Veillard *                         RFC 3986 parser				*
144d7af555327843a9938a913205ac703c13c225603Daniel Veillard *									*
145d7af555327843a9938a913205ac703c13c225603Daniel Veillard ************************************************************************/
146d7af555327843a9938a913205ac703c13c225603Daniel Veillard
147d7af555327843a9938a913205ac703c13c225603Daniel Veillard#define ISA_DIGIT(p) ((*(p) >= '0') && (*(p) <= '9'))
148d7af555327843a9938a913205ac703c13c225603Daniel Veillard#define ISA_ALPHA(p) (((*(p) >= 'a') && (*(p) <= 'z')) ||		\
149d7af555327843a9938a913205ac703c13c225603Daniel Veillard                      ((*(p) >= 'A') && (*(p) <= 'Z')))
150d7af555327843a9938a913205ac703c13c225603Daniel Veillard#define ISA_HEXDIG(p)							\
151d7af555327843a9938a913205ac703c13c225603Daniel Veillard       (ISA_DIGIT(p) || ((*(p) >= 'a') && (*(p) <= 'f')) ||		\
152d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ((*(p) >= 'A') && (*(p) <= 'F')))
1533473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1543473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/*
155d7af555327843a9938a913205ac703c13c225603Daniel Veillard *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
156d7af555327843a9938a913205ac703c13c225603Daniel Veillard *                     / "*" / "+" / "," / ";" / "="
1573473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
158d7af555327843a9938a913205ac703c13c225603Daniel Veillard#define ISA_SUB_DELIM(p)						\
159d7af555327843a9938a913205ac703c13c225603Daniel Veillard      (((*(p) == '!')) || ((*(p) == '$')) || ((*(p) == '&')) ||		\
160d7af555327843a9938a913205ac703c13c225603Daniel Veillard       ((*(p) == '(')) || ((*(p) == ')')) || ((*(p) == '*')) ||		\
161d7af555327843a9938a913205ac703c13c225603Daniel Veillard       ((*(p) == '+')) || ((*(p) == ',')) || ((*(p) == ';')) ||		\
1622ee91eb6587191de876dbcf147d99bc9b8c7799dDaniel Veillard       ((*(p) == '=')) || ((*(p) == '\'')))
1633473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1643473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/*
165d7af555327843a9938a913205ac703c13c225603Daniel Veillard *    gen-delims    = ":" / "/" / "?" / "#" / "[" / "]" / "@"
1663473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
167d7af555327843a9938a913205ac703c13c225603Daniel Veillard#define ISA_GEN_DELIM(p)						\
168d7af555327843a9938a913205ac703c13c225603Daniel Veillard      (((*(p) == ':')) || ((*(p) == '/')) || ((*(p) == '?')) ||         \
169d7af555327843a9938a913205ac703c13c225603Daniel Veillard       ((*(p) == '#')) || ((*(p) == '[')) || ((*(p) == ']')) ||         \
170d7af555327843a9938a913205ac703c13c225603Daniel Veillard       ((*(p) == '@')))
1713473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1723473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/*
173d7af555327843a9938a913205ac703c13c225603Daniel Veillard *    reserved      = gen-delims / sub-delims
1743473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
175d7af555327843a9938a913205ac703c13c225603Daniel Veillard#define ISA_RESERVED(p) (ISA_GEN_DELIM(p) || (ISA_SUB_DELIM(p)))
1763473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1773473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/*
178d7af555327843a9938a913205ac703c13c225603Daniel Veillard *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1793473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
180d7af555327843a9938a913205ac703c13c225603Daniel Veillard#define ISA_UNRESERVED(p)						\
181d7af555327843a9938a913205ac703c13c225603Daniel Veillard      ((ISA_ALPHA(p)) || (ISA_DIGIT(p)) || ((*(p) == '-')) ||		\
182d7af555327843a9938a913205ac703c13c225603Daniel Veillard       ((*(p) == '.')) || ((*(p) == '_')) || ((*(p) == '~')))
1833473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1843473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/*
185d7af555327843a9938a913205ac703c13c225603Daniel Veillard *    pct-encoded   = "%" HEXDIG HEXDIG
1863473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
187d7af555327843a9938a913205ac703c13c225603Daniel Veillard#define ISA_PCT_ENCODED(p)						\
188d7af555327843a9938a913205ac703c13c225603Daniel Veillard     ((*(p) == '%') && (ISA_HEXDIG(p + 1)) && (ISA_HEXDIG(p + 2)))
1893473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1903473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/*
191d7af555327843a9938a913205ac703c13c225603Daniel Veillard *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1923473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
193d7af555327843a9938a913205ac703c13c225603Daniel Veillard#define ISA_PCHAR(p)							\
194d7af555327843a9938a913205ac703c13c225603Daniel Veillard     (ISA_UNRESERVED(p) || ISA_PCT_ENCODED(p) || ISA_SUB_DELIM(p) ||	\
195d7af555327843a9938a913205ac703c13c225603Daniel Veillard      ((*(p) == ':')) || ((*(p) == '@')))
1963473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
197d7af555327843a9938a913205ac703c13c225603Daniel Veillard/**
198d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlParse3986Scheme:
199d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @uri:  pointer to an URI structure
200d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  pointer to the string to analyze
201d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
202d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Parse an URI scheme
203d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
204d7af555327843a9938a913205ac703c13c225603Daniel Veillard * ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
205d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
206d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns 0 or the error code
207d7af555327843a9938a913205ac703c13c225603Daniel Veillard */
208d7af555327843a9938a913205ac703c13c225603Daniel Veillardstatic int
209d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlParse3986Scheme(xmlURIPtr uri, const char **str) {
210d7af555327843a9938a913205ac703c13c225603Daniel Veillard    const char *cur;
2113473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
212d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (str == NULL)
213d7af555327843a9938a913205ac703c13c225603Daniel Veillard	return(-1);
214bb6808ea16b16055727ceb73d45a7f748b14ccfdDaniel Veillard
215d7af555327843a9938a913205ac703c13c225603Daniel Veillard    cur = *str;
216d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (!ISA_ALPHA(cur))
217d7af555327843a9938a913205ac703c13c225603Daniel Veillard	return(2);
218d7af555327843a9938a913205ac703c13c225603Daniel Veillard    cur++;
219d7af555327843a9938a913205ac703c13c225603Daniel Veillard    while (ISA_ALPHA(cur) || ISA_DIGIT(cur) ||
220d7af555327843a9938a913205ac703c13c225603Daniel Veillard           (*cur == '+') || (*cur == '-') || (*cur == '.')) cur++;
221d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri != NULL) {
222d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (uri->scheme != NULL) xmlFree(uri->scheme);
223d7af555327843a9938a913205ac703c13c225603Daniel Veillard	uri->scheme = STRNDUP(*str, cur - *str);
224d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
225d7af555327843a9938a913205ac703c13c225603Daniel Veillard    *str = cur;
226d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return(0);
227d7af555327843a9938a913205ac703c13c225603Daniel Veillard}
228bb6808ea16b16055727ceb73d45a7f748b14ccfdDaniel Veillard
229d7af555327843a9938a913205ac703c13c225603Daniel Veillard/**
230d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlParse3986Fragment:
231d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @uri:  pointer to an URI structure
232d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  pointer to the string to analyze
233d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
234d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Parse the query part of an URI
235d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
23684c45df8d88f2b44f9c16474795fa2d30265bc21Daniel Veillard * fragment      = *( pchar / "/" / "?" )
23784c45df8d88f2b44f9c16474795fa2d30265bc21Daniel Veillard * NOTE: the strict syntax as defined by 3986 does not allow '[' and ']'
23884c45df8d88f2b44f9c16474795fa2d30265bc21Daniel Veillard *       in the fragment identifier but this is used very broadly for
23984c45df8d88f2b44f9c16474795fa2d30265bc21Daniel Veillard *       xpointer scheme selection, so we are allowing it here to not break
24084c45df8d88f2b44f9c16474795fa2d30265bc21Daniel Veillard *       for example all the DocBook processing chains.
241d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
242d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns 0 or the error code
2433473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
244d7af555327843a9938a913205ac703c13c225603Daniel Veillardstatic int
245d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlParse3986Fragment(xmlURIPtr uri, const char **str)
246d7af555327843a9938a913205ac703c13c225603Daniel Veillard{
247d7af555327843a9938a913205ac703c13c225603Daniel Veillard    const char *cur;
2483473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
249d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (str == NULL)
250d7af555327843a9938a913205ac703c13c225603Daniel Veillard        return (-1);
2513473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
252d7af555327843a9938a913205ac703c13c225603Daniel Veillard    cur = *str;
253d7af555327843a9938a913205ac703c13c225603Daniel Veillard
254d7af555327843a9938a913205ac703c13c225603Daniel Veillard    while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') ||
25584c45df8d88f2b44f9c16474795fa2d30265bc21Daniel Veillard           (*cur == '[') || (*cur == ']') ||
256d7af555327843a9938a913205ac703c13c225603Daniel Veillard           ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
257d7af555327843a9938a913205ac703c13c225603Daniel Veillard        NEXT(cur);
258d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri != NULL) {
259d7af555327843a9938a913205ac703c13c225603Daniel Veillard        if (uri->fragment != NULL)
260d7af555327843a9938a913205ac703c13c225603Daniel Veillard            xmlFree(uri->fragment);
261d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (uri->cleanup & 2)
262d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    uri->fragment = STRNDUP(*str, cur - *str);
263d7af555327843a9938a913205ac703c13c225603Daniel Veillard	else
264d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    uri->fragment = xmlURIUnescapeString(*str, cur - *str, NULL);
265d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
266d7af555327843a9938a913205ac703c13c225603Daniel Veillard    *str = cur;
267d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return (0);
268d7af555327843a9938a913205ac703c13c225603Daniel Veillard}
269d7af555327843a9938a913205ac703c13c225603Daniel Veillard
270d7af555327843a9938a913205ac703c13c225603Daniel Veillard/**
271d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlParse3986Query:
272d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @uri:  pointer to an URI structure
273d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  pointer to the string to analyze
2743473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
275d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Parse the query part of an URI
2763473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
277d7af555327843a9938a913205ac703c13c225603Daniel Veillard * query = *uric
278d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
279d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns 0 or the error code
2803473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
281d7af555327843a9938a913205ac703c13c225603Daniel Veillardstatic int
282d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlParse3986Query(xmlURIPtr uri, const char **str)
283d7af555327843a9938a913205ac703c13c225603Daniel Veillard{
284d7af555327843a9938a913205ac703c13c225603Daniel Veillard    const char *cur;
2853473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
286d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (str == NULL)
287d7af555327843a9938a913205ac703c13c225603Daniel Veillard        return (-1);
288336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard
289d7af555327843a9938a913205ac703c13c225603Daniel Veillard    cur = *str;
290d7af555327843a9938a913205ac703c13c225603Daniel Veillard
291d7af555327843a9938a913205ac703c13c225603Daniel Veillard    while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') ||
292d7af555327843a9938a913205ac703c13c225603Daniel Veillard           ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
293d7af555327843a9938a913205ac703c13c225603Daniel Veillard        NEXT(cur);
294d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri != NULL) {
295d7af555327843a9938a913205ac703c13c225603Daniel Veillard        if (uri->query != NULL)
296d7af555327843a9938a913205ac703c13c225603Daniel Veillard            xmlFree(uri->query);
297d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (uri->cleanup & 2)
298d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    uri->query = STRNDUP(*str, cur - *str);
299d7af555327843a9938a913205ac703c13c225603Daniel Veillard	else
300d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    uri->query = xmlURIUnescapeString(*str, cur - *str, NULL);
301d7af555327843a9938a913205ac703c13c225603Daniel Veillard
302d7af555327843a9938a913205ac703c13c225603Daniel Veillard	/* Save the raw bytes of the query as well.
303d7af555327843a9938a913205ac703c13c225603Daniel Veillard	 * See: http://mail.gnome.org/archives/xml/2007-April/thread.html#00114
304d7af555327843a9938a913205ac703c13c225603Daniel Veillard	 */
305d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (uri->query_raw != NULL)
306d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    xmlFree (uri->query_raw);
307d7af555327843a9938a913205ac703c13c225603Daniel Veillard	uri->query_raw = STRNDUP (*str, cur - *str);
308d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
309d7af555327843a9938a913205ac703c13c225603Daniel Veillard    *str = cur;
310d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return (0);
311d7af555327843a9938a913205ac703c13c225603Daniel Veillard}
3123473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
3133473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/**
314d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlParse3986Port:
315d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @uri:  pointer to an URI structure
316d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  the string to analyze
3173473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
318846cf015a77b9bca7b90c17c1f608ece3e268dadMichael Paddon * Parse a port part and fills in the appropriate fields
319d7af555327843a9938a913205ac703c13c225603Daniel Veillard * of the @uri structure
3203473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
321d7af555327843a9938a913205ac703c13c225603Daniel Veillard * port          = *DIGIT
322d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
323d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns 0 or the error code
3243473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
325d7af555327843a9938a913205ac703c13c225603Daniel Veillardstatic int
326d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlParse3986Port(xmlURIPtr uri, const char **str)
327d7af555327843a9938a913205ac703c13c225603Daniel Veillard{
328d7af555327843a9938a913205ac703c13c225603Daniel Veillard    const char *cur = *str;
329846cf015a77b9bca7b90c17c1f608ece3e268dadMichael Paddon    unsigned port = 0; /* unsigned for defined overflow behavior */
3303473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
331d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (ISA_DIGIT(cur)) {
332d7af555327843a9938a913205ac703c13c225603Daniel Veillard	while (ISA_DIGIT(cur)) {
333846cf015a77b9bca7b90c17c1f608ece3e268dadMichael Paddon	    port = port * 10 + (*cur - '0');
334846cf015a77b9bca7b90c17c1f608ece3e268dadMichael Paddon
335d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    cur++;
336d7af555327843a9938a913205ac703c13c225603Daniel Veillard	}
337846cf015a77b9bca7b90c17c1f608ece3e268dadMichael Paddon	if (uri != NULL)
33822e01bd4c5bc675bd3313404abb570a865917859Brian C. Young	    uri->port = port & USHRT_MAX; /* port value modulo INT_MAX+1 */
339d7af555327843a9938a913205ac703c13c225603Daniel Veillard	*str = cur;
340d7af555327843a9938a913205ac703c13c225603Daniel Veillard	return(0);
3413473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
342d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return(1);
3433473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor}
3443473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
3453473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/**
346d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlParse3986Userinfo:
347d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @uri:  pointer to an URI structure
348d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  the string to analyze
3493473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
350d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Parse an user informations part and fills in the appropriate fields
351d7af555327843a9938a913205ac703c13c225603Daniel Veillard * of the @uri structure
3523473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
353d7af555327843a9938a913205ac703c13c225603Daniel Veillard * userinfo      = *( unreserved / pct-encoded / sub-delims / ":" )
354d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
355d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns 0 or the error code
3563473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
357d7af555327843a9938a913205ac703c13c225603Daniel Veillardstatic int
358d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlParse3986Userinfo(xmlURIPtr uri, const char **str)
359d7af555327843a9938a913205ac703c13c225603Daniel Veillard{
360d7af555327843a9938a913205ac703c13c225603Daniel Veillard    const char *cur;
3613473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
362d7af555327843a9938a913205ac703c13c225603Daniel Veillard    cur = *str;
363d7af555327843a9938a913205ac703c13c225603Daniel Veillard    while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) ||
364d7af555327843a9938a913205ac703c13c225603Daniel Veillard           ISA_SUB_DELIM(cur) || (*cur == ':'))
365d7af555327843a9938a913205ac703c13c225603Daniel Veillard	NEXT(cur);
366d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (*cur == '@') {
367d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (uri != NULL) {
368d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    if (uri->user != NULL) xmlFree(uri->user);
369d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    if (uri->cleanup & 2)
370d7af555327843a9938a913205ac703c13c225603Daniel Veillard		uri->user = STRNDUP(*str, cur - *str);
371d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    else
372d7af555327843a9938a913205ac703c13c225603Daniel Veillard		uri->user = xmlURIUnescapeString(*str, cur - *str, NULL);
373d7af555327843a9938a913205ac703c13c225603Daniel Veillard	}
374d7af555327843a9938a913205ac703c13c225603Daniel Veillard	*str = cur;
375d7af555327843a9938a913205ac703c13c225603Daniel Veillard	return(0);
376d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
377d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return(1);
378d7af555327843a9938a913205ac703c13c225603Daniel Veillard}
3793473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
380d7af555327843a9938a913205ac703c13c225603Daniel Veillard/**
381d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlParse3986DecOctet:
382d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  the string to analyze
383d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
384d7af555327843a9938a913205ac703c13c225603Daniel Veillard *    dec-octet     = DIGIT                 ; 0-9
385d7af555327843a9938a913205ac703c13c225603Daniel Veillard *                  / %x31-39 DIGIT         ; 10-99
386d7af555327843a9938a913205ac703c13c225603Daniel Veillard *                  / "1" 2DIGIT            ; 100-199
387d7af555327843a9938a913205ac703c13c225603Daniel Veillard *                  / "2" %x30-34 DIGIT     ; 200-249
388d7af555327843a9938a913205ac703c13c225603Daniel Veillard *                  / "25" %x30-35          ; 250-255
389d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
390d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Skip a dec-octet.
391d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
392d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns 0 if found and skipped, 1 otherwise
393d7af555327843a9938a913205ac703c13c225603Daniel Veillard */
394d7af555327843a9938a913205ac703c13c225603Daniel Veillardstatic int
395d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlParse3986DecOctet(const char **str) {
396d7af555327843a9938a913205ac703c13c225603Daniel Veillard    const char *cur = *str;
3973473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
398d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (!(ISA_DIGIT(cur)))
399d7af555327843a9938a913205ac703c13c225603Daniel Veillard        return(1);
400d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (!ISA_DIGIT(cur+1))
401d7af555327843a9938a913205ac703c13c225603Daniel Veillard	cur++;
402d7af555327843a9938a913205ac703c13c225603Daniel Veillard    else if ((*cur != '0') && (ISA_DIGIT(cur + 1)) && (!ISA_DIGIT(cur+2)))
403d7af555327843a9938a913205ac703c13c225603Daniel Veillard	cur += 2;
404d7af555327843a9938a913205ac703c13c225603Daniel Veillard    else if ((*cur == '1') && (ISA_DIGIT(cur + 1)) && (ISA_DIGIT(cur + 2)))
405d7af555327843a9938a913205ac703c13c225603Daniel Veillard	cur += 3;
406d7af555327843a9938a913205ac703c13c225603Daniel Veillard    else if ((*cur == '2') && (*(cur + 1) >= '0') &&
407d7af555327843a9938a913205ac703c13c225603Daniel Veillard	     (*(cur + 1) <= '4') && (ISA_DIGIT(cur + 2)))
408d7af555327843a9938a913205ac703c13c225603Daniel Veillard	cur += 3;
409d7af555327843a9938a913205ac703c13c225603Daniel Veillard    else if ((*cur == '2') && (*(cur + 1) == '5') &&
410d7af555327843a9938a913205ac703c13c225603Daniel Veillard	     (*(cur + 2) >= '0') && (*(cur + 1) <= '5'))
411d7af555327843a9938a913205ac703c13c225603Daniel Veillard	cur += 3;
412d7af555327843a9938a913205ac703c13c225603Daniel Veillard    else
413d7af555327843a9938a913205ac703c13c225603Daniel Veillard        return(1);
414d7af555327843a9938a913205ac703c13c225603Daniel Veillard    *str = cur;
415d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return(0);
416d7af555327843a9938a913205ac703c13c225603Daniel Veillard}
417d7af555327843a9938a913205ac703c13c225603Daniel Veillard/**
418d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlParse3986Host:
419d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @uri:  pointer to an URI structure
420d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  the string to analyze
421d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
422d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Parse an host part and fills in the appropriate fields
423d7af555327843a9938a913205ac703c13c225603Daniel Veillard * of the @uri structure
424d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
425d7af555327843a9938a913205ac703c13c225603Daniel Veillard * host          = IP-literal / IPv4address / reg-name
426d7af555327843a9938a913205ac703c13c225603Daniel Veillard * IP-literal    = "[" ( IPv6address / IPvFuture  ) "]"
427d7af555327843a9938a913205ac703c13c225603Daniel Veillard * IPv4address   = dec-octet "." dec-octet "." dec-octet "." dec-octet
428d7af555327843a9938a913205ac703c13c225603Daniel Veillard * reg-name      = *( unreserved / pct-encoded / sub-delims )
429d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
430d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns 0 or the error code
431d7af555327843a9938a913205ac703c13c225603Daniel Veillard */
432d7af555327843a9938a913205ac703c13c225603Daniel Veillardstatic int
433d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlParse3986Host(xmlURIPtr uri, const char **str)
434d7af555327843a9938a913205ac703c13c225603Daniel Veillard{
435d7af555327843a9938a913205ac703c13c225603Daniel Veillard    const char *cur = *str;
436d7af555327843a9938a913205ac703c13c225603Daniel Veillard    const char *host;
4373473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
438d7af555327843a9938a913205ac703c13c225603Daniel Veillard    host = cur;
439d7af555327843a9938a913205ac703c13c225603Daniel Veillard    /*
440d7af555327843a9938a913205ac703c13c225603Daniel Veillard     * IPv6 and future adressing scheme are enclosed between brackets
441d7af555327843a9938a913205ac703c13c225603Daniel Veillard     */
442d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (*cur == '[') {
443d7af555327843a9938a913205ac703c13c225603Daniel Veillard        cur++;
444d7af555327843a9938a913205ac703c13c225603Daniel Veillard	while ((*cur != ']') && (*cur != 0))
445d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    cur++;
446d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (*cur != ']')
447d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    return(1);
448d7af555327843a9938a913205ac703c13c225603Daniel Veillard	cur++;
449d7af555327843a9938a913205ac703c13c225603Daniel Veillard	goto found;
4503473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
451d7af555327843a9938a913205ac703c13c225603Daniel Veillard    /*
452d7af555327843a9938a913205ac703c13c225603Daniel Veillard     * try to parse an IPv4
453d7af555327843a9938a913205ac703c13c225603Daniel Veillard     */
454d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (ISA_DIGIT(cur)) {
455d7af555327843a9938a913205ac703c13c225603Daniel Veillard        if (xmlParse3986DecOctet(&cur) != 0)
456d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    goto not_ipv4;
457d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (*cur != '.')
458d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    goto not_ipv4;
459d7af555327843a9938a913205ac703c13c225603Daniel Veillard	cur++;
460d7af555327843a9938a913205ac703c13c225603Daniel Veillard        if (xmlParse3986DecOctet(&cur) != 0)
461d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    goto not_ipv4;
462d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (*cur != '.')
463d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    goto not_ipv4;
464d7af555327843a9938a913205ac703c13c225603Daniel Veillard        if (xmlParse3986DecOctet(&cur) != 0)
465d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    goto not_ipv4;
466d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (*cur != '.')
467d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    goto not_ipv4;
468d7af555327843a9938a913205ac703c13c225603Daniel Veillard        if (xmlParse3986DecOctet(&cur) != 0)
469d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    goto not_ipv4;
470d7af555327843a9938a913205ac703c13c225603Daniel Veillard	goto found;
471d7af555327843a9938a913205ac703c13c225603Daniel Veillardnot_ipv4:
472d7af555327843a9938a913205ac703c13c225603Daniel Veillard        cur = *str;
473d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
474d7af555327843a9938a913205ac703c13c225603Daniel Veillard    /*
475d7af555327843a9938a913205ac703c13c225603Daniel Veillard     * then this should be a hostname which can be empty
476d7af555327843a9938a913205ac703c13c225603Daniel Veillard     */
477d7af555327843a9938a913205ac703c13c225603Daniel Veillard    while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur))
478d7af555327843a9938a913205ac703c13c225603Daniel Veillard        NEXT(cur);
479d7af555327843a9938a913205ac703c13c225603Daniel Veillardfound:
480d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri != NULL) {
481d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (uri->authority != NULL) xmlFree(uri->authority);
482d7af555327843a9938a913205ac703c13c225603Daniel Veillard	uri->authority = NULL;
483d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (uri->server != NULL) xmlFree(uri->server);
484d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (cur != host) {
485d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    if (uri->cleanup & 2)
486d7af555327843a9938a913205ac703c13c225603Daniel Veillard		uri->server = STRNDUP(host, cur - host);
487d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    else
488d7af555327843a9938a913205ac703c13c225603Daniel Veillard		uri->server = xmlURIUnescapeString(host, cur - host, NULL);
489d7af555327843a9938a913205ac703c13c225603Daniel Veillard	} else
490d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    uri->server = NULL;
491d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
492d7af555327843a9938a913205ac703c13c225603Daniel Veillard    *str = cur;
493d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return(0);
494d7af555327843a9938a913205ac703c13c225603Daniel Veillard}
495d7af555327843a9938a913205ac703c13c225603Daniel Veillard
496d7af555327843a9938a913205ac703c13c225603Daniel Veillard/**
497d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlParse3986Authority:
498d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @uri:  pointer to an URI structure
499d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  the string to analyze
500d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
501d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Parse an authority part and fills in the appropriate fields
502d7af555327843a9938a913205ac703c13c225603Daniel Veillard * of the @uri structure
503d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
504d7af555327843a9938a913205ac703c13c225603Daniel Veillard * authority     = [ userinfo "@" ] host [ ":" port ]
505d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
506d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns 0 or the error code
507d7af555327843a9938a913205ac703c13c225603Daniel Veillard */
508d7af555327843a9938a913205ac703c13c225603Daniel Veillardstatic int
509d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlParse3986Authority(xmlURIPtr uri, const char **str)
510d7af555327843a9938a913205ac703c13c225603Daniel Veillard{
511d7af555327843a9938a913205ac703c13c225603Daniel Veillard    const char *cur;
512d7af555327843a9938a913205ac703c13c225603Daniel Veillard    int ret;
513d7af555327843a9938a913205ac703c13c225603Daniel Veillard
514d7af555327843a9938a913205ac703c13c225603Daniel Veillard    cur = *str;
515d7af555327843a9938a913205ac703c13c225603Daniel Veillard    /*
516d7af555327843a9938a913205ac703c13c225603Daniel Veillard     * try to parse an userinfo and check for the trailing @
517d7af555327843a9938a913205ac703c13c225603Daniel Veillard     */
518d7af555327843a9938a913205ac703c13c225603Daniel Veillard    ret = xmlParse3986Userinfo(uri, &cur);
519d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if ((ret != 0) || (*cur != '@'))
520d7af555327843a9938a913205ac703c13c225603Daniel Veillard        cur = *str;
521d7af555327843a9938a913205ac703c13c225603Daniel Veillard    else
522d7af555327843a9938a913205ac703c13c225603Daniel Veillard        cur++;
523d7af555327843a9938a913205ac703c13c225603Daniel Veillard    ret = xmlParse3986Host(uri, &cur);
524d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (ret != 0) return(ret);
525d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (*cur == ':') {
526f582d14fbcba1cd1e6598d556d8838ea6f4788baDaniel Veillard        cur++;
527d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret = xmlParse3986Port(uri, &cur);
528d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (ret != 0) return(ret);
529d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
530d7af555327843a9938a913205ac703c13c225603Daniel Veillard    *str = cur;
531d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return(0);
532d7af555327843a9938a913205ac703c13c225603Daniel Veillard}
533d7af555327843a9938a913205ac703c13c225603Daniel Veillard
534d7af555327843a9938a913205ac703c13c225603Daniel Veillard/**
535d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlParse3986Segment:
536d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  the string to analyze
537d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @forbid: an optional forbidden character
538d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @empty: allow an empty segment
539d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
540d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Parse a segment and fills in the appropriate fields
541d7af555327843a9938a913205ac703c13c225603Daniel Veillard * of the @uri structure
542d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
543d7af555327843a9938a913205ac703c13c225603Daniel Veillard * segment       = *pchar
544d7af555327843a9938a913205ac703c13c225603Daniel Veillard * segment-nz    = 1*pchar
545d7af555327843a9938a913205ac703c13c225603Daniel Veillard * segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
546d7af555327843a9938a913205ac703c13c225603Daniel Veillard *               ; non-zero-length segment without any colon ":"
547d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
548d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns 0 or the error code
549d7af555327843a9938a913205ac703c13c225603Daniel Veillard */
550d7af555327843a9938a913205ac703c13c225603Daniel Veillardstatic int
551d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlParse3986Segment(const char **str, char forbid, int empty)
552d7af555327843a9938a913205ac703c13c225603Daniel Veillard{
553d7af555327843a9938a913205ac703c13c225603Daniel Veillard    const char *cur;
554d7af555327843a9938a913205ac703c13c225603Daniel Veillard
555d7af555327843a9938a913205ac703c13c225603Daniel Veillard    cur = *str;
556d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (!ISA_PCHAR(cur)) {
557d7af555327843a9938a913205ac703c13c225603Daniel Veillard        if (empty)
558d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    return(0);
559d7af555327843a9938a913205ac703c13c225603Daniel Veillard	return(1);
560fdd27d2718b9d6ef234092fb6cddfd7e9916feb6Daniel Veillard    }
561d7af555327843a9938a913205ac703c13c225603Daniel Veillard    while (ISA_PCHAR(cur) && (*cur != forbid))
562d7af555327843a9938a913205ac703c13c225603Daniel Veillard        NEXT(cur);
563d7af555327843a9938a913205ac703c13c225603Daniel Veillard    *str = cur;
564d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return (0);
565d7af555327843a9938a913205ac703c13c225603Daniel Veillard}
566d7af555327843a9938a913205ac703c13c225603Daniel Veillard
567d7af555327843a9938a913205ac703c13c225603Daniel Veillard/**
568d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlParse3986PathAbEmpty:
569d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @uri:  pointer to an URI structure
570d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  the string to analyze
571d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
572d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Parse an path absolute or empty and fills in the appropriate fields
573d7af555327843a9938a913205ac703c13c225603Daniel Veillard * of the @uri structure
574d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
575d7af555327843a9938a913205ac703c13c225603Daniel Veillard * path-abempty  = *( "/" segment )
576d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
577d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns 0 or the error code
578d7af555327843a9938a913205ac703c13c225603Daniel Veillard */
579d7af555327843a9938a913205ac703c13c225603Daniel Veillardstatic int
580d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlParse3986PathAbEmpty(xmlURIPtr uri, const char **str)
581d7af555327843a9938a913205ac703c13c225603Daniel Veillard{
582d7af555327843a9938a913205ac703c13c225603Daniel Veillard    const char *cur;
583d7af555327843a9938a913205ac703c13c225603Daniel Veillard    int ret;
584d7af555327843a9938a913205ac703c13c225603Daniel Veillard
585d7af555327843a9938a913205ac703c13c225603Daniel Veillard    cur = *str;
586d7af555327843a9938a913205ac703c13c225603Daniel Veillard
587d7af555327843a9938a913205ac703c13c225603Daniel Veillard    while (*cur == '/') {
588d7af555327843a9938a913205ac703c13c225603Daniel Veillard        cur++;
589d7af555327843a9938a913205ac703c13c225603Daniel Veillard	ret = xmlParse3986Segment(&cur, 0, 1);
590d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (ret != 0) return(ret);
591d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
592d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri != NULL) {
593d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (uri->path != NULL) xmlFree(uri->path);
5941358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard        if (*str != cur) {
5951358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard            if (uri->cleanup & 2)
5961358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard                uri->path = STRNDUP(*str, cur - *str);
5971358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard            else
5981358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard                uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
5991358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard        } else {
6001358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard            uri->path = NULL;
6011358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard        }
602d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
603d7af555327843a9938a913205ac703c13c225603Daniel Veillard    *str = cur;
604d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return (0);
605d7af555327843a9938a913205ac703c13c225603Daniel Veillard}
606d7af555327843a9938a913205ac703c13c225603Daniel Veillard
607d7af555327843a9938a913205ac703c13c225603Daniel Veillard/**
608d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlParse3986PathAbsolute:
609d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @uri:  pointer to an URI structure
610d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  the string to analyze
611d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
612d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Parse an path absolute and fills in the appropriate fields
613d7af555327843a9938a913205ac703c13c225603Daniel Veillard * of the @uri structure
614d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
615d7af555327843a9938a913205ac703c13c225603Daniel Veillard * path-absolute = "/" [ segment-nz *( "/" segment ) ]
616d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
617d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns 0 or the error code
618d7af555327843a9938a913205ac703c13c225603Daniel Veillard */
619d7af555327843a9938a913205ac703c13c225603Daniel Veillardstatic int
620d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlParse3986PathAbsolute(xmlURIPtr uri, const char **str)
621d7af555327843a9938a913205ac703c13c225603Daniel Veillard{
622d7af555327843a9938a913205ac703c13c225603Daniel Veillard    const char *cur;
623d7af555327843a9938a913205ac703c13c225603Daniel Veillard    int ret;
624d7af555327843a9938a913205ac703c13c225603Daniel Veillard
625d7af555327843a9938a913205ac703c13c225603Daniel Veillard    cur = *str;
626d7af555327843a9938a913205ac703c13c225603Daniel Veillard
627d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (*cur != '/')
628d7af555327843a9938a913205ac703c13c225603Daniel Veillard        return(1);
629d7af555327843a9938a913205ac703c13c225603Daniel Veillard    cur++;
630d7af555327843a9938a913205ac703c13c225603Daniel Veillard    ret = xmlParse3986Segment(&cur, 0, 0);
631d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (ret == 0) {
632d7af555327843a9938a913205ac703c13c225603Daniel Veillard	while (*cur == '/') {
633d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    cur++;
634d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    ret = xmlParse3986Segment(&cur, 0, 1);
635d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    if (ret != 0) return(ret);
6363473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	}
637fdd27d2718b9d6ef234092fb6cddfd7e9916feb6Daniel Veillard    }
638d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri != NULL) {
639d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (uri->path != NULL) xmlFree(uri->path);
6401358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard        if (cur != *str) {
6411358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard            if (uri->cleanup & 2)
6421358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard                uri->path = STRNDUP(*str, cur - *str);
6431358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard            else
6441358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard                uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
6451358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard        } else {
6461358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard            uri->path = NULL;
6471358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard        }
6483473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
649d7af555327843a9938a913205ac703c13c225603Daniel Veillard    *str = cur;
650d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return (0);
6513473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor}
6523473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
6533473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/**
654d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlParse3986PathRootless:
655d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @uri:  pointer to an URI structure
656d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  the string to analyze
6573473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
658d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Parse an path without root and fills in the appropriate fields
659d7af555327843a9938a913205ac703c13c225603Daniel Veillard * of the @uri structure
660d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
661d7af555327843a9938a913205ac703c13c225603Daniel Veillard * path-rootless = segment-nz *( "/" segment )
662d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
663d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns 0 or the error code
6643473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
665d7af555327843a9938a913205ac703c13c225603Daniel Veillardstatic int
666d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlParse3986PathRootless(xmlURIPtr uri, const char **str)
667d7af555327843a9938a913205ac703c13c225603Daniel Veillard{
668d7af555327843a9938a913205ac703c13c225603Daniel Veillard    const char *cur;
669d7af555327843a9938a913205ac703c13c225603Daniel Veillard    int ret;
6703473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
671d7af555327843a9938a913205ac703c13c225603Daniel Veillard    cur = *str;
672d7af555327843a9938a913205ac703c13c225603Daniel Veillard
673d7af555327843a9938a913205ac703c13c225603Daniel Veillard    ret = xmlParse3986Segment(&cur, 0, 0);
674d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (ret != 0) return(ret);
675d7af555327843a9938a913205ac703c13c225603Daniel Veillard    while (*cur == '/') {
676d7af555327843a9938a913205ac703c13c225603Daniel Veillard        cur++;
677d7af555327843a9938a913205ac703c13c225603Daniel Veillard	ret = xmlParse3986Segment(&cur, 0, 1);
678d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (ret != 0) return(ret);
679d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
680d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri != NULL) {
681d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (uri->path != NULL) xmlFree(uri->path);
6821358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard        if (cur != *str) {
6831358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard            if (uri->cleanup & 2)
6841358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard                uri->path = STRNDUP(*str, cur - *str);
6851358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard            else
6861358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard                uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
6871358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard        } else {
6881358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard            uri->path = NULL;
6891358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard        }
6903473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
691d7af555327843a9938a913205ac703c13c225603Daniel Veillard    *str = cur;
692d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return (0);
6933473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor}
6943473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
6953473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/**
696d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlParse3986PathNoScheme:
697d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @uri:  pointer to an URI structure
698d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  the string to analyze
6993473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
700d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Parse an path which is not a scheme and fills in the appropriate fields
701d7af555327843a9938a913205ac703c13c225603Daniel Veillard * of the @uri structure
702d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
703d7af555327843a9938a913205ac703c13c225603Daniel Veillard * path-noscheme = segment-nz-nc *( "/" segment )
704d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
705d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns 0 or the error code
7063473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
707d7af555327843a9938a913205ac703c13c225603Daniel Veillardstatic int
708d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlParse3986PathNoScheme(xmlURIPtr uri, const char **str)
709d7af555327843a9938a913205ac703c13c225603Daniel Veillard{
710d7af555327843a9938a913205ac703c13c225603Daniel Veillard    const char *cur;
711d7af555327843a9938a913205ac703c13c225603Daniel Veillard    int ret;
7123473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
713d7af555327843a9938a913205ac703c13c225603Daniel Veillard    cur = *str;
714d7af555327843a9938a913205ac703c13c225603Daniel Veillard
715d7af555327843a9938a913205ac703c13c225603Daniel Veillard    ret = xmlParse3986Segment(&cur, ':', 0);
716d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (ret != 0) return(ret);
717d7af555327843a9938a913205ac703c13c225603Daniel Veillard    while (*cur == '/') {
718d7af555327843a9938a913205ac703c13c225603Daniel Veillard        cur++;
719d7af555327843a9938a913205ac703c13c225603Daniel Veillard	ret = xmlParse3986Segment(&cur, 0, 1);
720d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (ret != 0) return(ret);
721d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
722d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri != NULL) {
723d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (uri->path != NULL) xmlFree(uri->path);
7241358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard        if (cur != *str) {
7251358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard            if (uri->cleanup & 2)
7261358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard                uri->path = STRNDUP(*str, cur - *str);
7271358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard            else
7281358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard                uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
7291358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard        } else {
7301358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard            uri->path = NULL;
7311358fef9aa2c3fea5ed3d6ee50c7eb4d6f92b247Daniel Veillard        }
732d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
733d7af555327843a9938a913205ac703c13c225603Daniel Veillard    *str = cur;
734d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return (0);
735d7af555327843a9938a913205ac703c13c225603Daniel Veillard}
736d7af555327843a9938a913205ac703c13c225603Daniel Veillard
737d7af555327843a9938a913205ac703c13c225603Daniel Veillard/**
738d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlParse3986HierPart:
739d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @uri:  pointer to an URI structure
740d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  the string to analyze
741d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
742d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Parse an hierarchical part and fills in the appropriate fields
743d7af555327843a9938a913205ac703c13c225603Daniel Veillard * of the @uri structure
744d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
745d7af555327843a9938a913205ac703c13c225603Daniel Veillard * hier-part     = "//" authority path-abempty
746d7af555327843a9938a913205ac703c13c225603Daniel Veillard *                / path-absolute
747d7af555327843a9938a913205ac703c13c225603Daniel Veillard *                / path-rootless
748d7af555327843a9938a913205ac703c13c225603Daniel Veillard *                / path-empty
749d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
750d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns 0 or the error code
751d7af555327843a9938a913205ac703c13c225603Daniel Veillard */
752d7af555327843a9938a913205ac703c13c225603Daniel Veillardstatic int
753d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlParse3986HierPart(xmlURIPtr uri, const char **str)
754d7af555327843a9938a913205ac703c13c225603Daniel Veillard{
755d7af555327843a9938a913205ac703c13c225603Daniel Veillard    const char *cur;
756d7af555327843a9938a913205ac703c13c225603Daniel Veillard    int ret;
757d7af555327843a9938a913205ac703c13c225603Daniel Veillard
758d7af555327843a9938a913205ac703c13c225603Daniel Veillard    cur = *str;
759d7af555327843a9938a913205ac703c13c225603Daniel Veillard
760d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if ((*cur == '/') && (*(cur + 1) == '/')) {
761d7af555327843a9938a913205ac703c13c225603Daniel Veillard        cur += 2;
762d7af555327843a9938a913205ac703c13c225603Daniel Veillard	ret = xmlParse3986Authority(uri, &cur);
763d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (ret != 0) return(ret);
764beb7281055dbf0ed4d041022a67c6c5cfd126f25Daniel Veillard	if (uri->server == NULL)
765beb7281055dbf0ed4d041022a67c6c5cfd126f25Daniel Veillard	    uri->port = -1;
766d7af555327843a9938a913205ac703c13c225603Daniel Veillard	ret = xmlParse3986PathAbEmpty(uri, &cur);
767d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (ret != 0) return(ret);
768d7af555327843a9938a913205ac703c13c225603Daniel Veillard	*str = cur;
769d7af555327843a9938a913205ac703c13c225603Daniel Veillard	return(0);
770d7af555327843a9938a913205ac703c13c225603Daniel Veillard    } else if (*cur == '/') {
771d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret = xmlParse3986PathAbsolute(uri, &cur);
772d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (ret != 0) return(ret);
773d7af555327843a9938a913205ac703c13c225603Daniel Veillard    } else if (ISA_PCHAR(cur)) {
774d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret = xmlParse3986PathRootless(uri, &cur);
775d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (ret != 0) return(ret);
776d7af555327843a9938a913205ac703c13c225603Daniel Veillard    } else {
777d7af555327843a9938a913205ac703c13c225603Daniel Veillard	/* path-empty is effectively empty */
778d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (uri != NULL) {
779d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    if (uri->path != NULL) xmlFree(uri->path);
780d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    uri->path = NULL;
781d7af555327843a9938a913205ac703c13c225603Daniel Veillard	}
782d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
783d7af555327843a9938a913205ac703c13c225603Daniel Veillard    *str = cur;
784d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return (0);
785d7af555327843a9938a913205ac703c13c225603Daniel Veillard}
786d7af555327843a9938a913205ac703c13c225603Daniel Veillard
787d7af555327843a9938a913205ac703c13c225603Daniel Veillard/**
788d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlParse3986RelativeRef:
789d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @uri:  pointer to an URI structure
790d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  the string to analyze
791d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
792d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Parse an URI string and fills in the appropriate fields
793d7af555327843a9938a913205ac703c13c225603Daniel Veillard * of the @uri structure
794d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
795d7af555327843a9938a913205ac703c13c225603Daniel Veillard * relative-ref  = relative-part [ "?" query ] [ "#" fragment ]
796d7af555327843a9938a913205ac703c13c225603Daniel Veillard * relative-part = "//" authority path-abempty
797d7af555327843a9938a913205ac703c13c225603Daniel Veillard *               / path-absolute
798d7af555327843a9938a913205ac703c13c225603Daniel Veillard *               / path-noscheme
799d7af555327843a9938a913205ac703c13c225603Daniel Veillard *               / path-empty
800d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
801d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns 0 or the error code
802d7af555327843a9938a913205ac703c13c225603Daniel Veillard */
803d7af555327843a9938a913205ac703c13c225603Daniel Veillardstatic int
804d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlParse3986RelativeRef(xmlURIPtr uri, const char *str) {
805d7af555327843a9938a913205ac703c13c225603Daniel Veillard    int ret;
806d7af555327843a9938a913205ac703c13c225603Daniel Veillard
807d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if ((*str == '/') && (*(str + 1) == '/')) {
808d7af555327843a9938a913205ac703c13c225603Daniel Veillard        str += 2;
809d7af555327843a9938a913205ac703c13c225603Daniel Veillard	ret = xmlParse3986Authority(uri, &str);
810d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (ret != 0) return(ret);
811d7af555327843a9938a913205ac703c13c225603Daniel Veillard	ret = xmlParse3986PathAbEmpty(uri, &str);
812d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (ret != 0) return(ret);
813d7af555327843a9938a913205ac703c13c225603Daniel Veillard    } else if (*str == '/') {
814d7af555327843a9938a913205ac703c13c225603Daniel Veillard	ret = xmlParse3986PathAbsolute(uri, &str);
815d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (ret != 0) return(ret);
816d7af555327843a9938a913205ac703c13c225603Daniel Veillard    } else if (ISA_PCHAR(str)) {
817d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret = xmlParse3986PathNoScheme(uri, &str);
818d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (ret != 0) return(ret);
819d7af555327843a9938a913205ac703c13c225603Daniel Veillard    } else {
820d7af555327843a9938a913205ac703c13c225603Daniel Veillard	/* path-empty is effectively empty */
821d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (uri != NULL) {
822d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    if (uri->path != NULL) xmlFree(uri->path);
823d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    uri->path = NULL;
824d7af555327843a9938a913205ac703c13c225603Daniel Veillard	}
825d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
826d7af555327843a9938a913205ac703c13c225603Daniel Veillard
827d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (*str == '?') {
828d7af555327843a9938a913205ac703c13c225603Daniel Veillard	str++;
829d7af555327843a9938a913205ac703c13c225603Daniel Veillard	ret = xmlParse3986Query(uri, &str);
830d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (ret != 0) return(ret);
831d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
832d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (*str == '#') {
833d7af555327843a9938a913205ac703c13c225603Daniel Veillard	str++;
834d7af555327843a9938a913205ac703c13c225603Daniel Veillard	ret = xmlParse3986Fragment(uri, &str);
835d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (ret != 0) return(ret);
836d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
837d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (*str != 0) {
838d7af555327843a9938a913205ac703c13c225603Daniel Veillard	xmlCleanURI(uri);
839d7af555327843a9938a913205ac703c13c225603Daniel Veillard	return(1);
840d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
841d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return(0);
8423473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor}
8433473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
844d7af555327843a9938a913205ac703c13c225603Daniel Veillard
8453473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/**
846d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlParse3986URI:
847d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @uri:  pointer to an URI structure
848d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  the string to analyze
8493473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
850d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Parse an URI string and fills in the appropriate fields
851d7af555327843a9938a913205ac703c13c225603Daniel Veillard * of the @uri structure
852d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
853d7af555327843a9938a913205ac703c13c225603Daniel Veillard * scheme ":" hier-part [ "?" query ] [ "#" fragment ]
854d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
855d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns 0 or the error code
8563473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
857d7af555327843a9938a913205ac703c13c225603Daniel Veillardstatic int
858d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlParse3986URI(xmlURIPtr uri, const char *str) {
859d7af555327843a9938a913205ac703c13c225603Daniel Veillard    int ret;
8603473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
861d7af555327843a9938a913205ac703c13c225603Daniel Veillard    ret = xmlParse3986Scheme(uri, &str);
862d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (ret != 0) return(ret);
863d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (*str != ':') {
864d7af555327843a9938a913205ac703c13c225603Daniel Veillard	return(1);
865d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
866d7af555327843a9938a913205ac703c13c225603Daniel Veillard    str++;
867d7af555327843a9938a913205ac703c13c225603Daniel Veillard    ret = xmlParse3986HierPart(uri, &str);
868d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (ret != 0) return(ret);
869d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (*str == '?') {
870d7af555327843a9938a913205ac703c13c225603Daniel Veillard	str++;
871d7af555327843a9938a913205ac703c13c225603Daniel Veillard	ret = xmlParse3986Query(uri, &str);
872d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (ret != 0) return(ret);
873d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
874d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (*str == '#') {
875d7af555327843a9938a913205ac703c13c225603Daniel Veillard	str++;
876d7af555327843a9938a913205ac703c13c225603Daniel Veillard	ret = xmlParse3986Fragment(uri, &str);
877d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (ret != 0) return(ret);
878d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
879d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (*str != 0) {
880d7af555327843a9938a913205ac703c13c225603Daniel Veillard	xmlCleanURI(uri);
881d7af555327843a9938a913205ac703c13c225603Daniel Veillard	return(1);
882d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
883d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return(0);
8843473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor}
8853473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
8863473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/**
887d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlParse3986URIReference:
888d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @uri:  pointer to an URI structure
889d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  the string to analyze
8903473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
891d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Parse an URI reference string and fills in the appropriate fields
892d7af555327843a9938a913205ac703c13c225603Daniel Veillard * of the @uri structure
8933473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
894d7af555327843a9938a913205ac703c13c225603Daniel Veillard * URI-reference = URI / relative-ref
8953473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
896d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns 0 or the error code
8973473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
898d7af555327843a9938a913205ac703c13c225603Daniel Veillardstatic int
899d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlParse3986URIReference(xmlURIPtr uri, const char *str) {
900d7af555327843a9938a913205ac703c13c225603Daniel Veillard    int ret;
9013473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
902d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (str == NULL)
9033473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	return(-1);
904d7af555327843a9938a913205ac703c13c225603Daniel Veillard    xmlCleanURI(uri);
9053473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
9063473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    /*
907d7af555327843a9938a913205ac703c13c225603Daniel Veillard     * Try first to parse absolute refs, then fallback to relative if
908d7af555327843a9938a913205ac703c13c225603Daniel Veillard     * it fails.
9093473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     */
910d7af555327843a9938a913205ac703c13c225603Daniel Veillard    ret = xmlParse3986URI(uri, str);
911d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (ret != 0) {
912d7af555327843a9938a913205ac703c13c225603Daniel Veillard	xmlCleanURI(uri);
913d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret = xmlParse3986RelativeRef(uri, str);
914d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (ret != 0) {
915d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    xmlCleanURI(uri);
916d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    return(ret);
9173473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	}
9183473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
919d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return(0);
920d7af555327843a9938a913205ac703c13c225603Daniel Veillard}
9213473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
922d7af555327843a9938a913205ac703c13c225603Daniel Veillard/**
923d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlParseURI:
924d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  the URI string to analyze
925d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
926d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Parse an URI based on RFC 3986
927d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
928d7af555327843a9938a913205ac703c13c225603Daniel Veillard * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
929d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
930d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns a newly built xmlURIPtr or NULL in case of error
931d7af555327843a9938a913205ac703c13c225603Daniel Veillard */
932d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlURIPtr
933d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlParseURI(const char *str) {
934d7af555327843a9938a913205ac703c13c225603Daniel Veillard    xmlURIPtr uri;
935d7af555327843a9938a913205ac703c13c225603Daniel Veillard    int ret;
9363473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
937d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (str == NULL)
938d7af555327843a9938a913205ac703c13c225603Daniel Veillard	return(NULL);
939d7af555327843a9938a913205ac703c13c225603Daniel Veillard    uri = xmlCreateURI();
940d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri != NULL) {
941d7af555327843a9938a913205ac703c13c225603Daniel Veillard	ret = xmlParse3986URIReference(uri, str);
942d7af555327843a9938a913205ac703c13c225603Daniel Veillard        if (ret) {
943d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    xmlFreeURI(uri);
944d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    return(NULL);
945d7af555327843a9938a913205ac703c13c225603Daniel Veillard	}
9463473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
947d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return(uri);
948d7af555327843a9938a913205ac703c13c225603Daniel Veillard}
9493473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
950d7af555327843a9938a913205ac703c13c225603Daniel Veillard/**
951d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlParseURIReference:
952d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @uri:  pointer to an URI structure
953d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  the string to analyze
954d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
955d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Parse an URI reference string based on RFC 3986 and fills in the
956d7af555327843a9938a913205ac703c13c225603Daniel Veillard * appropriate fields of the @uri structure
957d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
958d7af555327843a9938a913205ac703c13c225603Daniel Veillard * URI-reference = URI / relative-ref
959d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
960d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns 0 or the error code
961d7af555327843a9938a913205ac703c13c225603Daniel Veillard */
962d7af555327843a9938a913205ac703c13c225603Daniel Veillardint
963d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlParseURIReference(xmlURIPtr uri, const char *str) {
964d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return(xmlParse3986URIReference(uri, str));
965d7af555327843a9938a913205ac703c13c225603Daniel Veillard}
9663473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
967d7af555327843a9938a913205ac703c13c225603Daniel Veillard/**
968d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlParseURIRaw:
969d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  the URI string to analyze
970d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @raw:  if 1 unescaping of URI pieces are disabled
971d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
972d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Parse an URI but allows to keep intact the original fragments.
973d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
974d7af555327843a9938a913205ac703c13c225603Daniel Veillard * URI-reference = URI / relative-ref
975d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
976d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns a newly built xmlURIPtr or NULL in case of error
977d7af555327843a9938a913205ac703c13c225603Daniel Veillard */
978d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlURIPtr
979d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlParseURIRaw(const char *str, int raw) {
980d7af555327843a9938a913205ac703c13c225603Daniel Veillard    xmlURIPtr uri;
981d7af555327843a9938a913205ac703c13c225603Daniel Veillard    int ret;
9823473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
983d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (str == NULL)
984d7af555327843a9938a913205ac703c13c225603Daniel Veillard	return(NULL);
985d7af555327843a9938a913205ac703c13c225603Daniel Veillard    uri = xmlCreateURI();
986d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri != NULL) {
987d7af555327843a9938a913205ac703c13c225603Daniel Veillard        if (raw) {
988d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    uri->cleanup |= 2;
989d7af555327843a9938a913205ac703c13c225603Daniel Veillard	}
990d7af555327843a9938a913205ac703c13c225603Daniel Veillard	ret = xmlParseURIReference(uri, str);
991d7af555327843a9938a913205ac703c13c225603Daniel Veillard        if (ret) {
992d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    xmlFreeURI(uri);
993d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    return(NULL);
994d7af555327843a9938a913205ac703c13c225603Daniel Veillard	}
995d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
996d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return(uri);
9973473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor}
9983473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
999d7af555327843a9938a913205ac703c13c225603Daniel Veillard/************************************************************************
1000d7af555327843a9938a913205ac703c13c225603Daniel Veillard *									*
1001d7af555327843a9938a913205ac703c13c225603Daniel Veillard *			Generic URI structure functions			*
1002d7af555327843a9938a913205ac703c13c225603Daniel Veillard *									*
1003d7af555327843a9938a913205ac703c13c225603Daniel Veillard ************************************************************************/
1004d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1005d7af555327843a9938a913205ac703c13c225603Daniel Veillard/**
1006d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlCreateURI:
1007d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
1008d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Simply creates an empty xmlURI
1009d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
1010d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns the new structure or NULL in case of error
1011d7af555327843a9938a913205ac703c13c225603Daniel Veillard */
1012d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlURIPtr
1013d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlCreateURI(void) {
1014d7af555327843a9938a913205ac703c13c225603Daniel Veillard    xmlURIPtr ret;
1015d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1016d7af555327843a9938a913205ac703c13c225603Daniel Veillard    ret = (xmlURIPtr) xmlMalloc(sizeof(xmlURI));
1017d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (ret == NULL) {
101857560386503be0fd023f3b7537fd496784f3be18Daniel Veillard        xmlURIErrMemory("creating URI structure\n");
1019d7af555327843a9938a913205ac703c13c225603Daniel Veillard	return(NULL);
1020d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
1021d7af555327843a9938a913205ac703c13c225603Daniel Veillard    memset(ret, 0, sizeof(xmlURI));
1022d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return(ret);
1023966a31e222f478b8ab3174617794808aa90f20c0Daniel Veillard}
1024966a31e222f478b8ab3174617794808aa90f20c0Daniel Veillard
10253473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/**
102657560386503be0fd023f3b7537fd496784f3be18Daniel Veillard * xmlSaveUriRealloc:
102757560386503be0fd023f3b7537fd496784f3be18Daniel Veillard *
102857560386503be0fd023f3b7537fd496784f3be18Daniel Veillard * Function to handle properly a reallocation when saving an URI
102957560386503be0fd023f3b7537fd496784f3be18Daniel Veillard * Also imposes some limit on the length of an URI string output
103057560386503be0fd023f3b7537fd496784f3be18Daniel Veillard */
103157560386503be0fd023f3b7537fd496784f3be18Daniel Veillardstatic xmlChar *
103257560386503be0fd023f3b7537fd496784f3be18Daniel VeillardxmlSaveUriRealloc(xmlChar *ret, int *max) {
103357560386503be0fd023f3b7537fd496784f3be18Daniel Veillard    xmlChar *temp;
103457560386503be0fd023f3b7537fd496784f3be18Daniel Veillard    int tmp;
103557560386503be0fd023f3b7537fd496784f3be18Daniel Veillard
103657560386503be0fd023f3b7537fd496784f3be18Daniel Veillard    if (*max > MAX_URI_LENGTH) {
103757560386503be0fd023f3b7537fd496784f3be18Daniel Veillard        xmlURIErrMemory("reaching arbitrary MAX_URI_LENGTH limit\n");
103857560386503be0fd023f3b7537fd496784f3be18Daniel Veillard        return(NULL);
103957560386503be0fd023f3b7537fd496784f3be18Daniel Veillard    }
104057560386503be0fd023f3b7537fd496784f3be18Daniel Veillard    tmp = *max * 2;
104157560386503be0fd023f3b7537fd496784f3be18Daniel Veillard    temp = (xmlChar *) xmlRealloc(ret, (tmp + 1));
104257560386503be0fd023f3b7537fd496784f3be18Daniel Veillard    if (temp == NULL) {
104357560386503be0fd023f3b7537fd496784f3be18Daniel Veillard        xmlURIErrMemory("saving URI\n");
104457560386503be0fd023f3b7537fd496784f3be18Daniel Veillard        return(NULL);
104557560386503be0fd023f3b7537fd496784f3be18Daniel Veillard    }
104657560386503be0fd023f3b7537fd496784f3be18Daniel Veillard    *max = tmp;
104757560386503be0fd023f3b7537fd496784f3be18Daniel Veillard    return(temp);
104857560386503be0fd023f3b7537fd496784f3be18Daniel Veillard}
104957560386503be0fd023f3b7537fd496784f3be18Daniel Veillard
105057560386503be0fd023f3b7537fd496784f3be18Daniel Veillard/**
1051d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlSaveUri:
1052d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @uri:  pointer to an xmlURI
10533473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
1054d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Save the URI as an escaped string
10553473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
1056d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns a new string (to be deallocated by caller)
10573473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
1058d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlChar *
1059d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlSaveUri(xmlURIPtr uri) {
1060d7af555327843a9938a913205ac703c13c225603Daniel Veillard    xmlChar *ret = NULL;
1061d7af555327843a9938a913205ac703c13c225603Daniel Veillard    xmlChar *temp;
1062d7af555327843a9938a913205ac703c13c225603Daniel Veillard    const char *p;
1063d7af555327843a9938a913205ac703c13c225603Daniel Veillard    int len;
1064d7af555327843a9938a913205ac703c13c225603Daniel Veillard    int max;
10653473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1066d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri == NULL) return(NULL);
1067d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1068d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1069d7af555327843a9938a913205ac703c13c225603Daniel Veillard    max = 80;
1070d7af555327843a9938a913205ac703c13c225603Daniel Veillard    ret = (xmlChar *) xmlMallocAtomic((max + 1) * sizeof(xmlChar));
1071d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (ret == NULL) {
107257560386503be0fd023f3b7537fd496784f3be18Daniel Veillard        xmlURIErrMemory("saving URI\n");
10733473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	return(NULL);
1074d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
1075d7af555327843a9938a913205ac703c13c225603Daniel Veillard    len = 0;
10763473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1077d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->scheme != NULL) {
1078d7af555327843a9938a913205ac703c13c225603Daniel Veillard	p = uri->scheme;
1079d7af555327843a9938a913205ac703c13c225603Daniel Veillard	while (*p != 0) {
1080d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    if (len >= max) {
108157560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                temp = xmlSaveUriRealloc(ret, &max);
108257560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                if (temp == NULL) goto mem_error;
1083d7af555327843a9938a913205ac703c13c225603Daniel Veillard		ret = temp;
1084d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    }
1085d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    ret[len++] = *p++;
10863473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	}
1087d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (len >= max) {
108857560386503be0fd023f3b7537fd496784f3be18Daniel Veillard            temp = xmlSaveUriRealloc(ret, &max);
108957560386503be0fd023f3b7537fd496784f3be18Daniel Veillard            if (temp == NULL) goto mem_error;
109057560386503be0fd023f3b7537fd496784f3be18Daniel Veillard            ret = temp;
1091d7af555327843a9938a913205ac703c13c225603Daniel Veillard	}
1092d7af555327843a9938a913205ac703c13c225603Daniel Veillard	ret[len++] = ':';
1093d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
1094d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->opaque != NULL) {
1095d7af555327843a9938a913205ac703c13c225603Daniel Veillard	p = uri->opaque;
1096d7af555327843a9938a913205ac703c13c225603Daniel Veillard	while (*p != 0) {
1097d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    if (len + 3 >= max) {
109857560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                temp = xmlSaveUriRealloc(ret, &max);
109957560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                if (temp == NULL) goto mem_error;
110057560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                ret = temp;
1101d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    }
1102d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    if (IS_RESERVED(*(p)) || IS_UNRESERVED(*(p)))
1103d7af555327843a9938a913205ac703c13c225603Daniel Veillard		ret[len++] = *p++;
1104d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    else {
1105d7af555327843a9938a913205ac703c13c225603Daniel Veillard		int val = *(unsigned char *)p++;
1106d7af555327843a9938a913205ac703c13c225603Daniel Veillard		int hi = val / 0x10, lo = val % 0x10;
1107d7af555327843a9938a913205ac703c13c225603Daniel Veillard		ret[len++] = '%';
1108d7af555327843a9938a913205ac703c13c225603Daniel Veillard		ret[len++] = hi + (hi > 9? 'A'-10 : '0');
1109d7af555327843a9938a913205ac703c13c225603Daniel Veillard		ret[len++] = lo + (lo > 9? 'A'-10 : '0');
1110d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    }
1111d7af555327843a9938a913205ac703c13c225603Daniel Veillard	}
1112d7af555327843a9938a913205ac703c13c225603Daniel Veillard    } else {
1113beb7281055dbf0ed4d041022a67c6c5cfd126f25Daniel Veillard	if ((uri->server != NULL) || (uri->port == -1)) {
1114d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    if (len + 3 >= max) {
111557560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                temp = xmlSaveUriRealloc(ret, &max);
111657560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                if (temp == NULL) goto mem_error;
111757560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                ret = temp;
1118d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    }
1119d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    ret[len++] = '/';
1120d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    ret[len++] = '/';
1121d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    if (uri->user != NULL) {
1122d7af555327843a9938a913205ac703c13c225603Daniel Veillard		p = uri->user;
1123d7af555327843a9938a913205ac703c13c225603Daniel Veillard		while (*p != 0) {
1124d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    if (len + 3 >= max) {
112557560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                        temp = xmlSaveUriRealloc(ret, &max);
112657560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                        if (temp == NULL) goto mem_error;
112757560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                        ret = temp;
1128d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    }
1129d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    if ((IS_UNRESERVED(*(p))) ||
1130d7af555327843a9938a913205ac703c13c225603Daniel Veillard			((*(p) == ';')) || ((*(p) == ':')) ||
1131d7af555327843a9938a913205ac703c13c225603Daniel Veillard			((*(p) == '&')) || ((*(p) == '=')) ||
1132d7af555327843a9938a913205ac703c13c225603Daniel Veillard			((*(p) == '+')) || ((*(p) == '$')) ||
1133d7af555327843a9938a913205ac703c13c225603Daniel Veillard			((*(p) == ',')))
1134d7af555327843a9938a913205ac703c13c225603Daniel Veillard			ret[len++] = *p++;
1135d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    else {
1136d7af555327843a9938a913205ac703c13c225603Daniel Veillard			int val = *(unsigned char *)p++;
1137d7af555327843a9938a913205ac703c13c225603Daniel Veillard			int hi = val / 0x10, lo = val % 0x10;
1138d7af555327843a9938a913205ac703c13c225603Daniel Veillard			ret[len++] = '%';
1139d7af555327843a9938a913205ac703c13c225603Daniel Veillard			ret[len++] = hi + (hi > 9? 'A'-10 : '0');
1140d7af555327843a9938a913205ac703c13c225603Daniel Veillard			ret[len++] = lo + (lo > 9? 'A'-10 : '0');
1141d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    }
1142d7af555327843a9938a913205ac703c13c225603Daniel Veillard		}
1143d7af555327843a9938a913205ac703c13c225603Daniel Veillard		if (len + 3 >= max) {
114457560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                    temp = xmlSaveUriRealloc(ret, &max);
114557560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                    if (temp == NULL) goto mem_error;
114657560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                    ret = temp;
1147d7af555327843a9938a913205ac703c13c225603Daniel Veillard		}
1148d7af555327843a9938a913205ac703c13c225603Daniel Veillard		ret[len++] = '@';
1149d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    }
1150beb7281055dbf0ed4d041022a67c6c5cfd126f25Daniel Veillard	    if (uri->server != NULL) {
1151beb7281055dbf0ed4d041022a67c6c5cfd126f25Daniel Veillard		p = uri->server;
1152beb7281055dbf0ed4d041022a67c6c5cfd126f25Daniel Veillard		while (*p != 0) {
1153beb7281055dbf0ed4d041022a67c6c5cfd126f25Daniel Veillard		    if (len >= max) {
1154beb7281055dbf0ed4d041022a67c6c5cfd126f25Daniel Veillard			temp = xmlSaveUriRealloc(ret, &max);
1155beb7281055dbf0ed4d041022a67c6c5cfd126f25Daniel Veillard			if (temp == NULL) goto mem_error;
1156beb7281055dbf0ed4d041022a67c6c5cfd126f25Daniel Veillard			ret = temp;
1157beb7281055dbf0ed4d041022a67c6c5cfd126f25Daniel Veillard		    }
1158beb7281055dbf0ed4d041022a67c6c5cfd126f25Daniel Veillard		    ret[len++] = *p++;
1159d7af555327843a9938a913205ac703c13c225603Daniel Veillard		}
1160beb7281055dbf0ed4d041022a67c6c5cfd126f25Daniel Veillard		if (uri->port > 0) {
1161beb7281055dbf0ed4d041022a67c6c5cfd126f25Daniel Veillard		    if (len + 10 >= max) {
1162beb7281055dbf0ed4d041022a67c6c5cfd126f25Daniel Veillard			temp = xmlSaveUriRealloc(ret, &max);
1163beb7281055dbf0ed4d041022a67c6c5cfd126f25Daniel Veillard			if (temp == NULL) goto mem_error;
1164beb7281055dbf0ed4d041022a67c6c5cfd126f25Daniel Veillard			ret = temp;
1165beb7281055dbf0ed4d041022a67c6c5cfd126f25Daniel Veillard		    }
1166beb7281055dbf0ed4d041022a67c6c5cfd126f25Daniel Veillard		    len += snprintf((char *) &ret[len], max - len, ":%d", uri->port);
1167d7af555327843a9938a913205ac703c13c225603Daniel Veillard		}
1168d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    }
1169d7af555327843a9938a913205ac703c13c225603Daniel Veillard	} else if (uri->authority != NULL) {
1170d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    if (len + 3 >= max) {
117157560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                temp = xmlSaveUriRealloc(ret, &max);
117257560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                if (temp == NULL) goto mem_error;
117357560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                ret = temp;
1174d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    }
1175d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    ret[len++] = '/';
1176d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    ret[len++] = '/';
1177d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    p = uri->authority;
1178d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    while (*p != 0) {
1179d7af555327843a9938a913205ac703c13c225603Daniel Veillard		if (len + 3 >= max) {
118057560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                    temp = xmlSaveUriRealloc(ret, &max);
118157560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                    if (temp == NULL) goto mem_error;
118257560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                    ret = temp;
1183d7af555327843a9938a913205ac703c13c225603Daniel Veillard		}
1184d7af555327843a9938a913205ac703c13c225603Daniel Veillard		if ((IS_UNRESERVED(*(p))) ||
1185d7af555327843a9938a913205ac703c13c225603Daniel Veillard                    ((*(p) == '$')) || ((*(p) == ',')) || ((*(p) == ';')) ||
1186d7af555327843a9938a913205ac703c13c225603Daniel Veillard                    ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) ||
1187d7af555327843a9938a913205ac703c13c225603Daniel Veillard                    ((*(p) == '=')) || ((*(p) == '+')))
1188d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    ret[len++] = *p++;
1189d7af555327843a9938a913205ac703c13c225603Daniel Veillard		else {
1190d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    int val = *(unsigned char *)p++;
1191d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    int hi = val / 0x10, lo = val % 0x10;
1192d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    ret[len++] = '%';
1193d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    ret[len++] = hi + (hi > 9? 'A'-10 : '0');
1194d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    ret[len++] = lo + (lo > 9? 'A'-10 : '0');
1195d7af555327843a9938a913205ac703c13c225603Daniel Veillard		}
1196d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    }
1197d7af555327843a9938a913205ac703c13c225603Daniel Veillard	} else if (uri->scheme != NULL) {
1198d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    if (len + 3 >= max) {
119957560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                temp = xmlSaveUriRealloc(ret, &max);
120057560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                if (temp == NULL) goto mem_error;
120157560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                ret = temp;
1202d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    }
12033473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	}
1204d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (uri->path != NULL) {
1205d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    p = uri->path;
1206d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    /*
1207d7af555327843a9938a913205ac703c13c225603Daniel Veillard	     * the colon in file:///d: should not be escaped or
1208d7af555327843a9938a913205ac703c13c225603Daniel Veillard	     * Windows accesses fail later.
1209d7af555327843a9938a913205ac703c13c225603Daniel Veillard	     */
1210d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    if ((uri->scheme != NULL) &&
1211d7af555327843a9938a913205ac703c13c225603Daniel Veillard		(p[0] == '/') &&
1212d7af555327843a9938a913205ac703c13c225603Daniel Veillard		(((p[1] >= 'a') && (p[1] <= 'z')) ||
1213d7af555327843a9938a913205ac703c13c225603Daniel Veillard		 ((p[1] >= 'A') && (p[1] <= 'Z'))) &&
1214d7af555327843a9938a913205ac703c13c225603Daniel Veillard		(p[2] == ':') &&
1215d7af555327843a9938a913205ac703c13c225603Daniel Veillard	        (xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) {
1216d7af555327843a9938a913205ac703c13c225603Daniel Veillard		if (len + 3 >= max) {
121757560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                    temp = xmlSaveUriRealloc(ret, &max);
121857560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                    if (temp == NULL) goto mem_error;
121957560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                    ret = temp;
1220d7af555327843a9938a913205ac703c13c225603Daniel Veillard		}
1221d7af555327843a9938a913205ac703c13c225603Daniel Veillard		ret[len++] = *p++;
1222d7af555327843a9938a913205ac703c13c225603Daniel Veillard		ret[len++] = *p++;
1223d7af555327843a9938a913205ac703c13c225603Daniel Veillard		ret[len++] = *p++;
1224d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    }
1225d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    while (*p != 0) {
1226d7af555327843a9938a913205ac703c13c225603Daniel Veillard		if (len + 3 >= max) {
122757560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                    temp = xmlSaveUriRealloc(ret, &max);
122857560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                    if (temp == NULL) goto mem_error;
122957560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                    ret = temp;
1230d7af555327843a9938a913205ac703c13c225603Daniel Veillard		}
1231d7af555327843a9938a913205ac703c13c225603Daniel Veillard		if ((IS_UNRESERVED(*(p))) || ((*(p) == '/')) ||
1232d7af555327843a9938a913205ac703c13c225603Daniel Veillard                    ((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) ||
1233d7af555327843a9938a913205ac703c13c225603Daniel Veillard	            ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||
1234d7af555327843a9938a913205ac703c13c225603Daniel Veillard	            ((*(p) == ',')))
1235d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    ret[len++] = *p++;
1236d7af555327843a9938a913205ac703c13c225603Daniel Veillard		else {
1237d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    int val = *(unsigned char *)p++;
1238d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    int hi = val / 0x10, lo = val % 0x10;
1239d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    ret[len++] = '%';
1240d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    ret[len++] = hi + (hi > 9? 'A'-10 : '0');
1241d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    ret[len++] = lo + (lo > 9? 'A'-10 : '0');
1242d7af555327843a9938a913205ac703c13c225603Daniel Veillard		}
12433473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    }
12443473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	}
1245d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (uri->query_raw != NULL) {
1246d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    if (len + 1 >= max) {
124757560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                temp = xmlSaveUriRealloc(ret, &max);
124857560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                if (temp == NULL) goto mem_error;
124957560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                ret = temp;
1250d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    }
1251d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    ret[len++] = '?';
1252d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    p = uri->query_raw;
1253d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    while (*p != 0) {
1254d7af555327843a9938a913205ac703c13c225603Daniel Veillard		if (len + 1 >= max) {
125557560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                    temp = xmlSaveUriRealloc(ret, &max);
125657560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                    if (temp == NULL) goto mem_error;
125757560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                    ret = temp;
1258d7af555327843a9938a913205ac703c13c225603Daniel Veillard		}
1259d7af555327843a9938a913205ac703c13c225603Daniel Veillard		ret[len++] = *p++;
1260d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    }
1261d7af555327843a9938a913205ac703c13c225603Daniel Veillard	} else if (uri->query != NULL) {
1262d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    if (len + 3 >= max) {
126357560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                temp = xmlSaveUriRealloc(ret, &max);
126457560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                if (temp == NULL) goto mem_error;
126557560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                ret = temp;
1266d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    }
1267d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    ret[len++] = '?';
1268d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    p = uri->query;
1269d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    while (*p != 0) {
1270d7af555327843a9938a913205ac703c13c225603Daniel Veillard		if (len + 3 >= max) {
127157560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                    temp = xmlSaveUriRealloc(ret, &max);
127257560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                    if (temp == NULL) goto mem_error;
127357560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                    ret = temp;
1274d7af555327843a9938a913205ac703c13c225603Daniel Veillard		}
127557560386503be0fd023f3b7537fd496784f3be18Daniel Veillard		if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p))))
1276d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    ret[len++] = *p++;
1277d7af555327843a9938a913205ac703c13c225603Daniel Veillard		else {
1278d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    int val = *(unsigned char *)p++;
1279d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    int hi = val / 0x10, lo = val % 0x10;
1280d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    ret[len++] = '%';
1281d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    ret[len++] = hi + (hi > 9? 'A'-10 : '0');
1282d7af555327843a9938a913205ac703c13c225603Daniel Veillard		    ret[len++] = lo + (lo > 9? 'A'-10 : '0');
1283d7af555327843a9938a913205ac703c13c225603Daniel Veillard		}
1284d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    }
12853473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	}
12864def3bd94c4c34ad0b7b2848f7f43a62c9ea067cDaniel Veillard    }
1287d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->fragment != NULL) {
1288d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (len + 3 >= max) {
128957560386503be0fd023f3b7537fd496784f3be18Daniel Veillard            temp = xmlSaveUriRealloc(ret, &max);
129057560386503be0fd023f3b7537fd496784f3be18Daniel Veillard            if (temp == NULL) goto mem_error;
129157560386503be0fd023f3b7537fd496784f3be18Daniel Veillard            ret = temp;
1292d7af555327843a9938a913205ac703c13c225603Daniel Veillard	}
1293d7af555327843a9938a913205ac703c13c225603Daniel Veillard	ret[len++] = '#';
1294d7af555327843a9938a913205ac703c13c225603Daniel Veillard	p = uri->fragment;
1295d7af555327843a9938a913205ac703c13c225603Daniel Veillard	while (*p != 0) {
1296d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    if (len + 3 >= max) {
129757560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                temp = xmlSaveUriRealloc(ret, &max);
129857560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                if (temp == NULL) goto mem_error;
129957560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                ret = temp;
1300d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    }
130157560386503be0fd023f3b7537fd496784f3be18Daniel Veillard	    if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p))))
1302d7af555327843a9938a913205ac703c13c225603Daniel Veillard		ret[len++] = *p++;
1303d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    else {
1304d7af555327843a9938a913205ac703c13c225603Daniel Veillard		int val = *(unsigned char *)p++;
1305d7af555327843a9938a913205ac703c13c225603Daniel Veillard		int hi = val / 0x10, lo = val % 0x10;
1306d7af555327843a9938a913205ac703c13c225603Daniel Veillard		ret[len++] = '%';
1307d7af555327843a9938a913205ac703c13c225603Daniel Veillard		ret[len++] = hi + (hi > 9? 'A'-10 : '0');
1308d7af555327843a9938a913205ac703c13c225603Daniel Veillard		ret[len++] = lo + (lo > 9? 'A'-10 : '0');
1309d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    }
1310d7af555327843a9938a913205ac703c13c225603Daniel Veillard	}
13113473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
1312d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (len >= max) {
131357560386503be0fd023f3b7537fd496784f3be18Daniel Veillard        temp = xmlSaveUriRealloc(ret, &max);
131457560386503be0fd023f3b7537fd496784f3be18Daniel Veillard        if (temp == NULL) goto mem_error;
131557560386503be0fd023f3b7537fd496784f3be18Daniel Veillard        ret = temp;
13163473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
131713cee4e37ba9f2a401f976e069539514ebfce7bcDaniel Veillard    ret[len] = 0;
1318d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return(ret);
131957560386503be0fd023f3b7537fd496784f3be18Daniel Veillard
132057560386503be0fd023f3b7537fd496784f3be18Daniel Veillardmem_error:
132157560386503be0fd023f3b7537fd496784f3be18Daniel Veillard    xmlFree(ret);
132257560386503be0fd023f3b7537fd496784f3be18Daniel Veillard    return(NULL);
13233473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor}
13243473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
13253473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/**
1326d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlPrintURI:
1327d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @stream:  a FILE* for the output
1328d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @uri:  pointer to an xmlURI
13293473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
1330d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Prints the URI in the stream @stream.
13313473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
1332d7af555327843a9938a913205ac703c13c225603Daniel Veillardvoid
1333d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlPrintURI(FILE *stream, xmlURIPtr uri) {
1334d7af555327843a9938a913205ac703c13c225603Daniel Veillard    xmlChar *out;
13353473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1336d7af555327843a9938a913205ac703c13c225603Daniel Veillard    out = xmlSaveUri(uri);
1337d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (out != NULL) {
1338d7af555327843a9938a913205ac703c13c225603Daniel Veillard	fprintf(stream, "%s", (char *) out);
1339d7af555327843a9938a913205ac703c13c225603Daniel Veillard	xmlFree(out);
13403473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
13413473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor}
13423473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
13433473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/**
1344d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlCleanURI:
1345d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @uri:  pointer to an xmlURI
13463473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
1347d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Make sure the xmlURI struct is free of content
13483473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
1349d7af555327843a9938a913205ac703c13c225603Daniel Veillardstatic void
1350d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlCleanURI(xmlURIPtr uri) {
1351d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri == NULL) return;
13523473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1353d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->scheme != NULL) xmlFree(uri->scheme);
1354d7af555327843a9938a913205ac703c13c225603Daniel Veillard    uri->scheme = NULL;
1355d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->server != NULL) xmlFree(uri->server);
1356d7af555327843a9938a913205ac703c13c225603Daniel Veillard    uri->server = NULL;
1357d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->user != NULL) xmlFree(uri->user);
1358d7af555327843a9938a913205ac703c13c225603Daniel Veillard    uri->user = NULL;
1359d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->path != NULL) xmlFree(uri->path);
1360d7af555327843a9938a913205ac703c13c225603Daniel Veillard    uri->path = NULL;
1361d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->fragment != NULL) xmlFree(uri->fragment);
1362d7af555327843a9938a913205ac703c13c225603Daniel Veillard    uri->fragment = NULL;
1363d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->opaque != NULL) xmlFree(uri->opaque);
1364d7af555327843a9938a913205ac703c13c225603Daniel Veillard    uri->opaque = NULL;
1365d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->authority != NULL) xmlFree(uri->authority);
1366d7af555327843a9938a913205ac703c13c225603Daniel Veillard    uri->authority = NULL;
1367d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->query != NULL) xmlFree(uri->query);
1368d7af555327843a9938a913205ac703c13c225603Daniel Veillard    uri->query = NULL;
1369d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->query_raw != NULL) xmlFree(uri->query_raw);
1370d7af555327843a9938a913205ac703c13c225603Daniel Veillard    uri->query_raw = NULL;
1371d7af555327843a9938a913205ac703c13c225603Daniel Veillard}
13724def3bd94c4c34ad0b7b2848f7f43a62c9ea067cDaniel Veillard
1373d7af555327843a9938a913205ac703c13c225603Daniel Veillard/**
1374d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlFreeURI:
1375d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @uri:  pointer to an xmlURI
1376d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
1377d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Free up the xmlURI struct
1378d7af555327843a9938a913205ac703c13c225603Daniel Veillard */
1379d7af555327843a9938a913205ac703c13c225603Daniel Veillardvoid
1380d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlFreeURI(xmlURIPtr uri) {
1381d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri == NULL) return;
1382d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1383d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->scheme != NULL) xmlFree(uri->scheme);
1384d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->server != NULL) xmlFree(uri->server);
1385d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->user != NULL) xmlFree(uri->user);
1386d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->path != NULL) xmlFree(uri->path);
1387d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->fragment != NULL) xmlFree(uri->fragment);
1388d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->opaque != NULL) xmlFree(uri->opaque);
1389d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->authority != NULL) xmlFree(uri->authority);
1390d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->query != NULL) xmlFree(uri->query);
1391d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->query_raw != NULL) xmlFree(uri->query_raw);
1392d7af555327843a9938a913205ac703c13c225603Daniel Veillard    xmlFree(uri);
13933473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor}
13943473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1395d7af555327843a9938a913205ac703c13c225603Daniel Veillard/************************************************************************
1396d7af555327843a9938a913205ac703c13c225603Daniel Veillard *									*
1397d7af555327843a9938a913205ac703c13c225603Daniel Veillard *			Helper functions				*
1398d7af555327843a9938a913205ac703c13c225603Daniel Veillard *									*
1399d7af555327843a9938a913205ac703c13c225603Daniel Veillard ************************************************************************/
1400d7af555327843a9938a913205ac703c13c225603Daniel Veillard
14013473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/**
1402d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlNormalizeURIPath:
1403d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @path:  pointer to the path string
14043473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
1405d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Applies the 5 normalization steps to a path string--that is, RFC 2396
1406d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Section 5.2, steps 6.c through 6.g.
14073473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
1408d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Normalization occurs directly on the string, no new allocation is done
1409d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
1410d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns 0 or an error code
14113473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
1412d7af555327843a9938a913205ac703c13c225603Daniel Veillardint
1413d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlNormalizeURIPath(char *path) {
1414d7af555327843a9938a913205ac703c13c225603Daniel Veillard    char *cur, *out;
14153473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1416d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (path == NULL)
14173473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	return(-1);
14183473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1419d7af555327843a9938a913205ac703c13c225603Daniel Veillard    /* Skip all initial "/" chars.  We want to get to the beginning of the
1420d7af555327843a9938a913205ac703c13c225603Daniel Veillard     * first non-empty segment.
14213473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     */
1422d7af555327843a9938a913205ac703c13c225603Daniel Veillard    cur = path;
1423d7af555327843a9938a913205ac703c13c225603Daniel Veillard    while (cur[0] == '/')
1424d7af555327843a9938a913205ac703c13c225603Daniel Veillard      ++cur;
1425d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (cur[0] == '\0')
1426d7af555327843a9938a913205ac703c13c225603Daniel Veillard      return(0);
1427d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1428d7af555327843a9938a913205ac703c13c225603Daniel Veillard    /* Keep everything we've seen so far.  */
1429d7af555327843a9938a913205ac703c13c225603Daniel Veillard    out = cur;
1430d7af555327843a9938a913205ac703c13c225603Daniel Veillard
14313473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    /*
1432d7af555327843a9938a913205ac703c13c225603Daniel Veillard     * Analyze each segment in sequence for cases (c) and (d).
14333473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     */
1434d7af555327843a9938a913205ac703c13c225603Daniel Veillard    while (cur[0] != '\0') {
1435015ccb2c747fb73561e2fe72d6214585dd9985e8William M. Brack	/*
1436d7af555327843a9938a913205ac703c13c225603Daniel Veillard	 * c) All occurrences of "./", where "." is a complete path segment,
1437d7af555327843a9938a913205ac703c13c225603Daniel Veillard	 *    are removed from the buffer string.
1438015ccb2c747fb73561e2fe72d6214585dd9985e8William M. Brack	 */
1439d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if ((cur[0] == '.') && (cur[1] == '/')) {
1440d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    cur += 2;
1441d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    /* '//' normalization should be done at this point too */
1442d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    while (cur[0] == '/')
14433473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor		cur++;
1444d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    continue;
14453473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	}
14463473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1447d7af555327843a9938a913205ac703c13c225603Daniel Veillard	/*
1448d7af555327843a9938a913205ac703c13c225603Daniel Veillard	 * d) If the buffer string ends with "." as a complete path segment,
1449d7af555327843a9938a913205ac703c13c225603Daniel Veillard	 *    that "." is removed.
1450d7af555327843a9938a913205ac703c13c225603Daniel Veillard	 */
1451d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if ((cur[0] == '.') && (cur[1] == '\0'))
1452d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    break;
14533473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1454d7af555327843a9938a913205ac703c13c225603Daniel Veillard	/* Otherwise keep the segment.  */
1455d7af555327843a9938a913205ac703c13c225603Daniel Veillard	while (cur[0] != '/') {
1456d7af555327843a9938a913205ac703c13c225603Daniel Veillard            if (cur[0] == '\0')
1457d7af555327843a9938a913205ac703c13c225603Daniel Veillard              goto done_cd;
1458d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    (out++)[0] = (cur++)[0];
1459d7af555327843a9938a913205ac703c13c225603Daniel Veillard	}
1460d7af555327843a9938a913205ac703c13c225603Daniel Veillard	/* nomalize // */
1461d7af555327843a9938a913205ac703c13c225603Daniel Veillard	while ((cur[0] == '/') && (cur[1] == '/'))
1462d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    cur++;
14634def3bd94c4c34ad0b7b2848f7f43a62c9ea067cDaniel Veillard
1464d7af555327843a9938a913205ac703c13c225603Daniel Veillard        (out++)[0] = (cur++)[0];
14653473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
1466d7af555327843a9938a913205ac703c13c225603Daniel Veillard done_cd:
1467d7af555327843a9938a913205ac703c13c225603Daniel Veillard    out[0] = '\0';
1468d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1469d7af555327843a9938a913205ac703c13c225603Daniel Veillard    /* Reset to the beginning of the first segment for the next sequence.  */
1470d7af555327843a9938a913205ac703c13c225603Daniel Veillard    cur = path;
1471d7af555327843a9938a913205ac703c13c225603Daniel Veillard    while (cur[0] == '/')
1472d7af555327843a9938a913205ac703c13c225603Daniel Veillard      ++cur;
1473d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (cur[0] == '\0')
1474d7af555327843a9938a913205ac703c13c225603Daniel Veillard	return(0);
1475d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1476d7af555327843a9938a913205ac703c13c225603Daniel Veillard    /*
1477d7af555327843a9938a913205ac703c13c225603Daniel Veillard     * Analyze each segment in sequence for cases (e) and (f).
1478d7af555327843a9938a913205ac703c13c225603Daniel Veillard     *
1479d7af555327843a9938a913205ac703c13c225603Daniel Veillard     * e) All occurrences of "<segment>/../", where <segment> is a
1480d7af555327843a9938a913205ac703c13c225603Daniel Veillard     *    complete path segment not equal to "..", are removed from the
1481d7af555327843a9938a913205ac703c13c225603Daniel Veillard     *    buffer string.  Removal of these path segments is performed
1482d7af555327843a9938a913205ac703c13c225603Daniel Veillard     *    iteratively, removing the leftmost matching pattern on each
1483d7af555327843a9938a913205ac703c13c225603Daniel Veillard     *    iteration, until no matching pattern remains.
1484d7af555327843a9938a913205ac703c13c225603Daniel Veillard     *
1485d7af555327843a9938a913205ac703c13c225603Daniel Veillard     * f) If the buffer string ends with "<segment>/..", where <segment>
1486d7af555327843a9938a913205ac703c13c225603Daniel Veillard     *    is a complete path segment not equal to "..", that
1487d7af555327843a9938a913205ac703c13c225603Daniel Veillard     *    "<segment>/.." is removed.
1488d7af555327843a9938a913205ac703c13c225603Daniel Veillard     *
1489d7af555327843a9938a913205ac703c13c225603Daniel Veillard     * To satisfy the "iterative" clause in (e), we need to collapse the
1490d7af555327843a9938a913205ac703c13c225603Daniel Veillard     * string every time we find something that needs to be removed.  Thus,
1491d7af555327843a9938a913205ac703c13c225603Daniel Veillard     * we don't need to keep two pointers into the string: we only need a
1492d7af555327843a9938a913205ac703c13c225603Daniel Veillard     * "current position" pointer.
1493d7af555327843a9938a913205ac703c13c225603Daniel Veillard     */
1494d7af555327843a9938a913205ac703c13c225603Daniel Veillard    while (1) {
1495d7af555327843a9938a913205ac703c13c225603Daniel Veillard        char *segp, *tmp;
14963473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1497d7af555327843a9938a913205ac703c13c225603Daniel Veillard        /* At the beginning of each iteration of this loop, "cur" points to
1498d7af555327843a9938a913205ac703c13c225603Daniel Veillard         * the first character of the segment we want to examine.
1499d7af555327843a9938a913205ac703c13c225603Daniel Veillard         */
15003473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1501d7af555327843a9938a913205ac703c13c225603Daniel Veillard        /* Find the end of the current segment.  */
1502d7af555327843a9938a913205ac703c13c225603Daniel Veillard        segp = cur;
1503d7af555327843a9938a913205ac703c13c225603Daniel Veillard        while ((segp[0] != '/') && (segp[0] != '\0'))
1504d7af555327843a9938a913205ac703c13c225603Daniel Veillard          ++segp;
15054def3bd94c4c34ad0b7b2848f7f43a62c9ea067cDaniel Veillard
1506d7af555327843a9938a913205ac703c13c225603Daniel Veillard        /* If this is the last segment, we're done (we need at least two
1507d7af555327843a9938a913205ac703c13c225603Daniel Veillard         * segments to meet the criteria for the (e) and (f) cases).
1508d7af555327843a9938a913205ac703c13c225603Daniel Veillard         */
1509d7af555327843a9938a913205ac703c13c225603Daniel Veillard        if (segp[0] == '\0')
1510d7af555327843a9938a913205ac703c13c225603Daniel Veillard          break;
15113473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1512d7af555327843a9938a913205ac703c13c225603Daniel Veillard        /* If the first segment is "..", or if the next segment _isn't_ "..",
1513d7af555327843a9938a913205ac703c13c225603Daniel Veillard         * keep this segment and try the next one.
1514d7af555327843a9938a913205ac703c13c225603Daniel Veillard         */
1515d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ++segp;
1516d7af555327843a9938a913205ac703c13c225603Daniel Veillard        if (((cur[0] == '.') && (cur[1] == '.') && (segp == cur+3))
1517d7af555327843a9938a913205ac703c13c225603Daniel Veillard            || ((segp[0] != '.') || (segp[1] != '.')
1518d7af555327843a9938a913205ac703c13c225603Daniel Veillard                || ((segp[2] != '/') && (segp[2] != '\0')))) {
1519d7af555327843a9938a913205ac703c13c225603Daniel Veillard          cur = segp;
1520d7af555327843a9938a913205ac703c13c225603Daniel Veillard          continue;
15214def3bd94c4c34ad0b7b2848f7f43a62c9ea067cDaniel Veillard        }
15223473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1523d7af555327843a9938a913205ac703c13c225603Daniel Veillard        /* If we get here, remove this segment and the next one and back up
1524d7af555327843a9938a913205ac703c13c225603Daniel Veillard         * to the previous segment (if there is one), to implement the
1525d7af555327843a9938a913205ac703c13c225603Daniel Veillard         * "iteratively" clause.  It's pretty much impossible to back up
1526d7af555327843a9938a913205ac703c13c225603Daniel Veillard         * while maintaining two pointers into the buffer, so just compact
1527d7af555327843a9938a913205ac703c13c225603Daniel Veillard         * the whole buffer now.
15284def3bd94c4c34ad0b7b2848f7f43a62c9ea067cDaniel Veillard         */
15293473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1530d7af555327843a9938a913205ac703c13c225603Daniel Veillard        /* If this is the end of the buffer, we're done.  */
1531d7af555327843a9938a913205ac703c13c225603Daniel Veillard        if (segp[2] == '\0') {
1532d7af555327843a9938a913205ac703c13c225603Daniel Veillard          cur[0] = '\0';
1533d7af555327843a9938a913205ac703c13c225603Daniel Veillard          break;
15344def3bd94c4c34ad0b7b2848f7f43a62c9ea067cDaniel Veillard        }
1535d7af555327843a9938a913205ac703c13c225603Daniel Veillard        /* Valgrind complained, strcpy(cur, segp + 3); */
1536cedf84d35ab127dd24f9bcbf8b8339518d0e8928Nico Weber        /* string will overlap, do not use strcpy */
1537cedf84d35ab127dd24f9bcbf8b8339518d0e8928Nico Weber        tmp = cur;
1538cedf84d35ab127dd24f9bcbf8b8339518d0e8928Nico Weber        segp += 3;
1539cedf84d35ab127dd24f9bcbf8b8339518d0e8928Nico Weber        while ((*tmp++ = *segp++) != 0)
1540cedf84d35ab127dd24f9bcbf8b8339518d0e8928Nico Weber          ;
15413473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1542d7af555327843a9938a913205ac703c13c225603Daniel Veillard        /* If there are no previous segments, then keep going from here.  */
1543d7af555327843a9938a913205ac703c13c225603Daniel Veillard        segp = cur;
1544d7af555327843a9938a913205ac703c13c225603Daniel Veillard        while ((segp > path) && ((--segp)[0] == '/'))
1545d7af555327843a9938a913205ac703c13c225603Daniel Veillard          ;
1546d7af555327843a9938a913205ac703c13c225603Daniel Veillard        if (segp == path)
1547d7af555327843a9938a913205ac703c13c225603Daniel Veillard          continue;
15483473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1549d7af555327843a9938a913205ac703c13c225603Daniel Veillard        /* "segp" is pointing to the end of a previous segment; find it's
1550d7af555327843a9938a913205ac703c13c225603Daniel Veillard         * start.  We need to back up to the previous segment and start
1551d7af555327843a9938a913205ac703c13c225603Daniel Veillard         * over with that to handle things like "foo/bar/../..".  If we
1552d7af555327843a9938a913205ac703c13c225603Daniel Veillard         * don't do this, then on the first pass we'll remove the "bar/..",
1553d7af555327843a9938a913205ac703c13c225603Daniel Veillard         * but be pointing at the second ".." so we won't realize we can also
1554d7af555327843a9938a913205ac703c13c225603Daniel Veillard         * remove the "foo/..".
1555d7af555327843a9938a913205ac703c13c225603Daniel Veillard         */
1556d7af555327843a9938a913205ac703c13c225603Daniel Veillard        cur = segp;
1557d7af555327843a9938a913205ac703c13c225603Daniel Veillard        while ((cur > path) && (cur[-1] != '/'))
1558d7af555327843a9938a913205ac703c13c225603Daniel Veillard          --cur;
1559d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
1560d7af555327843a9938a913205ac703c13c225603Daniel Veillard    out[0] = '\0';
15613473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
15623473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    /*
1563d7af555327843a9938a913205ac703c13c225603Daniel Veillard     * g) If the resulting buffer string still begins with one or more
1564d7af555327843a9938a913205ac703c13c225603Daniel Veillard     *    complete path segments of "..", then the reference is
1565d7af555327843a9938a913205ac703c13c225603Daniel Veillard     *    considered to be in error. Implementations may handle this
1566d7af555327843a9938a913205ac703c13c225603Daniel Veillard     *    error by retaining these components in the resolved path (i.e.,
1567d7af555327843a9938a913205ac703c13c225603Daniel Veillard     *    treating them as part of the final URI), by removing them from
1568d7af555327843a9938a913205ac703c13c225603Daniel Veillard     *    the resolved path (i.e., discarding relative levels above the
1569d7af555327843a9938a913205ac703c13c225603Daniel Veillard     *    root), or by avoiding traversal of the reference.
1570d7af555327843a9938a913205ac703c13c225603Daniel Veillard     *
1571d7af555327843a9938a913205ac703c13c225603Daniel Veillard     * We discard them from the final path.
15723473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     */
1573d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (path[0] == '/') {
1574d7af555327843a9938a913205ac703c13c225603Daniel Veillard      cur = path;
1575d7af555327843a9938a913205ac703c13c225603Daniel Veillard      while ((cur[0] == '/') && (cur[1] == '.') && (cur[2] == '.')
1576d7af555327843a9938a913205ac703c13c225603Daniel Veillard             && ((cur[3] == '/') || (cur[3] == '\0')))
1577d7af555327843a9938a913205ac703c13c225603Daniel Veillard	cur += 3;
15783473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1579d7af555327843a9938a913205ac703c13c225603Daniel Veillard      if (cur != path) {
1580d7af555327843a9938a913205ac703c13c225603Daniel Veillard	out = path;
1581d7af555327843a9938a913205ac703c13c225603Daniel Veillard	while (cur[0] != '\0')
1582d7af555327843a9938a913205ac703c13c225603Daniel Veillard          (out++)[0] = (cur++)[0];
1583d7af555327843a9938a913205ac703c13c225603Daniel Veillard	out[0] = 0;
1584d7af555327843a9938a913205ac703c13c225603Daniel Veillard      }
15853473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
15863473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
15873473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    return(0);
15883473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor}
15893473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1590d7af555327843a9938a913205ac703c13c225603Daniel Veillardstatic int is_hex(char c) {
1591d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (((c >= '0') && (c <= '9')) ||
1592d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ((c >= 'a') && (c <= 'f')) ||
1593d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ((c >= 'A') && (c <= 'F')))
15943473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	return(1);
1595d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return(0);
15963473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor}
15973473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
15983473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/**
1599d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlURIUnescapeString:
1600d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  the string to unescape
1601d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @len:   the length in bytes to unescape (or <= 0 to indicate full string)
1602d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @target:  optional destination buffer
16033473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
1604d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Unescaping routine, but does not check that the string is an URI. The
1605d7af555327843a9938a913205ac703c13c225603Daniel Veillard * output is a direct unsigned char translation of %XX values (no encoding)
1606d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Note that the length of the result can only be smaller or same size as
1607d7af555327843a9938a913205ac703c13c225603Daniel Veillard * the input string.
16083473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
1609d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns a copy of the string, but unescaped, will return NULL only in case
1610d7af555327843a9938a913205ac703c13c225603Daniel Veillard * of error
16113473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
1612d7af555327843a9938a913205ac703c13c225603Daniel Veillardchar *
1613d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlURIUnescapeString(const char *str, int len, char *target) {
1614d7af555327843a9938a913205ac703c13c225603Daniel Veillard    char *ret, *out;
1615d7af555327843a9938a913205ac703c13c225603Daniel Veillard    const char *in;
16163473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
16173473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if (str == NULL)
1618d7af555327843a9938a913205ac703c13c225603Daniel Veillard	return(NULL);
1619d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (len <= 0) len = strlen(str);
1620d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (len < 0) return(NULL);
1621d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1622d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (target == NULL) {
1623d7af555327843a9938a913205ac703c13c225603Daniel Veillard	ret = (char *) xmlMallocAtomic(len + 1);
1624d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (ret == NULL) {
162557560386503be0fd023f3b7537fd496784f3be18Daniel Veillard            xmlURIErrMemory("unescaping URI value\n");
1626d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    return(NULL);
16273473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	}
1628d7af555327843a9938a913205ac703c13c225603Daniel Veillard    } else
1629d7af555327843a9938a913205ac703c13c225603Daniel Veillard	ret = target;
1630d7af555327843a9938a913205ac703c13c225603Daniel Veillard    in = str;
1631d7af555327843a9938a913205ac703c13c225603Daniel Veillard    out = ret;
1632d7af555327843a9938a913205ac703c13c225603Daniel Veillard    while(len > 0) {
1633d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if ((len > 2) && (*in == '%') && (is_hex(in[1])) && (is_hex(in[2]))) {
1634d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    in++;
163557560386503be0fd023f3b7537fd496784f3be18Daniel Veillard	    if ((*in >= '0') && (*in <= '9'))
1636d7af555327843a9938a913205ac703c13c225603Daniel Veillard	        *out = (*in - '0');
1637d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    else if ((*in >= 'a') && (*in <= 'f'))
1638d7af555327843a9938a913205ac703c13c225603Daniel Veillard	        *out = (*in - 'a') + 10;
1639d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    else if ((*in >= 'A') && (*in <= 'F'))
1640d7af555327843a9938a913205ac703c13c225603Daniel Veillard	        *out = (*in - 'A') + 10;
1641d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    in++;
164257560386503be0fd023f3b7537fd496784f3be18Daniel Veillard	    if ((*in >= '0') && (*in <= '9'))
1643d7af555327843a9938a913205ac703c13c225603Daniel Veillard	        *out = *out * 16 + (*in - '0');
1644d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    else if ((*in >= 'a') && (*in <= 'f'))
1645d7af555327843a9938a913205ac703c13c225603Daniel Veillard	        *out = *out * 16 + (*in - 'a') + 10;
1646d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    else if ((*in >= 'A') && (*in <= 'F'))
1647d7af555327843a9938a913205ac703c13c225603Daniel Veillard	        *out = *out * 16 + (*in - 'A') + 10;
1648d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    in++;
1649d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    len -= 3;
1650d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    out++;
1651d7af555327843a9938a913205ac703c13c225603Daniel Veillard	} else {
1652d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    *out++ = *in++;
1653d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    len--;
16543473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	}
16553473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
1656d7af555327843a9938a913205ac703c13c225603Daniel Veillard    *out = 0;
16573473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    return(ret);
16583473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor}
16593473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
16603473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/**
1661d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlURIEscapeStr:
1662d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  string to escape
1663d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @list: exception list string of chars not to escape
16643473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
1665d7af555327843a9938a913205ac703c13c225603Daniel Veillard * This routine escapes a string to hex, ignoring reserved characters (a-z)
1666d7af555327843a9938a913205ac703c13c225603Daniel Veillard * and the characters in the exception list.
16673473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
1668d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns a new escaped string or NULL in case of error.
16693473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
1670d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlChar *
1671d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlURIEscapeStr(const xmlChar *str, const xmlChar *list) {
1672d7af555327843a9938a913205ac703c13c225603Daniel Veillard    xmlChar *ret, ch;
1673d7af555327843a9938a913205ac703c13c225603Daniel Veillard    xmlChar *temp;
1674d7af555327843a9938a913205ac703c13c225603Daniel Veillard    const xmlChar *in;
167557560386503be0fd023f3b7537fd496784f3be18Daniel Veillard    int len, out;
16763473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
16773473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if (str == NULL)
1678d7af555327843a9938a913205ac703c13c225603Daniel Veillard	return(NULL);
1679d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (str[0] == 0)
1680d7af555327843a9938a913205ac703c13c225603Daniel Veillard	return(xmlStrdup(str));
1681d7af555327843a9938a913205ac703c13c225603Daniel Veillard    len = xmlStrlen(str);
1682d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (!(len > 0)) return(NULL);
16833473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1684d7af555327843a9938a913205ac703c13c225603Daniel Veillard    len += 20;
1685d7af555327843a9938a913205ac703c13c225603Daniel Veillard    ret = (xmlChar *) xmlMallocAtomic(len);
1686d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (ret == NULL) {
168757560386503be0fd023f3b7537fd496784f3be18Daniel Veillard        xmlURIErrMemory("escaping URI value\n");
1688d7af555327843a9938a913205ac703c13c225603Daniel Veillard	return(NULL);
16893473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
1690d7af555327843a9938a913205ac703c13c225603Daniel Veillard    in = (const xmlChar *) str;
1691d7af555327843a9938a913205ac703c13c225603Daniel Veillard    out = 0;
1692d7af555327843a9938a913205ac703c13c225603Daniel Veillard    while(*in != 0) {
1693d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if (len - out <= 3) {
169457560386503be0fd023f3b7537fd496784f3be18Daniel Veillard            temp = xmlSaveUriRealloc(ret, &len);
1695d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    if (temp == NULL) {
169657560386503be0fd023f3b7537fd496784f3be18Daniel Veillard                xmlURIErrMemory("escaping URI value\n");
1697d7af555327843a9938a913205ac703c13c225603Daniel Veillard		xmlFree(ret);
1698d7af555327843a9938a913205ac703c13c225603Daniel Veillard		return(NULL);
1699d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    }
1700d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    ret = temp;
1701d7af555327843a9938a913205ac703c13c225603Daniel Veillard	}
1702d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1703d7af555327843a9938a913205ac703c13c225603Daniel Veillard	ch = *in;
1704d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1705d7af555327843a9938a913205ac703c13c225603Daniel Veillard	if ((ch != '@') && (!IS_UNRESERVED(ch)) && (!xmlStrchr(list, ch))) {
1706d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    unsigned char val;
1707d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    ret[out++] = '%';
1708d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    val = ch >> 4;
1709d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    if (val <= 9)
1710d7af555327843a9938a913205ac703c13c225603Daniel Veillard		ret[out++] = '0' + val;
1711d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    else
1712d7af555327843a9938a913205ac703c13c225603Daniel Veillard		ret[out++] = 'A' + val - 0xA;
1713d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    val = ch & 0xF;
1714d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    if (val <= 9)
1715d7af555327843a9938a913205ac703c13c225603Daniel Veillard		ret[out++] = '0' + val;
1716d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    else
1717d7af555327843a9938a913205ac703c13c225603Daniel Veillard		ret[out++] = 'A' + val - 0xA;
1718d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    in++;
1719d7af555327843a9938a913205ac703c13c225603Daniel Veillard	} else {
1720d7af555327843a9938a913205ac703c13c225603Daniel Veillard	    ret[out++] = *in++;
1721d7af555327843a9938a913205ac703c13c225603Daniel Veillard	}
17223473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
17233473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
1724d7af555327843a9938a913205ac703c13c225603Daniel Veillard    ret[out] = 0;
1725d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return(ret);
17263473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor}
17273473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
17283473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/**
1729d7af555327843a9938a913205ac703c13c225603Daniel Veillard * xmlURIEscape:
1730d7af555327843a9938a913205ac703c13c225603Daniel Veillard * @str:  the string of the URI to escape
17313473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
1732d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Escaping routine, does not do validity checks !
1733d7af555327843a9938a913205ac703c13c225603Daniel Veillard * It will try to escape the chars needing this, but this is heuristic
1734d7af555327843a9938a913205ac703c13c225603Daniel Veillard * based it's impossible to be sure.
17353473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
1736d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Returns an copy of the string, but escaped
1737d7af555327843a9938a913205ac703c13c225603Daniel Veillard *
1738d7af555327843a9938a913205ac703c13c225603Daniel Veillard * 25 May 2001
1739d7af555327843a9938a913205ac703c13c225603Daniel Veillard * Uses xmlParseURI and xmlURIEscapeStr to try to escape correctly
1740d7af555327843a9938a913205ac703c13c225603Daniel Veillard * according to RFC2396.
1741d7af555327843a9938a913205ac703c13c225603Daniel Veillard *   - Carl Douglas
17423473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
1743d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlChar *
1744d7af555327843a9938a913205ac703c13c225603Daniel VeillardxmlURIEscape(const xmlChar * str)
1745d7af555327843a9938a913205ac703c13c225603Daniel Veillard{
1746d7af555327843a9938a913205ac703c13c225603Daniel Veillard    xmlChar *ret, *segment = NULL;
17473473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    xmlURIPtr uri;
1748d7af555327843a9938a913205ac703c13c225603Daniel Veillard    int ret2;
1749d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1750d7af555327843a9938a913205ac703c13c225603Daniel Veillard#define NULLCHK(p) if(!p) { \
175157560386503be0fd023f3b7537fd496784f3be18Daniel Veillard         xmlURIErrMemory("escaping URI value\n"); \
175257560386503be0fd023f3b7537fd496784f3be18Daniel Veillard         xmlFreeURI(uri); \
175357560386503be0fd023f3b7537fd496784f3be18Daniel Veillard         return NULL; } \
17543473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
17553473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if (str == NULL)
1756d7af555327843a9938a913205ac703c13c225603Daniel Veillard        return (NULL);
1757d7af555327843a9938a913205ac703c13c225603Daniel Veillard
17583473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    uri = xmlCreateURI();
17593473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if (uri != NULL) {
1760d7af555327843a9938a913205ac703c13c225603Daniel Veillard	/*
1761d7af555327843a9938a913205ac703c13c225603Daniel Veillard	 * Allow escaping errors in the unescaped form
1762d7af555327843a9938a913205ac703c13c225603Daniel Veillard	 */
1763d7af555327843a9938a913205ac703c13c225603Daniel Veillard        uri->cleanup = 1;
1764d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret2 = xmlParseURIReference(uri, (const char *)str);
1765d7af555327843a9938a913205ac703c13c225603Daniel Veillard        if (ret2) {
1766d7af555327843a9938a913205ac703c13c225603Daniel Veillard            xmlFreeURI(uri);
1767d7af555327843a9938a913205ac703c13c225603Daniel Veillard            return (NULL);
1768d7af555327843a9938a913205ac703c13c225603Daniel Veillard        }
17693473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
17703473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
1771d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (!uri)
1772d7af555327843a9938a913205ac703c13c225603Daniel Veillard        return NULL;
1773336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard
1774d7af555327843a9938a913205ac703c13c225603Daniel Veillard    ret = NULL;
1775d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1776d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->scheme) {
1777d7af555327843a9938a913205ac703c13c225603Daniel Veillard        segment = xmlURIEscapeStr(BAD_CAST uri->scheme, BAD_CAST "+-.");
1778d7af555327843a9938a913205ac703c13c225603Daniel Veillard        NULLCHK(segment)
1779d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret = xmlStrcat(ret, segment);
1780d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret = xmlStrcat(ret, BAD_CAST ":");
1781d7af555327843a9938a913205ac703c13c225603Daniel Veillard        xmlFree(segment);
1782336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard    }
1783d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1784d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->authority) {
1785d7af555327843a9938a913205ac703c13c225603Daniel Veillard        segment =
1786d7af555327843a9938a913205ac703c13c225603Daniel Veillard            xmlURIEscapeStr(BAD_CAST uri->authority, BAD_CAST "/?;:@");
1787d7af555327843a9938a913205ac703c13c225603Daniel Veillard        NULLCHK(segment)
1788d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret = xmlStrcat(ret, BAD_CAST "//");
1789d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret = xmlStrcat(ret, segment);
1790d7af555327843a9938a913205ac703c13c225603Daniel Veillard        xmlFree(segment);
1791d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
1792d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1793d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->user) {
1794d7af555327843a9938a913205ac703c13c225603Daniel Veillard        segment = xmlURIEscapeStr(BAD_CAST uri->user, BAD_CAST ";:&=+$,");
1795d7af555327843a9938a913205ac703c13c225603Daniel Veillard        NULLCHK(segment)
179657560386503be0fd023f3b7537fd496784f3be18Daniel Veillard		ret = xmlStrcat(ret,BAD_CAST "//");
1797d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret = xmlStrcat(ret, segment);
1798d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret = xmlStrcat(ret, BAD_CAST "@");
1799d7af555327843a9938a913205ac703c13c225603Daniel Veillard        xmlFree(segment);
1800d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
1801d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1802d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->server) {
1803d7af555327843a9938a913205ac703c13c225603Daniel Veillard        segment = xmlURIEscapeStr(BAD_CAST uri->server, BAD_CAST "/?;:@");
1804d7af555327843a9938a913205ac703c13c225603Daniel Veillard        NULLCHK(segment)
1805d7af555327843a9938a913205ac703c13c225603Daniel Veillard		if (uri->user == NULL)
1806d7af555327843a9938a913205ac703c13c225603Daniel Veillard		ret = xmlStrcat(ret, BAD_CAST "//");
1807d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret = xmlStrcat(ret, segment);
1808d7af555327843a9938a913205ac703c13c225603Daniel Veillard        xmlFree(segment);
1809d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
1810d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1811d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->port) {
1812d7af555327843a9938a913205ac703c13c225603Daniel Veillard        xmlChar port[10];
1813d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1814d7af555327843a9938a913205ac703c13c225603Daniel Veillard        snprintf((char *) port, 10, "%d", uri->port);
1815d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret = xmlStrcat(ret, BAD_CAST ":");
1816d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret = xmlStrcat(ret, port);
1817d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
1818d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1819d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->path) {
1820d7af555327843a9938a913205ac703c13c225603Daniel Veillard        segment =
1821d7af555327843a9938a913205ac703c13c225603Daniel Veillard            xmlURIEscapeStr(BAD_CAST uri->path, BAD_CAST ":@&=+$,/?;");
1822d7af555327843a9938a913205ac703c13c225603Daniel Veillard        NULLCHK(segment)
1823d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret = xmlStrcat(ret, segment);
1824d7af555327843a9938a913205ac703c13c225603Daniel Veillard        xmlFree(segment);
1825d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
1826d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1827d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->query_raw) {
1828d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret = xmlStrcat(ret, BAD_CAST "?");
1829d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret = xmlStrcat(ret, BAD_CAST uri->query_raw);
1830d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
1831d7af555327843a9938a913205ac703c13c225603Daniel Veillard    else if (uri->query) {
1832d7af555327843a9938a913205ac703c13c225603Daniel Veillard        segment =
1833d7af555327843a9938a913205ac703c13c225603Daniel Veillard            xmlURIEscapeStr(BAD_CAST uri->query, BAD_CAST ";/?:@&=+,$");
1834d7af555327843a9938a913205ac703c13c225603Daniel Veillard        NULLCHK(segment)
1835d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret = xmlStrcat(ret, BAD_CAST "?");
1836d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret = xmlStrcat(ret, segment);
1837d7af555327843a9938a913205ac703c13c225603Daniel Veillard        xmlFree(segment);
1838d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
1839d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1840d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->opaque) {
1841d7af555327843a9938a913205ac703c13c225603Daniel Veillard        segment = xmlURIEscapeStr(BAD_CAST uri->opaque, BAD_CAST "");
1842d7af555327843a9938a913205ac703c13c225603Daniel Veillard        NULLCHK(segment)
1843d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret = xmlStrcat(ret, segment);
1844d7af555327843a9938a913205ac703c13c225603Daniel Veillard        xmlFree(segment);
1845d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
1846d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1847d7af555327843a9938a913205ac703c13c225603Daniel Veillard    if (uri->fragment) {
1848d7af555327843a9938a913205ac703c13c225603Daniel Veillard        segment = xmlURIEscapeStr(BAD_CAST uri->fragment, BAD_CAST "#");
1849d7af555327843a9938a913205ac703c13c225603Daniel Veillard        NULLCHK(segment)
1850d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret = xmlStrcat(ret, BAD_CAST "#");
1851d7af555327843a9938a913205ac703c13c225603Daniel Veillard        ret = xmlStrcat(ret, segment);
1852d7af555327843a9938a913205ac703c13c225603Daniel Veillard        xmlFree(segment);
1853d7af555327843a9938a913205ac703c13c225603Daniel Veillard    }
1854d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1855d7af555327843a9938a913205ac703c13c225603Daniel Veillard    xmlFreeURI(uri);
1856d7af555327843a9938a913205ac703c13c225603Daniel Veillard#undef NULLCHK
1857d7af555327843a9938a913205ac703c13c225603Daniel Veillard
1858d7af555327843a9938a913205ac703c13c225603Daniel Veillard    return (ret);
1859336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard}
1860336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard
18613473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/************************************************************************
18623473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *									*
18633473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *			Public functions				*
18643473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *									*
18653473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor ************************************************************************/
18663473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
18673473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor/**
18683473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor * xmlBuildURI:
18693473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor * @URI:  the URI instance found in the document
18703473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor * @base:  the base value
18713473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
18723473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor * Computes he final URI of the reference done by checking that
18733473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor * the given URI is valid, and building the final URI using the
187457560386503be0fd023f3b7537fd496784f3be18Daniel Veillard * base URI. This is processed according to section 5.2 of the
18753473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor * RFC 2396
18763473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
18773473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor * 5.2. Resolving Relative References to Absolute Form
18783473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *
18793473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor * Returns a new URI string (to be freed by the caller) or NULL in case
18803473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor *         of error.
18813473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor */
18823473f88a7abdf4e585e267288fb77e898c580d2bOwen TaylorxmlChar *
18833473f88a7abdf4e585e267288fb77e898c580d2bOwen TaylorxmlBuildURI(const xmlChar *URI, const xmlChar *base) {
18843473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    xmlChar *val = NULL;
188556a4cb8c4d3eab4ab3295a61c87e8e92483922c6Daniel Veillard    int ret, len, indx, cur, out;
18863473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    xmlURIPtr ref = NULL;
18873473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    xmlURIPtr bas = NULL;
18883473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    xmlURIPtr res = NULL;
18893473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
18903473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    /*
18913473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     * 1) The URI reference is parsed into the potential four components and
18923473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    fragment identifier, as described in Section 4.3.
18933473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *
18943473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    NOTE that a completely empty URI is treated by modern browsers
18953473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    as a reference to "." rather than as a synonym for the current
18963473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    URI.  Should we do that here?
18973473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     */
189857560386503be0fd023f3b7537fd496784f3be18Daniel Veillard    if (URI == NULL)
18993473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	ret = -1;
19003473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    else {
19013473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	if (*URI) {
19023473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    ref = xmlCreateURI();
19033473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    if (ref == NULL)
19043473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor		goto done;
19053473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    ret = xmlParseURIReference(ref, (const char *) URI);
19063473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	}
19073473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	else
19083473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    ret = 0;
19093473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
19103473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if (ret != 0)
19113473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	goto done;
19127b4b2f9d8fc712c49beaf75985161a130c77d13aDaniel Veillard    if ((ref != NULL) && (ref->scheme != NULL)) {
19137b4b2f9d8fc712c49beaf75985161a130c77d13aDaniel Veillard	/*
19147b4b2f9d8fc712c49beaf75985161a130c77d13aDaniel Veillard	 * The URI is absolute don't modify.
19157b4b2f9d8fc712c49beaf75985161a130c77d13aDaniel Veillard	 */
19167b4b2f9d8fc712c49beaf75985161a130c77d13aDaniel Veillard	val = xmlStrdup(URI);
19177b4b2f9d8fc712c49beaf75985161a130c77d13aDaniel Veillard	goto done;
19187b4b2f9d8fc712c49beaf75985161a130c77d13aDaniel Veillard    }
19193473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if (base == NULL)
19203473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	ret = -1;
19213473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    else {
19223473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	bas = xmlCreateURI();
19233473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	if (bas == NULL)
19243473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    goto done;
19253473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	ret = xmlParseURIReference(bas, (const char *) base);
19263473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
19273473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if (ret != 0) {
19283473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	if (ref)
19293473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    val = xmlSaveUri(ref);
19303473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	goto done;
19313473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
19323473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if (ref == NULL) {
19333473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	/*
19343473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	 * the base fragment must be ignored
19353473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	 */
19363473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	if (bas->fragment != NULL) {
19373473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    xmlFree(bas->fragment);
19383473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    bas->fragment = NULL;
19393473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	}
19403473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	val = xmlSaveUri(bas);
19413473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	goto done;
19423473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
19433473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
19443473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    /*
19453473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     * 2) If the path component is empty and the scheme, authority, and
19463473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    query components are undefined, then it is a reference to the
19473473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    current document and we are done.  Otherwise, the reference URI's
19483473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    query and fragment components are defined as found (or not found)
19493473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    within the URI reference and not inherited from the base URI.
19503473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *
19513473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    NOTE that in modern browsers, the parsing differs from the above
19523473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    in the following aspect:  the query component is allowed to be
19533473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    defined while still treating this as a reference to the current
19543473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    document.
19553473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     */
19563473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    res = xmlCreateURI();
19573473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if (res == NULL)
19583473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	goto done;
19593473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if ((ref->scheme == NULL) && (ref->path == NULL) &&
19603473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	((ref->authority == NULL) && (ref->server == NULL))) {
19613473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	if (bas->scheme != NULL)
19623473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    res->scheme = xmlMemStrdup(bas->scheme);
19633473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	if (bas->authority != NULL)
19643473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    res->authority = xmlMemStrdup(bas->authority);
19653473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	else if (bas->server != NULL) {
19663473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    res->server = xmlMemStrdup(bas->server);
19673473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    if (bas->user != NULL)
19683473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor		res->user = xmlMemStrdup(bas->user);
196957560386503be0fd023f3b7537fd496784f3be18Daniel Veillard	    res->port = bas->port;
19703473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	}
19713473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	if (bas->path != NULL)
19723473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    res->path = xmlMemStrdup(bas->path);
1973a1413b84f7163d57c6251d5f4251186368efd859Daniel Veillard	if (ref->query_raw != NULL)
1974a1413b84f7163d57c6251d5f4251186368efd859Daniel Veillard	    res->query_raw = xmlMemStrdup (ref->query_raw);
1975a1413b84f7163d57c6251d5f4251186368efd859Daniel Veillard	else if (ref->query != NULL)
19763473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    res->query = xmlMemStrdup(ref->query);
1977a1413b84f7163d57c6251d5f4251186368efd859Daniel Veillard	else if (bas->query_raw != NULL)
1978a1413b84f7163d57c6251d5f4251186368efd859Daniel Veillard	    res->query_raw = xmlMemStrdup(bas->query_raw);
19793473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	else if (bas->query != NULL)
19803473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    res->query = xmlMemStrdup(bas->query);
19813473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	if (ref->fragment != NULL)
19823473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    res->fragment = xmlMemStrdup(ref->fragment);
19833473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	goto step_7;
19843473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
19853473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
19863473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    /*
19873473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     * 3) If the scheme component is defined, indicating that the reference
19883473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    starts with a scheme name, then the reference is interpreted as an
19893473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    absolute URI and we are done.  Otherwise, the reference URI's
19903473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    scheme is inherited from the base URI's scheme component.
19913473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     */
19923473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if (ref->scheme != NULL) {
19933473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	val = xmlSaveUri(ref);
19943473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	goto done;
19953473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
19963473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if (bas->scheme != NULL)
19973473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	res->scheme = xmlMemStrdup(bas->scheme);
199857560386503be0fd023f3b7537fd496784f3be18Daniel Veillard
1999a1413b84f7163d57c6251d5f4251186368efd859Daniel Veillard    if (ref->query_raw != NULL)
2000a1413b84f7163d57c6251d5f4251186368efd859Daniel Veillard	res->query_raw = xmlMemStrdup(ref->query_raw);
2001a1413b84f7163d57c6251d5f4251186368efd859Daniel Veillard    else if (ref->query != NULL)
20029231ff9250af7e22104cc5e9406f0dd43e86aec0Daniel Veillard	res->query = xmlMemStrdup(ref->query);
20039231ff9250af7e22104cc5e9406f0dd43e86aec0Daniel Veillard    if (ref->fragment != NULL)
20049231ff9250af7e22104cc5e9406f0dd43e86aec0Daniel Veillard	res->fragment = xmlMemStrdup(ref->fragment);
20053473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
20063473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    /*
20073473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     * 4) If the authority component is defined, then the reference is a
20083473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    network-path and we skip to step 7.  Otherwise, the reference
20093473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    URI's authority is inherited from the base URI's authority
20103473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    component, which will also be undefined if the URI scheme does not
20113473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    use an authority component.
20123473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     */
20133473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if ((ref->authority != NULL) || (ref->server != NULL)) {
20143473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	if (ref->authority != NULL)
20153473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    res->authority = xmlMemStrdup(ref->authority);
20163473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	else {
20173473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    res->server = xmlMemStrdup(ref->server);
20183473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    if (ref->user != NULL)
20193473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor		res->user = xmlMemStrdup(ref->user);
202057560386503be0fd023f3b7537fd496784f3be18Daniel Veillard            res->port = ref->port;
20213473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	}
20223473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	if (ref->path != NULL)
20233473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    res->path = xmlMemStrdup(ref->path);
20243473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	goto step_7;
20253473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
20263473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if (bas->authority != NULL)
20273473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	res->authority = xmlMemStrdup(bas->authority);
20283473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    else if (bas->server != NULL) {
20293473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	res->server = xmlMemStrdup(bas->server);
20303473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	if (bas->user != NULL)
20313473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    res->user = xmlMemStrdup(bas->user);
203257560386503be0fd023f3b7537fd496784f3be18Daniel Veillard	res->port = bas->port;
20333473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
20343473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
20353473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    /*
20363473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     * 5) If the path component begins with a slash character ("/"), then
20373473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    the reference is an absolute-path and we skip to step 7.
20383473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     */
20393473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if ((ref->path != NULL) && (ref->path[0] == '/')) {
20403473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	res->path = xmlMemStrdup(ref->path);
20413473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	goto step_7;
20423473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
20433473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
20443473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
20453473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    /*
20463473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     * 6) If this step is reached, then we are resolving a relative-path
20473473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    reference.  The relative path needs to be merged with the base
20483473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    URI's path.  Although there are many ways to do this, we will
20493473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    describe a simple method using a separate string buffer.
20503473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *
20513473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     * Allocate a buffer large enough for the result string.
20523473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     */
20533473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    len = 2; /* extra / and 0 */
20543473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if (ref->path != NULL)
20553473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	len += strlen(ref->path);
20563473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if (bas->path != NULL)
20573473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	len += strlen(bas->path);
20583c908dca479ed50dca24b8593bca90e40dbde6b8Daniel Veillard    res->path = (char *) xmlMallocAtomic(len);
20593473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if (res->path == NULL) {
206057560386503be0fd023f3b7537fd496784f3be18Daniel Veillard        xmlURIErrMemory("resolving URI against base\n");
20613473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	goto done;
20623473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
20633473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    res->path[0] = 0;
20643473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
20653473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    /*
20663473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     * a) All but the last segment of the base URI's path component is
20673473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    copied to the buffer.  In other words, any characters after the
20683473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    last (right-most) slash character, if any, are excluded.
20693473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     */
20703473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    cur = 0;
20713473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    out = 0;
20723473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if (bas->path != NULL) {
20733473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	while (bas->path[cur] != 0) {
20743473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    while ((bas->path[cur] != 0) && (bas->path[cur] != '/'))
20753473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor		cur++;
20763473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    if (bas->path[cur] == 0)
20773473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor		break;
20783473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
20793473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    cur++;
20803473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    while (out < cur) {
20813473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor		res->path[out] = bas->path[out];
20823473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor		out++;
20833473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    }
20843473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	}
20853473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
20863473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    res->path[out] = 0;
20873473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
20883473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    /*
20893473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     * b) The reference's path component is appended to the buffer
20903473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    string.
20913473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     */
20923473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if (ref->path != NULL && ref->path[0] != 0) {
209356a4cb8c4d3eab4ab3295a61c87e8e92483922c6Daniel Veillard	indx = 0;
20943473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	/*
20953473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	 * Ensure the path includes a '/'
20963473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	 */
20973473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	if ((out == 0) && (bas->server != NULL))
20983473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	    res->path[out++] = '/';
209956a4cb8c4d3eab4ab3295a61c87e8e92483922c6Daniel Veillard	while (ref->path[indx] != 0) {
210056a4cb8c4d3eab4ab3295a61c87e8e92483922c6Daniel Veillard	    res->path[out++] = ref->path[indx++];
21013473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	}
21023473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    }
21033473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    res->path[out] = 0;
21043473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
21053473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    /*
21063473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     * Steps c) to h) are really path normalization steps
21073473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     */
21083473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    xmlNormalizeURIPath(res->path);
21093473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
21103473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylorstep_7:
21113473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
21123473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    /*
21133473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     * 7) The resulting URI components, including any inherited from the
21143473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    base URI, are recombined to give the absolute form of the URI
21153473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     *    reference.
21163473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor     */
21173473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    val = xmlSaveUri(res);
21183473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
21193473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylordone:
21203473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if (ref != NULL)
21213473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	xmlFreeURI(ref);
21223473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if (bas != NULL)
21233473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	xmlFreeURI(bas);
21243473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    if (res != NULL)
21253473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor	xmlFreeURI(res);
21263473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor    return(val);
21273473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor}
21283473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
2129f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic/**
2130f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack * xmlBuildRelativeURI:
2131f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack * @URI:  the URI reference under consideration
2132f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack * @base:  the base value
2133f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack *
2134f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack * Expresses the URI of the reference in terms relative to the
2135f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack * base.  Some examples of this operation include:
2136f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack *     base = "http://site1.com/docs/book1.html"
2137f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack *        URI input                        URI returned
2138f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack *     docs/pic1.gif                    pic1.gif
2139f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack *     docs/img/pic1.gif                img/pic1.gif
2140f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack *     img/pic1.gif                     ../img/pic1.gif
2141f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack *     http://site1.com/docs/pic1.gif   pic1.gif
2142f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack *     http://site2.com/docs/pic1.gif   http://site2.com/docs/pic1.gif
2143f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack *
2144f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack *     base = "docs/book1.html"
2145f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack *        URI input                        URI returned
2146f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack *     docs/pic1.gif                    pic1.gif
2147f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack *     docs/img/pic1.gif                img/pic1.gif
2148f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack *     img/pic1.gif                     ../img/pic1.gif
2149f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack *     http://site1.com/docs/pic1.gif   http://site1.com/docs/pic1.gif
2150f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack *
2151f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack *
2152f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack * Note: if the URI reference is really wierd or complicated, it may be
2153f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack *       worthwhile to first convert it into a "nice" one by calling
2154f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack *       xmlBuildURI (using 'base') before calling this routine,
2155f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack *       since this routine (for reasonable efficiency) assumes URI has
2156f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack *       already been through some validation.
2157f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack *
2158f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack * Returns a new URI string (to be freed by the caller) or NULL in case
2159f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack * error.
2160f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack */
2161f7789b13c59ef9d9e73047543c704c6ab21a6212William M. BrackxmlChar *
2162f7789b13c59ef9d9e73047543c704c6ab21a6212William M. BrackxmlBuildRelativeURI (const xmlChar * URI, const xmlChar * base)
2163f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack{
2164f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    xmlChar *val = NULL;
2165f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    int ret;
2166f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    int ix;
2167f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    int pos = 0;
2168f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    int nbslash = 0;
2169820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack    int len;
2170f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    xmlURIPtr ref = NULL;
2171f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    xmlURIPtr bas = NULL;
2172f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    xmlChar *bptr, *uptr, *vptr;
21730f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard    int remove_path = 0;
2174f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack
2175f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    if ((URI == NULL) || (*URI == 0))
2176f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack	return NULL;
2177f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack
2178f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    /*
2179f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack     * First parse URI into a standard form
2180f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack     */
2181f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    ref = xmlCreateURI ();
2182f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    if (ref == NULL)
2183f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack	return NULL;
218438c4b332c4ec2f0db5ee601abaa9b46ec2e272e2William M. Brack    /* If URI not already in "relative" form */
218538c4b332c4ec2f0db5ee601abaa9b46ec2e272e2William M. Brack    if (URI[0] != '.') {
218638c4b332c4ec2f0db5ee601abaa9b46ec2e272e2William M. Brack	ret = xmlParseURIReference (ref, (const char *) URI);
218738c4b332c4ec2f0db5ee601abaa9b46ec2e272e2William M. Brack	if (ret != 0)
218838c4b332c4ec2f0db5ee601abaa9b46ec2e272e2William M. Brack	    goto done;		/* Error in URI, return NULL */
218938c4b332c4ec2f0db5ee601abaa9b46ec2e272e2William M. Brack    } else
219038c4b332c4ec2f0db5ee601abaa9b46ec2e272e2William M. Brack	ref->path = (char *)xmlStrdup(URI);
2191f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack
2192f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    /*
2193f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack     * Next parse base into the same standard form
2194f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack     */
2195f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    if ((base == NULL) || (*base == 0)) {
2196f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack	val = xmlStrdup (URI);
2197f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack	goto done;
2198f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    }
2199f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    bas = xmlCreateURI ();
2200f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    if (bas == NULL)
2201f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack	goto done;
220238c4b332c4ec2f0db5ee601abaa9b46ec2e272e2William M. Brack    if (base[0] != '.') {
220338c4b332c4ec2f0db5ee601abaa9b46ec2e272e2William M. Brack	ret = xmlParseURIReference (bas, (const char *) base);
220438c4b332c4ec2f0db5ee601abaa9b46ec2e272e2William M. Brack	if (ret != 0)
220538c4b332c4ec2f0db5ee601abaa9b46ec2e272e2William M. Brack	    goto done;		/* Error in base, return NULL */
220638c4b332c4ec2f0db5ee601abaa9b46ec2e272e2William M. Brack    } else
220738c4b332c4ec2f0db5ee601abaa9b46ec2e272e2William M. Brack	bas->path = (char *)xmlStrdup(base);
2208f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack
2209f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    /*
2210f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack     * If the scheme / server on the URI differs from the base,
2211f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack     * just return the URI
2212f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack     */
2213f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    if ((ref->scheme != NULL) &&
22140f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard	((bas->scheme == NULL) ||
22150f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard	 (xmlStrcmp ((xmlChar *)bas->scheme, (xmlChar *)ref->scheme)) ||
22160f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard	 (xmlStrcmp ((xmlChar *)bas->server, (xmlChar *)ref->server)))) {
2217f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack	val = xmlStrdup (URI);
2218f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack	goto done;
2219f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    }
22200f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard    if (xmlStrEqual((xmlChar *)bas->path, (xmlChar *)ref->path)) {
22210f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard	val = xmlStrdup(BAD_CAST "");
22220f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard	goto done;
22230f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard    }
22240f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard    if (bas->path == NULL) {
22250f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard	val = xmlStrdup((xmlChar *)ref->path);
22260f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard	goto done;
22270f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard    }
22280f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard    if (ref->path == NULL) {
22290f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard        ref->path = (char *) "/";
22300f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard	remove_path = 1;
22310f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard    }
2232f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack
2233f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    /*
2234f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack     * At this point (at last!) we can compare the two paths
2235f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack     *
2236820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack     * First we take care of the special case where either of the
2237820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack     * two path components may be missing (bug 316224)
2238f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack     */
2239820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack    if (bas->path == NULL) {
2240820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	if (ref->path != NULL) {
22410f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard	    uptr = (xmlChar *) ref->path;
2242820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	    if (*uptr == '/')
2243820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack		uptr++;
2244504201966dbcc76b0d3c60d85e36133188620f6cWilliam M. Brack	    /* exception characters from xmlSaveUri */
2245504201966dbcc76b0d3c60d85e36133188620f6cWilliam M. Brack	    val = xmlURIEscapeStr(uptr, BAD_CAST "/;&=+$,");
2246820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	}
2247820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	goto done;
2248f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    }
2249820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack    bptr = (xmlChar *)bas->path;
2250820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack    if (ref->path == NULL) {
2251820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	for (ix = 0; bptr[ix] != 0; ix++) {
2252820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	    if (bptr[ix] == '/')
2253820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack		nbslash++;
2254820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	}
2255820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	uptr = NULL;
2256820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	len = 1;	/* this is for a string terminator only */
2257f2a657aa599bf9e9a1cbf4082ba885d177f05697William M. Brack    } else {
2258f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    /*
2259820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack     * Next we compare the two strings and find where they first differ
2260f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack     */
2261820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	if ((ref->path[pos] == '.') && (ref->path[pos+1] == '/'))
2262820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack            pos += 2;
2263820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	if ((*bptr == '.') && (bptr[1] == '/'))
2264820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack            bptr += 2;
2265820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	else if ((*bptr == '/') && (ref->path[pos] != '/'))
2266820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	    bptr++;
2267820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	while ((bptr[pos] == ref->path[pos]) && (bptr[pos] != 0))
2268820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	    pos++;
2269820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack
2270820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	if (bptr[pos] == ref->path[pos]) {
22710f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard	    val = xmlStrdup(BAD_CAST "");
2272820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	    goto done;		/* (I can't imagine why anyone would do this) */
2273820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	}
2274820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack
2275820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	/*
2276820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	 * In URI, "back up" to the last '/' encountered.  This will be the
2277820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	 * beginning of the "unique" suffix of URI
2278820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	 */
2279820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	ix = pos;
2280820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	if ((ref->path[ix] == '/') && (ix > 0))
2281820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	    ix--;
22820f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard	else if ((ref->path[ix] == 0) && (ix > 1) && (ref->path[ix - 1] == '/'))
22830f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard	    ix -= 2;
2284820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	for (; ix > 0; ix--) {
2285820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	    if (ref->path[ix] == '/')
2286820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack		break;
2287820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	}
2288820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	if (ix == 0) {
2289820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	    uptr = (xmlChar *)ref->path;
2290820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	} else {
2291820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	    ix++;
2292820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	    uptr = (xmlChar *)&ref->path[ix];
2293f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack	}
2294f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack
2295820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	/*
2296820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	 * In base, count the number of '/' from the differing point
2297820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	 */
2298820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	if (bptr[pos] != ref->path[pos]) {/* check for trivial URI == base */
2299820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	    for (; bptr[ix] != 0; ix++) {
2300820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack		if (bptr[ix] == '/')
2301820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack		    nbslash++;
2302820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	    }
2303820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	}
2304820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	len = xmlStrlen (uptr) + 1;
2305820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack    }
230657560386503be0fd023f3b7537fd496784f3be18Daniel Veillard
2307f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    if (nbslash == 0) {
2308820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	if (uptr != NULL)
2309504201966dbcc76b0d3c60d85e36133188620f6cWilliam M. Brack	    /* exception characters from xmlSaveUri */
2310504201966dbcc76b0d3c60d85e36133188620f6cWilliam M. Brack	    val = xmlURIEscapeStr(uptr, BAD_CAST "/;&=+$,");
2311f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack	goto done;
2312f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    }
2313f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack
2314f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    /*
2315f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack     * Allocate just enough space for the returned string -
2316f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack     * length of the remainder of the URI, plus enough space
2317f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack     * for the "../" groups, plus one for the terminator
2318f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack     */
2319820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack    val = (xmlChar *) xmlMalloc (len + 3 * nbslash);
2320f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    if (val == NULL) {
232157560386503be0fd023f3b7537fd496784f3be18Daniel Veillard        xmlURIErrMemory("building relative URI\n");
2322f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack	goto done;
2323f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    }
2324f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    vptr = val;
2325f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    /*
2326f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack     * Put in as many "../" as needed
2327f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack     */
2328f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    for (; nbslash>0; nbslash--) {
2329f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack	*vptr++ = '.';
2330f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack	*vptr++ = '.';
2331f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack	*vptr++ = '/';
2332f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    }
2333f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    /*
2334f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack     * Finish up with the end of the URI
2335f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack     */
23360f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard    if (uptr != NULL) {
23370f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard        if ((vptr > val) && (len > 0) &&
23380f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard	    (uptr[0] == '/') && (vptr[-1] == '/')) {
23390f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard	    memcpy (vptr, uptr + 1, len - 1);
23400f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard	    vptr[len - 2] = 0;
23410f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard	} else {
23420f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard	    memcpy (vptr, uptr, len);
23430f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard	    vptr[len - 1] = 0;
23440f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard	}
23450f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard    } else {
2346820d5ed74771a2efc2a7b42386b9710d4f129e48William M. Brack	vptr[len - 1] = 0;
23470f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard    }
2348f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack
2349504201966dbcc76b0d3c60d85e36133188620f6cWilliam M. Brack    /* escape the freshly-built path */
2350504201966dbcc76b0d3c60d85e36133188620f6cWilliam M. Brack    vptr = val;
2351504201966dbcc76b0d3c60d85e36133188620f6cWilliam M. Brack	/* exception characters from xmlSaveUri */
2352504201966dbcc76b0d3c60d85e36133188620f6cWilliam M. Brack    val = xmlURIEscapeStr(vptr, BAD_CAST "/;&=+$,");
2353504201966dbcc76b0d3c60d85e36133188620f6cWilliam M. Brack    xmlFree(vptr);
2354504201966dbcc76b0d3c60d85e36133188620f6cWilliam M. Brack
23550f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillarddone:
2356f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    /*
2357f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack     * Free the working variables
2358f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack     */
23590f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard    if (remove_path != 0)
23600f7b33101b1850f671e81b15f3aecc7a332c813fDaniel Veillard        ref->path = NULL;
2361f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    if (ref != NULL)
2362f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack	xmlFreeURI (ref);
2363f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    if (bas != NULL)
2364f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack	xmlFreeURI (bas);
2365f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack
2366f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack    return val;
2367f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack}
2368f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack
2369f7789b13c59ef9d9e73047543c704c6ab21a6212William M. Brack/**
2370f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic * xmlCanonicPath:
2371f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic * @path:  the resource locator in a filesystem notation
2372f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic *
237357560386503be0fd023f3b7537fd496784f3be18Daniel Veillard * Constructs a canonic path from the specified path.
2374f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic *
237557560386503be0fd023f3b7537fd496784f3be18Daniel Veillard * Returns a new canonic path, or a duplicate of the path parameter if the
2376f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic * construction fails. The caller is responsible for freeing the memory occupied
237757560386503be0fd023f3b7537fd496784f3be18Daniel Veillard * by the returned string. If there is insufficient memory available, or the
2378f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic * argument is NULL, the function returns NULL.
2379f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic */
238057560386503be0fd023f3b7537fd496784f3be18Daniel Veillard#define IS_WINDOWS_PATH(p)					\
2381f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic	((p != NULL) &&						\
2382f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic	 (((p[0] >= 'a') && (p[0] <= 'z')) ||			\
2383f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic	  ((p[0] >= 'A') && (p[0] <= 'Z'))) &&			\
2384f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic	 (p[1] == ':') && ((p[2] == '/') || (p[2] == '\\')))
2385b8efdda0a31947d5291fcb9221040fdab88dc549Daniel VeillardxmlChar *
2386f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor ZlatkovicxmlCanonicPath(const xmlChar *path)
2387f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic{
23882224227818b8196ea9250235038e069f6bc03a55William M. Brack/*
23892224227818b8196ea9250235038e069f6bc03a55William M. Brack * For Windows implementations, additional work needs to be done to
23902224227818b8196ea9250235038e069f6bc03a55William M. Brack * replace backslashes in pathnames with "forward slashes"
23912224227818b8196ea9250235038e069f6bc03a55William M. Brack */
239257560386503be0fd023f3b7537fd496784f3be18Daniel Veillard#if defined(_WIN32) && !defined(__CYGWIN__)
2393ce07616c089bf22653e31e2f7286cfdd8462857fIgor Zlatkovic    int len = 0;
2394ce07616c089bf22653e31e2f7286cfdd8462857fIgor Zlatkovic    int i = 0;
2395ce07616c089bf22653e31e2f7286cfdd8462857fIgor Zlatkovic    xmlChar *p = NULL;
2396c64b8e984c13a0d989dea436c13128b289a4d4d6Daniel Veillard#endif
2397f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic    xmlURIPtr uri;
2398336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard    xmlChar *ret;
2399336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard    const xmlChar *absuri;
2400f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic
2401f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic    if (path == NULL)
2402f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic	return(NULL);
240369f8a13e52d4d4afd34e7642ce99c9cd0fcd8f03Daniel Veillard
240455b899a23acfa2e1bb36026b50a8f7cb36dc4fdaMichael Stahl#if defined(_WIN32)
240555b899a23acfa2e1bb36026b50a8f7cb36dc4fdaMichael Stahl    /*
240655b899a23acfa2e1bb36026b50a8f7cb36dc4fdaMichael Stahl     * We must not change the backslashes to slashes if the the path
240755b899a23acfa2e1bb36026b50a8f7cb36dc4fdaMichael Stahl     * starts with \\?\
240855b899a23acfa2e1bb36026b50a8f7cb36dc4fdaMichael Stahl     * Those paths can be up to 32k characters long.
240955b899a23acfa2e1bb36026b50a8f7cb36dc4fdaMichael Stahl     * Was added specifically for OpenOffice, those paths can't be converted
241055b899a23acfa2e1bb36026b50a8f7cb36dc4fdaMichael Stahl     * to URIs anyway.
241155b899a23acfa2e1bb36026b50a8f7cb36dc4fdaMichael Stahl     */
241255b899a23acfa2e1bb36026b50a8f7cb36dc4fdaMichael Stahl    if ((path[0] == '\\') && (path[1] == '\\') && (path[2] == '?') &&
241355b899a23acfa2e1bb36026b50a8f7cb36dc4fdaMichael Stahl        (path[3] == '\\') )
241455b899a23acfa2e1bb36026b50a8f7cb36dc4fdaMichael Stahl	return xmlStrdup((const xmlChar *) path);
241555b899a23acfa2e1bb36026b50a8f7cb36dc4fdaMichael Stahl#endif
241655b899a23acfa2e1bb36026b50a8f7cb36dc4fdaMichael Stahl
241755b899a23acfa2e1bb36026b50a8f7cb36dc4fdaMichael Stahl	/* sanitize filename starting with // so it can be used as URI */
241869f8a13e52d4d4afd34e7642ce99c9cd0fcd8f03Daniel Veillard    if ((path[0] == '/') && (path[1] == '/') && (path[2] != '/'))
241969f8a13e52d4d4afd34e7642ce99c9cd0fcd8f03Daniel Veillard        path++;
242069f8a13e52d4d4afd34e7642ce99c9cd0fcd8f03Daniel Veillard
2421c64b8e984c13a0d989dea436c13128b289a4d4d6Daniel Veillard    if ((uri = xmlParseURI((const char *) path)) != NULL) {
2422f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic	xmlFreeURI(uri);
2423f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic	return xmlStrdup(path);
2424f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic    }
2425f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic
24262224227818b8196ea9250235038e069f6bc03a55William M. Brack    /* Check if this is an "absolute uri" */
2427336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard    absuri = xmlStrstr(path, BAD_CAST "://");
2428336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard    if (absuri != NULL) {
2429336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard        int l, j;
2430336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard	unsigned char c;
2431336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard	xmlChar *escURI;
2432336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard
2433336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard        /*
2434336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard	 * this looks like an URI where some parts have not been
24352224227818b8196ea9250235038e069f6bc03a55William M. Brack	 * escaped leading to a parsing problem.  Check that the first
2436336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard	 * part matches a protocol.
2437336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard	 */
2438336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard	l = absuri - path;
24392224227818b8196ea9250235038e069f6bc03a55William M. Brack	/* Bypass if first part (part before the '://') is > 20 chars */
2440336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard	if ((l <= 0) || (l > 20))
2441336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard	    goto path_processing;
24422224227818b8196ea9250235038e069f6bc03a55William M. Brack	/* Bypass if any non-alpha characters are present in first part */
2443336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard	for (j = 0;j < l;j++) {
2444336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard	    c = path[j];
2445336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard	    if (!(((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))))
2446336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard	        goto path_processing;
2447336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard	}
2448336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard
24492224227818b8196ea9250235038e069f6bc03a55William M. Brack	/* Escape all except the characters specified in the supplied path */
2450336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard        escURI = xmlURIEscapeStr(path, BAD_CAST ":/?_.#&;=");
2451336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard	if (escURI != NULL) {
24522224227818b8196ea9250235038e069f6bc03a55William M. Brack	    /* Try parsing the escaped path */
2453336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard	    uri = xmlParseURI((const char *) escURI);
24542224227818b8196ea9250235038e069f6bc03a55William M. Brack	    /* If successful, return the escaped string */
2455336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard	    if (uri != NULL) {
2456336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard	        xmlFreeURI(uri);
2457336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard		return escURI;
2458336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard	    }
2459336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard	}
2460336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard    }
2461336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard
2462336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillardpath_processing:
24632224227818b8196ea9250235038e069f6bc03a55William M. Brack/* For Windows implementations, replace backslashes with 'forward slashes' */
246457560386503be0fd023f3b7537fd496784f3be18Daniel Veillard#if defined(_WIN32) && !defined(__CYGWIN__)
2465336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard    /*
24662224227818b8196ea9250235038e069f6bc03a55William M. Brack     * Create a URI structure
2467336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard     */
2468f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic    uri = xmlCreateURI();
24692224227818b8196ea9250235038e069f6bc03a55William M. Brack    if (uri == NULL) {		/* Guard against 'out of memory' */
2470a76fe5ca11ebf9e9322dfcf7728dc55077086d43Daniel Veillard        return(NULL);
2471a76fe5ca11ebf9e9322dfcf7728dc55077086d43Daniel Veillard    }
2472f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic
2473f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic    len = xmlStrlen(path);
2474f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic    if ((len > 2) && IS_WINDOWS_PATH(path)) {
24752224227818b8196ea9250235038e069f6bc03a55William M. Brack        /* make the scheme 'file' */
2476f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic	uri->scheme = xmlStrdup(BAD_CAST "file");
24772224227818b8196ea9250235038e069f6bc03a55William M. Brack	/* allocate space for leading '/' + path + string terminator */
2478b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard	uri->path = xmlMallocAtomic(len + 2);
2479b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard	if (uri->path == NULL) {
24802224227818b8196ea9250235038e069f6bc03a55William M. Brack	    xmlFreeURI(uri);	/* Guard agains 'out of memory' */
2481b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard	    return(NULL);
2482b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard	}
24832224227818b8196ea9250235038e069f6bc03a55William M. Brack	/* Put in leading '/' plus path */
2484f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic	uri->path[0] = '/';
2485ce07616c089bf22653e31e2f7286cfdd8462857fIgor Zlatkovic	p = uri->path + 1;
2486ce07616c089bf22653e31e2f7286cfdd8462857fIgor Zlatkovic	strncpy(p, path, len + 1);
2487ce07616c089bf22653e31e2f7286cfdd8462857fIgor Zlatkovic    } else {
2488b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard	uri->path = xmlStrdup(path);
2489b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard	if (uri->path == NULL) {
2490b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard	    xmlFreeURI(uri);
2491b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard	    return(NULL);
2492b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard	}
2493ce07616c089bf22653e31e2f7286cfdd8462857fIgor Zlatkovic	p = uri->path;
2494ce07616c089bf22653e31e2f7286cfdd8462857fIgor Zlatkovic    }
24952224227818b8196ea9250235038e069f6bc03a55William M. Brack    /* Now change all occurences of '\' to '/' */
2496ce07616c089bf22653e31e2f7286cfdd8462857fIgor Zlatkovic    while (*p != '\0') {
2497ce07616c089bf22653e31e2f7286cfdd8462857fIgor Zlatkovic	if (*p == '\\')
2498ce07616c089bf22653e31e2f7286cfdd8462857fIgor Zlatkovic	    *p = '/';
2499ce07616c089bf22653e31e2f7286cfdd8462857fIgor Zlatkovic	p++;
2500ce07616c089bf22653e31e2f7286cfdd8462857fIgor Zlatkovic    }
25018f3392ef69ec36d34a389336c4df66bcce26969bDaniel Veillard
2502b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard    if (uri->scheme == NULL) {
25032224227818b8196ea9250235038e069f6bc03a55William M. Brack	ret = xmlStrdup((const xmlChar *) uri->path);
2504b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard    } else {
2505b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard	ret = xmlSaveUri(uri);
2506b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard    }
25078f3392ef69ec36d34a389336c4df66bcce26969bDaniel Veillard
2508f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic    xmlFreeURI(uri);
2509336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard#else
2510336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard    ret = xmlStrdup((const xmlChar *) path);
2511336a8e13bf013d6cf260c8b78a1129cef1e3662cDaniel Veillard#endif
2512f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic    return(ret);
2513f2238e6e553f0fa039ed084c436b38dbb33a0c86Igor Zlatkovic}
25143473f88a7abdf4e585e267288fb77e898c580d2bOwen Taylor
2515b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard/**
2516b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard * xmlPathToURI:
2517b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard * @path:  the resource locator in a filesystem notation
2518b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard *
2519b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard * Constructs an URI expressing the existing path
2520b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard *
252157560386503be0fd023f3b7537fd496784f3be18Daniel Veillard * Returns a new URI, or a duplicate of the path parameter if the
2522b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard * construction fails. The caller is responsible for freeing the memory
2523b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard * occupied by the returned string. If there is insufficient memory available,
2524b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard * or the argument is NULL, the function returns NULL.
2525b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard */
2526b8efdda0a31947d5291fcb9221040fdab88dc549Daniel VeillardxmlChar *
2527b8efdda0a31947d5291fcb9221040fdab88dc549Daniel VeillardxmlPathToURI(const xmlChar *path)
2528b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard{
2529b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard    xmlURIPtr uri;
2530b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard    xmlURI temp;
2531b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard    xmlChar *ret, *cal;
2532b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard
2533b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard    if (path == NULL)
2534b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard        return(NULL);
2535b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard
2536b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard    if ((uri = xmlParseURI((const char *) path)) != NULL) {
2537b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard	xmlFreeURI(uri);
2538b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard	return xmlStrdup(path);
2539b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard    }
2540b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard    cal = xmlCanonicPath(path);
2541b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard    if (cal == NULL)
2542b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard        return(NULL);
2543481dcfcff3945620a05b8cdbc2f3c7aa5de7a470Daniel Veillard#if defined(_WIN32) && !defined(__CYGWIN__)
254457560386503be0fd023f3b7537fd496784f3be18Daniel Veillard    /* xmlCanonicPath can return an URI on Windows (is that the intended behaviour?)
2545481dcfcff3945620a05b8cdbc2f3c7aa5de7a470Daniel Veillard       If 'cal' is a valid URI allready then we are done here, as continuing would make
2546481dcfcff3945620a05b8cdbc2f3c7aa5de7a470Daniel Veillard       it invalid. */
2547481dcfcff3945620a05b8cdbc2f3c7aa5de7a470Daniel Veillard    if ((uri = xmlParseURI((const char *) cal)) != NULL) {
2548481dcfcff3945620a05b8cdbc2f3c7aa5de7a470Daniel Veillard	xmlFreeURI(uri);
2549481dcfcff3945620a05b8cdbc2f3c7aa5de7a470Daniel Veillard	return cal;
2550481dcfcff3945620a05b8cdbc2f3c7aa5de7a470Daniel Veillard    }
2551481dcfcff3945620a05b8cdbc2f3c7aa5de7a470Daniel Veillard    /* 'cal' can contain a relative path with backslashes. If that is processed
2552481dcfcff3945620a05b8cdbc2f3c7aa5de7a470Daniel Veillard       by xmlSaveURI, they will be escaped and the external entity loader machinery
2553481dcfcff3945620a05b8cdbc2f3c7aa5de7a470Daniel Veillard       will fail. So convert them to slashes. Misuse 'ret' for walking. */
2554481dcfcff3945620a05b8cdbc2f3c7aa5de7a470Daniel Veillard    ret = cal;
2555481dcfcff3945620a05b8cdbc2f3c7aa5de7a470Daniel Veillard    while (*ret != '\0') {
2556481dcfcff3945620a05b8cdbc2f3c7aa5de7a470Daniel Veillard	if (*ret == '\\')
2557481dcfcff3945620a05b8cdbc2f3c7aa5de7a470Daniel Veillard	    *ret = '/';
2558481dcfcff3945620a05b8cdbc2f3c7aa5de7a470Daniel Veillard	ret++;
2559481dcfcff3945620a05b8cdbc2f3c7aa5de7a470Daniel Veillard    }
2560481dcfcff3945620a05b8cdbc2f3c7aa5de7a470Daniel Veillard#endif
2561b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard    memset(&temp, 0, sizeof(temp));
2562b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard    temp.path = (char *) cal;
2563b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard    ret = xmlSaveUri(&temp);
2564b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard    xmlFree(cal);
2565b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard    return(ret);
2566b8efdda0a31947d5291fcb9221040fdab88dc549Daniel Veillard}
25675d4644ef6e38479a648615eca758c5e962a141d5Daniel Veillard#define bottom_uri
25685d4644ef6e38479a648615eca758c5e962a141d5Daniel Veillard#include "elfgcchack.h"
2569