librazor/path.c
author J. Ali Harlow <ali@juiblex.co.uk>
Mon Jul 11 16:12:45 2016 +0100 (2016-07-11)
changeset 487 a5837882a252
parent 475 008c75a5e08d
child 491 b18e0bf48a91
permissions -rw-r--r--
More tweaks for archive error reporting
     1 /*
     2  * Copyright (C) 2014, 2016  J. Ali Harlow <ali@juiblex.co.uk>
     3  *
     4  * This program is free software; you can redistribute it and/or modify
     5  * it under the terms of the GNU General Public License as published by
     6  * the Free Software Foundation; either version 2 of the License, or
     7  * (at your option) any later version.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License along
    15  * with this program; if not, write to the Free Software Foundation, Inc.,
    16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    17  */
    18 
    19 #include "config.h"
    20 #include <stdlib.h>
    21 #include <string.h>
    22 #include <ctype.h>
    23 #include "razor.h"
    24 #include "razor-internal.h"
    25 #include "uri.h"
    26 
    27 static int valid_unicode(unsigned unicode)
    28 {
    29 	/*
    30 	 * Within the U+0000..U+10FFFF range defined by RFC3629
    31 	 * but not in the U+D800..U+DFFF range prohibited in UTF-8.
    32 	 */
    33 	return unicode < 0xD800 || (unicode >= 0xE000 && unicode < 0x110000);
    34 }
    35 
    36 char *razor_path_from_parsed_uri(const struct razor_uri *ru,
    37   struct razor_error **error)
    38 {
    39 	int continuation_bytes = 0;
    40 	char *path, *p, *s, *uri;
    41 	unsigned char c;
    42 	unsigned unicode;
    43 
    44 	if (!ru->scheme) {
    45 		uri = razor_uri_recompose(ru);
    46 		razor_set_error(error, RAZOR_GENERAL_ERROR,
    47 				RAZOR_GENERAL_ERROR_BAD_URI, uri,
    48 				"URI does not include a scheme");
    49 		free(uri);
    50 		return NULL;
    51 	}
    52 
    53 	if (strcmp(ru->scheme, "file")) {
    54 		uri = razor_uri_recompose(ru);
    55 		razor_set_error(error, RAZOR_GENERAL_ERROR,
    56 				RAZOR_GENERAL_ERROR_UNSUPPORTED_URI, uri,
    57 				"Not a file URI");
    58 		free(uri);
    59 		return NULL;
    60 	}
    61 
    62 	if (ru->host && *ru->host && strcmp(ru->host, "localhost") ||
    63 	    ru->userinfo || ru->port) {
    64 		uri = razor_uri_recompose(ru);
    65 		razor_set_error(error, RAZOR_GENERAL_ERROR,
    66 				RAZOR_GENERAL_ERROR_UNSUPPORTED_URI, uri,
    67 				"URI refers to a non-local file");
    68 		free(uri);
    69 		return NULL;
    70 	}
    71 
    72 	s = ru->path;
    73 #ifdef MSWIN_API
    74 	/*
    75 	 * Under MS-Windows, a path of /c:/xxx maps to c:/xxx
    76 	 * Note that PathCreateFromUrl converts / to \ as well.
    77 	 */
    78 	if (s[0] == '/' && is_alpha(s[1]) && s[2] == ':' && s[3] == '/')
    79 		s++;
    80 #endif
    81 
    82 	p = path = malloc(strlen(s) + 1);
    83 
    84 	while (*s) {
    85 		if (*s >= 0x7F || *s < 0x20)
    86 			break;
    87 		else if (*s != '%') {
    88 			if (continuation_bytes)
    89 				break;
    90 			else
    91 				*p++ = *s++;
    92 		} else {
    93 			c = pchar_get_char(s);
    94 #ifdef MSWIN_API
    95 			if (c == '/' || c == '\\')
    96 #else
    97 			if (c == '/')
    98 #endif
    99 				break;
   100 			else if (!continuation_bytes) {
   101 				if (c >= 0xF5 || c == 0xC0 || c == 0xC1)
   102 					break;
   103 				else if (c >= 0xF0) {
   104 					unicode = c & 7;
   105 					continuation_bytes = 3;
   106 				} else if (c >= 0xE0) {
   107 					unicode = c & 3;
   108 					continuation_bytes = 2;
   109 				} else if (c >= 0xC0) {
   110 					unicode = c & 1;
   111 					continuation_bytes = 1;
   112 				}
   113 			} else if ((c & 0xC0) != 0x80)
   114 				break;
   115 			else {
   116 				unicode <<= 6;
   117 				unicode |= (c & 0x3F);
   118 
   119 				if (!--continuation_bytes &&
   120 				    !valid_unicode(unicode))
   121 					break;
   122 			}
   123 
   124 			*p++ = c;
   125 			s += 3;
   126 		}
   127 	}
   128 
   129 	if (*s || continuation_bytes) {
   130 		uri = razor_uri_recompose(ru);
   131 		razor_set_error(error, RAZOR_GENERAL_ERROR,
   132 				RAZOR_GENERAL_ERROR_BAD_URI,
   133 				uri, "Illegal character in file URI path");
   134 		free(uri);
   135 		free(path);
   136 		return NULL;
   137 	}
   138 
   139 	*p++ = '\0';
   140 
   141 	return realloc(path, p - path);
   142 }
   143 
   144 RAZOR_EXPORT char *razor_path_from_uri(const char *uri,
   145   struct razor_error **error)
   146 {
   147 	struct razor_uri ru;
   148 	char *path;
   149 
   150 	if (razor_uri_parse(&ru, uri, error))
   151 		return NULL;
   152 
   153 	path = razor_path_from_parsed_uri(&ru, error);
   154 
   155 	razor_uri_destroy(&ru);
   156 
   157 	return path;
   158 }
   159 
   160 RAZOR_EXPORT char *razor_path_to_uri(const char *path)
   161 {
   162 	char *uri, *p;
   163 
   164 	uri = malloc(6 + 3 * strlen(path) + 1);
   165 
   166 	strcpy(uri, "file:");
   167 
   168 	p = uri + 5;
   169 
   170 #ifdef MSWIN_API
   171 	/*
   172 	 * Under MS-Windows, c:/xxx maps to a path of /c:/xxx
   173 	 */
   174 	if (is_alpha(path[0]) && path[1] == ':' &&
   175 	    (path[2] == '/' || path[2] == '\\'))
   176 		*p++ = '/';
   177 #endif
   178 
   179 	while(*path) {
   180 		if (*path == '/' || is_unreserved(*path) ||
   181 		    is_sub_delim(*path) || *path == ':' || *path == '@')
   182 			*p++ = *path;
   183 #ifdef MSWIN_API
   184 		else if (*path == '\\')
   185 			*p++ = '/';
   186 #endif
   187 		else {
   188 			*p++ = '%';
   189 			*p++ = "0123456789ABCDEF"[(*(unsigned char *)path)/16];
   190 			*p++ = "0123456789ABCDEF"[(*(unsigned char *)path)%16];
   191 		}
   192 		path++;
   193 	}
   194 	*p++ = '\0';
   195 
   196 	return realloc(uri, p - uri);
   197 }
   198 
   199 RAZOR_EXPORT char *
   200 razor_path_relative_to_uri(const char *uri, const char *path,
   201 			   struct razor_error **error)
   202 {
   203 	char *rel_uri, *result;
   204 
   205 	/* Strictly wrong if uri isn't a file URI, but probably okay */
   206 	rel_uri = razor_path_to_uri(path);
   207 
   208 	result = razor_resolve_uri_root(uri, rel_uri + 5, 1, error);
   209 
   210 	free(rel_uri);
   211 
   212 	return result;
   213 }