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