/* * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" #include #include #include #include "razor.h" #include "razor-internal.h" #include "uri.h" static int valid_unicode(unsigned unicode) { /* * Within the U+0000..U+10FFFF range defined by RFC3629 * but not in the U+D800..U+DFFF range prohibited in UTF-8. */ return unicode < 0xD800 || (unicode >= 0xE000 && unicode < 0x110000); } char *razor_path_from_parsed_uri(const struct razor_uri *ru, struct razor_error **error) { int continuation_bytes = 0; char *path, *p, *s, *uri; unsigned char c; unsigned unicode; 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 (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, a path of /c:/xxx maps to c:/xxx * Note that PathCreateFromUrl converts / to \ as well. */ if (s[0] == '/' && is_alpha(s[1]) && s[2] == ':' && s[3] == '/') s++; #endif p = path = malloc(strlen(s) + 1); 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) { unicode = c & 3; continuation_bytes = 2; } else if (c >= 0xC0) { unicode = c & 1; continuation_bytes = 1; } } else if ((c & 0xC0) != 0x80) break; else { unicode <<= 6; unicode |= (c & 0x3F); if (!--continuation_bytes && !valid_unicode(unicode)) break; } *p++ = c; s += 3; } } 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; } *p++ = '\0'; return realloc(path, p - path); } 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; }