added a new routine xmlBuildRelativeURI needed for enhancement of
* uri.c, include/libxml/uri.h: added a new routine
xmlBuildRelativeURI needed for enhancement of xinclude.c
* xinclude.c: changed handling of xml:base (bug 135864)
* result/XInclude/*: results of 5 tests changed as a result
of the above change
diff --git a/uri.c b/uri.c
index 1b2c08a..fe75e78 100644
--- a/uri.c
+++ b/uri.c
@@ -1972,6 +1972,181 @@
}
/**
+ * xmlBuildRelativeURI:
+ * @URI: the URI reference under consideration
+ * @base: the base value
+ *
+ * Expresses the URI of the reference in terms relative to the
+ * base. Some examples of this operation include:
+ * base = "http://site1.com/docs/book1.html"
+ * URI input URI returned
+ * docs/pic1.gif pic1.gif
+ * docs/img/pic1.gif img/pic1.gif
+ * img/pic1.gif ../img/pic1.gif
+ * http://site1.com/docs/pic1.gif pic1.gif
+ * http://site2.com/docs/pic1.gif http://site2.com/docs/pic1.gif
+ *
+ * base = "docs/book1.html"
+ * URI input URI returned
+ * docs/pic1.gif pic1.gif
+ * docs/img/pic1.gif img/pic1.gif
+ * img/pic1.gif ../img/pic1.gif
+ * http://site1.com/docs/pic1.gif http://site1.com/docs/pic1.gif
+ *
+ *
+ * Note: if the URI reference is really wierd or complicated, it may be
+ * worthwhile to first convert it into a "nice" one by calling
+ * xmlBuildURI (using 'base') before calling this routine,
+ * since this routine (for reasonable efficiency) assumes URI has
+ * already been through some validation.
+ *
+ * Returns a new URI string (to be freed by the caller) or NULL in case
+ * error.
+ */
+xmlChar *
+xmlBuildRelativeURI (const xmlChar * URI, const xmlChar * base)
+{
+ xmlChar *val = NULL;
+ int ret;
+ int ix;
+ int pos = 0;
+ int nbslash = 0;
+ xmlURIPtr ref = NULL;
+ xmlURIPtr bas = NULL;
+ xmlChar *bptr, *uptr, *vptr;
+
+ if ((URI == NULL) || (*URI == 0))
+ return NULL;
+ /*
+ * Special case - if URI starts with '.', we assume it's already
+ * in relative form, so nothing to do.
+ */
+ if (*URI == '.') {
+ val = xmlStrdup (URI);
+ goto done;
+ }
+
+ /*
+ * First parse URI into a standard form
+ */
+ ref = xmlCreateURI ();
+ if (ref == NULL)
+ return NULL;
+ ret = xmlParseURIReference (ref, (const char *) URI);
+ if (ret != 0)
+ goto done; /* Error in URI, return NULL */
+
+ /*
+ * Next parse base into the same standard form
+ */
+ if ((base == NULL) || (*base == 0)) {
+ val = xmlStrdup (URI);
+ goto done;
+ }
+ bas = xmlCreateURI ();
+ if (bas == NULL)
+ goto done;
+ ret = xmlParseURIReference (bas, (const char *) base);
+ if (ret != 0)
+ goto done; /* Error in base, return NULL */
+
+ /*
+ * If the scheme / server on the URI differs from the base,
+ * just return the URI
+ */
+ if ((ref->scheme != NULL) &&
+ ((bas->scheme == NULL) ||
+ xmlStrcmp ((xmlChar *)bas->scheme, (xmlChar *)ref->scheme) ||
+ xmlStrcmp ((xmlChar *)bas->server, (xmlChar *)ref->server))) {
+ val = xmlStrdup (URI);
+ goto done;
+ }
+
+ /*
+ * At this point (at last!) we can compare the two paths
+ *
+ * First we compare the two strings and find where they first differ
+ */
+ bptr = (xmlChar *)bas->path;
+ if ((*bptr == '/') && (ref->path[0] != '/'))
+ bptr++;
+ while ((bptr[pos] == ref->path[pos]) && (bptr[pos] != 0))
+ pos++;
+
+ if (bptr[pos] == ref->path[pos]) {
+ val = NULL; /* if no differences, return NULL */
+ goto done; /* (I can't imagine why anyone would do this) */
+ }
+
+ /*
+ * In URI, "back up" to the last '/' encountered. This will be the
+ * beginning of the "unique" suffix of URI
+ */
+ ix = pos;
+ if ((ref->path[ix] == '/') && (ix > 0))
+ ix--;
+ for (; ix > 0; ix--) {
+ if (ref->path[ix] == '/')
+ break;
+ }
+ if (ix == 0)
+ uptr = (xmlChar *)ref->path;
+ else
+ uptr = (xmlChar *)&ref->path[ix + 1];
+
+ /*
+ * In base, count the number of '/' from the differing point
+ */
+ if (bptr[pos] != ref->path[pos]) { /* check for trivial URI == base */
+ for (; bptr[ix] != 0; ix++) {
+ if (bptr[ix] == '/')
+ nbslash++;
+ }
+ }
+
+ if (nbslash == 0) {
+ val = xmlStrdup (uptr);
+ goto done;
+ }
+ nbslash--;
+
+ /*
+ * Allocate just enough space for the returned string -
+ * length of the remainder of the URI, plus enough space
+ * for the "../" groups, plus one for the terminator
+ */
+ ix = xmlStrlen (uptr) + 1;
+ val = (xmlChar *) xmlMalloc (ix + 3 * nbslash);
+ if (val == NULL) {
+ goto done;
+ }
+ vptr = val;
+ /*
+ * Put in as many "../" as needed
+ */
+ for (; nbslash>0; nbslash--) {
+ *vptr++ = '.';
+ *vptr++ = '.';
+ *vptr++ = '/';
+ }
+ /*
+ * Finish up with the end of the URI
+ */
+ memcpy (vptr, uptr, ix);
+
+ done:
+ /*
+ * Free the working variables
+ */
+ if (ref != NULL)
+ xmlFreeURI (ref);
+ if (bas != NULL)
+ xmlFreeURI (bas);
+
+ return val;
+}
+
+/**
* xmlCanonicPath:
* @path: the resource locator in a filesystem notation
*