forked from enlightenment/efl
199 lines
4.8 KiB
C
199 lines
4.8 KiB
C
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
#ifdef _WIN32
|
|
# include <windows.h>
|
|
# include <shlwapi.h>
|
|
#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 <scheme>:[<authority>][<path>][<query>][<fragment>] */
|
|
|
|
/*
|
|
* 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);
|
|
}
|