Blame gio/gosxcontenttype.c

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