Home | History | Annotate | Download | only in gio
      1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
      2 
      3 /* GIO - GLib Input, Output and Streaming Library
      4  *
      5  * Copyright (C) 2006-2007 Red Hat, Inc.
      6  *
      7  * This library is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU Lesser General Public
      9  * License as published by the Free Software Foundation; either
     10  * version 2 of the License, or (at your option) any later version.
     11  *
     12  * This library is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  * Lesser General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU Lesser General
     18  * Public License along with this library; if not, write to the
     19  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
     20  * Boston, MA 02111-1307, USA.
     21  *
     22  * Author: Alexander Larsson <alexl (at) redhat.com>
     23  */
     24 
     25 #include "config.h"
     26 #include <sys/types.h>
     27 #include <stdlib.h>
     28 #include <string.h>
     29 #include <stdio.h>
     30 #include "gcontenttypeprivate.h"
     31 #include "gthemedicon.h"
     32 #include "gicon.h"
     33 #include "gfile.h"
     34 #include "gfileenumerator.h"
     35 #include "gfileinfo.h"
     36 #include "glibintl.h"
     37 
     38 #include "gioalias.h"
     39 
     40 /**
     41  * SECTION:gcontenttype
     42  * @short_description: Platform-specific content typing
     43  * @include: gio/gio.h
     44  *
     45  * A content type is a platform specific string that defines the type
     46  * of a file. On unix it is a mime type, on win32 it is an extension string
     47  * like ".doc", ".txt" or a percieved string like "audio". Such strings
     48  * can be looked up in the registry at HKEY_CLASSES_ROOT.
     49  **/
     50 
     51 #ifdef G_OS_WIN32
     52 
     53 #include <windows.h>
     54 
     55 static char *
     56 get_registry_classes_key (const char    *subdir,
     57 			  const wchar_t *key_name)
     58 {
     59   wchar_t *wc_key;
     60   HKEY reg_key = NULL;
     61   DWORD key_type;
     62   DWORD nbytes;
     63   char *value_utf8;
     64 
     65   value_utf8 = NULL;
     66 
     67   nbytes = 0;
     68   wc_key = g_utf8_to_utf16 (subdir, -1, NULL, NULL, NULL);
     69   if (RegOpenKeyExW (HKEY_CLASSES_ROOT, wc_key, 0,
     70 		     KEY_QUERY_VALUE, &reg_key) == ERROR_SUCCESS &&
     71       RegQueryValueExW (reg_key, key_name, 0,
     72 			&key_type, NULL, &nbytes) == ERROR_SUCCESS &&
     73       (key_type == REG_SZ || key_type == REG_EXPAND_SZ))
     74     {
     75       wchar_t *wc_temp = g_new (wchar_t, (nbytes+1)/2 + 1);
     76       RegQueryValueExW (reg_key, key_name, 0,
     77 			&key_type, (LPBYTE) wc_temp, &nbytes);
     78       wc_temp[nbytes/2] = '\0';
     79       if (key_type == REG_EXPAND_SZ)
     80         {
     81           wchar_t dummy[1];
     82           int len = ExpandEnvironmentStringsW (wc_temp, dummy, 1);
     83           if (len > 0)
     84             {
     85               wchar_t *wc_temp_expanded = g_new (wchar_t, len);
     86               if (ExpandEnvironmentStringsW (wc_temp, wc_temp_expanded, len) == len)
     87                 value_utf8 = g_utf16_to_utf8 (wc_temp_expanded, -1, NULL, NULL, NULL);
     88               g_free (wc_temp_expanded);
     89             }
     90         }
     91       else
     92         {
     93           value_utf8 = g_utf16_to_utf8 (wc_temp, -1, NULL, NULL, NULL);
     94         }
     95       g_free (wc_temp);
     96 
     97     }
     98   g_free (wc_key);
     99 
    100   if (reg_key != NULL)
    101     RegCloseKey (reg_key);
    102 
    103   return value_utf8;
    104 }
    105 
    106 gboolean
    107 g_content_type_equals (const char *type1,
    108 		       const char *type2)
    109 {
    110   char *progid1, *progid2;
    111   gboolean res;
    112 
    113   g_return_val_if_fail (type1 != NULL, FALSE);
    114   g_return_val_if_fail (type2 != NULL, FALSE);
    115 
    116   if (g_ascii_strcasecmp (type1, type2) == 0)
    117     return TRUE;
    118 
    119   res = FALSE;
    120   progid1 = get_registry_classes_key (type1, NULL);
    121   progid2 = get_registry_classes_key (type2, NULL);
    122   if (progid1 != NULL && progid2 != NULL &&
    123       strcmp (progid1, progid2) == 0)
    124     res = TRUE;
    125   g_free (progid1);
    126   g_free (progid2);
    127 
    128   return res;
    129 }
    130 
    131 gboolean
    132 g_content_type_is_a (const char *type,
    133 		     const char *supertype)
    134 {
    135   gboolean res;
    136   char *value_utf8;
    137 
    138   g_return_val_if_fail (type != NULL, FALSE);
    139   g_return_val_if_fail (supertype != NULL, FALSE);
    140 
    141   if (g_content_type_equals (type, supertype))
    142     return TRUE;
    143 
    144   res = FALSE;
    145   value_utf8 = get_registry_classes_key (type, L"PerceivedType");
    146   if (value_utf8 && strcmp (value_utf8, supertype) == 0)
    147     res = TRUE;
    148   g_free (value_utf8);
    149 
    150   return res;
    151 }
    152 
    153 gboolean
    154 g_content_type_is_unknown (const char *type)
    155 {
    156   g_return_val_if_fail (type != NULL, FALSE);
    157 
    158   return strcmp ("*", type) == 0;
    159 }
    160 
    161 char *
    162 g_content_type_get_description (const char *type)
    163 {
    164   char *progid;
    165   char *description;
    166 
    167   g_return_val_if_fail (type != NULL, NULL);
    168 
    169   progid = get_registry_classes_key (type, NULL);
    170   if (progid)
    171     {
    172       description = get_registry_classes_key (progid, NULL);
    173       g_free (progid);
    174 
    175       if (description)
    176 	return description;
    177     }
    178 
    179   if (g_content_type_is_unknown (type))
    180     return g_strdup (_("Unknown type"));
    181   return g_strdup_printf (_("%s filetype"), type);
    182 }
    183 
    184 char *
    185 g_content_type_get_mime_type (const char *type)
    186 {
    187   char *mime;
    188 
    189   g_return_val_if_fail (type != NULL, NULL);
    190 
    191   mime = get_registry_classes_key (type, L"Content Type");
    192   if (mime)
    193     return mime;
    194   else if (g_content_type_is_unknown (type))
    195     return g_strdup ("application/octet-stream");
    196   else if (*type == '.')
    197     return g_strdup_printf ("application/x-ext-%s", type+1);
    198   /* TODO: Map "image" to "image/ *", etc? */
    199 
    200   return g_strdup ("application/octet-stream");
    201 }
    202 
    203 G_LOCK_DEFINE_STATIC (_type_icons);
    204 static GHashTable *_type_icons = NULL;
    205 
    206 GIcon *
    207 g_content_type_get_icon (const char *type)
    208 {
    209   GIcon *themed_icon;
    210   char *name = NULL;
    211 
    212   g_return_val_if_fail (type != NULL, NULL);
    213 
    214   /* In the Registry icons are the default value of
    215      HKEY_CLASSES_ROOT\<progid>\DefaultIcon with typical values like:
    216      <type>: <value>
    217      REG_EXPAND_SZ: %SystemRoot%\System32\Wscript.exe,3
    218      REG_SZ: shimgvw.dll,3
    219   */
    220   G_LOCK (_type_icons);
    221   if (!_type_icons)
    222     _type_icons = g_hash_table_new (g_str_hash, g_str_equal);
    223   name = g_hash_table_lookup (_type_icons, type);
    224   if (!name && type[0] == '.')
    225     {
    226       /* double lookup by extension */
    227       gchar *key = get_registry_classes_key (type, NULL);
    228       if (!key)
    229         key = g_strconcat (type+1, "file\\DefaultIcon", NULL);
    230       else
    231         {
    232 	  gchar *key2 = g_strconcat (key, "\\DefaultIcon", NULL);
    233 	  g_free (key);
    234 	  key = key2;
    235 	}
    236       name = get_registry_classes_key (key, NULL);
    237       if (name && strcmp (name, "%1") == 0)
    238         {
    239 	  g_free (name);
    240 	  name = NULL;
    241 	}
    242       if (name)
    243         g_hash_table_insert (_type_icons, g_strdup (type), g_strdup (name));
    244       g_free (key);
    245     }
    246 
    247   /* icon-name similar to how it was with gtk-2-12 */
    248   if (name)
    249     {
    250       themed_icon = g_themed_icon_new (name);
    251     }
    252   else
    253     {
    254       /* if not found an icon fall back to gtk-builtins */
    255       name = strcmp (type, "inode/directory") == 0 ? "gtk-directory" :
    256 	                   g_content_type_can_be_executable (type) ? "gtk-execute" : "gtk-file";
    257       g_hash_table_insert (_type_icons, g_strdup (type), g_strdup (name));
    258       themed_icon = g_themed_icon_new_with_default_fallbacks (name);
    259     }
    260   G_UNLOCK (_type_icons);
    261 
    262   return G_ICON (themed_icon);
    263 }
    264 
    265 gboolean
    266 g_content_type_can_be_executable (const char *type)
    267 {
    268   g_return_val_if_fail (type != NULL, FALSE);
    269 
    270   if (strcmp (type, ".exe") == 0 ||
    271       strcmp (type, ".com") == 0 ||
    272       strcmp (type, ".bat") == 0)
    273     return TRUE;
    274 
    275   /* TODO: Also look at PATHEXT, which lists the extensions for
    276    * "scripts" in addition to those for true binary executables.
    277    *
    278    * (PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH for me
    279    * right now, for instance). And in a sense, all associated file
    280    * types are "executable" on Windows... You can just type foo.jpg as
    281    * a command name in cmd.exe, and it will run the application
    282    * associated with .jpg. Hard to say what this API actually means
    283    * with "executable".
    284    */
    285 
    286   return FALSE;
    287 }
    288 
    289 static gboolean
    290 looks_like_text (const guchar *data,
    291                  gsize         data_size)
    292 {
    293   gsize i;
    294   guchar c;
    295   for (i = 0; i < data_size; i++)
    296     {
    297       c = data[i];
    298       if (g_ascii_iscntrl (c) && !g_ascii_isspace (c))
    299 	return FALSE;
    300     }
    301   return TRUE;
    302 }
    303 
    304 char *
    305 g_content_type_from_mime_type (const char *mime_type)
    306 {
    307   char *key, *content_type;
    308 
    309   g_return_val_if_fail (mime_type != NULL, NULL);
    310 
    311   key = g_strconcat ("MIME\\DataBase\\Content Type\\", mime_type, NULL);
    312   content_type = get_registry_classes_key (key, L"Extension");
    313   g_free (key);
    314 
    315   return content_type;
    316 }
    317 
    318 char *
    319 g_content_type_guess (const char   *filename,
    320 		      const guchar *data,
    321 		      gsize         data_size,
    322 		      gboolean     *result_uncertain)
    323 {
    324   char *basename;
    325   char *type;
    326   char *dot;
    327 
    328   type = NULL;
    329 
    330   if (filename)
    331     {
    332       basename = g_path_get_basename (filename);
    333       dot = strrchr (basename, '.');
    334       if (dot)
    335 	type = g_strdup (dot);
    336       g_free (basename);
    337     }
    338 
    339   if (type)
    340     return type;
    341 
    342   if (data && looks_like_text (data, data_size))
    343     return g_strdup (".txt");
    344 
    345   return g_strdup ("*");
    346 }
    347 
    348 GList *
    349 g_content_types_get_registered (void)
    350 {
    351   DWORD index;
    352   wchar_t keyname[256];
    353   DWORD key_len;
    354   char *key_utf8;
    355   GList *types;
    356 
    357   types = NULL;
    358   index = 0;
    359   key_len = 256;
    360   while (RegEnumKeyExW(HKEY_CLASSES_ROOT,
    361 		       index,
    362 		       keyname,
    363 		       &key_len,
    364 		       NULL,
    365 		       NULL,
    366 		       NULL,
    367 		       NULL) == ERROR_SUCCESS)
    368     {
    369       key_utf8 = g_utf16_to_utf8 (keyname, -1, NULL, NULL, NULL);
    370       if (key_utf8)
    371 	{
    372 	  if (*key_utf8 == '.')
    373 	    types = g_list_prepend (types, key_utf8);
    374 	  else
    375 	    g_free (key_utf8);
    376 	}
    377       index++;
    378       key_len = 256;
    379     }
    380 
    381   return g_list_reverse (types);
    382 }
    383 
    384 char **
    385 g_content_type_guess_for_tree (GFile *root)
    386 {
    387   /* FIXME: implement */
    388   return NULL;
    389 }
    390 
    391 #else /* !G_OS_WIN32 - Unix specific version */
    392 
    393 #include <dirent.h>
    394 
    395 #define XDG_PREFIX _gio_xdg
    396 #include "xdgmime/xdgmime.h"
    397 
    398 /* We lock this mutex whenever we modify global state in this module.  */
    399 G_LOCK_DEFINE_STATIC (gio_xdgmime);
    400 
    401 gsize
    402 _g_unix_content_type_get_sniff_len (void)
    403 {
    404   gsize size;
    405 
    406   G_LOCK (gio_xdgmime);
    407   size = xdg_mime_get_max_buffer_extents ();
    408   G_UNLOCK (gio_xdgmime);
    409 
    410   return size;
    411 }
    412 
    413 char *
    414 _g_unix_content_type_unalias (const char *type)
    415 {
    416   char *res;
    417 
    418   G_LOCK (gio_xdgmime);
    419   res = g_strdup (xdg_mime_unalias_mime_type (type));
    420   G_UNLOCK (gio_xdgmime);
    421 
    422   return res;
    423 }
    424 
    425 char **
    426 _g_unix_content_type_get_parents (const char *type)
    427 {
    428   const char *umime;
    429   char **parents;
    430   GPtrArray *array;
    431   int i;
    432 
    433   array = g_ptr_array_new ();
    434 
    435   G_LOCK (gio_xdgmime);
    436 
    437   umime = xdg_mime_unalias_mime_type (type);
    438 
    439   g_ptr_array_add (array, g_strdup (umime));
    440 
    441   parents = xdg_mime_list_mime_parents (umime);
    442   for (i = 0; parents && parents[i] != NULL; i++)
    443     g_ptr_array_add (array, g_strdup (parents[i]));
    444 
    445   free (parents);
    446 
    447   G_UNLOCK (gio_xdgmime);
    448 
    449   g_ptr_array_add (array, NULL);
    450 
    451   return (char **)g_ptr_array_free (array, FALSE);
    452 }
    453 
    454 /**
    455  * g_content_type_equals:
    456  * @type1: a content type string.
    457  * @type2: a content type string.
    458  *
    459  * Compares two content types for equality.
    460  *
    461  * Returns: %TRUE if the two strings are identical or equivalent,
    462  * %FALSE otherwise.
    463  **/
    464 gboolean
    465 g_content_type_equals (const char *type1,
    466 		       const char *type2)
    467 {
    468   gboolean res;
    469 
    470   g_return_val_if_fail (type1 != NULL, FALSE);
    471   g_return_val_if_fail (type2 != NULL, FALSE);
    472 
    473   G_LOCK (gio_xdgmime);
    474   res = xdg_mime_mime_type_equal (type1, type2);
    475   G_UNLOCK (gio_xdgmime);
    476 
    477   return res;
    478 }
    479 
    480 /**
    481  * g_content_type_is_a:
    482  * @type: a content type string.
    483  * @supertype: a string.
    484  *
    485  * Determines if @type is a subset of @supertype.
    486  *
    487  * Returns: %TRUE if @type is a kind of @supertype,
    488  * %FALSE otherwise.
    489  **/
    490 gboolean
    491 g_content_type_is_a (const char *type,
    492 		     const char *supertype)
    493 {
    494   gboolean res;
    495 
    496   g_return_val_if_fail (type != NULL, FALSE);
    497   g_return_val_if_fail (supertype != NULL, FALSE);
    498 
    499   G_LOCK (gio_xdgmime);
    500   res = xdg_mime_mime_type_subclass (type, supertype);
    501   G_UNLOCK (gio_xdgmime);
    502 
    503   return res;
    504 }
    505 
    506 /**
    507  * g_content_type_is_unknown:
    508  * @type: a content type string.
    509  *
    510  * Checks if the content type is the generic "unknown" type.
    511  * On unix this is the "application/octet-stream" mimetype,
    512  * while on win32 it is "*".
    513  *
    514  * Returns: %TRUE if the type is the unknown type.
    515  **/
    516 gboolean
    517 g_content_type_is_unknown (const char *type)
    518 {
    519   g_return_val_if_fail (type != NULL, FALSE);
    520 
    521   return strcmp (XDG_MIME_TYPE_UNKNOWN, type) == 0;
    522 }
    523 
    524 
    525 typedef enum {
    526   MIME_TAG_TYPE_OTHER,
    527   MIME_TAG_TYPE_COMMENT
    528 } MimeTagType;
    529 
    530 typedef struct {
    531   int current_type;
    532   int current_lang_level;
    533   int comment_lang_level;
    534   char *comment;
    535 } MimeParser;
    536 
    537 
    538 static int
    539 language_level (const char *lang)
    540 {
    541   const char * const *lang_list;
    542   int i;
    543 
    544   /* The returned list is sorted from most desirable to least
    545      desirable and always contains the default locale "C". */
    546   lang_list = g_get_language_names ();
    547 
    548   for (i = 0; lang_list[i]; i++)
    549     if (strcmp (lang_list[i], lang) == 0)
    550       return 1000-i;
    551 
    552   return 0;
    553 }
    554 
    555 static void
    556 mime_info_start_element (GMarkupParseContext  *context,
    557 			 const gchar          *element_name,
    558 			 const gchar         **attribute_names,
    559 			 const gchar         **attribute_values,
    560 			 gpointer              user_data,
    561 			 GError              **error)
    562 {
    563   int i;
    564   const char *lang;
    565   MimeParser *parser = user_data;
    566 
    567   if (strcmp (element_name, "comment") == 0)
    568     {
    569       lang = "C";
    570       for (i = 0; attribute_names[i]; i++)
    571 	if (strcmp (attribute_names[i], "xml:lang") == 0)
    572 	  {
    573 	    lang = attribute_values[i];
    574 	    break;
    575 	  }
    576 
    577       parser->current_lang_level = language_level (lang);
    578       parser->current_type = MIME_TAG_TYPE_COMMENT;
    579     }
    580   else
    581     parser->current_type = MIME_TAG_TYPE_OTHER;
    582 
    583 }
    584 
    585 static void
    586 mime_info_end_element (GMarkupParseContext  *context,
    587 		       const gchar          *element_name,
    588 		       gpointer              user_data,
    589 		       GError              **error)
    590 {
    591   MimeParser *parser = user_data;
    592 
    593   parser->current_type = MIME_TAG_TYPE_OTHER;
    594 }
    595 
    596 static void
    597 mime_info_text (GMarkupParseContext  *context,
    598 		const gchar          *text,
    599 		gsize                 text_len,
    600 		gpointer              user_data,
    601 		GError              **error)
    602 {
    603   MimeParser *parser = user_data;
    604 
    605   if (parser->current_type == MIME_TAG_TYPE_COMMENT &&
    606       parser->current_lang_level > parser->comment_lang_level)
    607     {
    608       g_free (parser->comment);
    609       parser->comment = g_strndup (text, text_len);
    610       parser->comment_lang_level = parser->current_lang_level;
    611     }
    612 }
    613 
    614 static char *
    615 load_comment_for_mime_helper (const char *dir,
    616                               const char *basename)
    617 {
    618   GMarkupParseContext *context;
    619   char *filename, *data;
    620   gsize len;
    621   gboolean res;
    622   MimeParser parse_data = {0};
    623   GMarkupParser parser = {
    624     mime_info_start_element,
    625     mime_info_end_element,
    626     mime_info_text
    627   };
    628 
    629   filename = g_build_filename (dir, "mime", basename, NULL);
    630 
    631   res = g_file_get_contents (filename,  &data,  &len,  NULL);
    632   g_free (filename);
    633   if (!res)
    634     return NULL;
    635 
    636   context = g_markup_parse_context_new   (&parser, 0, &parse_data, NULL);
    637   res = g_markup_parse_context_parse (context, data, len, NULL);
    638   g_free (data);
    639   g_markup_parse_context_free (context);
    640 
    641   if (!res)
    642     return NULL;
    643 
    644   return parse_data.comment;
    645 }
    646 
    647 
    648 static char *
    649 load_comment_for_mime (const char *mimetype)
    650 {
    651   const char * const* dirs;
    652   char *basename;
    653   char *comment;
    654   int i;
    655 
    656   basename = g_strdup_printf ("%s.xml", mimetype);
    657 
    658   comment = load_comment_for_mime_helper (g_get_user_data_dir (), basename);
    659   if (comment)
    660     {
    661       g_free (basename);
    662       return comment;
    663     }
    664 
    665   dirs = g_get_system_data_dirs ();
    666 
    667   for (i = 0; dirs[i] != NULL; i++)
    668     {
    669       comment = load_comment_for_mime_helper (dirs[i], basename);
    670       if (comment)
    671 	{
    672 	  g_free (basename);
    673 	  return comment;
    674 	}
    675     }
    676   g_free (basename);
    677 
    678   return g_strdup_printf (_("%s type"), mimetype);
    679 }
    680 
    681 /**
    682  * g_content_type_get_description:
    683  * @type: a content type string.
    684  *
    685  * Gets the human readable description of the content type.
    686  *
    687  * Returns: a short description of the content type @type.
    688  **/
    689 char *
    690 g_content_type_get_description (const char *type)
    691 {
    692   static GHashTable *type_comment_cache = NULL;
    693   char *comment;
    694 
    695   g_return_val_if_fail (type != NULL, NULL);
    696 
    697   G_LOCK (gio_xdgmime);
    698   type = xdg_mime_unalias_mime_type (type);
    699 
    700   if (type_comment_cache == NULL)
    701     type_comment_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
    702 
    703   comment = g_hash_table_lookup (type_comment_cache, type);
    704   comment = g_strdup (comment);
    705   G_UNLOCK (gio_xdgmime);
    706 
    707   if (comment != NULL)
    708     return comment;
    709 
    710   comment = load_comment_for_mime (type);
    711 
    712   G_LOCK (gio_xdgmime);
    713   g_hash_table_insert (type_comment_cache,
    714 		       g_strdup (type),
    715 		       g_strdup (comment));
    716   G_UNLOCK (gio_xdgmime);
    717 
    718   return comment;
    719 }
    720 
    721 /**
    722  * g_content_type_get_mime_type:
    723  * @type: a content type string.
    724  *
    725  * Gets the mime-type for the content type. If one is registered
    726  *
    727  * Returns: the registered mime-type for the given @type, or NULL if unknown.
    728  **/
    729 char *
    730 g_content_type_get_mime_type (const char *type)
    731 {
    732   g_return_val_if_fail (type != NULL, NULL);
    733 
    734   return g_strdup (type);
    735 }
    736 
    737 /**
    738  * g_content_type_get_icon:
    739  * @type: a content type string.
    740  *
    741  * Gets the icon for a content type.
    742  *
    743  * Returns: #GIcon corresponding to the content type.
    744  **/
    745 GIcon *
    746 g_content_type_get_icon (const char *type)
    747 {
    748   char *mimetype_icon, *generic_mimetype_icon, *q;
    749   char *xdg_mimetype_icon, *legacy_mimetype_icon;
    750   char *xdg_mimetype_generic_icon;
    751   char *icon_names[4];
    752   int n = 0;
    753   const char *p;
    754   GIcon *themed_icon;
    755 
    756   g_return_val_if_fail (type != NULL, NULL);
    757 
    758   G_LOCK (gio_xdgmime);
    759   xdg_mimetype_icon = g_strdup (xdg_mime_get_icon (type));
    760   xdg_mimetype_generic_icon = g_strdup (xdg_mime_get_generic_icon (type));
    761   G_UNLOCK (gio_xdgmime);
    762 
    763   mimetype_icon = g_strdup (type);
    764 
    765   while ((q = strchr (mimetype_icon, '/')) != NULL)
    766     *q = '-';
    767 
    768   p = strchr (type, '/');
    769   if (p == NULL)
    770     p = type + strlen (type);
    771 
    772   /* Not all icons have migrated to the new icon theme spec, look for old names too */
    773   legacy_mimetype_icon = g_strconcat ("gnome-mime-", mimetype_icon, NULL);
    774 
    775   generic_mimetype_icon = g_malloc (p - type + strlen ("-x-generic") + 1);
    776   memcpy (generic_mimetype_icon, type, p - type);
    777   memcpy (generic_mimetype_icon + (p - type), "-x-generic", strlen ("-x-generic"));
    778   generic_mimetype_icon[(p - type) + strlen ("-x-generic")] = 0;
    779 
    780   if (xdg_mimetype_icon)
    781     icon_names[n++] = xdg_mimetype_icon;
    782 
    783   icon_names[n++] = mimetype_icon;
    784   icon_names[n++] = legacy_mimetype_icon;
    785 
    786   if (xdg_mimetype_generic_icon)
    787     icon_names[n++] = xdg_mimetype_generic_icon;
    788 
    789   icon_names[n++] = generic_mimetype_icon;
    790 
    791   themed_icon = g_themed_icon_new_from_names (icon_names, n);
    792 
    793   g_free (xdg_mimetype_icon);
    794   g_free (xdg_mimetype_generic_icon);
    795   g_free (mimetype_icon);
    796   g_free (legacy_mimetype_icon);
    797   g_free (generic_mimetype_icon);
    798 
    799   return themed_icon;
    800 }
    801 
    802 /**
    803  * g_content_type_can_be_executable:
    804  * @type: a content type string.
    805  *
    806  * Checks if a content type can be executable. Note that for instance
    807  * things like text files can be executables (i.e. scripts and batch files).
    808  *
    809  * Returns: %TRUE if the file type corresponds to a type that
    810  * can be executable, %FALSE otherwise.
    811  **/
    812 gboolean
    813 g_content_type_can_be_executable (const char *type)
    814 {
    815   g_return_val_if_fail (type != NULL, FALSE);
    816 
    817   if (g_content_type_is_a (type, "application/x-executable")  ||
    818       g_content_type_is_a (type, "text/plain"))
    819     return TRUE;
    820 
    821   return FALSE;
    822 }
    823 
    824 static gboolean
    825 looks_like_text (const guchar *data, gsize data_size)
    826 {
    827   gsize i;
    828   char c;
    829 
    830   for (i = 0; i < data_size; i++)
    831     {
    832       c = data[i];
    833 
    834       if (g_ascii_iscntrl (c) &&
    835 	  !g_ascii_isspace (c))
    836 	return FALSE;
    837     }
    838   return TRUE;
    839 }
    840 
    841 /**
    842  * g_content_type_from_mime_type:
    843  * @mime_type: a mime type string.
    844  *
    845  * Tries to find a content type based on the mime type name.
    846  *
    847  * Returns: Newly allocated string with content type or NULL when does not know.
    848  *
    849  * Since: 2.18
    850  **/
    851 char *
    852 g_content_type_from_mime_type (const char *mime_type)
    853 {
    854   char *umime;
    855 
    856   g_return_val_if_fail (mime_type != NULL, NULL);
    857 
    858   G_LOCK (gio_xdgmime);
    859   /* mime type and content type are same on unixes */
    860   umime = g_strdup (xdg_mime_unalias_mime_type (mime_type));
    861   G_UNLOCK (gio_xdgmime);
    862 
    863   return umime;
    864 }
    865 
    866 /**
    867  * g_content_type_guess:
    868  * @filename: a string, or %NULL
    869  * @data: a stream of data, or %NULL
    870  * @data_size: the size of @data
    871  * @result_uncertain: a flag indicating the certainty of the result
    872  *
    873  * Guesses the content type based on example data. If the function is
    874  * uncertain, @result_uncertain will be set to %TRUE. Either @filename
    875  * or @data may be %NULL, in which case the guess will be based solely
    876  * on the other argument.
    877  *
    878  * Returns: a string indicating a guessed content type for the
    879  * given data.
    880  **/
    881 char *
    882 g_content_type_guess (const char   *filename,
    883 		      const guchar *data,
    884 		      gsize         data_size,
    885 		      gboolean     *result_uncertain)
    886 {
    887   char *basename;
    888   const char *name_mimetypes[10], *sniffed_mimetype;
    889   char *mimetype;
    890   int i;
    891   int n_name_mimetypes;
    892   int sniffed_prio;
    893 
    894   sniffed_prio = 0;
    895   n_name_mimetypes = 0;
    896   sniffed_mimetype = XDG_MIME_TYPE_UNKNOWN;
    897 
    898   if (result_uncertain)
    899     *result_uncertain = FALSE;
    900 
    901   G_LOCK (gio_xdgmime);
    902 
    903   if (filename)
    904     {
    905       i = strlen (filename);
    906       if (filename[i - 1] == '/')
    907         {
    908           name_mimetypes[0] = "inode/directory";
    909           name_mimetypes[1] = NULL;
    910           n_name_mimetypes = 1;
    911           if (result_uncertain)
    912             *result_uncertain = TRUE;
    913         }
    914       else
    915         {
    916           basename = g_path_get_basename (filename);
    917           n_name_mimetypes = xdg_mime_get_mime_types_from_file_name (basename, name_mimetypes, 10);
    918           g_free (basename);
    919         }
    920     }
    921 
    922   /* Got an extension match, and no conflicts. This is it. */
    923   if (n_name_mimetypes == 1)
    924     {
    925       G_UNLOCK (gio_xdgmime);
    926       return g_strdup (name_mimetypes[0]);
    927     }
    928 
    929   if (data)
    930     {
    931       sniffed_mimetype = xdg_mime_get_mime_type_for_data (data, data_size, &sniffed_prio);
    932       if (sniffed_mimetype == XDG_MIME_TYPE_UNKNOWN &&
    933 	  data &&
    934 	  looks_like_text (data, data_size))
    935 	sniffed_mimetype = "text/plain";
    936 
    937       /* For security reasons we don't ever want to sniff desktop files
    938        * where we know the filename and it doesn't have a .desktop extension.
    939        * This is because desktop files allow executing any application and
    940        * we don't want to make it possible to hide them looking like something
    941        * else.
    942        */
    943       if (filename != NULL &&
    944           strcmp (sniffed_mimetype, "application/x-desktop") == 0)
    945         sniffed_mimetype = "text/plain";
    946     }
    947 
    948   if (n_name_mimetypes == 0)
    949     {
    950       if (sniffed_mimetype == XDG_MIME_TYPE_UNKNOWN &&
    951 	  result_uncertain)
    952 	*result_uncertain = TRUE;
    953 
    954       mimetype = g_strdup (sniffed_mimetype);
    955     }
    956   else
    957     {
    958       mimetype = NULL;
    959       if (sniffed_mimetype != XDG_MIME_TYPE_UNKNOWN)
    960 	{
    961 	  if (sniffed_prio >= 80) /* High priority sniffing match, use that */
    962 	    mimetype = g_strdup (sniffed_mimetype);
    963 	  else
    964 	    {
    965 	      /* There are conflicts between the name matches and we have a sniffed
    966 		 type, use that as a tie breaker. */
    967 
    968 	      for (i = 0; i < n_name_mimetypes; i++)
    969 		{
    970 		  if ( xdg_mime_mime_type_subclass (name_mimetypes[i], sniffed_mimetype))
    971 		    {
    972 		      /* This nametype match is derived from (or the same as) the sniffed type).
    973 			 This is probably it. */
    974 		      mimetype = g_strdup (name_mimetypes[i]);
    975 		      break;
    976 		    }
    977 		}
    978 	    }
    979 	}
    980 
    981       if (mimetype == NULL)
    982 	{
    983 	  /* Conflicts, and sniffed type was no help or not there. Guess on the first one */
    984 	  mimetype = g_strdup (name_mimetypes[0]);
    985 	  if (result_uncertain)
    986 	    *result_uncertain = TRUE;
    987 	}
    988     }
    989 
    990   G_UNLOCK (gio_xdgmime);
    991 
    992   return mimetype;
    993 }
    994 
    995 static void
    996 enumerate_mimetypes_subdir (const char *dir,
    997                             const char *prefix,
    998                             GHashTable *mimetypes)
    999 {
   1000   DIR *d;
   1001   struct dirent *ent;
   1002   char *mimetype;
   1003 
   1004   d = opendir (dir);
   1005   if (d)
   1006     {
   1007       while ((ent = readdir (d)) != NULL)
   1008 	{
   1009 	  if (g_str_has_suffix (ent->d_name, ".xml"))
   1010 	    {
   1011 	      mimetype = g_strdup_printf ("%s/%.*s", prefix, (int) strlen (ent->d_name) - 4, ent->d_name);
   1012 	      g_hash_table_replace (mimetypes, mimetype, NULL);
   1013 	    }
   1014 	}
   1015       closedir (d);
   1016     }
   1017 }
   1018 
   1019 static void
   1020 enumerate_mimetypes_dir (const char *dir,
   1021                          GHashTable *mimetypes)
   1022 {
   1023   DIR *d;
   1024   struct dirent *ent;
   1025   char *mimedir;
   1026   char *name;
   1027 
   1028   mimedir = g_build_filename (dir, "mime", NULL);
   1029 
   1030   d = opendir (mimedir);
   1031   if (d)
   1032     {
   1033       while ((ent = readdir (d)) != NULL)
   1034 	{
   1035 	  if (strcmp (ent->d_name, "packages") != 0)
   1036 	    {
   1037 	      name = g_build_filename (mimedir, ent->d_name, NULL);
   1038 	      if (g_file_test (name, G_FILE_TEST_IS_DIR))
   1039 		enumerate_mimetypes_subdir (name, ent->d_name, mimetypes);
   1040 	      g_free (name);
   1041 	    }
   1042 	}
   1043       closedir (d);
   1044     }
   1045 
   1046   g_free (mimedir);
   1047 }
   1048 
   1049 /**
   1050  * g_content_types_get_registered:
   1051  *
   1052  * Gets a list of strings containing all the registered content types
   1053  * known to the system. The list and its data should be freed using
   1054  * @g_list_foreach(list, g_free, NULL) and @g_list_free(list)
   1055  * Returns: #GList of the registered content types.
   1056  **/
   1057 GList *
   1058 g_content_types_get_registered (void)
   1059 {
   1060   const char * const* dirs;
   1061   GHashTable *mimetypes;
   1062   GHashTableIter iter;
   1063   gpointer key;
   1064   int i;
   1065   GList *l;
   1066 
   1067   mimetypes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
   1068 
   1069   enumerate_mimetypes_dir (g_get_user_data_dir (), mimetypes);
   1070   dirs = g_get_system_data_dirs ();
   1071 
   1072   for (i = 0; dirs[i] != NULL; i++)
   1073     enumerate_mimetypes_dir (dirs[i], mimetypes);
   1074 
   1075   l = NULL;
   1076   g_hash_table_iter_init (&iter, mimetypes);
   1077   while (g_hash_table_iter_next (&iter, &key, NULL))
   1078     {
   1079       l = g_list_prepend (l, key);
   1080       g_hash_table_iter_steal (&iter);
   1081     }
   1082 
   1083   g_hash_table_destroy (mimetypes);
   1084 
   1085   return l;
   1086 }
   1087 
   1088 
   1089 /* tree magic data */
   1090 static GList *tree_matches = NULL;
   1091 static gboolean need_reload = FALSE;
   1092 
   1093 G_LOCK_DEFINE_STATIC (gio_treemagic);
   1094 
   1095 typedef struct
   1096 {
   1097   gchar *path;
   1098   GFileType type;
   1099   guint match_case : 1;
   1100   guint executable : 1;
   1101   guint non_empty  : 1;
   1102   guint on_disc    : 1;
   1103   gchar *mimetype;
   1104   GList *matches;
   1105 } TreeMatchlet;
   1106 
   1107 typedef struct
   1108 {
   1109   gchar *contenttype;
   1110   gint priority;
   1111   GList *matches;
   1112 } TreeMatch;
   1113 
   1114 
   1115 static void
   1116 tree_matchlet_free (TreeMatchlet *matchlet)
   1117 {
   1118   g_list_foreach (matchlet->matches, (GFunc)tree_matchlet_free, NULL);
   1119   g_list_free (matchlet->matches);
   1120   g_free (matchlet->path);
   1121   g_free (matchlet->mimetype);
   1122   g_slice_free (TreeMatchlet, matchlet);
   1123 }
   1124 
   1125 static void
   1126 tree_match_free (TreeMatch *match)
   1127 {
   1128   g_list_foreach (match->matches, (GFunc)tree_matchlet_free, NULL);
   1129   g_list_free (match->matches);
   1130   g_free (match->contenttype);
   1131   g_slice_free (TreeMatch, match);
   1132 }
   1133 
   1134 static TreeMatch *
   1135 parse_header (gchar *line)
   1136 {
   1137   gint len;
   1138   gchar *s;
   1139   TreeMatch *match;
   1140 
   1141   len = strlen (line);
   1142 
   1143   if (line[0] != '[' || line[len - 1] != ']')
   1144     return NULL;
   1145 
   1146   line[len - 1] = 0;
   1147   s = strchr (line, ':');
   1148 
   1149   match = g_slice_new0 (TreeMatch);
   1150   match->priority = atoi (line + 1);
   1151   match->contenttype = g_strdup (s + 1);
   1152 
   1153   return match;
   1154 }
   1155 
   1156 static TreeMatchlet *
   1157 parse_match_line (gchar *line,
   1158 		  gint  *depth)
   1159 {
   1160   gchar *s, *p;
   1161   TreeMatchlet *matchlet;
   1162   gchar **parts;
   1163   gint i;
   1164 
   1165   matchlet = g_slice_new0 (TreeMatchlet);
   1166 
   1167   if (line[0] == '>')
   1168     {
   1169       *depth = 0;
   1170       s = line;
   1171     }
   1172   else
   1173     {
   1174       *depth = atoi (line);
   1175       s = strchr (line, '>');
   1176     }
   1177   s += 2;
   1178   p = strchr (s, '"');
   1179   *p = 0;
   1180 
   1181   matchlet->path = g_strdup (s);
   1182   s = p + 1;
   1183   parts = g_strsplit (s, ",", 0);
   1184   if (strcmp (parts[0], "=file") == 0)
   1185     matchlet->type = G_FILE_TYPE_REGULAR;
   1186   else if (strcmp (parts[0], "=directory") == 0)
   1187     matchlet->type = G_FILE_TYPE_DIRECTORY;
   1188   else if (strcmp (parts[0], "=link") == 0)
   1189     matchlet->type = G_FILE_TYPE_SYMBOLIC_LINK;
   1190   else
   1191     matchlet->type = G_FILE_TYPE_UNKNOWN;
   1192   for (i = 1; parts[i]; i++)
   1193     {
   1194       if (strcmp (parts[i], "executable") == 0)
   1195         matchlet->executable = 1;
   1196       else if (strcmp (parts[i], "match-case") == 0)
   1197         matchlet->match_case = 1;
   1198       else if (strcmp (parts[i], "non-empty") == 0)
   1199         matchlet->non_empty = 1;
   1200       else if (strcmp (parts[i], "on-disc") == 0)
   1201         matchlet->on_disc = 1;
   1202       else
   1203         matchlet->mimetype = g_strdup (parts[i]);
   1204     }
   1205 
   1206   g_strfreev (parts);
   1207 
   1208   return matchlet;
   1209 }
   1210 
   1211 static gint
   1212 cmp_match (gconstpointer a, gconstpointer b)
   1213 {
   1214   const TreeMatch *aa = (const TreeMatch *)a;
   1215   const TreeMatch *bb = (const TreeMatch *)b;
   1216 
   1217   return bb->priority - aa->priority;
   1218 }
   1219 
   1220 static void
   1221 insert_match (TreeMatch *match)
   1222 {
   1223   tree_matches = g_list_insert_sorted (tree_matches, match, cmp_match);
   1224 }
   1225 
   1226 static void
   1227 insert_matchlet (TreeMatch    *match,
   1228                  TreeMatchlet *matchlet,
   1229                  gint          depth)
   1230 {
   1231   if (depth == 0)
   1232     match->matches = g_list_append (match->matches, matchlet);
   1233   else
   1234     {
   1235       GList *last;
   1236       TreeMatchlet *m;
   1237 
   1238       last = g_list_last (match->matches);
   1239       if (!last)
   1240         {
   1241           tree_matchlet_free (matchlet);
   1242           g_warning ("can't insert tree matchlet at depth %d", depth);
   1243           return;
   1244         }
   1245 
   1246       m = (TreeMatchlet *) last->data;
   1247       while (--depth > 0)
   1248         {
   1249           last = g_list_last (m->matches);
   1250           if (!last)
   1251             {
   1252               tree_matchlet_free (matchlet);
   1253               g_warning ("can't insert tree matchlet at depth %d", depth);
   1254               return;
   1255             }
   1256 
   1257           m = (TreeMatchlet *) last->data;
   1258         }
   1259       m->matches = g_list_append (m->matches, matchlet);
   1260     }
   1261 }
   1262 
   1263 static void
   1264 read_tree_magic_from_directory (const gchar *prefix)
   1265 {
   1266   gchar *filename;
   1267   gchar *text;
   1268   gsize len;
   1269   gchar **lines;
   1270   gint i;
   1271   TreeMatch *match;
   1272   TreeMatchlet *matchlet;
   1273   gint depth;
   1274 
   1275   filename = g_build_filename (prefix, "mime", "treemagic", NULL);
   1276 
   1277   if (g_file_get_contents (filename, &text, &len, NULL))
   1278     {
   1279       if (strcmp (text, "MIME-TreeMagic") == 0)
   1280         {
   1281           lines = g_strsplit (text + strlen ("MIME-TreeMagic") + 2, "\n", 0);
   1282           match = NULL;
   1283           for (i = 0; lines[i] && lines[i][0]; i++)
   1284             {
   1285               if (lines[i][0] == '[')
   1286                 {
   1287                   match = parse_header (lines[i]);
   1288                   insert_match (match);
   1289                 }
   1290               else
   1291                 {
   1292                   matchlet = parse_match_line (lines[i], &depth);
   1293                   insert_matchlet (match, matchlet, depth);
   1294                 }
   1295             }
   1296 
   1297           g_strfreev (lines);
   1298         }
   1299       else
   1300         g_warning ("%s: header not found, skipping\n", filename);
   1301 
   1302       g_free (text);
   1303     }
   1304 
   1305   g_free (filename);
   1306 }
   1307 
   1308 
   1309 static void
   1310 xdg_mime_reload (void *user_data)
   1311 {
   1312   need_reload = TRUE;
   1313 }
   1314 
   1315 static void
   1316 tree_magic_shutdown (void)
   1317 {
   1318   g_list_foreach (tree_matches, (GFunc)tree_match_free, NULL);
   1319   g_list_free (tree_matches);
   1320   tree_matches = NULL;
   1321 }
   1322 
   1323 static void
   1324 tree_magic_init (void)
   1325 {
   1326   static gboolean initialized = FALSE;
   1327   const gchar *dir;
   1328   const gchar * const * dirs;
   1329   int i;
   1330 
   1331   if (!initialized)
   1332     {
   1333       initialized = TRUE;
   1334 
   1335       xdg_mime_register_reload_callback (xdg_mime_reload, NULL, NULL);
   1336       need_reload = TRUE;
   1337     }
   1338 
   1339   if (need_reload)
   1340     {
   1341       need_reload = FALSE;
   1342 
   1343       tree_magic_shutdown ();
   1344 
   1345       dir = g_get_user_data_dir ();
   1346       read_tree_magic_from_directory (dir);
   1347       dirs = g_get_system_data_dirs ();
   1348       for (i = 0; dirs[i]; i++)
   1349         read_tree_magic_from_directory (dirs[i]);
   1350     }
   1351 }
   1352 
   1353 /* a filtering enumerator */
   1354 
   1355 typedef struct
   1356 {
   1357   gchar *path;
   1358   gint depth;
   1359   gboolean ignore_case;
   1360   gchar **components;
   1361   gchar **case_components;
   1362   GFileEnumerator **enumerators;
   1363   GFile **children;
   1364 } Enumerator;
   1365 
   1366 static gboolean
   1367 component_match (Enumerator  *e,
   1368                  gint         depth,
   1369                  const gchar *name)
   1370 {
   1371   gchar *case_folded, *key;
   1372   gboolean found;
   1373 
   1374   if (strcmp (name, e->components[depth]) == 0)
   1375     return TRUE;
   1376 
   1377   if (!e->ignore_case)
   1378     return FALSE;
   1379 
   1380   case_folded = g_utf8_casefold (name, -1);
   1381   key = g_utf8_collate_key (case_folded, -1);
   1382 
   1383   found = strcmp (key, e->case_components[depth]) == 0;
   1384 
   1385   g_free (case_folded);
   1386   g_free (key);
   1387 
   1388   return found;
   1389 }
   1390 
   1391 static GFile *
   1392 next_match_recurse (Enumerator *e,
   1393                     gint        depth)
   1394 {
   1395   GFile *file;
   1396   GFileInfo *info;
   1397   const gchar *name;
   1398 
   1399   while (TRUE)
   1400     {
   1401       if (e->enumerators[depth] == NULL)
   1402         {
   1403           if (depth > 0)
   1404             {
   1405               file = next_match_recurse (e, depth - 1);
   1406               if (file)
   1407                 {
   1408                   e->children[depth] = file;
   1409                   e->enumerators[depth] = g_file_enumerate_children (file,
   1410                                                                      G_FILE_ATTRIBUTE_STANDARD_NAME,
   1411                                                                      G_FILE_QUERY_INFO_NONE,
   1412 							             NULL,
   1413 							             NULL);
   1414                 }
   1415             }
   1416           if (e->enumerators[depth] == NULL)
   1417             return NULL;
   1418         }
   1419 
   1420       while ((info = g_file_enumerator_next_file (e->enumerators[depth], NULL, NULL)))
   1421         {
   1422           name = g_file_info_get_name (info);
   1423           if (component_match (e, depth, name))
   1424             {
   1425               file = g_file_get_child (e->children[depth], name);
   1426               g_object_unref (info);
   1427               return file;
   1428             }
   1429           g_object_unref (info);
   1430         }
   1431 
   1432       g_object_unref (e->enumerators[depth]);
   1433       e->enumerators[depth] = NULL;
   1434       g_object_unref (e->children[depth]);
   1435       e->children[depth] = NULL;
   1436     }
   1437 }
   1438 
   1439 static GFile *
   1440 enumerator_next (Enumerator *e)
   1441 {
   1442   return next_match_recurse (e, e->depth - 1);
   1443 }
   1444 
   1445 static Enumerator *
   1446 enumerator_new (GFile      *root,
   1447                 const char *path,
   1448                 gboolean    ignore_case)
   1449 {
   1450   Enumerator *e;
   1451   gint i;
   1452   gchar *case_folded;
   1453 
   1454   e = g_new0 (Enumerator, 1);
   1455   e->path = g_strdup (path);
   1456   e->ignore_case = ignore_case;
   1457 
   1458   e->components = g_strsplit (e->path, G_DIR_SEPARATOR_S, -1);
   1459   e->depth = g_strv_length (e->components);
   1460   if (e->ignore_case)
   1461     {
   1462       e->case_components = g_new0 (char *, e->depth + 1);
   1463       for (i = 0; e->components[i]; i++)
   1464         {
   1465           case_folded = g_utf8_casefold (e->components[i], -1);
   1466           e->case_components[i] = g_utf8_collate_key (case_folded, -1);
   1467           g_free (case_folded);
   1468         }
   1469     }
   1470 
   1471   e->children = g_new0 (GFile *, e->depth);
   1472   e->children[0] = g_object_ref (root);
   1473   e->enumerators = g_new0 (GFileEnumerator *, e->depth);
   1474   e->enumerators[0] = g_file_enumerate_children (root,
   1475                                                  G_FILE_ATTRIBUTE_STANDARD_NAME,
   1476                                                  G_FILE_QUERY_INFO_NONE,
   1477                                                  NULL,
   1478                                                  NULL);
   1479 
   1480   return e;
   1481 }
   1482 
   1483 static void
   1484 enumerator_free (Enumerator *e)
   1485 {
   1486   gint i;
   1487 
   1488   for (i = 0; i < e->depth; i++)
   1489     {
   1490       if (e->enumerators[i])
   1491         g_object_unref (e->enumerators[i]);
   1492       if (e->children[i])
   1493         g_object_unref (e->children[i]);
   1494     }
   1495 
   1496   g_free (e->enumerators);
   1497   g_free (e->children);
   1498   g_strfreev (e->components);
   1499   if (e->case_components)
   1500     g_strfreev (e->case_components);
   1501   g_free (e->path);
   1502   g_free (e);
   1503 }
   1504 
   1505 static gboolean
   1506 matchlet_match (TreeMatchlet *matchlet,
   1507                 GFile        *root)
   1508 {
   1509   GFile *file;
   1510   GFileInfo *info;
   1511   gboolean result;
   1512   const gchar *attrs;
   1513   Enumerator *e;
   1514   GList *l;
   1515 
   1516   e = enumerator_new (root, matchlet->path, !matchlet->match_case);
   1517 
   1518   do
   1519     {
   1520       file = enumerator_next (e);
   1521       if (!file)
   1522         {
   1523           enumerator_free (e);
   1524           return FALSE;
   1525         }
   1526 
   1527       if (matchlet->mimetype)
   1528         attrs = G_FILE_ATTRIBUTE_STANDARD_TYPE ","
   1529                 G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE ","
   1530                 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE;
   1531       else
   1532         attrs = G_FILE_ATTRIBUTE_STANDARD_TYPE ","
   1533                 G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE;
   1534       info = g_file_query_info (file,
   1535                                 attrs,
   1536                                 G_FILE_QUERY_INFO_NONE,
   1537                                 NULL,
   1538                                 NULL);
   1539       if (info)
   1540         {
   1541           result = TRUE;
   1542 
   1543           if (matchlet->type != G_FILE_TYPE_UNKNOWN &&
   1544               g_file_info_get_file_type (info) != matchlet->type)
   1545             result = FALSE;
   1546 
   1547           if (matchlet->executable &&
   1548               !g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE))
   1549             result = FALSE;
   1550         }
   1551       else
   1552         result = FALSE;
   1553 
   1554       if (result && matchlet->non_empty)
   1555         {
   1556           GFileEnumerator *child_enum;
   1557           GFileInfo *child_info;
   1558 
   1559           child_enum = g_file_enumerate_children (file,
   1560                                                   G_FILE_ATTRIBUTE_STANDARD_NAME,
   1561                                                   G_FILE_QUERY_INFO_NONE,
   1562                                                   NULL,
   1563                                                   NULL);
   1564 
   1565           if (child_enum)
   1566             {
   1567               child_info = g_file_enumerator_next_file (child_enum, NULL, NULL);
   1568               if (child_info)
   1569                 g_object_unref (child_info);
   1570               else
   1571                 result = FALSE;
   1572               g_object_unref (child_enum);
   1573             }
   1574           else
   1575             result = FALSE;
   1576         }
   1577 
   1578       if (result && matchlet->mimetype)
   1579         {
   1580           if (strcmp (matchlet->mimetype, g_file_info_get_content_type (info)) != 0)
   1581             result = FALSE;
   1582         }
   1583 
   1584       g_object_unref (info);
   1585       g_object_unref (file);
   1586     }
   1587   while (!result);
   1588 
   1589   enumerator_free (e);
   1590 
   1591   if (!matchlet->matches)
   1592     return TRUE;
   1593 
   1594   for (l = matchlet->matches; l; l = l->next)
   1595     {
   1596       TreeMatchlet *submatchlet;
   1597 
   1598       submatchlet = l->data;
   1599       if (matchlet_match (submatchlet, root))
   1600         return TRUE;
   1601     }
   1602 
   1603   return FALSE;
   1604 }
   1605 
   1606 static void
   1607 match_match (TreeMatch    *match,
   1608              GFile        *root,
   1609              GPtrArray    *types)
   1610 {
   1611   GList *l;
   1612 
   1613   for (l = match->matches; l; l = l->next)
   1614     {
   1615       TreeMatchlet *matchlet = l->data;
   1616       if (matchlet_match (matchlet, root))
   1617         {
   1618           g_ptr_array_add (types, g_strdup (match->contenttype));
   1619           break;
   1620         }
   1621     }
   1622 }
   1623 
   1624 /**
   1625  * g_content_type_guess_for_tree:
   1626  * @root: the root of the tree to guess a type for
   1627  *
   1628  * Tries to guess the type of the tree with root @root, by
   1629  * looking at the files it contains. The result is an array
   1630  * of content types, with the best guess coming first.
   1631  *
   1632  * The types returned all have the form x-content/foo, e.g.
   1633  * x-content/audio-cdda (for audio CDs) or x-content/image-dcf
   1634  * (for a camera memory card). See the <ulink url="http://www.freedesktop.org/wiki/Specifications/shared-mime-info-spec">shared-mime-info</ulink>
   1635  * specification for more on x-content types.
   1636  *
   1637  * This function is useful in the implementation of g_mount_guess_content_type().
   1638  *
   1639  * Returns: an %NULL-terminated array of zero or more content types, or %NULL.
   1640  *    Free with g_strfreev()
   1641  *
   1642  * Since: 2.18
   1643  */
   1644 char **
   1645 g_content_type_guess_for_tree (GFile *root)
   1646 {
   1647   GPtrArray *types;
   1648   GList *l;
   1649 
   1650   types = g_ptr_array_new ();
   1651 
   1652   G_LOCK (gio_treemagic);
   1653 
   1654   tree_magic_init ();
   1655   for (l = tree_matches; l; l = l->next)
   1656     {
   1657       TreeMatch *match = l->data;
   1658       match_match (match, root, types);
   1659     }
   1660 
   1661   G_UNLOCK (gio_treemagic);
   1662 
   1663   g_ptr_array_add (types, NULL);
   1664 
   1665   return (char **)g_ptr_array_free (types, FALSE);
   1666 }
   1667 
   1668 #endif /* Unix version */
   1669 
   1670 #define __G_CONTENT_TYPE_C__
   1671 #include "gioaliasdef.c"
   1672