winemenubuilder: Escape freedesktop exec keys properly.

This commit is contained in:
Damjan Jovanovic 2010-05-08 23:20:32 +02:00 committed by Alexandre Julliard
parent c545982472
commit 745747688d
1 changed files with 105 additions and 67 deletions

View File

@ -792,6 +792,36 @@ static BOOL create_directories(char *directory)
return ret;
}
static char* wchars_to_utf8_chars(LPCWSTR string)
{
char *ret;
INT size = WideCharToMultiByte(CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
ret = HeapAlloc(GetProcessHeap(), 0, size);
if (ret)
WideCharToMultiByte(CP_UTF8, 0, string, -1, ret, size, NULL, NULL);
return ret;
}
static char* wchars_to_unix_chars(LPCWSTR string)
{
char *ret;
INT size = WideCharToMultiByte(CP_UNIXCP, 0, string, -1, NULL, 0, NULL, NULL);
ret = HeapAlloc(GetProcessHeap(), 0, size);
if (ret)
WideCharToMultiByte(CP_UNIXCP, 0, string, -1, ret, size, NULL, NULL);
return ret;
}
static WCHAR* utf8_chars_to_wchars(LPCSTR string)
{
WCHAR *ret;
INT size = MultiByteToWideChar(CP_UTF8, 0, string, -1, NULL, 0);
ret = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
if (ret)
MultiByteToWideChar(CP_UTF8, 0, string, -1, ret, size);
return ret;
}
/* extract an icon from an exe or icon file; helper for IPersistFile_fnSave */
static char *extract_icon( LPCWSTR path, int index, const char *destFilename, BOOL bWait )
{
@ -945,7 +975,7 @@ static BOOL write_desktop_entry(const char *unix_link, const char *location, con
fprintf(file, "[Desktop Entry]\n");
fprintf(file, "Name=%s\n", linkname);
fprintf(file, "Exec=env WINEPREFIX=\"%s\" wine \"%s\" %s\n",
fprintf(file, "Exec=env WINEPREFIX=\"%s\" wine %s %s\n",
wine_get_config_dir(), path, args);
fprintf(file, "Type=Application\n");
fprintf(file, "StartupNotify=true\n");
@ -1154,35 +1184,63 @@ end:
return ret;
}
/* This escapes \ in filenames */
/* This escapes reserved characters in .desktop files' Exec keys. */
static LPSTR escape(LPCWSTR arg)
{
LPSTR narg, x;
LPCWSTR esc;
int len = 0, n;
int i, j;
WCHAR *escaped_string;
char *utf8_string;
esc = arg;
while((esc = strchrW(esc, '\\')))
escaped_string = HeapAlloc(GetProcessHeap(), 0, (4 * strlenW(arg) + 1) * sizeof(WCHAR));
if (escaped_string == NULL) return NULL;
for (i = j = 0; arg[i]; i++)
{
esc++;
len++;
switch (arg[i])
{
case '\\':
escaped_string[j++] = '\\';
escaped_string[j++] = '\\';
escaped_string[j++] = '\\';
escaped_string[j++] = '\\';
break;
case ' ':
case '\t':
case '\n':
case '"':
case '\'':
case '>':
case '<':
case '~':
case '|':
case '&':
case ';':
case '$':
case '*':
case '?':
case '#':
case '(':
case ')':
case '`':
escaped_string[j++] = '\\';
escaped_string[j++] = '\\';
/* fall through */
default:
escaped_string[j++] = arg[i];
break;
}
}
escaped_string[j] = 0;
utf8_string = wchars_to_utf8_chars(escaped_string);
if (utf8_string == NULL)
{
WINE_ERR("out of memory\n");
goto end;
}
len += WideCharToMultiByte(CP_UNIXCP, 0, arg, -1, NULL, 0, NULL, NULL);
narg = HeapAlloc(GetProcessHeap(), 0, len);
x = narg;
while (*arg)
{
n = WideCharToMultiByte(CP_UNIXCP, 0, arg, 1, x, len, NULL, NULL);
x += n;
len -= n;
if (*arg == '\\')
*x++='\\'; /* escape \ */
arg++;
}
*x = 0;
return narg;
end:
HeapFree(GetProcessHeap(), 0, escaped_string);
return utf8_string;
}
/* Return a heap-allocated copy of the unix format difference between the two
@ -1424,36 +1482,6 @@ static WCHAR* assoc_query(ASSOCSTR assocStr, LPCWSTR name, LPCWSTR extra)
return value;
}
static char* wchars_to_utf8_chars(LPCWSTR string)
{
char *ret;
INT size = WideCharToMultiByte(CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
ret = HeapAlloc(GetProcessHeap(), 0, size);
if (ret)
WideCharToMultiByte(CP_UTF8, 0, string, -1, ret, size, NULL, NULL);
return ret;
}
static char* wchars_to_unix_chars(LPCWSTR string)
{
char *ret;
INT size = WideCharToMultiByte(CP_UNIXCP, 0, string, -1, NULL, 0, NULL, NULL);
ret = HeapAlloc(GetProcessHeap(), 0, size);
if (ret)
WideCharToMultiByte(CP_UNIXCP, 0, string, -1, ret, size, NULL, NULL);
return ret;
}
static WCHAR* utf8_chars_to_wchars(LPCSTR string)
{
WCHAR *ret;
INT size = MultiByteToWideChar(CP_UTF8, 0, string, -1, NULL, 0);
ret = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
if (ret)
MultiByteToWideChar(CP_UTF8, 0, string, -1, ret, size);
return ret;
}
static char *slashes_to_minuses(const char *string)
{
int i;
@ -2135,7 +2163,7 @@ static BOOL generate_associations(const char *xdg_data_home, const char *package
progIdW = reg_get_valW(HKEY_CLASSES_ROOT, extensionW, NULL);
if (progIdW)
{
progIdA = wchars_to_utf8_chars(progIdW);
progIdA = escape(progIdW);
if (progIdA == NULL)
{
WINE_ERR("out of memory\n");
@ -2187,7 +2215,7 @@ static BOOL InvokeShellLinker( IShellLinkW *sl, LPCWSTR link, BOOL bWait )
static const WCHAR startW[] = {'\\','c','o','m','m','a','n','d',
'\\','s','t','a','r','t','.','e','x','e',0};
char *link_name = NULL, *icon_name = NULL, *work_dir = NULL;
char *escaped_path = NULL, *escaped_args = NULL, *escaped_description = NULL;
char *escaped_path = NULL, *escaped_args = NULL, *description = NULL;
WCHAR szTmp[INFOTIPSIZE];
WCHAR szDescription[INFOTIPSIZE], szPath[MAX_PATH], szWorkDir[MAX_PATH];
WCHAR szArgs[INFOTIPSIZE], szIconPath[MAX_PATH];
@ -2311,7 +2339,12 @@ static BOOL InvokeShellLinker( IShellLinkW *sl, LPCWSTR link, BOOL bWait )
/* escape the path and parameters */
escaped_path = escape(szPath);
escaped_args = escape(szArgs);
escaped_description = escape(szDescription);
description = wchars_to_utf8_chars(szDescription);
if (escaped_path == NULL || escaped_args == NULL || description == NULL)
{
WINE_ERR("out of memory allocating/escaping parameters\n");
goto cleanup;
}
/* building multiple menus concurrently has race conditions */
hsem = CreateSemaphoreA( NULL, 1, 1, "winemenubuilder_semaphore");
@ -2333,7 +2366,7 @@ static BOOL InvokeShellLinker( IShellLinkW *sl, LPCWSTR link, BOOL bWait )
location = heap_printf("%s/%s.desktop", xdg_desktop_dir, lastEntry);
if (location)
{
r = !write_desktop_entry(NULL, location, lastEntry, escaped_path, escaped_args, escaped_description, work_dir, icon_name);
r = !write_desktop_entry(NULL, location, lastEntry, escaped_path, escaped_args, description, work_dir, icon_name);
if (r == 0)
chmod(location, 0755);
HeapFree(GetProcessHeap(), 0, location);
@ -2341,21 +2374,21 @@ static BOOL InvokeShellLinker( IShellLinkW *sl, LPCWSTR link, BOOL bWait )
}
else
{
char *arg = heap_printf("/Unix \"%s\"", unix_link);
if (arg)
WCHAR *unix_linkW = utf8_chars_to_wchars(unix_link);
if (unix_linkW)
{
WCHAR *warg = utf8_chars_to_wchars(arg);
if (warg)
char *escaped_lnk = escape(unix_linkW);
if (escaped_lnk)
{
char *menuarg = escape(warg);
char *menuarg = heap_printf("/Unix %s", escaped_lnk);
if (menuarg)
{
r = !write_menu_entry(unix_link, link_name, "start", menuarg, escaped_description, work_dir, icon_name);
r = !write_menu_entry(unix_link, link_name, "start", menuarg, description, work_dir, icon_name);
HeapFree(GetProcessHeap(), 0, menuarg);
}
HeapFree(GetProcessHeap(), 0, warg);
HeapFree(GetProcessHeap(), 0, escaped_lnk);
}
HeapFree(GetProcessHeap(), 0, arg);
HeapFree(GetProcessHeap(), 0, unix_linkW);
}
}
@ -2368,7 +2401,7 @@ cleanup:
HeapFree( GetProcessHeap(), 0, link_name );
HeapFree( GetProcessHeap(), 0, escaped_args );
HeapFree( GetProcessHeap(), 0, escaped_path );
HeapFree( GetProcessHeap(), 0, escaped_description );
HeapFree( GetProcessHeap(), 0, description );
HeapFree( GetProcessHeap(), 0, unix_link);
if (r && !bWait)
@ -2424,6 +2457,11 @@ static BOOL InvokeShellLinkerForURL( IUniformResourceLocatorW *url, LPCWSTR link
}
escaped_urlPath = escape(urlPath);
if (escaped_urlPath == NULL)
{
WINE_ERR("couldn't escape url, out of memory\n");
goto cleanup;
}
hSem = CreateSemaphoreA( NULL, 1, 1, "winemenubuilder_semaphore");
if( WAIT_OBJECT_0 != MsgWaitForMultipleObjects( 1, &hSem, FALSE, INFINITE, QS_ALLINPUT ) )