winemenubuilder: add Wine's MIME types to freedesktop
Damjan Jovanovic
damjan.jov at gmail.com
Mon Apr 27 08:47:12 CDT 2009
Changelog:
* add Wine's MIME types to freedesktop
Damjan Jovanovic
-------------- next part --------------
diff --git a/programs/winemenubuilder/Makefile.in b/programs/winemenubuilder/Makefile.in
index 050b3b3..3d0af13 100644
--- a/programs/winemenubuilder/Makefile.in
+++ b/programs/winemenubuilder/Makefile.in
@@ -5,7 +5,7 @@ SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = winemenubuilder.exe
APPMODE = -mwindows
-IMPORTS = uuid shell32 ole32 user32 advapi32 kernel32
+IMPORTS = uuid shell32 ole32 user32 advapi32 kernel32 shlwapi
C_SRCS = \
winemenubuilder.c
diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c
index 58e84c6..df8c58c 100644
--- a/programs/winemenubuilder/winemenubuilder.c
+++ b/programs/winemenubuilder/winemenubuilder.c
@@ -64,6 +64,7 @@
#endif
#include <errno.h>
#include <stdarg.h>
+#include <fnmatch.h>
#define COBJMACROS
@@ -74,6 +75,7 @@
#include <appmgmt.h>
#include <tlhelp32.h>
#include <intshcut.h>
+#include <shlwapi.h>
#include "wine/unicode.h"
#include "wine/debug.h"
@@ -1251,6 +1253,38 @@ static HRESULT get_cmdline( IShellLinkW *sl, LPWSTR szPath, DWORD pathSize,
return hr;
}
+static WCHAR* assoc_query(ASSOCSTR assocStr, LPCWSTR name, LPCWSTR extra)
+{
+ HRESULT hr;
+ WCHAR *value = NULL;
+ DWORD size = 0;
+ hr = AssocQueryStringW(0, assocStr, name, extra, NULL, &size);
+ if (SUCCEEDED(hr))
+ {
+ value = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
+ if (value)
+ {
+ hr = AssocQueryStringW(0, assocStr, name, extra, value, &size);
+ if (FAILED(hr))
+ {
+ HeapFree(GetProcessHeap(), 0, value);
+ value = NULL;
+ }
+ }
+ }
+ return value;
+}
+
+static char* wchars_to_unix_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 BOOL next_line(FILE *file, char **line, int *size)
{
int pos = 0;
@@ -1316,9 +1350,12 @@ static BOOL add_mimes(const char *xdg_data_dir, struct list *mime_types)
if (mime_type_entry)
{
*pos = 0;
- mime_type_entry->mimeType = line;
- mime_type_entry->glob = pos + 1;
- list_add_tail(mime_types, &mime_type_entry->entry);
+ mime_type_entry->mimeType = heap_printf("%s", line);
+ mime_type_entry->glob = heap_printf("%s", pos + 1);
+ if (mime_type_entry->mimeType && mime_type_entry->glob)
+ list_add_tail(mime_types, &mime_type_entry->entry);
+ else
+ ret = FALSE;
}
else
ret = FALSE;
@@ -1341,6 +1378,7 @@ static void free_native_mime_types(struct list *native_mime_types)
LIST_FOR_EACH_ENTRY_SAFE(mime_type_entry, mime_type_entry2, native_mime_types, struct xdg_mime_type, entry)
{
list_remove(&mime_type_entry->entry);
+ HeapFree(GetProcessHeap(), 0, mime_type_entry->glob);
HeapFree(GetProcessHeap(), 0, mime_type_entry->mimeType);
HeapFree(GetProcessHeap(), 0, mime_type_entry);
}
@@ -1398,16 +1436,179 @@ static BOOL build_native_mime_types(const char *xdg_data_home, struct list **mim
return ret;
}
+static char* match_glob(struct list *native_mime_types, const char *extension, BOOL caseSensitive)
+{
+ struct xdg_mime_type *mime_type_entry;
+ char *match = NULL;
+ int matchLength = 0;
+
+ LIST_FOR_EACH_ENTRY(mime_type_entry, native_mime_types, struct xdg_mime_type, entry)
+ {
+ BOOL matched;
+ if (caseSensitive)
+ matched = (fnmatch(mime_type_entry->glob, extension, 0) == 0);
+ else
+#ifdef FNM_CASEFOLD
+ matched = (fnmatch(mime_type_entry->glob, extension, FNM_CASEFOLD) == 0);
+#else
+ WINE_FIXME("FNM_CASEFOLD is not implemented on your system\n");
+#endif
+ if (matched)
+ {
+ if (match == NULL || matchLength < strlen(mime_type_entry->glob))
+ {
+ match = mime_type_entry->mimeType;
+ matchLength = strlen(mime_type_entry->glob);
+ }
+ }
+ }
+ return match ? heap_printf("%s", match) : NULL;
+}
+
+static char* native_mime_type_for_extension(struct list *native_mime_types, const char *extension)
+{
+ char *mime_type;
+
+ mime_type = match_glob(native_mime_types, extension, TRUE);
+ if (mime_type)
+ return mime_type;
+ return match_glob(native_mime_types, extension, FALSE);
+}
+
+static BOOL write_freedesktop_mime_type_entry(const char *packages_dir, const char *dot_extension,
+ const char *mime_type, const char *comment)
+{
+ BOOL ret = FALSE;
+ char *filename;
+
+ filename = heap_printf("%s/x-wine-extension-%s.xml", packages_dir, &dot_extension[1]);
+ if (filename)
+ {
+ FILE *packageFile = fopen(filename, "w");
+ if (packageFile)
+ {
+ fprintf(packageFile, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ fprintf(packageFile, "<mime-info xmlns=\"http://www.freedesktop.org/standards/shared-mime-info\">\n");
+ fprintf(packageFile, " <mime-type type=\"%s\">\n", mime_type);
+ fprintf(packageFile, " <glob pattern=\"*%s\"/>\n", dot_extension);
+ if (comment)
+ fprintf(packageFile, " <comment>%s</comment>\n", comment);
+ fprintf(packageFile, " </mime-type>\n");
+ fprintf(packageFile, "</mime-info>\n");
+ ret = TRUE;
+ fclose(packageFile);
+ }
+ else
+ WINE_ERR("error writing file %s\n", filename);
+ HeapFree(GetProcessHeap(), 0, filename);
+ }
+ else
+ WINE_ERR("out of memory\n");
+ return ret;
+}
+
static BOOL generate_associations(const char *xdg_data_home, const char *packages_dir, const char *applications_dir)
{
struct list *nativeMimeTypes = NULL;
+ LSTATUS ret = 0;
+ int i;
+ BOOL hasChanged = FALSE;
if (!build_native_mime_types(xdg_data_home, &nativeMimeTypes))
{
WINE_ERR("could not build native MIME types\n");
return FALSE;
}
- return TRUE;
+
+ for (i = 0; ; i++)
+ {
+ WCHAR *extensionW;
+ DWORD size = 0;
+
+ ret = RegQueryInfoKeyW(HKEY_CLASSES_ROOT, 0, 0, 0, 0, &size, 0, 0, 0, 0, 0, 0);
+ if (ret != 0)
+ {
+ WINE_ERR("error reading registry\n");
+ break;
+ }
+ ++size;
+ extensionW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
+ if (extensionW == NULL)
+ {
+ WINE_ERR("out of memory\n");
+ break;
+ }
+ ret = RegEnumKeyExW(HKEY_CLASSES_ROOT, i, extensionW, &size, NULL, NULL, NULL, NULL);
+ if (ret == ERROR_SUCCESS && extensionW[0] == '.')
+ {
+ char *extensionA = NULL;
+ WCHAR *commandW = NULL;
+ WCHAR *friendlyDocNameW = NULL;
+ char *friendlyDocNameA = NULL;
+ WCHAR *contentTypeW = NULL;
+ char *mimeTypeA = NULL;
+
+ extensionA = wchars_to_unix_chars(extensionW);
+ if (extensionA == NULL)
+ {
+ WINE_ERR("out of memory\n");
+ goto end;
+ }
+
+ commandW = assoc_query(ASSOCSTR_COMMAND, extensionW, NULL);
+ if (commandW == NULL)
+ /* no command -> unusable extension */
+ goto end;
+
+ friendlyDocNameW = assoc_query(ASSOCSTR_FRIENDLYDOCNAME, extensionW, NULL);
+ if (friendlyDocNameW)
+ {
+ friendlyDocNameA = wchars_to_unix_chars(friendlyDocNameW);
+ if (friendlyDocNameA == NULL)
+ {
+ WINE_ERR("out of memory\n");
+ goto end;
+ }
+ }
+
+ contentTypeW = assoc_query(ASSOCSTR_CONTENTTYPE, extensionW, NULL);
+
+ mimeTypeA = native_mime_type_for_extension(nativeMimeTypes, extensionA);
+ if (mimeTypeA == NULL)
+ {
+ if (contentTypeW != NULL)
+ mimeTypeA = wchars_to_unix_chars(contentTypeW);
+ else
+ mimeTypeA = heap_printf("application/x-wine-extension-%s", &extensionA[1]);
+
+ if (mimeTypeA != NULL)
+ {
+ write_freedesktop_mime_type_entry(packages_dir, extensionA, mimeTypeA, friendlyDocNameA);
+ hasChanged = TRUE;
+ }
+ else
+ {
+ WINE_ERR("out of memory\n");
+ goto end;
+ }
+ }
+
+
+ end:
+ HeapFree(GetProcessHeap(), 0, extensionA);
+ HeapFree(GetProcessHeap(), 0, commandW);
+ HeapFree(GetProcessHeap(), 0, friendlyDocNameW);
+ HeapFree(GetProcessHeap(), 0, friendlyDocNameA);
+ HeapFree(GetProcessHeap(), 0, contentTypeW);
+ HeapFree(GetProcessHeap(), 0, mimeTypeA);
+ }
+ HeapFree(GetProcessHeap(), 0, extensionW);
+ if (ret != ERROR_SUCCESS)
+ break;
+ }
+
+ free_native_mime_types(nativeMimeTypes);
+ return hasChanged;
}
static BOOL InvokeShellLinker( IShellLinkW *sl, LPCWSTR link, BOOL bWait )
@@ -1841,6 +2042,7 @@ static void RefreshFileTypeAssociations(void)
char *mime_dir = NULL;
char *packages_dir = NULL;
char *applications_dir = NULL;
+ BOOL hasChanged;
hSem = CreateSemaphoreA( NULL, 1, 1, "winemenubuilder_semaphore");
if( WAIT_OBJECT_0 != MsgWaitForMultipleObjects( 1, &hSem, FALSE, INFINITE, QS_ALLINPUT ) )
@@ -1875,7 +2077,23 @@ static void RefreshFileTypeAssociations(void)
}
create_directories(applications_dir);
- generate_associations(xdg_data_dir, packages_dir, applications_dir);
+ hasChanged = generate_associations(xdg_data_dir, packages_dir, applications_dir);
+ if (hasChanged)
+ {
+ int unused;
+ char *command;
+ command = heap_printf("update-mime-database %s", mime_dir);
+ if (command)
+ {
+ unused = system(command);
+ HeapFree(GetProcessHeap(), 0, command);
+ }
+ else
+ {
+ WINE_ERR("out of memory\n");
+ goto end;
+ }
+ }
end:
if (hSem)
More information about the wine-patches
mailing list