#ifdef HAVE_CONFIG_H # include #endif #include #include #include #ifdef _WIN32 # include # include #endif #ifndef _POSIX_HOST_NAME_MAX #define _POSIX_HOST_NAME_MAX 255 #endif /* define macros and variable for using the eina logging system */ #define EFREET_MODULE_LOG_DOM /* no logging in this file */ #include "Efreet.h" #include "efreet_private.h" /* The URI standard is at http://tools.ietf.org/html/std66 */ EAPI Efreet_Uri * efreet_uri_decode(const char *full_uri) { Efreet_Uri *uri; const char *p; char scheme[64], authority[_POSIX_HOST_NAME_MAX], path[PATH_MAX]; char *sep; int i = 0; EINA_SAFETY_ON_NULL_RETURN_VAL(full_uri, NULL); /* An uri should be in the form :[][][][] */ /* * Specific code for Windows when the scheme part of full_uri is 'file', * for local Windows file path. * see https://docs.microsoft.com/en-us/archive/blogs/ie/file-uris-in-windows * * Correct syntax : * file:///c:/path/to/file * * The returned path must be c:\path\to\file */ #ifdef _WIN32 *scheme = 0; *authority = 0; *path = 0; if (strncasecmp(full_uri, "file://", strlen("file://")) == 0) { HRESULT res; DWORD len; # ifdef UNICODE wchar_t buf[MAX_PATH]; wchar_t *w_full_uri; char *uri; w_full_uri = evil_utf8_to_utf16(full_uri); if (!w_full_uri) return NULL; if (wcslen(w_full_uri) > 2048) { free(w_full_uri); return NULL; } len = sizeof(buf); res = PathCreateFromUrl(w_full_uri, buf, &len, 0UL); free(w_full_uri); if (res != S_OK) return NULL; uri = evil_utf16_to_utf8(buf); if (uri) { strncpy(path, uri, sizeof(path)); path[sizeof(path)-1] = 0; goto win32_file_scheme; } #else len = sizeof(path); res = PathCreateFromUrl(full_uri, path, &len, 0UL); if (res == S_OK) goto win32_file_scheme; #endif return NULL; } #endif sep = strchr(full_uri, ':'); if (!sep) return NULL; /* check if we have a Windows PATH, that is a letter follow by a colon */ if ((sep - full_uri) == 1) return NULL; memset(scheme, 0, 64); memset(authority, 0, _POSIX_HOST_NAME_MAX); memset(path, 0, PATH_MAX); /* parse scheme */ p = full_uri; for (i = 0; *p != ':' && *p != '\0' && i < (64 - 1); p++, i++) scheme[i] = *p; if (i == 0) return NULL; /* scheme is required */ scheme[i] = '\0'; /* parse authority */ p++; if (*p == '/') { p++; if (*p == '/') { p++; for (i = 0; *p != '/' && *p != '?' && *p != '#' && *p != '\0' && i < (_POSIX_HOST_NAME_MAX - 1); p++, i++) authority[i] = *p; authority[i] = '\0'; } else /* It's a path, let path parser handle the leading slash */ p--; } else authority[0] = '\0'; /* parse path */ /* See http://www.faqs.org/rfcs/rfc1738.html for the escaped chars */ for (i = 0; *p != '\0' && i < (PATH_MAX - 1); i++, p++) { if (*p == '%') { path[i] = *(++p); path[i + 1] = *(++p); path[i] = (char)strtol(&(path[i]), NULL, 16); path[i + 1] = '\0'; } else path[i] = *p; } #ifdef _WIN32 win32_file_scheme: strcpy(scheme, "file"); #endif uri = NEW(Efreet_Uri, 1); if (!uri) return NULL; uri->protocol = eina_stringshare_add(scheme); uri->hostname = eina_stringshare_add(authority); uri->path = eina_stringshare_add(path); return uri; } EAPI const char * efreet_uri_encode(Efreet_Uri *uri) { char dest[PATH_MAX * 3 + 4]; const char *p; int i; EINA_SAFETY_ON_NULL_RETURN_VAL(uri, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(uri->path, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(uri->protocol, NULL); memset(dest, 0, PATH_MAX * 3 + 4); snprintf(dest, strlen(uri->protocol) + 4, "%s://", uri->protocol); /* Most app doesn't handle the hostname in the uri so it's put to NULL */ for (i = strlen(uri->protocol) + 3, p = uri->path; *p != '\0'; p++, i++) { if (isalnum(*p) || strchr("/$-_.+!*'()", *p)) dest[i] = *p; else { snprintf(&(dest[i]), 4, "%%%02X", (unsigned char) *p); i += 2; } } return eina_stringshare_add(dest); } EAPI void efreet_uri_free(Efreet_Uri *uri) { if (!uri) return; IF_RELEASE(uri->protocol); IF_RELEASE(uri->path); IF_RELEASE(uri->hostname); FREE(uri); }