From bb1e3c973526e66024e1a3260255368034cb2008 Mon Sep 17 00:00:00 2001 From: Robin Watts Date: Thu, 2 Feb 2012 16:18:13 +0000 Subject: Support remote links in XPS documents. Update xps path handling to cope with URLs. Fix premature freeing of links. Spot remote URLs and use appropriate link type. --- xps/xps_util.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 83 insertions(+), 14 deletions(-) (limited to 'xps/xps_util.c') diff --git a/xps/xps_util.c b/xps/xps_util.c index 6af4da91..5a3b1fbf 100644 --- a/xps/xps_util.c +++ b/xps/xps_util.c @@ -20,15 +20,77 @@ xps_strcasecmp(char *a, char *b) return xps_tolower(*a) - xps_tolower(*b); } +/* A URL is defined as consisting of a: + * SCHEME (e.g. http:) + * AUTHORITY (username, password, hostname, port, eg //test:passwd@mupdf.com:999) + * PATH (e.g. /download) + * QUERY (e.g. ?view=page) + * FRAGMENT (e.g. #fred) (not strictly part of the URL) + */ +static char * +skip_scheme(char *path) +{ + char *p = path; + + /* Skip over: alpha *(alpha | digit | "+" | "-" | ".") looking for : */ + if (*p >= 'a' && *p <= 'z') + {} + else if (*p >= 'A' && *p <= 'Z') + {} + else + return path; + + while (*++p) + { + if (*p >= 'a' && *p <= 'z') + {} + else if (*p >= 'A' && *p <= 'Z') + {} + else if (*p >= '0' && *p <= '9') + {} + else if (*p == '+') + {} + else if (*p == '-') + {} + else if (*p == '.') + {} + else if (*p == ':') + return p+1; + else + break; + } + return path; +} + +static char * +skip_authority(char *path) +{ + char *p = path; + + /* Authority section must start with '//' */ + if (p[0] != '/' || p[1] != '/') + return path; + p += 2; + + /* Authority is terminated by end of URL, '/' or '?' */ + while (*p && *p != '/' && *p != '?') + p++; + + return p; +} + + #define SEP(x) ((x)=='/' || (x) == 0) static char * xps_clean_path(char *name) { - char *p, *q, *dotdot; + char *p, *q, *dotdot, *start; int rooted; - rooted = name[0] == '/'; + start = skip_scheme(name); + start = skip_authority(start); + rooted = start[0] == '/'; /* * invariants: @@ -37,7 +99,7 @@ xps_clean_path(char *name) * dotdot points just past the point where .. cannot backtrack * any further (no slash). */ - p = q = dotdot = name + rooted; + p = q = dotdot = start + rooted; while (*p) { if(p[0] == '/') /* null element */ @@ -54,7 +116,7 @@ xps_clean_path(char *name) } else if (!rooted) /* /.. is / but ./../ is .. */ { - if (q != name) + if (q != start) *q++ = '/'; *q++ = '.'; *q++ = '.'; @@ -63,36 +125,43 @@ xps_clean_path(char *name) } else /* real path element */ { - if (q != name+rooted) + if (q != start+rooted) *q++ = '/'; while ((*q = *p) != '/' && *q != 0) p++, q++; } } - if (q == name) /* empty string is really "." */ + if (q == start) /* empty string is really "." */ *q++ = '.'; *q = '\0'; return name; } -/* RJW: Possible problems here: - * "/foo" + "../../bar" = "/bar" not "../bar" - * "http://something/" + ... doesn't work. - */ void -xps_absolute_path(char *output, char *base_uri, char *path, int output_size) +xps_resolve_url(char *output, char *base_uri, char *path, int output_size) { - if (path[0] == '/') + char *p = skip_authority(skip_scheme(path)); + + if (p != path || path[0] == '/') { fz_strlcpy(output, path, output_size); } else { - fz_strlcpy(output, base_uri, output_size); - fz_strlcat(output, "/", output_size); + int len = fz_strlcpy(output, base_uri, output_size); + if (len == 0 || output[len-1] != '/') + fz_strlcat(output, "/", output_size); fz_strlcat(output, path, output_size); } xps_clean_path(output); } + +int +xps_url_is_remote(char *path) +{ + char *p = skip_authority(skip_scheme(path)); + + return p != path; +} -- cgit v1.2.3