librazor/path.c
changeset 475 008c75a5e08d
parent 459 5576a85e174a
child 479 4204db81cdbc
     1.1 --- a/librazor/path.c	Fri Oct 17 10:13:48 2014 +0100
     1.2 +++ b/librazor/path.c	Mon Jul 04 10:48:18 2016 +0100
     1.3 @@ -1,5 +1,5 @@
     1.4  /*
     1.5 - * Copyright (C) 2014  J. Ali Harlow <ali@juiblex.co.uk>
     1.6 + * Copyright (C) 2014, 2016  J. Ali Harlow <ali@juiblex.co.uk>
     1.7   *
     1.8   * This program is free software; you can redistribute it and/or modify
     1.9   * it under the terms of the GNU General Public License as published by
    1.10 @@ -19,78 +19,10 @@
    1.11  #include "config.h"
    1.12  #include <stdlib.h>
    1.13  #include <string.h>
    1.14 +#include <ctype.h>
    1.15  #include "razor.h"
    1.16  #include "razor-internal.h"
    1.17 -
    1.18 -/**
    1.19 - * razor_path_add_root:
    1.20 - *
    1.21 - * Adds a root to a path. path must be an absolute pathname. In POSIX
    1.22 - * environments this is equivalent to the concationation of root and path.
    1.23 - * In Microsoft Windows an adjustment may need to be made for a drive letter
    1.24 - * in path (which will be dropped).
    1.25 - *
    1.26 - * Returns: The new pathname.
    1.27 - **/
    1.28 -RAZOR_EXPORT char *razor_path_add_root(const char *path, const char *root)
    1.29 -{
    1.30 -	if (root && *root)
    1.31 -		return razor_concat(root, SKIP_DRIVE_LETTER(path), NULL);
    1.32 -	else
    1.33 -		return strdup(path);
    1.34 -}
    1.35 -
    1.36 -#if 0
    1.37 -
    1.38 -/*
    1.39 - * This should work, but for some reason PathCreateFromUrlW()
    1.40 - * treats the percent-encoded bytes as being in CP 850 rather
    1.41 - * than UTF-8 as expected even if we set the codepage.
    1.42 - */
    1.43 -RAZOR_EXPORT char *razor_path_from_url(const char *url)
    1.44 -{
    1.45 -	UINT saved_cp;
    1.46 -	HRESULT result;
    1.47 -	DWORD len = MAX_PATH;
    1.48 -	wchar_t *url16;
    1.49 -	wchar_t path16[MAX_PATH];
    1.50 -	char *path;
    1.51 -
    1.52 -	url16 = razor_utf8_to_utf16(url, -1);
    1.53 -
    1.54 -	saved_cp = GetConsoleCP();
    1.55 -	SetConsoleCP(CP_UTF8);
    1.56 -
    1.57 -	result = PathCreateFromUrlW(url16, path16, &len, NULL);
    1.58 -
    1.59 -	SetConsoleCP(saved_cp);
    1.60 -
    1.61 -	if (result == S_OK)
    1.62 -		path = razor_utf16_to_utf8(path16, len);
    1.63 -	else
    1.64 -		path = NULL;
    1.65 -
    1.66 -	free(url16);
    1.67 -
    1.68 -	return path;
    1.69 -}
    1.70 -
    1.71 -#else
    1.72 -
    1.73 -#ifdef MSWIN_API
    1.74 -static int is_ascii_letter(char c)
    1.75 -{
    1.76 -	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
    1.77 -}
    1.78 -#endif
    1.79 -
    1.80 -static int xdigit_value(char c)
    1.81 -{
    1.82 -	if (c >= '0' && c <= '9')
    1.83 -		return c - '0';
    1.84 -	else
    1.85 -		return (c | 0x20) - 'a' + 10;
    1.86 -}
    1.87 +#include "uri.h"
    1.88  
    1.89  static int valid_unicode(unsigned unicode)
    1.90  {
    1.91 @@ -101,54 +33,74 @@
    1.92  	return unicode < 0xD800 || (unicode >= 0xE000 && unicode < 0x110000);
    1.93  }
    1.94  
    1.95 -RAZOR_EXPORT char *razor_path_from_url(const char *url)
    1.96 +char *razor_path_from_parsed_uri(const struct razor_uri *ru,
    1.97 +  struct razor_error **error)
    1.98  {
    1.99  	int continuation_bytes = 0;
   1.100 -	char *path, *p;
   1.101 +	char *path, *p, *s, *uri;
   1.102  	unsigned char c;
   1.103  	unsigned unicode;
   1.104  
   1.105 -	if (strncmp(url, "file://", 7) == 0)
   1.106 -		url += 7;
   1.107 -	else
   1.108 +	if (!ru->scheme) {
   1.109 +		uri = razor_uri_recompose(ru);
   1.110 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
   1.111 +				RAZOR_GENERAL_ERROR_BAD_URI, uri,
   1.112 +				"URI does not include a scheme");
   1.113 +		free(uri);
   1.114  		return NULL;
   1.115 +	}
   1.116  
   1.117 -	if (strncmp(url, "localhost/", 10) == 0)
   1.118 -		url += 9;
   1.119 -	else if (strncmp(url, "/", 1) != 0)
   1.120 +	if (strcmp(ru->scheme, "file")) {
   1.121 +		uri = razor_uri_recompose(ru);
   1.122 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
   1.123 +				RAZOR_GENERAL_ERROR_UNSUPPORTED_URI, uri,
   1.124 +				"Not a file URI");
   1.125 +		free(uri);
   1.126  		return NULL;
   1.127 +	}
   1.128  
   1.129 +	if (ru->host && *ru->host && strcmp(ru->host, "localhost") ||
   1.130 +	    ru->userinfo || ru->port) {
   1.131 +		uri = razor_uri_recompose(ru);
   1.132 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
   1.133 +				RAZOR_GENERAL_ERROR_UNSUPPORTED_URI, uri,
   1.134 +				"URI refers to a non-local file");
   1.135 +		free(uri);
   1.136 +		return NULL;
   1.137 +	}
   1.138 +
   1.139 +	s = ru->path;
   1.140  #ifdef MSWIN_API
   1.141  	/*
   1.142 -	 * Under MS-Windows, file:///c:/xxx maps to c:/xxx
   1.143 +	 * Under MS-Windows, a path of /c:/xxx maps to c:/xxx
   1.144  	 * Note that PathCreateFromUrl converts / to \ as well.
   1.145  	 */
   1.146 -	if (is_ascii_letter(url[1]) && url[2] == ':' && url[3] == '/')
   1.147 -		url++;
   1.148 +	if (s[0] == '/' && is_alpha(s[1]) && s[2] == ':' && s[3] == '/')
   1.149 +		s++;
   1.150  #endif
   1.151  
   1.152 -	p = path = malloc(strlen(url) + 1);
   1.153 +	p = path = malloc(strlen(s) + 1);
   1.154  
   1.155 -	while(*url) {
   1.156 -		if (*url >= 0x7F || *url < 0x20) {
   1.157 -			free(path);
   1.158 -			return NULL;
   1.159 -		} else if (*url != '%') {
   1.160 -			if (continuation_bytes) {
   1.161 -				free(path);
   1.162 -				return NULL;
   1.163 -			} else
   1.164 -				*p++ = *url++;
   1.165 -		} else if (isxdigit(url[1]) && isxdigit(url[2])) {
   1.166 -			c = xdigit_value(url[1]) * 16 + xdigit_value(url[2]);
   1.167 -			if (c == '/') {
   1.168 -				free(path);
   1.169 -				return NULL;
   1.170 -			} else if (!continuation_bytes) {
   1.171 -				if (c >= 0xF5 || c == 0xC0 || c == 0xC1) {
   1.172 -					free(path);
   1.173 -					return NULL;
   1.174 -				} else if (c >= 0xF0) {
   1.175 +	while (*s) {
   1.176 +		if (*s >= 0x7F || *s < 0x20)
   1.177 +			break;
   1.178 +		else if (*s != '%') {
   1.179 +			if (continuation_bytes)
   1.180 +				break;
   1.181 +			else
   1.182 +				*p++ = *s++;
   1.183 +		} else {
   1.184 +			c = pchar_get_char(s);
   1.185 +#ifdef MSWIN_API
   1.186 +			if (c == '/' || c == '\\')
   1.187 +#else
   1.188 +			if (c == '/')
   1.189 +#endif
   1.190 +				break;
   1.191 +			else if (!continuation_bytes) {
   1.192 +				if (c >= 0xF5 || c == 0xC0 || c == 0xC1)
   1.193 +					break;
   1.194 +				else if (c >= 0xF0) {
   1.195  					unicode = c & 7;
   1.196  					continuation_bytes = 3;
   1.197  				} else if (c >= 0xE0) {
   1.198 @@ -158,29 +110,28 @@
   1.199  					unicode = c & 1;
   1.200  					continuation_bytes = 1;
   1.201  				}
   1.202 -			} else if ((c & 0xC0) != 0x80) {
   1.203 -				free(path);
   1.204 -				return NULL;
   1.205 -			} else {
   1.206 +			} else if ((c & 0xC0) != 0x80)
   1.207 +				break;
   1.208 +			else {
   1.209  				unicode <<= 6;
   1.210  				unicode |= (c & 0x3F);
   1.211  
   1.212  				if (!--continuation_bytes &&
   1.213 -				    !valid_unicode(unicode)) {
   1.214 -					free(path);
   1.215 -					return NULL;
   1.216 -				}
   1.217 +				    !valid_unicode(unicode))
   1.218 +					break;
   1.219  			}
   1.220  
   1.221  			*p++ = c;
   1.222 -			url += 3;
   1.223 -		} else {
   1.224 -			free(path);
   1.225 -			return NULL;
   1.226 +			s += 3;
   1.227  		}
   1.228  	}
   1.229  
   1.230 -	if (continuation_bytes) {
   1.231 +	if (*s || continuation_bytes) {
   1.232 +		uri = razor_uri_recompose(ru);
   1.233 +		razor_set_error(error, RAZOR_GENERAL_ERROR,
   1.234 +				RAZOR_GENERAL_ERROR_BAD_URI,
   1.235 +				uri, "Illegal character in file URI path");
   1.236 +		free(uri);
   1.237  		free(path);
   1.238  		return NULL;
   1.239  	}
   1.240 @@ -190,4 +141,72 @@
   1.241  	return realloc(path, p - path);
   1.242  }
   1.243  
   1.244 -#endif	/* 0 */
   1.245 +RAZOR_EXPORT char *razor_path_from_uri(const char *uri,
   1.246 +  struct razor_error **error)
   1.247 +{
   1.248 +	struct razor_uri ru;
   1.249 +	char *path;
   1.250 +
   1.251 +	if (razor_uri_parse(&ru, uri, error))
   1.252 +		return NULL;
   1.253 +
   1.254 +	path = razor_path_from_parsed_uri(&ru, error);
   1.255 +
   1.256 +	razor_uri_destroy(&ru);
   1.257 +
   1.258 +	return path;
   1.259 +}
   1.260 +
   1.261 +RAZOR_EXPORT char *razor_path_to_uri(const char *path)
   1.262 +{
   1.263 +	char *uri, *p;
   1.264 +
   1.265 +	uri = malloc(6 + 3 * strlen(path) + 1);
   1.266 +
   1.267 +	strcpy(uri, "file:");
   1.268 +
   1.269 +	p = uri + 5;
   1.270 +
   1.271 +#ifdef MSWIN_API
   1.272 +	/*
   1.273 +	 * Under MS-Windows, c:/xxx maps to a path of /c:/xxx
   1.274 +	 */
   1.275 +	if (is_alpha(path[0]) && path[1] == ':' && path[2] == '/')
   1.276 +		*p++ = '/';
   1.277 +#endif
   1.278 +
   1.279 +	while(*path) {
   1.280 +		if (*path == '/' || is_unreserved(*path) ||
   1.281 +		    is_sub_delim(*path) || *path == ':' || *path == '@')
   1.282 +			*p++ = *path;
   1.283 +#ifdef MSWIN_API
   1.284 +		else if (*path == '\\')
   1.285 +			*p++ = '/';
   1.286 +#endif
   1.287 +		else {
   1.288 +			*p++ = '%';
   1.289 +			*p++ = "0123456789ABCDEF"[(*(unsigned char *)path)/16];
   1.290 +			*p++ = "0123456789ABCDEF"[(*(unsigned char *)path)%16];
   1.291 +		}
   1.292 +		path++;
   1.293 +	}
   1.294 +	*p++ = '\0';
   1.295 +
   1.296 +	return realloc(uri, p - uri);
   1.297 +}
   1.298 +
   1.299 +RAZOR_EXPORT char *
   1.300 +razor_path_relative_to_uri(const char *uri, const char *path,
   1.301 +			   struct razor_error **error)
   1.302 +{
   1.303 +	char *rel_uri, *result;
   1.304 +
   1.305 +	/* Strictly wrong if uri isn't a file URI, but probably okay */
   1.306 +	rel_uri = razor_path_to_uri(path);
   1.307 +
   1.308 +	result = razor_resolve_uri_root(uri, rel_uri + 5, 1, error);
   1.309 +
   1.310 +	free(rel_uri);
   1.311 +
   1.312 +	return result;
   1.313 +}