diff -r 5576a85e174a -r 8e4bf84a7bb8 librazor/path.c --- a/librazor/path.c Fri Oct 17 10:13:48 2014 +0100 +++ b/librazor/path.c Thu Jul 07 11:04:10 2016 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 J. Ali Harlow + * Copyright (C) 2014, 2016 J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,78 +19,10 @@ #include "config.h" #include #include +#include #include "razor.h" #include "razor-internal.h" - -/** - * razor_path_add_root: - * - * Adds a root to a path. path must be an absolute pathname. In POSIX - * environments this is equivalent to the concationation of root and path. - * In Microsoft Windows an adjustment may need to be made for a drive letter - * in path (which will be dropped). - * - * Returns: The new pathname. - **/ -RAZOR_EXPORT char *razor_path_add_root(const char *path, const char *root) -{ - if (root && *root) - return razor_concat(root, SKIP_DRIVE_LETTER(path), NULL); - else - return strdup(path); -} - -#if 0 - -/* - * This should work, but for some reason PathCreateFromUrlW() - * treats the percent-encoded bytes as being in CP 850 rather - * than UTF-8 as expected even if we set the codepage. - */ -RAZOR_EXPORT char *razor_path_from_url(const char *url) -{ - UINT saved_cp; - HRESULT result; - DWORD len = MAX_PATH; - wchar_t *url16; - wchar_t path16[MAX_PATH]; - char *path; - - url16 = razor_utf8_to_utf16(url, -1); - - saved_cp = GetConsoleCP(); - SetConsoleCP(CP_UTF8); - - result = PathCreateFromUrlW(url16, path16, &len, NULL); - - SetConsoleCP(saved_cp); - - if (result == S_OK) - path = razor_utf16_to_utf8(path16, len); - else - path = NULL; - - free(url16); - - return path; -} - -#else - -#ifdef MSWIN_API -static int is_ascii_letter(char c) -{ - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); -} -#endif - -static int xdigit_value(char c) -{ - if (c >= '0' && c <= '9') - return c - '0'; - else - return (c | 0x20) - 'a' + 10; -} +#include "uri.h" static int valid_unicode(unsigned unicode) { @@ -101,54 +33,74 @@ return unicode < 0xD800 || (unicode >= 0xE000 && unicode < 0x110000); } -RAZOR_EXPORT char *razor_path_from_url(const char *url) +char *razor_path_from_parsed_uri(const struct razor_uri *ru, + struct razor_error **error) { int continuation_bytes = 0; - char *path, *p; + char *path, *p, *s, *uri; unsigned char c; unsigned unicode; - if (strncmp(url, "file://", 7) == 0) - url += 7; - else + if (!ru->scheme) { + uri = razor_uri_recompose(ru); + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_BAD_URI, uri, + "URI does not include a scheme"); + free(uri); return NULL; + } - if (strncmp(url, "localhost/", 10) == 0) - url += 9; - else if (strncmp(url, "/", 1) != 0) + if (strcmp(ru->scheme, "file")) { + uri = razor_uri_recompose(ru); + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI, uri, + "Not a file URI"); + free(uri); return NULL; + } + if (ru->host && *ru->host && strcmp(ru->host, "localhost") || + ru->userinfo || ru->port) { + uri = razor_uri_recompose(ru); + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_UNSUPPORTED_URI, uri, + "URI refers to a non-local file"); + free(uri); + return NULL; + } + + s = ru->path; #ifdef MSWIN_API /* - * Under MS-Windows, file:///c:/xxx maps to c:/xxx + * Under MS-Windows, a path of /c:/xxx maps to c:/xxx * Note that PathCreateFromUrl converts / to \ as well. */ - if (is_ascii_letter(url[1]) && url[2] == ':' && url[3] == '/') - url++; + if (s[0] == '/' && is_alpha(s[1]) && s[2] == ':' && s[3] == '/') + s++; #endif - p = path = malloc(strlen(url) + 1); + p = path = malloc(strlen(s) + 1); - while(*url) { - if (*url >= 0x7F || *url < 0x20) { - free(path); - return NULL; - } else if (*url != '%') { - if (continuation_bytes) { - free(path); - return NULL; - } else - *p++ = *url++; - } else if (isxdigit(url[1]) && isxdigit(url[2])) { - c = xdigit_value(url[1]) * 16 + xdigit_value(url[2]); - if (c == '/') { - free(path); - return NULL; - } else if (!continuation_bytes) { - if (c >= 0xF5 || c == 0xC0 || c == 0xC1) { - free(path); - return NULL; - } else if (c >= 0xF0) { + while (*s) { + if (*s >= 0x7F || *s < 0x20) + break; + else if (*s != '%') { + if (continuation_bytes) + break; + else + *p++ = *s++; + } else { + c = pchar_get_char(s); +#ifdef MSWIN_API + if (c == '/' || c == '\\') +#else + if (c == '/') +#endif + break; + else if (!continuation_bytes) { + if (c >= 0xF5 || c == 0xC0 || c == 0xC1) + break; + else if (c >= 0xF0) { unicode = c & 7; continuation_bytes = 3; } else if (c >= 0xE0) { @@ -158,29 +110,28 @@ unicode = c & 1; continuation_bytes = 1; } - } else if ((c & 0xC0) != 0x80) { - free(path); - return NULL; - } else { + } else if ((c & 0xC0) != 0x80) + break; + else { unicode <<= 6; unicode |= (c & 0x3F); if (!--continuation_bytes && - !valid_unicode(unicode)) { - free(path); - return NULL; - } + !valid_unicode(unicode)) + break; } *p++ = c; - url += 3; - } else { - free(path); - return NULL; + s += 3; } } - if (continuation_bytes) { + if (*s || continuation_bytes) { + uri = razor_uri_recompose(ru); + razor_set_error(error, RAZOR_GENERAL_ERROR, + RAZOR_GENERAL_ERROR_BAD_URI, + uri, "Illegal character in file URI path"); + free(uri); free(path); return NULL; } @@ -190,4 +141,72 @@ return realloc(path, p - path); } -#endif /* 0 */ +RAZOR_EXPORT char *razor_path_from_uri(const char *uri, + struct razor_error **error) +{ + struct razor_uri ru; + char *path; + + if (razor_uri_parse(&ru, uri, error)) + return NULL; + + path = razor_path_from_parsed_uri(&ru, error); + + razor_uri_destroy(&ru); + + return path; +} + +RAZOR_EXPORT char *razor_path_to_uri(const char *path) +{ + char *uri, *p; + + uri = malloc(6 + 3 * strlen(path) + 1); + + strcpy(uri, "file:"); + + p = uri + 5; + +#ifdef MSWIN_API + /* + * Under MS-Windows, c:/xxx maps to a path of /c:/xxx + */ + if (is_alpha(path[0]) && path[1] == ':' && path[2] == '/') + *p++ = '/'; +#endif + + while(*path) { + if (*path == '/' || is_unreserved(*path) || + is_sub_delim(*path) || *path == ':' || *path == '@') + *p++ = *path; +#ifdef MSWIN_API + else if (*path == '\\') + *p++ = '/'; +#endif + else { + *p++ = '%'; + *p++ = "0123456789ABCDEF"[(*(unsigned char *)path)/16]; + *p++ = "0123456789ABCDEF"[(*(unsigned char *)path)%16]; + } + path++; + } + *p++ = '\0'; + + return realloc(uri, p - uri); +} + +RAZOR_EXPORT char * +razor_path_relative_to_uri(const char *uri, const char *path, + struct razor_error **error) +{ + char *rel_uri, *result; + + /* Strictly wrong if uri isn't a file URI, but probably okay */ + rel_uri = razor_path_to_uri(path); + + result = razor_resolve_uri_root(uri, rel_uri + 5, 1, error); + + free(rel_uri); + + return result; +}