gtkfilechoosernativewin32: Fix support for non-ASCII paths
authorChristoph Reiter <creiter@src.gnome.org>
Fri, 2 Jun 2017 10:55:23 +0000 (12:55 +0200)
committerChristoph Reiter <creiter@src.gnome.org>
Fri, 2 Jun 2017 11:20:25 +0000 (13:20 +0200)
The code used SIGDN_URL to get an URL for the selected item, but Windows URLs
are a mix of unicode and percent encoded characters in the locale encoding
and not something GFile can understand. The result is a garbage file
path.

Instead use SIGDN_FILESYSPATH to get a real file path if available.

Also checks the return value of g_utf16_to_utf8 because file paths on
Windows can contain lone surrogates which would make the conversion fail.

https://bugzilla.gnome.org/show_bug.cgi?id=783347

gtk/gtkfilechoosernativewin32.c

index 22411d35be2b86d0e9286c2498d7963cecc46fbd..9a1a3a2c13d4581c35e29d9c0f91f14c7f406bf7 100644 (file)
@@ -342,22 +342,45 @@ filechooser_win32_thread_done (gpointer _data)
   return FALSE;
 }
 
+static GFile *
+get_file_for_shell_item (IShellItem *item)
+{
+  HRESULT hr;
+  PWSTR pathw = NULL;
+  char *path;
+  GFile *file;
+
+  hr = IShellItem_GetDisplayName (item, SIGDN_FILESYSPATH, &pathw);
+  if (SUCCEEDED (hr))
+    {
+      path = g_utf16_to_utf8 (pathw, -1, NULL, NULL, NULL);
+      CoTaskMemFree (pathw);
+      if (path != NULL)
+        {
+          file = g_file_new_for_path (path);
+          g_free (path);
+          return file;
+       }
+    }
+
+  /* TODO: also support URLs through SIGDN_URL, but Windows URLS are not
+   * RFC 3986 compliant and we'd need to convert them first.
+   */
+
+  return NULL;
+}
+
 static void
 data_add_shell_item (FilechooserWin32ThreadData *data,
                      IShellItem *item)
 {
-  HRESULT hr;
-  PWSTR urlw = NULL;
-  char *url;
+  GFile *file;
 
-  hr = IShellItem_GetDisplayName (item, SIGDN_URL, &urlw);
-  if (SUCCEEDED (hr))
+  file = get_file_for_shell_item (item);
+  if (file != NULL)
     {
-      url = g_utf16_to_utf8 (urlw, -1, NULL, NULL, NULL);
-      CoTaskMemFree (urlw);
-      data->files = g_slist_prepend (data->files, g_file_new_for_uri (url));
+      data->files = g_slist_prepend (data->files, file);
       data->response = GTK_RESPONSE_ACCEPT;
-      g_free (url);
     }
 }