ali@459: /* ali@459: * Copyright (C) 2014 J. Ali Harlow ali@459: * ali@459: * This program is free software; you can redistribute it and/or modify ali@459: * it under the terms of the GNU General Public License as published by ali@459: * the Free Software Foundation; either version 2 of the License, or ali@459: * (at your option) any later version. ali@459: * ali@459: * This program is distributed in the hope that it will be useful, ali@459: * but WITHOUT ANY WARRANTY; without even the implied warranty of ali@459: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ali@459: * GNU General Public License for more details. ali@459: * ali@459: * You should have received a copy of the GNU General Public License along ali@459: * with this program; if not, write to the Free Software Foundation, Inc., ali@459: * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ali@459: */ ali@459: ali@459: #include "config.h" ali@459: #include ali@459: #include ali@459: #include "razor.h" ali@459: #include "razor-internal.h" ali@459: ali@459: /** ali@459: * razor_path_add_root: ali@459: * ali@459: * Adds a root to a path. path must be an absolute pathname. In POSIX ali@459: * environments this is equivalent to the concationation of root and path. ali@459: * In Microsoft Windows an adjustment may need to be made for a drive letter ali@459: * in path (which will be dropped). ali@459: * ali@459: * Returns: The new pathname. ali@459: **/ ali@459: RAZOR_EXPORT char *razor_path_add_root(const char *path, const char *root) ali@459: { ali@459: if (root && *root) ali@459: return razor_concat(root, SKIP_DRIVE_LETTER(path), NULL); ali@459: else ali@459: return strdup(path); ali@459: } ali@459: ali@459: #if 0 ali@459: ali@459: /* ali@459: * This should work, but for some reason PathCreateFromUrlW() ali@459: * treats the percent-encoded bytes as being in CP 850 rather ali@459: * than UTF-8 as expected even if we set the codepage. ali@459: */ ali@459: RAZOR_EXPORT char *razor_path_from_url(const char *url) ali@459: { ali@459: UINT saved_cp; ali@459: HRESULT result; ali@459: DWORD len = MAX_PATH; ali@459: wchar_t *url16; ali@459: wchar_t path16[MAX_PATH]; ali@459: char *path; ali@459: ali@459: url16 = razor_utf8_to_utf16(url, -1); ali@459: ali@459: saved_cp = GetConsoleCP(); ali@459: SetConsoleCP(CP_UTF8); ali@459: ali@459: result = PathCreateFromUrlW(url16, path16, &len, NULL); ali@459: ali@459: SetConsoleCP(saved_cp); ali@459: ali@459: if (result == S_OK) ali@459: path = razor_utf16_to_utf8(path16, len); ali@459: else ali@459: path = NULL; ali@459: ali@459: free(url16); ali@459: ali@459: return path; ali@459: } ali@459: ali@459: #else ali@459: ali@459: #ifdef MSWIN_API ali@459: static int is_ascii_letter(char c) ali@459: { ali@459: return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); ali@459: } ali@459: #endif ali@459: ali@459: static int xdigit_value(char c) ali@459: { ali@459: if (c >= '0' && c <= '9') ali@459: return c - '0'; ali@459: else ali@459: return (c | 0x20) - 'a' + 10; ali@459: } ali@459: ali@459: static int valid_unicode(unsigned unicode) ali@459: { ali@459: /* ali@459: * Within the U+0000..U+10FFFF range defined by RFC3629 ali@459: * but not in the U+D800..U+DFFF range prohibited in UTF-8. ali@459: */ ali@459: return unicode < 0xD800 || (unicode >= 0xE000 && unicode < 0x110000); ali@459: } ali@459: ali@459: RAZOR_EXPORT char *razor_path_from_url(const char *url) ali@459: { ali@459: int continuation_bytes = 0; ali@459: char *path, *p; ali@459: unsigned char c; ali@459: unsigned unicode; ali@459: ali@459: if (strncmp(url, "file://", 7) == 0) ali@459: url += 7; ali@459: else ali@459: return NULL; ali@459: ali@459: if (strncmp(url, "localhost/", 10) == 0) ali@459: url += 9; ali@459: else if (strncmp(url, "/", 1) != 0) ali@459: return NULL; ali@459: ali@459: #ifdef MSWIN_API ali@459: /* ali@459: * Under MS-Windows, file:///c:/xxx maps to c:/xxx ali@459: * Note that PathCreateFromUrl converts / to \ as well. ali@459: */ ali@459: if (is_ascii_letter(url[1]) && url[2] == ':' && url[3] == '/') ali@459: url++; ali@459: #endif ali@459: ali@459: p = path = malloc(strlen(url) + 1); ali@459: ali@459: while(*url) { ali@459: if (*url >= 0x7F || *url < 0x20) { ali@459: free(path); ali@459: return NULL; ali@459: } else if (*url != '%') { ali@459: if (continuation_bytes) { ali@459: free(path); ali@459: return NULL; ali@459: } else ali@459: *p++ = *url++; ali@459: } else if (isxdigit(url[1]) && isxdigit(url[2])) { ali@459: c = xdigit_value(url[1]) * 16 + xdigit_value(url[2]); ali@459: if (c == '/') { ali@459: free(path); ali@459: return NULL; ali@459: } else if (!continuation_bytes) { ali@459: if (c >= 0xF5 || c == 0xC0 || c == 0xC1) { ali@459: free(path); ali@459: return NULL; ali@459: } else if (c >= 0xF0) { ali@459: unicode = c & 7; ali@459: continuation_bytes = 3; ali@459: } else if (c >= 0xE0) { ali@459: unicode = c & 3; ali@459: continuation_bytes = 2; ali@459: } else if (c >= 0xC0) { ali@459: unicode = c & 1; ali@459: continuation_bytes = 1; ali@459: } ali@459: } else if ((c & 0xC0) != 0x80) { ali@459: free(path); ali@459: return NULL; ali@459: } else { ali@459: unicode <<= 6; ali@459: unicode |= (c & 0x3F); ali@459: ali@459: if (!--continuation_bytes && ali@459: !valid_unicode(unicode)) { ali@459: free(path); ali@459: return NULL; ali@459: } ali@459: } ali@459: ali@459: *p++ = c; ali@459: url += 3; ali@459: } else { ali@459: free(path); ali@459: return NULL; ali@459: } ali@459: } ali@459: ali@459: if (continuation_bytes) { ali@459: free(path); ali@459: return NULL; ali@459: } ali@459: ali@459: *p++ = '\0'; ali@459: ali@459: return realloc(path, p - path); ali@459: } ali@459: ali@459: #endif /* 0 */