| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  | /* GIO - GLib Input, Output and Streaming Library
 | 
					
						
							|  |  |  |  *
 | 
					
						
							|  |  |  |  * Copyright (C) 2014 Patrick Griffis
 | 
					
						
							|  |  |  |  *
 | 
					
						
							|  |  |  |  * This library is free software; you can redistribute it and/or
 | 
					
						
							|  |  |  |  * modify it under the terms of the GNU Lesser General Public
 | 
					
						
							|  |  |  |  * License as published by the Free Software Foundation; either
 | 
					
						
							| 
									
										
										
										
											2017-05-27 18:21:30 +02:00
										 |  |  |  * version 2.1 of the License, or (at your option) any later version.
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  |  *
 | 
					
						
							|  |  |  |  * This library is distributed in the hope that it will be useful,
 | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
					
						
							|  |  |  |  * Lesser General Public License for more details.
 | 
					
						
							|  |  |  |  *
 | 
					
						
							|  |  |  |  * You should have received a copy of the GNU Lesser General
 | 
					
						
							|  |  |  |  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							|  |  |  |  *
 | 
					
						
							|  |  |  |  */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "config.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "gcontenttype.h"
 | 
					
						
							|  |  |  | #include "gicon.h"
 | 
					
						
							|  |  |  | #include "gthemedicon.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <CoreServices/CoreServices.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-11 15:59:16 +02:00
										 |  |  | #define XDG_PREFIX _gio_xdg
 | 
					
						
							|  |  |  | #include "xdgmime/xdgmime.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* We lock this mutex whenever we modify global state in this module.  */
 | 
					
						
							|  |  |  | G_LOCK_DEFINE_STATIC (gio_xdgmime);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | /*< internal >
 | 
					
						
							|  |  |  |  * create_cfstring_from_cstr:
 | 
					
						
							|  |  |  |  * @cstr: a #gchar
 | 
					
						
							|  |  |  |  *
 | 
					
						
							|  |  |  |  * Converts a cstr to a utf8 cfstring
 | 
					
						
							|  |  |  |  * It must be CFReleased()'d.
 | 
					
						
							|  |  |  |  *
 | 
					
						
							|  |  |  |  */
 | 
					
						
							|  |  |  | static CFStringRef
 | 
					
						
							|  |  |  | create_cfstring_from_cstr (const gchar *cstr)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |   return CFStringCreateWithCString (NULL, cstr, kCFStringEncodingUTF8);
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*< internal >
 | 
					
						
							|  |  |  |  * create_cstr_from_cfstring:
 | 
					
						
							|  |  |  |  * @str: a #CFStringRef
 | 
					
						
							|  |  |  |  *
 | 
					
						
							|  |  |  |  * Converts a cfstring to a utf8 cstring.
 | 
					
						
							|  |  |  |  * The incoming cfstring is released for you.
 | 
					
						
							|  |  |  |  * The returned string must be g_free()'d.
 | 
					
						
							|  |  |  |  *
 | 
					
						
							|  |  |  |  */
 | 
					
						
							|  |  |  | static gchar *
 | 
					
						
							|  |  |  | create_cstr_from_cfstring (CFStringRef str)
 | 
					
						
							|  |  |  | {
 | 
					
						
							| 
									
										
										
										
											2017-10-15 13:16:44 +02:00
										 |  |  |   g_return_val_if_fail (str != NULL, NULL);
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-15 13:16:44 +02:00
										 |  |  |   CFIndex length = CFStringGetLength (str);
 | 
					
						
							|  |  |  |   CFIndex maxlen = CFStringGetMaximumSizeForEncoding (length, kCFStringEncodingUTF8);
 | 
					
						
							|  |  |  |   gchar *buffer = g_malloc (maxlen + 1);
 | 
					
						
							|  |  |  |   Boolean success = CFStringGetCString (str, (char *) buffer, maxlen,
 | 
					
						
							|  |  |  |                                         kCFStringEncodingUTF8);
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  |   CFRelease (str);
 | 
					
						
							| 
									
										
										
										
											2017-10-15 13:16:44 +02:00
										 |  |  |   if (success)
 | 
					
						
							|  |  |  |     return buffer;
 | 
					
						
							|  |  |  |   else
 | 
					
						
							|  |  |  |     {
 | 
					
						
							|  |  |  |       g_free (buffer);
 | 
					
						
							|  |  |  |       return NULL;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*< internal >
 | 
					
						
							|  |  |  |  * create_cstr_from_cfstring_with_fallback:
 | 
					
						
							|  |  |  |  * @str: a #CFStringRef
 | 
					
						
							|  |  |  |  * @fallback: a #gchar
 | 
					
						
							|  |  |  |  *
 | 
					
						
							|  |  |  |  * Tries to convert a cfstring to a utf8 cstring.
 | 
					
						
							|  |  |  |  * If @str is NULL or conversion fails @fallback is returned.
 | 
					
						
							|  |  |  |  * The incoming cfstring is released for you.
 | 
					
						
							|  |  |  |  * The returned string must be g_free()'d.
 | 
					
						
							|  |  |  |  *
 | 
					
						
							|  |  |  |  */
 | 
					
						
							|  |  |  | static gchar *
 | 
					
						
							|  |  |  | create_cstr_from_cfstring_with_fallback (CFStringRef  str,
 | 
					
						
							|  |  |  |                                          const gchar *fallback)
 | 
					
						
							|  |  |  | {
 | 
					
						
							| 
									
										
										
										
											2017-10-22 12:12:59 +02:00
										 |  |  |   gchar *cstr = NULL;
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-22 12:12:59 +02:00
										 |  |  |   if (str)
 | 
					
						
							|  |  |  |     cstr = create_cstr_from_cfstring (str);
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  |   if (!cstr)
 | 
					
						
							|  |  |  |     return g_strdup (fallback);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return cstr;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-18 11:33:44 +01:00
										 |  |  | /*< private >*/
 | 
					
						
							|  |  |  | void
 | 
					
						
							|  |  |  | g_content_type_set_mime_dirs (const gchar * const *dirs)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |   /* noop on macOS */
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*< private >*/
 | 
					
						
							|  |  |  | const gchar * const *
 | 
					
						
							|  |  |  | g_content_type_get_mime_dirs (void)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |   const gchar * const *mime_dirs = { NULL };
 | 
					
						
							|  |  |  |   return mime_dirs;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  | gboolean
 | 
					
						
							|  |  |  | g_content_type_equals (const gchar *type1,
 | 
					
						
							|  |  |  |                        const gchar *type2)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |   CFStringRef str1, str2;
 | 
					
						
							|  |  |  |   gboolean ret;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   g_return_val_if_fail (type1 != NULL, FALSE);
 | 
					
						
							|  |  |  |   g_return_val_if_fail (type2 != NULL, FALSE);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (g_ascii_strcasecmp (type1, type2) == 0)
 | 
					
						
							|  |  |  |     return TRUE;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   str1 = create_cfstring_from_cstr (type1);
 | 
					
						
							|  |  |  |   str2 = create_cfstring_from_cstr (type2);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ret = UTTypeEqual (str1, str2);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   CFRelease (str1);
 | 
					
						
							|  |  |  |   CFRelease (str2);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return ret;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | gboolean
 | 
					
						
							|  |  |  | g_content_type_is_a (const gchar *ctype,
 | 
					
						
							|  |  |  |                      const gchar *csupertype)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |   CFStringRef type, supertype;
 | 
					
						
							|  |  |  |   gboolean ret;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   g_return_val_if_fail (ctype != NULL, FALSE);
 | 
					
						
							|  |  |  |   g_return_val_if_fail (csupertype != NULL, FALSE);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   type = create_cfstring_from_cstr (ctype);
 | 
					
						
							|  |  |  |   supertype = create_cfstring_from_cstr (csupertype);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ret = UTTypeConformsTo (type, supertype);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   CFRelease (type);
 | 
					
						
							|  |  |  |   CFRelease (supertype);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return ret;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-24 01:52:27 -04:00
										 |  |  | gboolean
 | 
					
						
							|  |  |  | g_content_type_is_mime_type (const gchar *type,
 | 
					
						
							|  |  |  |                              const gchar *mime_type)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |   gchar *content_type;
 | 
					
						
							|  |  |  |   gboolean ret;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   g_return_val_if_fail (type != NULL, FALSE);
 | 
					
						
							|  |  |  |   g_return_val_if_fail (mime_type != NULL, FALSE);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   content_type = g_content_type_from_mime_type (mime_type);
 | 
					
						
							|  |  |  |   ret = g_content_type_is_a (type, content_type);
 | 
					
						
							|  |  |  |   g_free (content_type);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return ret;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  | gboolean
 | 
					
						
							|  |  |  | g_content_type_is_unknown (const gchar *type)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |   g_return_val_if_fail (type != NULL, FALSE);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Should dynamic types be considered "unknown"? */
 | 
					
						
							|  |  |  |   if (g_str_has_prefix (type, "dyn."))
 | 
					
						
							|  |  |  |     return TRUE;
 | 
					
						
							|  |  |  |   /* application/octet-stream */
 | 
					
						
							|  |  |  |   else if (g_strcmp0 (type, "public.data") == 0)
 | 
					
						
							|  |  |  |     return TRUE;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return FALSE;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | gchar *
 | 
					
						
							|  |  |  | g_content_type_get_description (const gchar *type)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |   CFStringRef str;
 | 
					
						
							|  |  |  |   CFStringRef desc_str;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   g_return_val_if_fail (type != NULL, NULL);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   str = create_cfstring_from_cstr (type);
 | 
					
						
							|  |  |  |   desc_str = UTTypeCopyDescription (str);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   CFRelease (str);
 | 
					
						
							|  |  |  |   return create_cstr_from_cfstring_with_fallback (desc_str, "unknown");
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-04 00:39:38 +01:00
										 |  |  | /* <internal>
 | 
					
						
							|  |  |  |  * _get_generic_icon_name_from_mime_type
 | 
					
						
							|  |  |  |  *
 | 
					
						
							|  |  |  |  * This function produces a generic icon name from a @mime_type.
 | 
					
						
							|  |  |  |  * If no generic icon name is found in the xdg mime database, the
 | 
					
						
							|  |  |  |  * generic icon name is constructed.
 | 
					
						
							|  |  |  |  *
 | 
					
						
							|  |  |  |  * Background:
 | 
					
						
							|  |  |  |  * generic-icon elements specify the icon to use as a generic icon for this
 | 
					
						
							|  |  |  |  * particular mime-type, given by the name attribute. This is used if there
 | 
					
						
							|  |  |  |  * is no specific icon (see icon for how these are found). These are used
 | 
					
						
							|  |  |  |  * for categories of similar types (like spreadsheets or archives) that can
 | 
					
						
							|  |  |  |  * use a common icon. The Icon Naming Specification lists a set of such
 | 
					
						
							|  |  |  |  * icon names. If this element is not specified then the mimetype is used
 | 
					
						
							|  |  |  |  * to generate the generic icon by using the top-level media type
 | 
					
						
							|  |  |  |  * (e.g. "video" in "video/ogg") and appending "-x-generic"
 | 
					
						
							|  |  |  |  * (i.e. "video-x-generic" in the previous example).
 | 
					
						
							|  |  |  |  *
 | 
					
						
							|  |  |  |  * From: https://specifications.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-0.18.html
 | 
					
						
							|  |  |  |  */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static gchar *
 | 
					
						
							|  |  |  | _get_generic_icon_name_from_mime_type (const gchar *mime_type)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |   const gchar *xdg_icon_name;
 | 
					
						
							|  |  |  |   gchar *icon_name;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   G_LOCK (gio_xdgmime);
 | 
					
						
							|  |  |  |   xdg_icon_name = xdg_mime_get_generic_icon (mime_type);
 | 
					
						
							|  |  |  |   G_UNLOCK (gio_xdgmime);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (xdg_icon_name == NULL)
 | 
					
						
							|  |  |  |     {
 | 
					
						
							|  |  |  |       const char *p;
 | 
					
						
							|  |  |  |       const char *suffix = "-x-generic";
 | 
					
						
							|  |  |  |       gsize prefix_len;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       p = strchr (mime_type, '/');
 | 
					
						
							|  |  |  |       if (p == NULL)
 | 
					
						
							|  |  |  |         prefix_len = strlen (mime_type);
 | 
					
						
							|  |  |  |       else
 | 
					
						
							|  |  |  |         prefix_len = p - mime_type;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       icon_name = g_malloc (prefix_len + strlen (suffix) + 1);
 | 
					
						
							|  |  |  |       memcpy (icon_name, mime_type, prefix_len);
 | 
					
						
							|  |  |  |       memcpy (icon_name + prefix_len, suffix, strlen (suffix));
 | 
					
						
							|  |  |  |       icon_name[prefix_len + strlen (suffix)] = 0;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |   else
 | 
					
						
							|  |  |  |     {
 | 
					
						
							|  |  |  |       icon_name = g_strdup (xdg_icon_name);
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return icon_name;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  | static GIcon *
 | 
					
						
							| 
									
										
										
										
											2017-10-27 23:45:14 +02:00
										 |  |  | g_content_type_get_icon_internal (const gchar *uti,
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  |                                   gboolean     symbolic)
 | 
					
						
							|  |  |  | {
 | 
					
						
							| 
									
										
										
										
											2017-10-27 23:45:14 +02:00
										 |  |  |   char *mimetype_icon;
 | 
					
						
							| 
									
										
										
										
											2017-11-04 00:39:38 +01:00
										 |  |  |   char *mime_type;
 | 
					
						
							| 
									
										
										
										
											2017-10-27 23:45:14 +02:00
										 |  |  |   char *generic_mimetype_icon = NULL;
 | 
					
						
							|  |  |  |   char *q;
 | 
					
						
							|  |  |  |   char *icon_names[6];
 | 
					
						
							|  |  |  |   int n = 0;
 | 
					
						
							|  |  |  |   GIcon *themed_icon;
 | 
					
						
							|  |  |  |   const char  *xdg_icon;
 | 
					
						
							|  |  |  |   int i;
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-27 23:45:14 +02:00
										 |  |  |   g_return_val_if_fail (uti != NULL, NULL);
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-04 00:39:38 +01:00
										 |  |  |   mime_type = g_content_type_get_mime_type (uti);
 | 
					
						
							| 
									
										
										
										
											2017-10-27 23:45:14 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   G_LOCK (gio_xdgmime);
 | 
					
						
							| 
									
										
										
										
											2017-11-04 00:39:38 +01:00
										 |  |  |   xdg_icon = xdg_mime_get_icon (mime_type);
 | 
					
						
							| 
									
										
										
										
											2017-10-27 23:45:14 +02:00
										 |  |  |   G_UNLOCK (gio_xdgmime);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (xdg_icon)
 | 
					
						
							|  |  |  |     icon_names[n++] = g_strdup (xdg_icon);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-04 00:39:38 +01:00
										 |  |  |   mimetype_icon = g_strdup (mime_type);
 | 
					
						
							| 
									
										
										
										
											2017-10-27 23:45:14 +02:00
										 |  |  |   while ((q = strchr (mimetype_icon, '/')) != NULL)
 | 
					
						
							|  |  |  |     *q = '-';
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-27 23:45:14 +02:00
										 |  |  |   icon_names[n++] = mimetype_icon;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-04 00:39:38 +01:00
										 |  |  |   generic_mimetype_icon = _get_generic_icon_name_from_mime_type (mime_type);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-27 23:45:14 +02:00
										 |  |  |   if (generic_mimetype_icon)
 | 
					
						
							|  |  |  |     icon_names[n++] = generic_mimetype_icon;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (symbolic)
 | 
					
						
							|  |  |  |     {
 | 
					
						
							|  |  |  |       for (i = 0; i < n; i++)
 | 
					
						
							|  |  |  |         {
 | 
					
						
							|  |  |  |           icon_names[n + i] = icon_names[i];
 | 
					
						
							|  |  |  |           icon_names[i] = g_strconcat (icon_names[i], "-symbolic", NULL);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       n += n;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-27 23:45:14 +02:00
										 |  |  |   themed_icon = g_themed_icon_new_from_names (icon_names, n);
 | 
					
						
							|  |  |  |  
 | 
					
						
							|  |  |  |   for (i = 0; i < n; i++)
 | 
					
						
							|  |  |  |     g_free (icon_names[i]);
 | 
					
						
							|  |  |  |  
 | 
					
						
							| 
									
										
										
										
											2017-11-04 00:39:38 +01:00
										 |  |  |   g_free(mime_type);
 | 
					
						
							| 
									
										
										
										
											2017-10-27 23:45:14 +02:00
										 |  |  |  
 | 
					
						
							|  |  |  |   return themed_icon;
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | GIcon *
 | 
					
						
							|  |  |  | g_content_type_get_icon (const gchar *type)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |   return g_content_type_get_icon_internal (type, FALSE);
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | GIcon *
 | 
					
						
							|  |  |  | g_content_type_get_symbolic_icon (const gchar *type)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |   return g_content_type_get_icon_internal (type, TRUE);
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | gchar *
 | 
					
						
							|  |  |  | g_content_type_get_generic_icon_name (const gchar *type)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |   return NULL;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | gboolean
 | 
					
						
							|  |  |  | g_content_type_can_be_executable (const gchar *type)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |   CFStringRef uti;
 | 
					
						
							|  |  |  |   gboolean ret = FALSE;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   g_return_val_if_fail (type != NULL, FALSE);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   uti = create_cfstring_from_cstr (type);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (UTTypeConformsTo (uti, kUTTypeApplication))
 | 
					
						
							|  |  |  |     ret = TRUE;
 | 
					
						
							|  |  |  |   else if (UTTypeConformsTo (uti, CFSTR("public.executable")))
 | 
					
						
							|  |  |  |     ret = TRUE;
 | 
					
						
							|  |  |  |   else if (UTTypeConformsTo (uti, CFSTR("public.script")))
 | 
					
						
							|  |  |  |     ret = TRUE;
 | 
					
						
							| 
									
										
										
										
											2017-03-22 01:37:43 -04:00
										 |  |  |   /* Our tests assert that all text can be executable... */
 | 
					
						
							|  |  |  |   else if (UTTypeConformsTo (uti, CFSTR("public.text")))
 | 
					
						
							|  |  |  |       ret = TRUE;
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   CFRelease (uti);
 | 
					
						
							|  |  |  |   return ret;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | gchar *
 | 
					
						
							|  |  |  | g_content_type_from_mime_type (const gchar *mime_type)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |   CFStringRef mime_str;
 | 
					
						
							|  |  |  |   CFStringRef uti_str;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   g_return_val_if_fail (mime_type != NULL, NULL);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Their api does not handle globs but they are common. */
 | 
					
						
							|  |  |  |   if (g_str_has_suffix (mime_type, "*"))
 | 
					
						
							|  |  |  |     {
 | 
					
						
							|  |  |  |       if (g_str_has_prefix (mime_type, "audio"))
 | 
					
						
							|  |  |  |         return g_strdup ("public.audio");
 | 
					
						
							|  |  |  |       if (g_str_has_prefix (mime_type, "image"))
 | 
					
						
							|  |  |  |         return g_strdup ("public.image");
 | 
					
						
							|  |  |  |       if (g_str_has_prefix (mime_type, "text"))
 | 
					
						
							|  |  |  |         return g_strdup ("public.text");
 | 
					
						
							|  |  |  |       if (g_str_has_prefix (mime_type, "video"))
 | 
					
						
							|  |  |  |         return g_strdup ("public.movie");
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Some exceptions are needed for gdk-pixbuf.
 | 
					
						
							|  |  |  |    * This list is not exhaustive.
 | 
					
						
							|  |  |  |    */
 | 
					
						
							|  |  |  |   if (g_str_has_prefix (mime_type, "image"))
 | 
					
						
							|  |  |  |     {
 | 
					
						
							|  |  |  |       if (g_str_has_suffix (mime_type, "x-icns"))
 | 
					
						
							|  |  |  |         return g_strdup ("com.apple.icns");
 | 
					
						
							|  |  |  |       if (g_str_has_suffix (mime_type, "x-tga"))
 | 
					
						
							|  |  |  |         return g_strdup ("com.truevision.tga-image");
 | 
					
						
							|  |  |  |       if (g_str_has_suffix (mime_type, "x-ico"))
 | 
					
						
							|  |  |  |         return g_strdup ("com.microsoft.ico ");
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* These are also not supported...
 | 
					
						
							|  |  |  |    * Used in glocalfileinfo.c
 | 
					
						
							|  |  |  |    */
 | 
					
						
							|  |  |  |   if (g_str_has_prefix (mime_type, "inode"))
 | 
					
						
							|  |  |  |     {
 | 
					
						
							|  |  |  |       if (g_str_has_suffix (mime_type, "directory"))
 | 
					
						
							| 
									
										
										
										
											2017-03-22 01:37:43 -04:00
										 |  |  |         return g_strdup ("public.folder");
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  |       if (g_str_has_suffix (mime_type, "symlink"))
 | 
					
						
							|  |  |  |         return g_strdup ("public.symlink");
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-22 01:37:43 -04:00
										 |  |  |   /* This is correct according to the Apple docs:
 | 
					
						
							|  |  |  |      https://developer.apple.com/library/content/documentation/Miscellaneous/Reference/UTIRef/Articles/System-DeclaredUniformTypeIdentifiers.html
 | 
					
						
							|  |  |  |   */
 | 
					
						
							|  |  |  |   if (strcmp (mime_type, "text/plain") == 0)
 | 
					
						
							|  |  |  |     return g_strdup ("public.text");
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Non standard type */
 | 
					
						
							|  |  |  |   if (strcmp (mime_type, "application/x-executable") == 0)
 | 
					
						
							|  |  |  |     return g_strdup ("public.executable");
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  |   mime_str = create_cfstring_from_cstr (mime_type);
 | 
					
						
							|  |  |  |   uti_str = UTTypeCreatePreferredIdentifierForTag (kUTTagClassMIMEType, mime_str, NULL);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   CFRelease (mime_str);
 | 
					
						
							|  |  |  |   return create_cstr_from_cfstring_with_fallback (uti_str, "public.data");
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | gchar *
 | 
					
						
							|  |  |  | g_content_type_get_mime_type (const gchar *type)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |   CFStringRef uti_str;
 | 
					
						
							|  |  |  |   CFStringRef mime_str;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   g_return_val_if_fail (type != NULL, NULL);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* We must match the additions above
 | 
					
						
							|  |  |  |    * so conversions back and forth work.
 | 
					
						
							|  |  |  |    */
 | 
					
						
							|  |  |  |   if (g_str_has_prefix (type, "public"))
 | 
					
						
							|  |  |  |     {
 | 
					
						
							|  |  |  |       if (g_str_has_suffix (type, ".image"))
 | 
					
						
							|  |  |  |         return g_strdup ("image/*");
 | 
					
						
							|  |  |  |       if (g_str_has_suffix (type, ".movie"))
 | 
					
						
							|  |  |  |         return g_strdup ("video/*");
 | 
					
						
							|  |  |  |       if (g_str_has_suffix (type, ".text"))
 | 
					
						
							|  |  |  |         return g_strdup ("text/*");
 | 
					
						
							|  |  |  |       if (g_str_has_suffix (type, ".audio"))
 | 
					
						
							|  |  |  |         return g_strdup ("audio/*");
 | 
					
						
							| 
									
										
										
										
											2017-03-22 01:37:43 -04:00
										 |  |  |       if (g_str_has_suffix (type, ".folder"))
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  |         return g_strdup ("inode/directory");
 | 
					
						
							|  |  |  |       if (g_str_has_suffix (type, ".symlink"))
 | 
					
						
							|  |  |  |         return g_strdup ("inode/symlink");
 | 
					
						
							| 
									
										
										
										
											2017-03-22 01:37:43 -04:00
										 |  |  |       if (g_str_has_suffix (type, ".executable"))
 | 
					
						
							|  |  |  |         return g_strdup ("application/x-executable");
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   uti_str = create_cfstring_from_cstr (type);
 | 
					
						
							|  |  |  |   mime_str = UTTypeCopyPreferredTagWithClass(uti_str, kUTTagClassMIMEType);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   CFRelease (uti_str);
 | 
					
						
							|  |  |  |   return create_cstr_from_cfstring_with_fallback (mime_str, "application/octet-stream");
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static gboolean
 | 
					
						
							|  |  |  | looks_like_text (const guchar *data,
 | 
					
						
							|  |  |  |                  gsize         data_size)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |   gsize i;
 | 
					
						
							|  |  |  |   guchar c;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (i = 0; i < data_size; i++)
 | 
					
						
							|  |  |  |     {
 | 
					
						
							|  |  |  |       c = data[i];
 | 
					
						
							|  |  |  |       if (g_ascii_iscntrl (c) && !g_ascii_isspace (c) && c != '\b')
 | 
					
						
							|  |  |  |         return FALSE;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |   return TRUE;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | gchar *
 | 
					
						
							|  |  |  | g_content_type_guess (const gchar  *filename,
 | 
					
						
							|  |  |  |                       const guchar *data,
 | 
					
						
							|  |  |  |                       gsize         data_size,
 | 
					
						
							|  |  |  |                       gboolean     *result_uncertain)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |   CFStringRef uti = NULL;
 | 
					
						
							|  |  |  |   gchar *cextension;
 | 
					
						
							|  |  |  |   CFStringRef extension;
 | 
					
						
							| 
									
										
										
										
											2017-03-22 01:37:43 -04:00
										 |  |  |   int uncertain = -1;
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   g_return_val_if_fail (data_size != (gsize) -1, NULL);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (filename && *filename)
 | 
					
						
							|  |  |  |     {
 | 
					
						
							|  |  |  |       gchar *basename = g_path_get_basename (filename);
 | 
					
						
							|  |  |  |       gchar *dirname = g_path_get_dirname (filename);
 | 
					
						
							|  |  |  |       gsize i = strlen (filename);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (filename[i - 1] == '/')
 | 
					
						
							|  |  |  |         {
 | 
					
						
							|  |  |  |           if (g_strcmp0 (dirname, "/Volumes") == 0)
 | 
					
						
							|  |  |  |             {
 | 
					
						
							|  |  |  |               uti = CFStringCreateCopy (NULL, kUTTypeVolume);
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |           else if ((cextension = strrchr (basename, '.')) != NULL)
 | 
					
						
							|  |  |  |             {
 | 
					
						
							|  |  |  |               cextension++;
 | 
					
						
							|  |  |  |               extension = create_cfstring_from_cstr (cextension);
 | 
					
						
							|  |  |  |               uti = UTTypeCreatePreferredIdentifierForTag (kUTTagClassFilenameExtension,
 | 
					
						
							|  |  |  |                                                            extension, NULL);
 | 
					
						
							|  |  |  |               CFRelease (extension);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               if (CFStringHasPrefix (uti, CFSTR ("dyn.")))
 | 
					
						
							|  |  |  |                 {
 | 
					
						
							|  |  |  |                   CFRelease (uti);
 | 
					
						
							|  |  |  |                   uti = CFStringCreateCopy (NULL, kUTTypeFolder);
 | 
					
						
							| 
									
										
										
										
											2017-03-22 01:37:43 -04:00
										 |  |  |                   uncertain = TRUE;
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  |                 }
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |           else
 | 
					
						
							|  |  |  |             {
 | 
					
						
							|  |  |  |               uti = CFStringCreateCopy (NULL, kUTTypeFolder);
 | 
					
						
							| 
									
										
										
										
											2017-03-22 01:37:43 -04:00
										 |  |  |               uncertain = TRUE; /* Matches Unix backend */
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  |             }
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |       else
 | 
					
						
							|  |  |  |         {
 | 
					
						
							|  |  |  |           /* GTK needs this... */
 | 
					
						
							|  |  |  |           if (g_str_has_suffix (basename, ".ui"))
 | 
					
						
							|  |  |  |             {
 | 
					
						
							|  |  |  |               uti = CFStringCreateCopy (NULL, kUTTypeXML);
 | 
					
						
							|  |  |  |             }
 | 
					
						
							| 
									
										
										
										
											2017-03-22 01:37:43 -04:00
										 |  |  |           else if (g_str_has_suffix (basename, ".txt"))
 | 
					
						
							|  |  |  |             {
 | 
					
						
							|  |  |  |               uti = CFStringCreateCopy (NULL, CFSTR ("public.text"));
 | 
					
						
							|  |  |  |             }
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  |           else if ((cextension = strrchr (basename, '.')) != NULL)
 | 
					
						
							|  |  |  |             {
 | 
					
						
							|  |  |  |               cextension++;
 | 
					
						
							|  |  |  |               extension = create_cfstring_from_cstr (cextension);
 | 
					
						
							|  |  |  |               uti = UTTypeCreatePreferredIdentifierForTag (kUTTagClassFilenameExtension,
 | 
					
						
							|  |  |  |                                                            extension, NULL);
 | 
					
						
							|  |  |  |               CFRelease (extension);
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |           g_free (basename);
 | 
					
						
							|  |  |  |           g_free (dirname);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2017-03-22 01:37:43 -04:00
										 |  |  |   if (data && (!filename || !uti ||
 | 
					
						
							|  |  |  |                CFStringCompare (uti, CFSTR ("public.data"), 0) == kCFCompareEqualTo))
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  |     {
 | 
					
						
							| 
									
										
										
										
											2017-10-11 15:59:16 +02:00
										 |  |  |       const char *sniffed_mimetype;
 | 
					
						
							|  |  |  |       G_LOCK (gio_xdgmime);
 | 
					
						
							|  |  |  |       sniffed_mimetype = xdg_mime_get_mime_type_for_data (data, data_size, NULL);
 | 
					
						
							|  |  |  |       G_UNLOCK (gio_xdgmime);
 | 
					
						
							|  |  |  |       if (sniffed_mimetype != XDG_MIME_TYPE_UNKNOWN)
 | 
					
						
							|  |  |  |         {
 | 
					
						
							|  |  |  |           gchar *uti_str = g_content_type_from_mime_type (sniffed_mimetype);
 | 
					
						
							|  |  |  |           uti = create_cfstring_from_cstr (uti_str);
 | 
					
						
							|  |  |  |           g_free (uti_str);
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |       if (!uti && looks_like_text (data, data_size))
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  |         {
 | 
					
						
							|  |  |  |           if (g_str_has_prefix ((const gchar*)data, "#!/"))
 | 
					
						
							|  |  |  |             uti = CFStringCreateCopy (NULL, CFSTR ("public.script"));
 | 
					
						
							|  |  |  |           else
 | 
					
						
							| 
									
										
										
										
											2017-03-22 01:37:43 -04:00
										 |  |  |             uti = CFStringCreateCopy (NULL, CFSTR ("public.text"));
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  |         }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!uti)
 | 
					
						
							|  |  |  |     {
 | 
					
						
							|  |  |  |       /* Generic data type */
 | 
					
						
							|  |  |  |       uti = CFStringCreateCopy (NULL, CFSTR ("public.data"));
 | 
					
						
							|  |  |  |       if (result_uncertain)
 | 
					
						
							|  |  |  |         *result_uncertain = TRUE;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2017-03-22 01:37:43 -04:00
										 |  |  |   else if (result_uncertain)
 | 
					
						
							|  |  |  |     {
 | 
					
						
							|  |  |  |       *result_uncertain = uncertain == -1 ? FALSE : uncertain;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2014-08-15 06:11:38 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return create_cstr_from_cfstring (uti);
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | GList *
 | 
					
						
							|  |  |  | g_content_types_get_registered (void)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |   /* TODO: UTTypeCreateAllIdentifiersForTag? */
 | 
					
						
							|  |  |  |   return NULL;
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | gchar **
 | 
					
						
							|  |  |  | g_content_type_guess_for_tree (GFile *root)
 | 
					
						
							|  |  |  | {
 | 
					
						
							|  |  |  |   return NULL;
 | 
					
						
							|  |  |  | }
 |